From d594ad95e0a1f2d22014b53365e5ee4f6709581f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=80=A1?= Date: Fri, 11 Jul 2025 17:26:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=B3=BB=E7=BB=9F=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E8=B7=AF=E7=94=B1=E9=85=8D=E7=BD=AE=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E6=8B=AC=E7=94=A8=E6=88=B7=E7=AE=A1=E7=90=86=E3=80=81=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E7=AE=A1=E7=90=86=E3=80=81=E8=A7=92=E8=89=B2=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E3=80=81=E8=8F=9C=E5=8D=95=E7=AE=A1=E7=90=86=E5=92=8C?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E7=AE=A1=E7=90=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/router.config.ts | 2 + config/router_system.ts | 27 ++ src/layouts/BasicLayout.tsx | 37 ++ src/pages/System/Department/service.ts | 2 +- src/pages/System/Menu/index.tsx | 488 +++++++++++++++++++++++++ src/pages/System/Menu/service.ts | 72 ++++ 6 files changed, 627 insertions(+), 1 deletion(-) create mode 100644 config/router_system.ts create mode 100644 src/pages/System/Menu/index.tsx create mode 100644 src/pages/System/Menu/service.ts diff --git a/config/router.config.ts b/config/router.config.ts index 50da76f..d65c8b1 100644 --- a/config/router.config.ts +++ b/config/router.config.ts @@ -6,6 +6,7 @@ import approvalForm from './router_approval_form'; import partyMemberTopic from './router_partyMemberTopic'; import highQualityOperation from './router_highQualityOperation'; import { elecBidEvaluation, monitor, monitorScreen } from './router_elecEvaluation'; +import system from './router_system'; export default [ //========================================================================登陆 ...transfer,//跳转、登陆 @@ -159,6 +160,7 @@ export default [ ...home,//各角色主页 ...menuaZhaoBiao,//项目菜单所有路由 ...elecBidEvaluation,//电子评标室-监控大屏 + ...system,//电子评标室-监控大屏 {//问卷调查 name: 'Questionnaire', icon: 'UnorderedListOutlined', diff --git a/config/router_system.ts b/config/router_system.ts new file mode 100644 index 0000000..2276db7 --- /dev/null +++ b/config/router_system.ts @@ -0,0 +1,27 @@ +//审批单 +export default [{ + name: '/System', + path: '/System', + routes: [ + {//用户管理 + path: '/System/User', + component: './System/User', + }, + {//部门管理 + path: '/System/Dept', + component: './System/Department', + }, + {//角色管理 + path: '/System/Role', + component: './System/Role', + }, + {//菜单管理 + path: '/System/Menu', + component: './System/Menu', + }, + {//定时任务管理 + path: '/System/Scheduled', + component: './System/Scheduled', + }, + ], +}] diff --git a/src/layouts/BasicLayout.tsx b/src/layouts/BasicLayout.tsx index 1dd6416..8dc9fe1 100644 --- a/src/layouts/BasicLayout.tsx +++ b/src/layouts/BasicLayout.tsx @@ -174,6 +174,43 @@ const BasicLayout: React.FC = (props) => { ], "feignFlag": null }, + { + "menuId": "99", + "path": "", + "name": "系统管理", + "icon": "BookOutlined", + "menuScope": "EBTP", + "menuOu": null, + "isTop": 0, + "children": [ + { + "path": "/System/User", + "name": "用户管理", + "frame": "N" + }, + { + "path": "/System/Dept", + "name": "部门管理", + "frame": "N" + }, + { + "path": "/System/Role", + "name": "角色管理", + "frame": "N" + }, + { + "path": "/System/Menu", + "name": "菜单管理", + "frame": "N" + }, + { + "path": "/System/Scheduled", + "name": "定时任务管理", + "frame": "N" + } + ], + "feignFlag": null + }, { "menuId": "41", "path": "", diff --git a/src/pages/System/Department/service.ts b/src/pages/System/Department/service.ts index eaa2e4d..3383396 100644 --- a/src/pages/System/Department/service.ts +++ b/src/pages/System/Department/service.ts @@ -1,4 +1,4 @@ -import { request } from '@umijs/max'; +import request from '@/utils/request'; export async function fetchAllDepartment(params: any) { return request(`/api/sys-manager-ebtp-project/v1/sysorg/queryAll`, { diff --git a/src/pages/System/Menu/index.tsx b/src/pages/System/Menu/index.tsx new file mode 100644 index 0000000..76838db --- /dev/null +++ b/src/pages/System/Menu/index.tsx @@ -0,0 +1,488 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { Button, Form, Input, Select, Modal, message, Popconfirm, PageHeader, Spin } from 'antd'; +import { DeleteOutlined } from '@ant-design/icons'; +import ProTable, { ProColumns, ActionType } from '@ant-design/pro-table'; + +const { Option } = Select; +import { + fetchMenuList, + fetchMenuTreeList, + updateMenu, + deleteMenu, + createMenu, + MenuData +} from "@/pages/System/Menu/service"; + +// 菜单数据结构,扩展服务接口 +type MenuItem = MenuData & { + id: string; + menuId: string; + key: string; + createBy?: string; + createDate?: string; + updateBy?: string; + updateDate?: string; + isCache?: number; + children?: MenuItem[]; // 用于处理树结构 +}; + +// 工具函数:将平铺数组转为树形结构 +function listToTree(list: T[], parentId: string = '0'): T[] { + return list + .filter(item => (item.parentId ?? '0') === parentId) + .map(item => ({ + ...item, + children: listToTree(list, item.menuId) + })); +} + +// 菜单管理组件 + +const MenuManagement: React.FC = () => { + const [form] = Form.useForm(); + const [folder, setFolder] = useState(false); + const [btn, setBtn] = useState(false); + const [loading, setLoading] = useState(false); + const [menuList, setMenuList] = useState([]); + const [visible, setVisible] = useState(false); + const [editingItem, setEditingItem] = useState(null); + const [title, setTitle] = useState(''); + const [spin, setSpin] = useState(false); + const actionRef = useRef(); + const [pageData, setPageData] = useState({ + pageNo: 1, + pageSize: 10 + }); + + const layout = { + labelCol: { span: 6 }, + wrapperCol: { span: 13 }, + }; + + const fetchMenu = async (params: any) => { + setSpin(true); + try { + const result = await fetchMenuTreeList(params); + const flatData = result.data?.records || result.data || []; + let res = { + data: flatData, + total: result.data?.total || flatData.length, + success: true, + pageSize: result.data?.size || 10, + current: result.data?.current || 1 + } + console.log(res); + return res; + } catch (error) { + message.error('获取菜单列表失败'); + return { + data: [], + total: 0, + success: false, + pageSize: 10, + current: 1 + }; + } finally { + setSpin(false); + } + }; + + // 处理编辑 + const handleEdit = (item: MenuItem) => { + debugger; + setEditingItem(item); + form.setFieldsValue({ + id: item.menuId, + parentId: item.parentId, + // parentName: item.parentName, + menuName: item.menuName, + menuOrder: item.menuOrder, + menuUrl: item.menuUrl, + componet: item.componet, + menuFrame: item.menuFrame, + isCache: item.isCache, + menuType: item.menuType, + menuVisible: item.menuVisible, + menuStatus: item.menuStatus, + menuPerms: item.menuPerms, + menuIcon: item.menuIcon, + remark: item.remark, + menuScope: item.menuScope, + menuOu: item.menuOu, + menuAuth: item.menuAuth, + menuSuspension: item.menuSuspension, + menuDefault: item.menuDefault, + tenantId: item.tenantId, + versions: item.versions, + menuDesc: item.menuDesc, + }); + setVisible(true); + }; + + const handleDelete = async (menuItem: MenuItem) => { + Modal.confirm({ + title: '确认删除该菜单?', + onOk: async () => { + try { + await deleteMenu(menuItem.menuId); + message.success('删除成功'); + actionRef.current?.reload(); + } catch (error) { + message.error('删除失败'); + } + }, + }); + }; + + // 处理新增子菜单 + const handleAddSub = (parentItem: MenuItem) => { + setEditingItem({ + ...parentItem, + menuId: '-1', // 临时标识新增项 + }); + form.setFieldsValue({ + id: null, + menuName: '', + menuOrder: 0, + menuUrl: '', + componet: '', + menuFrame: 'N', + isCache: 0, + menuType: 'menu', + menuVisible: 'show', + menuStatus: 'valid', + menuPerms: '', + menuIcon: '', + remark: '', + parentId: parentItem.menuId, + menuScope: '', + menuOu: '', + menuAuth: 'N', + menuSuspension: 'N', + menuDefault: 'N', + tenantId: '', + versions: 1, + menuDesc: '' + }); + setVisible(true); + setTitle('新增子菜单'); + }; + // 表格列配置 + const columns: ProColumns[] = [ + { + title: '菜单名称', + dataIndex: 'menuName', + key: 'menuName', + ellipsis: true, + }, + { + title: '排序', + dataIndex: 'menuOrder', + key: 'menuOrder', + search: false, + }, + { + title: '权限标识', + dataIndex: 'menuPerms', + key: 'menuPerms', + search: false, + }, + { + title: '组件路径', + dataIndex: 'componet', + key: 'componet', + search: false, + }, + { + title: '状态', + dataIndex: 'menuStatus', + key: 'menuStatus', + valueEnum: { + 'valid': { text: '正常', status: 'Success' }, + 'invalid': { text: '停用', status: 'Error' }, + }, + }, + { + title: '创建时间', + dataIndex: 'createDate', + key: 'createDate', + valueType: 'dateTime', + search: false, + }, + { + title: '操作', + key: 'action', + valueType: 'option', + render: (_: any, record: MenuItem) => [ + , + , + handleDelete(record)} + okText="确定" + cancelText="取消" + > + + + ], + }, + ]; + + // 显示模态框 + const handleAdd = () => { + setEditingItem(null); + form.resetFields(); + // 设置新增时的默认值 + form.setFieldsValue({ + menuType: 'menu', + menuFrame: 'N', + menuVisible: 'show', + menuStatus: 'valid', + menuAuth: 'N', + menuSuspension: 'N', + menuDefault: 'N', + versions: 1, + isCache: 0, + parentId: '0', + }); + setVisible(true); + setTitle('新增菜单'); + }; + + // 模态框确定按钮处理 + const handleOk = async () => { + try { + const values = await form.validateFields(); + if (!values.parentId) values.parentId = '0'; + if (editingItem && editingItem.menuId !== '-1') { + // 编辑操作 + await updateMenu(values); + message.success('修改成功'); + } else { + // 新增操作 + await createMenu(values); + message.success('创建成功'); + } + closeModal(); + } catch (error) { + console.error(error); + } + }; + + // 关闭模态框 + const closeModal = () => { + actionRef.current?.reload(); + form.resetFields(); + setVisible(false); + }; + + // 模态框取消按钮处理 + const handleCancel = () => { + closeModal(); + }; + + const handleMenuTypeChange = (value: string) => { + if (value === 'folder') { + setFolder(true) + setBtn(false) + } else if (value === 'operation') { + setBtn(true) + setFolder(false) + } else { + setFolder(false) + setBtn(false) + } + }; + + + return ( + + +
+ + actionRef={actionRef} + columns={columns} + options={false} + bordered={false} + className='tableSearch' + size='small' + search={{ labelWidth: 'auto', span: 6 }} + request={(params) => fetchMenu(params)} + toolBarRender={() => [ + , + ]} + pagination={{ + defaultPageSize: 10, + showSizeChanger: false, + onChange: (page, pageSize) => setPageData({ pageNo: page, pageSize: pageSize }), + onShowSizeChange: (current, size) => setPageData({ pageNo: current, pageSize: size }), + }} + onReset={() => { setPageData({ pageNo: 1, pageSize: 10 }) }} + rowKey="menuId" + expandable={{ defaultExpandAllRows: false }} + /> + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ ); +}; + +export default MenuManagement; diff --git a/src/pages/System/Menu/service.ts b/src/pages/System/Menu/service.ts new file mode 100644 index 0000000..e63a97a --- /dev/null +++ b/src/pages/System/Menu/service.ts @@ -0,0 +1,72 @@ +import request from "@/utils/request"; + +// 菜单数据接口 +export interface MenuData { + id?: string; + menuId?: string; + menuName: string; + parentId?: string; + menuOrder?: number; + menuUrl?: string; + componet?: string; + menuFrame?: string; + isCache?: number; + menuType: 'folder' | 'menu' | 'operation'; + menuVisible?: string; + menuStatus?: string; + menuPerms?: string; + menuIcon?: string; + menuScope?: string; + menuOu?: string; + menuAuth?: string; + menuSuspension?: string; + menuDefault?: string; + tenantId?: string; + versions?: number; + menuDesc?: string; + deleteFlag?: string; + remark?: string; +} + +const prefix = '/api/sys-manager-ebtp-project/'; + +export async function fetchMenuList(params: any) { + return request(prefix + 'v1/menu/list', { + params: params, + method: 'GET' + }); +} + +export async function fetchMenuTreeList(params: any) { + return request(prefix + 'v1/menu/menuList', { + params: params, + method: 'GET' + }); +} + +export async function fetchMenuTree(params: any) { + return request(prefix + 'v1/menu/treeselect', { + params: params, + method: 'GET' + }); +} + +export async function createMenu(params: MenuData) { + return request(prefix + 'v1/menu', { + data: params, + method: 'POST' + }); +} + +export async function updateMenu(params: MenuData) { + return request(prefix + 'v1/menu', { + data: params, + method: 'PUT' + }); +} + +export async function deleteMenu(param: string) { + return request(prefix + 'v1/menu/delete/' + param, { + method: 'DELETE', + }); +}