fix(flow): 解决流程节点类型兼容性和状态处理问题

- 添加 device_universal 节点类型的别名支持
- 实现遗留节点类型别名映射机制
- 修复流程运行结果显示中的空数组处理逻辑
- 优化流程状态判断和时间计算逻辑
- 改进流程调度和错误处理机制
This commit is contained in:
lixiaolong 2026-08-12 11:17:19 +08:00
parent c54f1da126
commit 8d2f3e37b4
4 changed files with 27 additions and 15 deletions

View File

@ -17,6 +17,9 @@ const DEVICE_KIND_META = Object.freeze({
const clone = (value) => JSON.parse(JSON.stringify(value ?? null))
const normalizedText = (value) => String(value || '').trim()
const LEGACY_NODE_TYPE_ALIASES = Object.freeze({
device_universal: 'deviceUniversal',
})
export const createResourceKey = (prefix) => {
const random = globalThis.crypto?.randomUUID?.().replace(/-/g, '').slice(0, 10)
@ -90,6 +93,11 @@ const findOrCreateLegacySlot = (role, node, legacySlotByIdentity, legacyDeviceId
*/
export const normalizeFlowResourceSchema = (sourceGraph) => {
const graph = clone(sourceGraph || { nodes: [], edges: [] })
graph.nodes = Array.isArray(graph.nodes) ? graph.nodes : []
graph.edges = Array.isArray(graph.edges) ? graph.edges : []
graph.nodes.forEach((node) => {
node.type = LEGACY_NODE_TYPE_ALIASES[node.type] || node.type
})
const start = getStartNode(graph)
if (!start) return graph

View File

@ -62,7 +62,7 @@ const currentComponent = computed(() => {
if (type === 'http') return HttpNodeParams
if (type === 'sdAgent') return SdAgentNodeParams
if (type === 'recognize') return RecognizeNodeParams
if (type === 'deviceUniversal') return DeviceUniversal
if (['deviceUniversal', 'device_universal'].includes(type)) return DeviceUniversal
if (type === 'branch') return SwitchNodeParams
return null
})

View File

@ -791,35 +791,38 @@ const loopFlowView = async (instId, taskId = null) => {
if (flowDisposed) return;
if (res.code === 200) {
const arr = res.data || [];
if (arr.length === 0) {
if (!flowInfoData.value.isLog) scheduleFlowView(instId, taskId);
return;
}
if (arr.length > 0) hasRunResult.value = true;
arr.forEach((item) => {
emitter.emit("changeNodeState", item);
});
oldFlowData = JSON.parse(JSON.stringify(lf.getGraphData()));
if (
arr[arr.length - 1]?.nodeType !== "END" &&
!["FAILED", "STOPPED"].includes(arr[arr.length - 1]?.status)
) {
scheduleFlowView(instId);
} else if (
arr[arr.length - 1]?.nodeType === "END" &&
arr[arr.length - 1]?.status === "SUCCESS"
) {
const first = arr[0];
const last = arr[arr.length - 1];
const lastNodeType = String(last?.nodeType || "").toUpperCase();
const lastStatus = String(last?.status || "").toUpperCase();
if (lastNodeType === "END" && lastStatus === "SUCCESS") {
if (!flowInfoData.value.isLog) {
flowStore.updateDisableForm(false);
flowState.value = "testRunFinish";
totalRunningTime.value = arr[arr.length - 1].endTime - arr[0].startTime
totalRunningTime.value = last.endTime - first.startTime;
}
} else {
} else if (["FAILED", "STOPPED", "PAUSED"].includes(lastStatus)) {
if (!flowInfoData.value.isLog) {
if (["PAUSED", "STOPPED"].includes(arr[arr.length - 1]?.status)) {
flowState.value = arr[arr.length - 1]?.status === "PAUSED" ? "pause" : "stop";
if (["PAUSED", "STOPPED"].includes(lastStatus)) {
flowState.value = lastStatus === "PAUSED" ? "pause" : "stop";
} else {
flowState.value = "testRunError";
totalRunningTime.value = arr[arr.length - 1].endTime - arr[0].startTime
totalRunningTime.value = last.endTime - first.startTime;
flowStore.updateDisableForm(false);
}
}
} else if (!flowInfoData.value.isLog) {
// END is first persisted as RUNNING and updated to SUCCESS after the handler returns.
scheduleFlowView(instId, taskId);
}
}
};

View File

@ -105,6 +105,7 @@ const componentMap = {
sdAgent: SdAgentNode,
recognize: RecognizeNode,
deviceUniversal: DeviceUniversal,
device_universal: DeviceUniversal,
};
const flowStore = useFlowStore();