张延森 4 anni fa
parent
commit
11f5ec4a90

+ 6
- 0
config/routes.js Vedi File

@@ -92,6 +92,12 @@ export default [
92 92
                     component: './Post/Edit',
93 93
                     hideInMenu: true,
94 94
                   },
95
+                  {
96
+                    path: '/post/post-type',
97
+                    name: '分类管理',
98
+                    menuCode: 'post.post-type',
99
+                    component: './Post/Type',
100
+                  },
95 101
                 ],
96 102
               },
97 103
               {

+ 30
- 3
src/components/ChangePassword/index.jsx Vedi File

@@ -1,12 +1,39 @@
1
-import React from 'react';
1
+import React, { useState } from 'react';
2 2
 import {
3 3
   ModalForm,
4 4
   ProFormText,
5 5
 } from '@ant-design/pro-form';
6
+import md5 from 'md5';
7
+import { notification } from 'antd';
8
+import request from '@/utils/request';
6 9
 
7 10
 export default (props) => {
11
+  const checkSame = ({ getFieldValue }) => ({
12
+    validator(_, value) {
13
+      if (!value || getFieldValue('nw1') === value) {
14
+        return Promise.resolve();
15
+      }
16
+
17
+      return Promise.reject(new Error('两次密码输入不一致!'));
18
+    }
19
+  })
20
+
21
+  const handleSubmit = (values) => {
22
+    const data = {
23
+      originPassword: md5(values.originPassword),
24
+      newPassword: md5(values.nw1),
25
+    }
26
+
27
+    return request('/change-password', { data, method: 'put' }).then(() => {
28
+      props.onFinish()
29
+      return true
30
+    }).catch((e) => {
31
+      notification.error({ message: e.message })
32
+    })
33
+  }
34
+
8 35
   return (
9
-    <ModalForm>
36
+    <ModalForm width={480} visible={props.visible} onFinish={handleSubmit} onVisibleChange={props.onVisibleChange}>
10 37
       <ProFormText.Password
11 38
         label="原始密码"
12 39
         name="originPassword"
@@ -20,7 +47,7 @@ export default (props) => {
20 47
       <ProFormText.Password
21 48
         label="新密码"
22 49
         name="nw2"
23
-        rules={[{ required: true, message: '新密码不能为空' }]}
50
+        rules={[{ required: true, message: '新密码不能为空' }, checkSame ]}
24 51
       />
25 52
     </ModalForm>
26 53
   )

+ 20
- 3
src/components/GlobalHeader/AvatarDropdown.jsx Vedi File

@@ -1,12 +1,17 @@
1
-import { LogoutOutlined } from '@ant-design/icons';
2
-import { Avatar, Menu, Spin } from 'antd';
3 1
 import React from 'react';
2
+import { Avatar, Menu, Spin } from 'antd';
3
+import { LogoutOutlined, FormOutlined } from '@ant-design/icons';
4 4
 import { history, connect } from 'umi';
5 5
 import { defaultAvatar } from '@/utils/utils';
6
+import ChangePassword from '@/components/ChangePassword'
6 7
 import HeaderDropdown from '../HeaderDropdown';
7 8
 import styles from './index.less';
8 9
 
9 10
 class AvatarDropdown extends React.Component {
11
+  state = {
12
+    showPassword: false,
13
+  }
14
+
10 15
   onMenuClick = (event) => {
11 16
     const { key } = event;
12 17
 
@@ -22,7 +27,9 @@ class AvatarDropdown extends React.Component {
22 27
       return;
23 28
     }
24 29
 
25
-    history.push(`/account/${key}`);
30
+    if (key === 'password') {
31
+      this.setState({ showPassword: true })
32
+    }
26 33
   };
27 34
 
28 35
   render() {
@@ -32,12 +39,22 @@ class AvatarDropdown extends React.Component {
32 39
         userName: '',
33 40
       },
34 41
     } = this.props;
42
+
35 43
     const menuHeaderDropdown = (
36 44
       <Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
45
+        <Menu.Item key="password">
46
+          <FormOutlined />
47
+          修改密码
48
+        </Menu.Item>
37 49
         <Menu.Item key="logout">
38 50
           <LogoutOutlined />
39 51
           退出登录
40 52
         </Menu.Item>
53
+        <ChangePassword
54
+          visible={this.state.showPassword}
55
+          onVisibleChange={(v) => this.setState({ showPassword: v })}
56
+          onFinish={() => this.setState({ showPassword: false })}
57
+        />
41 58
       </Menu>
42 59
     );
43 60
     return currentUser && currentUser.userName ? (

+ 4
- 2
src/components/School/index.jsx Vedi File

@@ -7,6 +7,8 @@ export default (props) => {
7 7
   const [list, setList] = useState([])
8 8
   const [value, setValue] = useState()
9 9
 
10
+  const { autoDefault, ...selectProps } = props
11
+
10 12
   const filterFunc = (input, option) => {
11 13
     return option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
12 14
   }
@@ -31,7 +33,7 @@ export default (props) => {
31 33
       setList(records)
32 34
       setLoading(false)
33 35
 
34
-      if (props.autoDefault !== false && records.length > 0) {
36
+      if (autoDefault !== false && records.length > 0) {
35 37
         setValue(records[0].schoolId)
36 38
         props.onChange(records[0].schoolId, records[0])
37 39
       }
@@ -51,7 +53,7 @@ export default (props) => {
51 53
         showSearch
52 54
         optionFilterProp="children"
53 55
         filterOption={filterFunc}
54
-        {...props}
56
+        {...selectProps}
55 57
         value={value}
56 58
         onChange={handleChange}
57 59
       >

+ 140
- 0
src/pages/Post/Type/index.jsx Vedi File

@@ -0,0 +1,140 @@
1
+import React, { useEffect, useRef, useState } from 'react';
2
+import { connect } from 'umi';
3
+import { PageContainer } from '@ant-design/pro-layout';
4
+import ProTable from '@ant-design/pro-table';
5
+import { PlusOutlined } from '@ant-design/icons';
6
+import { Button, notification } from 'antd';
7
+import {
8
+  ModalForm,
9
+  ProFormText,
10
+} from '@ant-design/pro-form';
11
+import request, { queryTable } from '@/utils/request';
12
+
13
+const PostTypeList = (props) => {
14
+  const tableRef = useRef()
15
+  const form = useRef();
16
+  const [current, setCurrent] = useState({})
17
+  const [visible, setVisible] = useState(false)
18
+
19
+  const handleEdit = (postType) => {
20
+    const data = postType || {}
21
+    setCurrent(data)
22
+    setVisible(true)
23
+    if (form.current) {
24
+      form.current.setFieldsValue(data)
25
+    }
26
+  }
27
+
28
+  const emitPublishOrNot = (postType) => {
29
+    // 1 变成 0, 0 变成 1
30
+    const status = Math.abs(postType.status - 1)
31
+    request(`/post-type/${postType.typeId}`, { method: 'put', data: { ...postType, status } }).then(() => {
32
+      notification.success({ message: '操作成功' })
33
+      tableRef.current.reload()
34
+    }).catch((e) => {
35
+      notification.warn({ message: e.message })
36
+    })
37
+  }
38
+
39
+  const handleSubmit = (postType) => {
40
+    const method = current.typeId ? 'put' : 'post'
41
+    const api = current.typeId ? `/post-type/${current.typeId}` : '/post-type'
42
+    const data = { ...current, ...postType }
43
+    return request(api, { method, data }).then(() => {
44
+      notification.success({ message: '操作成功' })
45
+      tableRef.current.reload()
46
+      setVisible(false)
47
+    }).catch((e) => {
48
+      notification.warn({ message: e.message })
49
+    })
50
+  }
51
+
52
+  const actions = [
53
+    <Button key="button" icon={<PlusOutlined />} type="primary" onClick={handleEdit}>
54
+      新建
55
+    </Button>,
56
+  ];
57
+
58
+  const columns = [
59
+    {
60
+      title: '标题',
61
+      key: 'name',
62
+      dataIndex: 'name',
63
+    },
64
+    {
65
+      title: '状态',
66
+      key: 'status',
67
+      dataIndex: 'status',
68
+      width: 240,
69
+      valueType: 'select',
70
+      valueEnum: {
71
+        0: {
72
+          text: '下架',
73
+          status: 'Processing',
74
+        },
75
+        1: {
76
+          text: '上架',
77
+          status: 'Success',
78
+        },
79
+      },
80
+    },
81
+    {
82
+      title: '创建时间',
83
+      key: 'createDate',
84
+      dataIndex: 'createDate',
85
+      valueType: 'date',
86
+      width: 240,
87
+      hideInSearch: true,
88
+    },
89
+    {
90
+      title: '操作',
91
+      key: 'option',
92
+      valueType: 'option',
93
+      width: 160,
94
+      render: (_, item) => [
95
+        <a key="edit" onClick={() => handleEdit(item)}>
96
+          编辑
97
+        </a>,
98
+        <a key="up" onClick={() => emitPublishOrNot(item)}>
99
+          {item.status === 1 ? '下架' : '上架'}
100
+        </a>,
101
+      ],
102
+    },
103
+  ];
104
+
105
+  useEffect(() => {
106
+    if (!props.typeList || !props.typeList.length) {
107
+      props.dispatch({
108
+        type: 'post/getTypeList',
109
+        payload: { pageSize: 999 },
110
+      });
111
+    }
112
+  }, [props]);
113
+
114
+  return (
115
+    <PageContainer>
116
+      <ProTable
117
+        actionRef={tableRef}
118
+        columns={columns}
119
+        request={queryTable('/post-type')}
120
+        rowKey="typeId"
121
+        headerTitle="科普列表"
122
+        search={{
123
+          labelWidth: '4em',
124
+        }}
125
+        toolBarRender={() => actions}
126
+      />
127
+      <ModalForm formRef={form} width={600} visible={visible} onVisibleChange={setVisible} onFinish={handleSubmit}>
128
+        <ProFormText
129
+          label="名称"
130
+          name="name"
131
+          rules={[{ required: true, message: '请填写名称' }]}
132
+        />
133
+      </ModalForm>
134
+    </PageContainer>
135
+  );
136
+};
137
+
138
+export default connect((s) => ({
139
+  typeList: s.post.typeList,
140
+}))(PostTypeList);

+ 1
- 1
src/pages/Statistic/StudentData.jsx Vedi File

@@ -4,7 +4,7 @@ import { PageContainer } from '@ant-design/pro-layout';
4 4
 import ProTable from '@ant-design/pro-table';
5 5
 import request, { queryTable } from '@/utils/request';
6 6
 
7
-const StudentData = (props) => {
7
+const StudentData = () => {
8 8
   const tableRef = useRef()
9 9
   const [schoolDict, setSchoolDict] = useState({})
10 10
 

+ 15
- 4
src/pages/User/List/index.jsx Vedi File

@@ -35,6 +35,14 @@ export default () => {
35 35
     })
36 36
   }
37 37
 
38
+  const handleResetPassword = (user) => {
39
+    request(`/reset-password/${user.userId}`, { method: 'put' }).then(() => {
40
+      notification.success({ message: '操作成功' })
41
+    }).catch((e) => {
42
+      notification.error({ message: e.message })
43
+    })
44
+  }
45
+
38 46
   const columns = [
39 47
     {
40 48
       title: '编号',
@@ -77,12 +85,15 @@ export default () => {
77 85
       key: 'option',
78 86
       valueType: 'option',
79 87
       // 不能操作超级管理员
80
-      render: (_, user) => [
81
-        user.userId !== '1' && <a key="edit" onClick={() => handleEdit(user)}>修改</a>,
82
-        user.userId !== '1' && <a key="disable" onClick={() => changeStatus(user)}>{user.status === 1 ? '禁用' : '启用'}</a>,
83
-        user.userId !== '1' && <Popconfirm key="delete" title="确定删除当前人员?" onConfirm={() => handleDelete(user)}>
88
+      render: (_, user) => user.userId === '1' ? [] : [
89
+        <a key="edit" onClick={() => handleEdit(user)}>修改</a>,
90
+        <a key="disable" onClick={() => changeStatus(user)}>{user.status === 1 ? '禁用' : '启用'}</a>,
91
+        <Popconfirm key="delete" title="确定删除当前人员?" onConfirm={() => handleDelete(user)}>
84 92
           <a href="#">删除</a>
85 93
         </Popconfirm>,
94
+        <Popconfirm key="reset" title="确定重置用户密码?" onConfirm={() => handleResetPassword(user)}>
95
+          <a href="#">重置密码</a>
96
+        </Popconfirm>,
86 97
       ].filter(Boolean)
87 98
     },
88 99
   ]

+ 0
- 1
src/pages/Welcome/components/LineCard.jsx Vedi File

@@ -84,7 +84,6 @@ export default (props) => {
84 84
   const [params, setParams] = useState()
85 85
 
86 86
   useEffect(() => {
87
-    console.log('-------->', dtRange)
88 87
     if (dtRange) {
89 88
       setParams({
90 89
         startDate: dtRange[0].format('YYYY-MM-DD'),