import React, { useEffect, useState } from 'react'; import { Table, Button, Modal, Form, Input, Space, Switch, Select, TreeSelect, Tooltip, InputNumber, Tree } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, QuestionCircleOutlined, FolderOutlined, MenuOutlined, ToolOutlined, CaretRightOutlined } from '@ant-design/icons'; import type { TablePaginationConfig } from 'antd/es/table'; import type { FilterValue, SorterResult } from 'antd/es/table/interface'; import { getMenuTree } from './service'; import type { MenuResponse } from './types'; import { MenuTypeEnum } from './types'; import IconSelect from '@/components/IconSelect'; import { useTableData } from '@/hooks/useTableData'; import * as AntdIcons from '@ant-design/icons'; import {FixedType} from "rc-table/lib/interface"; const MenuPage: React.FC = () => { const { list: menus, loading, loadData: fetchMenus, handleCreate, handleUpdate, handleDelete } = useTableData({ service: { baseUrl: '/api/v1/menu' }, defaultParams: { sortField: 'sort', sortOrder: 'asc' } }); const [modalVisible, setModalVisible] = useState(false); const [editingMenu, setEditingMenu] = useState(null); const [menuTree, setMenuTree] = useState([]); const [iconSelectVisible, setIconSelectVisible] = useState(false); const [form] = Form.useForm(); useEffect(() => { getMenuTree().then(menus => setMenuTree(menus)); }, []); const handleAdd = () => { setEditingMenu(null); form.resetFields(); const maxSort = Math.max(0, ...menus.map(menu => menu.sort)); form.setFieldsValue({ type: MenuTypeEnum.MENU, sort: maxSort + 10, hidden: false }); setModalVisible(true); }; const handleEdit = (record: MenuResponse) => { setEditingMenu(record); form.setFieldsValue({ ...record, parentId: record.parentId === 0 ? undefined : record.parentId }); setModalVisible(true); }; const handleTableChange = ( pagination: TablePaginationConfig, filters: Record, sorter: SorterResult | SorterResult[] ) => { const { field, order } = Array.isArray(sorter) ? sorter[0] : sorter; fetchMenus({ sortField: field as string, sortOrder: order }); }; const buildMenuTree = (menuList: MenuResponse[]): MenuResponse[] => { const menuMap = new Map(); const result: MenuResponse[] = []; menuList.forEach(menu => { menuMap.set(menu.id, { ...menu, children: [] }); }); menuList.forEach(menu => { const node = menuMap.get(menu.id)!; if (menu.parentId === 0 || !menuMap.has(menu.parentId)) { result.push(node); } else { const parent = menuMap.get(menu.parentId)!; parent.children = parent.children || []; parent.children.push(node); } }); return result; }; const getTreeSelectData = () => { const menuTree = buildMenuTree(menus); return menuTree.map(menu => ({ title: menu.name, value: menu.id, children: menu.children?.map(child => ({ title: child.name, value: child.id, disabled: editingMenu?.id === child.id })) })); }; const handleSubmit = async () => { try { const values = await form.validateFields(); if (editingMenu) { const success = await handleUpdate(editingMenu.id, { ...values, version: editingMenu.version }); if (success) { setModalVisible(false); fetchMenus(); } } else { const success = await handleCreate(values); if (success) { setModalVisible(false); fetchMenus(); } } } catch (error) { console.error('操作失败:', error); } }; const getIcon = (iconName: string | undefined) => { if (!iconName) return null; const iconKey = `${iconName.charAt(0).toUpperCase() + iconName.slice(1)}Outlined`; const Icon = (AntdIcons as any)[iconKey]; return Icon ? : null; }; const columns = [ { title: '菜单名称', dataIndex: 'name', key: 'name', width: 250, fixed: 'left' as FixedType, sorter: true }, { title: '图标', dataIndex: 'icon', key: 'icon', width: 80, render: (icon: string) => getIcon(icon) }, { title: '类型', dataIndex: 'type', key: 'type', width: 100, render: (type: MenuTypeEnum) => { const typeMap = { [MenuTypeEnum.DIRECTORY]: '目录', [MenuTypeEnum.MENU]: '菜单', [MenuTypeEnum.BUTTON]: '按钮' }; return typeMap[type]; } }, { title: '路由地址', dataIndex: 'path', key: 'path', width: 200, ellipsis: true }, { title: '组件路径', dataIndex: 'component', key: 'component', width: 200, ellipsis: true }, { title: '权限标识', dataIndex: 'permission', key: 'permission', width: 150, ellipsis: true }, { title: '排序', dataIndex: 'sort', key: 'sort', width: 80, sorter: true }, { title: '状态', dataIndex: 'enabled', key: 'enabled', width: 80, render: (enabled: boolean) => ( ) }, { title: '操作', key: 'action', width: 160, fixed: 'right' as FixedType, render: (_: any, record: MenuResponse) => ( ) } ]; return (
setModalVisible(false)} width={600} destroyOnClose >
上级菜单 } > setIconSelectVisible(true)} suffix={form.getFieldValue('icon') && getIcon(form.getFieldValue('icon'))} />
setIconSelectVisible(false)} value={form.getFieldValue('icon')} onChange={value => { form.setFieldValue('icon', value); setIconSelectVisible(false); }} /> ); }; export default MenuPage;