page.tsx 18 KB

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