Commit 01ac3d1d by zhaochengxiang

主数据定义目录

parent 7749be88
......@@ -10,8 +10,9 @@ import * as map from './map';
import * as datamodel from './datamodel';
import * as assetmanage from './assetmanage';
import * as tag from './tag';
import * as msd from './msd';
const funcs = Connect({ user, datamodel, map, assetmanage, datasource, tag })
const funcs = Connect({ user, datamodel, map, assetmanage, datasource, tag, msd })
function* request(args) {
const { type, payload, callback, error } = args.args;
......
import * as service from '../service/msd';
import { call } from 'redux-saga/effects';
export function* getTreeNodes() {
return yield call(service.getTreeNodes);
}
export function* addTreeNode(payload) {
return yield call(service.addTreeNode, payload);
}
export function* updateTreeNode(payload) {
return yield call(service.updateTreeNode, payload);
}
export function* deleteTreeNode(payload) {
return yield call(service.deleteTreeNode, payload);
}
\ No newline at end of file
import { PostJSON, GetJSON, Post } from "../util/axios"
export function getTreeNodes() {
return GetJSON("/metadatarepo/rest/msdDefinition/getTreeNode");
}
export function addTreeNode(payload) {
return Post("/metadatarepo/rest/msdDefinition/addTreeNode", payload);
}
export function updateTreeNode(payload) {
return Post("/metadatarepo/rest/msdDefinition/updateTreeNode", payload);
}
export function deleteTreeNode(payload) {
return PostJSON("/metadatarepo/rest/msdDefinition/deleteTreeNode", payload);
}
\ No newline at end of file
import {useEffect, useMemo, useState} from 'react';
import {Tooltip, Spin, AutoComplete, Tree} from 'antd';
import {useEffect, useMemo, useState, useRef} from 'react';
import {Tooltip, Spin, AutoComplete, Tree, Modal} from 'antd';
import {PlusOutlined, ReloadOutlined} from '@ant-design/icons';
import { useContextMenu, Menu as RcMenu, Item as RcItem } from "react-contexify";
import {highlightSearchContentByTerms} from '../../../../../util';
import {treeData} from './Mock';
import { dispatch } from '../../../../../model';
import {highlightSearchContentByTerms, showMessage} from '../../../../../util';
import UpdateDefineTreeNodeModal from './UpdateDefineTreeNodeModal';
import 'react-contexify/dist/ReactContexify.css';
import './DefineTree.less';
const {Option} = AutoComplete;
......@@ -12,31 +15,60 @@ const {Option} = AutoComplete;
const DefineTree = (props) => {
const {onClick} = props;
const [loading, setLoading] = useState(false);
const [data, setData] = useState();
const [options, setOptions] = useState([]);
const [keyword, setKeyword] = useState('');
const [expandedKeys, setExpandedKeys] = useState(['0-0']);
const [selectedKeys, setSelectedKeys] = useState(['0-0']);
const [expandedKeys, setExpandedKeys] = useState([]);
const [selectedKeys, setSelectedKeys] = useState([]);
const [autoExpandParent, setAutoExpandParent] = useState(false);
const [updateNodeModalVisible, setUpdateNodeModalVisible] = useState(false);
const [updateNodeType, setUpdateNodeType] = useState('');
const [rightSelectNode, setRightSelectNode] = useState({});
const selectedKeysRef = useRef([]);
const [modal, contextHolder] = Modal.useModal();
const MENU_ID = 'msd-define-tree';
const { show } = useContextMenu({
id: MENU_ID,
});
useEffect(() => {
setLoading(false);
onTreeSelect(['0-0']);
getTreeNodes();
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const treeData = useMemo(() => {
const loop = (data) =>
(data||[]).map((item) => {
if (item.children) {
return {
title: item.name||'',
key: item._id||'',
origin: item,
children: loop(item.children),
};
}
return {
title: item.name||'',
key: item._id||'',
};
});
return loop(data);
}, [data])
const treeList = useMemo(() => {
const generateList = (data, list, path = null) => {
for (let i = 0; i < data.length; i++) {
const node = data[i];
const { key, title } = node;
(data||[]).forEach(node => {
const {key, title} = node;
const currentPath = path ? `${path}/${title}` : title;
list.push({ key, title: currentPath });
list.push({key, title: currentPath});
if (node.children) {
generateList(node.children, list, currentPath);
}
}
});
};
const newTreeList = [];
......@@ -46,12 +78,94 @@ const DefineTree = (props) => {
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [treeData])
const onAddClick = () => {
const selectNode = useMemo(() => {
const generateList = (data, list) => {
(data||[]).forEach(node => {
list.push({...node});
if (node.children) {
generateList(node.children, list);
}
});
};
const newTreeList = [];
generateList(data, newTreeList);
const filterNodes = newTreeList.filter(item => selectedKeys.indexOf(item._id)!==-1);
return (filterNodes||[]).length>0 ? filterNodes[0]:{};
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, selectedKeys])
const getTreeNodes = () => {
setLoading(true);
dispatch({
type: 'msd.getTreeNodes',
callback: (data) => {
setLoading(false);
setData(data||[]);
if ((selectedKeysRef.current||[]).length===0 && (data||[]).length>0) {
onTreeSelect([data[0]._id]);
}
if ((expandedKeys||[]).length===0 && (data||[]).length>0) {
setExpandedKeys([data[0]._id]);
} else {
//新增目录操作后
setExpandedKeys(Array.from(new Set([...expandedKeys, ...selectedKeysRef.current])));
setAutoExpandParent(true);
}
},
error: () => {
setLoading(false);
}
})
}
const onAddClick = () => {
setUpdateNodeType('add');
setUpdateNodeModalVisible(true);
}
const onRefreshClick = () => {
getTreeNodes();
}
const updateNode = () => {
setUpdateNodeType('update');
setUpdateNodeModalVisible(true);
}
const deleteNode = () => {
modal.confirm({
title: '提示!',
content: '删除目录会删除相关的模版,您确定删除吗?',
onOk: () => {
setLoading(true);
dispatch({
type: 'msd.deleteTreeNode',
payload: {
params: {
nodeId: rightSelectNode?._id
}
},
callback: () => {
showMessage('success', '删除目录成功');
setLoading(false);
if (selectedKeysRef.current.indexOf(rightSelectNode?._id)!==-1) {
setSelectedKeys([]);
selectedKeysRef.current = [];
}
getTreeNodes();
},
error: () => {
setLoading(false);
}
});
}
});
}
const onAutoCompleteSearch = (searchText) => {
......@@ -83,9 +197,20 @@ const DefineTree = (props) => {
}
setSelectedKeys(selectedKeys);
selectedKeysRef.current = selectedKeys;
onClick && onClick(selectedKeys[0]);
}
const onUpdateNodeModalCancel = (refresh = false, nodeId = null) => {
setUpdateNodeModalVisible(false);
if (refresh) {
nodeId && onTreeSelect([nodeId]);
getTreeNodes();
}
}
return (
<div className='data-master-tree'>
<div className='header p-3'>
......@@ -145,9 +270,35 @@ const DefineTree = (props) => {
onSelect={onTreeSelect}
expandedKeys={expandedKeys}
selectedKeys={selectedKeys}
onRightClick={({event, node}) => {
setRightSelectNode(node?.origin);
show(event, {
position: {
x: event.clientX + 30,
y: event.clientY - 10
}
});
}}
/>
</Spin>
</div>
<UpdateDefineTreeNodeModal
visible={updateNodeModalVisible}
onCancel={onUpdateNodeModalCancel}
type={updateNodeType}
node={(updateNodeType==='add')?selectNode:rightSelectNode}
/>
<RcMenu id={MENU_ID}>
<RcItem id="edit" onClick={updateNode}>
修改目录
</RcItem>
<RcItem id="delete" onClick={deleteNode}>
删除目录
</RcItem>
</RcMenu>
{contextHolder}
</div>
);
}
......
import { useState, useEffect } from 'react';
import { Modal, Form } from 'antd';
import UpdateNodeForm from './UpdateNodeForm';
import { dispatch } from '../../../../../model';
const UpdateDefineTreeNodeModal = (props) => {
const {visible, onCancel, type, node} = props;
const [confirmLoading, setConfirmLoading] = useState(false);
const [form] = Form.useForm();
useEffect(() => {
if (visible) {
if (type === 'add') {
form.setFieldsValue({action: node ? 'sub' : 'root', name: '', comment: ''});
} else {
form.setFieldsValue({action: '', name: node?.name||'', comment: node?.comment||''});
}
}
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible, node, type])
const handleCancel = () => {
setConfirmLoading(false);
form.setFields([{ name: 'name', errors: [] }, { name: 'comment', errors: [] }]);
onCancel && onCancel();
}
const handleOk = async () => {
setConfirmLoading(true);
try {
const values = await form.validateFields();
let payload = null;
if (type === 'add') {
payload = {
name: values.name||'',
comment: values.comment||'',
parentId: (values.action==='root')?'root':node?._id
};
} else {
payload = {
...node,
name: values.name||'',
comment: values.comment||'',
}
}
let url = (type === 'add')?'msd.addTreeNode':'msd.updateTreeNode';
dispatch({
type: url,
payload: {
data: payload
},
callback: id => {
setConfirmLoading(false);
onCancel && onCancel(true, id);
},
error: () => {
setConfirmLoading(false);
}
});
} catch (errInfo) {
setConfirmLoading(false);
}
}
return (
<Modal
confirmLoading={confirmLoading}
visible={visible}
title={type==='add'?"新增目录":"更新目录"}
onOk={handleOk}
onCancel={handleCancel}
>
<UpdateNodeForm type={type} node={node} form={form} />
</Modal>
);
}
export default UpdateDefineTreeNodeModal;
\ No newline at end of file
import { useMemo } from "react";
import { Form, Input, Radio } from 'antd';
const UpdateNodeForm = (props) => {
const {form, type, node} = props;
const radioDisable = useMemo(() => {
return !node;
}, [node])
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 },
},
};
return (
<Form
{...formItemLayout}
form={form}
>
{
type==='add'&&<Form.Item label="目录类型" name="action">
<Radio.Group disabled={radioDisable} >
<Radio value='root'>根目录</Radio>
<Radio value='sub'>子目录</Radio>
</Radio.Group>
</Form.Item>
}
<Form.Item
label="名称"
name="name"
rules={[{ required: true, message: '请输入名称!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="描述"
name="comment"
rules={[{ required: true, message: '请输入描述!' }]}
>
<Input />
</Form.Item>
</Form>
);
}
export default UpdateNodeForm;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment