From 38166cb0b8f067f888835833f09cf748901e813b Mon Sep 17 00:00:00 2001 From: 2910410219 <2910410219@qq.com> Date: Sat, 23 May 2026 10:22:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=80=89=E4=B8=AD=E5=85=83=E7=B4=A0=E5=8A=9F=E8=83=BD=E4=B8=8E?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E5=B7=A5=E4=BD=9C=E6=B5=81=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E6=A1=86=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增删除选中元素的按钮,支持对节点的删除操作,并处理下级节点引用的清理。 - 将保存工作流对话框重构为独立组件,提升代码可读性与复用性。 - 优化了预览功能的代码结构,确保视频展示的样式一致性。 --- .../creation/component/SaveWorkflowDialog.vue | 40 +++++ src/views/settings/creation/index.vue | 157 +++++++++++++++--- 2 files changed, 170 insertions(+), 27 deletions(-) create mode 100644 src/views/settings/creation/component/SaveWorkflowDialog.vue diff --git a/src/views/settings/creation/component/SaveWorkflowDialog.vue b/src/views/settings/creation/component/SaveWorkflowDialog.vue new file mode 100644 index 0000000..6ce746b --- /dev/null +++ b/src/views/settings/creation/component/SaveWorkflowDialog.vue @@ -0,0 +1,40 @@ + + + diff --git a/src/views/settings/creation/index.vue b/src/views/settings/creation/index.vue index ac4aef2..afcf5e2 100644 --- a/src/views/settings/creation/index.vue +++ b/src/views/settings/creation/index.vue @@ -449,6 +449,18 @@
清空画布 + + 删除选中 + 保存工作流
@@ -564,25 +576,13 @@ - - - - - - - - - - - + :save-form="saveForm" + :current-editing-workflow-id="currentEditingWorkflowId" + :saving="saving" + @confirm="confirmSaveWorkflow" + /> @@ -770,7 +770,12 @@
- + @@ -789,6 +794,7 @@ import '@logicflow/core/dist/index.css'; import '@logicflow/extension/lib/style/index.css'; import SkillSelector from '/@/components/skill/NodeSkillSelector.vue'; import ModelSelector from '/@/components/model/ModelSelector.vue'; +import SaveWorkflowDialog from './component/SaveWorkflowDialog.vue'; import type { SkillItem } from '/@/api/settings/skill'; import { downloadToFile, @@ -3236,14 +3242,14 @@ watch( currentHttpBodyField.value = ''; showHttpBodyDialog.value = false; - // 重置 dynamicFormValues(不删除固定字段键,动态 expand 键按节点切换清理) - for (const key in dynamicFormValues) { - if (key.includes('_responseType_expand_')) { - delete dynamicFormValues[key]; - continue; - } - dynamicFormValues[key] = ''; + // 重置 dynamicFormValues(不删除固定字段键,动态 expand 键按节点切换清理) + for (const key in dynamicFormValues) { + if (key.includes('_responseType_expand_')) { + delete dynamicFormValues[key]; + continue; } + dynamicFormValues[key] = ''; + } const currentNodeCode = formState.nodeCode; const baseFormFields = nodeSchemaMap.value[currentNodeCode] || []; const baseFieldNames = new Set(baseFormFields.map((f) => f.field)); @@ -3779,7 +3785,100 @@ const resetFlow = () => { selectedElement.value = null; syncDsl(); }; -// 从后端 DSL 恢复工作流 +const cleanupReferencesToNode = (deletedNodeId: string) => { + const lf = logicFlowInstance.value; + if (!lf) return 0; + + const graphData = lf.getGraphData() as { nodes?: Item[] }; + const nodes = graphData.nodes || []; + let affectedCount = 0; + + nodes.forEach((node: any) => { + if (node.id === deletedNodeId) return; + const props = node.properties || {}; + const inputSource = Array.isArray(props.inputSource) ? props.inputSource : []; + const nextInputSource = inputSource.filter((item: any) => item?.nodeId !== deletedNodeId); + + if (nextInputSource.length === inputSource.length) return; + + affectedCount += 1; + const normalizedInputSource = nextInputSource.length > 0 ? nextInputSource : null; + lf.setProperties(node.id, { + ...props, + inputSource: normalizedInputSource, + }); + + if (selectedElement.value?.id === node.id) { + selectedElement.value.properties = { + ...props, + inputSource: normalizedInputSource, + }; + } + }); + + return affectedCount; +}; +const getAffectedDownstreamNodeNames = (deletedNodeId: string) => { + const lf = logicFlowInstance.value; + if (!lf) return [] as string[]; + + const graphData = lf.getGraphData() as { nodes?: Item[] }; + const nodes = graphData.nodes || []; + const names: string[] = []; + + nodes.forEach((node: any) => { + if (node.id === deletedNodeId) return; + const props = node.properties || {}; + const inputSource = Array.isArray(props.inputSource) ? props.inputSource : []; + const referenced = inputSource.some((item: any) => item?.nodeId === deletedNodeId); + if (!referenced) return; + + const nodeName = typeof node.text === 'string' ? node.text : node.text?.value || node.id; + names.push(String(nodeName)); + }); + + return names; +}; +const deleteSelectedElement = async () => { + const lf = logicFlowInstance.value; + const cur = selectedElement.value; + if (!lf || !cur) return; + + if (cur.kind === 'node' && (cur.properties?.nodeCode === START_NODE_CODE || cur.text === START_NODE_TEXT)) { + ElMessage.warning('开始节点不能删除'); + return; + } + + try { + let affectedCount = 0; + if (cur.kind === 'node') { + const affectedNodeNames = getAffectedDownstreamNodeNames(cur.id); + if (affectedNodeNames.length > 0) { + const previewNames = affectedNodeNames.slice(0, 8); + const overflowText = affectedNodeNames.length > 8 ? `\n...等 ${affectedNodeNames.length} 个节点` : ''; + await ElMessageBox.confirm( + `删除该节点将清理以下下级节点中的引用:\n${previewNames.join('、')}${overflowText}`, + '删除确认', + { + confirmButtonText: '继续删除', + cancelButtonText: '取消', + type: 'warning', + } + ); + } + + affectedCount = cleanupReferencesToNode(cur.id); + lf.deleteNode(cur.id); + } else { + lf.deleteEdge(cur.id); + } + selectedElement.value = null; + ElMessage.success(affectedCount > 0 ? `删除成功,已清理 ${affectedCount} 个下级节点引用` : '删除成功'); + } catch (error) { + if (error === 'cancel') return; + ElMessage.error('删除失败'); + } +};// 从后端 DSL 恢复工作流 const loadWorkflowFromDsl = (dsl: any) => { const lf = logicFlowInstance.value; if (!lf || !dsl) return; @@ -5527,3 +5626,7 @@ onBeforeUnmount(() => { justify-content: center; } + + + +