基于react antd设计的树状参数需求,之前遇到过这个层级比较深的参数需求,类型与请求后端设计参数,类型可以选择数组对象数字字符串等

ini
import React, { useEffect, useState, forwardRef, useImperativeHandle } from 'react';
import { Form, Select, Input, Row, Col, Button, Tree, Space } from 'antd';
import { PlusCircleOutlined, MinusCircleOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import styles from '../index.module.less';
import { cloneDeep } from 'lodash';
const ParamSet = forwardRef((props, ref) => {
const { onChange, value } = props;
const [treeData, setTreeData] = useState([
{
title: (key) => renderTreeNodesTitle(key),
key: '0-0',
isLeaf: false,
name: 'root',
type: 'object',
desc: 'root',
children: [],
},
]);
const addNode = (currNode) => {
if (currNode.isLeaf) {
currNode.isLeaf = false;
}
console.log('currNode', currNode);
if (currNode.children && currNode.children.length > 0) {
if (currNode.type === 'array') {
const firstChild = currNode.children[0];
currNode.children.push({
title: (key) => renderTreeNodesTitle(key),
key: `${currNode.key}-${Date.now().toString().slice(-5)}`,
isLeaf: true,
parentType: currNode.type,
parentNode: currNode,
name: '',
type: firstChild.type,
value: '',
desc: '',
});
} else if (currNode.type === 'object') {
currNode.children.push({
title: (key) => renderTreeNodesTitle(key),
key: `${currNode.key}-${Date.now().toString().slice(-5)}`,
isLeaf: true,
parentType: currNode.type,
name: '',
type: 'string',
value: '',
desc: '',
});
}
console.log('treeData', treeData);
setTreeData([...treeData]);
return;
}
console.log('zhepaobulai');
currNode.children = [
{
title: (key) => renderTreeNodesTitle(key),
key: `${currNode.key}-${Date.now().toString().slice(-5)}`,
isLeaf: true,
parentType: currNode.type,
parentNode: currNode,
name: '',
type: 'string',
value: '',
desc: '',
},
];
setTreeData([...treeData]);
};
const findNodes = (treeData, currNode) => {
const res = treeData.filter((item) => {
if (item.key !== currNode.key) {
if (item.children?.length) {
item.children = findNodes(item.children, currNode);
}
return true;
} else {
return false;
}
});
return res;
};
const delNode = (currNode) => {
const res = findNodes(treeData, currNode);
setTreeData(res);
};
const changeParamName = (e, currNode) => {
console.log(e.target.value);
currNode.name = e.target.value;
setTreeData([...treeData]);
};
const changeParamType = (e, currNode) => {
currNode.type = e;
if (e === 'object' || e === 'array') {
currNode.children = null;
currNode.isLeaf = false;
currNode.value = '';
} else {
currNode.children = null;
currNode.isLeaf = true;
}
if (currNode.parentType === 'array') {
currNode.parentNode.children.forEach((item) => {
item.type = currNode.type;
});
}
setTreeData([...treeData]);
};
const changeParamValue = (e, currNode) => {
currNode.value = e.target.value;
setTreeData([...treeData]);
};
const changeParamDesc = (e, currNode) => {
currNode.desc = e.target.value;
setTreeData([...treeData]);
};
const renderTreeNodesTitle = (currNode) => {
console.log('整棵树', treeData);
return (
<div key={currNode.key}>
<Space size={3}>
<Input placeholder="参数名" value={currNode.name} disabled={currNode.parentType === 'array'} onChange={(e) => changeParamName(e, currNode)} />
<Select
placeholder="参数类型"
style={{ width: 120 }}
value={currNode.type}
onChange={(e) => changeParamType(e, currNode)}
options={[
{ value: 'string', label: 'string' },
{ value: 'integer', label: 'integer' },
{ value: 'number', label: 'number' },
{ value: 'boolean', label: 'boolean' },
{ value: 'array', label: 'array' },
{ value: 'object', label: 'object' },
]}
/>
<div style={{ width: '120px' }}>
<Input
placeholder="参数值"
disabled={['object', 'array'].includes(currNode.type)}
value={currNode.value}
onChange={(e) => changeParamValue(e, currNode)}
/>
</div>
<div style={{ width: '120px' }}>
<Input placeholder="备注" value={currNode.desc} onChange={(e) => changeParamDesc(e, currNode)} />
</div>
<div style={{ width: '10px' }}>
{['object', 'array'].includes(currNode.type) && (
<PlusCircleOutlined className={styles.headerIcon} onClick={() => addNode(currNode)} />
)}
</div>
<div style={{ width: '10px' }}>
{!currNode.children?.length && (
<MinusCircleOutlined className={styles.headerIcon} onClick={() => delNode(currNode)} />
)}
</div>
</Space>
</div>
);
};
const add = () => {};
const formatTreeData = (treeData = []) => {
const res = treeData.map((item) => {
if (item.type === 'object' || item.type === 'array') {
if (item.children?.length) {
item.children = formatTreeData(item.children);
}
return {
name: item.name,
type: item.type,
children: item.children,
desc: item.desc,
};
}
return {
name: item.name,
type: item.type,
value: item.value,
desc: item.desc,
};
});
return res;
};
useEffect(() => {
const copyData = cloneDeep(treeData);
const resTreeData = formatTreeData(copyData);
onChange(resTreeData);
}, [treeData]);
useImperativeHandle(ref, () => ({
getParams: (newParams) => {
return treeData;
},
}));
return (
<div>
<Tree autoExpandParent={true} defaultExpandAll={true} treeData={treeData} />
{/* <Row>
<Col span={14}>
<Button type="dashed" onClick={() => add()} icon={<PlusOutlined />}>
添加参数信息
</Button>
</Col>
</Row> */}
</div>
);
});
export default ParamSet;