From 8c3647b300b4f99bf831a8754224d3b05c3286cb Mon Sep 17 00:00:00 2001 From: zhanghao <774378400@qq.com> Date: Wed, 23 Sep 2026 11:36:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E6=A0=87=E5=8A=A0=E8=BD=BD=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E5=A4=84=E7=90=86=E5=8F=8A=E7=A8=B3=E5=AE=9A=E7=9A=84?= =?UTF-8?q?=20action=20=E5=9B=BE=E6=A0=87=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/flow/components/NodeTitle.vue | 31 ++++++++++++++++++++++++- src/views/flow/config.js | 22 ++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/views/flow/components/NodeTitle.vue b/src/views/flow/components/NodeTitle.vue index f8e4e76..53d96bc 100644 --- a/src/views/flow/components/NodeTitle.vue +++ b/src/views/flow/components/NodeTitle.vue @@ -7,7 +7,7 @@
- +
@@ -76,6 +76,7 @@ import { computed, nextTick, onMounted, ref, watch } from "vue"; import { CloseBold, Delete, EditPen, FolderRemove, Operation, Select, VideoPlay } from "@element-plus/icons-vue"; import { ElMessageBox } from "element-plus"; import { emitter } from "@/utils/eventBus"; +import { getFlowNodeIconByAction } from "../config"; const props = defineProps({ icon: { type: String, default: "" }, @@ -90,7 +91,9 @@ const emits = defineEmits(["setNodeName"]); const isEditing = ref(false); const localName = ref(""); const nameInputRef = ref(); +const displayedIcon = ref(""); const isSelectArea = computed(() => props.nodeType === "selectArea"); +const configuredIcon = computed(() => getFlowNodeIconByAction(props.nodeProperties?.action)); const flowContextActions = new Set([ "NONE", "START", @@ -113,6 +116,32 @@ const typeLabel = computed(() => { return { EDGE: "设备", LLM: "模型", AE: "评估" }[props.nodeType] || props.nodeType; }); +/** + * 重置节点当前展示的图标。 + * + * 实现思路:内置节点优先根据稳定的 action 使用当前生产包中的图标,避免浏览器先请求 + * 后端流程数据里保存的开发地址或旧构建地址;无法识别的扩展节点继续使用后端自定义图标。 + */ +const resetDisplayedIcon = () => { + displayedIcon.value = configuredIcon.value || props.icon || ""; +}; + +watch([() => props.icon, configuredIcon], resetDisplayedIcon, { immediate: true }); + +/** + * 处理节点图标加载失败。 + * + * 实现思路:扩展节点的自定义 URL 失效时尝试 action 对应的内置图标;如果当前展示的 + * 已经是内置图标或没有可匹配图标,则使用 Element Plus 通用图标,避免破图占位。 + */ +const handleIconLoadError = () => { + if (configuredIcon.value && displayedIcon.value !== configuredIcon.value) { + displayedIcon.value = configuredIcon.value; + return; + } + displayedIcon.value = ""; +}; + /** * 处理 sourceName 对应的数据或交互;作用范围仅限当前组件或模块。 */ diff --git a/src/views/flow/config.js b/src/views/flow/config.js index 6100346..cff58a0 100644 --- a/src/views/flow/config.js +++ b/src/views/flow/config.js @@ -977,3 +977,25 @@ function handler(params) { }] }, ] + +// 流程数据会长期保存,而 Vite 生成的图标地址只对当前构建有效。 +// 这里用稳定的 action 建立索引,使旧流程或后端缺失 icon 时可以恢复为当前版本的内置图标。 +const flowNodeIconByAction = new Map( + collapseList.flatMap((group) => group.nodeList) + .filter((node) => node.action && node.icon) + .map((node) => [String(node.action).trim().toUpperCase(), node.icon]), +) + +/** + * 根据流程节点 action 获取当前版本的内置图标。 + * + * 实现思路:action 是流程协议中的稳定标识,比构建生成的资源 URL 更适合跨版本匹配; + * 未识别的 action 返回空字符串,由调用方继续使用后端自定义图标或通用占位图标。 + * + * @param {*} action 流程节点的动作标识 + * @returns {string} 当前构建对应的图标地址,未匹配时返回空字符串 + */ +export const getFlowNodeIconByAction = (action) => { + const normalizedAction = String(action || '').trim().toUpperCase() + return normalizedAction ? flowNodeIconByAction.get(normalizedAction) || '' : '' +}