| | |
| | | :max="10000" |
| | | :step="100" |
| | | style="width: 100%;" |
| | | @change="emitConfigUpdate" |
| | | /> |
| | | <span class="form-tip">车辆最大容量</span> |
| | | </el-form-item> |
| | |
| | | :step="0.1" |
| | | :precision="1" |
| | | style="width: 100%;" |
| | | @change="emitConfigUpdate" |
| | | /> |
| | | <span class="form-tip">车辆运动速度,默认1格/秒</span> |
| | | </el-form-item> |
| | |
| | | :max="10000" |
| | | :step="100" |
| | | style="width: 100%;" |
| | | @change="emitConfigUpdate" |
| | | /> |
| | | <span class="form-tip">当玻璃未提供长度时使用的默认值</span> |
| | | </el-form-item> |
| | |
| | | :max="1000" |
| | | :step="1" |
| | | style="width: 100%;" |
| | | @change="emitConfigUpdate" |
| | | /> |
| | | <span class="form-tip">车辆初始位置(格子)</span> |
| | | </el-form-item> |
| | |
| | | :step="1" |
| | | style="width: 40%;" |
| | | placeholder="最小" |
| | | @change="emitConfigUpdate" |
| | | /> |
| | | <span style="margin: 0 2%;">~</span> |
| | | <el-input-number |
| | |
| | | :step="1" |
| | | style="width: 40%;" |
| | | placeholder="最大" |
| | | @change="emitConfigUpdate" |
| | | /> |
| | | <span class="form-tip">运动距离范围(格子)</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> |
| | |
| | | :max="10" |
| | | :step="1" |
| | | style="width: 100%;" |
| | | @change="emitConfigUpdate" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <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]" |
| | | v-model="item.key" |
| | | placeholder="位置代码(如900/901)" |
| | | 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> |
| | |
| | | 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) |
| | |
| | | // 监听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, |
| | |
| | | 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 }) |
| | | emitConfigUpdate() |
| | | }) |
| | | |
| | | 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> |
| | | |