index.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. import { Key, useEffect, useState } from 'react'
  2. import { LockFlag } from '#/enum'
  3. import { toast } from 'sonner'
  4. import { deleteUser, getUserListPage } from '@/api/services/user'
  5. import { Button, Card, Col, Popconfirm, Row, Tag } from 'antd'
  6. import { PlusOutlined } from '@ant-design/icons'
  7. import type { ProColumns } from '@ant-design/pro-components'
  8. import { ProTable } from '@ant-design/pro-components'
  9. import { AddModal, AddModalProps } from './components/AddModal'
  10. import DeptTreeSelect from './components/DeptTreeSelect'
  11. import { IconButton, Iconify } from '@/components/icon'
  12. const nameColorList = ['#71BC78', '#5BB4EB', '#F28CAE', '#ED9848', '#DB93DB']
  13. export default function RolePage() {
  14. const [searchForm, setSearchForm] = useState({})
  15. const [page, setPage] = useState({ total: 0, currentPage: 1, pageSize: 20 })
  16. const [tableData, setTableData] = useState<API.UserListPageResult>([])
  17. const [isLoading, setIsLoading] = useState(false)
  18. const onDeptTreeSelect = (values: Key[]) => {
  19. setSearchForm((prev) => ({ ...prev, deptId: values[0] }))
  20. }
  21. const getList = async () => {
  22. setTableData([])
  23. setIsLoading(true)
  24. const res = await getUserListPage(
  25. Object.assign(
  26. {
  27. current: page.currentPage,
  28. size: page.pageSize
  29. },
  30. searchForm
  31. )
  32. )
  33. if (res) {
  34. setTableData(res.data.records)
  35. setPage((prev) => ({ ...prev, total: res.data.total }))
  36. }
  37. setIsLoading(false)
  38. }
  39. useEffect(() => {
  40. getList()
  41. }, [searchForm, page.currentPage, page.pageSize])
  42. const [addUserModalProps, setAddUserModalProps] = useState<AddModalProps>({
  43. show: false,
  44. onCancel: () => {
  45. setAddUserModalProps((prev) => ({ ...prev, show: false }))
  46. },
  47. getList: () => {
  48. getList()
  49. }
  50. })
  51. const editFn = (record: API.UserListPageResultItem) => {
  52. console.log(record)
  53. }
  54. const deleteFn = async (row: API.UserListPageResultItem) => {
  55. const res = await deleteUser(row.userId)
  56. if (res) {
  57. getList()
  58. toast.success('删除成功', {
  59. position: 'top-center'
  60. })
  61. }
  62. }
  63. const columns: ProColumns<API.UserListPageResultItem>[] = [
  64. {
  65. title: '序号',
  66. dataIndex: 'index',
  67. valueType: 'indexBorder',
  68. width: 50
  69. },
  70. {
  71. title: '用户名',
  72. dataIndex: 'username',
  73. width: 160,
  74. render: (_, record, index) => {
  75. return (
  76. <div className='flex'>
  77. <div
  78. className='w-[40px] h-[40px] rounded-full mr-[8px] text-[#fff] text-center leading-[40px] text-[16px]'
  79. style={{ backgroundColor: nameColorList[index % 5] }}>
  80. <span>{record?.username?.slice(0, 1)?.toUpperCase() || '-'}</span>
  81. </div>
  82. <div className='ml-2 flex flex-col'>
  83. <span className='text-sm'>{record.username}</span>
  84. <span className='text-xs text-text-secondary'>{record.phone}</span>
  85. </div>
  86. </div>
  87. )
  88. }
  89. },
  90. {
  91. title: '姓名',
  92. dataIndex: 'realName',
  93. width: 100
  94. },
  95. {
  96. title: '手机号',
  97. dataIndex: 'phone',
  98. width: 120,
  99. hideInTable: true
  100. },
  101. {
  102. title: '角色',
  103. dataIndex: 'roleList',
  104. width: 120,
  105. search: false,
  106. render: (_, record) => {
  107. return record.roleList.length === 1 ? (
  108. <Tag color='processing'>{record.roleList[0].roleName}</Tag>
  109. ) : (
  110. <div className='overflow-hidden text-ellipsis whitespace-nowrap'>
  111. {record.roleList.map((item) => {
  112. return (
  113. <Tag color='processing' key={item.roleId}>
  114. {item.roleName}
  115. </Tag>
  116. )
  117. })}
  118. </div>
  119. )
  120. }
  121. },
  122. {
  123. title: '状态',
  124. dataIndex: 'lockFlag',
  125. width: 80,
  126. search: false,
  127. render: (lockFlag) => (
  128. <Tag
  129. color={
  130. lockFlag === LockFlag.OK
  131. ? 'success'
  132. : lockFlag === LockFlag.LOCKED
  133. ? 'error'
  134. : lockFlag === LockFlag.DELETED
  135. ? 'default'
  136. : ''
  137. }>
  138. {lockFlag === LockFlag.OK
  139. ? '正常'
  140. : lockFlag === LockFlag.LOCKED
  141. ? '锁定'
  142. : lockFlag === LockFlag.DELETED
  143. ? '删除'
  144. : ''}
  145. </Tag>
  146. )
  147. },
  148. {
  149. title: '创建时间',
  150. dataIndex: 'createdTime',
  151. width: 120,
  152. search: false
  153. },
  154. {
  155. title: '操作',
  156. key: 'operation',
  157. align: 'center',
  158. width: 100,
  159. search: false,
  160. render: (_, record) => (
  161. <div className='flex w-full justify-center text-gray-500'>
  162. <IconButton
  163. onClick={() => {
  164. editFn(record)
  165. }}>
  166. <Iconify icon='mdi:card-account-details' size={18} />
  167. </IconButton>
  168. <IconButton onClick={() => {}}>
  169. <Iconify icon='solar:pen-bold-duotone' size={18} />
  170. </IconButton>
  171. <Popconfirm
  172. title='确定删除?'
  173. okText='确定'
  174. cancelText='取消'
  175. placement='left'
  176. onConfirm={() => {
  177. deleteFn(record)
  178. }}>
  179. <IconButton>
  180. <Iconify icon='mingcute:delete-2-fill' size={18} className='text-error' />
  181. </IconButton>
  182. </Popconfirm>
  183. </div>
  184. )
  185. }
  186. ]
  187. return (
  188. <Card bordered={false}>
  189. <Row gutter={16}>
  190. <Col span={5}>
  191. <DeptTreeSelect onSelect={onDeptTreeSelect} />
  192. </Col>
  193. <Col span={19}>
  194. <ProTable<API.UserListPageResultItem>
  195. headerTitle='用户管理'
  196. cardBordered
  197. rowKey='userId'
  198. loading={isLoading}
  199. columns={columns}
  200. dataSource={tableData}
  201. pagination={{
  202. current: page.currentPage,
  203. pageSize: page.pageSize,
  204. total: page.total,
  205. showSizeChanger: true,
  206. showQuickJumper: true,
  207. onChange: (page) => {
  208. setPage((prev) => ({ ...prev, currentPage: page }))
  209. },
  210. onShowSizeChange: (_current, size) => {
  211. setPage((prev) => ({ ...prev, pageSize: size }))
  212. }
  213. }}
  214. search={{
  215. labelWidth: 'auto'
  216. }}
  217. onSubmit={(params) => {
  218. setSearchForm(() => ({ ...params }))
  219. }}
  220. toolBarRender={() => [
  221. <Button
  222. key='button'
  223. icon={<PlusOutlined />}
  224. onClick={() => {
  225. setAddUserModalProps((prev) => ({ ...prev, show: true }))
  226. }}
  227. type='primary'>
  228. 新增
  229. </Button>
  230. ]}
  231. options={{
  232. fullScreen: true,
  233. reload: () => {
  234. getList()
  235. }
  236. }}
  237. columnsState={{
  238. persistenceKey: 'system-auth-user-list-column',
  239. persistenceType: 'localStorage'
  240. }}
  241. />
  242. </Col>
  243. </Row>
  244. <AddModal {...addUserModalProps} />
  245. </Card>
  246. )
  247. }