张延森 4 years ago
parent
commit
35c07bdd83

+ 8
- 1
config/routes.js View File

@@ -202,7 +202,14 @@ export default [
202 202
                     path: '/system/user',
203 203
                     name: '用户管理',
204 204
                     menuCode: 'system.user',
205
-                    component: '../layouts/BlankLayout',
205
+                    component: './user/List',
206
+                  },
207
+                  {
208
+                    path: '/system/user/edit',
209
+                    name: '用户编辑',
210
+                    menuCode: 'system.user',
211
+                    component: './user/Edit',
212
+                    hideInMenu: true,
206 213
                   },
207 214
                   {
208 215
                     path: '/system/role',

+ 21
- 1
src/models/user.js View File

@@ -1,4 +1,5 @@
1
-import { queryCurrent, query as queryUsers } from '@/services/user';
1
+import { notification } from 'antd'
2
+import { queryCurrent, query as queryUsers, queryRoles } from '@/services/user';
2 3
 import { setAuthority } from '@/utils/authority';
3 4
 
4 5
 const UserModel = {
@@ -6,6 +7,7 @@ const UserModel = {
6 7
   state: {
7 8
     currentUser: {},
8 9
     menus: [],
10
+    roles: [],
9 11
   },
10 12
   effects: {
11 13
     *fetch(_, { call, put }) {
@@ -27,6 +29,20 @@ const UserModel = {
27 29
         //
28 30
       }
29 31
     },
32
+
33
+    *fetchRoles(_, { call, put }) {
34
+      try {
35
+        const response = yield call(queryRoles);
36
+        yield put({
37
+          type: 'updateRoles',
38
+          payload: response.records,
39
+        });
40
+      } catch (e) {
41
+        notification.error({
42
+          message: `获取角色失败: ${e.message}`
43
+        })
44
+      }
45
+    }
30 46
   },
31 47
   reducers: {
32 48
     saveCurrentUser(state, action) {
@@ -37,6 +53,10 @@ const UserModel = {
37 53
       return { ...state, currentUser: user, menus };
38 54
     },
39 55
 
56
+    updateRoles(state, { payload }) {
57
+      return { ...state, roles: payload || [] };
58
+    },
59
+
40 60
     changeNotifyCount(
41 61
       state = {
42 62
         currentUser: {},

+ 12
- 10
src/pages/Post/Edit/index.jsx View File

@@ -26,16 +26,18 @@ const PostEdit = (props) => {
26 26
   }
27 27
 
28 28
   useEffect(() => {
29
-    setLoading(true);
30
-    request(`/post/${id}`)
31
-      .then((res) => {
32
-        setPost(res);
33
-        setLoading(false);
34
-      })
35
-      .catch((e) => {
36
-        setLoading(false);
37
-        notification.error({ message: e.message });
38
-      });
29
+    if (id) {
30
+      setLoading(true);
31
+      request(`/post/${id}`)
32
+        .then((res) => {
33
+          setPost(res);
34
+          setLoading(false);
35
+        })
36
+        .catch((e) => {
37
+          setLoading(false);
38
+          notification.error({ message: e.message });
39
+        });
40
+    }
39 41
   }, [id]);
40 42
 
41 43
   useEffect(() => {

+ 21
- 7
src/pages/Post/List/index.jsx View File

@@ -1,16 +1,29 @@
1
-import React, { useEffect, useMemo, useCallback } from 'react';
1
+import React, { useEffect, useMemo, useCallback, useRef } from 'react';
2 2
 import { connect, history } from 'umi';
3 3
 import { PageContainer } from '@ant-design/pro-layout';
4 4
 import ProTable from '@ant-design/pro-table';
5 5
 import { PlusOutlined } from '@ant-design/icons';
6
-import { Button } from 'antd';
7
-import { queryTable } from '@/utils/request';
6
+import { Button, notification } from 'antd';
7
+import request, { queryTable } from '@/utils/request';
8 8
 
9 9
 const PostList = (props) => {
10
+  const tableRef = useRef()
11
+
10 12
   const handlePostClick = useCallback((post) => {
11 13
     history.push(post ? `/post/edit?id=${post.postId}` : '/post/edit');
12 14
   }, []);
13 15
 
16
+  const emitPublishOrNot = (post) => {
17
+    // 1 变成 0, 0 变成 1
18
+    const status = Math.abs(post.status - 1)
19
+    request(`/post/${post.postId}`, { method: 'put', data: { ...post, status } }).then(() => {
20
+      notification.success({ message: '操作成功' })
21
+      tableRef.current.reload()
22
+    }).catch((e) => {
23
+      notification.warn({ message: e.message })
24
+    })
25
+  }
26
+
14 27
   const actions = [
15 28
     <Button key="button" icon={<PlusOutlined />} type="primary" onClick={() => handlePostClick()}>
16 29
       新建
@@ -79,11 +92,11 @@ const PostList = (props) => {
79 92
       valueType: 'select',
80 93
       valueEnum: {
81 94
         0: {
82
-          text: '未发布',
83
-          status: 'Default',
95
+          text: '下架',
96
+          status: 'Processing',
84 97
         },
85 98
         1: {
86
-          text: '已发布',
99
+          text: '上架',
87 100
           status: 'Success',
88 101
         },
89 102
       },
@@ -104,7 +117,7 @@ const PostList = (props) => {
104 117
           编辑
105 118
         </a>,
106 119
         <a key="up" onClick={() => emitPublishOrNot(item)}>
107
-          下架
120
+          {item.status === 1 ? '下架' : '上架'}
108 121
         </a>,
109 122
       ],
110 123
     },
@@ -122,6 +135,7 @@ const PostList = (props) => {
122 135
   return (
123 136
     <PageContainer>
124 137
       <ProTable
138
+        actionRef={tableRef}
125 139
         columns={columns}
126 140
         request={queryTable('/post')}
127 141
         rowKey="postId"

+ 3
- 4
src/pages/Student/School/Edit/Specialty.jsx View File

@@ -1,6 +1,5 @@
1
-import React, { useRef, useCallback, useState } from 'react';
2
-import { connect, history } from 'umi';
3
-import { PageContainer } from '@ant-design/pro-layout';
1
+import React, { useRef, useState } from 'react';
2
+import { connect } from 'umi';
4 3
 import ProTable from '@ant-design/pro-table';
5 4
 import { PlusOutlined } from '@ant-design/icons';
6 5
 import { Button, Popconfirm, Modal, Space, notification } from 'antd';
@@ -52,7 +51,7 @@ const Specialty = (props) => {
52 51
   //       });
53 52
   //   };
54 53
 
55
-  const deleteSchoolClick = (id) => {
54
+  const deleteSchoolClick = () => {
56 55
       console.log(ref)
57 56
     ref.current.reload();
58 57
     //   request(`/specialty/${id}`, { method: 'delete' })

+ 28
- 35
src/pages/Student/School/Edit/components/SchoolFrom.jsx View File

@@ -3,49 +3,42 @@ import { connect } from 'umi';
3 3
 
4 4
 import ProForm, { ProFormText, ProFormTextArea } from '@ant-design/pro-form';
5 5
 import UploadImage from '@/components/UploadImage';
6
-import {  Form } from 'antd';
6
+import { Form } from 'antd';
7 7
 
8 8
 const SchoolFrom = (props) => {
9
-
10 9
   const [form] = Form.useForm();
11 10
   //   const [bannerData, setBannerData] = useState({});
12 11
 
13 12
   useEffect(() => {
14
- 
15
-        form.setFieldsValue(props.data);
16
-     
17
-  }, [props.data]);
18
-
13
+    form.setFieldsValue(props.data);
14
+  }, [props, form]);
19 15
 
20 16
   return (
21
-
22
-    
23
-        <ProForm form={form} onFinish={props.handleSubmit}>
24
-          <Form.Item
25
-            name="logo"
26
-            label="logo"
27
-            placeholder="请选择logo"
28
-            extra="支持jpg/png文件,且不超过500kb"
29
-            rules={[{ required: true, message: '请上传logo' }]}
30
-          >
31
-            <UploadImage />
32
-          </Form.Item>
33
-
34
-          <ProFormText
35
-            label="名称"
36
-            placeholder="输入名称"
37
-            name="name"
38
-            rules={[{ required: true, message: '请填写名称' }]}
39
-          />
40
-
41
-          <ProFormTextArea
42
-            label="简介"
43
-            placeholder="输入简介"
44
-            name="desc"
45
-            rules={[{ required: true, message: '请填写简介' }]}
46
-          />
47
-        </ProForm>
48
-
17
+    <ProForm form={form} onFinish={props.handleSubmit}>
18
+      <Form.Item
19
+        name="logo"
20
+        label="logo"
21
+        placeholder="请选择logo"
22
+        extra="支持jpg/png文件,且不超过500kb"
23
+        rules={[{ required: true, message: '请上传logo' }]}
24
+      >
25
+        <UploadImage />
26
+      </Form.Item>
27
+
28
+      <ProFormText
29
+        label="名称"
30
+        placeholder="输入名称"
31
+        name="name"
32
+        rules={[{ required: true, message: '请填写名称' }]}
33
+      />
34
+
35
+      <ProFormTextArea
36
+        label="简介"
37
+        placeholder="输入简介"
38
+        name="desc"
39
+        rules={[{ required: true, message: '请填写简介' }]}
40
+      />
41
+    </ProForm>
49 42
   );
50 43
 };
51 44
 

+ 2
- 3
src/pages/Student/School/Edit/components/SpecialtyModel.jsx View File

@@ -1,7 +1,6 @@
1
-import React, { useEffect } from 'react';
2
-import { connect } from 'umi';
1
+import React from 'react';
3 2
 
4
-import ProForm, { ProFormText, ProFormTextArea } from '@ant-design/pro-form';
3
+import ProForm, { ProFormText } from '@ant-design/pro-form';
5 4
 
6 5
 import { Form } from 'antd';
7 6
 

+ 3
- 12
src/pages/Student/Student/List/index.jsx View File

@@ -1,24 +1,15 @@
1
-import React, { useCallback, useState } from 'react';
1
+import React, { useCallback } from 'react';
2 2
 import { connect, history } from 'umi';
3 3
 import { PageContainer } from '@ant-design/pro-layout';
4 4
 import ProTable from '@ant-design/pro-table';
5
-import { PlusOutlined } from '@ant-design/icons';
6
-import { Button, Popconfirm, Image, Space, notification } from 'antd';
7
-import request, { queryTable } from '@/utils/request';
5
+import { Space } from 'antd';
6
+import { queryTable } from '@/utils/request';
8 7
 
9 8
 const StudentList = () => {
10
-  const [, setLoading] = useState(false);
11 9
   const handleStudentClick = useCallback((id) => {
12 10
     history.push(id ? `/student/student/edit?id=${id}` : '/student/student/edit');
13 11
   }, []);
14 12
 
15
-  const actions = [
16
-    <Button key="button" icon={<PlusOutlined />} type="primary" onClick={() => handleBannerClick()}>
17
-      新建
18
-    </Button>,
19
-  ];
20
-
21
-
22 13
   const columns = [
23 14
     {
24 15
       title: '编号',

+ 89
- 0
src/pages/User/Edit/components/Role.jsx View File

@@ -0,0 +1,89 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { connect } from 'umi'
3
+import { Button, Checkbox, Row, Col, Divider, notification } from 'antd'
4
+import request from '@/utils/request';
5
+
6
+const UserRole = (props) => {
7
+  const [loading, setLoading] = useState(false);
8
+  const [checkedList, setCheckedList] = useState([])
9
+  const [indeterminate, setIndeterminate] = useState(true);
10
+  const [checkAll, setCheckAll] = useState(false);
11
+  const [allRoles, setAllRoles] = useState([])
12
+
13
+  const handleChange = (list) => {
14
+    setCheckedList(list);
15
+    setIndeterminate(!!list.length && list.length < allRoles.length);
16
+    setCheckAll(list.length === allRoles.length);
17
+  }
18
+
19
+  const handleCheckAll = (e) => {
20
+    setCheckedList(e.target.checked ? allRoles : []);
21
+    setIndeterminate(false);
22
+    setCheckAll(e.target.checked);
23
+  }
24
+
25
+  const handleSubmit = () => {
26
+    if (props.user.userId) {
27
+      const data = checkedList.map((roleId) => ({ userId: props.user.userId, roleId }))
28
+      setLoading(true)
29
+      request(`/user-role/${props.user.userId}`, { method: 'post',  data })
30
+        .then((res) => {
31
+          props.onSubmit(res);
32
+          setLoading(false);
33
+          notification.success({ message: '操作成功' });
34
+        })
35
+        .catch((e) => {
36
+          setLoading(false);
37
+          notification.error({ message: e.message });
38
+        });
39
+    } else {
40
+      notification.error({ message: '请先保存用户信息' });
41
+    }
42
+  }
43
+
44
+  useEffect(() => {
45
+    if (!props.roleList?.length) {
46
+      props.dispatch({
47
+        type: 'user/fetchRoles',
48
+      })
49
+    } else {
50
+      setAllRoles(props.roleList.map((r) => r.roleId))
51
+    }
52
+
53
+    if (props.user.roleList) {
54
+      setCheckedList(props.user.roleList?.map((r) => r.roleId))
55
+    }
56
+
57
+    setIndeterminate(props.user.roleList?.length < props.roleList?.length);
58
+    setCheckAll(props.user.roleList?.length === props.roleList?.length);
59
+  }, [props])
60
+
61
+  return (
62
+    <div>
63
+      <Checkbox indeterminate={indeterminate} onChange={handleCheckAll} checked={checkAll}>
64
+        全选
65
+      </Checkbox>
66
+      <Divider />
67
+      <Checkbox.Group value={checkedList} onChange={handleChange} style={{ width: '100%' }}>
68
+        <Row>
69
+          {
70
+            (props.roleList || []).map((role) => {
71
+              return (
72
+                <Col span={8} key={role.roleId}>
73
+                  <Checkbox value={role.roleId}>{role.name}</Checkbox>
74
+                </Col>
75
+              )
76
+            })
77
+          }
78
+        </Row>
79
+      </Checkbox.Group>
80
+      <div style={{ marginTop: '3em' }}>
81
+        <Button type="primary" onClick={handleSubmit} loading={loading}>确定</Button>
82
+      </div>
83
+    </div>
84
+  )
85
+}
86
+
87
+export default connect((s) => ({
88
+  roleList: s.user.roles,
89
+}))(UserRole)

+ 60
- 0
src/pages/User/Edit/components/User.jsx View File

@@ -0,0 +1,60 @@
1
+import React, { useEffect } from 'react'
2
+import ProForm, {
3
+  ProFormText,
4
+} from '@ant-design/pro-form';
5
+import UploadImage from '@/components/UploadImage';
6
+import { notification, Form } from 'antd';
7
+import request from '@/utils/request';
8
+
9
+export default (props) => {
10
+  const [form] = Form.useForm();
11
+
12
+  const handleSubmit = (values) => {
13
+    if (!props.user?.userId) {
14
+      // 新增
15
+      request('/user', { method: 'post', data: values }).then(res => {
16
+        notification.success({ message: '新增用户成功' })
17
+        props.onChange(res)
18
+      }).catch((e) => {
19
+        notification.error({ message: e.message })
20
+      })
21
+    } else {
22
+      //
23
+    }
24
+  }
25
+
26
+  useEffect(() => {
27
+    if (props.user && props.user.userId) {
28
+      form.setFieldsValue(props.user);
29
+    }
30
+  }, [props.user, form]);
31
+
32
+  return (
33
+    <ProForm form={form} onFinish={handleSubmit}>
34
+      <ProFormText
35
+        label="姓名"
36
+        placeholder="请输入姓名"
37
+        name="userName"
38
+        rules={[{ required: true, message: '请填写姓名' }]}
39
+      />
40
+
41
+      <Form.Item name="avatar" label="头像" placeholder="请设置头像">
42
+        <UploadImage />
43
+      </Form.Item>
44
+
45
+      <ProFormText
46
+        label="手机号"
47
+        placeholder="请输入手机号"
48
+        name="phone"
49
+      />
50
+
51
+      <ProFormText
52
+        label="登录名"
53
+        placeholder="请设置用户登录名"
54
+        name="loginName"
55
+        rules={[{ required: true, message: '请设置用户登录名' }]}
56
+        extra="默认密码 abc@123 "
57
+      />
58
+    </ProForm>
59
+  )
60
+}

+ 56
- 0
src/pages/User/Edit/index.jsx View File

@@ -0,0 +1,56 @@
1
+import React, { useState, useEffect } from 'react'
2
+import { PageContainer } from '@ant-design/pro-layout';
3
+import { notification, Tabs } from 'antd';
4
+import Container from '@/components/Container';
5
+import request from '@/utils/request';
6
+import UserForm from './components/User'
7
+import UserRole from './components/Role'
8
+
9
+const { TabPane } = Tabs;
10
+
11
+export default (props) => {
12
+  const { id } = props.location.query;
13
+  const [loading, setLoading] = useState(false);
14
+  const [user, setUser] = useState({});
15
+
16
+  const handleRoleSubmit = (roleList) => {
17
+    setUser({
18
+      ...user,
19
+      roleList,
20
+    })
21
+  }
22
+
23
+  useEffect(() => {
24
+    if (id) {
25
+      setLoading(true);
26
+      request(`/user/${id}`)
27
+        .then((res) => {
28
+          setUser(res);
29
+          setLoading(false);
30
+        })
31
+        .catch((e) => {
32
+          setLoading(false);
33
+          notification.error({ message: e.message });
34
+        });
35
+    }
36
+  }, [id]);
37
+
38
+  return (
39
+    <PageContainer>
40
+    <Container>
41
+      <Tabs>
42
+        <TabPane tab="基本信息" key="1">
43
+          <Container loading={loading}>
44
+            <UserForm user={user} onChange={setUser} />
45
+          </Container>
46
+        </TabPane>
47
+        <TabPane tab="角色设置" key="2">
48
+          <Container>
49
+            <UserRole user={user} onSubmit={handleRoleSubmit} />
50
+          </Container>
51
+        </TabPane>
52
+      </Tabs>
53
+    </Container>
54
+    </PageContainer>
55
+  )
56
+}

+ 99
- 0
src/pages/User/List/index.jsx View File

@@ -0,0 +1,99 @@
1
+import React, { useRef } from 'react'
2
+import { history } 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, Popconfirm, notification } from 'antd';
7
+import request, { queryTable } from '@/utils/request';
8
+
9
+export default () => {
10
+  const tableRef = useRef()
11
+
12
+  const handleDelete = (user) => {
13
+    request(`/user/${user.userId}`, { method: 'delete' } ).then(() => {
14
+      notification.success({ message: '操作成功' })
15
+      tableRef.current.reload()
16
+    }).catch((e) => {
17
+      notification.error({ message: e.message })
18
+    })
19
+  }
20
+
21
+  const handleEdit = (user) => {
22
+    const url = user && user.userId ? `/system/user/edit?id=${user.userId}` : '/system/user/edit'
23
+    history.push(url)
24
+  }
25
+
26
+  const columns = [
27
+    {
28
+      title: '编号',
29
+      key: 'userId',
30
+      dataIndex: 'userId',
31
+      width: 200,
32
+      hideInSearch: true,
33
+    },
34
+    {
35
+      title: '姓名',
36
+      key: 'userName',
37
+      dataIndex: 'userName',
38
+    },
39
+    {
40
+      title: '电话',
41
+      key: 'phone',
42
+      dataIndex: 'phone',
43
+    },
44
+    {
45
+      title: '登录名',
46
+      key: 'loginName',
47
+      dataIndex: 'loginName',
48
+      hideInSearch: true,
49
+    },
50
+    {
51
+      title: '角色',
52
+      key: 'roleName',
53
+      dataIndex: 'roleName',
54
+      hideInSearch: true,
55
+    },
56
+    {
57
+      title: '创建时间',
58
+      key: 'createDate',
59
+      dataIndex: 'createDate',
60
+      valueType: 'date',
61
+      hideInSearch: true,
62
+    },
63
+    {
64
+      title: '操作',
65
+      key: 'option',
66
+      valueType: 'option',
67
+      // 不能操作超级管理员
68
+      render: (_, user) => [
69
+        user.userId !== '1' && <a key="edit" onClick={() => handleEdit(user)}>修改</a>,
70
+        user.userId !== '1' && <a key="disable">禁用</a>,
71
+        user.userId !== '1' && <Popconfirm key="delete" title="确定删除当前人员?" onConfirm={() => handleDelete(user)}>
72
+          <a href="#">删除</a>
73
+        </Popconfirm>,
74
+      ].filter(Boolean)
75
+    },
76
+  ]
77
+  
78
+  const actions = [
79
+    <Button key="button" icon={<PlusOutlined />} type="primary" onClick={handleEdit}>
80
+      新建
81
+    </Button>,
82
+  ];
83
+
84
+  return (
85
+    <PageContainer>
86
+      <ProTable
87
+        actionRef={tableRef}
88
+        columns={columns}
89
+        request={queryTable('/user')}
90
+        rowKey="userId"
91
+        headerTitle="用户列表"
92
+        search={{
93
+          labelWidth: '4em',
94
+        }}
95
+        toolBarRender={() => actions}
96
+      />
97
+    </PageContainer>
98
+  )
99
+}

+ 4
- 0
src/services/user.js View File

@@ -9,3 +9,7 @@ export async function queryCurrent() {
9 9
 export async function queryNotices() {
10 10
   return request('/notices');
11 11
 }
12
+
13
+export async function queryRoles() {
14
+  return request('/role', { params: { pageSize: 500 } });
15
+}