huang
7 天以前 22e17b6db03ca58bc477a35ca067e55a09cffce7
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,27 +32,16 @@
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="玻璃间隔(ms)">
        <el-form-item label="玻璃间隙(mm)">
          <el-input-number
            v-model="config.glassIntervalMs"
            :min="100"
            :max="10000"
            :step="100"
            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>
@@ -64,6 +55,7 @@
            :max="1000"
            :step="1"
            style="width: 100%;"
            @change="emitConfigUpdate"
          />
          <span class="form-tip">车辆初始位置(格子)</span>
        </el-form-item>
@@ -75,8 +67,9 @@
            :min="1"
            :max="1000"
            :step="1"
            style="width: 48%;"
            style="width: 40%;"
            placeholder="最小"
            @change="emitConfigUpdate"
          />
          <span style="margin: 0 2%;">~</span>
          <el-input-number
@@ -84,8 +77,9 @@
            :min="1"
            :max="1000"
            :step="1"
            style="width: 48%;"
            style="width: 40%;"
            placeholder="最大"
            @change="emitConfigUpdate"
          />
          <span class="form-tip">运动距离范围(格子)</span>
        </el-form-item>
@@ -94,62 +88,50 @@
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="空闲监控间隔(ms)">
        <el-form-item label="空闲监控间隔(秒)">
          <el-input-number
            v-model="config.idleMonitorIntervalMs"
            :min="500"
            :max="10000"
            :step="100"
            v-model="idleMonitorIntervalSeconds"
            :min="0.5"
            :max="10"
            :step="0.1"
            :precision="1"
            style="width: 100%;"
          />
          <span class="form-tip">空闲状态监控间隔,默认2000ms</span>
          <span class="form-tip">空闲状态监控间隔,默认2秒</span>
        </el-form-item>
      </el-col>
      <el-col :span="12">
        <el-form-item label="任务监控间隔(ms)">
        <el-form-item label="任务监控间隔(秒)">
          <el-input-number
            v-model="config.taskMonitorIntervalMs"
            :min="500"
            :max="10000"
            :step="100"
            v-model="taskMonitorIntervalSeconds"
            :min="0.5"
            :max="10"
            :step="0.1"
            :precision="1"
            style="width: 100%;"
          />
          <span class="form-tip">任务执行监控间隔,默认1000ms</span>
          <span class="form-tip">任务执行监控间隔,默认1秒</span>
        </el-form-item>
      </el-col>
    </el-row>
    <el-row :gutter="20">
      <el-col :span="12">
        <el-form-item label="MES确认超时(ms)">
        <el-form-item label="MES确认超时(秒)">
          <el-input-number
            v-model="config.mesConfirmTimeoutMs"
            :min="5000"
            :max="300000"
            :step="1000"
            v-model="mesConfirmTimeoutSeconds"
            :min="5"
            :max="300"
            :step="1"
            style="width: 100%;"
          />
          <span class="form-tip">等待MES确认的超时时间,默认30000ms</span>
          <span class="form-tip">等待MES确认的超时时间,默认30秒</span>
        </el-form-item>
      </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>
@@ -157,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>
@@ -190,27 +173,6 @@
        </el-button>
      </div>
      <span class="form-tip">将MES编号(如900/901)映射为实际位置值(格子)</span>
    </el-form-item>
    <el-form-item label="出片任务格子范围">
      <el-input-number
        v-model="config.outboundSlotRanges[0]"
        :min="1"
        :max="1000"
        :step="1"
        style="width: 48%;"
        placeholder="最小格子编号"
      />
      <span style="margin: 0 2%;">~</span>
      <el-input-number
        v-model="config.outboundSlotRanges[1]"
        :min="1"
        :max="1000"
        :step="1"
        style="width: 48%;"
        placeholder="最大格子编号"
      />
      <span class="form-tip">出片任务的startSlot范围,例如[1, 101]表示格子1~101都是出片任务</span>
    </el-form-item>
  </div>
</template>
@@ -231,8 +193,7 @@
const config = ref({
  vehicleCapacity: 6000,
  vehicleSpeed: 1.0,
  glassIntervalMs: 1000,
  defaultGlassLength: 2000,
  glassGap: 200,
  homePosition: 0,
  minRange: 1,
  maxRange: 100,
@@ -240,22 +201,57 @@
  taskMonitorIntervalMs: 1000,
  mesConfirmTimeoutMs: 30000,
  autoFeed: true,
  maxRetryCount: 5,
  positionMapping: {},
  outboundSlotRanges: [1, 101]
  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 idleMonitorIntervalSeconds = ref(2.0)
const taskMonitorIntervalSeconds = ref(1.0)
const mesConfirmTimeoutSeconds = ref(30)
// 监听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,
@@ -263,40 +259,55 @@
      taskMonitorIntervalMs: newVal.taskMonitorIntervalMs ?? 1000,
      mesConfirmTimeoutMs: newVal.mesConfirmTimeoutMs ?? 30000,
      autoFeed: newVal.autoFeed ?? true,
      maxRetryCount: newVal.maxRetryCount ?? 5,
      positionMapping: newVal.positionMapping || {},
      outboundSlotRanges: newVal.outboundSlotRanges || [1, 101]
      positionMapping: newVal.positionMapping || {}
    }
    mappingKeys.value = Object.keys(config.value.positionMapping)
    // 将毫秒转换为秒用于显示
    idleMonitorIntervalSeconds.value = (config.value.idleMonitorIntervalMs ?? 2000) / 1000
    taskMonitorIntervalSeconds.value = (config.value.taskMonitorIntervalMs ?? 1000) / 1000
    mesConfirmTimeoutSeconds.value = (config.value.mesConfirmTimeoutMs ?? 30000) / 1000
    syncPositionListFromConfig()
    suppressEmit = false
  }
}, { immediate: true, deep: true })
// 监听config变化,同步到父组件
watch(config, (newVal) => {
  emit('update:modelValue', { ...newVal })
}, { deep: true })
// 监听秒字段变化,转换为毫秒并更新config
watch(idleMonitorIntervalSeconds, (val) => {
  config.value.idleMonitorIntervalMs = Math.round(val * 1000)
  emitConfigUpdate()
})
watch(taskMonitorIntervalSeconds, (val) => {
  config.value.taskMonitorIntervalMs = Math.round(val * 1000)
  emitConfigUpdate()
})
watch(mesConfirmTimeoutSeconds, (val) => {
  config.value.mesConfirmTimeoutMs = Math.round(val * 1000)
  emitConfigUpdate()
})
// 监听config其他字段变化,同步到父组件
// 位置映射相关方法
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>