index.tsx 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. import {
  2. addUser,
  3. batchDeleteUsers,
  4. deleteUser,
  5. getUsers,
  6. updateUser,
  7. updateUserPoints,
  8. } from '@/services/api';
  9. import { PlusOutlined } from '@ant-design/icons';
  10. import type { ActionType, ProColumns } from '@ant-design/pro-components';
  11. import { ModalForm, ProFormDigit, ProFormSelect, ProFormText } from '@ant-design/pro-form';
  12. import { FooterToolbar, PageContainer, ProTable } from '@ant-design/pro-components';
  13. import { Button, FormInstance, message, Popconfirm } from 'antd';
  14. import React, { useRef, useState } from 'react';
  15. import UpdateUser from './components/UpdateUser';
  16. import UpdateUserPoints from './components/UpdateUserPoints';
  17. const UserList: React.FC = () => {
  18. const [createModalOpen, handleModalOpen] = useState<boolean>(false);
  19. const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
  20. const actionRef = useRef<ActionType>();
  21. const [currentRow, setCurrentRow] = useState<API.UserItem>();
  22. const [selectedRows, setSelectedRows] = useState<API.UserItem[]>([]);
  23. const [pageSize, setPageSize] = useState<number>(10);
  24. const formRef = useRef<FormInstance>(null);
  25. const [updatePointsModalOpen, setUpdatePointsModalOpen] = useState(false);
  26. const handleDelete = async (record: API.UserItem) => {
  27. const res = await deleteUser(record._id);
  28. if (res.success) {
  29. message.success('用户已成功删除');
  30. actionRef.current?.reload();
  31. }
  32. };
  33. const handleBatchDelete = async (selectedRowKeys: string[]) => {
  34. if (selectedRowKeys.length === 0) return;
  35. const res = await batchDeleteUsers(selectedRowKeys);
  36. if (res.success) {
  37. message.success(`${res.message}`);
  38. actionRef.current?.reload();
  39. }
  40. };
  41. const columns: ProColumns<API.UserItem>[] = [
  42. {
  43. title: '用户名',
  44. dataIndex: 'username',
  45. valueType: 'text',
  46. },
  47. {
  48. title: '角色',
  49. dataIndex: 'role',
  50. valueType: 'select',
  51. valueEnum: {
  52. user: { text: '普通用户' },
  53. admin: { text: '管理员' },
  54. },
  55. },
  56. {
  57. title: '积分',
  58. dataIndex: 'points',
  59. valueType: 'digit',
  60. },
  61. {
  62. title: '操作',
  63. dataIndex: 'option',
  64. valueType: 'option',
  65. render: (_, record) => [
  66. <a
  67. key="edit"
  68. onClick={() => {
  69. handleUpdateModalOpen(true);
  70. setCurrentRow(record);
  71. }}
  72. >
  73. 编辑用户
  74. </a>,
  75. <a
  76. key="edit"
  77. onClick={() => {
  78. setUpdatePointsModalOpen(true);
  79. setCurrentRow(record);
  80. }}
  81. >
  82. 修改积分
  83. </a>,
  84. <Popconfirm
  85. key="delete"
  86. title="确认删除"
  87. description={`您确定要删除用户 ${record.username} 吗?`}
  88. onConfirm={() => handleDelete(record)}
  89. okText="确定"
  90. cancelText="取消"
  91. >
  92. <a>删除</a>
  93. </Popconfirm>,
  94. ],
  95. },
  96. ];
  97. return (
  98. <PageContainer>
  99. <ProTable<API.UserItem, API.PageParams>
  100. actionRef={actionRef}
  101. rowKey="_id"
  102. search={{
  103. labelWidth: 120,
  104. }}
  105. toolBarRender={() => [
  106. <Button
  107. type="primary"
  108. key="primary"
  109. onClick={() => {
  110. formRef.current?.resetFields();
  111. handleModalOpen(true);
  112. }}
  113. >
  114. <PlusOutlined /> 新建用户
  115. </Button>,
  116. ]}
  117. request={async (params) => {
  118. const response = await getUsers(params);
  119. return {
  120. data: response.data,
  121. success: response.success,
  122. total: response.total,
  123. };
  124. }}
  125. columns={columns}
  126. pagination={{
  127. showSizeChanger: true,
  128. pageSize: pageSize,
  129. onChange: (page, pageSize) => {
  130. setPageSize(pageSize);
  131. if (actionRef.current) {
  132. actionRef.current.reload();
  133. }
  134. },
  135. }}
  136. rowSelection={{
  137. onChange: (_, selectedRows) => {
  138. setSelectedRows(selectedRows);
  139. },
  140. }}
  141. />
  142. {selectedRows?.length > 0 && (
  143. <FooterToolbar
  144. extra={
  145. <div>
  146. 已选择 <a style={{ fontWeight: 600 }}>{selectedRows.length}</a> 项 &nbsp;&nbsp;
  147. </div>
  148. }
  149. >
  150. <Button
  151. onClick={async () => {
  152. const selectedRowKeys = selectedRows.map((row) => row._id);
  153. await handleBatchDelete(selectedRowKeys);
  154. setSelectedRows([]);
  155. actionRef.current?.reloadAndRest?.();
  156. }}
  157. >
  158. 批量删除
  159. </Button>
  160. </FooterToolbar>
  161. )}
  162. <ModalForm
  163. title="新建用户"
  164. width="400px"
  165. open={createModalOpen}
  166. onOpenChange={handleModalOpen}
  167. formRef={formRef}
  168. onFinish={async (value) => {
  169. const res = await addUser(value as API.UserItem);
  170. if (res.success) {
  171. message.success('创建成功');
  172. handleModalOpen(false);
  173. if (actionRef.current) {
  174. actionRef.current.reload();
  175. }
  176. formRef.current?.resetFields();
  177. }
  178. }}
  179. >
  180. <ProFormText
  181. rules={[
  182. {
  183. required: true,
  184. message: '用户名是必填项',
  185. },
  186. ]}
  187. width="md"
  188. name="username"
  189. label="用户名"
  190. />
  191. <ProFormText.Password
  192. rules={[
  193. {
  194. required: true,
  195. message: '密码是必填项',
  196. },
  197. ]}
  198. width="md"
  199. name="password"
  200. label="密码"
  201. />
  202. <ProFormSelect
  203. rules={[
  204. {
  205. required: true,
  206. message: '角色是必填项',
  207. },
  208. ]}
  209. width="md"
  210. name="role"
  211. label="角色"
  212. valueEnum={{
  213. user: '普通用户',
  214. admin: '管理员',
  215. }}
  216. />
  217. <ProFormDigit width="md" name="points" label="积分" initialValue={0} />
  218. </ModalForm>
  219. <UpdateUser
  220. onSubmit={async (value) => {
  221. const res = await updateUser(value._id, value as API.UserItem);
  222. if (res.success) {
  223. message.success('修改成功');
  224. handleUpdateModalOpen(false);
  225. setCurrentRow(undefined);
  226. if (actionRef.current) {
  227. actionRef.current.reload();
  228. }
  229. }
  230. }}
  231. onCancel={() => {
  232. handleUpdateModalOpen(false);
  233. }}
  234. updateUserModalOpen={updateModalOpen}
  235. values={currentRow || {}}
  236. />
  237. {/* 修改积分 */}
  238. <UpdateUserPoints
  239. onSubmit={async (value: API.UpdateUserPointsParams) => {
  240. const res = await updateUserPoints(value.userId, value.points, value.reason);
  241. if (res.success) {
  242. message.success('积分更新成功');
  243. setUpdatePointsModalOpen(false);
  244. setCurrentRow(undefined);
  245. if (actionRef.current) {
  246. actionRef.current.reload();
  247. }
  248. }
  249. }}
  250. onCancel={() => {
  251. setUpdatePointsModalOpen(false);
  252. }}
  253. updatePointsModalOpen={updatePointsModalOpen}
  254. currentUser={currentRow || {}}
  255. />
  256. </PageContainer>
  257. );
  258. };
  259. export default UserList;