huang
5 天以前 0dfdc8148cc266fd3e877183c5b162fb986d5c65
mes-web/src/views/device/components/DeviceLogicConfig/LoadVehicleConfig.vue
@@ -9,6 +9,7 @@
            :max="10000"
            :step="100"
            style="width: 100%;"
            @change="emitConfigUpdate"
          />
          <span class="form-tip">车辆最大容量</span>
        </el-form-item>
@@ -22,6 +23,7 @@
            :step="0.1"
            :precision="1"
            style="width: 100%;"
            @change="emitConfigUpdate"
          />
          <span class="form-tip">车辆运动速度,默认1格/秒</span>
        </el-form-item>
@@ -30,28 +32,16 @@
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="玻璃间隔(秒)">
        <el-form-item label="玻璃间隙(mm)">
          <el-input-number
            v-model="glassIntervalSeconds"
            :min="0.1"
            :max="10"
            :step="0.1"
            :precision="1"
            v-model="config.glassGap"
            :min="0"
            :max="1000"
            :step="10"
            style="width: 100%;"
            @change="emitConfigUpdate"
          />
          <span class="form-tip">玻璃上料间隔时间(秒)</span>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="默认玻璃长度(mm)">
          <el-input-number
            v-model="config.defaultGlassLength"
            :min="100"
            :max="10000"
            :step="100"
            style="width: 100%;"
          />
          <span class="form-tip">当玻璃未提供长度时使用的默认值</span>
          <span class="form-tip">多块玻璃之间的物理间隔空隙,默认200mm</span>
        </el-form-item>
      </el-col>
    </el-row>
@@ -65,6 +55,7 @@
            :max="1000"
            :step="1"
            style="width: 100%;"
            @change="emitConfigUpdate"
          />
          <span class="form-tip">车辆初始位置(格子)</span>
        </el-form-item>
@@ -78,6 +69,7 @@
            :step="1"
            style="width: 40%;"
            placeholder="最小"
            @change="emitConfigUpdate"
          />
          <span style="margin: 0 2%;">~</span>
          <el-input-number
@@ -87,6 +79,7 @@
            :step="1"
            style="width: 40%;"
            placeholder="最大"
            @change="emitConfigUpdate"
          />
          <span class="form-tip">运动距离范围(格子)</span>
        </el-form-item>
@@ -137,22 +130,8 @@
      </el-col>
      <el-col :span="12">
        <el-form-item label="自动上料">
          <el-switch v-model="config.autoFeed" />
          <el-switch v-model="config.autoFeed" @change="emitConfigUpdate" />
          <span class="form-tip">是否自动触发上料请求</span>
        </el-form-item>
      </el-col>
    </el-row>
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="最大重试次数">
          <el-input-number
            v-model="config.maxRetryCount"
            :min="0"
            :max="10"
            :step="1"
            style="width: 100%;"
          />
        </el-form-item>
      </el-col>
    </el-row>
@@ -160,30 +139,31 @@
    <el-form-item label="位置映射">
      <div class="position-mapping">
        <div
          v-for="(value, key, index) in config.positionMapping"
          :key="index"
          v-for="(item, index) in positionList"
          :key="item.id"
          class="mapping-item"
        >
          <el-input
            v-model="mappingKeys[index]"
            placeholder="位置代码(如900/901)"
            v-model="item.key"
            placeholder="位置代码(如1001/1002)"
            size="small"
            style="width: 150px; margin-right: 10px;"
            @input="updatePositionMapping(index, $event, value)"
            @change="handlePositionKeyChange(index)"
          />
          <el-input-number
            v-model="config.positionMapping[mappingKeys[index] || key]"
            v-model="item.value"
            :min="0"
            :max="1000"
            :step="1"
            size="small"
            style="width: 120px; margin-right: 10px;"
            placeholder="位置值(格)"
            @change="handlePositionValueChange(index)"
          />
          <el-button
            type="danger"
            size="small"
            @click="removePositionMapping(key)"
            @click="removePositionMapping(index)"
          >
            删除
          </el-button>
@@ -213,8 +193,7 @@
const config = ref({
  vehicleCapacity: 6000,
  vehicleSpeed: 1.0,
  glassIntervalMs: 1000,
  defaultGlassLength: 2000,
  glassGap: 200,
  homePosition: 0,
  minRange: 1,
  maxRange: 100,
@@ -222,15 +201,45 @@
  taskMonitorIntervalMs: 1000,
  mesConfirmTimeoutMs: 30000,
  autoFeed: true,
  maxRetryCount: 5,
  positionMapping: {}
})
// 位置映射的键数组
const mappingKeys = ref([])
// 位置映射编辑列表
const positionList = ref([])
let suppressPositionSync = false
let suppressEmit = false
const emitConfigUpdate = () => {
  if (suppressEmit) return
  emit('update:modelValue', { ...config.value })
}
const syncPositionListFromConfig = () => {
  suppressPositionSync = true
  const entries = Object.entries(config.value.positionMapping || {})
  positionList.value = entries.map(([key, value], idx) => ({
    id: `${key}_${idx}_${Date.now()}`,
    key,
    value: value ?? 1
  }))
  suppressPositionSync = false
}
const applyPositionListToConfig = () => {
  if (suppressPositionSync) return
  const mapping = {}
  positionList.value.forEach((item) => {
    if (item.key && item.key.trim()) {
      mapping[item.key.trim()] = item.value ?? 1
    }
  })
  config.value.positionMapping = mapping
  emitConfigUpdate()
}
syncPositionListFromConfig()
// 时间字段(秒)- 用于前端显示和输入
const glassIntervalSeconds = ref(1.0)
const idleMonitorIntervalSeconds = ref(2.0)
const taskMonitorIntervalSeconds = ref(1.0)
const mesConfirmTimeoutSeconds = ref(30)
@@ -238,11 +247,11 @@
// 监听props变化
watch(() => props.modelValue, (newVal) => {
  if (newVal && Object.keys(newVal).length > 0) {
    suppressEmit = true
    config.value = {
      vehicleCapacity: newVal.vehicleCapacity ?? 6000,
      vehicleSpeed: newVal.vehicleSpeed ?? 1.0,
      glassIntervalMs: newVal.glassIntervalMs ?? 1000,
      defaultGlassLength: newVal.defaultGlassLength ?? 2000,
      glassGap: newVal.glassGap ?? 200,
      homePosition: newVal.homePosition ?? 0,
      minRange: newVal.minRange ?? 1,
      maxRange: newVal.maxRange ?? 100,
@@ -250,75 +259,55 @@
      taskMonitorIntervalMs: newVal.taskMonitorIntervalMs ?? 1000,
      mesConfirmTimeoutMs: newVal.mesConfirmTimeoutMs ?? 30000,
      autoFeed: newVal.autoFeed ?? true,
      maxRetryCount: newVal.maxRetryCount ?? 5,
      positionMapping: newVal.positionMapping || {}
    }
    // 将毫秒转换为秒用于显示
    glassIntervalSeconds.value = (config.value.glassIntervalMs ?? 1000) / 1000
    idleMonitorIntervalSeconds.value = (config.value.idleMonitorIntervalMs ?? 2000) / 1000
    taskMonitorIntervalSeconds.value = (config.value.taskMonitorIntervalMs ?? 1000) / 1000
    mesConfirmTimeoutSeconds.value = (config.value.mesConfirmTimeoutMs ?? 30000) / 1000
    mappingKeys.value = Object.keys(config.value.positionMapping)
    syncPositionListFromConfig()
    suppressEmit = false
  }
}, { immediate: true, deep: true })
// 监听秒字段变化,转换为毫秒并更新config
watch(glassIntervalSeconds, (val) => {
  config.value.glassIntervalMs = Math.round(val * 1000)
  emit('update:modelValue', { ...config.value })
})
watch(idleMonitorIntervalSeconds, (val) => {
  config.value.idleMonitorIntervalMs = Math.round(val * 1000)
  emit('update:modelValue', { ...config.value })
  emitConfigUpdate()
})
watch(taskMonitorIntervalSeconds, (val) => {
  config.value.taskMonitorIntervalMs = Math.round(val * 1000)
  emit('update:modelValue', { ...config.value })
  emitConfigUpdate()
})
watch(mesConfirmTimeoutSeconds, (val) => {
  config.value.mesConfirmTimeoutMs = Math.round(val * 1000)
  emit('update:modelValue', { ...config.value })
  emitConfigUpdate()
})
// 监听config其他字段变化,同步到父组件
watch(() => [
  config.value.vehicleCapacity,
  config.value.vehicleSpeed,
  config.value.defaultGlassLength,
  config.value.homePosition,
  config.value.minRange,
  config.value.maxRange,
  config.value.autoFeed,
  config.value.maxRetryCount,
  config.value.positionMapping
], () => {
  emit('update:modelValue', { ...config.value })
}, { deep: true })
// 位置映射相关方法
const addPositionMapping = () => {
  const newKey = `POS${Object.keys(config.value.positionMapping).length + 1}`
  config.value.positionMapping[newKey] = 1
  mappingKeys.value.push(newKey)
  const nextIndex = positionList.value.length + 1
  positionList.value.push({
    id: `POS_${Date.now()}_${nextIndex}`,
    key: '',
    value: 1
  })
}
const removePositionMapping = (key) => {
  delete config.value.positionMapping[key]
  mappingKeys.value = mappingKeys.value.filter(k => k !== key)
const removePositionMapping = (idx) => {
  positionList.value.splice(idx, 1)
  applyPositionListToConfig()
}
const updatePositionMapping = (index, newKey, oldValue) => {
  const oldKey = mappingKeys.value[index]
  if (oldKey && oldKey !== newKey) {
    delete config.value.positionMapping[oldKey]
  }
  mappingKeys.value[index] = newKey
  if (newKey) {
    config.value.positionMapping[newKey] = oldValue || 1
  }
const handlePositionKeyChange = () => {
  applyPositionListToConfig()
}
const handlePositionValueChange = () => {
  applyPositionListToConfig()
}
</script>