This commit is contained in:
xhf 2025-03-08 09:41:31 +08:00
commit b909e61b0a
6 changed files with 349 additions and 131 deletions

View File

@ -148,3 +148,9 @@ export const getAGVPointInformation = async (macAddress) => {
url: `/system/position-map-item/getAGVPointInformation?macAddress=` + macAddress url: `/system/position-map-item/getAGVPointInformation?macAddress=` + macAddress
}) })
} }
//根据地图id获取车辆列表
export const getListByMapId = async (mapId) => {
return await request.get({
url: `/system/robot/information/getListByMapId?mapId=` + mapId
})
}

View File

@ -43,7 +43,13 @@
> >
<el-input-number v-model="form.layersNumber" :min="1" :max="3" /> <el-input-number v-model="form.layersNumber" :min="1" :max="3" />
</el-form-item> </el-form-item>
<el-form-item label="排序" prop="locationNumber" v-if="form.type === 2" required> <el-form-item
label="排序"
prop="locationNumber"
v-if="form.type === 2"
required
:rules="{ required: true, message: '请输入排序', trigger: 'change' }"
>
<el-input-number v-model="form.locationNumber" :min="1" :max="10000000" /> <el-input-number v-model="form.locationNumber" :min="1" :max="10000000" />
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -173,7 +179,8 @@ const rules = reactive({
locationX: [{ required: true, message: '请输入X', trigger: 'blur' }], locationX: [{ required: true, message: '请输入X', trigger: 'blur' }],
locationY: [{ required: true, message: '请输入Y', trigger: 'blur' }], locationY: [{ required: true, message: '请输入Y', trigger: 'blur' }],
type: [{ required: true, message: '请选择类型', trigger: 'blur' }], type: [{ required: true, message: '请选择类型', trigger: 'blur' }],
layersNumber: [{ required: true, message: '请输入层数', trigger: 'blur' }] layersNumber: [{ required: true, message: '请输入层数', trigger: 'blur' }],
locationNumber: [{ required: true, message: '请输入排序', trigger: 'blur' }]
}) })
const emit = defineEmits(['submitNodeSuccess', 'addEventListener']) const emit = defineEmits(['submitNodeSuccess', 'addEventListener'])
@ -274,22 +281,40 @@ const typeChange = (type) => {
form.value.inDirection = null form.value.inDirection = null
form.value.outDirection = null form.value.outDirection = null
form.value.locationNumber = null form.value.locationNumber = null
form.value.locationDeep = 50 form.value.locationDeep = 40
form.value.locationWide = 50 form.value.locationWide = 40
form.value.locationDeepPx = 10 form.value.locationDeepPx = 8
form.value.locationWidePx = 10 form.value.locationWidePx = 8
} else if (type === 2) { } else if (type === 2) {
form.value.locationNumber = 1 form.value.locationNumber = null
if (!form.value.id) {
form.value.locationDeep = 150
form.value.locationWide = 150
form.value.locationDeepPx = 30
form.value.locationWidePx = 30
}
} else if (type === 3) { } else if (type === 3) {
form.value.direction = null form.value.direction = null
form.value.inDirection = null form.value.inDirection = null
form.value.outDirection = null form.value.outDirection = null
form.value.locationNumber = null form.value.locationNumber = null
if (!form.value.id) {
form.value.locationDeep = 150
form.value.locationWide = 150
form.value.locationDeepPx = 30
form.value.locationWidePx = 30
}
} else if (type === 4) { } else if (type === 4) {
form.value.direction = null form.value.direction = null
form.value.inDirection = null form.value.inDirection = null
form.value.outDirection = null form.value.outDirection = null
form.value.locationNumber = null form.value.locationNumber = null
if (!form.value.id) {
form.value.locationDeep = 150
form.value.locationWide = 150
form.value.locationDeepPx = 30
form.value.locationWidePx = 30
}
} else if (type === 5) { } else if (type === 5) {
form.value.layersNumber = null form.value.layersNumber = null
form.value.direction = null form.value.direction = null

View File

@ -83,9 +83,13 @@
:key="index" :key="index"
:style="{ :style="{
left: item.realX * radio + 'px', left: item.realX * radio + 'px',
top: item.realY * radio + 'px', top: item.realY * radio + 'px',
width: legendObj.carShow ? carWidth / nowObject.showYamlJson.resolution / 100 * radio + 'px' : '0', width: legendObj.carShow
height: legendObj.carShow ? carHeight / nowObject.showYamlJson.resolution / 100 * radio + 'px' : '0', ? (carWidth / nowObject.showYamlJson.resolution / 100) * radio + 'px'
: '0',
height: legendObj.carShow
? (carHeight / nowObject.showYamlJson.resolution / 100) * radio + 'px'
: '0',
transform: 'rotate(' + radianToDegree(item.data.pose2d.yaw) + 'deg)', transform: 'rotate(' + radianToDegree(item.data.pose2d.yaw) + 'deg)',
transition: 'all 0.2s linear', transition: 'all 0.2s linear',
zIndex: 9999 zIndex: 9999
@ -438,14 +442,20 @@ const props = defineProps({
isAllBoard: propTypes.bool.def(false) isAllBoard: propTypes.bool.def(false)
}) })
const convertActualToBrowser = (pointX, pointY) => { const convertActualToBrowser = (pointX, pointY) => {
  const y1 = Number(nowObject.value.showYamlJson.origin[1]) + Number(nowObject.value.showYamlJson.height) * Number(nowObject.value.showYamlJson.resolution) const y1 =
  let x = Math.max(Number(pointX) - Number(nowObject.value.showYamlJson.origin[0]), 0) Number(nowObject.value.showYamlJson.origin[1]) +
  let y = Math.max(y1 - Number(pointY), 0) Number(nowObject.value.showYamlJson.height) * Number(nowObject.value.showYamlJson.resolution)
let x = Math.max(Number(pointX) - Number(nowObject.value.showYamlJson.origin[0]), 0)
let y = Math.max(y1 - Number(pointY), 0)
  return { return {
    x :(x / nowObject.value.showYamlJson.resolution) - (carWidth.value / nowObject.value.showYamlJson.resolution / 100/2), x:
    y: (y / nowObject.value.showYamlJson.resolution) - (carHeight.value / nowObject.value.showYamlJson.resolution / 100/2) x / nowObject.value.showYamlJson.resolution -
  } carWidth.value / nowObject.value.showYamlJson.resolution / 100 / 2,
y:
y / nowObject.value.showYamlJson.resolution -
carHeight.value / nowObject.value.showYamlJson.resolution / 100 / 2
}
} }
// //
const isDrag = ref(false) const isDrag = ref(false)
@ -654,7 +664,6 @@ const getPositionMapListFun = async (positionMapId) => {
} else if (item.type === 7) { } else if (item.type === 7) {
} }
}) })
} }
const draggableElement = ref(null) const draggableElement = ref(null)
const resetPosition = () => { const resetPosition = () => {
@ -831,11 +840,11 @@ const getMapData = async (item) => {
getMapLineList() getMapLineList()
} }
// //
const radianToDegree = (radian) =>{ const radianToDegree = (radian) => {
// //
const degree = radian * (180 / Math.PI); const degree = radian * (180 / Math.PI)
// 'deg' CSS // 'deg' CSS
return `${degree}`; return `${degree}`
} }
const heightVal = ref(0) const heightVal = ref(0)
const widthVal = ref(0) const widthVal = ref(0)

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="edit-map-page"> <div class="edit-map-page" @wheel="handleWheel">
<div class="top-tool"> <div class="top-tool">
<div class="top-tool-list"> <div class="top-tool-list">
<div v-for="item in state.topToolList" :key="item.switchType" class="top-tool-item"> <div v-for="item in state.topToolList" :key="item.switchType" class="top-tool-item">
@ -236,7 +236,8 @@
(item.switchType === 'next' && (item.switchType === 'next' &&
(toolbarSwitchType === 'createLineLibrary' || (toolbarSwitchType === 'createLineLibrary' ||
toolbarSwitchType === 'createRegion' || toolbarSwitchType === 'createRegion' ||
toolbarSwitchType === 'drawRoute')) toolbarSwitchType === 'drawRoute' ||
toolbarSwitchType === 'generateLine'))
" "
></div> ></div>
<el-button <el-button
@ -244,7 +245,8 @@
item.switchType === 'next' && item.switchType === 'next' &&
(toolbarSwitchType === 'createLineLibrary' || (toolbarSwitchType === 'createLineLibrary' ||
toolbarSwitchType === 'createRegion' || toolbarSwitchType === 'createRegion' ||
toolbarSwitchType === 'drawRoute') toolbarSwitchType === 'drawRoute' ||
toolbarSwitchType === 'generateLine')
" "
type="danger" type="danger"
class="selection-area-btn" class="selection-area-btn"
@ -1164,6 +1166,12 @@ const state = reactive({
name: '编辑路线', name: '编辑路线',
icon: 'ep:semi-select', icon: 'ep:semi-select',
isActive: false isActive: false
},
{
switchType: 'generateLine',
name: '生成直线',
icon: 'ep:finished',
isActive: false
} }
], ],
isShowToolbar: true, // isShowToolbar: true, //
@ -1542,11 +1550,7 @@ const rotationFormSubmit = () => {
// //
const mapMark = async () => { const mapMark = async () => {
let res = await MapApi.getRobotInformationPage({ state.mapMarkCarList = await MapApi.getListByMapId(imgBgObj.positionMapId)
pageNo: 1,
pageSize: 20
})
state.mapMarkCarList = res.list
if (state.currentItemIndex != -1) { if (state.currentItemIndex != -1) {
let item = state.allMapPointInfo[state.currentItemIndex] let item = state.allMapPointInfo[state.currentItemIndex]
@ -1671,32 +1675,33 @@ const startFromPoint = (index, event) => {
// //
const startDrawSelection = (event) => { const startDrawSelection = (event) => {
if ( if (
toolbarSwitchType.value === 'createLineLibrary' || toolbarSwitchType.value !== 'createLineLibrary' &&
toolbarSwitchType.value === 'createRegion' || toolbarSwitchType.value !== 'createRegion' &&
toolbarSwitchType.value === 'drawRoute' toolbarSwitchType.value !== 'drawRoute' &&
) { toolbarSwitchType.value !== 'generateLine'
const backgroundRect = mapBackgroundRef.value.getBoundingClientRect() )
const x = disposeEventPoints(event).x
const y = disposeEventPoints(event).y
//
if (x >= 0 && x <= backgroundRect.width && y >= 0 && y <= backgroundRect.height) {
state.drawSelectionAreaShow = true
state.drawSelectionStartPoint = { x: x, y: y }
state.drawSelectionAreaBox = { x: x, y: y, width: 0, height: 0 }
}
event.preventDefault() //
return return
const backgroundRect = mapBackgroundRef.value.getBoundingClientRect()
const x = disposeEventPoints(event).x
const y = disposeEventPoints(event).y
//
if (x >= 0 && x <= backgroundRect.width && y >= 0 && y <= backgroundRect.height) {
state.drawSelectionAreaShow = true
state.drawSelectionStartPoint = { x: x, y: y }
state.drawSelectionAreaBox = { x: x, y: y, width: 0, height: 0 }
} }
event.preventDefault() //
} }
// //
const updateDrawSelection = (event) => { const updateDrawSelection = (event) => {
if ( if (
toolbarSwitchType.value === 'createLineLibrary' || toolbarSwitchType.value === 'createLineLibrary' ||
toolbarSwitchType.value === 'createRegion' || toolbarSwitchType.value === 'createRegion' ||
toolbarSwitchType.value === 'drawRoute' toolbarSwitchType.value === 'drawRoute' ||
toolbarSwitchType.value === 'generateLine'
) { ) {
if (state.drawSelectionAreaShow) { if (state.drawSelectionAreaShow) {
const x = disposeEventPoints(event).x const x = disposeEventPoints(event).x
@ -1721,16 +1726,17 @@ const updateDrawSelection = (event) => {
state.currentDrawX = x state.currentDrawX = x
state.currentDrawY = y state.currentDrawY = y
} }
event.preventDefault() //
return
} }
event.preventDefault() //
return
} }
// //
const endDrawSelection = (event) => { const endDrawSelection = (event) => {
if ( if (
toolbarSwitchType.value === 'createLineLibrary' || toolbarSwitchType.value === 'createLineLibrary' ||
toolbarSwitchType.value === 'createRegion' || toolbarSwitchType.value === 'createRegion' ||
toolbarSwitchType.value === 'drawRoute' toolbarSwitchType.value === 'drawRoute' ||
toolbarSwitchType.value === 'generateLine'
) { ) {
state.drawSelectionAreaShow = false state.drawSelectionAreaShow = false
state.allDrawSelectionAreaBox.push({ ...state.drawSelectionAreaBox }) state.allDrawSelectionAreaBox.push({ ...state.drawSelectionAreaBox })
@ -1825,7 +1831,6 @@ const endDrawSelection = (event) => {
state.currentDrawX = 0 state.currentDrawX = 0
state.currentDrawY = 0 state.currentDrawY = 0
} }
event.preventDefault() // event.preventDefault() //
return return
} }
@ -1875,6 +1880,7 @@ const clickDrawSelectionArea = () => {
item.id item.id
}) })
//线
if (toolbarSwitchType.value === 'createLineLibrary') { if (toolbarSwitchType.value === 'createLineLibrary') {
//线 //线
if (binLocation.length < 2) { if (binLocation.length < 2) {
@ -1911,7 +1917,7 @@ const clickDrawSelectionArea = () => {
removeEventListener() // removeEventListener() //
itemAreaSettingDialogRef.value.open(binLocation) itemAreaSettingDialogRef.value.open(binLocation)
} }
//线
if (toolbarSwitchType.value === 'drawRoute') { if (toolbarSwitchType.value === 'drawRoute') {
if (routeList.length !== 2) { if (routeList.length !== 2) {
message.warning('只能选择两个路径点') message.warning('只能选择两个路径点')
@ -1962,6 +1968,105 @@ const clickDrawSelectionArea = () => {
state.mapRouteList.push(curve) state.mapRouteList.push(curve)
addEditHistory() addEditHistory()
} }
//线
if (toolbarSwitchType.value === 'generateLine') {
if (routeList.length < 3) {
message.warning('至少框选三个点')
return
}
let isHaveId = routeList.every((item) => {
return item.id
})
if (!isHaveId) {
message.warning('您选择的路径点存在未保存的')
return
}
const list = mapPointsToLine(routeList)
const idNameMap = {}
list.forEach((item) => {
idNameMap[item.id] = item
})
// name
state.allMapPointInfo.forEach((item) => {
if (idNameMap[item.id]) {
let actualPoint = disposeEventPoint(
idNameMap[item.id].locationX,
idNameMap[item.id].locationY
)
item.locationX = idNameMap[item.id].locationX
item.locationY = idNameMap[item.id].locationY
item.actualLocationX = actualPoint.actualLocationX
item.actualLocationY = actualPoint.actualLocationY
}
})
state.mapRouteList.forEach((item) => {
if (idNameMap[item.startingPointId]) {
let actualPoint = disposeEventPoint(
idNameMap[item.startingPointId].locationX,
idNameMap[item.startingPointId].locationY
)
item.startPointX = idNameMap[item.startingPointId].locationX
item.startPointY = idNameMap[item.startingPointId].locationY
item.actualStartPointX = actualPoint.actualLocationX
item.actualStartPointY = actualPoint.actualLocationY
}
if (idNameMap[item.endPointId]) {
let actualPoint = disposeEventPoint(
idNameMap[item.endPointId].locationX,
idNameMap[item.endPointId].locationY
)
item.endPointX = idNameMap[item.endPointId].locationX
item.endPointY = idNameMap[item.endPointId].locationY
item.actualEndPointX = actualPoint.actualLocationX
item.actualEndPointY = actualPoint.actualLocationY
}
})
addEditHistory()
}
}
// 线
const mapPointsToLine = (points) => {
if (points.length < 2) {
return points
}
//
const firstPoint = points[0]
const lastPoint = points[points.length - 1]
// 线
const dx = lastPoint.locationX - firstPoint.locationX
const dy = lastPoint.locationY - firstPoint.locationY
if (dx === 0) {
// 线
return points.map((point, index) => {
if (index === 0 || index === points.length - 1) {
return point
}
return {
...point,
locationX: firstPoint.locationX,
locationY: point.locationY
}
})
}
const slope = dy / dx
// 线
const intercept = firstPoint.locationY - slope * firstPoint.locationX
// 线
return points.map((point, index) => {
if (index === 0 || index === points.length - 1) {
return point
}
const newY = slope * point.locationX + intercept
//
const roundedY = parseFloat(newY.toFixed(8))
return {
...point,
locationY: roundedY
}
})
} }
//线 //线
const isStraightLine = (binLocation) => { const isStraightLine = (binLocation) => {
@ -2489,6 +2594,33 @@ const handleKeyDown = (event) => {
} }
} }
//
const handleWheel = (event) => {
// Ctrl
if (event.ctrlKey) {
//
event.preventDefault()
//
if (event.deltaY < 0) {
//
//
if (state.imageChangeMultiple < 4) {
state.imageChangeMultiple += 0.2
} else {
message.warning('不能在放大了')
}
} else {
//
if (state.imageChangeMultiple > 0.2) {
state.imageChangeMultiple -= 0.2
} else {
message.warning('不能在缩小了')
}
}
}
}
const addEventListener = () => { const addEventListener = () => {
window.addEventListener('keydown', handleKeyDown) window.addEventListener('keydown', handleKeyDown)
} }
@ -2638,8 +2770,6 @@ onUnmounted(() => {
// 20px 20px, // 20px 20px,
// 20px 20px; // 20px 20px;
width: 100%;
height: 100%;
background-image: repeating-linear-gradient( background-image: repeating-linear-gradient(
to right, to right,
rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1),

View File

@ -1,79 +1,94 @@
<template> <template>
<div> <div style="width: 600px; height: 300px; background: #dbeede; position: relative">
<ul> <div v-for="(item, index) in points" :key="index">
<li v-for="(point, index) in points" :key="index"> <div
点位 {{ index + 1 }}: ({{ point.x }}, {{ point.y }}) :style="{
<button @click="movePoint(index)">移动</button> position: 'absolute',
<button @click="deletePoint(index)">删除</button> width: '10px',
</li> height: '10px',
</ul> backgroundColor: '#000',
<button @click="addPoint">新增点位</button> borderRadius: '50%',
<button @click="undo" :disabled="historyIndex === 0">撤回</button> zIndex: 999,
<button @click="redo" :disabled="historyIndex === history.length - 1">重做</button> left: item.x + 'px',
top: item.y + 'px'
}"
></div>
</div>
</div>
<div style="width: 600px; height: 300px; background: #b3dcff; position: relative">
<div v-for="(item, index) in mappedPoints" :key="index">
<div
:style="{
position: 'absolute',
width: '10px',
height: '10px',
backgroundColor: '#000',
borderRadius: '50%',
zIndex: 999,
left: item.x + 'px',
top: item.y + 'px'
}"
></div>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { reactive, ref } from 'vue' import { ref } from 'vue'
// const points = ref([
const points = reactive([ {
{ x: 10, y: 20 }, x: 123.567,
{ x: 30, y: 40 } y: 178.123
},
{
x: 255.567,
y: 79.123
},
{
x: 382.567,
y: 178.123
},
{
x: 481.567,
y: 238.123
}
]) ])
// const mapPointsToLine = (points) => {
const history = reactive([[...points]]) if (points.length < 2) {
// return points
const historyIndex = ref(0)
//
const addPoint = () => {
const newPoint = { x: Math.random() * 100, y: Math.random() * 100 }
points.push(newPoint)
updateHistory()
}
//
const movePoint = (index) => {
points[index].x = Math.random() * 100
points[index].y = Math.random() * 100
updateHistory()
}
//
const deletePoint = (index) => {
points.splice(index, 1)
updateHistory()
}
//
const updateHistory = () => {
//
if (historyIndex.value < history.length - 1) {
history.splice(historyIndex.value + 1)
} }
// //
history.push([...points]) const firstPoint = points[0]
// const lastPoint = points[points.length - 1]
historyIndex.value++
// 线
const dx = lastPoint.x - firstPoint.x
const dy = lastPoint.y - firstPoint.y
if (dx === 0) {
// 线
return points.map((point, index) => {
if (index === 0 || index === points.length - 1) {
return point
}
return { x: firstPoint.x, y: point.y }
})
}
const slope = dy / dx
// 线
const intercept = firstPoint.y - slope * firstPoint.x
// 线
return points.map((point, index) => {
if (index === 0 || index === points.length - 1) {
return point
}
const newY = slope * point.x + intercept
return { x: point.x, y: newY }
})
} }
// const mappedPoints = mapPointsToLine(points.value)
const undo = () => { console.log(mappedPoints)
if (historyIndex.value > 0) {
historyIndex.value--
//
points.splice(0, points.length, ...history[historyIndex.value])
}
}
//
const redo = () => {
if (historyIndex.value < history.length - 1) {
historyIndex.value++
//
points.splice(0, points.length, ...history[historyIndex.value])
}
}
</script> </script>

View File

@ -298,7 +298,11 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="指定车辆"> <el-form-item label="指定车辆">
<el-select v-model="detailItem.robotNo" placeholder="请选择车辆"> <el-select
v-model="detailItem.robotNo"
placeholder="请选择车辆"
@change="chooseCarErrorMsg"
>
<el-option <el-option
v-for="car in robotList" v-for="car in robotList"
:key="car.id" :key="car.id"
@ -320,7 +324,11 @@
:prop="`taskDetailList[${index}].robotNo`" :prop="`taskDetailList[${index}].robotNo`"
:rules="{ required: true, message: '车辆不能为空', trigger: 'change' }" :rules="{ required: true, message: '车辆不能为空', trigger: 'change' }"
> >
<el-select v-model="detailItem.robotNo" placeholder="请选择车辆"> <el-select
v-model="detailItem.robotNo"
placeholder="请选择车辆"
@change="chooseCarErrorMsg"
>
<el-option <el-option
v-for="car in robotList" v-for="car in robotList"
:key="car.id" :key="car.id"
@ -390,7 +398,11 @@
:prop="`taskDetailList[${index}].robotNo`" :prop="`taskDetailList[${index}].robotNo`"
:rules="{ required: true, message: '车辆不能为空', trigger: 'change' }" :rules="{ required: true, message: '车辆不能为空', trigger: 'change' }"
> >
<el-select v-model="detailItem.robotNo" placeholder="请选择车辆"> <el-select
v-model="detailItem.robotNo"
placeholder="请选择车辆"
@change="chooseCarErrorMsg"
>
<el-option <el-option
v-for="car in robotList" v-for="car in robotList"
:key="car.id" :key="car.id"
@ -501,7 +513,11 @@
:prop="`taskDetailList[${index}].robotNo`" :prop="`taskDetailList[${index}].robotNo`"
:rules="{ required: true, message: '车辆不能为空', trigger: 'change' }" :rules="{ required: true, message: '车辆不能为空', trigger: 'change' }"
> >
<el-select v-model="detailItem.robotNo" placeholder="请选择车辆"> <el-select
v-model="detailItem.robotNo"
placeholder="请选择车辆"
@change="chooseCarErrorMsg"
>
<el-option <el-option
v-for="car in robotList" v-for="car in robotList"
:key="car.id" :key="car.id"
@ -577,7 +593,11 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
<el-form-item required label="指定车辆" prop="montageTask"> <el-form-item required label="指定车辆" prop="montageTask">
<el-select v-model="detailItem.robotNo" placeholder="请选择车辆"> <el-select
v-model="detailItem.robotNo"
placeholder="请选择车辆"
@change="chooseCarErrorMsg"
>
<el-option <el-option
v-for="car in robotList" v-for="car in robotList"
:key="car.id" :key="car.id"
@ -828,10 +848,14 @@ const getCanUseRobotList = async () => {
// //
const robotNoChange = (e, detailItem) => { const robotNoChange = (e, detailItem) => {
let car = robotList.value.filter((item) => { let car = robotList.value.find((item) => {
return item.robotNo == e return item.robotNo == e
}) })
detailItem.electricity = car[0].electricity detailItem.electricity = car.electricity
if (car?.errorMsg) {
message.warning(car.errorMsg)
}
} }
// //
@ -1073,6 +1097,15 @@ const releaseTypeChange = (item) => {
item.releaseId = undefined item.releaseId = undefined
} }
//
const chooseCarErrorMsg = (e) => {
let carItem = robotList.value.find((item) => item.robotNo === e)
if (carItem?.errorMsg) {
message.warning(carItem.errorMsg)
}
}
// //
const formRef = ref() const formRef = ref()
const formLoading = ref(false) const formLoading = ref(false)