feat: 添加试运行结果处理逻辑,优化节点状态同步与布局更新

This commit is contained in:
zhanghao 2026-09-22 11:12:19 +08:00
parent fb207a4ff1
commit 92540f594d
3 changed files with 57 additions and 8 deletions

View File

@ -399,7 +399,7 @@ function handler(params) {
name: "通用指令", name: "通用指令",
type: "deviceUniversal", type: "deviceUniversal",
desc: "执行设备通用指令", desc: "执行设备通用指令",
show: __PROJECT_NAME__ === 'aima', // show: __PROJECT_NAME__ === 'aima',
action: 'DEVICE_EXECUTE_JSON_COMMAND', action: 'DEVICE_EXECUTE_JSON_COMMAND',
nodeType: 'EDGE', nodeType: 'EDGE',
nodeParams: [ nodeParams: [
@ -415,7 +415,7 @@ function handler(params) {
name: "动作队列", name: "动作队列",
type: "actionQueue", type: "actionQueue",
desc: "在边缘端按顺序连续执行多个动作", desc: "在边缘端按顺序连续执行多个动作",
show: __PROJECT_NAME__ === 'aima', // show: __PROJECT_NAME__ === 'aima',
action: 'SYSTEM_EXECUTE_ACTION_QUEUE', action: 'SYSTEM_EXECUTE_ACTION_QUEUE',
nodeType: 'EDGE', nodeType: 'EDGE',
nodeParams: [ nodeParams: [

View File

@ -1511,6 +1511,45 @@ const findMainFlowEndLog = (logs) => {
}); });
}; };
/**
* 等待运行结果引起的 Vue 渲染、ResizeObserver 和锚点同步全部完成。
*
* 实现思路:运行日志更新节点后,部分布局同步会延迟到下一动画帧。连续等待两个动画帧,
* 再跨过一个任务周期,确保同帧内后注册的布局回调也已执行;随后才建立新的图数据基线
* 并开放编辑和发布。
*
* @returns {Promise<void>} 两轮浏览器布局帧完成后结束
*/
const waitForRunResultLayout = async () => {
await nextTick();
await new Promise((resolve) => {
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => window.setTimeout(resolve, 0));
});
});
};
/**
* 将当前试运行实例稳定地切换为成功状态。
*
* 实现思路:先等待所有运行态布局副作用结束,再以最终画布数据刷新脏数据比较基线;
* 最后设置成功状态并解除表单锁,确保延迟的内部布局事件不会被识别为用户编辑。
*
* @param {string | number | null} currentInstId 当前流程实例 ID
* @param {Object} mainEnd 主流程结束节点成功日志
* @param {Object} first 当前实例第一条执行日志
* @returns {Promise<boolean>} 当前实例成功完成状态同步时返回 true
*/
const completeTrialRun = async (currentInstId, mainEnd, first) => {
await waitForRunResultLayout();
if (!isCurrentFlowPoll(currentInstId)) return false;
oldFlowData = JSON.parse(JSON.stringify(lf.getGraphData()));
totalRunningTime.value = mainEnd.endTime - first.startTime;
flowState.value = "testRunFinish";
flowStore.updateDisableForm(false);
return true;
};
/** /**
* 查询并同步试运行结果,直到当前实例进入成功、失败、暂停或终止状态。 * 查询并同步试运行结果,直到当前实例进入成功、失败、暂停或终止状态。
* *
@ -1585,9 +1624,7 @@ const loopFlowView = async (currentInstId, taskId = null) => {
} }
} else if (mainEndStatus === "SUCCESS") { } else if (mainEndStatus === "SUCCESS") {
if (!flowInfoData.value.isLog) { if (!flowInfoData.value.isLog) {
flowStore.updateDisableForm(false); await completeTrialRun(currentInstId, mainEnd, first);
flowState.value = "testRunFinish";
totalRunningTime.value = mainEnd.endTime - first.startTime;
} }
} else if (["STOPPED", "PAUSED"].includes(lastStatus)) { } else if (["STOPPED", "PAUSED"].includes(lastStatus)) {
if (!flowInfoData.value.isLog) { if (!flowInfoData.value.isLog) {

View File

@ -214,11 +214,20 @@ const removeAnchor = (anchorId) => syncAnchors(branchAnchors.value.filter((ancho
*/ */
const changeAnchor = (height, anchorId) => syncAnchors(branchAnchors.value.map((anchor) => anchor.id === anchorId ? { ...anchor, height } : anchor)); const changeAnchor = (height, anchorId) => syncAnchors(branchAnchors.value.map((anchor) => anchor.id === anchorId ? { ...anchor, height } : anchor));
/** /**
* 同步与 branch anchors 相关的状态或数据,该影响范围仅限当前组件。 * 同步分支节点的锚点位置。
*
* 实现思路:编辑状态下把测量结果写回节点属性,保证保存和重载后的连线位置一致;
* 试运行期间节点状态变化也会触发 ResizeObserver,但这不是流程定义修改,因此只刷新
* Vue Flow 内部布局,不持久化锚点,避免延迟回调取消“试运行成功”状态。
*
* @param {*} positions 分支锚点位置集合 * @param {*} positions 分支锚点位置集合
*/ */
const syncBranchAnchors = (positions = []) => { const syncBranchAnchors = (positions = []) => {
if (!positions.length) return; if (!positions.length) return;
if (flowStore.disableForm) {
vueFlow.updateNodeInternals([props.id]);
return;
}
const positionMap = new Map(positions.map((item) => [item.id, Number(item.height || 0)])); const positionMap = new Map(positions.map((item) => [item.id, Number(item.height || 0)]));
const current = [...(properties.value.anchor || [])]; const current = [...(properties.value.anchor || [])];
let changed = false; let changed = false;
@ -238,11 +247,14 @@ const syncBranchAnchors = (positions = []) => {
else vueFlow.updateNodeInternals([props.id]); else vueFlow.updateNodeInternals([props.id]);
}; };
/** /**
* 处理与 content changed 相关的状态或数据,该影响范围仅限当前组件。 * 响应节点内容变化并刷新节点尺寸。
*
* 实现思路:用户编辑时记录历史和草稿脏状态;试运行期间的状态图标、耗时和输出结果
* 只是临时展示数据,不应写入编辑历史,否则异步布局事件会错误撤销发布资格。
*/ */
const contentChanged = () => { const contentChanged = () => {
vueFlow.updateNodeInternals([props.id]); vueFlow.updateNodeInternals([props.id]);
window.lf?.markChanged(); if (!flowStore.disableForm) window.lf?.markChanged();
}; };
/** /**
* 绑定与 component 相关的状态或数据,该影响范围仅限当前组件。 * 绑定与 component 相关的状态或数据,该影响范围仅限当前组件。