|
|
@@ -1,5 +1,5 @@
|
|
|
-import {PageContainer} from '@ant-design/pro-layout';
|
|
|
-import {useDomFullHeight} from '@/hooks';
|
|
|
+import { PageContainer } from '@ant-design/pro-layout';
|
|
|
+import { useDomFullHeight } from '@/hooks';
|
|
|
import {
|
|
|
ExclamationCircleOutlined,
|
|
|
QuestionCircleOutlined,
|
|
|
@@ -7,37 +7,40 @@ import {
|
|
|
} from '@ant-design/icons';
|
|
|
import Tree from './tree';
|
|
|
import './index.less';
|
|
|
-import {Button, Tooltip} from 'antd';
|
|
|
+import { Button, Tooltip } from 'antd';
|
|
|
import BaseTreeData from './baseMenu';
|
|
|
-import { useEffect, useState} from 'react';
|
|
|
-import {HTML5Backend} from 'react-dnd-html5-backend';
|
|
|
-import {DndProvider} from 'react-dnd';
|
|
|
-import {cloneDeep} from 'lodash'
|
|
|
+import { useEffect, useState } from 'react';
|
|
|
+import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
|
+import { DndProvider } from 'react-dnd';
|
|
|
+import { cloneDeep } from 'lodash';
|
|
|
import { observable } from '@formily/reactive';
|
|
|
-import { Observer, observer } from '@formily/react'
|
|
|
-import { service } from '../index'
|
|
|
-import type {TreeProps, DataNode} from 'antd/es/tree'
|
|
|
+import { Observer, observer } from '@formily/react';
|
|
|
+import { service } from '../index';
|
|
|
+import type { TreeProps, DataNode } from 'antd/es/tree';
|
|
|
|
|
|
type MenuSettingModelType = {
|
|
|
- menuData: any[]
|
|
|
- notDragKeys: (string | number)[]
|
|
|
-}
|
|
|
+ menuData: any[];
|
|
|
+ notDragKeys: (string | number)[];
|
|
|
+};
|
|
|
|
|
|
export const MenuSettingModel = observable<MenuSettingModelType>({
|
|
|
menuData: [],
|
|
|
- notDragKeys: []
|
|
|
-})
|
|
|
+ notDragKeys: [],
|
|
|
+});
|
|
|
|
|
|
export default observer(() => {
|
|
|
- const {minHeight} = useDomFullHeight(`.menu-setting-warp`);
|
|
|
+ const { minHeight } = useDomFullHeight(`.menu-setting-warp`);
|
|
|
const [baseMenu, setBaseMenu] = useState<any[]>(BaseTreeData);
|
|
|
- const [loading, setLoading] = useState(false)
|
|
|
-
|
|
|
- const finedObject = (data: any[], code: string | number, callback: (index: number, arr: any[], item: any) => void) => {
|
|
|
+ const [loading, setLoading] = useState(false);
|
|
|
|
|
|
+ const finedObject = (
|
|
|
+ data: any[],
|
|
|
+ code: string | number,
|
|
|
+ callback: (index: number, arr: any[], item: any) => void,
|
|
|
+ ) => {
|
|
|
data.forEach((item, index) => {
|
|
|
if (item.code === code) {
|
|
|
- return callback(index, data, item)
|
|
|
+ return callback(index, data, item);
|
|
|
}
|
|
|
|
|
|
if (item.children) {
|
|
|
@@ -53,7 +56,7 @@ export default observer(() => {
|
|
|
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
|
|
|
|
|
|
const data = [...MenuSettingModel.menuData];
|
|
|
- let dragObj: DataNode & {parentId: string};
|
|
|
+ let dragObj: DataNode & { parentId: string };
|
|
|
|
|
|
finedObject(data, dragKey, (index, arr, item) => {
|
|
|
arr.splice(index, 1);
|
|
|
@@ -64,19 +67,19 @@ export default observer(() => {
|
|
|
if (!info.dropToGap) {
|
|
|
finedObject(data, dropKey, (_i, _arr, item) => {
|
|
|
item.children = item.children || [];
|
|
|
- dragObj.parentId = item.id
|
|
|
-
|
|
|
+ dragObj.parentId = item.id;
|
|
|
+
|
|
|
item.children.unshift(dragObj);
|
|
|
});
|
|
|
} else if (
|
|
|
- ((info.node as any).props.children || []).length > 0 &&
|
|
|
- (info.node as any).props.expanded &&
|
|
|
- dropPosition === 1
|
|
|
+ ((info.node as any).props.children || []).length > 0 &&
|
|
|
+ (info.node as any).props.expanded &&
|
|
|
+ dropPosition === 1
|
|
|
) {
|
|
|
finedObject(data, dropKey, (_i, _arr, item) => {
|
|
|
item.children = item.children || [];
|
|
|
- dragObj.parentId = item.id
|
|
|
-
|
|
|
+ dragObj.parentId = item.id;
|
|
|
+
|
|
|
item.children.unshift(dragObj);
|
|
|
});
|
|
|
} else {
|
|
|
@@ -93,105 +96,106 @@ export default observer(() => {
|
|
|
ar.splice(i! + 1, 0, dragObj!);
|
|
|
}
|
|
|
}
|
|
|
- MenuSettingModel.menuData = [...data]
|
|
|
- }
|
|
|
+ MenuSettingModel.menuData = [...data];
|
|
|
+ };
|
|
|
|
|
|
- const getKeys = (data: any[]): (string|number)[] => {
|
|
|
- return data.reduce((pre: (string|number)[] , next: any) => {
|
|
|
- const childrenKeys = next.children ? getKeys(next.children) : []
|
|
|
- return [...pre, next.code, ...childrenKeys]
|
|
|
- }, [])
|
|
|
- }
|
|
|
+ const getKeys = (data: any[]): (string | number)[] => {
|
|
|
+ return data.reduce((pre: (string | number)[], next: any) => {
|
|
|
+ const childrenKeys = next.children ? getKeys(next.children) : [];
|
|
|
+ return [...pre, next.code, ...childrenKeys];
|
|
|
+ }, []);
|
|
|
+ };
|
|
|
|
|
|
const filterItem = (data: any[], dragKeys: (string | number)[]) => {
|
|
|
- return data.filter(item => {
|
|
|
+ return data.filter((item) => {
|
|
|
if (dragKeys.includes(item.code)) {
|
|
|
- return false
|
|
|
+ return false;
|
|
|
} else if (item.children) {
|
|
|
- item.children = filterItem(item.children, dragKeys)
|
|
|
+ item.children = filterItem(item.children, dragKeys);
|
|
|
}
|
|
|
- return true
|
|
|
- })
|
|
|
- }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ };
|
|
|
|
|
|
const onDrop = (item: any, dropIndex: string, type?: string) => {
|
|
|
- const newItem = cloneDeep(item);
|
|
|
-
|
|
|
- if (dropIndex) { // 切换层级或者挪动
|
|
|
- // const newMenus = cloneDeep(menuData);
|
|
|
- if (type === 'source') {
|
|
|
- finedObject(MenuSettingModel.menuData, dropIndex, (index, arr) => {
|
|
|
- arr.splice(index + 1, 0, newItem);
|
|
|
- });
|
|
|
- MenuSettingModel.menuData = [...MenuSettingModel.menuData];
|
|
|
- }
|
|
|
- } else { // 新增
|
|
|
- newItem.parentId = ''
|
|
|
- // 过滤掉内部已选择的节点
|
|
|
- if (newItem.children && MenuSettingModel.notDragKeys.length) {
|
|
|
- newItem.children = filterItem(newItem.children, MenuSettingModel.notDragKeys)
|
|
|
- }
|
|
|
- MenuSettingModel.menuData.push(newItem)
|
|
|
- MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData)
|
|
|
+ const newItem = cloneDeep(item);
|
|
|
+
|
|
|
+ if (dropIndex) {
|
|
|
+ // 切换层级或者挪动
|
|
|
+ // const newMenus = cloneDeep(menuData);
|
|
|
+ if (type === 'source') {
|
|
|
+ finedObject(MenuSettingModel.menuData, dropIndex, (index, arr) => {
|
|
|
+ arr.splice(index + 1, 0, newItem);
|
|
|
+ });
|
|
|
+ MenuSettingModel.menuData = [...MenuSettingModel.menuData];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 新增
|
|
|
+ newItem.parentId = '';
|
|
|
+ // 过滤掉内部已选择的节点
|
|
|
+ if (newItem.children && MenuSettingModel.notDragKeys.length) {
|
|
|
+ newItem.children = filterItem(newItem.children, MenuSettingModel.notDragKeys);
|
|
|
}
|
|
|
+ MenuSettingModel.menuData.push(newItem);
|
|
|
+ MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData);
|
|
|
}
|
|
|
+ };
|
|
|
|
|
|
const removeDragItem = (id: string | number) => {
|
|
|
finedObject(MenuSettingModel.menuData, id, (index, arr) => {
|
|
|
arr.splice(index, 1);
|
|
|
});
|
|
|
- MenuSettingModel.menuData = [...MenuSettingModel.menuData]
|
|
|
- MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData)
|
|
|
- }
|
|
|
+ MenuSettingModel.menuData = [...MenuSettingModel.menuData];
|
|
|
+ MenuSettingModel.notDragKeys = getKeys(MenuSettingModel.menuData);
|
|
|
+ };
|
|
|
|
|
|
const getSystemMenu = () => {
|
|
|
- service.queryMenuThree({ paging: false }).then(res => {
|
|
|
+ service.queryMenuThree({ paging: false }).then((res) => {
|
|
|
if (res.status === 200) {
|
|
|
- MenuSettingModel.menuData = [...res.result]
|
|
|
- MenuSettingModel.notDragKeys = getKeys(res.result)
|
|
|
+ MenuSettingModel.menuData = [...res.result];
|
|
|
+ MenuSettingModel.notDragKeys = getKeys(res.result);
|
|
|
}
|
|
|
- })
|
|
|
- }
|
|
|
+ });
|
|
|
+ };
|
|
|
|
|
|
useEffect(() => {
|
|
|
- getSystemMenu()
|
|
|
+ getSystemMenu();
|
|
|
setBaseMenu(BaseTreeData);
|
|
|
}, []);
|
|
|
|
|
|
const updateMenu = () => {
|
|
|
- setLoading(true)
|
|
|
- service.updateMenus(MenuSettingModel.menuData).then(res => {
|
|
|
- setLoading(false)
|
|
|
+ setLoading(true);
|
|
|
+ service.updateMenus(MenuSettingModel.menuData).then((res) => {
|
|
|
+ setLoading(false);
|
|
|
if (res.status === 200) {
|
|
|
-
|
|
|
}
|
|
|
- })
|
|
|
- }
|
|
|
+ });
|
|
|
+ };
|
|
|
|
|
|
return (
|
|
|
<PageContainer>
|
|
|
- <div className={'menu-setting-warp'} style={{minHeight}}>
|
|
|
+ <div className={'menu-setting-warp'} style={{ minHeight }}>
|
|
|
<div className={'menu-setting-tip'}>
|
|
|
- <ExclamationCircleOutlined/>
|
|
|
- <span style={{paddingLeft: 12}}>
|
|
|
- 基于系统源代码中的菜单数据,配置系统菜单。
|
|
|
- </span>
|
|
|
+ <ExclamationCircleOutlined />
|
|
|
+ <span style={{ paddingLeft: 12 }}>基于系统源代码中的菜单数据,配置系统菜单。</span>
|
|
|
</div>
|
|
|
<div className={'menu-tree-content'}>
|
|
|
<DndProvider backend={HTML5Backend}>
|
|
|
<div className={'menu-tree left-tree'}>
|
|
|
- <div className={'menu-tree-title'} style={{padding: '10px 16px'}}>
|
|
|
+ <div className={'menu-tree-title'} style={{ padding: '10px 16px' }}>
|
|
|
<div>
|
|
|
- <span style={{paddingRight: 12}}>
|
|
|
- 源菜单
|
|
|
- </span>
|
|
|
+ <span style={{ paddingRight: 12 }}>源菜单</span>
|
|
|
<Tooltip title={'根据系统代码自动读取的菜单数据'}>
|
|
|
- <QuestionCircleOutlined/>
|
|
|
+ <QuestionCircleOutlined />
|
|
|
</Tooltip>
|
|
|
</div>
|
|
|
- <Button type={'primary'} ghost onClick={() => {
|
|
|
- MenuSettingModel.menuData = cloneDeep(baseMenu)
|
|
|
- }}>
|
|
|
+ <Button
|
|
|
+ type={'primary'}
|
|
|
+ ghost
|
|
|
+ onClick={() => {
|
|
|
+ MenuSettingModel.menuData = cloneDeep(baseMenu);
|
|
|
+ }}
|
|
|
+ >
|
|
|
一键拷贝
|
|
|
</Button>
|
|
|
</div>
|
|
|
@@ -206,34 +210,32 @@ export default observer(() => {
|
|
|
)}
|
|
|
</Observer>
|
|
|
</div>
|
|
|
- <div style={{display: 'flex', alignItems: 'center'}}>
|
|
|
+ <div style={{ display: 'flex', alignItems: 'center' }}>
|
|
|
<div className={'menu-tree-drag-btn'}>
|
|
|
请拖动至右侧
|
|
|
- <RightOutlined/>
|
|
|
+ <RightOutlined />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div className={'menu-tree right-tree'}>
|
|
|
<div className={'menu-tree-title'}>
|
|
|
<div>
|
|
|
- <span style={{paddingRight: 12}}>
|
|
|
- 系统菜单
|
|
|
- </span>
|
|
|
+ <span style={{ paddingRight: 12 }}>系统菜单</span>
|
|
|
<Tooltip title={'菜单管理页面配置的菜单数据'}>
|
|
|
- <QuestionCircleOutlined/>
|
|
|
+ <QuestionCircleOutlined />
|
|
|
</Tooltip>
|
|
|
</div>
|
|
|
</div>
|
|
|
<Observer>
|
|
|
{() => (
|
|
|
<>
|
|
|
- <Tree
|
|
|
- onTreeDrop={onTreeDrop}
|
|
|
- onDrop={onDrop}
|
|
|
- treeData={MenuSettingModel.menuData}
|
|
|
- droppableId={'menu'}
|
|
|
- removeDragItem={removeDragItem}
|
|
|
- />
|
|
|
+ <Tree
|
|
|
+ onTreeDrop={onTreeDrop}
|
|
|
+ onDrop={onDrop}
|
|
|
+ treeData={MenuSettingModel.menuData}
|
|
|
+ droppableId={'menu'}
|
|
|
+ removeDragItem={removeDragItem}
|
|
|
+ />
|
|
|
</>
|
|
|
)}
|
|
|
</Observer>
|