page.tsx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. "use client";
  2. import {fetchApi} 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. ProFormDigit,
  10. ProFormRadio,
  11. ProFormSelect,
  12. ProFormText,
  13. ProFormTreeSelect,
  14. ProTable,
  15. } from "@ant-design/pro-components";
  16. import {Button, message, Modal, Space, Tag} from "antd";
  17. import {useRouter} from "next/navigation";
  18. import {
  19. faArrowsUpDown,
  20. faCheck,
  21. faPenToSquare,
  22. faToggleOff,
  23. faToggleOn,
  24. faXmark,
  25. } from "@fortawesome/free-solid-svg-icons";
  26. import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
  27. import {IconMap} from "@/app/_modules/definies";
  28. import {useRef, useState} from "react";
  29. //查询表格数据API
  30. const queryAPI = "/api/system/menu/list";
  31. //新建数据API
  32. const newAPI = "/api/system/menu";
  33. //修改数据API
  34. const modifyAPI = "/api/system/menu";
  35. //查询详情数据API
  36. const queryDetailAPI = "/api/system/menu";
  37. //删除API
  38. const deleteAPI = "/api/system/menu";
  39. export default function Menu() {
  40. const { push } = useRouter();
  41. // 添加用于控制删除确认模态框的状态
  42. const [deleteModalVisible, setDeleteModalVisible] = useState(false);
  43. const [deleteRecord, setDeleteRecord] = useState<any>(null);
  44. // 添加用于控制清空确认模态框的状态(如果需要的话)
  45. const [clearModalVisible, setClearModalVisible] = useState(false);
  46. //表格列定义
  47. const columns: ProColumns[] = [
  48. {
  49. title: "菜单名称",
  50. fieldProps: {
  51. placeholder: "请输入菜单名称",
  52. },
  53. dataIndex: "menuName",
  54. order: 2,
  55. },
  56. {
  57. title: "图标",
  58. dataIndex: "icon",
  59. search: false,
  60. },
  61. {
  62. title: "排序",
  63. dataIndex: "orderNum",
  64. search: false,
  65. },
  66. {
  67. title: "权限标识",
  68. dataIndex: "perms",
  69. ellipsis: true,
  70. search: false,
  71. },
  72. {
  73. title: "状态",
  74. fieldProps: {
  75. placeholder: "请选择菜单状态",
  76. },
  77. dataIndex: "status",
  78. valueType: "select",
  79. render: (_, record) => {
  80. return (
  81. <Space>
  82. <Tag
  83. color={record.status === "0" ? "green" : "red"}
  84. icon={
  85. record.status == 0 ? (
  86. <FontAwesomeIcon icon={faCheck} />
  87. ) : (
  88. <FontAwesomeIcon icon={faXmark} />
  89. )
  90. }
  91. >
  92. {_}
  93. </Tag>
  94. </Space>
  95. );
  96. },
  97. valueEnum: {
  98. 0: {
  99. text: "正常",
  100. status: "0",
  101. },
  102. 1: {
  103. text: "停用",
  104. status: "1",
  105. },
  106. },
  107. order: 1,
  108. },
  109. {
  110. title: "创建时间",
  111. dataIndex: "createTime",
  112. valueType: "dateTime",
  113. search: false,
  114. },
  115. {
  116. title: "操作",
  117. key: "option",
  118. search: false,
  119. render: (_, record) => [
  120. <Button
  121. key="modifyBtn"
  122. type="link"
  123. icon={<FontAwesomeIcon icon={faPenToSquare} />}
  124. onClick={() => onClickShowRowModifyModal(record)}
  125. >
  126. 修改
  127. </Button>,
  128. <Button
  129. key="newBtn"
  130. type="link"
  131. icon={<PlusOutlined />}
  132. onClick={() => onClickAdd(record)}
  133. >
  134. 新建
  135. </Button>,
  136. <Button
  137. key="deleteBtn"
  138. type="link"
  139. danger
  140. icon={<DeleteOutlined />}
  141. onClick={() => onClickDeleteRow(record)}
  142. >
  143. 删除
  144. </Button>,
  145. ],
  146. },
  147. ];
  148. //0.查询表格数据
  149. //原始的可展开的所有行的 id
  150. const [defaultExpandKeys, setDefaultExpandKeys] = useState<any[]>([]);
  151. //控制行展开的数据
  152. const [expandKeys, setExpandKeys] = useState<any[]>([]);
  153. const queryTableData = async (params: any, sorter: any, filter: any) => {
  154. const searchParams = {
  155. ...params,
  156. };
  157. const queryParams = new URLSearchParams(searchParams);
  158. Object.keys(sorter).forEach((key) => {
  159. queryParams.append("orderByColumn", key);
  160. if (sorter[key] === "ascend") {
  161. queryParams.append("isAsc", "ascending");
  162. } else {
  163. queryParams.append("isAsc", "descending");
  164. }
  165. });
  166. const body = await fetchApi(`${queryAPI}?${queryParams}`, push);
  167. const firstLevel = getFirstLevel(body.data);
  168. firstLevel.forEach((first) => {
  169. getChildren(body.data, first);
  170. });
  171. const newExpandedKeys: any[] = [];
  172. const render = (treeDatas: any[]) => {
  173. // 获取到所有可展开的父节点
  174. treeDatas.map((item) => {
  175. if (item.children) {
  176. newExpandedKeys.push(item.menuId);
  177. render(item.children);
  178. }
  179. });
  180. return newExpandedKeys;
  181. };
  182. const keys = render(firstLevel);
  183. setDefaultExpandKeys(keys);
  184. setExpandKeys([]);
  185. return firstLevel;
  186. };
  187. const getFirstLevel = (data: any[]) => {
  188. const firstLevel: any[] = [];
  189. for (let index = 0; index < data.length; index++) {
  190. const item = data[index];
  191. if (item.parentId === 0) {
  192. firstLevel.push(item);
  193. }
  194. }
  195. return firstLevel;
  196. };
  197. const getChildren = (data: any[], parentNode: any) => {
  198. for (let index = 0; index < data.length; index++) {
  199. const item = data[index];
  200. if (item.parentId === parentNode.menuId) {
  201. parentNode.children.push(item);
  202. getChildren(data, item);
  203. }
  204. }
  205. if (parentNode.children.length == 0) {
  206. delete parentNode.children;
  207. }
  208. };
  209. //1.新建
  210. const [showAddModal, setShowAddModal] = useState(false);
  211. //新建表单是否带有父节点id
  212. const [rowParentId, setRowParentId] = useState(0);
  213. //点击新建,如果从行点击新建,给定父节点
  214. const onClickAdd = (record?: any) => {
  215. setRowParentId(record.menuId);
  216. setShowAddModal(true);
  217. };
  218. const cancelAddModal = () => {
  219. setShowAddModal(false);
  220. setRowParentId(0);
  221. };
  222. //确定新建数据
  223. const executeAddData = async (values: any) => {
  224. const body = await fetchApi(newAPI, push, {
  225. method: "POST",
  226. headers: {
  227. "Content-Type": "application/json",
  228. },
  229. body: JSON.stringify(values),
  230. });
  231. if (body != undefined) {
  232. if (body.code == 200) {
  233. message.success(body.msg);
  234. if (actionTableRef.current) {
  235. actionTableRef.current.reload();
  236. }
  237. setShowAddModal(false);
  238. return true;
  239. }
  240. message.error(body.msg);
  241. return false;
  242. }
  243. return false;
  244. };
  245. //2.修改
  246. //是否展示修改对话框
  247. const [isShowModifyDataModal, setIsShowModifyDataModal] = useState(false);
  248. //展示修改对话框
  249. const onClickShowRowModifyModal = (record: any) => {
  250. queryRowData(record);
  251. setIsShowModifyDataModal(true);
  252. };
  253. //修改数据表单引用
  254. const modifyFormRef = useRef<ProFormInstance>(null);
  255. //操作当前数据的附加数据
  256. const [operatRowData, setOperateRowData] = useState<{
  257. [key: string]: any;
  258. }>({});
  259. //查询并加载待修改数据的详细信息
  260. const queryRowData = async (record: any) => {
  261. const menuId = record.menuId;
  262. operatRowData["menuId"] = menuId;
  263. setOperateRowData(operatRowData);
  264. if (menuId !== undefined) {
  265. const body = await fetchApi(`${queryDetailAPI}/${menuId}`, push);
  266. if (body !== undefined) {
  267. if (body.code == 200) {
  268. modifyFormRef?.current?.setFieldsValue({
  269. //需要加载到修改表单中的数据
  270. parentId: body.data.parentId,
  271. menuName: body.data.menuName,
  272. orderNum: body.data.orderNum,
  273. path: body.data.path,
  274. isFrame: body.data.isFrame,
  275. menuType: body.data.menuType,
  276. perms: body.data.perms,
  277. icon: body.data.icon,
  278. visible: body.data.visible,
  279. status: body.data.status,
  280. });
  281. setIsCatalog(body.data.menuType === "M");
  282. setIsMenu(body.data.menuType === "C");
  283. setIsButton(body.data.menuType === "F");
  284. }
  285. }
  286. }
  287. };
  288. //确认修改数据
  289. const executeModifyData = async (values: any) => {
  290. values["menuId"] = operatRowData["menuId"];
  291. const body = await fetchApi(modifyAPI, push, {
  292. method: "PUT",
  293. headers: {
  294. "Content-Type": "application/json",
  295. },
  296. body: JSON.stringify(values),
  297. });
  298. if (body !== undefined) {
  299. if (body.code == 200) {
  300. message.success(body.msg);
  301. //刷新列表
  302. if (actionTableRef.current) {
  303. actionTableRef.current.reload();
  304. }
  305. setIsShowModifyDataModal(false);
  306. return true;
  307. }
  308. message.error(body.msg);
  309. return false;
  310. }
  311. };
  312. //3.展开/折叠
  313. //点击展开/折叠按钮
  314. const onClickExpandRow = () => {
  315. if (expandKeys.length > 0) {
  316. setExpandKeys([]);
  317. } else {
  318. setExpandKeys(defaultExpandKeys);
  319. }
  320. };
  321. //处理行的展开/折叠逻辑
  322. const handleExpand = (expanded: boolean, record: any) => {
  323. console.log("has keys:", expandKeys);
  324. let keys = [...expandKeys];
  325. if (expanded) {
  326. keys.push(record.menuId);
  327. } else {
  328. keys = keys.filter((key: number) => key !== record.menuId);
  329. }
  330. console.log("now keys:", keys);
  331. setExpandKeys(keys);
  332. };
  333. //4.导出
  334. //5.选择行
  335. //搜索栏显示状态
  336. const [showSearch, setShowSearch] = useState(true);
  337. //action对象引用
  338. const actionTableRef = useRef<ActionType>(null);
  339. //搜索表单对象引用
  340. const searchTableFormRef = useRef<ProFormInstance>(null!);
  341. const getMenuList = async () => {
  342. const body = await fetchApi(queryAPI, push);
  343. if (body !== undefined) {
  344. const firstLevel = getFirstLevel(body.data);
  345. firstLevel.forEach((first) => {
  346. getChildren(body.data, first);
  347. });
  348. const root: any = {
  349. menuId: 0,
  350. menuName: "根目录",
  351. children: [],
  352. };
  353. firstLevel.forEach((first: any) => {
  354. root.children.push(first as never);
  355. });
  356. return [root];
  357. }
  358. return [];
  359. };
  360. //点击删除按钮
  361. const onClickDeleteRow = (record: any) => {
  362. setDeleteRecord(record);
  363. setDeleteModalVisible(true);
  364. };
  365. //确定删除选中的菜单
  366. const executeDeleteRow = async () => {
  367. if (!deleteRecord) return;
  368. const menuId = deleteRecord.menuId;
  369. const body = await fetchApi(`${deleteAPI}/${menuId}`, push, {
  370. method: "DELETE",
  371. });
  372. if (body !== undefined) {
  373. if (body.code == 200) {
  374. message.success("删除成功");
  375. //刷新列表
  376. if (actionTableRef.current) {
  377. actionTableRef.current.reload();
  378. }
  379. } else {
  380. message.error(body.msg);
  381. }
  382. }
  383. setDeleteModalVisible(false);
  384. setDeleteRecord(null);
  385. };
  386. const [isCatalog, setIsCatalog] = useState(true);
  387. const [isMenu, setIsMenu] = useState(false);
  388. const [isButton, setIsButton] = useState(false);
  389. const onChangeType = (e: any) => {
  390. const type = e.target.value;
  391. setIsCatalog(type === "M");
  392. setIsMenu(type === "C");
  393. setIsButton(type === "F");
  394. };
  395. const IconData = () => {
  396. const iconData = { ...IconMap };
  397. Object.keys(iconData).forEach((key) => {
  398. iconData[key] = (
  399. <>
  400. <span style={{ marginRight: 8 }}>{iconData[key]}</span>
  401. {key}
  402. </>
  403. );
  404. });
  405. return iconData;
  406. };
  407. return (
  408. <PageContainer title={false}>
  409. <ProTable
  410. formRef={searchTableFormRef}
  411. rowKey="menuId"
  412. columns={columns}
  413. expandable={{
  414. expandedRowKeys: expandKeys,
  415. onExpand: handleExpand,
  416. }}
  417. request={async (params: any, sorter: any, filter: any) => {
  418. // 表单搜索项会从 params 传入,传递给后端接口。
  419. const data = await queryTableData(params, sorter, filter);
  420. if (data !== undefined) {
  421. return Promise.resolve({
  422. data: data,
  423. success: true,
  424. total: data.length,
  425. });
  426. }
  427. return Promise.resolve({
  428. data: [],
  429. success: true,
  430. });
  431. }}
  432. pagination={false}
  433. search={
  434. showSearch
  435. ? {
  436. defaultCollapsed: false,
  437. searchText: "搜索",
  438. }
  439. : false
  440. }
  441. dateFormatter="string"
  442. actionRef={actionTableRef}
  443. toolbar={{
  444. actions: [
  445. <ModalForm
  446. key="addmodal"
  447. title="添加菜单"
  448. open={showAddModal}
  449. trigger={
  450. <Button icon={<PlusOutlined />} type="primary">
  451. 新建
  452. </Button>
  453. }
  454. autoFocusFirstInput
  455. modalProps={{
  456. destroyOnHidden: true,
  457. onCancel: () => {
  458. cancelAddModal();
  459. },
  460. }}
  461. submitTimeout={2000}
  462. onFinish={executeAddData}
  463. >
  464. <ProForm.Group>
  465. <ProFormTreeSelect
  466. width="md"
  467. name="parentId"
  468. initialValue={rowParentId}
  469. label="上级菜单"
  470. placeholder="请选择上级菜单"
  471. rules={[{ required: true, message: "请选择上级菜单" }]}
  472. request={getMenuList}
  473. fieldProps={{
  474. filterTreeNode: true,
  475. showSearch: true,
  476. treeNodeFilterProp: "label",
  477. fieldNames: {
  478. label: "menuName",
  479. value: "menuId",
  480. },
  481. }}
  482. />
  483. </ProForm.Group>
  484. <ProForm.Group>
  485. <ProFormRadio.Group
  486. name="menuType"
  487. width="md"
  488. label="类型"
  489. initialValue="M"
  490. fieldProps={{
  491. onChange: (e: any) => onChangeType(e),
  492. }}
  493. options={[
  494. {
  495. label: "目录",
  496. value: "M",
  497. },
  498. {
  499. label: "菜单",
  500. value: "C",
  501. },
  502. {
  503. label: "按钮",
  504. value: "F",
  505. },
  506. ]}
  507. />
  508. </ProForm.Group>
  509. {(isCatalog || isMenu) && (
  510. <ProForm.Group>
  511. <ProFormSelect
  512. width="md"
  513. name="icon"
  514. label="菜单图标"
  515. fieldProps={{
  516. showSearch,
  517. }}
  518. valueEnum={IconData}
  519. placeholder="请选择菜单图标"
  520. rules={[{ required: true, message: "请选择菜单图标" }]}
  521. />
  522. </ProForm.Group>
  523. )}
  524. <ProForm.Group>
  525. <ProFormText
  526. width="md"
  527. name="menuName"
  528. label="菜单名称"
  529. placeholder="请输入菜单名称"
  530. rules={[{ required: true, message: "请输入菜单名称" }]}
  531. />
  532. <ProFormDigit
  533. fieldProps={{ precision: 0 }}
  534. width="md"
  535. name="orderNum"
  536. initialValue="1"
  537. label="排序"
  538. placeholder="请输入排序"
  539. rules={[{ required: true, message: "请输入排序" }]}
  540. />
  541. </ProForm.Group>
  542. {(isCatalog || isMenu) && (
  543. <ProForm.Group>
  544. <ProFormText
  545. width="md"
  546. name="path"
  547. label="路由地址"
  548. placeholder="请输入路由地址"
  549. rules={[{ required: true, message: "请输入路由地址" }]}
  550. />
  551. <ProFormRadio.Group
  552. name="isFrame"
  553. width="md"
  554. label="是否外链"
  555. initialValue="1"
  556. options={[
  557. {
  558. label: "是",
  559. value: "0",
  560. },
  561. {
  562. label: "否",
  563. value: "1",
  564. },
  565. ]}
  566. />
  567. </ProForm.Group>
  568. )}
  569. {isMenu && (
  570. <ProForm.Group>
  571. <ProFormText
  572. width="md"
  573. name="perms"
  574. label="权限字符"
  575. placeholder="请输入权限字符"
  576. />
  577. </ProForm.Group>
  578. )}
  579. <ProForm.Group>
  580. <ProFormRadio.Group
  581. name="visible"
  582. width="md"
  583. label="显示状态"
  584. initialValue="0"
  585. options={[
  586. {
  587. label: "显示",
  588. value: "0",
  589. },
  590. {
  591. label: "隐藏",
  592. value: "1",
  593. },
  594. ]}
  595. />
  596. <ProFormRadio.Group
  597. name="status"
  598. width="md"
  599. label="菜单状态"
  600. initialValue="0"
  601. options={[
  602. {
  603. label: "正常",
  604. value: "0",
  605. },
  606. {
  607. label: "停用",
  608. value: "1",
  609. },
  610. ]}
  611. />
  612. </ProForm.Group>
  613. </ModalForm>,
  614. <Button
  615. key="expand"
  616. icon={<FontAwesomeIcon icon={faArrowsUpDown} />}
  617. onClick={() => onClickExpandRow()}
  618. >
  619. 折叠/展开
  620. </Button>,
  621. ],
  622. settings: [
  623. {
  624. key: "switch",
  625. icon: showSearch ? (
  626. <FontAwesomeIcon icon={faToggleOn} />
  627. ) : (
  628. <FontAwesomeIcon icon={faToggleOff} />
  629. ),
  630. tooltip: showSearch ? "隐藏搜索栏" : "显示搜索栏",
  631. onClick: (key: string | undefined) => {
  632. setShowSearch(!showSearch);
  633. },
  634. },
  635. {
  636. key: "refresh",
  637. tooltip: "刷新",
  638. icon: <ReloadOutlined />,
  639. onClick: (key: string | undefined) => {
  640. if (actionTableRef.current) {
  641. actionTableRef.current.reload();
  642. }
  643. },
  644. },
  645. ],
  646. }}
  647. />
  648. <ModalForm
  649. key="modifymodal"
  650. title="修改菜单"
  651. formRef={modifyFormRef}
  652. open={isShowModifyDataModal}
  653. autoFocusFirstInput
  654. modalProps={{
  655. destroyOnHidden: true,
  656. onCancel: () => {
  657. setIsShowModifyDataModal(false);
  658. },
  659. }}
  660. submitTimeout={2000}
  661. onFinish={executeModifyData}
  662. >
  663. <ProForm.Group>
  664. <ProFormTreeSelect
  665. width="md"
  666. name="parentId"
  667. initialValue={rowParentId}
  668. label="上级菜单"
  669. placeholder="请选择上级菜单"
  670. rules={[{ required: true, message: "请选择上级菜单" }]}
  671. request={getMenuList}
  672. fieldProps={{
  673. filterTreeNode: true,
  674. showSearch: true,
  675. treeNodeFilterProp: "label",
  676. fieldNames: {
  677. label: "menuName",
  678. value: "menuId",
  679. },
  680. }}
  681. />
  682. </ProForm.Group>
  683. <ProForm.Group>
  684. <ProFormRadio.Group
  685. name="menuType"
  686. width="md"
  687. label="类型"
  688. fieldProps={{
  689. onChange: (e: any) => onChangeType(e),
  690. }}
  691. options={[
  692. {
  693. label: "目录",
  694. value: "M",
  695. },
  696. {
  697. label: "菜单",
  698. value: "C",
  699. },
  700. {
  701. label: "按钮",
  702. value: "F",
  703. },
  704. ]}
  705. />
  706. </ProForm.Group>
  707. {(isCatalog || isMenu) && (
  708. <ProForm.Group>
  709. <ProFormSelect
  710. width="md"
  711. name="icon"
  712. label="菜单图标"
  713. fieldProps={{
  714. showSearch,
  715. }}
  716. valueEnum={IconData}
  717. placeholder="请选择菜单图标"
  718. rules={[{ required: true, message: "请选择菜单图标" }]}
  719. />
  720. </ProForm.Group>
  721. )}
  722. <ProForm.Group>
  723. <ProFormText
  724. width="md"
  725. name="menuName"
  726. label="菜单名称"
  727. placeholder="请输入菜单名称"
  728. rules={[{ required: true, message: "请输入菜单名称" }]}
  729. />
  730. <ProFormDigit
  731. fieldProps={{ precision: 0 }}
  732. width="md"
  733. name="orderNum"
  734. initialValue="1"
  735. label="排序"
  736. placeholder="请输入排序"
  737. rules={[{ required: true, message: "请输入排序" }]}
  738. />
  739. </ProForm.Group>
  740. {(isCatalog || isMenu) && (
  741. <ProForm.Group>
  742. <ProFormText
  743. width="md"
  744. name="path"
  745. label="路由地址"
  746. placeholder="请输入路由地址"
  747. rules={[{ required: true, message: "请输入路由地址" }]}
  748. />
  749. <ProFormRadio.Group
  750. name="isFrame"
  751. width="md"
  752. label="是否外链"
  753. initialValue="1"
  754. options={[
  755. {
  756. label: "是",
  757. value: "0",
  758. },
  759. {
  760. label: "否",
  761. value: "1",
  762. },
  763. ]}
  764. />
  765. </ProForm.Group>
  766. )}
  767. {isMenu && (
  768. <ProForm.Group>
  769. <ProFormText
  770. width="md"
  771. name="perms"
  772. label="权限字符"
  773. placeholder="请输入权限字符"
  774. />
  775. </ProForm.Group>
  776. )}
  777. <ProForm.Group>
  778. <ProFormRadio.Group
  779. name="visible"
  780. width="md"
  781. label="显示状态"
  782. initialValue="0"
  783. options={[
  784. {
  785. label: "显示",
  786. value: "0",
  787. },
  788. {
  789. label: "隐藏",
  790. value: "1",
  791. },
  792. ]}
  793. />
  794. <ProFormRadio.Group
  795. name="status"
  796. width="md"
  797. label="菜单状态"
  798. initialValue="0"
  799. options={[
  800. {
  801. label: "正常",
  802. value: "0",
  803. },
  804. {
  805. label: "停用",
  806. value: "1",
  807. },
  808. ]}
  809. />
  810. </ProForm.Group>
  811. </ModalForm>
  812. {/* 删除确认模态框 */}
  813. <Modal
  814. title={
  815. <div style={{ display: 'flex', alignItems: 'center' }}>
  816. <ExclamationCircleFilled style={{ color: '#faad14', marginRight: 8 }} />
  817. <span>系统提示</span>
  818. </div>
  819. }
  820. open={deleteModalVisible}
  821. onOk={executeDeleteRow}
  822. onCancel={() => {
  823. setDeleteModalVisible(false);
  824. setDeleteRecord(null);
  825. }}
  826. okText="确认"
  827. cancelText="取消"
  828. >
  829. <p>{`确定删除菜单名称为“${deleteRecord?.menuName}”的数据项?`}</p>
  830. </Modal>
  831. </PageContainer>
  832. );
  833. }