feat(flow): 添加单节点执行机器人选择记忆功能
- 引入 watch 监听器和相关变量用于缓存单节点机器人选择 - 实现按节点ID缓存机器人选择,新节点默认沿用最近一次选择 - 在单节点执行前后记录当前机器人选择到缓存中 - 修改NodeTitle组件传递节点ID用于按节点恢复机器人选择 - 添加试运行参数缓存功能,支持按流程缓存整套参数 - 实现参数层级缓存值恢复,兼容参数结构变化 - 优化试运行关闭和确认时的数据缓存处理逻辑
This commit is contained in:
parent
e6d379f571
commit
8e2afcbaa6
@ -159,7 +159,8 @@ const execute = () => {
|
|||||||
document.dispatchEvent(new CustomEvent("singleNodeExecution", {
|
document.dispatchEvent(new CustomEvent("singleNodeExecution", {
|
||||||
bubbles: false,
|
bubbles: false,
|
||||||
cancelable: false,
|
cancelable: false,
|
||||||
detail: { ...props.nodeProperties },
|
// 携带节点 ID,供单节点执行弹窗按节点恢复上次选择的机器人。
|
||||||
|
detail: { ...props.nodeProperties, nodeId: props.nodeId },
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -90,14 +90,42 @@ const props = defineProps({
|
|||||||
const ruleFormRef = ref()
|
const ruleFormRef = ref()
|
||||||
const rules = ref({});
|
const rules = ref({});
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
// 按流程缓存整套试运行参数,关闭或执行后再次打开时继续使用。
|
||||||
|
const trialRunCache = new Map()
|
||||||
const bindingLoading = ref(false)
|
const bindingLoading = ref(false)
|
||||||
const emptyBindingSummary = (robotId = '') => ({ robotId, matched: 0, missing: 0, untouched: 0 })
|
const emptyBindingSummary = (robotId = '') => ({ robotId, matched: 0, missing: 0, untouched: 0 })
|
||||||
const bindingSummary = ref(emptyBindingSummary())
|
const bindingSummary = ref(emptyBindingSummary())
|
||||||
|
|
||||||
const emits = defineEmits(['close', 'changeState'])
|
const emits = defineEmits(['close', 'changeState'])
|
||||||
|
|
||||||
|
const cloneData = (data) => JSON.parse(JSON.stringify(data || []))
|
||||||
|
|
||||||
|
// 根据参数层级恢复缓存值,同时兼容流程参数结构发生增删的情况。
|
||||||
|
const mergeCachedValues = (source, cached) => {
|
||||||
|
const cachedByName = new Map((cached || []).map(item => [item.name, item]))
|
||||||
|
return (source || []).map((item, index) => {
|
||||||
|
const cachedAtIndex = cached?.[index]
|
||||||
|
const cachedItem = cachedAtIndex?.name === item.name ? cachedAtIndex : cachedByName.get(item.name)
|
||||||
|
if (!cachedItem) return item
|
||||||
|
const merged = { ...item, value: cachedItem.value }
|
||||||
|
if (Array.isArray(item.children)) {
|
||||||
|
merged.children = mergeCachedValues(item.children, cachedItem.children)
|
||||||
|
}
|
||||||
|
return merged
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheKey = () => props.flowId || '__new_flow__'
|
||||||
|
|
||||||
|
// 深拷贝快照,避免后续表单编辑直接修改缓存内容。
|
||||||
|
const rememberTrialRunParams = () => {
|
||||||
|
if (!tableData.value.length) return
|
||||||
|
trialRunCache.set(cacheKey(), cloneData(tableData.value))
|
||||||
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
ruleFormRef.value?.resetFields()
|
rememberTrialRunParams()
|
||||||
|
ruleFormRef.value?.clearValidate()
|
||||||
emits('close')
|
emits('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,14 +133,17 @@ watch(() => props.drawer,
|
|||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
const data = getStartNodeFormData()
|
const data = getStartNodeFormData()
|
||||||
tableData.value = data
|
const cached = trialRunCache.get(cacheKey())
|
||||||
bindingSummary.value = emptyBindingSummary()
|
tableData.value = mergeCachedValues(data, cached)
|
||||||
|
const robotId = tableData.value.find(item => item.name === 'robotId')?.value || ''
|
||||||
|
bindingSummary.value = emptyBindingSummary(robotId)
|
||||||
loadRobotOptions()
|
loadRobotOptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const confirm = () => {
|
const confirm = () => {
|
||||||
|
rememberTrialRunParams()
|
||||||
lf.fitView()
|
lf.fitView()
|
||||||
ruleFormRef.value.validate().then(async () => {
|
ruleFormRef.value.validate().then(async () => {
|
||||||
const formData = formatTableData(tableData.value)
|
const formData = formatTableData(tableData.value)
|
||||||
|
|||||||
@ -245,7 +245,7 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, reactive, ref, onMounted, onUnmounted, nextTick } from "vue";
|
import { computed, reactive, ref, watch, onMounted, onUnmounted, nextTick } from "vue";
|
||||||
import { MarkerType, VueFlow, useVueFlow } from "@vue-flow/core";
|
import { MarkerType, VueFlow, useVueFlow } from "@vue-flow/core";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import { Background } from "@vue-flow/background";
|
import { Background } from "@vue-flow/background";
|
||||||
@ -899,6 +899,10 @@ const rules = reactive({});
|
|||||||
const executeForm = ref();
|
const executeForm = ref();
|
||||||
const nodeAction = ref("");
|
const nodeAction = ref("");
|
||||||
const singleNodeExecuting = ref(false);
|
const singleNodeExecuting = ref(false);
|
||||||
|
const activeSingleNodeId = ref("");
|
||||||
|
// 单节点机器人选择按节点缓存;新节点默认沿用最近一次选择。
|
||||||
|
const singleNodeRobotCache = new Map();
|
||||||
|
let lastSingleNodeRobotId = "";
|
||||||
const stationLoading = ref(false);
|
const stationLoading = ref(false);
|
||||||
const singleNodeRobotOptions = ref([]);
|
const singleNodeRobotOptions = ref([]);
|
||||||
const flattenSingleNodeParams = (params, parentPath = [], fields = []) => {
|
const flattenSingleNodeParams = (params, parentPath = [], fields = []) => {
|
||||||
@ -945,6 +949,16 @@ const singleNodeRobotId = computed(() =>
|
|||||||
const singleNodeDeviceId = computed(() =>
|
const singleNodeDeviceId = computed(() =>
|
||||||
formData.nodeParams.find((item) => item.name === "deviceId")?.input
|
formData.nodeParams.find((item) => item.name === "deviceId")?.input
|
||||||
);
|
);
|
||||||
|
// 在执行、关闭弹窗或切换节点前记录当前机器人选择。
|
||||||
|
const rememberSingleNodeRobot = () => {
|
||||||
|
if (!activeSingleNodeId.value || !singleNodeRobotId.value) return;
|
||||||
|
lastSingleNodeRobotId = singleNodeRobotId.value;
|
||||||
|
singleNodeRobotCache.set(activeSingleNodeId.value, singleNodeRobotId.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(visible, (value) => {
|
||||||
|
if (!value) rememberSingleNodeRobot();
|
||||||
|
});
|
||||||
|
|
||||||
const handleSingleNodeRobotChange = async (robotId) => {
|
const handleSingleNodeRobotChange = async (robotId) => {
|
||||||
const deviceParam = formData.nodeParams.find((item) => item.name === "deviceId");
|
const deviceParam = formData.nodeParams.find((item) => item.name === "deviceId");
|
||||||
@ -1035,10 +1049,12 @@ const loadSingleNodeRobots = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const singleNodeExecution = async (e) => {
|
const singleNodeExecution = async (e) => {
|
||||||
const { name, nodeType, nodeParams, action } = e.detail;
|
rememberSingleNodeRobot();
|
||||||
|
const { name, nodeType, nodeParams, action, nodeId } = e.detail;
|
||||||
const executionParams = JSON.parse(JSON.stringify(nodeParams || []));
|
const executionParams = JSON.parse(JSON.stringify(nodeParams || []));
|
||||||
const normalizedAction = String(action || "").toUpperCase();
|
const normalizedAction = String(action || "").toUpperCase();
|
||||||
const effectiveNodeType = nodeType || (getDeviceKindForAction(normalizedAction) ? "EDGE" : "");
|
const effectiveNodeType = nodeType || (getDeviceKindForAction(normalizedAction) ? "EDGE" : "");
|
||||||
|
activeSingleNodeId.value = nodeId || `${normalizedAction}:${name || ""}`;
|
||||||
nodeName.value = name;
|
nodeName.value = name;
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
nodeAction.value = normalizedAction;
|
nodeAction.value = normalizedAction;
|
||||||
@ -1057,6 +1073,11 @@ const singleNodeExecution = async (e) => {
|
|||||||
},
|
},
|
||||||
...executionParams,
|
...executionParams,
|
||||||
];
|
];
|
||||||
|
const cachedRobotId = singleNodeRobotCache.get(activeSingleNodeId.value) || lastSingleNodeRobotId;
|
||||||
|
if (cachedRobotId) {
|
||||||
|
formData.nodeParams[0].input = cachedRobotId;
|
||||||
|
await handleSingleNodeRobotChange(cachedRobotId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
formData.nodeParams = executionParams;
|
formData.nodeParams = executionParams;
|
||||||
}
|
}
|
||||||
@ -1081,6 +1102,7 @@ const execute = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!validateSingleNodeParams()) return;
|
if (!validateSingleNodeParams()) return;
|
||||||
|
rememberSingleNodeRobot();
|
||||||
singleNodeExecuting.value = true;
|
singleNodeExecuting.value = true;
|
||||||
try {
|
try {
|
||||||
const res = await flowAction({
|
const res = await flowAction({
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user