react-toolkits 0.0.8 → 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.
Files changed (38) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/CHANGELOG.md +6 -0
  3. package/README.md +41 -0
  4. package/dist/index.css +251 -1
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.mts +55 -54
  7. package/dist/index.esm.js +3574 -15
  8. package/dist/index.esm.js.map +1 -1
  9. package/package.json +2 -1
  10. package/src/components/GameSelect/index.tsx +82 -0
  11. package/src/components/Layout/index.tsx +90 -0
  12. package/src/{layouts/NavBar.tsx → components/NavMenu/index.tsx} +8 -17
  13. package/src/components/ReactToolkitsProvider/context.ts +76 -0
  14. package/src/components/ReactToolkitsProvider/index.tsx +23 -0
  15. package/src/components/UserWidget/index.tsx +46 -0
  16. package/src/components/index.ts +25 -1
  17. package/src/features/permission/components/PermissionCollapse/index.tsx +121 -0
  18. package/src/features/permission/components/PermissionList/index.tsx +17 -118
  19. package/src/features/permission/components/PermissionListV1/index.tsx +42 -0
  20. package/src/features/permission/components/PermissionListV2/index.tsx +146 -0
  21. package/src/features/permission/hooks/index.ts +24 -9
  22. package/src/features/permission/types/index.ts +8 -1
  23. package/src/hooks/use-http-client.tsx +9 -0
  24. package/src/hooks/use-permission.tsx +10 -2
  25. package/src/index.ts +0 -1
  26. package/src/pages/{NoMatch → base/NotFound}/index.tsx +4 -4
  27. package/src/pages/base/index.tsx +20 -0
  28. package/src/pages/index.ts +3 -4
  29. package/src/pages/permission/RoleList/index.tsx +63 -36
  30. package/src/pages/permission/index.tsx +26 -1
  31. package/src/stores/index.ts +0 -1
  32. package/src/stores/token.ts +15 -1
  33. package/tsup.config.ts +1 -1
  34. package/src/layouts/Layout.tsx +0 -103
  35. package/src/layouts/index.ts +0 -6
  36. package/src/stores/menu.ts +0 -27
  37. /package/src/pages/{Login → base/Login}/default.tsx +0 -0
  38. /package/src/pages/{Login → base/Login}/index.tsx +0 -0
@@ -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 { Role, RoleListItem } from '@/features/permission'
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 RoleList = () => {
19
- const { accessible: viewable } = usePermission('200005')
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 { showModal: showCreateModal, Modal: CreateModal } = useFormModal<{
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: string[]
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
- async onConfirm(values) {
45
- await create.trigger(
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
- const { showModal: showUpdateModal, Modal: UpdateModal } = useFormModal<{
86
+ return useFormModal<{
61
87
  id: number
62
88
  name: string
63
- permissions: string[]
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
- async onConfirm(values) {
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<Role>('/api/usystem/role/info', {
134
- params: { name: value.name },
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,
@@ -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,
@@ -1,3 +1,2 @@
1
- export * from './menu'
2
1
  export * from './token'
3
2
  export * from './query-list'
@@ -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: '' })
package/tsup.config.ts CHANGED
@@ -7,7 +7,7 @@ export default defineConfig({
7
7
  entry: ['src/index.ts'],
8
8
  format: ['esm'],
9
9
  sourcemap: true,
10
- minify: isProduction,
10
+ minify: false,
11
11
  treeshake: true,
12
12
  splitting: false,
13
13
  dts: true,
@@ -1,103 +0,0 @@
1
- import logo from '@/assets/512_orange_nobackground.png'
2
- import { Alert, Layout as AntdLayout, Spin, theme } from 'antd'
3
- import type { FC, PropsWithChildren, ReactNode } from 'react'
4
- import { Suspense } from 'react'
5
- import { Link } from 'react-router-dom'
6
- import type { ItemType2 } from './NavBar'
7
- import NavBar from './NavBar'
8
- import { usePermission } from '@/hooks'
9
-
10
- const { Header, Sider, Content } = AntdLayout
11
- const { ErrorBoundary } = Alert
12
-
13
- export interface LayoutProps {
14
- title?: ReactNode
15
- items: ItemType2[]
16
- header?: ReactNode
17
- }
18
-
19
- const Layout: FC<PropsWithChildren<LayoutProps>> = props => {
20
- const { title, items, header, children } = props
21
- const {
22
- token: { colorBgContainer, colorBorder },
23
- } = theme.useToken()
24
-
25
- // 为了验证 token 是否过期的请求,此处无其他用处。
26
- usePermission('100001')
27
-
28
- return (
29
- <AntdLayout hasSider className="h-screen">
30
- <ErrorBoundary>
31
- <Suspense
32
- fallback={
33
- <Spin
34
- style={{
35
- display: 'flex',
36
- justifyContent: 'center',
37
- alignItems: 'center',
38
- width: '100vw',
39
- height: '100vh',
40
- }}
41
- />
42
- }
43
- >
44
- <Sider
45
- width={256}
46
- style={{
47
- overflow: 'auto',
48
- height: '100vh',
49
- position: 'fixed',
50
- left: 0,
51
- top: 0,
52
- bottom: 0,
53
- borderRightWidth: 1,
54
- borderRightStyle: 'solid',
55
- borderRightColor: colorBorder,
56
- }}
57
- theme="light"
58
- >
59
- <div className="flex items-end px-6 py-4">
60
- <img src={logo} alt="logo" className="w-8 h-8" />
61
- <Link className="font-bold text-lg ml-2" to="/">
62
- {title}
63
- </Link>
64
- </div>
65
-
66
- <NavBar items={items} />
67
- </Sider>
68
- <AntdLayout className="ml-64">
69
- <Header
70
- style={{
71
- padding: '0 24px',
72
- background: colorBgContainer,
73
- borderBottomWidth: 1,
74
- borderBottomStyle: 'solid',
75
- borderBottomColor: colorBorder,
76
- }}
77
- >
78
- {header}
79
- </Header>
80
- <Content className="p-6 overflow-auto bg-gray-50">
81
- <Suspense
82
- fallback={
83
- <Spin
84
- style={{
85
- display: 'flex',
86
- justifyContent: 'center',
87
- alignItems: 'center',
88
- height: '50vh',
89
- }}
90
- />
91
- }
92
- >
93
- {children}
94
- </Suspense>
95
- </Content>
96
- </AntdLayout>
97
- </Suspense>
98
- </ErrorBoundary>
99
- </AntdLayout>
100
- )
101
- }
102
-
103
- export default Layout
@@ -1,6 +0,0 @@
1
- import type { LayoutProps } from './Layout'
2
- import Layout from './Layout'
3
- import type { ItemType2, NavBarProps } from './NavBar'
4
-
5
- export { Layout }
6
- export type { ItemType2, LayoutProps, NavBarProps }
@@ -1,27 +0,0 @@
1
- import { create } from 'zustand'
2
- import { persist } from 'zustand/middleware'
3
-
4
- export interface MenuState {
5
- openKeys: string[]
6
- selectedKeys: string[]
7
- setOpenKeys: (keys: string[]) => void
8
- setSelectedKeys: (keys: string[]) => void
9
- }
10
-
11
- export const useMenuStore = create<MenuState>()(
12
- persist(
13
- set => ({
14
- openKeys: [],
15
- selectedKeys: [],
16
- setOpenKeys: keys => set({ openKeys: keys }),
17
- setSelectedKeys: keys => set({ selectedKeys: keys }),
18
- }),
19
- {
20
- name: 'menu',
21
- partialize: state => ({
22
- openKeys: state.openKeys,
23
- selectedKeys: state.selectedKeys,
24
- }),
25
- },
26
- ),
27
- )
File without changes
File without changes