huang
2025-11-26 792236ef78c2cdd3a989fb40a7f2e2487c4e17b6
mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
@@ -5,7 +5,7 @@
        <h3>多设备测试编排</h3>
        <p v-if="group">当前设备组:{{ group.groupName }}({{ group.deviceCount || '-' }} 台设备)</p>
        <p v-else class="warning">请先在左侧选择一个设备组</p>
        <p v-if="group && loadDeviceName" class="sub-info">上大车设备:{{ loadDeviceName }}</p>
        <p v-if="group && loadDeviceName" class="sub-info">当前设备:{{ loadDeviceName }}</p>
      </div>
      <div class="action-buttons">
        <el-button
@@ -25,23 +25,54 @@
      </div>
    </div>
    <el-form :model="form" label-width="120px">
      <el-form-item label="玻璃ID列表">
    <el-form :model="form" label-width="120px" :rules="rules" ref="formRef">
      <el-form-item label="玻璃ID列表" prop="glassIds" required>
        <el-input
          v-model="glassIdsInput"
          type="textarea"
          :rows="4"
          placeholder="请输入玻璃条码,支持多行或逗号分隔"
          placeholder="请输入玻璃条码,支持多行或逗号分隔,每行一个或逗号分隔"
          show-word-limit
          :maxlength="5000"
        />
        <div class="form-tip">
          已输入 {{ glassIds.length }} 个玻璃ID
        </div>
      </el-form-item>
      <el-form-item label="位置编码">
        <el-input v-model="form.positionCode" placeholder="例如:POS1" />
      </el-form-item>
      <el-form-item label="存储位置">
        <el-input-number v-model="form.storagePosition" :min="1" :max="200" />
      </el-form-item>
      <el-divider content-position="left">执行配置</el-divider>
      <el-form-item label="执行间隔 (ms)">
        <el-input-number v-model="form.executionInterval" :min="100" :max="10000" />
        <el-input-number
          v-model="form.executionInterval"
          :min="100"
          :max="10000"
          :step="100"
          placeholder="设备操作间隔时间"
        />
        <div class="form-tip">每个设备操作之间的间隔时间(毫秒)</div>
      </el-form-item>
      <el-form-item label="超时时间 (分钟)">
        <el-input-number
          v-model="form.timeoutMinutes"
          :min="1"
          :max="60"
          :step="1"
          placeholder="任务超时时间"
        />
        <div class="form-tip">任务执行的最大超时时间</div>
      </el-form-item>
      <el-form-item label="重试次数">
        <el-input-number
          v-model="form.retryCount"
          :min="0"
          :max="10"
          :step="1"
          placeholder="失败重试次数"
        />
        <div class="form-tip">设备操作失败时的最大重试次数</div>
      </el-form-item>
    </el-form>
  </div>
@@ -64,10 +95,38 @@
const emit = defineEmits(['task-started'])
const form = reactive({
  positionCode: '',
  storagePosition: null,
  executionInterval: 1000
  executionInterval: 1000,
  timeoutMinutes: 30,
  retryCount: 3
})
const formRef = ref(null)
const rules = {
  glassIds: [
    {
      validator: (rule, value, callback) => {
        if (glassIds.value.length === 0) {
          callback(new Error('请至少输入一个玻璃ID'))
        } else if (glassIds.value.length > 100) {
          callback(new Error('玻璃ID数量不能超过100个'))
        } else {
          // 验证玻璃ID格式
          const invalidIds = glassIds.value.filter(id => {
            // 简单的格式验证:不能为空,长度在1-50之间
            return !id || id.length === 0 || id.length > 50
          })
          if (invalidIds.length > 0) {
            callback(new Error(`存在无效的玻璃ID格式,请检查`))
          } else {
            callback()
          }
        }
      },
      trigger: 'blur'
    }
  ]
}
const glassIdsInput = ref('')
const loading = ref(false)
@@ -133,23 +192,62 @@
    ElMessage.warning('请先选择设备组')
    return
  }
  // 表单验证
  if (!formRef.value) return
  try {
    await formRef.value.validate()
  } catch (error) {
    ElMessage.warning('请检查表单输入')
    return
  }
  if (glassIds.value.length === 0) {
    ElMessage.warning('请至少输入一个玻璃ID')
    return
  }
  try {
    loading.value = true
    await multiDeviceTaskApi.startTask({
    // 构建任务参数
    const parameters = {
      glassIds: glassIds.value,
      executionInterval: form.executionInterval || 1000
    }
    // 设备特定配置已移除,如有需要可在此扩展
    if (form.timeoutMinutes) {
      parameters.timeoutMinutes = form.timeoutMinutes
    }
    if (form.retryCount !== null) {
      parameters.retryCount = form.retryCount
    }
    // 异步启动任务,立即返回,不阻塞
    const response = await multiDeviceTaskApi.startTask({
      groupId: props.group.id || props.group.groupId,
      parameters: {
        glassIds: glassIds.value,
        positionCode: form.positionCode || null,
        storagePosition: form.storagePosition,
        executionInterval: form.executionInterval
      }
      parameters
    })
    ElMessage.success('任务已启动')
    emit('task-started')
    const task = response?.data
    if (task && task.taskId) {
      ElMessage.success(`任务已启动(异步执行): ${task.taskId}`)
      emit('task-started', task)
      // 立即刷新监控列表,显示新启动的任务
      setTimeout(() => {
        emit('task-started')
      }, 500)
      // 重置表单(保留执行配置),方便继续启动其他设备组
      glassIdsInput.value = ''
      // 提示用户可以继续启动其他设备组
      ElMessage.info('可以继续选择其他设备组启动测试,多个设备组将并行执行')
    } else {
      ElMessage.warning('任务启动响应异常')
    }
  } catch (error) {
    ElMessage.error(error?.message || '任务启动失败')
  } finally {
@@ -171,9 +269,7 @@
    const response = await deviceInteractionApi.executeOperation({
      deviceId: loadDeviceId.value,
      operation: 'clearGlass',
      params: {
        positionCode: form.positionCode || null
      }
      params: {}
    })
    if (response?.code !== 200) {
      throw new Error(response?.message || 'PLC清空失败')
@@ -234,5 +330,12 @@
  gap: 12px;
  align-items: center;
}
.form-tip {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
  line-height: 1.4;
}
</style>