From 287acfe3fbfaed145388b36d77f63b5a2a3b7fba Mon Sep 17 00:00:00 2001 From: liwenxuan <1298531568@qq.com> Date: Wed, 31 Dec 2025 13:23:05 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=A1=AB=E5=85=85=E8=AE=BE?= =?UTF-8?q?=E7=BD=AEv0.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DesignForm/assembly/index.ts | 8 + .../DesignForm/formControlPropertiNew.vue | 645 +++++++++++++++++- 2 files changed, 638 insertions(+), 15 deletions(-) diff --git a/src/components/DesignForm/assembly/index.ts b/src/components/DesignForm/assembly/index.ts index 67f885e..408fb92 100644 --- a/src/components/DesignForm/assembly/index.ts +++ b/src/components/DesignForm/assembly/index.ts @@ -262,6 +262,10 @@ export default [ control: { modelValue: '', glxxsz: [], + zdtcsz: { + tbx: '', + tby: '' + }, optionsValue3Formid:'', optionsValue3Field:'', }, @@ -312,6 +316,10 @@ export default [ modelValue: '', appendToBody: true, glxxsz: [], + zdtcsz: { + tbx: '', + tby: '' + }, optionsValue3Formid:'', optionsValue3Field:'', }, diff --git a/src/components/DesignForm/formControlPropertiNew.vue b/src/components/DesignForm/formControlPropertiNew.vue index c1c5fdd..2383905 100644 --- a/src/components/DesignForm/formControlPropertiNew.vue +++ b/src/components/DesignForm/formControlPropertiNew.vue @@ -2910,6 +2910,485 @@ function mergeArrays(a, b) { //选项批量编辑 liwenxuan 20251212 end +//自动填充设置 liwenxuan 20251230 start + + +/** + * 获取字符串最后一个英文冒号(:)后的字符 + * @param {string} str - 待处理的原始字符串 + * @returns {string} 最后一个冒号后的子串;无冒号/冒号在末尾时返回空字符串 + */ +function getLastColonAfterString(str) { + // 1. 输入校验:确保输入是字符串类型(处理非字符串入参) + if (typeof str !== 'string') { + console.warn('输入必须为字符串类型'); + return ''; + } + + // 2. 找到最后一个英文冒号的索引位置 + const lastColonIndex = str.lastIndexOf(':'); + + // 3. 边界判断:无冒号 或 冒号在最后一位 → 返回空字符串 + if (lastColonIndex === -1 || lastColonIndex === str.length - 1) { + return ''; + } + + // 4. 截取最后一个冒号后的所有字符并返回 + return str.slice(lastColonIndex + 1); +} + +// 原始选项数组(标题行=列,索引列=行) +const titleOptions = computed(() => { + let result = [] + if(controlData.value.control.zdtcsz.tbx){ + zdtcszTree.value.forEach(element => { + if(element.id==controlData.value.control.zdtcsz.tbx){ + result = element.options + } + }); + } + return result +}) +const indexOptions = computed(() => { // 原“索引列”数组 + let result = [] + if(controlData.value.control.zdtcsz.tby){ + zdtcszTree.value.forEach(element => { + if(element.id==controlData.value.control.zdtcsz.tby){ + result = element.options + } + }); + } + + + return result +}) + +// 表格列配置:基于“标题行”数组(作为表头) +const zdtcszTableColumns = computed(() => { + return titleOptions.value.map(item => ({ + label: item.label, + value: item.value + })) +}) + +// 表格行数据:基于“索引列”数组(作为行) +const zdtcszTableData = computed(() => { + return indexOptions.value.map(rowItem => { + const rowObj = { + rowKey: rowItem.value, + rowLabel: rowItem.label // 第一列显示索引列的数字 + } + // 为每个标题列生成空值 + titleOptions.value.forEach(colItem => { + rowObj[`col_${colItem.value}`] = '' + }) + return rowObj + }) +}) +const zdtcszTree = computed(()=>{ + if(datapropsformList.length==0){ + datapropsformList = JSON.parse(JSON.stringify(props.formList)) + } + + //console.log(datapropsformList) + if(associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf && associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf.value[0].children && associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf.value[0].children.length>0){ + + + let datab = JSON.parse(JSON.stringify(associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf.value[0].children)) + let currentCompId = controlData.value.name + const treeC = mergeAndFilterFormTrees(datapropsformList, datab,currentCompId); + //console.log(treeC) + return treeC + }else{ + return [] + } + +}) + +/** + * 合并两个组件树,仅保留type为radio和select的节点,并过滤掉指定compId的节点,同时保留options属性 + * @param {Array} treeA - 组件树a,包含表单结构信息 + * @param {Array} treeB - 组件树b,包含字段数据信息 + * @param {String} compId - 需要过滤掉的组件id的后一部分 + * @returns {Array} - 合并后仅包含radio和select节点的组件树c + */ +function mergeAndFilterFormTrees(treeA, treeB, compId) { + // 构建b树的映射,key为name(从id中提取),value为b树节点 + const bMap = new Map(); + + // 从b树中提取通用的parentId(假设所有节点有相同的parentId) + let commonParentId = null; + + // 从id中提取name:formField:30540:upload1765154030446 -> upload1765154030446 + treeB.forEach(node => { + const id = node.id; + if (id) { + const parts = id.split(':'); + const name = parts[parts.length - 1]; // 取最后一部分作为name + bMap.set(name, node); + + // 设置通用的parentId + if (node.parentId && !commonParentId) { + commonParentId = node.parentId; + } + } + }); + + // 如果没有找到parentId,使用默认值 + if (!commonParentId) { + commonParentId = "formField:30540"; + } + + // 计数器 + let gridCount = 0; + let tabsCount = 0; + let divCount = 0; + let cardCount = 0; + + // 递归处理a树,仅保留radio和select节点,并过滤掉compId + function processANode(node, parentId = commonParentId) { + // 获取当前节点的name + const nodeName = node.name; + const nodeType = node.type; + + // 检查当前节点是否需要被过滤(如果compId与节点name相等,则过滤) + if (compId && nodeName === compId) { + // 从bMap中删除对应的节点(如果存在),避免后面被使用 + if (nodeName && bMap.has(nodeName)) { + bMap.delete(nodeName); + } + return null; + } + + // 如果是radio或select类型,直接处理 + if (nodeType === 'radio' || nodeType === 'select') { + // 检查是否需要过滤 + if (compId && nodeName === compId) { + return null; + } + + // 查找b树中对应的节点 + let bNode = null; + if (nodeName && bMap.has(nodeName)) { + bNode = bMap.get(nodeName); + bMap.delete(nodeName); // 从map中删除,标记为已使用 + } + + // 如果b节点存在,检查是否需要过滤 + if (bNode && compId) { + const bNodeId = bNode.id || ''; + const parts = bNodeId.split(':'); + const bNodeName = parts[parts.length - 1]; + if (bNodeName === compId) { + return null; + } + } + + let cNode; + if (bNode) { + // 复制b节点的所有属性 + cNode = { ...bNode }; + // 确保children数组存在 + if (!cNode.children) { + cNode.children = []; + } + // 使用b节点的parentId + cNode.parentId = bNode.parentId || parentId; + + // 保留a节点中的options属性到c节点中 + if (node.options && Array.isArray(node.options)) { + // 如果c节点中已经有options,可以合并,这里我们直接用a节点的options + // 因为a节点中的options通常是最新的配置 + cNode.options = node.options; + + // 如果a节点有control.glxxsz(关联选项设置),也保留 + if (node.control && node.control.glxxsz && Array.isArray(node.control.glxxsz)) { + if (!cNode.control) { + cNode.control = {}; + } + cNode.control.glxxsz = node.control.glxxsz; + } + } + } else { + // 如果b中不存在,则创建新节点 + const label = node.item?.label || nodeName || nodeType; + const id = nodeName ? `${commonParentId}:${nodeName}` : null; + cNode = { + id: id, + label: label, + parentId: parentId, + children: [], + value: id, + treeAttrs: { + show: label + }, + disabled: false, // radio和select类型,叶子节点disabled为false + type: nodeType + }; + + // 保留a节点中的options属性 + if (node.options && Array.isArray(node.options)) { + cNode.options = node.options; + } + + // 保留control.glxxsz(关联选项设置) + if (node.control && node.control.glxxsz && Array.isArray(node.control.glxxsz)) { + if (!cNode.control) { + cNode.control = {}; + } + cNode.control.glxxsz = node.control.glxxsz; + } + + // 保留config属性 + if (node.config) { + cNode.config = node.config; + } + } + + return cNode; + } + + // 如果不是radio或select,但可能是容器类型,需要处理其子节点 + // 检查是否是容器类型 + const containerTypes = ['table', 'card', 'flex', 'div', 'grid', 'tabs']; + if (containerTypes.includes(nodeType)) { + // 检查容器节点本身是否需要过滤 + if (compId && nodeName === compId) { + // 如果容器节点需要过滤,其所有子节点都不处理 + // 从bMap中删除对应的节点(如果存在) + if (nodeName && bMap.has(nodeName)) { + bMap.delete(nodeName); + } + return null; + } + + // 创建一个容器节点占位符 + let containerId; + let containerLabel; + let originalName = nodeName; // 保存原始name用于检查过滤 + + // 根据容器类型设置不同的id和label + switch(nodeType) { + case 'grid': + gridCount++; + containerId = `格栅布局${gridCount}`; + containerLabel = containerId; + break; + case 'tabs': + tabsCount++; + containerId = `标签页${tabsCount}`; + containerLabel = containerId; + break; + case 'div': + divCount++; + containerId = `容器${divCount}`; + containerLabel = containerId; + break; + case 'card': + cardCount++; + containerId = `卡片${cardCount}`; + containerLabel = containerId; + break; + case 'table': + case 'flex': + // 对于table和flex,查找b树中对应的节点 + let bNode = null; + if (nodeName && bMap.has(nodeName)) { + bNode = bMap.get(nodeName); + bMap.delete(nodeName); + } + + // 检查b节点是否需要过滤 + if (bNode && compId) { + const bNodeId = bNode.id || ''; + const parts = bNodeId.split(':'); + const bNodeName = parts[parts.length - 1]; + if (bNodeName === compId) { + return null; + } + } + + if (bNode) { + containerId = bNode.id || `${commonParentId}:${nodeName}`; + containerLabel = nodeType === 'table' ? `子表${bNode.label || nodeName}` : + `弹性布局${bNode.label || nodeName}`; + } else { + containerId = `${commonParentId}:${nodeName}`; + containerLabel = nodeType === 'table' ? `子表${node.item?.label || nodeName}` : + `弹性布局${node.item?.label || nodeName}`; + } + break; + default: + containerId = `${commonParentId}:${nodeName}`; + containerLabel = node.item?.label || nodeName || nodeType; + } + + // 创建容器节点 + const containerNode = { + id: containerId, + label: containerLabel, + parentId: parentId, + children: [], + value: containerId, + treeAttrs: { + show: containerLabel + }, + disabled: null, // 容器节点,非叶子节点 + type: nodeType + }; + + // 处理子组件 + let hasValidChildren = false; + + if (nodeType === 'table' || nodeType === 'card' || nodeType === 'flex' || nodeType === 'div') { + // 这些类型的子组件在list中 + if (node.list && Array.isArray(node.list)) { + const childNodes = []; + node.list.forEach(child => { + const processedChild = processANode(child, containerId); + if (processedChild) { + childNodes.push(processedChild); + hasValidChildren = true; + } + }); + containerNode.children = childNodes; + } + } else if (nodeType === 'grid' || nodeType === 'tabs') { + // 这些类型的子组件在columns.list中 + if (node.columns && Array.isArray(node.columns)) { + // 对于tabs,需要为每个column创建子节点 + if (nodeType === 'tabs') { + const tabNodes = []; + node.columns.forEach((column, index) => { + // 为每个column创建一个节点 + const columnId = `${containerId}:${column.label}`; + const columnNode = { + id: columnId, + label: column.label || `Tab${index + 1}`, + parentId: containerId, + children: [], + value: columnId, + treeAttrs: { + show: column.label || `Tab${index + 1}` + }, + disabled: null, // 非叶子节点 + type: 'tab' + }; + + // 处理column中的子组件 + let columnHasValidChildren = false; + if (column.list && Array.isArray(column.list)) { + const childNodes = []; + column.list.forEach(child => { + const processedChild = processANode(child, columnId); + if (processedChild) { + childNodes.push(processedChild); + columnHasValidChildren = true; + hasValidChildren = true; + } + }); + columnNode.children = childNodes; + } + + // 如果column有子节点,添加到tabs节点下 + if (columnHasValidChildren) { + tabNodes.push(columnNode); + } + }); + containerNode.children = tabNodes; + } else { + // 对于grid,直接处理所有columns中的子组件 + const childNodes = []; + node.columns.forEach(column => { + if (column.list && Array.isArray(column.list)) { + column.list.forEach(child => { + const processedChild = processANode(child, containerId); + if (processedChild) { + childNodes.push(processedChild); + hasValidChildren = true; + } + }); + } + }); + containerNode.children = childNodes; + } + } + } + + // 如果容器没有有效的子节点(radio或select),则返回null + if (!hasValidChildren) { + // 对于table和flex,即使没有子节点也要保留(因为可以选择) + if (nodeType === 'table' || nodeType === 'flex') { + containerNode.disabled = false; + return containerNode; + } + return null; + } + + // 设置容器节点的disabled属性 + // 对于table和flex,即使有子节点也可以选择,disabled为false + if (nodeType === 'table' || nodeType === 'flex') { + containerNode.disabled = false; + } else { + // 其他容器类型,有子节点为null,没有子节点为true + containerNode.disabled = null; + } + + return containerNode; + } + + // 其他非radio/select类型,直接返回null + return null; + } + + // 处理a树的所有根节点 + const cTree = []; + treeA.forEach(rootNode => { + const processedNode = processANode(rootNode); + if (processedNode) { + cTree.push(processedNode); + } + }); + + // 将b树中剩余的radio和select元素(在a中不存在的)添加到c树中 + bMap.forEach((bNode, nodeName) => { + // 检查是否需要过滤 + if (compId) { + const bNodeId = bNode.id || ''; + const parts = bNodeId.split(':'); + const bNodeName = parts[parts.length - 1]; + if (bNodeName === compId) { + // 过滤掉这个节点 + return; + } + } + + // 只保留radio和select类型 + if (bNode.type === 'radio' || bNode.type === 'select') { + // 保留b节点的原始结构 + const newNode = { ...bNode }; + + // 确保children数组存在 + if (!newNode.children) { + newNode.children = []; + } + + // 设置disabled属性为false(叶子节点) + newNode.disabled = false; + + cTree.push(newNode); + } + }); + + return cTree; +} + +// 使用示例 +// const filteredTree = mergeAndFilterFormTrees(treeA, treeB, 'radio1763601215033'); + + +//自动填充设置 liwenxuan 20251230 end + //关联选项设置优化为树 liwenxuan 20251209 start @@ -2919,13 +3398,14 @@ const glxxszTree = computed(()=>{ datapropsformList = JSON.parse(JSON.stringify(props.formList)) } - //console.log(datapropsformList) + console.log(datapropsformList) if(associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf && associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf.value[0].children && associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf.value[0].children.length>0){ let datab = JSON.parse(JSON.stringify(associatedFormsCurrentFormFieldTreeForGlxxszExceptSelf.value[0].children)) const treeC = mergeFormTrees(datapropsformList, datab); + console.log(treeC) return treeC }else{ return null @@ -4014,6 +4494,7 @@ function handleDetermineAssociatedFormsChooseDialog() { //liwenxuan20240426 单选多选下拉 关联选项设置 start +const ZdtcszDialogFlag = ref(false); const glxxszDialogFlag = ref(false); const glxxszDialogFlagCheckBox = ref(false); const glxxszDialogFlagSwitch = ref(false); @@ -4035,6 +4516,24 @@ function handelGlxxszDialog() { } } +function handelZdtcszDialog(){ + if (controlData.value.options.length === 0) { + alert("无可配置选项,请先添加。"); + } else { + + if(controlData.value.control.zdtcsz){ + + }else{ + controlData.value.control.zdtcsz = { + tbx: '', + tby: '' + } + } + ZdtcszDialogFlag.value = true; + + } +} + function handelGlxxszDialogCheckbox() { glxxszDialogFlagCheckBox.value = true; } @@ -4048,6 +4547,9 @@ function handleDetermineGlxxszDialogSwitch() { function handleDetermineGlxxszDialogCheckBox() { glxxszDialogFlagCheckBox.value = false; } +function handleDetermineZdtcszDialogFlag(){ + ZdtcszDialogFlag.value = false; +} //同步开关的设置值和开关关联选项设置的值 watch( () => controlData.value.control, @@ -6228,26 +6730,39 @@ const formatTooltip = (val: number) => { + {{ controlData.type === "cascader" ? "编辑" : "新增" }} - + 批量导入 -
- 关联选项设置 -
-
- 关联选项设置 -
-
- 关联选项设置 +
+
+ 关联选项设置 +
+
+ 关联选项设置 +
+
+ 关联选项设置 +
+ +
+ 自动填充设置 +
@@ -7972,9 +8487,109 @@ const formatTooltip = (val: number) => { + + + + + +
+ + 标题行 + + + + + + 索引列 + + + +
+{{zdtcszTableData}} + +
+ + + + + + + + +
+ + + + +
+ + + + + - + +