diff --git a/web/src/components/modal/CascaderConfig.tsx b/web/src/components/modal/CascaderConfig.tsx index f514cd6e3f6f53e6b4d65f5412192b831aa74a66..1ac80ff8c1fe1f087c1f971656d07e27b7274040 100644 --- a/web/src/components/modal/CascaderConfig.tsx +++ b/web/src/components/modal/CascaderConfig.tsx @@ -1,63 +1,64 @@ -import { useState, useRef } from 'react'; -import { PlusCircleOutlined, MinusCircleOutlined, RightOutlined, CaretDownOutlined } from '@ant-design/icons'; -import { Modal, Input, Select } from 'antd'; +import {useState, useRef} from 'react'; +import {PlusCircleOutlined, MinusCircleOutlined, RightOutlined, CaretDownOutlined} from '@ant-design/icons'; +import {Modal, Input, Select} from 'antd'; import utils from '@/assets/utils'; -import { options } from '@/assets/utils/tree'; +import {options} from '@/assets/utils/tree'; import useMessage from '@/hooks/useMessage'; -import { baseProps, cascaderModeTypes } from '@/assets/utils/formConfig/editorConfig'; +import {baseProps, cascaderModeTypes} from '@/assets/utils/formConfig/editorConfig'; import '@/assets/style/modal.less'; type objProps = { - [key: string]: any + [key: string]: any } type propTypes = { - open: boolean, - cancel: Function, - item: baseProps + open: boolean, + cancel: Function, + item: baseProps } type cascaderOptionTypes = { - value: string, - text: string, - children?: Array, - [key: string]: any + value: string, + text: string, + children?: Array, + [key: string]: any } // 层级联动配置 const cascaderModeList = [{ - label: 'levelOne', - text: '' + label: 'levelOne', + text: '' }, { - label: 'levelTwo', - text: '' + label: 'levelTwo', + text: '' }, { - label: 'levelThree', - text: '' + label: 'levelThree', + text: '' }, { - label: 'levelFour', - text: '' + label: 'levelFour', + text: '' }]; // 截取树的节点 -function treeDataSlice(treeList: Array, level: number) { - if (!treeList || !treeList.length) return; - level--; - for (let i = 0; i < treeList.length; i++) { - const ele = treeList[i] as objProps; - if (!level) { - delete ele.children; - } - level && treeDataSlice(ele.children, level); - } +function treeDataSlice(treeList: Array, level: number) { + if (!treeList || !treeList.length) return; + level--; + for (let i = 0; i < treeList.length; i++) { + const ele = treeList[i] as objProps; + if (!level) { + delete ele.children; + } + level && treeDataSlice(ele.children, level); + } }; + // 生成树形结构数据 -function initTreeData(treeList: Array, level: number) { - if (level === 4) return options; - // 深拷贝一份 - const cloneTreeList = utils.deepClone(treeList); - treeDataSlice(cloneTreeList, level); - return cloneTreeList; +function initTreeData(treeList: Array, level: number) { + if (level === 4) return options; + // 深拷贝一份 + const cloneTreeList = utils.deepClone(treeList); + treeDataSlice(cloneTreeList, level); + return cloneTreeList; }; // 树结构的节点 // function addTreeData(nodeCount: number, level: number) { @@ -74,326 +75,341 @@ function initTreeData(treeList: Array, level: number) { // }; function addTreeData(nodeCount: number) { - // nodeCount 节点数 - const treeNode: cascaderOptionTypes = { - value: '', - text: '' - } - if (nodeCount === 1) return treeNode; - nodeCount--; - treeNode['children'] = [addTreeData(nodeCount), addTreeData(nodeCount)]; - return treeNode; + // nodeCount 节点数 + const treeNode: cascaderOptionTypes = { + value: '', + text: '' + } + if (nodeCount === 1) return treeNode; + nodeCount--; + treeNode['children'] = [addTreeData(nodeCount), addTreeData(nodeCount)]; + return treeNode; }; // 将树形结构转换成数组 function treeToList(tree: Array) { - let res: Array = []; - let id = 0; - formateData(tree, 0); - function formateData(tree: Array, level: number, pid?: number) { - for (let i = 0; i < tree.length; i++) { - let count = level || 0; - const element = tree[i] as cascaderOptionTypes; - element['level'] = count; - element['id'] = id; - element['pid'] = pid; - res.push(element as T); - id++; - if (element.children) { - count++; - formateData(element.children as Array, count, element.id); - } - } - } - return res; + let res: Array = []; + let id = 0; + formateData(tree, 0); + + function formateData(tree: Array, level: number, pid?: number) { + for (let i = 0; i < tree.length; i++) { + let count = level || 0; + const element = tree[i] as cascaderOptionTypes; + element['level'] = count; + element['id'] = id; + element['pid'] = pid; + res.push(element as T); + id++; + if (element.children) { + count++; + formateData(element.children as Array, count, element.id); + } + } + } + + return res; }; -/* 返回增加节点的新树结构 */ +/* 返回增加节点的新树结构 todo aaa */ function addTreeNodeCallback(treeList: Array, level: number): Array { - let newList = [...treeList]; - for (let i = 0; i < newList.length; i++) { - const element = newList[i] as cascaderOptionTypes; - if (!element.children) { - // 增加新节点到树上结构 - const treeNode = addTreeData(level); - element['children'] = [treeNode, treeNode]; - } else { - addTreeNodeCallback(element.children, level); - } - } - return newList; + return recursivelyData([...treeList],level); }; +const recursivelyData=(list:any[],level:number)=>{ + if(level==1){ + return list.length>0?list:[addTreeData(1),addTreeData(1)] + } + return list.map(item=>{ + if(item.children){ + recursivelyData(item.children,level-1) + }else { + item.children=[addTreeData(level-1),addTreeData(level-1)] + } + return item + }) +} const numArrIndex = ['一', '二', '三', '四']; /* 层级联动数据配置 */ function CascaderConfig(props: propTypes) { - const { open, cancel, item } = props; + const {open, cancel, item} = props; - // console.log('item===========', item) + // console.log('item===========', item) - const selectRef = useRef(null); - const message = useMessage(); - // 控制弹框显示 - const [show, setShow] = useState(open); - // 是否点击确认按钮 - const [clickBtn, setClickBtn] = useState(false); - // 选择层级联动次数 - const [visible, setVisible] = useState(false); - // 当前编辑的列索引 - const [idxObj, setIdxObj] = useState({ - idx0: 0, - idx1: 0, - idx2: 0, - idx3: 0 - }) - // 层级联动级数 - const [count, setCount] = useState(item.levelCount || 3); - // 层级联动显示数据 - const [cascaderMode, setCascaderMode] = useState>(item.cascaderMode); - // 层级联动树型列表 - const [cascaderOption, setCascaderOption] = useState>(() => { - return item.options.length ? item.options : initTreeData(options, count); - }); - // 层级联动数组列表 - // const [cascaderList, setCascaderList] = useState>(treeToList(cascaderOption)); + const selectRef = useRef(null); + const message = useMessage(); + // 控制弹框显示 + const [show, setShow] = useState(open); + // 是否点击确认按钮 + const [clickBtn, setClickBtn] = useState(false); + // 选择层级联动次数 + const [visible, setVisible] = useState(false); + // 当前编辑的列索引 + const [idxObj, setIdxObj] = useState({ + idx0: 0, + idx1: 0, + idx2: 0, + idx3: 0 + }) + // 层级联动级数 + const [count, setCount] = useState(item.levelCount || 3); + // 层级联动显示数据 + const [cascaderMode, setCascaderMode] = useState>(item.cascaderMode); + // 层级联动树型列表 + const [cascaderOption, setCascaderOption] = useState>(() => { + return item.options.length ? item.options : initTreeData(options, count); + }); + // 层级联动数组列表 + // const [cascaderList, setCascaderList] = useState>(treeToList(cascaderOption)); - /* 标题输入框内容发生变化 */ - const titleInputChange = (value: string, idx: number) => { - setCascaderMode(preList => { - const newList = utils.deepClone(preList); - newList[idx].text = value; - return newList; - }) - }; - /* 筛选出需要修改的层级下标索引 */ - const levelNumberCallback = (idx: number) => { - const arr = [0, 1, 2, 3]; - return arr.filter(el => el > idx); - }; - /* 当前选项选中 */ - const handleSelectActive = (idx: number, optIdx: number) => { - const newObj = { ...idxObj }; - const newArr = levelNumberCallback(idx); - // 修改当前选中项,后面层级选中第一个 - for (let i = 0; i < newArr.length; i++) { - newObj[('idx' + newArr[i]) as keyof typeof idxObj] = 0; - } - // 设置当前选中状态 - newObj[('idx' + idx) as keyof typeof idxObj] = optIdx; - setIdxObj(newObj); - }; - /* 生成当前显示选项列表 */ - const treeListCallback = (treeList: Array = [], idx: number): Array => { - if (!idx) return treeList; - let renderCascaderOptions: Array = []; - for (let i = 0; i < idx; i++) { - // 上一层级选中的索引值 - const preEditIdx = idxObj[('idx' + i) as keyof typeof idxObj]; - // 上一层级的孩子列表 - renderCascaderOptions = (renderCascaderOptions.length ? renderCascaderOptions[preEditIdx].children : treeList[preEditIdx].children) ?? []; - } - return renderCascaderOptions; - }; - /* 级联列表显示 */ - const renderListCallback = (idx: number, treeList?: Array) => { - return treeListCallback(treeList ?? utils.deepClone(cascaderOption), idx); - }; - /* 修改层级选项的数据(input输入) */ - const editCascaderOptionValue = (treeList: Array = [], value: string, idx: number, optIdx: number) => { - const newList = renderListCallback(idx, treeList); - newList[optIdx].text = value; - newList[optIdx].value = value; - return treeList; - }; - /* 选项输入框内容变化 */ - const cascaderInputChange = (value: string, idx: number, optIdx: number) => { - const newData = editCascaderOptionValue(utils.deepClone(cascaderOption), value, idx, optIdx); - setCascaderOption(newData); - }; - /* 点击选择层级联动变化的图标 */ - const handleSelect = () => { - const { current } = selectRef; - current && (current as objProps).focus(); - }; - /* 增加节点标题 */ - const addTreeOptionTitle = (modeList: Array, level: number): Array => { - const sliceList = cascaderModeList.slice(modeList.length); - const newModeList = [...modeList]; - for (let i = 0; i < level; i++) { - const element = sliceList[i] as T; - newModeList.push(element) - } - return newModeList; - }; - /* 选择层级联动级数变化 */ - const handleChange = (value: number) => { - let treeData: Array = []; - let newCascaderMode: Array = []; - if (value > count) { - // 增加节点 - treeData = addTreeNodeCallback(cascaderOption, value - count); //增加节点树 - newCascaderMode = addTreeOptionTitle(cascaderMode, value - count); // 增加节点标题 - } else { - // 删除节点 - treeData = initTreeData(cascaderOption, value); //删除节点树 - newCascaderMode = [...cascaderMode].slice(0, value); // 删除节点标题 - } - handleSelectActive(0, 0); - setCascaderOption(treeData); - setCascaderMode(newCascaderMode); - setCount(value); - }; - /* 增加选项的回调函数 */ - const editCascaderOptionCallback = (treeList: Array, level: number, type: string, treeNode?: cascaderOptionTypes, optIdx?: number) => { - const cloneTreeList = utils.deepClone(treeList); - let childrenList: Array = []; - for (let i = 0; i < level; i++) { - // 上一层级选中的索引值 - const preEditIdx = idxObj[('idx' + i) as keyof typeof idxObj]; - childrenList = (childrenList.length ? childrenList[preEditIdx].children : cloneTreeList[preEditIdx].children) || []; - } - // 限制至少设置一个选项 - if (type === 'delete' && childrenList.length <= 1) { - message.info('至少设置一个选项'); - return false; - } - type === 'add' ? childrenList.push(treeNode as cascaderOptionTypes) : childrenList.splice(optIdx as number, 1); - setCascaderOption(cloneTreeList); - }; - /* 添加层级的选项 */ - const handleAddCascaderOption = (idx: number) => { - const levelList = cascaderMode.map((el, i) => i + 1).reverse(); - const treeNode = addTreeData(levelList[idx]); //当前选项节点 - // 如果是第一级就直接添加,其它级需要插入到上一级选中的children中 - idx ? editCascaderOptionCallback(cascaderOption, idx, 'add', treeNode) : setCascaderOption([...cascaderOption, treeNode]); - }; - /* 删除层级选项 */ - const handleDeleteCascaderOption = (level: number, optIdx: number) => { - const cloneCascaderOption = [...cascaderOption]; - if (!level) { - // 限制至少设置一个选项 - if (cloneCascaderOption.length <= 1) { - message.info('至少设置一个选项'); - return false; - } - // 如果是第一级就直接删除选项 - cloneCascaderOption.splice(optIdx, 1); - setCascaderOption(cloneCascaderOption); - } else { - // 如果是其它层级就需要找到上一节点children的列表,再删除当前选项 - editCascaderOptionCallback(cascaderOption, level, 'delete', undefined, optIdx); - }; - handleSelectActive(level, optIdx - 1); - }; - /* 判断是否有相同的值 */ - const uniqueValueCallback = (treeList: Array): boolean => { - const values: Array = []; //数据数组,判断是否重复 - return treeList.some(el => { - // 判断是否是空字符串 - if (!el.value.trim().length) { - el.value.length > 0 ? message.info('选项内容不能为空') : message.info('请输入选项内容'); - return true; - }; - // 判断是否内容重复 - if (values.includes(el.value)) { - message.info('选项内容重复,请修改') - return true; - } else { - values.push(el.value); - }; - // 如果有children就递归判断内容 - if (el.children) { - return uniqueValueCallback(el.children); - }; - }); - }; - /* 点击确认操作 */ - const handleOk = () => { - if (!uniqueValueCallback(cascaderOption)) { - setShow(false); - setClickBtn(true); - } - }; - /* modal框完全关闭之后 */ - const afterClose = () => { - if (!clickBtn) return cancel(false); - // 关闭弹框,并且传递数据 - const configData = { - options: cascaderOption, - title: cascaderMode, - count - } - cancel(false, configData); - }; + /* 标题输入框内容发生变化 */ + const titleInputChange = (value: string, idx: number) => { + setCascaderMode(preList => { + const newList = utils.deepClone(preList); + newList[idx].text = value; + return newList; + }) + }; + /* 筛选出需要修改的层级下标索引 */ + const levelNumberCallback = (idx: number) => { + const arr = [0, 1, 2, 3]; + return arr.filter(el => el > idx); + }; + /* 当前选项选中 */ + const handleSelectActive = (idx: number, optIdx: number) => { + const newObj = {...idxObj}; + const newArr = levelNumberCallback(idx); + // 修改当前选中项,后面层级选中第一个 + for (let i = 0; i < newArr.length; i++) { + newObj[('idx' + newArr[i]) as keyof typeof idxObj] = 0; + } + // 设置当前选中状态 + newObj[('idx' + idx) as keyof typeof idxObj] = optIdx; + setIdxObj(newObj); + }; + /* 生成当前显示选项列表 */ + const treeListCallback = (treeList: Array = [], idx: number): Array => { + if (!idx) return treeList; + let renderCascaderOptions: Array = []; + for (let i = 0; i < idx; i++) { + // 上一层级选中的索引值 + const preEditIdx = idxObj[('idx' + i) as keyof typeof idxObj]; + // 上一层级的孩子列表 + renderCascaderOptions = (renderCascaderOptions.length ? renderCascaderOptions[preEditIdx].children : treeList[preEditIdx].children) ?? []; + } + return renderCascaderOptions; + }; + /* 级联列表显示 */ + const renderListCallback = (idx: number, treeList?: Array) => { + return treeListCallback(treeList ?? utils.deepClone(cascaderOption), idx); + }; + /* 修改层级选项的数据(input输入) */ + const editCascaderOptionValue = (treeList: Array = [], value: string, idx: number, optIdx: number) => { + const newList = renderListCallback(idx, treeList); + newList[optIdx].text = value; + newList[optIdx].value = value; + return treeList; + }; + /* 选项输入框内容变化 */ + const cascaderInputChange = (value: string, idx: number, optIdx: number) => { + const newData = editCascaderOptionValue(utils.deepClone(cascaderOption), value, idx, optIdx); + setCascaderOption(newData); + }; + /* 点击选择层级联动变化的图标 */ + const handleSelect = () => { + const {current} = selectRef; + current && (current as objProps).focus(); + }; + /* 增加节点标题 */ + const addTreeOptionTitle = (modeList: Array, level: number): Array => { + const sliceList = cascaderModeList.slice(modeList.length); + const newModeList = [...modeList]; + for (let i = 0; i < level; i++) { + const element = sliceList[i] as T; + newModeList.push(element) + } + return newModeList; + }; + /* 选择层级联动级数变化 */ + const handleChange = (value: number) => { + let treeData: Array = []; + let newCascaderMode: Array = []; + if (value > count) { + // 增加节点 + treeData = addTreeNodeCallback(cascaderOption, value); //增加节点树 + console.log(treeData) + newCascaderMode = addTreeOptionTitle(cascaderMode, value - count); // 增加节点标题 + } else { + // 删除节点 + treeData = initTreeData(cascaderOption, value); //删除节点树 + newCascaderMode = [...cascaderMode].slice(0, value); // 删除节点标题 + } + handleSelectActive(0, 0); + setCascaderOption(treeData); + setCascaderMode(newCascaderMode); + setCount(value); + }; + /* 增加选项的回调函数 */ + const editCascaderOptionCallback = (treeList: Array, level: number, type: string, treeNode?: cascaderOptionTypes, optIdx?: number) => { + const cloneTreeList = utils.deepClone(treeList); + let childrenList: Array = []; + for (let i = 0; i < level; i++) { + // 上一层级选中的索引值 + const preEditIdx = idxObj[('idx' + i) as keyof typeof idxObj]; + childrenList = (childrenList.length ? childrenList[preEditIdx].children : cloneTreeList[preEditIdx].children) || []; + } + // 限制至少设置一个选项 + if (type === 'delete' && childrenList.length <= 1) { + message.info('至少设置一个选项'); + return false; + } + type === 'add' ? childrenList.push(treeNode as cascaderOptionTypes) : childrenList.splice(optIdx as number, 1); + setCascaderOption(cloneTreeList); + }; + /* 添加层级的选项 */ + const handleAddCascaderOption = (idx: number) => { + const levelList = cascaderMode.map((el, i) => i + 1).reverse(); + const treeNode = addTreeData(levelList[idx]); //当前选项节点 + // 如果是第一级就直接添加,其它级需要插入到上一级选中的children中 + idx ? editCascaderOptionCallback(cascaderOption, idx, 'add', treeNode) : setCascaderOption([...cascaderOption, treeNode]); + }; + /* 删除层级选项 */ + const handleDeleteCascaderOption = (level: number, optIdx: number) => { + const cloneCascaderOption = [...cascaderOption]; + if (!level) { + // 限制至少设置一个选项 + if (cloneCascaderOption.length <= 1) { + message.info('至少设置一个选项'); + return false; + } + // 如果是第一级就直接删除选项 + cloneCascaderOption.splice(optIdx, 1); + setCascaderOption(cloneCascaderOption); + } else { + // 如果是其它层级就需要找到上一节点children的列表,再删除当前选项 + editCascaderOptionCallback(cascaderOption, level, 'delete', undefined, optIdx); + } + ; + handleSelectActive(level, optIdx - 1); + }; + /* 判断是否有相同的值 */ + const uniqueValueCallback = (treeList: Array): boolean => { + const values: Array = []; //数据数组,判断是否重复 + return treeList.some(el => { + // 判断是否是空字符串 + if (!el.value.trim().length) { + el.value.length > 0 ? message.info('选项内容不能为空') : message.info('请输入选项内容'); + return true; + } + ; + // 判断是否内容重复 + if (values.includes(el.value)) { + message.info('选项内容重复,请修改') + return true; + } else { + values.push(el.value); + } + ; + // 如果有children就递归判断内容 + if (el.children) { + return uniqueValueCallback(el.children); + } + ; + }); + }; + /* 点击确认操作 */ + const handleOk = () => { + if (!uniqueValueCallback(cascaderOption)) { + setShow(false); + setClickBtn(true); + } + }; + /* modal框完全关闭之后 */ + const afterClose = () => { + if (!clickBtn) return cancel(false); + // 关闭弹框,并且传递数据 + const configData = { + options: cascaderOption, + title: cascaderMode, + count + } + cancel(false, configData); + }; - return ( - 3 ? 1060 : 812} - title="请设置选项" - maskClosable={false} - open={show} - afterClose={afterClose} - onOk={handleOk} - onCancel={() => setShow(false)} - > -
-
- {cascaderMode.map((ele, idx) => ( -
-
- titleInputChange(e.target.value, idx)} - placeholder={numArrIndex[idx] + '级标题名称'} - /> - {renderListCallback(idx).map((opt: cascaderOptionTypes, i: number) => ( -
- handleDeleteCascaderOption(idx, i)} /> -
handleSelectActive(idx, i)}> - cascaderInputChange(e.target.value, idx, i)} placeholder={numArrIndex[idx] + '级选项名称'} /> - {cascaderMode.length === idx + 1 ? null : } -
-
- ))} -
-
-
handleAddCascaderOption(idx)}> - - 添加选项 -
-
-
- ))} -
- {/* 选择联动的级数 */} -
- 下拉框级数 - titleInputChange(e.target.value, idx)} + placeholder={numArrIndex[idx] + '级标题名称'} + /> + {renderListCallback(idx).map((opt: cascaderOptionTypes, i: number) => ( +
+ handleDeleteCascaderOption(idx, i)}/> +
handleSelectActive(idx, i)}> + cascaderInputChange(e.target.value, idx, i)} + placeholder={numArrIndex[idx] + '级选项名称'}/> + {cascaderMode.length === idx + 1 ? null : + } +
+
+ ))} +
+
+
handleAddCascaderOption(idx)}> + + 添加选项 +
+
+
+ ))} + + {/* 选择联动的级数 */} +
+ 下拉框级数 +