新增系统管理路由配置,包括用户管理、部门管理、角色管理、菜单管理和定时任务管理。

This commit is contained in:
刘倡
2025-07-11 17:26:28 +08:00
parent dcdf1e75f1
commit d594ad95e0
6 changed files with 627 additions and 1 deletions

View File

@ -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',

27
config/router_system.ts Normal file
View File

@ -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',
},
],
}]

View File

@ -174,6 +174,43 @@ const BasicLayout: React.FC<BasicLayoutProps> = (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": "",

View File

@ -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`, {

View File

@ -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<T extends { menuId: string; parentId?: string; children?: T[] }>(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<MenuItem[]>([]);
const [visible, setVisible] = useState(false);
const [editingItem, setEditingItem] = useState<MenuItem | null>(null);
const [title, setTitle] = useState<string>('');
const [spin, setSpin] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [pageData, setPageData] = useState<any>({
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<MenuItem>[] = [
{
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) => [
<Button key="edit" type="link" onClick={() => handleEdit(record)}></Button>,
<Button key="add" type="link" onClick={() => handleAddSub(record)}></Button>,
<Popconfirm
key="delete"
title="确定要删除吗?"
onConfirm={() => handleDelete(record)}
okText="确定"
cancelText="取消"
>
<Button icon={<DeleteOutlined />} danger>
</Button>
</Popconfirm>
],
},
];
// 显示模态框
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 (
<Spin spinning={spin}>
<PageHeader title="菜单管理" />
<div style={{ maxHeight: innerHeight - 130, height: innerHeight - 130 }} className='xsy-entrust bgCWhite'>
<ProTable<MenuItem>
actionRef={actionRef}
columns={columns}
options={false}
bordered={false}
className='tableSearch'
size='small'
search={{ labelWidth: 'auto', span: 6 }}
request={(params) => fetchMenu(params)}
toolBarRender={() => [
<Button key="add" onClick={handleAdd} type="primary">
</Button>,
]}
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 }}
/>
<Modal
title={title}
visible={visible}
width="70%"
centered
destroyOnClose={true}
bodyStyle={{ maxHeight: window.innerHeight * 0.96 - 108, overflowY: 'auto', paddingTop: 0 }}
onOk={handleOk}
onCancel={handleCancel}
>
<Form form={form} {...layout}>
<Form.Item
name="id"
hidden={true}
>
<Input />
</Form.Item>
<Form.Item name="parentId" hidden={true}>
<Input />
</Form.Item>
<Form.Item
name="menuType"
label="菜单类型"
rules={[{required: true, message: '请选择菜单类型'}]}
>
<Select placeholder="请选择" onChange={handleMenuTypeChange}>
<Option value="folder"></Option>
<Option value="menu"></Option>
<Option value="operation"></Option>
</Select>
</Form.Item>
<Form.Item
name="menuName"
label="菜单名称"
rules={[{required: true, message: '请输入菜单名称'}]}
>
<Input placeholder="请输入菜单名称"/>
</Form.Item>
<Form.Item
name="menuOrder"
label="排序"
rules={[{required: true, message: '请输入排序'}]}
>
<Input placeholder="请输入排序"/>
</Form.Item>
<Form.Item
name="menuFrame"
label="是否为外链"
hidden={btn}
>
<Select placeholder="请选择" defaultValue="N">
<Option value="Y"></Option>
<Option value="N"></Option>
<Option value="S">3.0</Option>
</Select>
</Form.Item>
<Form.Item
name="menuUrl"
label="路由地址"
hidden={btn}
>
<Input placeholder="请输入路由地址"/>
</Form.Item>
<Form.Item
name="query"
label="路由参数"
hidden={folder || btn}
>
<Input placeholder="请输入路由参数"/>
</Form.Item>
<Form.Item
name="componet"
label="组件路径"
hidden={folder || btn}
>
<Input placeholder="请输入组件路径"/>
</Form.Item>
<Form.Item
name="menuPerms"
label="权限标识"
hidden={folder && !btn}
>
<Input placeholder="请输入权限标识"/>
</Form.Item>
<Form.Item
name="menuIcon"
label="菜单图标"
hidden={btn}
>
<Input placeholder="请输入菜单图标"/>
</Form.Item>
<Form.Item
name="isCache"
label="是否缓存"
hidden={folder || btn}
rules={[{type: 'number', message: '请输入正确的数值'}]}
>
<Select placeholder="请选择" defaultValue={0}>
<Option value={0}></Option>
<Option value={1}></Option>
</Select>
</Form.Item>
<Form.Item
name="menuVisible"
label="显示状态"
hidden={btn}
rules={[{required: true, message: '请选择显示状态'}]}
>
<Select placeholder="请选择" defaultValue="show">
<Option value="show"></Option>
<Option value="hide"></Option>
</Select>
</Form.Item>
<Form.Item
name="menuStatus"
label="菜单状态"
>
<Select placeholder="请选择" defaultValue="valid">
<Option value="valid"></Option>
<Option value="invalid"></Option>
</Select>
</Form.Item>
<Form.Item
name="menuScope"
label="系统区分标识"
>
<Input placeholder="请输入系统区分标识"/>
</Form.Item>
<Form.Item
name="menuAuth"
label="是否授权"
>
<Select placeholder="请选择" defaultValue="N">
<Option value="Y"></Option>
<Option value="N"></Option>
</Select>
</Form.Item>
<Form.Item
name="menuDefault"
label="是否默认展示"
>
<Select placeholder="请选择" defaultValue="N">
<Option value="Y"></Option>
<Option value="N"></Option>
</Select>
</Form.Item>
<Form.Item
name="menuDesc"
label="信息描述"
>
<Input.TextArea placeholder="请输入信息描述"/>
</Form.Item>
</Form>
</Modal>
</div>
</Spin>
);
};
export default MenuManagement;

View File

@ -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',
});
}