react-toolkits 0.0.7 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -6
- package/CHANGELOG.md +12 -0
- package/README.md +41 -0
- package/dist/index.css +252 -1
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +55 -54
- package/dist/index.esm.js +3576 -15
- package/dist/index.esm.js.map +1 -0
- package/package.json +2 -1
- package/src/components/GameSelect/index.tsx +82 -0
- package/src/components/Layout/index.tsx +90 -0
- package/src/{layouts/NavBar.tsx → components/NavMenu/index.tsx} +8 -17
- package/src/components/ReactToolkitsProvider/context.ts +76 -0
- package/src/components/ReactToolkitsProvider/index.tsx +23 -0
- package/src/components/UserWidget/index.tsx +46 -0
- package/src/components/index.ts +25 -1
- package/src/features/permission/components/PermissionCollapse/index.tsx +121 -0
- package/src/features/permission/components/PermissionList/index.tsx +17 -118
- package/src/features/permission/components/PermissionListV1/index.tsx +42 -0
- package/src/features/permission/components/PermissionListV2/index.tsx +146 -0
- package/src/features/permission/hooks/index.ts +24 -9
- package/src/features/permission/types/index.ts +8 -1
- package/src/hooks/use-http-client.tsx +9 -0
- package/src/hooks/use-permission.tsx +10 -2
- package/src/index.ts +0 -1
- package/src/pages/{Login → base/Login}/index.tsx +3 -16
- package/src/pages/{NoMatch → base/NotFound}/index.tsx +4 -4
- package/src/pages/base/index.tsx +20 -0
- package/src/pages/index.ts +3 -4
- package/src/pages/permission/RoleList/index.tsx +63 -36
- package/src/pages/permission/UserList/index.tsx +2 -2
- package/src/pages/permission/index.tsx +26 -1
- package/src/stores/index.ts +0 -1
- package/src/stores/token.ts +15 -1
- package/tsup.config.ts +6 -6
- package/src/layouts/Layout.tsx +0 -103
- package/src/layouts/index.ts +0 -6
- package/src/stores/menu.ts +0 -27
- /package/src/pages/{Login → base/Login}/default.tsx +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Button, Card, Divider, Empty, Select, Skeleton, Space, Typography } from 'antd'
|
|
2
|
+
import type { FC } from 'react'
|
|
3
|
+
import { useEffect, useState } from 'react'
|
|
4
|
+
import type { RoleV2 } from '../../types'
|
|
5
|
+
import { useAllPermissionsV2 } from '../../hooks'
|
|
6
|
+
import PermissionCollapse from '../PermissionCollapse'
|
|
7
|
+
import type { PermissionListPropsBase } from '../PermissionList'
|
|
8
|
+
|
|
9
|
+
const { Text } = Typography
|
|
10
|
+
const { Option } = Select
|
|
11
|
+
|
|
12
|
+
interface PermissionListV2Props extends PermissionListPropsBase {
|
|
13
|
+
value?: RoleV2['permissions']
|
|
14
|
+
onChange?: (checkedValue: RoleV2['permissions']) => void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const PermissionListV2: FC<PermissionListV2Props> = props => {
|
|
18
|
+
const { expand = true, value, readonly, onChange } = props
|
|
19
|
+
const { data: permissions, isLoading, error } = useAllPermissionsV2()
|
|
20
|
+
const [gameList, setGameList] = useState<{ gameId: string; permissions: string[] }[]>([])
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const list: { gameId: string; permissions: string[] }[] = []
|
|
24
|
+
|
|
25
|
+
Object.keys(value ?? {}).forEach(key => {
|
|
26
|
+
if (key !== 'global') {
|
|
27
|
+
list.push({ gameId: key, permissions: value?.[key] ?? [] })
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
setGameList(list)
|
|
32
|
+
}, [value])
|
|
33
|
+
|
|
34
|
+
if (error) {
|
|
35
|
+
return (
|
|
36
|
+
<div className="flex justify-center">
|
|
37
|
+
<Text type="danger">权限获取失败</Text>
|
|
38
|
+
</div>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const addGame = () => {
|
|
43
|
+
setGameList(prev => [...prev, { gameId: '', permissions: [] }])
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const removeGame = (index: number) => {
|
|
47
|
+
setGameList(prev => prev.filter((_, i) => i !== index))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="flex flex-col w-full">
|
|
52
|
+
<div className="mb-12">
|
|
53
|
+
<Divider dashed>平台基础权限</Divider>
|
|
54
|
+
</div>
|
|
55
|
+
<Skeleton active loading={isLoading}>
|
|
56
|
+
<PermissionCollapse
|
|
57
|
+
value={value?.global}
|
|
58
|
+
readonly={readonly}
|
|
59
|
+
permissions={permissions?.permission?.slice(0, 2)}
|
|
60
|
+
expand={expand}
|
|
61
|
+
onChange={newValue => {
|
|
62
|
+
onChange?.({
|
|
63
|
+
...value,
|
|
64
|
+
global: newValue,
|
|
65
|
+
})
|
|
66
|
+
}}
|
|
67
|
+
/>
|
|
68
|
+
</Skeleton>
|
|
69
|
+
<div className="my-12">
|
|
70
|
+
<Divider dashed>游戏权限</Divider>
|
|
71
|
+
</div>
|
|
72
|
+
{gameList.map((item, index) => (
|
|
73
|
+
<Card
|
|
74
|
+
title={
|
|
75
|
+
<Space>
|
|
76
|
+
<Text>游戏</Text>
|
|
77
|
+
{readonly ? (
|
|
78
|
+
<Text>{permissions?.game?.find(game => game.id === item.gameId)?.name}</Text>
|
|
79
|
+
) : (
|
|
80
|
+
<Select
|
|
81
|
+
disabled={readonly}
|
|
82
|
+
value={gameList[index].gameId || undefined}
|
|
83
|
+
style={{ width: '160px' }}
|
|
84
|
+
placeholder="请选择游戏"
|
|
85
|
+
onChange={selectedValue => {
|
|
86
|
+
setGameList(pev => {
|
|
87
|
+
const temp = pev.slice()
|
|
88
|
+
temp[index].gameId = selectedValue
|
|
89
|
+
return temp
|
|
90
|
+
})
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
{permissions?.game?.map(game => (
|
|
94
|
+
<Option key={game.id} value={game.id} disabled={gameList.some(({ gameId }) => gameId === game.id)}>
|
|
95
|
+
{game.name}
|
|
96
|
+
</Option>
|
|
97
|
+
))}
|
|
98
|
+
</Select>
|
|
99
|
+
)}
|
|
100
|
+
</Space>
|
|
101
|
+
}
|
|
102
|
+
key={index}
|
|
103
|
+
className="mb-6"
|
|
104
|
+
extra={
|
|
105
|
+
!readonly && (
|
|
106
|
+
<Button
|
|
107
|
+
type="link"
|
|
108
|
+
onClick={() => {
|
|
109
|
+
removeGame(index)
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
移除
|
|
113
|
+
</Button>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
>
|
|
117
|
+
{gameList[index].gameId ? (
|
|
118
|
+
<Skeleton active loading={isLoading}>
|
|
119
|
+
<PermissionCollapse
|
|
120
|
+
value={value?.[gameList[index].gameId]}
|
|
121
|
+
readonly={readonly}
|
|
122
|
+
expand={expand}
|
|
123
|
+
permissions={permissions?.permission?.slice(2)}
|
|
124
|
+
onChange={newValue => {
|
|
125
|
+
onChange?.({
|
|
126
|
+
...value,
|
|
127
|
+
[gameList[index].gameId]: newValue,
|
|
128
|
+
})
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
</Skeleton>
|
|
132
|
+
) : (
|
|
133
|
+
<Empty description="请先选择游戏" />
|
|
134
|
+
)}
|
|
135
|
+
</Card>
|
|
136
|
+
))}
|
|
137
|
+
{!readonly && (
|
|
138
|
+
<Button block type="dashed" onClick={addGame}>
|
|
139
|
+
添加游戏权限
|
|
140
|
+
</Button>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default PermissionListV2
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useHttpClient, usePermission } from '@/hooks'
|
|
2
2
|
import useSWR from 'swr'
|
|
3
3
|
import useSWRMutation from 'swr/mutation'
|
|
4
|
-
import type { PermissionEnumItem, RoleEnumItem } from '../types'
|
|
4
|
+
import type { PermissionEnumItem, RoleEnumItem, RoleV1, RoleV2 } from '../types'
|
|
5
|
+
import type { GameType } from '@/components/GameSelect'
|
|
6
|
+
import { useReactToolkitsContext } from '@/components'
|
|
5
7
|
|
|
6
8
|
export function useAllPermissions() {
|
|
7
9
|
return useSWR<PermissionEnumItem[]>({
|
|
@@ -9,6 +11,15 @@ export function useAllPermissions() {
|
|
|
9
11
|
})
|
|
10
12
|
}
|
|
11
13
|
|
|
14
|
+
export function useAllPermissionsV2() {
|
|
15
|
+
return useSWR<{
|
|
16
|
+
game: GameType[]
|
|
17
|
+
permission: PermissionEnumItem[]
|
|
18
|
+
}>({
|
|
19
|
+
url: '/api/usystem/user/allPermissionsV2',
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
export function useAllRoles() {
|
|
13
24
|
const { accessible } = usePermission('200005')
|
|
14
25
|
|
|
@@ -22,23 +33,26 @@ export function useAllRoles() {
|
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
export function useRole(name: string) {
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
const isPermissionV2 = useReactToolkitsContext(state => state.isPermissionV2)
|
|
37
|
+
|
|
38
|
+
return useSWR<RoleV1 | RoleV2>({
|
|
39
|
+
url: isPermissionV2 ? '/api/usystem/role/infoV2' : '/api/usystem/role/info',
|
|
27
40
|
params: { name },
|
|
28
41
|
})
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
export function useCreateRole() {
|
|
32
45
|
const httpClient = useHttpClient()
|
|
46
|
+
const isPermissionV2 = useReactToolkitsContext(state => state.isPermissionV2)
|
|
33
47
|
|
|
34
48
|
return useSWRMutation(
|
|
35
|
-
'/api/usystem/role/create',
|
|
49
|
+
isPermissionV2 ? '/api/usystem/role/createV2' : '/api/usystem/role/create',
|
|
36
50
|
(
|
|
37
|
-
url,
|
|
51
|
+
url: string,
|
|
38
52
|
{
|
|
39
53
|
arg,
|
|
40
54
|
}: {
|
|
41
|
-
arg: { name: string; permissions:
|
|
55
|
+
arg: { name: string; permissions: RoleV1['permissions'] | RoleV2['permissions'] }
|
|
42
56
|
},
|
|
43
57
|
) => httpClient.post(url, arg),
|
|
44
58
|
)
|
|
@@ -46,15 +60,16 @@ export function useCreateRole() {
|
|
|
46
60
|
|
|
47
61
|
export function useUpdateRole() {
|
|
48
62
|
const httpClient = useHttpClient()
|
|
63
|
+
const isPermissionV2 = useReactToolkitsContext(state => state.isPermissionV2)
|
|
49
64
|
|
|
50
65
|
return useSWRMutation(
|
|
51
|
-
'/api/usystem/role/update',
|
|
66
|
+
isPermissionV2 ? '/api/usystem/role/updateV2' : '/api/usystem/role/update',
|
|
52
67
|
(
|
|
53
|
-
url,
|
|
68
|
+
url: string,
|
|
54
69
|
{
|
|
55
70
|
arg,
|
|
56
71
|
}: {
|
|
57
|
-
arg: { id: number; name: string; permissions:
|
|
72
|
+
arg: { id: number; name: string; permissions: RoleV1['permissions'] | RoleV2['permissions'] }
|
|
58
73
|
},
|
|
59
74
|
) => httpClient.post(url, arg),
|
|
60
75
|
)
|
|
@@ -18,13 +18,20 @@ export interface RoleListItem {
|
|
|
18
18
|
ctime: string
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export interface
|
|
21
|
+
export interface RoleV1 {
|
|
22
22
|
id: number
|
|
23
23
|
name: string
|
|
24
24
|
ctime: string
|
|
25
25
|
permissions: string[]
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export interface RoleV2 {
|
|
29
|
+
id: number
|
|
30
|
+
name: string
|
|
31
|
+
ctime: string
|
|
32
|
+
permissions: Record<string, string[]>
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
export interface UserListItem {
|
|
29
36
|
id: string
|
|
30
37
|
name: string
|
|
@@ -2,6 +2,7 @@ import {useTokenStore} from '@/stores'
|
|
|
2
2
|
import type {AxiosInstance, AxiosRequestConfig} from 'axios'
|
|
3
3
|
import axios from 'axios'
|
|
4
4
|
import type {Merge} from 'ts-essentials'
|
|
5
|
+
import {useReactToolkitsContext} from '@/components'
|
|
5
6
|
|
|
6
7
|
// 覆盖 AxiosInstance 各种请求方法的返回值,为了方便我们在 interceptors.response 里把 AxiosResponse 直接打平成后端返回的数据,去掉了 axios 的封装。
|
|
7
8
|
type ShimmedAxiosInstance = Merge<
|
|
@@ -31,6 +32,7 @@ export class HttpClientError extends Error {
|
|
|
31
32
|
|
|
32
33
|
export function useHttpClient() {
|
|
33
34
|
const token = useTokenStore(state => state.token)
|
|
35
|
+
const { game, isGlobalNS, isPermissionV2 } = useReactToolkitsContext(state => state)
|
|
34
36
|
|
|
35
37
|
const defaultOptions: AxiosRequestConfig = {
|
|
36
38
|
withCredentials: true,
|
|
@@ -41,6 +43,13 @@ export function useHttpClient() {
|
|
|
41
43
|
instance.interceptors.request.use(config => {
|
|
42
44
|
const headers = config.headers
|
|
43
45
|
headers.set('Authorization', `Bearer ${token}`)
|
|
46
|
+
|
|
47
|
+
if (isPermissionV2) {
|
|
48
|
+
if (!headers.has('App-ID')) {
|
|
49
|
+
headers.set('App-ID', isGlobalNS ? 'global' : game?.id)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
return config
|
|
45
54
|
})
|
|
46
55
|
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
import useSWRImmutable from 'swr/immutable'
|
|
2
2
|
import { useNavigate } from 'react-router-dom'
|
|
3
3
|
import { useHttpClient } from './use-http-client'
|
|
4
|
+
import { useReactToolkitsContext } from '@/components'
|
|
4
5
|
|
|
5
6
|
export interface PermissionCheckResult {
|
|
6
7
|
[k: string]: boolean
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
export function usePermissions(codes: string[]) {
|
|
10
|
+
export function usePermissions(codes: string[], isGlobalNS = false) {
|
|
10
11
|
const httpClient = useHttpClient()
|
|
11
12
|
const navigate = useNavigate()
|
|
13
|
+
const isPermissionV2 = useReactToolkitsContext(state => state.isPermissionV2)
|
|
14
|
+
const url = isPermissionV2 ? '/api/usystem/user/checkV2' : '/api/usystem/user/check'
|
|
12
15
|
|
|
13
16
|
const { data, isLoading } = useSWRImmutable(
|
|
14
17
|
codes.length > 0
|
|
15
18
|
? {
|
|
16
19
|
method: 'POST',
|
|
17
|
-
url
|
|
20
|
+
url,
|
|
18
21
|
data: { permissions: codes },
|
|
22
|
+
headers: isGlobalNS
|
|
23
|
+
? {
|
|
24
|
+
'App-ID': 'global',
|
|
25
|
+
}
|
|
26
|
+
: {},
|
|
19
27
|
}
|
|
20
28
|
: null,
|
|
21
29
|
config =>
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SSO_URL } from '@/constants'
|
|
2
2
|
import { useTokenStore } from '@/stores'
|
|
3
3
|
import { AliyunOutlined } from '@ant-design/icons'
|
|
4
|
-
import { Alert, Button, Card, Col, Divider, Row, Space,
|
|
4
|
+
import { Alert, Button, Card, Col, Divider, Row, Space, Typography } from 'antd'
|
|
5
5
|
import type { FC, PropsWithChildren } from 'react'
|
|
6
6
|
import { useEffect, useState } from 'react'
|
|
7
7
|
import { Navigate, useSearchParams } from 'react-router-dom'
|
|
@@ -19,7 +19,7 @@ const Login: FC<PropsWithChildren> = props => {
|
|
|
19
19
|
const [showAlert, setShowAlert] = useState(false)
|
|
20
20
|
const httpClient = useHttpClient()
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
useSWRImmutable<{ token: string }>(
|
|
23
23
|
searchParams.has('ticket')
|
|
24
24
|
? {
|
|
25
25
|
url: '/api/usystem/user/login',
|
|
@@ -30,6 +30,7 @@ const Login: FC<PropsWithChildren> = props => {
|
|
|
30
30
|
: null,
|
|
31
31
|
config => httpClient.request(config),
|
|
32
32
|
{
|
|
33
|
+
suspense: true,
|
|
33
34
|
onSuccess: data => {
|
|
34
35
|
setToken(data.token)
|
|
35
36
|
},
|
|
@@ -44,20 +45,6 @@ const Login: FC<PropsWithChildren> = props => {
|
|
|
44
45
|
}
|
|
45
46
|
}, [searchParams, setSearchParams])
|
|
46
47
|
|
|
47
|
-
if (isLoading) {
|
|
48
|
-
return (
|
|
49
|
-
<Spin
|
|
50
|
-
style={{
|
|
51
|
-
display: 'flex',
|
|
52
|
-
justifyContent: 'center',
|
|
53
|
-
alignItems: 'center',
|
|
54
|
-
width: '100vw',
|
|
55
|
-
height: '100vh',
|
|
56
|
-
}}
|
|
57
|
-
/>
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
48
|
if (token) {
|
|
62
49
|
return <Navigate replace to="/" />
|
|
63
50
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Button, Result } from 'antd'
|
|
2
2
|
import { useNavigate } from 'react-router-dom'
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const NotFound = () => {
|
|
5
5
|
const navigate = useNavigate()
|
|
6
6
|
return (
|
|
7
7
|
<div className="h-screen flex justify-center items-center">
|
|
8
8
|
<Result
|
|
9
9
|
status="404"
|
|
10
10
|
title="404"
|
|
11
|
-
subTitle="
|
|
11
|
+
subTitle="访问的页面不存在"
|
|
12
12
|
extra={
|
|
13
13
|
<Button
|
|
14
14
|
type="primary"
|
|
@@ -16,7 +16,7 @@ const NoMatch = () => {
|
|
|
16
16
|
navigate('/')
|
|
17
17
|
}}
|
|
18
18
|
>
|
|
19
|
-
|
|
19
|
+
返回页面
|
|
20
20
|
</Button>
|
|
21
21
|
}
|
|
22
22
|
/>
|
|
@@ -24,4 +24,4 @@ const NoMatch = () => {
|
|
|
24
24
|
)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export default
|
|
27
|
+
export default NotFound
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { lazy } from 'react'
|
|
2
|
+
import type { RouteObject } from 'react-router-dom'
|
|
3
|
+
|
|
4
|
+
const Login = lazy(() => import('./Login'))
|
|
5
|
+
const NotFound = lazy(() => import('./NotFound'))
|
|
6
|
+
|
|
7
|
+
const routes: RouteObject = {
|
|
8
|
+
children: [
|
|
9
|
+
{
|
|
10
|
+
path: 'login',
|
|
11
|
+
element: <Login />,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
path: '*',
|
|
15
|
+
element: <NotFound />,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default routes
|
package/src/pages/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Highlight, PermissionButton, QueryList } from '@/components'
|
|
1
|
+
import { Highlight, PermissionButton, QueryList, useReactToolkitsContext } from '@/components'
|
|
2
2
|
import { useFormModal } from '@/components/FormModal/hooks'
|
|
3
|
-
import type {
|
|
3
|
+
import type { RoleListItem, RoleV1, RoleV2 } from '@/features/permission'
|
|
4
4
|
import { PermissionList, useCreateRole, useRemoveRole, useUpdateRole } from '@/features/permission'
|
|
5
5
|
import { useHttpClient, usePermission } from '@/hooks'
|
|
6
6
|
import { useQueryListStore } from '@/stores'
|
|
7
7
|
import { UsergroupAddOutlined } from '@ant-design/icons'
|
|
8
8
|
import type { TableColumnsType } from 'antd'
|
|
9
9
|
import { App, Card, Form, Input, Space } from 'antd'
|
|
10
|
-
import { useMemo } from 'react'
|
|
10
|
+
import { useCallback, useMemo } from 'react'
|
|
11
11
|
import { Link } from 'react-router-dom'
|
|
12
12
|
import type { ListResponse } from '@/types'
|
|
13
13
|
|
|
@@ -15,18 +15,32 @@ export const swrKey = {
|
|
|
15
15
|
url: '/api/usystem/role/list',
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const {
|
|
20
|
-
const { modal, message } = App.useApp()
|
|
21
|
-
const httpClient = useHttpClient()
|
|
22
|
-
const create = useCreateRole()
|
|
23
|
-
const remove = useRemoveRole()
|
|
24
|
-
const update = useUpdateRole()
|
|
18
|
+
const useCreateModal = () => {
|
|
19
|
+
const { message } = App.useApp()
|
|
25
20
|
const refresh = useQueryListStore(state => state.refresh)
|
|
21
|
+
const create = useCreateRole()
|
|
26
22
|
|
|
27
|
-
const
|
|
23
|
+
const onConfirm = useCallback(
|
|
24
|
+
async (values: { name: string; permissions: RoleV1['permissions'] | RoleV2['permissions'] }) => {
|
|
25
|
+
await create.trigger(
|
|
26
|
+
{
|
|
27
|
+
name: `role_${values.name}`,
|
|
28
|
+
permissions: values.permissions,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
async onSuccess() {
|
|
32
|
+
await message.success('角色创建成功')
|
|
33
|
+
refresh(swrKey, { page: 1 })
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
},
|
|
38
|
+
[create, refresh, message],
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return useFormModal<{
|
|
28
42
|
name: string
|
|
29
|
-
permissions:
|
|
43
|
+
permissions: RoleV1['permissions'] | RoleV2['permissions']
|
|
30
44
|
}>({
|
|
31
45
|
title: '创建角色',
|
|
32
46
|
width: '50vw',
|
|
@@ -41,26 +55,38 @@ const RoleList = () => {
|
|
|
41
55
|
</Form.Item>
|
|
42
56
|
</>
|
|
43
57
|
),
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
onConfirm,
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const useUpdateModal = () => {
|
|
63
|
+
const { message } = App.useApp()
|
|
64
|
+
const refresh = useQueryListStore(state => state.refresh)
|
|
65
|
+
const update = useUpdateRole()
|
|
66
|
+
|
|
67
|
+
const onConfirm = useCallback(
|
|
68
|
+
async (values: { id: number; name: string; permissions: RoleV1['permissions'] | RoleV2['permissions'] }) => {
|
|
69
|
+
await update.trigger(
|
|
46
70
|
{
|
|
71
|
+
id: values.id,
|
|
47
72
|
name: `role_${values.name}`,
|
|
48
73
|
permissions: values.permissions,
|
|
49
74
|
},
|
|
50
75
|
{
|
|
51
76
|
async onSuccess() {
|
|
52
|
-
await message.success('
|
|
77
|
+
await message.success('角色更新成功')
|
|
53
78
|
refresh(swrKey, { page: 1 })
|
|
54
79
|
},
|
|
55
80
|
},
|
|
56
81
|
)
|
|
57
82
|
},
|
|
58
|
-
|
|
83
|
+
[update, refresh, message],
|
|
84
|
+
)
|
|
59
85
|
|
|
60
|
-
|
|
86
|
+
return useFormModal<{
|
|
61
87
|
id: number
|
|
62
88
|
name: string
|
|
63
|
-
permissions:
|
|
89
|
+
permissions: RoleV1['permissions'] | RoleV2['permissions']
|
|
64
90
|
}>({
|
|
65
91
|
title: '更新角色',
|
|
66
92
|
width: '50vw',
|
|
@@ -78,22 +104,19 @@ const RoleList = () => {
|
|
|
78
104
|
</Form.Item>
|
|
79
105
|
</>
|
|
80
106
|
),
|
|
81
|
-
|
|
82
|
-
await update.trigger(
|
|
83
|
-
{
|
|
84
|
-
id: values.id,
|
|
85
|
-
name: `role_${values.name}`,
|
|
86
|
-
permissions: values.permissions,
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
async onSuccess() {
|
|
90
|
-
await message.success('角色更新成功')
|
|
91
|
-
refresh(swrKey, { page: 1 })
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
)
|
|
95
|
-
},
|
|
107
|
+
onConfirm,
|
|
96
108
|
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const RoleList = () => {
|
|
112
|
+
const { accessible: viewable } = usePermission('200005')
|
|
113
|
+
const { modal, message } = App.useApp()
|
|
114
|
+
const httpClient = useHttpClient()
|
|
115
|
+
const isPermissionV2 = useReactToolkitsContext(state => state.isPermissionV2)
|
|
116
|
+
const remove = useRemoveRole()
|
|
117
|
+
const refresh = useQueryListStore(state => state.refresh)
|
|
118
|
+
const { showModal: showCreateModal, Modal: CreateModal } = useCreateModal()
|
|
119
|
+
const { showModal: showUpdateModal, Modal: UpdateModal } = useUpdateModal()
|
|
97
120
|
|
|
98
121
|
const columns = useMemo<TableColumnsType<RoleListItem>>(
|
|
99
122
|
() => [
|
|
@@ -130,9 +153,13 @@ const RoleList = () => {
|
|
|
130
153
|
size="small"
|
|
131
154
|
type="link"
|
|
132
155
|
onClick={async () => {
|
|
133
|
-
const role = await httpClient.get<
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
const role = await httpClient.get<RoleV1 | RoleV2>(
|
|
157
|
+
isPermissionV2 ? '/api/usystem/role/infoV2' : '/api/usystem/role/info',
|
|
158
|
+
{
|
|
159
|
+
params: { name: value.name },
|
|
160
|
+
},
|
|
161
|
+
)
|
|
162
|
+
|
|
136
163
|
showUpdateModal({
|
|
137
164
|
initialValues: {
|
|
138
165
|
id: role?.id,
|
|
@@ -23,7 +23,7 @@ function useCreatingUserModal() {
|
|
|
23
23
|
const refresh = useQueryListStore(state => state.refresh)
|
|
24
24
|
|
|
25
25
|
return useFormModal<{ id: string; name: string; roles: string[] }>({
|
|
26
|
-
title: '
|
|
26
|
+
title: '创建用户',
|
|
27
27
|
labelCol: { flex: '80px' },
|
|
28
28
|
content: (
|
|
29
29
|
<>
|
|
@@ -63,7 +63,7 @@ function useUpdatingUserModal() {
|
|
|
63
63
|
const refresh = useQueryListStore(state => state.refresh)
|
|
64
64
|
|
|
65
65
|
return useFormModal<{ id: string; name: string; roles: string[] }>({
|
|
66
|
-
title: '
|
|
66
|
+
title: '更新用户',
|
|
67
67
|
labelCol: { flex: '80px' },
|
|
68
68
|
content: (
|
|
69
69
|
<>
|
|
@@ -1,13 +1,38 @@
|
|
|
1
1
|
import { lazy } from 'react'
|
|
2
2
|
import type { RouteObject } from 'react-router-dom'
|
|
3
|
-
import { Navigate } from 'react-router-dom'
|
|
3
|
+
import { Navigate, Outlet } from 'react-router-dom'
|
|
4
|
+
import { Layout, ReactToolkitsProvider, useReactToolkitsContext } from '@/components'
|
|
5
|
+
import { SWRConfig } from 'swr'
|
|
6
|
+
import { useHttpClient } from '@/hooks'
|
|
4
7
|
|
|
5
8
|
const UserList = lazy(() => import('./UserList'))
|
|
6
9
|
const RoleList = lazy(() => import('./RoleList'))
|
|
7
10
|
const RoleDetail = lazy(() => import('./RoleDetail'))
|
|
8
11
|
|
|
12
|
+
const PermissionRoot = () => {
|
|
13
|
+
const httpClient = useHttpClient()
|
|
14
|
+
const configs = useReactToolkitsContext(state => state)
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
// NOTE: 目前嵌套的 ReactToolkitsProvider 只能手动注入父级 ReactToolkitsProvider 的配置
|
|
18
|
+
<ReactToolkitsProvider {...configs} isGlobalNS>
|
|
19
|
+
<SWRConfig
|
|
20
|
+
value={{
|
|
21
|
+
fetcher: httpClient.request,
|
|
22
|
+
shouldRetryOnError: false,
|
|
23
|
+
}}
|
|
24
|
+
>
|
|
25
|
+
<Layout>
|
|
26
|
+
<Outlet />
|
|
27
|
+
</Layout>
|
|
28
|
+
</SWRConfig>
|
|
29
|
+
</ReactToolkitsProvider>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
9
33
|
const routes: RouteObject = {
|
|
10
34
|
path: 'permission',
|
|
35
|
+
element: <PermissionRoot />,
|
|
11
36
|
children: [
|
|
12
37
|
{
|
|
13
38
|
index: true,
|
package/src/stores/index.ts
CHANGED
package/src/stores/token.ts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
import { create } from 'zustand'
|
|
2
2
|
import { persist } from 'zustand/middleware'
|
|
3
|
+
import jwtDecode from 'jwt-decode'
|
|
4
|
+
|
|
5
|
+
interface UserInfo {
|
|
6
|
+
authorityId: string
|
|
7
|
+
exp: number
|
|
8
|
+
}
|
|
3
9
|
|
|
4
10
|
export interface TokenState {
|
|
5
11
|
token: string
|
|
12
|
+
getUser: () => UserInfo | null
|
|
6
13
|
setToken: (token: string) => void
|
|
7
14
|
clearToken: () => void
|
|
8
15
|
}
|
|
9
16
|
|
|
10
17
|
export const useTokenStore = create<TokenState>()(
|
|
11
18
|
persist(
|
|
12
|
-
set => ({
|
|
19
|
+
(set, get) => ({
|
|
13
20
|
token: '',
|
|
21
|
+
getUser: () => {
|
|
22
|
+
try {
|
|
23
|
+
return jwtDecode(get().token) as UserInfo
|
|
24
|
+
} catch (_) {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
},
|
|
14
28
|
setToken: token => set({ token }),
|
|
15
29
|
clearToken: () => {
|
|
16
30
|
set({ token: '' })
|