<template>
|
<div class="load-vehicle-config">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="车辆容量(mm)">
|
<el-input-number
|
v-model="config.vehicleCapacity"
|
:min="1"
|
:max="10000"
|
:step="100"
|
style="width: 100%;"
|
@change="emitConfigUpdate"
|
/>
|
<span class="form-tip">车辆最大容量</span>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="车辆速度(格/秒)">
|
<el-input-number
|
v-model="config.vehicleSpeed"
|
:min="0.1"
|
:max="10"
|
:step="0.1"
|
:precision="1"
|
style="width: 100%;"
|
@change="emitConfigUpdate"
|
/>
|
<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="玻璃间隙(mm)">
|
<el-input-number
|
v-model="config.glassGap"
|
:min="0"
|
:max="1000"
|
:step="10"
|
style="width: 100%;"
|
@change="emitConfigUpdate"
|
/>
|
<span class="form-tip">多块玻璃之间的物理间隔空隙,默认200mm</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.homePosition"
|
:min="0"
|
:max="1000"
|
:step="1"
|
style="width: 100%;"
|
@change="emitConfigUpdate"
|
/>
|
<span class="form-tip">车辆初始位置(格子)</span>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="运动距离范围">
|
<el-input-number
|
v-model="config.minRange"
|
:min="1"
|
:max="1000"
|
:step="1"
|
style="width: 40%;"
|
placeholder="最小"
|
@change="emitConfigUpdate"
|
/>
|
<span style="margin: 0 2%;">~</span>
|
<el-input-number
|
v-model="config.maxRange"
|
:min="1"
|
:max="1000"
|
:step="1"
|
style="width: 40%;"
|
placeholder="最大"
|
@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="idleMonitorIntervalSeconds"
|
:min="0.5"
|
:max="10"
|
:step="0.1"
|
:precision="1"
|
style="width: 100%;"
|
/>
|
<span class="form-tip">空闲状态监控间隔,默认2秒</span>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="任务监控间隔(秒)">
|
<el-input-number
|
v-model="taskMonitorIntervalSeconds"
|
:min="0.5"
|
:max="10"
|
:step="0.1"
|
:precision="1"
|
style="width: 100%;"
|
/>
|
<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确认超时(秒)">
|
<el-input-number
|
v-model="mesConfirmTimeoutSeconds"
|
:min="5"
|
:max="300"
|
:step="1"
|
style="width: 100%;"
|
/>
|
<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" @change="emitConfigUpdate" />
|
<span class="form-tip">是否自动触发上料请求</span>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-form-item label="位置映射">
|
<div class="position-mapping">
|
<div
|
v-for="(item, index) in positionList"
|
:key="item.id"
|
class="mapping-item"
|
>
|
<el-input
|
v-model="item.key"
|
placeholder="位置代码(如1001/1002)"
|
size="small"
|
style="width: 150px; margin-right: 10px;"
|
@change="handlePositionKeyChange(index)"
|
/>
|
<el-input-number
|
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(index)"
|
>
|
删除
|
</el-button>
|
</div>
|
<el-button type="primary" size="small" @click="addPositionMapping">
|
添加位置映射
|
</el-button>
|
</div>
|
<span class="form-tip">将MES编号(如900/901)映射为实际位置值(格子)</span>
|
</el-form-item>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, watch } from 'vue'
|
|
const props = defineProps({
|
modelValue: {
|
type: Object,
|
default: () => ({})
|
}
|
})
|
|
const emit = defineEmits(['update:modelValue'])
|
|
// 配置数据
|
const config = ref({
|
vehicleCapacity: 6000,
|
vehicleSpeed: 1.0,
|
glassGap: 200,
|
homePosition: 0,
|
minRange: 1,
|
maxRange: 100,
|
idleMonitorIntervalMs: 2000,
|
taskMonitorIntervalMs: 1000,
|
mesConfirmTimeoutMs: 30000,
|
autoFeed: true,
|
positionMapping: {}
|
})
|
|
// 位置映射编辑列表
|
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,
|
glassGap: newVal.glassGap ?? 200,
|
homePosition: newVal.homePosition ?? 0,
|
minRange: newVal.minRange ?? 1,
|
maxRange: newVal.maxRange ?? 100,
|
idleMonitorIntervalMs: newVal.idleMonitorIntervalMs ?? 2000,
|
taskMonitorIntervalMs: newVal.taskMonitorIntervalMs ?? 1000,
|
mesConfirmTimeoutMs: newVal.mesConfirmTimeoutMs ?? 30000,
|
autoFeed: newVal.autoFeed ?? true,
|
positionMapping: newVal.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(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 nextIndex = positionList.value.length + 1
|
positionList.value.push({
|
id: `POS_${Date.now()}_${nextIndex}`,
|
key: '',
|
value: 1
|
})
|
}
|
|
const removePositionMapping = (idx) => {
|
positionList.value.splice(idx, 1)
|
applyPositionListToConfig()
|
}
|
|
const handlePositionKeyChange = () => {
|
applyPositionListToConfig()
|
}
|
|
const handlePositionValueChange = () => {
|
applyPositionListToConfig()
|
}
|
</script>
|
|
<style scoped>
|
.form-tip {
|
margin-left: 10px;
|
font-size: 12px;
|
color: #909399;
|
}
|
|
.position-mapping {
|
width: 100%;
|
}
|
|
.mapping-item {
|
display: flex;
|
align-items: center;
|
margin-bottom: 12px;
|
padding: 12px;
|
border: 1px solid #ebeef5;
|
border-radius: 6px;
|
background-color: #fafafa;
|
}
|
</style>
|