react-toolkits 0.1.1 → 0.1.2
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/CHANGELOG.md +6 -0
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.esm.js.map +1 -1
- package/package.json +8 -3
- package/.eslintignore +0 -2
- package/.eslintrc.js +0 -4
- package/.turbo/turbo-build.log +0 -20
- package/postcss.config.js +0 -9
- package/src/assets/512_orange_nobackground.png +0 -0
- package/src/components/DynamicTags/index.tsx +0 -160
- package/src/components/FilterForm/index.tsx +0 -63
- package/src/components/FormModal/hooks.tsx +0 -47
- package/src/components/FormModal/index.tsx +0 -137
- package/src/components/GameSelect/index.tsx +0 -83
- package/src/components/Highlight/index.tsx +0 -51
- package/src/components/Layout/index.tsx +0 -99
- package/src/components/NavMenu/index.tsx +0 -142
- package/src/components/PermissionButton/index.tsx +0 -36
- package/src/components/QueryList/index.tsx +0 -152
- package/src/components/ReactToolkitsProvider/context.ts +0 -76
- package/src/components/ReactToolkitsProvider/index.tsx +0 -23
- package/src/components/UserWidget/index.tsx +0 -46
- package/src/components/index.ts +0 -51
- package/src/constants/index.ts +0 -1
- package/src/features/permission/components/PermissionCollapse/index.tsx +0 -121
- package/src/features/permission/components/PermissionList/index.tsx +0 -28
- package/src/features/permission/components/PermissionListV1/index.tsx +0 -42
- package/src/features/permission/components/PermissionListV2/index.tsx +0 -146
- package/src/features/permission/hooks/index.ts +0 -140
- package/src/features/permission/index.ts +0 -5
- package/src/features/permission/types/index.ts +0 -40
- package/src/hooks/index.ts +0 -2
- package/src/hooks/use-http-client.ts +0 -85
- package/src/hooks/use-permission.ts +0 -75
- package/src/index.ts +0 -7
- package/src/pages/base/Login/default.tsx +0 -864
- package/src/pages/base/Login/index.tsx +0 -101
- package/src/pages/base/NotFound/index.tsx +0 -27
- package/src/pages/base/index.tsx +0 -20
- package/src/pages/index.ts +0 -4
- package/src/pages/permission/RoleDetail/index.tsx +0 -40
- package/src/pages/permission/RoleList/index.tsx +0 -251
- package/src/pages/permission/UserList/index.tsx +0 -236
- package/src/pages/permission/index.tsx +0 -56
- package/src/shims.d.ts +0 -20
- package/src/stores/index.ts +0 -2
- package/src/stores/query-list.ts +0 -61
- package/src/stores/token.ts +0 -39
- package/src/styles/index.css +0 -5
- package/src/types/index.ts +0 -10
- package/tailwind.config.js +0 -5
- package/tsconfig.json +0 -20
- package/tsup.config.ts +0 -28
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import logo from '@/assets/512_orange_nobackground.png'
|
|
2
|
-
import * as Antd from 'antd'
|
|
3
|
-
import { Divider, Space } from 'antd'
|
|
4
|
-
import type { FC, PropsWithChildren } from 'react'
|
|
5
|
-
import * as React from 'react'
|
|
6
|
-
import { Suspense } from 'react'
|
|
7
|
-
import { Link } from 'react-router-dom'
|
|
8
|
-
import { GameSelect, NavMenu, useReactToolkitsContext, UserWidget } from '@/components'
|
|
9
|
-
import { SWRConfig } from 'swr'
|
|
10
|
-
|
|
11
|
-
const { Spin, theme } = Antd
|
|
12
|
-
const { Header, Sider, Content } = Antd.Layout
|
|
13
|
-
|
|
14
|
-
export interface LayoutProps extends PropsWithChildren {
|
|
15
|
-
extra?: React.ReactNode[]
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const Layout: FC<LayoutProps> = props => {
|
|
19
|
-
const { children, extra } = props
|
|
20
|
-
const {
|
|
21
|
-
token: { colorBgContainer, colorBorder },
|
|
22
|
-
} = theme.useToken()
|
|
23
|
-
const { title, game } = useReactToolkitsContext(state => state)
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<Antd.Layout hasSider className="h-screen">
|
|
27
|
-
<Sider
|
|
28
|
-
width={256}
|
|
29
|
-
style={{
|
|
30
|
-
overflow: 'auto',
|
|
31
|
-
height: '100vh',
|
|
32
|
-
position: 'fixed',
|
|
33
|
-
left: 0,
|
|
34
|
-
top: 0,
|
|
35
|
-
bottom: 0,
|
|
36
|
-
borderRightWidth: 1,
|
|
37
|
-
borderRightStyle: 'solid',
|
|
38
|
-
borderRightColor: colorBorder,
|
|
39
|
-
}}
|
|
40
|
-
theme="light"
|
|
41
|
-
>
|
|
42
|
-
<div className="flex items-end px-6 py-4">
|
|
43
|
-
<img src={logo} alt="logo" className="w-8 h-8" />
|
|
44
|
-
<Link className="font-bold text-lg ml-2" to="/">
|
|
45
|
-
{title}
|
|
46
|
-
</Link>
|
|
47
|
-
</div>
|
|
48
|
-
<NavMenu />
|
|
49
|
-
</Sider>
|
|
50
|
-
<Antd.Layout className="ml-64">
|
|
51
|
-
<Header
|
|
52
|
-
style={{
|
|
53
|
-
padding: '0 24px',
|
|
54
|
-
background: colorBgContainer,
|
|
55
|
-
borderBottomWidth: 1,
|
|
56
|
-
borderBottomStyle: 'solid',
|
|
57
|
-
borderBottomColor: colorBorder,
|
|
58
|
-
}}
|
|
59
|
-
>
|
|
60
|
-
<div className="flex justify-between items-center h-full">
|
|
61
|
-
<div>
|
|
62
|
-
<GameSelect />
|
|
63
|
-
</div>
|
|
64
|
-
<Space size="small" split={<Divider type="vertical" />}>
|
|
65
|
-
{extra}
|
|
66
|
-
<UserWidget />
|
|
67
|
-
</Space>
|
|
68
|
-
</div>
|
|
69
|
-
</Header>
|
|
70
|
-
<Content className="p-6 overflow-auto bg-gray-50">
|
|
71
|
-
<Suspense
|
|
72
|
-
fallback={
|
|
73
|
-
<Spin
|
|
74
|
-
style={{
|
|
75
|
-
display: 'flex',
|
|
76
|
-
justifyContent: 'center',
|
|
77
|
-
alignItems: 'center',
|
|
78
|
-
height: '50vh',
|
|
79
|
-
}}
|
|
80
|
-
/>
|
|
81
|
-
}
|
|
82
|
-
>
|
|
83
|
-
<SWRConfig
|
|
84
|
-
value={{
|
|
85
|
-
// GameSelect 组件内的 game 变化时,会触发 children 的重新渲染
|
|
86
|
-
// 为了避免 SWR 使用缓存导致数据不更新,需要设置 revalidateOnMount 为 true
|
|
87
|
-
revalidateOnMount: true,
|
|
88
|
-
}}
|
|
89
|
-
>
|
|
90
|
-
{React.createElement('div', { key: game?.id }, children)}
|
|
91
|
-
</SWRConfig>
|
|
92
|
-
</Suspense>
|
|
93
|
-
</Content>
|
|
94
|
-
</Antd.Layout>
|
|
95
|
-
</Antd.Layout>
|
|
96
|
-
)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export default Layout
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import {usePermissions} from '@/hooks'
|
|
2
|
-
import {Menu} from 'antd'
|
|
3
|
-
import type {
|
|
4
|
-
ItemType,
|
|
5
|
-
MenuDividerType,
|
|
6
|
-
MenuItemGroupType,
|
|
7
|
-
MenuItemType,
|
|
8
|
-
SubMenuType,
|
|
9
|
-
} from 'antd/es/menu/hooks/useItems'
|
|
10
|
-
import type {ReactNode} from 'react'
|
|
11
|
-
import {useCallback, useEffect, useMemo} from 'react'
|
|
12
|
-
import {Link, useLocation} from 'react-router-dom'
|
|
13
|
-
import type {Merge} from 'ts-essentials'
|
|
14
|
-
import {useReactToolkitsContext} from '@/components'
|
|
15
|
-
|
|
16
|
-
// 扩展 antd Menu 的类型,使其支持一些我们想要的自定义字段。
|
|
17
|
-
type MenuItemType2 = Merge<
|
|
18
|
-
MenuItemType,
|
|
19
|
-
{
|
|
20
|
-
code /** 权限编号 **/?: string
|
|
21
|
-
route /** 前端路由地址 **/?: string
|
|
22
|
-
}
|
|
23
|
-
>
|
|
24
|
-
|
|
25
|
-
type SubMenuType2 = Merge<
|
|
26
|
-
SubMenuType,
|
|
27
|
-
{
|
|
28
|
-
children?: ItemType2[]
|
|
29
|
-
}
|
|
30
|
-
>
|
|
31
|
-
|
|
32
|
-
type MenuItemGroupType2 = Merge<MenuItemGroupType, { children?: ItemType2[] }>
|
|
33
|
-
|
|
34
|
-
export type ItemType2 = MenuItemType2 | SubMenuType2 | MenuItemGroupType2 | MenuDividerType | null
|
|
35
|
-
|
|
36
|
-
const withLink = (label?: ReactNode, route?: string): ReactNode => {
|
|
37
|
-
if (!label) {
|
|
38
|
-
return <></>
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (route) {
|
|
42
|
-
return <Link to={route}>{label}</Link>
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return label
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function transformItems(items: ItemType2[], permissions?: Record<string, boolean>) {
|
|
49
|
-
const result: ItemType[] = []
|
|
50
|
-
|
|
51
|
-
for (let i = 0; i < items.length; i++) {
|
|
52
|
-
if (items[i] === null) {
|
|
53
|
-
result[i] = null
|
|
54
|
-
} else if ((items[i] as MenuDividerType).type === 'divider') {
|
|
55
|
-
result[i] = { ...items[i] } as MenuDividerType
|
|
56
|
-
} else {
|
|
57
|
-
if ((items[i] as SubMenuType2 | MenuItemGroupType2).children) {
|
|
58
|
-
const { children, ...restProps } = items[i] as SubMenuType2 | MenuItemGroupType2
|
|
59
|
-
result[i] = {
|
|
60
|
-
...restProps,
|
|
61
|
-
children: transformItems(children ?? [], permissions),
|
|
62
|
-
} as SubMenuType | MenuItemGroupType
|
|
63
|
-
} else {
|
|
64
|
-
const { route, label, code, ...restProps } = items[i] as MenuItemType2
|
|
65
|
-
const isPass = !code || !permissions || permissions[code]
|
|
66
|
-
|
|
67
|
-
result[i] = isPass
|
|
68
|
-
? ({
|
|
69
|
-
...restProps,
|
|
70
|
-
label: withLink(label, route),
|
|
71
|
-
} as MenuItemType)
|
|
72
|
-
: null
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return result
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 拍平导航配置,并且注入 keypath 字段
|
|
81
|
-
function flatItems(
|
|
82
|
-
items: ItemType2[],
|
|
83
|
-
result: Merge<MenuItemType2, { keypath?: string[] }>[] = [],
|
|
84
|
-
keypath: string[] = [],
|
|
85
|
-
) {
|
|
86
|
-
for (const item of items) {
|
|
87
|
-
const children = (item as SubMenuType2 | MenuItemGroupType2)!.children as ItemType2[]
|
|
88
|
-
|
|
89
|
-
if (Array.isArray(children)) {
|
|
90
|
-
const _keys =
|
|
91
|
-
(item as MenuItemGroupType2)!.type !== 'group' && item!.key ? [...keypath, item!.key as string] : keypath
|
|
92
|
-
flatItems(children, result, _keys)
|
|
93
|
-
} else {
|
|
94
|
-
result.push(Object.assign(item as MenuItemType2, { keypath }))
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return result
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const NavMenu = () => {
|
|
102
|
-
const location = useLocation()
|
|
103
|
-
const items = useReactToolkitsContext(state => state.menuItems)
|
|
104
|
-
const flattenItems = useMemo(() => flatItems(items ?? []), [items])
|
|
105
|
-
const codes = flattenItems.map(item => item.code).filter(Boolean) as string[]
|
|
106
|
-
const { data: permissions } = usePermissions(codes, true)
|
|
107
|
-
const internalItems = useMemo(() => transformItems(items ?? [], permissions), [items, permissions])
|
|
108
|
-
const { openKeys, selectedKeys, setOpenKeys, setSelectedKeys } = useReactToolkitsContext(state => state)
|
|
109
|
-
|
|
110
|
-
const onOpenChange = useCallback(
|
|
111
|
-
(keys: string[]) => {
|
|
112
|
-
const latestOpenKey = keys?.find(key => openKeys?.indexOf(key) === -1)
|
|
113
|
-
const match = flattenItems.find(item => latestOpenKey === item.key)
|
|
114
|
-
setOpenKeys((match?.keypath ?? [latestOpenKey]) as string[])
|
|
115
|
-
},
|
|
116
|
-
[flattenItems, openKeys, setOpenKeys],
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
const match = flattenItems.find(item => location.pathname === item.route)
|
|
121
|
-
|
|
122
|
-
if (match) {
|
|
123
|
-
const key = match.key as string
|
|
124
|
-
const keypath = match.keypath as string[]
|
|
125
|
-
setSelectedKeys([key])
|
|
126
|
-
setOpenKeys(keypath)
|
|
127
|
-
}
|
|
128
|
-
}, [flattenItems, location, setOpenKeys, setSelectedKeys])
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<Menu
|
|
132
|
-
style={{ borderRight: 'none' }}
|
|
133
|
-
items={internalItems}
|
|
134
|
-
mode="inline"
|
|
135
|
-
openKeys={openKeys}
|
|
136
|
-
selectedKeys={selectedKeys}
|
|
137
|
-
onOpenChange={onOpenChange}
|
|
138
|
-
/>
|
|
139
|
-
)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export default NavMenu
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { usePermission } from '@/hooks'
|
|
2
|
-
import type { ButtonProps } from 'antd'
|
|
3
|
-
import { Button, Tooltip } from 'antd'
|
|
4
|
-
import type { FC, PropsWithChildren } from 'react'
|
|
5
|
-
|
|
6
|
-
export interface PermissionButtonProps extends Omit<ButtonProps, 'disabled'> {
|
|
7
|
-
code: string
|
|
8
|
-
showLoading?: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const PermissionButton: FC<PropsWithChildren<PermissionButtonProps>> = props => {
|
|
12
|
-
const { children, code, showLoading, ...restProps } = props
|
|
13
|
-
const { accessible, isValidating } = usePermission(code)
|
|
14
|
-
|
|
15
|
-
if (isValidating) {
|
|
16
|
-
return (
|
|
17
|
-
<Button loading={showLoading} disabled={!showLoading} {...restProps}>
|
|
18
|
-
{children}
|
|
19
|
-
</Button>
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!accessible) {
|
|
24
|
-
return (
|
|
25
|
-
<Tooltip defaultOpen={false} title="无权限,请联系管理员进行授权">
|
|
26
|
-
<Button disabled {...restProps}>
|
|
27
|
-
{children}
|
|
28
|
-
</Button>
|
|
29
|
-
</Tooltip>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return <Button {...restProps}>{children}</Button>
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default PermissionButton
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { useHttpClient, usePermission } from '@/hooks'
|
|
2
|
-
import { useQueryListStore } from '@/stores'
|
|
3
|
-
import type { ListResponse, PaginationParams } from '@/types'
|
|
4
|
-
import type { FormInstance, FormProps } from 'antd'
|
|
5
|
-
import { Form, Result, Table } from 'antd'
|
|
6
|
-
import type { TableProps } from 'antd/es/table'
|
|
7
|
-
import type { AxiosRequestConfig } from 'axios'
|
|
8
|
-
import type { ReactNode } from 'react'
|
|
9
|
-
import { useCallback, useEffect } from 'react'
|
|
10
|
-
import useSWRMutation from 'swr/mutation'
|
|
11
|
-
import FilterForm from '../FilterForm'
|
|
12
|
-
|
|
13
|
-
export type QueryListKey = Omit<AxiosRequestConfig, 'data' | 'params'>
|
|
14
|
-
|
|
15
|
-
export interface QueryListProps<Item, Values, Response>
|
|
16
|
-
extends Pick<TableProps<Item>, 'columns' | 'rowKey' | 'tableLayout' | 'expandable' | 'rowSelection' | 'bordered'>,
|
|
17
|
-
Pick<FormProps<Values>, 'initialValues' | 'labelCol'> {
|
|
18
|
-
// 由于表单的值和分页数据是封装在组件内部的,不便于在组件外部构造 swr key,
|
|
19
|
-
// 所以组件内部的 useSWRMutation hook 使用的 key 是不包含表单值和分页参数的。
|
|
20
|
-
// 因此 swr 并未按照分页缓存数据。
|
|
21
|
-
swrKey: QueryListKey
|
|
22
|
-
confirmText?: ReactNode
|
|
23
|
-
code?: string
|
|
24
|
-
renderForm?: (form: FormInstance<Values>) => ReactNode
|
|
25
|
-
// 把表单的值和分页数据转换成请求参数
|
|
26
|
-
transformArg?: (arg: Values & PaginationParams) => unknown
|
|
27
|
-
// 当请求的返回值不满足时进行转换
|
|
28
|
-
transformResponse?: (response: Response) => ListResponse<Item>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const QueryList = <Item extends object, Values = NonNullable<unknown>, Response = ListResponse<Item>>(
|
|
32
|
-
props: QueryListProps<Item, Values, Response>,
|
|
33
|
-
) => {
|
|
34
|
-
const {
|
|
35
|
-
code,
|
|
36
|
-
confirmText,
|
|
37
|
-
labelCol,
|
|
38
|
-
swrKey,
|
|
39
|
-
initialValues,
|
|
40
|
-
renderForm,
|
|
41
|
-
transformArg,
|
|
42
|
-
transformResponse,
|
|
43
|
-
...tableProps
|
|
44
|
-
} = props
|
|
45
|
-
const { accessible } = usePermission(code ?? '')
|
|
46
|
-
const [form] = Form.useForm<Values>()
|
|
47
|
-
const setRefresh = useQueryListStore(state => state.setRefresh)
|
|
48
|
-
const getPaginationData = useQueryListStore(state => state.getPaginationData)
|
|
49
|
-
const setPaginationData = useQueryListStore(state => state.setPaginationData)
|
|
50
|
-
const paginationData = getPaginationData(swrKey)
|
|
51
|
-
|
|
52
|
-
const httpClient = useHttpClient()
|
|
53
|
-
|
|
54
|
-
const { data, isMutating, trigger } = useSWRMutation(
|
|
55
|
-
swrKey,
|
|
56
|
-
async (key, { arg }: { arg?: Partial<PaginationParams> }) => {
|
|
57
|
-
const newPaginationData = {
|
|
58
|
-
page: arg?.page ?? paginationData.page,
|
|
59
|
-
size: arg?.size ?? paginationData.size,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
setPaginationData(swrKey, arg)
|
|
63
|
-
|
|
64
|
-
const values = form.getFieldsValue()
|
|
65
|
-
|
|
66
|
-
const _arg = {
|
|
67
|
-
...values,
|
|
68
|
-
...newPaginationData,
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return httpClient
|
|
72
|
-
.request<Response>({
|
|
73
|
-
...key,
|
|
74
|
-
[key.method === 'POST' ? 'data' : 'params']: transformArg?.(_arg) ?? _arg,
|
|
75
|
-
})
|
|
76
|
-
.then(response => transformResponse?.(response) ?? (response as ListResponse<Item>))
|
|
77
|
-
},
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
const onFinish = async () => {
|
|
81
|
-
await trigger({ page: 1 })
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const onReset = useCallback(async () => {
|
|
85
|
-
try {
|
|
86
|
-
form.resetFields()
|
|
87
|
-
await form.validateFields()
|
|
88
|
-
await trigger({ page: 1 })
|
|
89
|
-
} catch (_) {
|
|
90
|
-
console.log('表单校验失败')
|
|
91
|
-
}
|
|
92
|
-
}, [form, trigger])
|
|
93
|
-
|
|
94
|
-
const onPaginationChange = useCallback(
|
|
95
|
-
async (currentPage: number, currentSize: number) => {
|
|
96
|
-
await trigger({
|
|
97
|
-
page: currentPage,
|
|
98
|
-
size: currentSize,
|
|
99
|
-
})
|
|
100
|
-
},
|
|
101
|
-
[trigger],
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
setRefresh(swrKey, trigger)
|
|
106
|
-
}, [swrKey, trigger, setRefresh])
|
|
107
|
-
|
|
108
|
-
useEffect(() => {
|
|
109
|
-
;(async () => {
|
|
110
|
-
try {
|
|
111
|
-
await form.validateFields()
|
|
112
|
-
await trigger()
|
|
113
|
-
} catch (_) {
|
|
114
|
-
form.resetFields()
|
|
115
|
-
}
|
|
116
|
-
})()
|
|
117
|
-
}, [form, trigger])
|
|
118
|
-
|
|
119
|
-
if (!accessible) {
|
|
120
|
-
return <Result status={403} subTitle="无权限,请联系管理员进行授权" />
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return (
|
|
124
|
-
<>
|
|
125
|
-
<FilterForm<Values>
|
|
126
|
-
initialValues={initialValues}
|
|
127
|
-
form={form}
|
|
128
|
-
labelCol={labelCol}
|
|
129
|
-
confirmText={confirmText}
|
|
130
|
-
onFinish={onFinish}
|
|
131
|
-
onReset={onReset}
|
|
132
|
-
>
|
|
133
|
-
{renderForm?.(form)}
|
|
134
|
-
</FilterForm>
|
|
135
|
-
<Table
|
|
136
|
-
{...tableProps}
|
|
137
|
-
dataSource={data?.List}
|
|
138
|
-
loading={isMutating}
|
|
139
|
-
pagination={{
|
|
140
|
-
showSizeChanger: true,
|
|
141
|
-
showQuickJumper: true,
|
|
142
|
-
current: paginationData.page,
|
|
143
|
-
pageSize: paginationData.size,
|
|
144
|
-
total: data?.Total,
|
|
145
|
-
onChange: onPaginationChange,
|
|
146
|
-
}}
|
|
147
|
-
/>
|
|
148
|
-
</>
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export default QueryList
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import {create, useStore} from 'zustand'
|
|
2
|
-
import {createContext, useContext} from 'react'
|
|
3
|
-
import type {StateStorage} from 'zustand/middleware'
|
|
4
|
-
import {createJSONStorage, persist} from 'zustand/middleware'
|
|
5
|
-
import type {GameType} from '../GameSelect'
|
|
6
|
-
import type {ItemType2} from '../NavMenu'
|
|
7
|
-
|
|
8
|
-
// SessionStorage 在同一域下的不同页面间是隔离的,用于防止多开页面时的数据冲突
|
|
9
|
-
const mixedStorage: StateStorage = {
|
|
10
|
-
getItem: (name: string): string | null => {
|
|
11
|
-
return sessionStorage.getItem(name) || localStorage.getItem(name)
|
|
12
|
-
},
|
|
13
|
-
setItem: (name: string, value: string) => {
|
|
14
|
-
localStorage.setItem(name, value)
|
|
15
|
-
sessionStorage.setItem(name, value)
|
|
16
|
-
},
|
|
17
|
-
removeItem: async (name: string) => {
|
|
18
|
-
localStorage.removeItem(name)
|
|
19
|
-
sessionStorage.removeItem(name)
|
|
20
|
-
},
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface ReactToolkitsState {
|
|
24
|
-
title: string
|
|
25
|
-
isPermissionV2: boolean
|
|
26
|
-
isGlobalNS: boolean
|
|
27
|
-
game: GameType | null
|
|
28
|
-
setGame: (game: GameType | null) => void
|
|
29
|
-
openKeys: string[]
|
|
30
|
-
selectedKeys: string[]
|
|
31
|
-
setOpenKeys: (keys: string[]) => void
|
|
32
|
-
setSelectedKeys: (keys: string[]) => void
|
|
33
|
-
menuItems: ItemType2[]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export type ReactToolkitsStore = ReturnType<typeof createReactToolkitsStore>
|
|
37
|
-
|
|
38
|
-
export const createReactToolkitsStore = () => {
|
|
39
|
-
return create<ReactToolkitsState>()(
|
|
40
|
-
persist(
|
|
41
|
-
set => ({
|
|
42
|
-
title: '',
|
|
43
|
-
isPermissionV2: false,
|
|
44
|
-
isGlobalNS: false,
|
|
45
|
-
game: null,
|
|
46
|
-
setGame: game => set({ game }),
|
|
47
|
-
openKeys: [],
|
|
48
|
-
setOpenKeys: keys => set({ openKeys: keys }),
|
|
49
|
-
selectedKeys: [],
|
|
50
|
-
setSelectedKeys: keys => set({ selectedKeys: keys }),
|
|
51
|
-
menuItems: [],
|
|
52
|
-
}),
|
|
53
|
-
{
|
|
54
|
-
name: 'ReactToolkits',
|
|
55
|
-
storage: createJSONStorage(() => mixedStorage),
|
|
56
|
-
partialize: state => ({
|
|
57
|
-
title: state.title,
|
|
58
|
-
game: state.game,
|
|
59
|
-
openKeys: state.openKeys,
|
|
60
|
-
selectedKeys: state.selectedKeys,
|
|
61
|
-
}),
|
|
62
|
-
},
|
|
63
|
-
),
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export const ReactToolkitsContext = createContext<ReactToolkitsStore | null>(null)
|
|
68
|
-
|
|
69
|
-
export function useReactToolkitsContext<T>(
|
|
70
|
-
selector: (state: ReactToolkitsState) => T,
|
|
71
|
-
equalityFn?: (left: T, right: T) => boolean,
|
|
72
|
-
): T {
|
|
73
|
-
const store = useContext(ReactToolkitsContext)
|
|
74
|
-
if (!store) throw new Error('Missing ReactToolkitsContext.Provider in the tree')
|
|
75
|
-
return useStore(store, selector, equalityFn)
|
|
76
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { FC, PropsWithChildren } from 'react'
|
|
2
|
-
import { useEffect, useRef } from 'react'
|
|
3
|
-
import type { ReactToolkitsState, ReactToolkitsStore } from './context'
|
|
4
|
-
import { createReactToolkitsStore, ReactToolkitsContext } from './context'
|
|
5
|
-
|
|
6
|
-
const ReactToolkitsProvider: FC<
|
|
7
|
-
PropsWithChildren<Partial<Pick<ReactToolkitsState, 'isPermissionV2' | 'isGlobalNS' | 'menuItems' | 'title'>>>
|
|
8
|
-
> = props => {
|
|
9
|
-
const { children, ...restProps } = props
|
|
10
|
-
const storeRef = useRef<ReactToolkitsStore>()
|
|
11
|
-
|
|
12
|
-
if (!storeRef.current) {
|
|
13
|
-
storeRef.current = createReactToolkitsStore()
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
storeRef.current?.setState(restProps)
|
|
18
|
-
}, [restProps])
|
|
19
|
-
|
|
20
|
-
return <ReactToolkitsContext.Provider value={storeRef.current}>{children}</ReactToolkitsContext.Provider>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default ReactToolkitsProvider
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { FC } from 'react'
|
|
2
|
-
import { useNavigate } from 'react-router-dom'
|
|
3
|
-
import { Dropdown, Space } from 'antd'
|
|
4
|
-
import Link from 'antd/es/typography/Link'
|
|
5
|
-
import { LogoutOutlined, UserOutlined } from '@ant-design/icons'
|
|
6
|
-
import { useTokenStore } from '@/stores'
|
|
7
|
-
|
|
8
|
-
const UserWidget: FC = props => {
|
|
9
|
-
const navigate = useNavigate()
|
|
10
|
-
const clearToken = useTokenStore(state => state.clearToken)
|
|
11
|
-
const user = useTokenStore(state => state.getUser())
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<Dropdown
|
|
15
|
-
menu={{
|
|
16
|
-
selectable: true,
|
|
17
|
-
items: [
|
|
18
|
-
{
|
|
19
|
-
key: '1',
|
|
20
|
-
label: (
|
|
21
|
-
<Link
|
|
22
|
-
onClick={() => {
|
|
23
|
-
clearToken()
|
|
24
|
-
navigate('/login')
|
|
25
|
-
}}
|
|
26
|
-
>
|
|
27
|
-
登出
|
|
28
|
-
</Link>
|
|
29
|
-
),
|
|
30
|
-
icon: <LogoutOutlined />,
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
}}
|
|
34
|
-
placement="bottomRight"
|
|
35
|
-
>
|
|
36
|
-
<Link>
|
|
37
|
-
<Space align="center">
|
|
38
|
-
<span>{user?.authorityId}</span>
|
|
39
|
-
<UserOutlined style={{ fontSize: '16px' }} />
|
|
40
|
-
</Space>
|
|
41
|
-
</Link>
|
|
42
|
-
</Dropdown>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export default UserWidget
|
package/src/components/index.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { DynamicTagsProps } from './DynamicTags'
|
|
2
|
-
import DynamicTags from './DynamicTags'
|
|
3
|
-
import type { FilterFormProps } from './FilterForm'
|
|
4
|
-
import FilterForm from './FilterForm'
|
|
5
|
-
import type { FormModalProps, FormModalRef } from './FormModal'
|
|
6
|
-
import FormModal from './FormModal'
|
|
7
|
-
import type { UseFormModalProps } from './FormModal/hooks'
|
|
8
|
-
import { useFormModal } from './FormModal/hooks'
|
|
9
|
-
import type { HighlightTextsProps } from './Highlight'
|
|
10
|
-
import Highlight from './Highlight'
|
|
11
|
-
import type { PermissionButtonProps } from './PermissionButton'
|
|
12
|
-
import PermissionButton from './PermissionButton'
|
|
13
|
-
import type { QueryListKey, QueryListProps } from './QueryList'
|
|
14
|
-
import QueryList from './QueryList'
|
|
15
|
-
import { useReactToolkitsContext } from './ReactToolkitsProvider/context'
|
|
16
|
-
import ReactToolkitsProvider from './ReactToolkitsProvider'
|
|
17
|
-
import GameSelect from './GameSelect'
|
|
18
|
-
import UserWidget from './UserWidget'
|
|
19
|
-
import type { ItemType2 } from './NavMenu'
|
|
20
|
-
import NavMenu from './NavMenu'
|
|
21
|
-
import type { LayoutProps } from './Layout'
|
|
22
|
-
import Layout from './Layout'
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
FormModal,
|
|
26
|
-
PermissionButton,
|
|
27
|
-
DynamicTags,
|
|
28
|
-
QueryList,
|
|
29
|
-
FilterForm,
|
|
30
|
-
Highlight,
|
|
31
|
-
useFormModal,
|
|
32
|
-
useReactToolkitsContext,
|
|
33
|
-
ReactToolkitsProvider,
|
|
34
|
-
GameSelect,
|
|
35
|
-
UserWidget,
|
|
36
|
-
NavMenu,
|
|
37
|
-
Layout,
|
|
38
|
-
}
|
|
39
|
-
export type {
|
|
40
|
-
DynamicTagsProps,
|
|
41
|
-
FilterFormProps,
|
|
42
|
-
UseFormModalProps,
|
|
43
|
-
FormModalProps,
|
|
44
|
-
FormModalRef,
|
|
45
|
-
QueryListProps,
|
|
46
|
-
QueryListKey,
|
|
47
|
-
HighlightTextsProps,
|
|
48
|
-
PermissionButtonProps,
|
|
49
|
-
ItemType2,
|
|
50
|
-
LayoutProps,
|
|
51
|
-
}
|
package/src/constants/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const SSO_URL = 'https://idaas.ifunplus.cn/enduser/api/application/plugin_FunPlus/sso/v1'
|