Browse Source

Merge branch 'dev' of http://git.ycjcjy.com/jgz/admin into dev

lisenzhou 2 years ago
parent
commit
6c88990b68

+ 1
- 1
src/layouts/AuthLayout/components/Container.jsx View File

@@ -1,5 +1,5 @@
1 1
 import React, { useEffect, useRef, useMemo, useState } from 'react';
2
-import { Layout, Spin } from 'antd';
2
+import { Layout } from 'antd';
3 3
 import { Outlet } from "react-router-dom";
4 4
 import PageTransition from './PageTransition';
5 5
 import Footer from './Footer';

+ 3
- 19
src/layouts/AuthLayout/components/Header/SplitMenu.jsx View File

@@ -1,28 +1,12 @@
1 1
 import React from 'react';
2 2
 import { Menu } from 'antd';
3
-import { useNavigate } from 'react-router-dom';
4 3
 
5 4
 export default (props) => {
6
-  const { items, onChange, location } = props;
5
+  const { items, location } = props;
7 6
 
8
-  const navigate = useNavigate();
9
-  const [selectedKeys, setSelectedKeys] = React.useState([]);
10
-
11
-  const renderItems = React.useMemo(() => items.map(x => ({ ...x, children: undefined })), [items]);
12
-
13
-  const rootPath = React.useMemo(() => `/${location.pathname.split('/')[1]}`, [location.pathname]);
14
-
15
-  const onClick = (item) => {
16
-    onChange(item.key);
17
-    // navigate(item.key);
18
-  };
19
-
20
-  React.useEffect(() => {
21
-    setSelectedKeys([rootPath]);
22
-    onChange(rootPath);
23
-  }, [rootPath]);
7
+  const selectedKeys = React.useMemo(() => `/${location.pathname.split('/')[1]}`, [location.pathname]);
24 8
 
25 9
   return (
26
-    <Menu className='split-menu' mode="horizontal" items={renderItems} selectedKeys={selectedKeys} onClick={onClick} />
10
+    <Menu className='split-menu' mode="horizontal" items={items} selectedKeys={selectedKeys} />
27 11
   )
28 12
 }

+ 2
- 2
src/layouts/AuthLayout/components/Header/index.jsx View File

@@ -10,7 +10,7 @@ import SplitMenu from './SplitMenu';
10 10
 const { Header } = Layout;
11 11
 
12 12
 export default (props) => {
13
-  const { menus, theme, location, onMenuChange } = props;
13
+  const { menus, theme, location } = props;
14 14
 
15 15
   const className = useMemo(() => classNames({
16 16
     'layout-header': true,
@@ -20,7 +20,7 @@ export default (props) => {
20 20
   return (
21 21
     <Header className={className}>
22 22
       <Logo />
23
-      <SplitMenu items={menus} location={location} onChange={onMenuChange} />
23
+      <SplitMenu items={menus} location={location} />
24 24
       <Space>
25 25
         <User />
26 26
         <Exit />

+ 0
- 29
src/layouts/AuthLayout/components/Menus.jsx View File

@@ -1,39 +1,10 @@
1 1
 import React, { useState } from 'react';
2
-import { useNavigate, useLocation } from "react-router-dom";
3 2
 import { Menu } from 'antd';
4 3
 
5
-const linkTo = url => {
6
-  const a = document.createElement('a');
7
-  a.href = item.key;
8
-  a.target = '_blank';
9
-  a.click();
10
-}
11
-
12 4
 const menuStyle = { height: '100%' };
13 5
 
14 6
 export default (props) => {
15 7
   const { theme, items, location } = props;
16
-  // const [selectedKeys, setSelectedKeys] = useState([]);
17
-
18
-  const navigate = useNavigate();
19
-
20
-  const onClick = (item) => {
21
-    // console.log(item);
22
-
23
-    if (item.key.indexOf('http') === 0) {
24
-      // http 开头说明是外部链接
25
-      linkTo(item.key);
26
-    } else {
27
-      // setSelectedKeys([item.key]);
28
-      navigate(item.key);
29
-    }
30
-  }
31
-
32
-  // React.useEffect(() => {
33
-  //   if (location.pathname) {
34
-  //     setSelectedKeys([location.pathname]);
35
-  //   }
36
-  // }, [location.pathname]);
37 8
 
38 9
   return (
39 10
     <Menu style={menuStyle} theme={theme} items={items} selectedKeys={[location.pathname]} />

+ 3
- 5
src/layouts/AuthLayout/components/RequireLogin.jsx View File

@@ -1,16 +1,14 @@
1 1
 import React, { useState, useEffect } from 'react';
2
-import { useLocation, Navigate } from "react-router-dom";
2
+import { Navigate } from "react-router-dom";
3 3
 import { useModel } from '@/store';
4
-import { queryCurrentUser } from '@/services/user';
5 4
 
6 5
 export default (props) => {
7
-  const { user, setUser } = useModel('user');
6
+  const { user, getCurrentUser } = useModel('user');
8 7
   const [userStatus, setUserStatus] = useState(user && user.id ? 1 : 0);
9 8
 
10 9
   useEffect(() => {
11 10
     if (!user || !user.id) {
12
-      queryCurrentUser().then((res) => {
13
-        setUser(res);
11
+      getCurrentUser().then(() => {
14 12
         setUserStatus(1);
15 13
       }).catch(() => {
16 14
         setUserStatus(-1);

+ 8
- 13
src/layouts/AuthLayout/index.jsx View File

@@ -2,7 +2,7 @@ import React, { useEffect, useRef, useMemo, useState } from 'react';
2 2
 import { Layout, Spin } from 'antd';
3 3
 import { useLocation, Outlet } from "react-router-dom";
4 4
 import { useModel } from '@/store';
5
-import { getItems } from '@/routes/menus';
5
+import { getMenuItems } from '@/routes/menus';
6 6
 import useRoute from '@/utils/hooks/useRoute';
7 7
 import RequireLogin from './components/RequireLogin';
8 8
 import SiderBar from './components/SiderBar';
@@ -14,20 +14,15 @@ import './style.less';
14 14
 
15 15
 export default (props) => {
16 16
   const { theme } = useModel('system');
17
-  const { user } = useModel('user');
18
-
19
-  const allMenus = useMemo(() => getItems(), []);
20
-  const [siderMenus, setSiderMenus] = useState([]);
21
-
17
+  const { user, menus } = useModel('user');
22 18
   const location = useLocation();
23 19
   const currentRoute = useRoute();
24 20
 
25
-  const onSplitMenuChange = (key) => {
26
-    const target = allMenus.filter(x => x.key === key)[0];
27
-    if (target) {
28
-      setSiderMenus(target.children || []);
29
-    }
30
-  }
21
+  const splitMenus = useMemo(() => menus.map(x => ({ ...x, children: undefined })), [menus]);
22
+  const siderMenus = useMemo(() => {
23
+    const target = menus.filter(x => location.pathname.indexOf(x.key) === 0)[0];
24
+    return target ? target.children :  [];
25
+  }, [menus, location.pathname]);
31 26
 
32 27
   return (
33 28
     <Spin spinning={!user} size="large">
@@ -38,7 +33,7 @@ export default (props) => {
38 33
             ? <Outlet />
39 34
             : (
40 35
               <Layout style={{ minHeight: '100vh' }}>
41
-                <Header theme={theme} menus={allMenus} location={location} onMenuChange={onSplitMenuChange} />
36
+                <Header theme={theme} menus={splitMenus} location={location} />
42 37
                 <Layout>
43 38
                   <SiderBar theme={theme} menus={siderMenus} location={location} />
44 39
                   <Container location={location} />

+ 5
- 3
src/layouts/Container.jsx View File

@@ -1,4 +1,5 @@
1 1
 import React from 'react';
2
+import { Typography } from 'antd';
2 3
 import { Outlet } from 'react-router-dom';
3 4
 import useRoute from '@/utils/hooks/useRoute';
4 5
 
@@ -6,14 +7,15 @@ const containerStyle = {
6 7
   margin: '24px 24px 0 24px',
7 8
   height: '100%',
8 9
 }
10
+const { Title } = Typography;
9 11
 
10 12
 export default (props) => {
11
-
12
-  const currentRoute = useRoute();
13
-  const style = currentRoute.meta && currentRoute.meta.noLayout ? { height: '100%' } : containerStyle;
13
+  const { meta = {} } = useRoute() || {};
14
+  const style = meta.noLayout ? { height: '100%' } : containerStyle;
14 15
 
15 16
   return (
16 17
     <div style={style}>
18
+      {/* { meta.title && !meta.noLayout && <Title level={4} style={{ paddingBottom: '12px' }}>{ meta.title }</Title> } */}
17 19
       <Outlet />
18 20
     </div>
19 21
   )

+ 2
- 2
src/pages/roles/list.jsx View File

@@ -93,8 +93,8 @@ export default (props) => {
93 93
 
94 94
   React.useEffect(() => {
95 95
     startLoading();
96
-    getRoleList({ pageSize: 100 }).then((res) => {
97
-      setList(res.records || []);
96
+    getRoleList().then((res = []) => {
97
+      setList(res);
98 98
       cancelLoading();
99 99
     }).catch(() => {
100 100
       cancelLoading();

+ 63
- 28
src/pages/roles/menus.jsx View File

@@ -2,59 +2,92 @@ import React from 'react';
2 2
 import { Button, Card, Tree, message } from 'antd';
3 3
 import useBool from '@/utils/hooks/useBool';
4 4
 import { arr2Tree, uniq } from '@/utils/array';
5
-import { getResourceList } from '@/services/role';
5
+import { getResourceList, authRoleResource } from '@/services/role';
6 6
 
7 7
 export default (props) => {
8 8
   const { role } = props;
9 9
   
10 10
   const [loading, startLoading, cancelLoading] = useBool();
11 11
   const [list, setList] = React.useState([]);
12
+  const [expandedKeys, setExpandedKeys] = React.useState([]);
12 13
   const [treeData, setTreeData] = React.useState([]);
13 14
   const treeDictRef = React.useRef();
14
-  const [checkedKeys, setCheckedKeys] = React.useState([]);
15
-  const checkedNodesRef = React.useState([]);
15
+  const [checkedKeys, setCheckedKeys] = React.useState({ checked: [], halfChecked: [] });
16
+  const keys = checkedKeys.checked.concat(checkedKeys.halfChecked);
16 17
 
17 18
   const title = role ? `${role.name} - 授权菜单` : '授权菜单';
18 19
 
19
-  const onCheck = (keys, info) => {
20
-    const { checkedNodes } = info;
21
-    checkedNodesRef.current = checkedNodes;
22
-    // const keys = checkedNodes.map(node => getKeysWithParent(node, treeDictRef.current));
23
-    // setCheckedKeys(uniq(keys));
24
-    setCheckedKeys(keys);
20
+  const getListData = () => {
21
+    return new Promise((resolve, reject) => {
22
+      getResourceList({ type: 'menu' }).then((res = []) => {
23
+        setList(res);
24
+        resolve(res)
25
+      }).catch(reject);
26
+    });
27
+  }
28
+
29
+  const onCheck = (keys, { halfCheckedKeys }) => {
30
+    setCheckedKeys({ checked: keys, halfChecked: halfCheckedKeys });
25 31
   };
26 32
 
27 33
   const onSubmit = () => {
28
-    if (!checkedNodesRef.current) {
29
-      return;
30
-    }
31
-
32
-    if (checkedNodesRef.current.length !== checkedKeys.length) {
33
-      message.warn('未知错误, 请刷新重试');
34
-      return;
34
+    // 如果一个都不选,代表清空授权
35
+    const data = [];
36
+    const roleId = role.id;
37
+    for (let resourceId of keys) {
38
+      data.push({ roleId, resourceId });
35 39
     }
36
-
37
-    const keys = checkedNodesRef.current.map(node => getKeysWithParent(node, treeDictRef.current));
38
-
39
-  }
40
-
41
-  React.useEffect(() => {
42 40
     startLoading();
43
-    getResourceList({ pageSize: 500, type: 'menu' }).then((res) => {
41
+    authRoleResource(roleId, data).then((res) => {
44 42
       cancelLoading();
45
-      setList(res.records || []);
46 43
     }).catch(() => {
47 44
       cancelLoading();
48 45
     })
49
-  }, []);
46
+  }
50 47
 
51 48
   React.useEffect(() => {
52
-    if (!role) {
53
-      setList([]);
49
+    const p = !list.length ? getListData : () => Promise.resolve(list);
50
+    if (!role || !role.id) {
51
+      p();
52
+    } else {
53
+      startLoading();
54
+      p().then((allData) => {
55
+        getResourceList({ type: 'menu', roleId: role.id }).then((res = []) => {
56
+          cancelLoading();
57
+          
58
+          // 数据分为2部分, 一部分叶子节点, 一部分非叶子节点
59
+          const checked = [], halfChecked = [];
60
+          for (let item of res) {
61
+            // 获取子节点, 没有的话则为叶子节点, 否则为非叶子节点
62
+            const children = allData.filter(x => x.parentId === item.id);
63
+            if (!children.length) {
64
+              // 没有子节点, 则为叶子节点, 算入选中节点
65
+              checked.push(item.id);
66
+            } else {
67
+              // 获取选中子节点
68
+              const checkedChildren = res.filter(x => x.parentId === item.id);
69
+              if (checkedChildren.length === children.length) {
70
+                // 非叶子节点如果 子节点全部包含, 那么算入选中节点
71
+                checked.push(item.id);
72
+              } else {
73
+                halfChecked.push(item.id);
74
+              }
75
+            }
76
+          }
77
+
78
+          setCheckedKeys({ checked, halfChecked });
79
+        }).catch(() => {
80
+          cancelLoading();
81
+        })
82
+      }).catch(() => {
83
+        cancelLoading();
84
+      })
54 85
     }
55 86
   }, [role]);
56 87
   
57 88
   React.useEffect(() => {
89
+    // 展开节点
90
+    setExpandedKeys((list).filter(x => x.parentId === -1).map(x => x.id));
58 91
     // 先转为需要的格式
59 92
     const arr = list.map(x => ({ title: x.name, key: x.id, parentId: x.parentId }));
60 93
     // 再转为 tree
@@ -67,15 +100,17 @@ export default (props) => {
67 100
     <Card
68 101
       loading={loading}
69 102
       title={title}
70
-      extra={<Button type='primary' ghost onClick={onSubmit}>保存</Button>}
103
+      extra={<Button type='primary' disabled={!role || !role.id} ghost onClick={onSubmit}>保存</Button>}
71 104
     >
72 105
       <Tree
73 106
         checkable
74 107
         autoExpandParent
108
+        expandedKeys={expandedKeys}
75 109
         checkStrictly={false}
76 110
         selectable={false}
77 111
         checkedKeys={checkedKeys}
78 112
         onCheck={onCheck}
113
+        onExpand={setExpandedKeys}
79 114
         treeData={treeData}
80 115
       />
81 116
     </Card>

+ 147
- 0
src/pages/user/Edit.jsx View File

@@ -0,0 +1,147 @@
1
+import React from 'react';
2
+import { Button, Card, Form, Input, Select } from 'antd';
3
+import useBool from '@/utils/hooks/useBool';
4
+import { getRoleList } from '@/services/role';
5
+import { saveUser, getUser } from '@/services/user';
6
+import { useSearchParams, useNavigate } from 'react-router-dom';
7
+import md5 from 'md5';
8
+
9
+const formItemLayout = {
10
+  labelCol: {
11
+    xs: { span: 24 },
12
+    sm: { span: 8 },
13
+  },
14
+  wrapperCol: {
15
+    xs: { span: 24 },
16
+    sm: { span: 16 },
17
+  },
18
+};
19
+const tailFormItemLayout = {
20
+  wrapperCol: {
21
+    xs: {
22
+      span: 24,
23
+      offset: 0,
24
+    },
25
+    sm: {
26
+      span: 16,
27
+      offset: 8,
28
+    },
29
+  },
30
+};
31
+
32
+const { Option } = Select;
33
+
34
+export default (props) => {
35
+  const [loading, startLoading, cancelLoading] = useBool();
36
+  const [submiting, startSubmit, cancelSubmit] = useBool();
37
+  const [roleList, setRoleList] = React.useState([]);
38
+  const [searchParams] = useSearchParams();
39
+  const [form] = Form.useForm();
40
+  const userRef = React.useRef();
41
+  const navigate = useNavigate();
42
+
43
+  const id = searchParams.get('id');
44
+
45
+  const onFinish = (values) => {
46
+    const password = values.password ? md5(values.password) : undefined;
47
+    const loginName = values.phone;
48
+    const rolesList = (values.rolesList || []).map(x => ({ id: x }));
49
+
50
+    startSubmit();
51
+    saveUser({ ...values, loginName, password, rolesList, id }).then(res => {
52
+      cancelSubmit();
53
+      navigate(-1);
54
+    }).catch(() => {
55
+      cancelSubmit();
56
+    });
57
+  }
58
+
59
+  React.useEffect(() => {
60
+    getRoleList().then(setRoleList);
61
+  }, []);
62
+  
63
+  React.useEffect(() => {
64
+    if (id) {
65
+      startLoading();
66
+      getUser(id).then(user => {
67
+        userRef.current = user;
68
+        form.setFieldsValue({
69
+          ...user,
70
+          rolesList: (user.rolesList || []).map(x => `${x.id}`),
71
+        });
72
+        cancelLoading();
73
+      }).catch(() => {
74
+        cancelLoading();
75
+      });
76
+    } else {
77
+      form.setFieldsValue({ password: '123456' });
78
+    }
79
+  }, [id]);
80
+
81
+  return (
82
+    <Card loading={loading}>
83
+      <Form onFinish={onFinish} form={form} {...formItemLayout} scrollToFirstError>
84
+        <Form.Item
85
+          name="name"
86
+          label="姓名"
87
+          rules={[
88
+            {
89
+              required: true,
90
+              message: '请填写姓名',
91
+            },
92
+          ]}
93
+        >
94
+          <Input />
95
+        </Form.Item>
96
+        <Form.Item
97
+          name="dept"
98
+          label="部门"
99
+        >
100
+          <Input />
101
+        </Form.Item>
102
+        <Form.Item
103
+          name="phone"
104
+          label="手机号"
105
+        >
106
+          <Input />
107
+        </Form.Item>
108
+        <Form.Item label="账号">
109
+          系统账号与手机号相同
110
+        </Form.Item>
111
+        <Form.Item
112
+          name="password"
113
+          label="密码"
114
+          extra={id ? '填写密码意味着重置该账户密码' : '默认密码 123456'}
115
+          hasFeedback
116
+        >
117
+          <Input.Password allowClear />
118
+        </Form.Item>
119
+        <Form.Item
120
+          name="rolesList"
121
+          label="角色"
122
+        >
123
+          <Select
124
+            mode="multiple"
125
+            allowClear
126
+            style={{ width: '100%' }}
127
+            placeholder="请选择角色"
128
+          >
129
+            {
130
+              roleList.map(role => (<Option key={role.id}>{role.name}</Option>))
131
+            }
132
+          </Select>
133
+        </Form.Item>
134
+        <Form.Item {...tailFormItemLayout}>
135
+          <Button loading={submiting} type="primary" htmlType="submit">
136
+            保存
137
+          </Button>
138
+          <Button style={{ marginLeft: '2em' }} onClick={() => navigate(-1)}>
139
+            返回
140
+          </Button>
141
+        </Form.Item>
142
+      </Form>
143
+    </Card>
144
+  )
145
+}
146
+
147
+

+ 0
- 79
src/pages/user/Role.jsx View File

@@ -1,79 +0,0 @@
1
-import React from 'react';
2
-import { Button, Row, Col, Card, List, Popconfirm, Tree, Space, Modal } from 'antd';
3
-import List from './list';
4
-
5
-export default (props) => {
6
-
7
-  const treeData = [
8
-    {
9
-      title: 'parent 1',
10
-      key: '0-0',
11
-      children: [
12
-        {
13
-          title: 'parent 1-0',
14
-          key: '0-0-0',
15
-          disabled: true,
16
-          children: [
17
-            {
18
-              title: 'leaf',
19
-              key: '0-0-0-0',
20
-              disableCheckbox: true,
21
-            },
22
-            {
23
-              title: 'leaf',
24
-              key: '0-0-0-1',
25
-            },
26
-          ],
27
-        },
28
-        {
29
-          title: 'parent 1-1',
30
-          key: '0-0-1',
31
-          children: [
32
-            {
33
-              title: (
34
-                <span
35
-                  style={{
36
-                    color: '#1890ff',
37
-                  }}
38
-                >
39
-                  sss
40
-                </span>
41
-              ),
42
-              key: '0-0-1-0',
43
-            },
44
-          ],
45
-        },
46
-      ],
47
-    },
48
-  ];
49
-
50
-  const onSelect = (selectedKeys, info) => {
51
-    console.log('selected', selectedKeys, info);
52
-  };
53
-  const onCheck = (checkedKeys, info) => {
54
-    console.log('onCheck', checkedKeys, info);
55
-  };
56
-
57
-  return (
58
-    <div>
59
-      <Row gutter={24}>
60
-        <Col span={8}>
61
-        </Col>
62
-        <Col span={16}>
63
-          <Card title='授权菜单' extra={<Button type='primary' ghost>保存</Button>}>
64
-            <Tree
65
-              checkable
66
-              defaultExpandedKeys={['0-0-0', '0-0-1']}
67
-              defaultSelectedKeys={['0-0-0', '0-0-1']}
68
-              defaultCheckedKeys={['0-0-0', '0-0-1']}
69
-              onSelect={onSelect}
70
-              onCheck={onCheck}
71
-              treeData={treeData}
72
-            />
73
-          </Card>
74
-        </Col>
75
-      </Row>
76
-
77
-    </div>
78
-  )
79
-}

+ 112
- 0
src/pages/user/index.jsx View File

@@ -0,0 +1,112 @@
1
+import React from 'react';
2
+import { useNavigate } from 'react-router-dom';
3
+import { queryTable } from '@/utils/request';
4
+import { ProTable } from '@ant-design/pro-components';
5
+import { Button, message, Popconfirm } from 'antd';
6
+import { getUserList, updateUserStatus } from '@/services/user';
7
+
8
+const queryUserList = queryTable(getUserList);
9
+
10
+export default (props) => {
11
+  const actionRef = React.useRef();
12
+  const navigate = useNavigate();
13
+
14
+  const updateStatus = (user) => {
15
+    const status = user.status === 1 ? 0 : 1;
16
+    const hide = message.loading('请稍候...', 0);
17
+    updateUserStatus(user.id, status).then(res => {
18
+      hide();
19
+      actionRef.current.reload();
20
+    }).catch(() => {
21
+      hide();
22
+    })
23
+  }
24
+
25
+  const columns = [
26
+    {
27
+      title: 'id',
28
+      dataIndex: 'id',
29
+      search: false,
30
+    },
31
+    {
32
+      title: '姓名',
33
+      dataIndex: 'name',
34
+    },
35
+    {
36
+      title: '部门',
37
+      dataIndex: 'dept',
38
+    },
39
+    {
40
+      title: '手机号',
41
+      dataIndex: 'phone',
42
+    },
43
+    {
44
+      title: '账号',
45
+      dataIndex: 'loginName',
46
+      search: false,
47
+    },
48
+    {
49
+      title: '状态',
50
+      dataIndex: 'status',
51
+      search: false,
52
+      valueEnum: {
53
+        1: {
54
+          text: '正常',
55
+          status: 'Processing',
56
+        },
57
+        0: {
58
+          text: '禁用',
59
+          status: 'Error',
60
+        },
61
+      },
62
+    },
63
+    {
64
+      title: '操作',
65
+      valueType: 'option',
66
+      width: 200,
67
+      render: (_, record) => [
68
+        <Button
69
+          key={1}
70
+          style={{ padding: 0 }}
71
+          type="link"
72
+          onClick={() => {
73
+            updateStatus(record);
74
+          }}
75
+        >
76
+          {record.status === 1 ? '禁用' : '启用'}
77
+        </Button>,
78
+        <Button
79
+          key={2}
80
+          style={{ padding: 0 }}
81
+          type="link"
82
+          onClick={() => {
83
+            console.log(record, ']]');
84
+            navigate(`/system/user/edit?id=${record.id}`);
85
+          }}
86
+        >
87
+          编辑
88
+        </Button>,
89
+      ],
90
+    },
91
+  ]
92
+
93
+  return (
94
+    <ProTable
95
+      actionRef={actionRef}
96
+      rowKey="id"
97
+      toolBarRender={() => [
98
+        <Button
99
+          key="1"
100
+          type="primary"
101
+          onClick={() => {
102
+            navigate('/system/user/edit');
103
+          }}
104
+        >
105
+          新增
106
+        </Button>,
107
+      ]}
108
+      request={queryUserList}
109
+      columns={columns}
110
+    />
111
+  )
112
+}

+ 13
- 4
src/routes/Router.jsx View File

@@ -1,9 +1,18 @@
1
+import React from "react";
1 2
 import { createHashRouter, RouterProvider } from "react-router-dom";
2
-import routes from './routes'
3
-
4
-const router = createHashRouter(routes);
5
-export const hashRouter = true;
3
+import { useModel } from "@/store";
4
+import { defaultRoutes } from './routes';
6 5
 
7 6
 export default (props) => {
7
+  const { routes } = useModel('user');
8
+
9
+  const router = React.useMemo(() => {
10
+    if (!routes || routes.length < 1) {
11
+      return createHashRouter(defaultRoutes);
12
+    } else {
13
+      return createHashRouter(routes);
14
+    }
15
+  }, [routes]);
16
+
8 17
   return <RouterProvider router={router} />
9 18
 }

+ 12
- 41
src/routes/menus.jsx View File

@@ -1,8 +1,4 @@
1 1
 import { Link } from 'react-router-dom';
2
-import routes from './routes';
3
-import { hashRouter } from './Router';
4
-
5
-let routeArr = [];
6 2
 
7 3
 // 菜单是否显示
8 4
 // 没有 meta 或者 meta.title 为空, 或者 meta.hideInMenu = true 的 都不显示
@@ -20,55 +16,30 @@ const getPath = (parent, current = '') => {
20 16
   return `${parent}/${current}`.replace(/\/\//g, '/');
21 17
 }
22 18
 
23
-const getMenuItems = (dts = [], fullPath = '/') => {
24
-  return dts.map(item => {
25
-    const path = getPath(fullPath, item.path);
19
+export const getMenuItems = (routes = [], fullPath = '/') => {
20
+  return routes.map(route => {
21
+    const path = getPath(fullPath, route.path);
26 22
 
27 23
     //
28
-    if (!isShow(item)) return false;
24
+    if (!isShow(route)) return false;
29 25
     
30
-    const children = hasChildren(item.children) ? getMenuItems(item.children, path) : false;
26
+    const children = hasChildren(route.children) ? getMenuItems(route.children, path) : false;
27
+
28
+    const { target, title, icon } = route.meta || {}
31 29
 
32 30
     // 坑爹 react-router v6 不支持 hash 路由的 target 跳转
33
-    const label = hashRouter && item.meta && item.meta.target === '_blank' ?
34
-      <a href={`${window.location.pathname}#${path}`} target={item.meta.target}>{item.meta.title}</a>
35
-      : <Link to={path} target={item.meta.target}>{item.meta.title}</Link>;
31
+    const label = target === '_blank' ?
32
+      <a href={`${window.location.pathname}#${path}`} target={target}>{title}</a>
33
+      : <Link to={path} target={target}>{title}</Link>;
36 34
 
37 35
     return Object.assign(
38 36
       {
39 37
         key: path,
40 38
         label,
41
-        title: item.meta.title,
42
-        icon: item.meta.icon,
39
+        title,
40
+        icon,
43 41
       },
44 42
       children && { children },
45 43
     )
46 44
   }).filter(Boolean);
47 45
 }
48
-
49
-const flatten = (routes, parent) => {
50
-  (routes || []).forEach((route) => {
51
-    const path = getPath(parent, route.path);
52
-    routeArr.push({
53
-      ...route,
54
-      path
55
-    });
56
-
57
-    if (route.children) {
58
-      flatten(route.children, path);
59
-    }
60
-  });
61
-}
62
-
63
-const getItems = () => getMenuItems(routes[0]?.children);
64
-const getRouteArr = () => {
65
-  if (routeArr.length < 1) {
66
-    flatten(routes, '/');
67
-  }
68
-  return routeArr;
69
-}
70
-// 
71
-export {
72
-  getItems,
73
-  getRouteArr,
74
-};

+ 14
- 0
src/routes/permissions.js View File

@@ -0,0 +1,14 @@
1
+
2
+export const getAuthedRoutes = (routes, permissions) => {
3
+  if (!routes || routes.length < 1) return [];
4
+
5
+  return routes.map(route => {
6
+    if (route.meta && route.meta.permission && permissions.indexOf(route.meta.permission) < 0) return false;
7
+
8
+    if (route.children) {
9
+      route.children = getAuthedRoutes(route.children, permissions);
10
+    }
11
+
12
+    return route;
13
+  }).filter(Boolean);
14
+}

+ 306
- 303
src/routes/routes.jsx View File

@@ -1,3 +1,36 @@
1
+
2
+首页
3
+探索
4
+帮助
5
+注册
6
+登录
7
+ jgz / admin
8
+关注
9
+3
10
+ 
11
+点赞
12
+0
13
+ 
14
+派生
15
+0
16
+代码
17
+工单
18
+0
19
+合并请求
20
+0
21
+版本发布
22
+0
23
+百科
24
+动态
25
+ 55 提交
26
+ 2 分支
27
+ 分支: dev 
28
+admin/src/routes/routes.jsx
29
+routes.jsx 7.5KB
30
+永久链接
31
+文件历史
32
+原始文件
33
+  
1 34
 import {
2 35
   AppstoreOutlined,
3 36
   ContainerOutlined,
@@ -6,37 +39,33 @@ import {
6 39
   MenuFoldOutlined,
7 40
   MenuUnfoldOutlined,
8 41
   PieChartOutlined,
9
-} from "@ant-design/icons";
10
-import { Navigate } from "react-router-dom";
11
-import AuthLayout from "@/layouts/AuthLayout";
12
-import Container from "@/layouts/Container";
13
-import Login from "@/pages/login";
14
-import Page404 from "@/pages/404";
15
-import Home from "@/pages/sample/home";
16
-import BasicForm from "@/pages/sample/form";
17
-import BasicTable from "@/pages/sample/table";
18
-import GuaranteeTaskList from "@/pages/guaranteeTask";
19
-import GuaranteeTaskEdit from "@/pages/guaranteeTask/Edit";
20
-import GuaranteeTaskPrint from "@/pages/guaranteeTask/print";
21
-import EmergencyPlanList from "@/pages/cms/emergencyPlan/list";
22
-import EmergencyPlanEdit from "@/pages/cms/emergencyPlan/edit";
23
-import DishList from "@/pages/dish/list";
24
-import DishEdit from "@/pages/dish/edit";
25
-import PackageList from "@/pages/package/List";
26
-import StockList from "@/pages/stock/list";
27
-import StockEdit from "@/pages/stock/edit";
28
-import StockInOut from "@/pages/stock/outAndIn";
29
-import StockLog from "@/pages/stock/stockLog";
30
-import StockClassificationList from "@/pages/stockClassification/list";
31
-import StockClassificationEdit from "@/pages/stockClassification/edit";
32
-import RotationChartList from "@/pages/rotationChart/list";
33
-import RotationChartEdit from "@/pages/rotationChart/edit";
34
-import RotationChartIntroduction from "@/pages/rotationChart/introduction";
35
-import Roles from "@/pages/roles/index";
36
-import PurchasePlanList from "@/pages/purchase/plan/list";
37
-import PurchasePlanEdit from "@/pages/purchase/plan/edit";
38
-import PurchaseBillEdit from "@/pages/purchase/bill/edit";
39
-import PurchaseInStoreEdit from "@/pages/purchase/inStore/edit";
42
+} from '@ant-design/icons';
43
+import { Navigate } from 'react-router-dom';
44
+import AuthLayout from '@/layouts/AuthLayout';
45
+import Container from '@/layouts/Container';
46
+import Login from '@/pages/login';
47
+import Page404 from '@/pages/404';
48
+import Home from '@/pages/sample/home';
49
+import BasicForm from '@/pages/sample/form';
50
+import BasicTable from '@/pages/sample/table';
51
+import GuaranteeTaskList from '@/pages/guaranteeTask';
52
+import GuaranteeTaskEdit from '@/pages/guaranteeTask/Edit';
53
+import GuaranteeTaskPrint from '@/pages/guaranteeTask/print';
54
+import DishList from '@/pages/dish/list';
55
+import DishEdit from '@/pages/dish/edit';
56
+import PackageList from '@/pages/package/List';
57
+import StockList from '@/pages/stock/list';
58
+import StockEdit from '@/pages/stock/edit';
59
+import StockInOut from '@/pages/stock/outAndIn';
60
+import StockLog from '@/pages/stock/stockLog';
61
+import StockClassificationList from '@/pages/stockClassification/list';
62
+import StockClassificationEdit from '@/pages/stockClassification/edit';
63
+import RotationChartList from '@/pages/rotationChart/list';
64
+import RotationChartEdit from '@/pages/rotationChart/edit';
65
+import RotationChartIntroduction from '@/pages/rotationChart/introduction';
66
+import Roles from '@/pages/roles/index';
67
+import UserList from '@/pages/user';
68
+import UserEdit from '@/pages/user/Edit';
40 69
 
41 70
 /**
42 71
  * meta 用来扩展自定义数据数据
@@ -48,321 +77,295 @@ import PurchaseInStoreEdit from "@/pages/purchase/inStore/edit";
48 77
  * }
49 78
  */
50 79
 
51
-export default [
80
+export const authRoutes = [
52 81
   {
53
-    path: "/",
54
-    element: <AuthLayout />,
82
+    path: 'task',
83
+    element: <Container />,
84
+    meta: {
85
+      title: '军供任务',
86
+      icon: <AppstoreOutlined />,
87
+    },
55 88
     children: [
56 89
       {
57 90
         index: true,
58
-        element: <Home />,
91
+        element: <Navigate to='guaranteeTask' replace />,
59 92
       },
60 93
       {
61
-        path: "home",
62
-        element: <Home />,
94
+        path: 'guaranteeTask',
95
+        element: <GuaranteeTaskList />,
63 96
         meta: {
64
-          title: "首页",
65
-          icon: <DesktopOutlined />,
97
+          title: '军供通报',
98
+        },
99
+      },
100
+      {
101
+        path: 'guaranteeTask/edit',
102
+        element: <GuaranteeTaskEdit />,
103
+        meta: {
104
+          title: '任务配置',
105
+        },
106
+      },
107
+      {
108
+        path: 'guaranteeTask/print',
109
+        element: <GuaranteeTaskPrint />,
110
+        meta: {
111
+          hideInMenu: true,
112
+          noLayout: true,
113
+          target: '_blank',
114
+          title: '任务执行',
115
+        },
116
+      }
117
+    ]
118
+  },
119
+  {
120
+    path: 'material',
121
+    element: <Container />,
122
+    meta: {
123
+      title: '物资管理',
124
+      icon: <AppstoreOutlined />,
125
+    },
126
+    children: [
127
+      {
128
+        index: true,
129
+        element: <Navigate to='dish/list' replace />,
130
+      },
131
+      {
132
+        path: 'dish/list',
133
+        element: <DishList />,
134
+        meta: {
135
+          title: '菜肴管理',
136
+        },
137
+      },
138
+      {
139
+        path: 'dish/edit',
140
+        element: <DishEdit />,
141
+        meta: {
142
+          hideInMenu: true,
143
+          title: '菜肴维护',
66 144
         },
67 145
       },
68 146
       {
69
-        path: "task",
70
-        element: <Container />,
147
+        path: 'package/list',
148
+        element: <PackageList />,
71 149
         meta: {
72
-          title: "军供任务",
73
-          icon: <AppstoreOutlined />,
150
+          title: '套餐管理',
74 151
         },
75
-        children: [
76
-          {
77
-            index: true,
78
-            element: <Navigate to="guaranteeTask" replace />,
79
-          },
80
-          {
81
-            path: "guaranteeTask",
82
-            element: <GuaranteeTaskList />,
83
-            meta: {
84
-              title: "军供通报",
85
-            },
86
-          },
87
-          {
88
-            path: "guaranteeTask/edit",
89
-            element: <GuaranteeTaskEdit />,
90
-            meta: {
91
-              title: "任务配置",
92
-            },
93
-          },
94
-          {
95
-            path: "guaranteeTask/print",
96
-            element: <GuaranteeTaskPrint />,
97
-            meta: {
98
-              hideInMenu: true,
99
-              noLayout: true,
100
-              target: "_blank",
101
-              title: "任务执行",
102
-            },
103
-          },
104
-        ],
105 152
       },
153
+    ]
154
+  },
155
+  {
156
+    path: 'stock',
157
+    element: <Container />,
158
+    meta: {
159
+      title: '库存管理',
160
+      icon: <AppstoreOutlined />,
161
+    },
162
+    children: [
163
+      {
164
+        index: true,
165
+        element: <Navigate to='list' replace />,
166
+      },
167
+      {
168
+        path: 'list',
169
+        element: <StockList />,
170
+        meta: {
171
+          title: '库存列表',
172
+        },
173
+      },
174
+      {
175
+        path: 'add',
176
+        element: <StockEdit />,
177
+        meta: {
178
+          title: '库存维护',
179
+        },
180
+      },
181
+    ],
182
+  },
183
+  {
184
+    path: 'cms',
185
+    element: <Container />,
186
+    meta: {
187
+      title: '公告文件',
188
+    },
189
+    children: [
106 190
       {
107
-        path: "material",
108
-        element: <Container />,
191
+        index: true,
192
+        element: <Navigate to='rotationChart/list' replace />,
193
+      },
194
+      {
195
+        path: 'station',
196
+        element: null,
109 197
         meta: {
110
-          title: "物资管理",
111
-          icon: <AppstoreOutlined />,
198
+          title: '本站信息',
112 199
         },
113
-        children: [
114
-          {
115
-            index: true,
116
-            element: <Navigate to="dish/list" replace />,
117
-          },
118
-          {
119
-            path: "dish/list",
120
-            element: <DishList />,
121
-            meta: {
122
-              title: "菜肴管理",
123
-            },
124
-          },
125
-          {
126
-            path: "dish/edit",
127
-            element: <DishEdit />,
128
-            meta: {
129
-              hideInMenu: true,
130
-              title: "菜肴维护",
131
-            },
132
-          },
133
-          {
134
-            path: "package/list",
135
-            element: <PackageList />,
136
-            meta: {
137
-              title: "套餐管理",
138
-            },
139
-          },
140
-        ],
141 200
       },
142 201
       {
143
-        path: "stock",
144
-        element: <Container />,
202
+        path: 'rotationChart/list',
203
+        element: <RotationChartList />,
145 204
         meta: {
146
-          title: "库存管理",
147
-          icon: <AppstoreOutlined />,
205
+          title: '公告内容',
148 206
         },
149
-        children: [
150
-          {
151
-            index: true,
152
-            element: <Navigate to="list" replace />,
153
-          },
154
-          {
155
-            path: "list",
156
-            element: <StockList />,
157
-            meta: {
158
-              title: "库存列表",
159
-            },
160
-          },
161
-          {
162
-            path: "add",
163
-            element: <StockEdit />,
164
-            meta: {
165
-              title: "库存维护",
166
-            },
167
-          },
168
-        ],
169 207
       },
170 208
       {
171
-        path: "cms",
172
-        element: <Container />,
209
+        path: 'rotationChart/edit',
210
+        element: <RotationChartEdit />,
173 211
         meta: {
174
-          title: "公告文件",
212
+          title: '公告维护',
175 213
         },
176
-        children: [
177
-          {
178
-            index: true,
179
-            element: <Navigate to="rotationChart/list" replace />,
180
-          },
181
-          {
182
-            path: "station",
183
-            element: null,
184
-            meta: {
185
-              title: "本站信息",
186
-            },
187
-          },
188
-          {
189
-            path: "rotationChart/list",
190
-            element: <RotationChartList />,
191
-            meta: {
192
-              title: "公告内容",
193
-            },
194
-          },
195
-          {
196
-            path: "rotationChart/edit",
197
-            element: <RotationChartEdit />,
198
-            meta: {
199
-              title: "公告维护",
200
-            },
201
-          },
202
-          {
203
-            path: "rotationChart/introduction",
204
-            element: <RotationChartIntroduction />,
205
-            meta: {
206
-              title: "本站信息简介",
207
-            },
208
-          },
209
-          {
210
-            path: "regulation",
211
-            element: null,
212
-            meta: {
213
-              title: "规章制度",
214
-            },
215
-          },
216
-          {
217
-            path: "emergency-plan",
218
-            element: <EmergencyPlanList />,
219
-            meta: {
220
-              title: "应急预案",
221
-            },
222
-          },
223
-          {
224
-            path: "emergency-plan/edit",
225
-            element: <EmergencyPlanEdit />,
226
-            meta: {
227
-              title: "应急预案维护",
228
-              hideInMenu: true,
229
-            },
230
-          },
231
-          {
232
-            path: "files",
233
-            element: null,
234
-            meta: {
235
-              title: "文件管理",
236
-            },
237
-          },
238
-        ],
239 214
       },
240 215
       {
241
-        path: "static",
242
-        element: <Container />,
216
+        path: 'rotationChart/introduction',
217
+        element: <RotationChartIntroduction />,
243 218
         meta: {
244
-          title: "数据分析",
219
+          title: '本站信息简介',
245 220
         },
246 221
       },
247 222
       {
248
-        path: "system",
249
-        element: <Container />,
223
+        path: 'regulation',
224
+        element: null,
250 225
         meta: {
251
-          title: "系统管理",
226
+          title: '规章制度',
252 227
         },
253
-        children: [
254
-          {
255
-            index: true,
256
-            element: <Navigate to="stockClassification/list" replace />,
257
-          },
258
-          {
259
-            path: "stockClassification/list",
260
-            element: <StockClassificationList />,
261
-            meta: {
262
-              title: "库存分类管理",
263
-            },
264
-          },
265
-          {
266
-            path: "stockClassification/edit",
267
-            element: <StockClassificationEdit />,
268
-            meta: {
269
-              title: "库存分类维护",
270
-              hideInMenu: true,
271
-            },
272
-          },
273
-          {
274
-            path: "log",
275
-            element: <StockLog />,
276
-            meta: {
277
-              title: "库存操作日志",
278
-            },
279
-          },
280
-          {
281
-            path: "roles",
282
-            element: <Roles />,
283
-            meta: {
284
-              title: "系统角色管理",
285
-            },
286
-          },
287
-          {
288
-            path: "user",
289
-            element: null,
290
-            meta: {
291
-              title: "系统用户管理",
292
-            },
293
-          },
294
-        ],
295 228
       },
296 229
       {
297
-        path: "purchase",
298
-        element: <Container />,
230
+        path: 'emergency-plan',
231
+        element: null,
299 232
         meta: {
300
-          title: "采购管理",
233
+          title: '应急预案',
301 234
         },
302
-        children: [
303
-          {
304
-            index: true,
305
-            element: <Navigate to="plan/list" replace />,
306
-          },
307
-          {
308
-            path: "plan/list",
309
-            element: <PurchasePlanList type="plan" />,
310
-            meta: {
311
-              title: "采购计划",
312
-            },
313
-          },
314
-          {
315
-            path: "plan/edit",
316
-            element: <PurchasePlanEdit />,
317
-            meta: {
318
-              title: "采购计划维护",
319
-              hideInMenu: true,
320
-            },
321
-          },
322
-          {
323
-            path: "bill/list",
324
-            element: <PurchasePlanList type="bill" />,
325
-            meta: {
326
-              title: "采购账单",
327
-            },
328
-          },
329
-          {
330
-            path: "bill/edit",
331
-            element: <PurchaseBillEdit />,
332
-            meta: {
333
-              title: "采购账单维护",
334
-              hideInMenu: true,
335
-            },
336
-          },
337
-          {
338
-            path: "inStore/list",
339
-            element: <PurchasePlanList type="inStore" />,
340
-            meta: {
341
-              title: "采购入库",
342
-            },
343
-          },
344
-          {
345
-            path: "inStore/edit",
346
-            element: <PurchaseInStoreEdit  />,
347
-            meta: {
348
-              title: "采购入库维护",
349
-              hideInMenu: true,
350
-            },
351
-          },
352
-        ],
353 235
       },
354 236
       {
355
-        path: "*",
356
-        element: <Page404 />,
237
+        path: 'files',
238
+        element: null,
239
+        meta: {
240
+          title: '文件管理',
241
+        },
357 242
       },
358 243
     ],
359 244
   },
360 245
   {
361
-    path: "/login",
362
-    element: <Login />,
246
+    path: 'static',
247
+    element: <Container />,
248
+    meta: {
249
+      title: '数据分析',
250
+    },
251
+  },
252
+  {
253
+    path: 'system',
254
+    element: <Container />,
255
+    meta: {
256
+      title: '系统管理',
257
+    },
258
+    children: [
259
+      {
260
+        index: true,
261
+        element: <Navigate to='stockClassification/list' replace />,
262
+      },
263
+      {
264
+        path: 'stockClassification/list',
265
+        element: <StockClassificationList />,
266
+        meta: {
267
+          title: '库存分类管理',
268
+        },
269
+      },
270
+      {
271
+        path: 'stockClassification/edit',
272
+        element: <StockClassificationEdit />,
273
+        meta: {
274
+          title: '库存分类维护',
275
+          hideInMenu: true,
276
+        },
277
+      },
278
+      {
279
+        path: 'log',
280
+        element: <StockLog />,
281
+        meta: {
282
+          title: '库存操作日志',
283
+        },
284
+      },
285
+      {
286
+        path: 'roles',
287
+        element: <Roles />,
288
+        meta: {
289
+          title: '系统角色管理',
290
+        },
291
+      },
292
+      {
293
+        path: 'user',
294
+        element: <UserList />,
295
+        meta: {
296
+          title: '系统用户管理',
297
+        },
298
+      },
299
+      {
300
+        path: 'user/edit',
301
+        element: <UserEdit />,
302
+        meta: {
303
+          hideInMenu: true,
304
+          title: '系统用户编辑',
305
+        },
306
+      }
307
+    ],
308
+  },
309
+]
310
+
311
+export const defaultRoutes = [
312
+  {
313
+    path: '/',
314
+    element: <AuthLayout />,
315
+    children: [
316
+      {
317
+        index: true,
318
+        element: <Home />,
319
+      },
320
+      {
321
+        path: 'home',
322
+        element: <Home />,
323
+        meta: {
324
+          title: '首页',
325
+          icon: <DesktopOutlined />,
326
+        },
327
+      },
328
+      {
329
+        path: '*',
330
+        element: <Page404 />
331
+      }
332
+    ],
363 333
   },
364 334
   {
365
-    path: "*",
366
-    element: <Page404 />,
335
+    path: '/login',
336
+    element: <Login />,
367 337
   },
338
+  {
339
+    path: '*',
340
+    element: <Page404 />
341
+  }
368 342
 ];
343
+
344
+export function mergeAuthRoutes (r1, r2) {
345
+  const r = r1.slice();
346
+  const children = r1[0].children.slice();
347
+  r[0].children = children.concat(r2);
348
+  return r;
349
+}
350
+
351
+// 全部路由
352
+export const routes = mergeAuthRoutes(defaultRoutes, authRoutes);
353
+
354
+function getPath(parent = '/', current = '') {
355
+  if (current.indexOf('/') === 0 || current.indexOf('http') === 0) return current;
356
+  return `${parent}/${current}`.replace(/\/\//g, '/');
357
+}
358
+
359
+// 路由数组, 一维数组
360
+export const routeArr = (() => {
361
+  const flatten = (routes, parentPath = '/') => {
362
+    return routes.reduce((acc, route) => {
363
+      const path = getPath(parentPath, route.path);
364
+      const children = route.children ? flatten(route.children, path) : [];
365
+      
366
+      return acc.concat([{ ...route, path }].concat(children));
367
+    }, []);
368
+  }
369
+
370
+  return flatten(routes);
371
+})();

+ 4
- 1
src/services/role.js View File

@@ -1,4 +1,4 @@
1
-import { restful } from '@/utils/request';
1
+import request,  { restful } from '@/utils/request';
2 2
 
3 3
 /**
4 4
  * 构造 Service
@@ -35,3 +35,6 @@ import { restful } from '@/utils/request';
35 35
   updateResource,
36 36
   deleteResource,
37 37
  }
38
+
39
+// 授权菜单
40
+ export const authRoleResource = (roleId, data) => request.post(`/role/${roleId}/Resources`, data);

+ 25
- 1
src/services/user.js View File

@@ -1,4 +1,4 @@
1
-import request from '@/utils/request';
1
+import request, { restful } from '@/utils/request';
2 2
 
3 3
 /**
4 4
  * 获取当前人员
@@ -17,3 +17,27 @@ import request from '@/utils/request';
17 17
   */
18 18
   export const login = (data) => request('/login', { data, method: 'post' });
19 19
 
20
+
21
+  const [
22
+    getUserList,
23
+    getUser,
24
+    saveUser,
25
+    updateUser,
26
+    deleteUser,
27
+   ] = restful('/users');
28
+
29
+  export {
30
+    getUserList,
31
+    getUser,
32
+    saveUser,
33
+    updateUser,
34
+    deleteUser,
35
+  }
36
+
37
+  /**
38
+   * 更新用户状态
39
+   * @param {*} id 
40
+   * @param {*} status 
41
+   * @returns 
42
+   */
43
+  export const updateUserStatus = (id, status) => request.put(`/users/${id}/status?status=${status}`);

+ 26
- 2
src/store/models/user.js View File

@@ -1,12 +1,36 @@
1
-import { useState } from "react";
1
+import { useState, useRef } from "react";
2
+import { queryCurrentUser } from "@/services/user";
3
+import { defaultRoutes, authRoutes, mergeAuthRoutes } from '@/routes/routes';
4
+import { getMenuItems } from "@/routes/menus";
5
+import { getAuthedRoutes } from "@/routes/permissions";
2 6
 
3 7
 export default function useUser() {
4
-
5 8
   const [user, setUser] = useState();
9
+  const menusRef = useRef();
10
+  const routesRef = useRef();
11
+
12
+  const getCurrentUser = () => new Promise((resolve, reject) => {
13
+    queryCurrentUser().then(res => {
14
+      const permissions = (res.resourcesList || []).map(x => x.code);
15
+
16
+      // authRoutes 是所有待验证授权的路由
17
+      // authedRoutes 是已经被授权的路由
18
+      const authedRoutes = getAuthedRoutes(authRoutes, permissions);
19
+
20
+      menusRef.current = getMenuItems(authedRoutes);
21
+      routesRef.current = mergeAuthRoutes(defaultRoutes, authedRoutes);
22
+
23
+      setUser(res);
24
+      resolve(res);
25
+    })
26
+  });
6 27
 
7 28
   return {
8 29
     user,
9 30
     setUser,
31
+    getCurrentUser,
32
+    menus: menusRef.current || [],
33
+    routes: routesRef.current || [],
10 34
   }
11 35
 
12 36
 }

+ 1
- 4
src/utils/hooks/useRoute.jsx View File

@@ -1,12 +1,9 @@
1 1
 import { useLocation } from "react-router-dom";
2
-import { getRouteArr } from '@/routes/menus';
2
+import { routeArr } from '@/routes/routes';
3 3
 
4 4
 // 获取当前的 route 信息
5 5
 export default function useRoute() {
6 6
   const location = useLocation();
7
-  const routeArr = getRouteArr();
8
-
9 7
   const currentRoute = routeArr.filter(x => x.path === location.pathname)[0];
10
-
11 8
   return currentRoute;
12 9
 }