react-toolkits 0.0.4 → 0.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-toolkits",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "sideEffects": [
5
5
  "**/*.css"
6
6
  ],
@@ -1,6 +1,7 @@
1
1
  import type { FormInstance, FormProps } from 'antd'
2
2
  import { Button, Col, Form, Row, Space, theme } from 'antd'
3
3
  import type { PropsWithChildren } from 'react'
4
+ import * as React from 'react'
4
5
 
5
6
  export interface FilterFormProps<Values>
6
7
  extends Pick<
@@ -1,8 +1,8 @@
1
- import { useFetcher, usePermission } from '@/hooks'
1
+ import { useHttpClient, usePermission } from '@/hooks'
2
2
  import { useQueryTriggerStore } from '@/stores'
3
3
  import type { ListResponse, PaginationParams } from '@/types'
4
4
  import type { FormInstance, FormProps } from 'antd'
5
- import { Form, Result, Spin, Table } from 'antd'
5
+ import { Form, Result, Table } from 'antd'
6
6
  import type { TableProps } from 'antd/es/table'
7
7
  import type { AxiosRequestConfig } from 'axios'
8
8
  import type { ReactNode } from 'react'
@@ -27,7 +27,7 @@ export interface QueryListProps<Item, Values>
27
27
 
28
28
  const QueryList = <Item extends object, Values = NonNullable<unknown>>(props: QueryListProps<Item, Values>) => {
29
29
  const { code, confirmText, labelCol, swrKey, renderForm, transformArg, initialValues, ...tableProps } = props
30
- const { accessible, isValidating } = usePermission(code)
30
+ const { accessible } = usePermission(code ?? '')
31
31
  const [form] = Form.useForm<Values>()
32
32
  const setTrigger = useQueryTriggerStore(state => state.setTrigger)
33
33
 
@@ -36,7 +36,7 @@ const QueryList = <Item extends object, Values = NonNullable<unknown>>(props: Qu
36
36
  perPage: 10,
37
37
  })
38
38
 
39
- const fetcher = useFetcher()
39
+ const httpClient = useHttpClient()
40
40
 
41
41
  const { data, isMutating, trigger } = useSWRMutation(
42
42
  swrKey,
@@ -62,10 +62,10 @@ const QueryList = <Item extends object, Values = NonNullable<unknown>>(props: Qu
62
62
  ...newPaginationData,
63
63
  }
64
64
 
65
- return fetcher<ListResponse<Item>>({
65
+ return httpClient.request<ListResponse<Item>>({
66
66
  ...key,
67
- // TODO: 兼容 params data
68
- params: typeof transformArg === 'function' ? transformArg(fetcherArg) : fetcherArg,
67
+ [key.method === 'POST' ? 'data' : 'params']:
68
+ typeof transformArg === 'function' ? transformArg(fetcherArg) : fetcherArg,
69
69
  })
70
70
  },
71
71
  )
@@ -96,7 +96,7 @@ const QueryList = <Item extends object, Values = NonNullable<unknown>>(props: Qu
96
96
 
97
97
  useEffect(() => {
98
98
  setTrigger(swrKey, trigger)
99
- }, [swrKey, setTrigger, trigger])
99
+ }, [swrKey, trigger, setTrigger])
100
100
 
101
101
  useEffect(() => {
102
102
  ;(async () => {
@@ -109,19 +109,6 @@ const QueryList = <Item extends object, Values = NonNullable<unknown>>(props: Qu
109
109
  })()
110
110
  }, [form, trigger])
111
111
 
112
- if (isValidating) {
113
- return (
114
- <Spin
115
- style={{
116
- display: 'flex',
117
- justifyContent: 'center',
118
- alignItems: 'center',
119
- height: 200,
120
- }}
121
- />
122
- )
123
- }
124
-
125
112
  if (!accessible) {
126
113
  return <Result status={403} subTitle="无权限,请联系管理员进行授权" />
127
114
  }
@@ -1,3 +1 @@
1
1
  export const SSO_URL = 'https://idaas.ifunplus.cn/enduser/api/application/plugin_FunPlus/sso/v1'
2
-
3
- export const SECRET = new TextEncoder().encode('cc7e0d44fd473002f1c42167459001140ec6389b7353f8088f4d9a95f2f596f2')
@@ -1,4 +1,4 @@
1
- import { useFetcher, usePermission } from '@/hooks'
1
+ import { useHttpClient, usePermission } from '@/hooks'
2
2
  import useSWR from 'swr'
3
3
  import useSWRMutation from 'swr/mutation'
4
4
  import type { PermissionEnumItem, RoleEnumItem } from '../types'
@@ -29,7 +29,7 @@ export function useRole(name: string) {
29
29
  }
30
30
 
31
31
  export function useCreateRole() {
32
- const fetcher = useFetcher()
32
+ const httpClient = useHttpClient()
33
33
 
34
34
  return useSWRMutation(
35
35
  '/api/usystem/role/create',
@@ -40,12 +40,12 @@ export function useCreateRole() {
40
40
  }: {
41
41
  arg: { name: string; permissions: string[] }
42
42
  },
43
- ) => fetcher({ method: 'POST', url, data: arg }),
43
+ ) => httpClient.post(url, arg),
44
44
  )
45
45
  }
46
46
 
47
47
  export function useUpdateRole() {
48
- const fetcher = useFetcher()
48
+ const httpClient = useHttpClient()
49
49
 
50
50
  return useSWRMutation(
51
51
  '/api/usystem/role/update',
@@ -56,12 +56,12 @@ export function useUpdateRole() {
56
56
  }: {
57
57
  arg: { id: number; name: string; permissions: string[] }
58
58
  },
59
- ) => fetcher({ method: 'POST', url, data: arg }),
59
+ ) => httpClient.post(url, arg),
60
60
  )
61
61
  }
62
62
 
63
63
  export function useRemoveRole() {
64
- const fetcher = useFetcher()
64
+ const httpClient = useHttpClient()
65
65
 
66
66
  return useSWRMutation(
67
67
  '/api/usystem/role/delete',
@@ -72,12 +72,12 @@ export function useRemoveRole() {
72
72
  }: {
73
73
  arg: { id: number; name: string }
74
74
  },
75
- ) => fetcher({ method: 'POST', url, data: arg }),
75
+ ) => httpClient.post(url, arg),
76
76
  )
77
77
  }
78
78
 
79
79
  export function useCreateUser() {
80
- const fetcher = useFetcher()
80
+ const httpClient = useHttpClient()
81
81
 
82
82
  return useSWRMutation(
83
83
  '/api/usystem/user/create',
@@ -88,17 +88,12 @@ export function useCreateUser() {
88
88
  }: {
89
89
  arg: { name: string; roles: string[] }
90
90
  },
91
- ) =>
92
- fetcher({
93
- method: 'POST',
94
- url,
95
- data: arg,
96
- }),
91
+ ) => httpClient.post(url, arg),
97
92
  )
98
93
  }
99
94
 
100
95
  export function useUpdateUser() {
101
- const fetcher = useFetcher()
96
+ const httpClient = useHttpClient()
102
97
 
103
98
  return useSWRMutation(
104
99
  '/api/usystem/user/update',
@@ -109,17 +104,12 @@ export function useUpdateUser() {
109
104
  }: {
110
105
  arg: { id: string; name: string; roles: string[] }
111
106
  },
112
- ) =>
113
- fetcher({
114
- method: 'POST',
115
- url,
116
- data: arg,
117
- }),
107
+ ) => httpClient.post(url, arg),
118
108
  )
119
109
  }
120
110
 
121
111
  export function useRemoveUser() {
122
- const fetcher = useFetcher()
112
+ const httpClient = useHttpClient()
123
113
 
124
114
  return useSWRMutation(
125
115
  '/api/usystem/user/delete',
@@ -130,11 +120,6 @@ export function useRemoveUser() {
130
120
  }: {
131
121
  arg: { id: string; name: string }
132
122
  },
133
- ) =>
134
- fetcher({
135
- method: 'POST',
136
- url,
137
- data: arg,
138
- }),
123
+ ) => httpClient.post(url, arg),
139
124
  )
140
125
  }
@@ -1,2 +1,2 @@
1
- export * from './use-fetcher'
1
+ export * from './use-http-client'
2
2
  export * from './use-permission'
@@ -1,10 +1,7 @@
1
- import { useTokenStore } from '@/stores'
2
- import type { BackendResponse } from '@/types'
3
- import { App } from 'antd'
4
- import type { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'
1
+ import {useTokenStore} from '@/stores'
2
+ import type {AxiosInstance, AxiosRequestConfig} from 'axios'
5
3
  import axios from 'axios'
6
- import { useNavigate } from 'react-router-dom'
7
- import type { Merge } from 'ts-essentials'
4
+ import type {Merge} from 'ts-essentials'
8
5
 
9
6
  // 覆盖 AxiosInstance 各种请求方法的返回值,为了方便我们在 interceptors.response 里把 AxiosResponse 直接打平成后端返回的数据,去掉了 axios 的封装。
10
7
  type ShimmedAxiosInstance = Merge<
@@ -20,22 +17,19 @@ type ShimmedAxiosInstance = Merge<
20
17
  }
21
18
  >
22
19
 
23
- export class FetcherError extends Error {
24
- code: number
20
+ export class HttpClientError extends Error {
21
+ code?: number
25
22
  // 跳过错误提示
26
23
  skip: boolean
27
24
 
28
- constructor(message: string, code: number, skip = false) {
25
+ constructor(message: string, code?: number, skip = false) {
29
26
  super(message)
30
27
  this.code = code
31
28
  this.skip = skip
32
29
  }
33
30
  }
34
31
 
35
- export function useFetcher() {
36
- const { notification } = App.useApp()
37
- const clearToken = useTokenStore(state => state.clearToken)
38
- const navigate = useNavigate()
32
+ export function useHttpClient() {
39
33
  const token = useTokenStore(state => state.token)
40
34
 
41
35
  const defaultOptions: AxiosRequestConfig = {
@@ -56,47 +50,27 @@ export function useFetcher() {
56
50
  return response.data.data
57
51
  }
58
52
 
59
- throw new FetcherError(response.data.msg, 0)
53
+ throw new HttpClientError(response.data.msg, 0)
60
54
  },
61
- (error: AxiosError<BackendResponse<unknown>>) => {
55
+ error => {
62
56
  if (error.response) {
63
57
  // 请求成功发出且服务器也响应了状态码,但状态码超出了 2xx 的范围
64
58
  if (error.response.status === 401) {
65
- throw new FetcherError('未登录或登录已过期', error.response.status)
59
+ throw new HttpClientError('未登录或登录已过期', error.response.status)
66
60
  } else if (error.response.status === 403) {
67
- throw new FetcherError('无权限,请联系管理员进行授权', error.response.status)
61
+ throw new HttpClientError('无权限,请联系管理员进行授权', error.response.status)
68
62
  } else if ([404, 405].includes(error.response.status)) {
69
- throw new FetcherError('Not Found or Method not Allowed', error.response.status, true)
63
+ throw new HttpClientError('Not Found or Method not Allowed', error.response.status, true)
70
64
  } else if (error.response.status === 412) {
71
- throw new FetcherError('未注册用户', error.response.status)
65
+ throw new HttpClientError('未注册用户', error.response.status)
72
66
  } else {
73
- throw new FetcherError(error.response.data?.msg, error.response.status)
67
+ throw new HttpClientError(error.response.data?.msg, error.response.status)
74
68
  }
75
- } else if (error.request) {
76
- // 请求已经成功发起,但没有收到响应
77
- console.log(error.request)
78
69
  }
79
70
 
80
- return Promise.reject(error)
71
+ throw new HttpClientError('无响应')
81
72
  },
82
73
  )
83
74
 
84
- return <T = unknown,>(config: AxiosRequestConfig) =>
85
- instance.request<T>(config).catch((err: FetcherError) => {
86
- switch (err.code) {
87
- case 401:
88
- case 412:
89
- clearToken()
90
- navigate(err.code === 401 ? '/login' : '/login?not_registered=1', { replace: true })
91
- break
92
- default:
93
- if (!err.skip) {
94
- notification.error({
95
- message: '请求出错',
96
- description: err.message,
97
- })
98
- }
99
- }
100
- throw err
101
- })
75
+ return instance
102
76
  }
@@ -1,12 +1,14 @@
1
1
  import useSWRImmutable from 'swr/immutable'
2
- import { useFetcher } from './use-fetcher'
2
+ import { useNavigate } from 'react-router-dom'
3
+ import { useHttpClient } from './use-http-client'
3
4
 
4
5
  export interface PermissionCheckResult {
5
6
  [k: string]: boolean
6
7
  }
7
8
 
8
9
  export function usePermissions(codes: string[]) {
9
- const fetcher = useFetcher()
10
+ const httpClient = useHttpClient()
11
+ const navigate = useNavigate()
10
12
 
11
13
  const { data, isLoading } = useSWRImmutable(
12
14
  codes.length > 0
@@ -17,7 +19,7 @@ export function usePermissions(codes: string[]) {
17
19
  }
18
20
  : null,
19
21
  config =>
20
- fetcher<PermissionCheckResult>(config).then(res => {
22
+ httpClient.request<PermissionCheckResult>(config).then(res => {
21
23
  if (res.has_all) {
22
24
  return codes.reduce(
23
25
  (acc, curr) => {
@@ -37,14 +39,18 @@ export function usePermissions(codes: string[]) {
37
39
  )
38
40
  }),
39
41
  {
42
+ suspense: true,
40
43
  shouldRetryOnError: false,
44
+ onError() {
45
+ navigate('/login')
46
+ },
41
47
  },
42
48
  )
43
49
 
44
50
  return { data, isLoading }
45
51
  }
46
52
 
47
- export function usePermission(code?: string) {
53
+ export function usePermission(code: string) {
48
54
  const { data, isLoading } = usePermissions(code ? [code] : [])
49
55
 
50
56
  if (!code) {
package/src/index.ts CHANGED
@@ -5,3 +5,4 @@ export * from './hooks'
5
5
  export * from './stores'
6
6
  export * from './pages'
7
7
  export * from './layouts'
8
+ export * from './constants'
@@ -1,11 +1,14 @@
1
1
  import logo from '@/assets/512_orange_nobackground.png'
2
- import { Layout as AntdLayout, theme } from 'antd'
2
+ import { Alert, Layout as AntdLayout, Spin, theme } from 'antd'
3
3
  import type { FC, PropsWithChildren, ReactNode } from 'react'
4
+ import { Suspense } from 'react'
4
5
  import { Link } from 'react-router-dom'
5
6
  import type { ItemType2 } from './NavBar'
6
7
  import NavBar from './NavBar'
8
+ import { usePermission } from '@/hooks'
7
9
 
8
10
  const { Header, Sider, Content } = AntdLayout
11
+ const { ErrorBoundary } = Alert
9
12
 
10
13
  export interface LayoutProps {
11
14
  title?: ReactNode
@@ -19,45 +22,80 @@ const Layout: FC<PropsWithChildren<LayoutProps>> = props => {
19
22
  token: { colorBgContainer, colorBorder },
20
23
  } = theme.useToken()
21
24
 
25
+ // 为了验证 token 是否过期的请求,此处无其他用处。
26
+ usePermission('100001')
27
+
22
28
  return (
23
29
  <AntdLayout hasSider className="h-screen">
24
- <Sider
25
- width={256}
26
- style={{
27
- overflow: 'auto',
28
- height: '100vh',
29
- position: 'fixed',
30
- left: 0,
31
- top: 0,
32
- bottom: 0,
33
- borderRightWidth: 1,
34
- borderRightStyle: 'solid',
35
- borderRightColor: colorBorder,
36
- }}
37
- theme="light"
38
- >
39
- <div className="flex items-end px-6 py-4">
40
- <img src={logo} alt="logo" className="w-8 h-8" />
41
- <Link className="font-bold text-lg ml-2" to="/">
42
- {title}
43
- </Link>
44
- </div>
45
- <NavBar items={items} />
46
- </Sider>
47
- <AntdLayout className="ml-64">
48
- <Header
49
- style={{
50
- padding: '0 24px',
51
- background: colorBgContainer,
52
- borderBottomWidth: 1,
53
- borderBottomStyle: 'solid',
54
- borderBottomColor: colorBorder,
55
- }}
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
+ }
56
43
  >
57
- {header}
58
- </Header>
59
- <Content className="p-6 overflow-auto bg-gray-50">{children}</Content>
60
- </AntdLayout>
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>
61
99
  </AntdLayout>
62
100
  )
63
101
  }
@@ -1,6 +1,6 @@
1
- import { usePermissions } from '@/hooks'
2
- import { useMenuStore } from '@/stores'
3
- import { Menu, Spin } from 'antd'
1
+ import {usePermissions} from '@/hooks'
2
+ import {useMenuStore} from '@/stores'
3
+ import {Menu} from 'antd'
4
4
  import type {
5
5
  ItemType,
6
6
  MenuDividerType,
@@ -8,10 +8,10 @@ import type {
8
8
  MenuItemType,
9
9
  SubMenuType,
10
10
  } from 'antd/es/menu/hooks/useItems'
11
- import type { FC, ReactNode } from 'react'
12
- import { useCallback, useEffect, useMemo } from 'react'
13
- import { Link, useLocation } from 'react-router-dom'
14
- import type { Merge } from 'ts-essentials'
11
+ import type {FC, ReactNode} from 'react'
12
+ import {useCallback, useEffect, useMemo} from 'react'
13
+ import {Link, useLocation} from 'react-router-dom'
14
+ import type {Merge} from 'ts-essentials'
15
15
 
16
16
  // 扩展 antd Menu 的类型,使其支持一些我们想要的自定义字段。
17
17
  type MenuItemType2 = Merge<
@@ -107,7 +107,7 @@ const NavBar: FC<NavBarProps> = props => {
107
107
  const location = useLocation()
108
108
  const flattenItems = useMemo(() => flatItems(items ?? []), [items])
109
109
  const codes = flattenItems.map(item => item.code).filter(Boolean) as string[]
110
- const { data: permissions, isLoading } = usePermissions(codes)
110
+ const { data: permissions } = usePermissions(codes)
111
111
  const internalItems = useMemo(() => transformItems(items ?? [], permissions), [items, permissions])
112
112
 
113
113
  const openKeys = useMenuStore(state => state.openKeys)
@@ -136,19 +136,6 @@ const NavBar: FC<NavBarProps> = props => {
136
136
  }
137
137
  }, [flattenItems, location, setOpenKeys, setSelectedKeys])
138
138
 
139
- if (isLoading) {
140
- return (
141
- <Spin
142
- style={{
143
- display: 'flex',
144
- justifyContent: 'center',
145
- alignItems: 'center',
146
- height: 'calc(100vh - 64px)',
147
- }}
148
- />
149
- )
150
- }
151
-
152
139
  return (
153
140
  <Menu
154
141
  style={{ borderRight: 'none' }}
@@ -7,6 +7,7 @@ import { useEffect, useState } from 'react'
7
7
  import { Navigate, useSearchParams } from 'react-router-dom'
8
8
  import useSWRImmutable from 'swr/immutable'
9
9
  import Default from './default'
10
+ import { useHttpClient } from '@/hooks'
10
11
 
11
12
  const { Title } = Typography
12
13
 
@@ -16,6 +17,7 @@ const Login: FC<PropsWithChildren> = props => {
16
17
  const token = useTokenStore(state => state.token)
17
18
  const setToken = useTokenStore(state => state.setToken)
18
19
  const [showAlert, setShowAlert] = useState(false)
20
+ const httpClient = useHttpClient()
19
21
 
20
22
  const { isLoading } = useSWRImmutable<{ token: string }>(
21
23
  searchParams.has('ticket')
@@ -26,6 +28,7 @@ const Login: FC<PropsWithChildren> = props => {
26
28
  },
27
29
  }
28
30
  : null,
31
+ config => httpClient.request(config),
29
32
  {
30
33
  onSuccess: data => {
31
34
  setToken(data.token)
@@ -0,0 +1,27 @@
1
+ import { Button, Result } from 'antd'
2
+ import { useNavigate } from 'react-router-dom'
3
+
4
+ const NoMatch = () => {
5
+ const navigate = useNavigate()
6
+ return (
7
+ <div className="h-screen flex justify-center items-center">
8
+ <Result
9
+ status="404"
10
+ title="404"
11
+ subTitle="Sorry, the page you visited does not exist."
12
+ extra={
13
+ <Button
14
+ type="primary"
15
+ onClick={() => {
16
+ navigate('/')
17
+ }}
18
+ >
19
+ Back Home
20
+ </Button>
21
+ }
22
+ />
23
+ </div>
24
+ )
25
+ }
26
+
27
+ export default NoMatch
@@ -1,4 +1,5 @@
1
1
  import Login from './Login'
2
+ import NoMatch from './NoMatch'
2
3
  import permission from './permission'
3
4
 
4
- export { Login, permission }
5
+ export { Login, NoMatch, permission }
@@ -2,7 +2,7 @@ import { Highlight, PermissionButton, QueryList } from '@/components'
2
2
  import { useFormModal } from '@/components/FormModal/hooks'
3
3
  import type { Role, RoleListItem } from '@/features/permission'
4
4
  import { PermissionList, useCreateRole, useRemoveRole, useUpdateRole } from '@/features/permission'
5
- import { useFetcher, usePermission } from '@/hooks'
5
+ import { useHttpClient, usePermission } from '@/hooks'
6
6
  import { useQueryTriggerStore } from '@/stores'
7
7
  import { UsergroupAddOutlined } from '@ant-design/icons'
8
8
  import type { TableColumnsType } from 'antd'
@@ -17,7 +17,7 @@ export const swrKey = {
17
17
  const RoleList = () => {
18
18
  const { accessible: viewable } = usePermission('200005')
19
19
  const { modal, message } = App.useApp()
20
- const fetcher = useFetcher()
20
+ const httpClient = useHttpClient()
21
21
  const create = useCreateRole()
22
22
  const remove = useRemoveRole()
23
23
  const update = useUpdateRole()
@@ -129,9 +129,7 @@ const RoleList = () => {
129
129
  size="small"
130
130
  type="link"
131
131
  onClick={async () => {
132
- const role = await fetcher<Role>({
133
- method: 'GET',
134
- url: '/api/usystem/role/info',
132
+ const role = await httpClient.get<Role>('/api/usystem/role/info', {
135
133
  params: { name: value.name },
136
134
  })
137
135
  showUpdateModal({
@@ -153,11 +151,13 @@ const RoleList = () => {
153
151
  onClick={() => {
154
152
  modal.confirm({
155
153
  title: '删除角色',
156
- content: <Highlight texts={[value.name]}>
157
- 确定要删除角色&nbsp;
158
- {value.name}
159
- &nbsp;吗?
160
- </Highlight>,
154
+ content: (
155
+ <Highlight texts={[value.name]}>
156
+ 确定要删除角色&nbsp;
157
+ {value.name}
158
+ &nbsp;吗?
159
+ </Highlight>
160
+ ),
161
161
  async onOk() {
162
162
  await remove.trigger(
163
163
  {
@@ -182,7 +182,7 @@ const RoleList = () => {
182
182
  },
183
183
  },
184
184
  ],
185
- [trigger, viewable, fetcher, modal, message, remove, showUpdateModal],
185
+ [trigger, viewable, httpClient, modal, message, remove, showUpdateModal],
186
186
  )
187
187
 
188
188
  return (