@@ -118,12 +123,14 @@
import { computed, ref, reactive, watch, nextTick } from 'vue'
import { Plus, Minus } from '@element-plus/icons-vue'
import FormItemRecursive from '../FormItemRecursive.vue'
+import RobotExecutionTarget from './RobotExecutionTarget.vue'
import { getInput } from '@/utils/flow'
import { useQuote } from './useQuote.js'
import { getArmStatus, getArmJointState, getAgvStatus, getAgvStations } from '@/api/flow/flow'
import { getRobotList, getRobotDevicesByRobotId } from '@/api/inspection/robot'
import { ElMessage } from 'element-plus'
import { getDeviceKindForAction, toDeviceOptions } from '@/utils/robotDevice'
+import { actionRequiresDevice } from '@/utils/flowResources'
const props = defineProps({
data: Object
@@ -133,7 +140,8 @@ const emit = defineEmits(['save-success', 'save-error'])
const formData = reactive({
nodeParams: [],
- outputParams: []
+ outputParams: [],
+ executionTarget: {}
})
const rules = reactive({})
@@ -197,6 +205,7 @@ const initData = () => {
const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || []))
formData.nodeParams = nodeParams;
formData.outputParams = outputParams;
+ formData.executionTarget = JSON.parse(JSON.stringify(props.data.properties.executionTarget || {}));
}
watch(
@@ -220,6 +229,13 @@ const validateAndSave = async () => {
if (outputFormRef.value) {
await outputFormRef.value.validate((valid) => { if (!valid) outputValid = false })
}
+ if (isRobotNode.value && !formData.executionTarget.roleKey) inputValid = false
+ if (isRobotNode.value
+ && actionRequiresDevice(props.data.properties.action)
+ && !formData.executionTarget.deviceSlotKey) {
+ inputValid = false
+ ElMessage.warning('请选择该节点使用的设备用途')
+ }
// 保存到 lf
lf.setProperties(props.data.id, {
@@ -290,10 +306,9 @@ const testRule = (property) => {
return [
{ required: true, message: '请从站点列表中选择站点', trigger: 'change' },
{ validator: () => {
- const deviceId = formData.nodeParams.find(param => param.name === 'deviceId')?.input
const selectedFromList = property.selectOptions?.some(option => option.value === property.input)
- if (selectedFromList && property.stationDeviceId === deviceId) return Promise.resolve()
- return Promise.reject(new Error('设备已变化,请重新加载站点列表'))
+ if (selectedFromList) return Promise.resolve()
+ return Promise.reject(new Error('请重新加载并选择站点'))
}, trigger: 'change' }
]
}
@@ -331,10 +346,11 @@ const testRule = (property) => {
const robotFormAction = ref()
const stationListLoading = ref(false)
const POSITION_ACTIONS = ['AGV_MOVE_TO_POINT', 'ARM_MOVE_TO_POINT', 'ARM_MOVE_TO_J']
-const hasBindableDevice = computed(() =>
- formData.nodeParams.some(param => param.name === 'deviceId')
- && Boolean(getDeviceKindForAction(props.data.properties.action))
-)
+const isRobotNode = computed(() => props.data.properties?.nodeType === 'EDGE')
+const hasDeviceDebugAction = computed(() => (
+ POSITION_ACTIONS.includes(props.data.properties.action)
+ || props.data.properties.action === 'AGV_MOVE_TO_STATION'
+))
const robotActionButtonText = computed(() => {
if (props.data.properties.action === 'AGV_MOVE_TO_STATION') return '选择机器人并加载站点'
if (POSITION_ACTIONS.includes(props.data.properties.action)) return '选择机器人并获取位置'
@@ -361,8 +377,7 @@ const submitRobotForm = () => {
const testMap = {
x: x,
y: y,
- theta: theta,
- deviceId: robotForm.deviceId
+ theta: theta
}
// 将获取到的位置信息设置到 formData 中
formData.nodeParams.forEach(param => {
@@ -390,15 +405,12 @@ const submitRobotForm = () => {
throw new Error('AGV未返回可用站点')
}
const stationParam = formData.nodeParams.find(param => param.name === 'stationId')
- const deviceParam = formData.nodeParams.find(param => param.name === 'deviceId')
if (stationParam) {
stationParam.selectOptions = stationOptions
- stationParam.stationDeviceId = robotForm.deviceId
if (!stationOptions.some(item => item.value === stationParam.input)) {
stationParam.input = ''
}
}
- if (deviceParam) deviceParam.input = robotForm.deviceId
dialogVisible.value = false
ElMessage.success(`已加载${stationOptions.length}个AGV站点`)
} catch (error) {
@@ -424,7 +436,6 @@ const submitRobotForm = () => {
rx: rx,
ry: ry,
rz: rz,
- deviceId: robotForm.deviceId
}
// 将获取到的位置信息设置到 formData 中
formData.nodeParams.forEach(param => {
@@ -453,28 +464,13 @@ const submitRobotForm = () => {
}
dialogVisible.value = false
const targetParam = formData.nodeParams.find(param => param.name === 'target')
- const deviceParam = formData.nodeParams.find(param => param.name === 'deviceId')
if (targetParam) targetParam.input = JSON.stringify(target)
- if (deviceParam) deviceParam.input = robotForm.deviceId
}
} catch (error) {
console.error('获取机械臂关节位置失败:', error)
}
}
})
- } else {
- robotFormRef.value.validate((valid) => {
- if (!valid) return
- const deviceParam = formData.nodeParams.find(param => param.name === 'deviceId')
- if (deviceParam) {
- deviceParam.input = robotForm.deviceId
- deviceParam.componentType = 'select'
- deviceParam.selectOptions = [...deviceOptions.value]
- deviceParam.deviceLocked = deviceOptions.value.length === 1
- }
- dialogVisible.value = false
- ElMessage.success('机器人设备已匹配')
- })
}
}
@@ -500,8 +496,7 @@ const toStationOptions = (stations) => (Array.isArray(stations) ? stations : [])
const openRobotForm = async (action) => {
dialogVisible.value = true
robotFormAction.value = action
- const currentDeviceId = formData.nodeParams.find(param => param.name === 'deviceId')?.input || ''
- robotForm.deviceId = currentDeviceId
+ robotForm.deviceId = ''
await loadRobotOptions()
if (robotForm.robotId) await loadRobotDevices(robotForm.robotId)
}
diff --git a/src/views/flow/components/params/Device_universal.vue b/src/views/flow/components/params/Device_universal.vue
index 70fe46b..6995dc3 100644
--- a/src/views/flow/components/params/Device_universal.vue
+++ b/src/views/flow/components/params/Device_universal.vue
@@ -3,6 +3,7 @@
* 作用范围:仅服务于流程设计器模块。
-->
+
@@ -20,15 +21,6 @@
@@ -111,6 +112,18 @@ const vueFlow = useVueFlow("main-flow");
const componentRef = ref();
const flowType = computed(() => props.data.flowType);
const properties = computed(() => props.data.properties || {});
+const executionLabel = computed(() => {
+ const roleKey = properties.value.executionTarget?.roleKey;
+ if (!roleKey) return "";
+ const graph = window.lf?.getGraphData?.();
+ const start = graph?.nodes?.find((node) => node.type === "start");
+ const role = start?.properties?.resourceRoles?.find((item) => item.roleKey === roleKey);
+ if (!role) return "未配置机器人角色";
+ const slotKey = properties.value.executionTarget?.deviceSlotKey
+ || properties.value.executionTarget?.deviceBindings?.[0]?.slotKey;
+ const slot = role.deviceSlots?.find((item) => item.slotKey === slotKey);
+ return slot ? `${role.displayName} · ${slot.displayName}` : role.displayName;
+});
const nodeComponent = computed(() => componentMap[flowType.value] || ServiceNode);
const isGroup = computed(() => ["loop", "selectArea"].includes(flowType.value));
const childNodeCount = computed(() => (
@@ -285,6 +298,16 @@ onMounted(() => bindComponent(componentRef.value));
box-sizing: border-box;
}
+.flow-node-executor {
+ overflow: hidden;
+ margin-top: 8px;
+ color: #667085;
+ font-size: 11px;
+ line-height: 16px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
.flow-node-card {
width: 100%;
height: auto;
diff --git a/src/views/inspection/runTask/index.vue b/src/views/inspection/runTask/index.vue
index 7da4001..55f7ece 100644
--- a/src/views/inspection/runTask/index.vue
+++ b/src/views/inspection/runTask/index.vue
@@ -143,6 +143,14 @@
+
+
+
+
+ 取消
+ 开始执行
+
+
+
+
diff --git a/src/views/test/configs/Run.vue b/src/views/test/configs/Run.vue
index d97366f..798ff2d 100644
--- a/src/views/test/configs/Run.vue
+++ b/src/views/test/configs/Run.vue
@@ -7,16 +7,9 @@
:rules="rules"
label-width="auto"
>
-