page.tsx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. "use client";
  2. import {fetchApi, fetchFile} from "@/app/_modules/func";
  3. import {DeleteOutlined, ExclamationCircleFilled, PlusOutlined, ReloadOutlined,} from "@ant-design/icons";
  4. import type {ActionType, ProColumns, ProFormInstance,} from "@ant-design/pro-components";
  5. import {
  6. ModalForm,
  7. PageContainer,
  8. ProForm,
  9. ProFormRadio,
  10. ProFormText,
  11. ProFormTextArea,
  12. ProTable,
  13. } from "@ant-design/pro-components";
  14. import {Button, message, Modal, Space, Tag} from "antd";
  15. import {useRouter} from "next/navigation";
  16. import {
  17. faCheck,
  18. faDownload,
  19. faPenToSquare,
  20. faRotate,
  21. faToggleOff,
  22. faToggleOn,
  23. faXmark,
  24. } from "@fortawesome/free-solid-svg-icons";
  25. import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
  26. import {useRef, useState} from "react";
  27. //查询表格数据API
  28. const queryAPI = "/api/system/config/list";
  29. //新建数据API
  30. const newAPI = "/api/system/config";
  31. //修改数据API
  32. const modifyAPI = "/api/system/config";
  33. //查询详情数据API
  34. const queryDetailAPI = "/api/system/config";
  35. //删除API
  36. const deleteAPI = "/api/system/config";
  37. //导出API
  38. const exportAPI = "/api/system/config/export";
  39. //导出文件前缀名
  40. const exportFilePrefix = "config";
  41. //刷新缓存
  42. const refreshAPI = "/api/system/config/refreshCache";
  43. export default function Config() {
  44. const { push } = useRouter();
  45. //表格列定义
  46. const columns: ProColumns[] = [
  47. {
  48. title: "参数编号",
  49. dataIndex: "configId",
  50. search: false,
  51. },
  52. {
  53. title: "参数名称",
  54. fieldProps: {
  55. placeholder: "请输入参数名称",
  56. },
  57. dataIndex: "configName",
  58. ellipsis: true,
  59. sorter: true,
  60. order: 4,
  61. },
  62. {
  63. title: "参数键名",
  64. fieldProps: {
  65. placeholder: "请输入参数键名",
  66. },
  67. dataIndex: "configKey",
  68. ellipsis: true,
  69. order: 3,
  70. },
  71. {
  72. title: "参数键值",
  73. dataIndex: "configValue",
  74. ellipsis: true,
  75. search: false,
  76. },
  77. {
  78. title: "系统内置",
  79. fieldProps: {
  80. placeholder: "请选择是否系统内置",
  81. },
  82. dataIndex: "configType",
  83. valueType: "select",
  84. render: (_, record) => {
  85. return (
  86. <Space>
  87. <Tag
  88. color={record.configType === "Y" ? "green" : "red"}
  89. icon={
  90. record.configType === "Y" ? (
  91. <FontAwesomeIcon icon={faCheck} />
  92. ) : (
  93. <FontAwesomeIcon icon={faXmark} />
  94. )
  95. }
  96. >
  97. {_}
  98. </Tag>
  99. </Space>
  100. );
  101. },
  102. valueEnum: {
  103. Y: {
  104. text: "是",
  105. status: "Y",
  106. },
  107. N: {
  108. text: "否",
  109. status: "N",
  110. },
  111. },
  112. order: 2,
  113. },
  114. {
  115. title: "备注",
  116. dataIndex: "remark",
  117. ellipsis: true,
  118. search: false,
  119. },
  120. {
  121. title: "创建时间",
  122. dataIndex: "createTime",
  123. valueType: "dateTime",
  124. search: false,
  125. },
  126. {
  127. title: "创建时间",
  128. fieldProps: {
  129. placeholder: ["开始日期", "结束日期"],
  130. },
  131. dataIndex: "createTimeRange",
  132. valueType: "dateRange",
  133. hideInTable: true,
  134. order: 1,
  135. search: {
  136. transform: (value) => {
  137. return {
  138. "params[beginTime]": `${value[0]} 00:00:00`,
  139. "params[endTime]": `${value[1]} 23:59:59`,
  140. };
  141. },
  142. },
  143. },
  144. {
  145. title: "操作",
  146. key: "option",
  147. search: false,
  148. render: (_, record) => [
  149. <Button
  150. key="modifyBtn"
  151. type="link"
  152. icon={<FontAwesomeIcon icon={faPenToSquare} />}
  153. onClick={() => onClickShowRowModifyModal(record)}
  154. >
  155. 修改
  156. </Button>,
  157. <Button
  158. key="deleteBtn"
  159. type="link"
  160. danger
  161. icon={<DeleteOutlined />}
  162. onClick={() => onClickDeleteRow(record)}
  163. >
  164. 删除
  165. </Button>,
  166. ],
  167. },
  168. ];
  169. //0.查询表格数据
  170. const queryTableData = async (params: any, sorter: any, filter: any) => {
  171. const searchParams = {
  172. pageNum: params.current,
  173. ...params,
  174. };
  175. delete searchParams.current;
  176. const queryParams = new URLSearchParams(searchParams);
  177. Object.keys(sorter).forEach((key) => {
  178. queryParams.append("orderByColumn", key);
  179. if (sorter[key] === "ascend") {
  180. queryParams.append("isAsc", "ascending");
  181. } else {
  182. queryParams.append("isAsc", "descending");
  183. }
  184. });
  185. const body = await fetchApi(`${queryAPI}?${queryParams}`, push);
  186. return body;
  187. };
  188. //1.新建
  189. //确定新建数据
  190. const executeAddData = async (values: any) => {
  191. const body = await fetchApi(newAPI, push, {
  192. method: "POST",
  193. headers: {
  194. "Content-Type": "application/json",
  195. },
  196. body: JSON.stringify(values),
  197. });
  198. if (body != undefined) {
  199. if (body.code == 200) {
  200. message.success(body.msg);
  201. if (actionTableRef.current) {
  202. actionTableRef.current.reload();
  203. }
  204. return true;
  205. }
  206. message.error(body.msg);
  207. return false;
  208. }
  209. return false;
  210. };
  211. //2.修改
  212. //是否展示修改对话框
  213. const [isShowModifyDataModal, setIsShowModifyDataModal] = useState(false);
  214. //展示修改对话框
  215. const onClickShowRowModifyModal = (record?: any) => {
  216. queryRowData(record);
  217. setIsShowModifyDataModal(true);
  218. };
  219. //修改数据表单引用
  220. const modifyFormRef = useRef<ProFormInstance>(null);
  221. //操作当前数据的附加数据
  222. const [operatRowData, setOperateRowData] = useState<{
  223. [key: string]: any;
  224. }>({});
  225. //查询并加载待修改数据的详细信息
  226. const queryRowData = async (record?: any) => {
  227. const configId =
  228. record !== undefined ? record.configId : selectedRow.configId;
  229. operatRowData["configId"] = configId;
  230. setOperateRowData(operatRowData);
  231. if (configId !== undefined) {
  232. const body = await fetchApi(`${queryDetailAPI}/${configId}`, push);
  233. if (body !== undefined) {
  234. if (body.code == 200) {
  235. modifyFormRef?.current?.setFieldsValue({
  236. //需要加载到修改表单中的数据
  237. configName: body.data.configName,
  238. configKey: body.data.configKey,
  239. configValue: body.data.configValue,
  240. configType: body.data.configType,
  241. remark: body.data.remark,
  242. });
  243. }
  244. }
  245. }
  246. };
  247. //确认修改数据
  248. const executeModifyData = async (values: any) => {
  249. values["configId"] = operatRowData["configId"];
  250. const body = await fetchApi(modifyAPI, push, {
  251. method: "PUT",
  252. headers: {
  253. "Content-Type": "application/json",
  254. },
  255. body: JSON.stringify(values),
  256. });
  257. if (body !== undefined) {
  258. if (body.code == 200) {
  259. message.success(body.msg);
  260. //刷新列表
  261. if (actionTableRef.current) {
  262. actionTableRef.current.reload();
  263. }
  264. setIsShowModifyDataModal(false);
  265. return true;
  266. }
  267. message.error(body.msg);
  268. return false;
  269. }
  270. };
  271. //3.删除
  272. //点击删除按钮,展示删除确认框
  273. const onClickDeleteRow = (record?: any) => {
  274. const configId =
  275. record != undefined ? record.configId : selectedRowKeys.join(",");
  276. Modal.confirm({
  277. title: "系统提示",
  278. icon: <ExclamationCircleFilled />,
  279. content: `是否确认删除参数编号为“${configId}”的数据项?`,
  280. onOk() {
  281. executeDeleteRow(configId);
  282. },
  283. onCancel() {},
  284. });
  285. };
  286. //确定删除选中的数据
  287. const executeDeleteRow = async (dictId: any) => {
  288. const body = await fetchApi(`${deleteAPI}/${dictId}`, push, {
  289. method: "DELETE",
  290. });
  291. if (body !== undefined) {
  292. if (body.code == 200) {
  293. message.success("删除成功");
  294. //修改按钮变回不可点击
  295. setRowCanModify(false);
  296. //删除按钮变回不可点击
  297. setRowCanDelete(false);
  298. //选中行数据重置为空
  299. setSelectedRowKeys([]);
  300. //刷新列表
  301. if (actionTableRef.current) {
  302. actionTableRef.current.reload();
  303. }
  304. } else {
  305. message.error(body.msg);
  306. }
  307. }
  308. };
  309. //4.导出
  310. //导出表格数据
  311. const exportTable = async () => {
  312. if (searchTableFormRef.current) {
  313. const formData = new FormData();
  314. const data = {
  315. pageNum: page,
  316. pageSize: pageSize,
  317. ...searchTableFormRef.current.getFieldsValue(),
  318. };
  319. Object.keys(data).forEach((key) => {
  320. if (data[key] !== undefined) {
  321. formData.append(key, data[key]);
  322. }
  323. });
  324. await fetchFile(
  325. exportAPI,
  326. push,
  327. {
  328. method: "POST",
  329. body: formData,
  330. },
  331. `${exportFilePrefix}_${new Date().getTime()}.xlsx`
  332. );
  333. }
  334. };
  335. //5.选择行
  336. //选中行操作
  337. const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
  338. const [selectedRow, setSelectedRow] = useState(undefined as any);
  339. //修改按钮是否可用,选中行时才可用
  340. const [rowCanModify, setRowCanModify] = useState(false);
  341. //删除按钮是否可用,选中行时才可用
  342. const [rowCanDelete, setRowCanDelete] = useState(false);
  343. //ProTable rowSelection
  344. const rowSelection = {
  345. onChange: (newSelectedRowKeys: React.Key[], selectedRows: any[]) => {
  346. setSelectedRowKeys(newSelectedRowKeys);
  347. setRowCanDelete(newSelectedRowKeys && newSelectedRowKeys.length > 0);
  348. if (newSelectedRowKeys && newSelectedRowKeys.length == 1) {
  349. setSelectedRow(selectedRows[0]);
  350. setRowCanModify(true);
  351. } else {
  352. setRowCanModify(false);
  353. setSelectedRow(undefined);
  354. }
  355. },
  356. //复选框的额外禁用判断
  357. // getCheckboxProps: (record) => ({
  358. // disabled: record.userId == 1,
  359. // }),
  360. };
  361. //搜索栏显示状态
  362. const [showSearch, setShowSearch] = useState(true);
  363. //action对象引用
  364. const actionTableRef = useRef<ActionType>(null);
  365. //搜索表单对象引用
  366. const searchTableFormRef = useRef<ProFormInstance>(null!);
  367. //当前页数和每页条数
  368. const [page, setPage] = useState(1);
  369. const defaultPageSize = 10;
  370. const [pageSize, setPageSize] = useState(defaultPageSize);
  371. const pageChange = (page: number, pageSize: number) => {
  372. setPage(page);
  373. setPageSize(pageSize);
  374. };
  375. //刷新缓存
  376. const refreshCache = async () => {
  377. const body = await fetchApi(refreshAPI, push, {
  378. method: "DELETE",
  379. });
  380. if (body !== undefined) {
  381. if (body.code == 200) {
  382. message.success("刷新成功");
  383. if (actionTableRef.current) {
  384. actionTableRef.current.reload();
  385. }
  386. } else {
  387. message.error(body.msg);
  388. }
  389. }
  390. };
  391. return (
  392. <PageContainer title={false}>
  393. <ProTable
  394. formRef={searchTableFormRef}
  395. rowKey="configId"
  396. rowSelection={{
  397. selectedRowKeys,
  398. ...rowSelection,
  399. }}
  400. columns={columns}
  401. request={async (params: any, sorter: any, filter: any) => {
  402. // 表单搜索项会从 params 传入,传递给后端接口。
  403. const data = await queryTableData(params, sorter, filter);
  404. if (data !== undefined) {
  405. return Promise.resolve({
  406. data: data.rows,
  407. success: true,
  408. total: data.total,
  409. });
  410. }
  411. return Promise.resolve({
  412. data: [],
  413. success: true,
  414. });
  415. }}
  416. pagination={{
  417. defaultPageSize: defaultPageSize,
  418. showQuickJumper: true,
  419. showSizeChanger: true,
  420. onChange: pageChange,
  421. }}
  422. search={
  423. showSearch
  424. ? {
  425. defaultCollapsed: false,
  426. searchText: "搜索",
  427. }
  428. : false
  429. }
  430. dateFormatter="string"
  431. actionRef={actionTableRef}
  432. toolbar={{
  433. actions: [
  434. <ModalForm
  435. key="addmodal"
  436. title="添加参数"
  437. trigger={
  438. <Button icon={<PlusOutlined />} type="primary">
  439. 新建
  440. </Button>
  441. }
  442. autoFocusFirstInput
  443. modalProps={{
  444. destroyOnHidden: true,
  445. }}
  446. submitTimeout={2000}
  447. onFinish={executeAddData}
  448. >
  449. <ProForm.Group>
  450. <ProFormText
  451. width="md"
  452. name="configName"
  453. label="参数名称"
  454. placeholder="请输入参数名称"
  455. rules={[{ required: true, message: "请输入参数名称" }]}
  456. />
  457. </ProForm.Group>
  458. <ProForm.Group>
  459. <ProFormText
  460. width="md"
  461. name="configKey"
  462. label="参数键名"
  463. placeholder="请输入参数键名"
  464. rules={[{ required: true, message: "请输入参数键名" }]}
  465. />
  466. <ProFormText
  467. width="md"
  468. name="configValue"
  469. label="参数键值"
  470. placeholder="请输入参数键值"
  471. rules={[{ required: true, message: "请输入参数键值" }]}
  472. />
  473. </ProForm.Group>
  474. <ProForm.Group>
  475. <ProFormRadio.Group
  476. name="configType"
  477. width="sm"
  478. label="系统内置"
  479. initialValue="Y"
  480. options={[
  481. {
  482. label: "是",
  483. value: "Y",
  484. },
  485. {
  486. label: "否",
  487. value: "N",
  488. },
  489. ]}
  490. />
  491. </ProForm.Group>
  492. <ProFormTextArea
  493. name="remark"
  494. width={688}
  495. label="备注"
  496. placeholder="请输入内容"
  497. />
  498. </ModalForm>,
  499. <ModalForm
  500. key="modifymodal"
  501. title="修改参数"
  502. formRef={modifyFormRef}
  503. trigger={
  504. <Button
  505. icon={<FontAwesomeIcon icon={faPenToSquare} />}
  506. disabled={!rowCanModify}
  507. onClick={() => onClickShowRowModifyModal()}
  508. >
  509. 修改
  510. </Button>
  511. }
  512. open={isShowModifyDataModal}
  513. autoFocusFirstInput
  514. modalProps={{
  515. destroyOnHidden: true,
  516. onCancel: () => {
  517. setIsShowModifyDataModal(false);
  518. },
  519. }}
  520. submitTimeout={2000}
  521. onFinish={executeModifyData}
  522. >
  523. <ProForm.Group>
  524. <ProFormText
  525. width="md"
  526. name="configName"
  527. label="参数名称"
  528. placeholder="请输入参数名称"
  529. rules={[{ required: true, message: "请输入参数名称" }]}
  530. />
  531. </ProForm.Group>
  532. <ProForm.Group>
  533. <ProFormText
  534. width="md"
  535. name="configKey"
  536. label="参数键名"
  537. placeholder="请输入参数键名"
  538. rules={[{ required: true, message: "请输入参数键名" }]}
  539. />
  540. <ProFormText
  541. width="md"
  542. name="configValue"
  543. label="参数键值"
  544. placeholder="请输入参数键值"
  545. rules={[{ required: true, message: "请输入参数键值" }]}
  546. />
  547. </ProForm.Group>
  548. <ProForm.Group>
  549. <ProFormRadio.Group
  550. name="configType"
  551. width="sm"
  552. label="系统内置"
  553. initialValue="Y"
  554. options={[
  555. {
  556. label: "是",
  557. value: "Y",
  558. },
  559. {
  560. label: "否",
  561. value: "N",
  562. },
  563. ]}
  564. />
  565. </ProForm.Group>
  566. <ProFormTextArea
  567. name="remark"
  568. width={688}
  569. label="备注"
  570. placeholder="请输入内容"
  571. />
  572. </ModalForm>,
  573. <Button
  574. key="danger"
  575. danger
  576. icon={<DeleteOutlined />}
  577. disabled={!rowCanDelete}
  578. onClick={() => onClickDeleteRow()}
  579. >
  580. 删除
  581. </Button>,
  582. <Button
  583. key="export"
  584. type="primary"
  585. icon={<FontAwesomeIcon icon={faDownload} />}
  586. onClick={exportTable}
  587. >
  588. 导出
  589. </Button>,
  590. <Button
  591. key="refresh"
  592. type="primary"
  593. icon={<FontAwesomeIcon icon={faRotate} />}
  594. onClick={refreshCache}
  595. >
  596. 刷新缓存
  597. </Button>,
  598. ],
  599. settings: [
  600. {
  601. key: "switch",
  602. icon: showSearch ? (
  603. <FontAwesomeIcon icon={faToggleOn} />
  604. ) : (
  605. <FontAwesomeIcon icon={faToggleOff} />
  606. ),
  607. tooltip: showSearch ? "隐藏搜索栏" : "显示搜索栏",
  608. onClick: (key: string | undefined) => {
  609. setShowSearch(!showSearch);
  610. },
  611. },
  612. {
  613. key: "refresh",
  614. tooltip: "刷新",
  615. icon: <ReloadOutlined />,
  616. onClick: (key: string | undefined) => {
  617. if (actionTableRef.current) {
  618. actionTableRef.current.reload();
  619. }
  620. },
  621. },
  622. ],
  623. }}
  624. />
  625. </PageContainer>
  626. );
  627. }