Compare commits

..

No commits in common. "74701d7fb79bbd26b652ab2cb8500caf119239e3" and "3bd363e8aca826ed42e59937e22ff193acfe9269" have entirely different histories.

7 changed files with 448 additions and 814 deletions

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="edit-map-page" @wheel="handleWheel"> <div class="edit-map-page">
<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">
@ -155,62 +155,6 @@
> >
</div> </div>
</el-popover> </el-popover>
<!-- 标记 -->
<el-popover
placement="bottom"
trigger="click"
v-else-if="item.switchType === 'marker'"
width="220"
>
<template #reference>
<div
class="tool-item"
:class="
toolbarSwitchType === item.switchType
? 'tool-active'
: item.isActive
? 'right-tool-active'
: ''
"
@click="toolbarClick(item)"
>
<Icon :icon="item.icon" :size="24" />
<div class="name"> {{ item.name }} </div>
</div>
</template>
<!-- 位置 -->
<el-form :model="state.markForm" class="mt-2" label-width="68">
<el-form-item label="标记车辆">
<el-select
v-model="state.markForm.macAddress"
placeholder="请选择"
@change="macAddressChange"
>
<el-option
v-for="item in state.mapMarkCarList"
:key="item.id"
:label="item.robotNo"
:value="item.macAddress"
/>
</el-select>
</el-form-item>
<el-form-item label="标记属性" v-if="state.markForm.markProperty">
<el-input v-model="state.markForm.markProperty" style="width: 240px" disabled />
</el-form-item>
<el-form-item label="原节点" v-if="state.markForm.originalNode">
<el-input v-model="state.markForm.originalNode" style="width: 240px" disabled />
</el-form-item>
<div style="text-align: right">
<el-button
size="small"
style="width: 64px; height: 30px; background: #00329f"
color="#00329F"
@click="markFormSubmit()"
>确认</el-button
>
</div>
</el-form>
</el-popover>
<div <div
v-else v-else
class="tool-item" class="tool-item"
@ -236,8 +180,7 @@
(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
@ -245,8 +188,7 @@
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"
@ -327,10 +269,7 @@
style="border: none; z-index: 999" style="border: none; z-index: 999"
> >
<!-- 节点合集 --> <!-- 节点合集 -->
<div <div @mousedown="startFromPoint(index, $event)">
@mousedown="startFromPoint(index, $event)"
:style="{ width: item.locationWidePx + 'px', height: item.locationDeepPx + 'px' }"
>
<!-- 1 路径点 --> <!-- 1 路径点 -->
<el-tooltip <el-tooltip
class="box-item" class="box-item"
@ -422,33 +361,17 @@
:x2="Number(state.currentDrawX)" :x2="Number(state.currentDrawX)"
:y2="Number(state.currentDrawY)" :y2="Number(state.currentDrawY)"
stroke="#00329F" stroke="#00329F"
stroke-width="3" stroke-width="4"
/> />
<template v-if="state.mapRouteList.length > 0"> <template v-if="state.mapRouteList.length > 0">
<template v-for="(curve, index) in state.mapRouteList" :key="index"> <template v-for="(curve, index) in state.mapRouteList" :key="index">
<!-- 定义箭头 --> <!-- 定义箭头 -->
<defs> <defs>
<marker <marker id="forward-arrow" viewBox="0 0 9 9" refX="10" refY="5" orient="auto">
id="forward-arrow"
viewBox="0 0 10 10"
refX="10"
refY="5"
orient="auto"
markerWidth="2"
markerHeight="2"
>
<path d="M 0 0 L 10 5 L 0 10 z" fill="black" /> <path d="M 0 0 L 10 5 L 0 10 z" fill="black" />
</marker> </marker>
<!-- 反向箭头 --> <!-- 反向箭头 -->
<marker <marker id="backward-arrow" viewBox="0 0 9 9" refX="0" refY="5" orient="auto">
id="backward-arrow"
viewBox="0 0 10 10"
refX="0"
refY="5"
orient="auto"
markerWidth="2"
markerHeight="2"
>
<path d="M 10 0 L 0 5 L 10 10 z" fill="black" /> <path d="M 10 0 L 0 5 L 10 10 z" fill="black" />
</marker> </marker>
</defs> </defs>
@ -901,10 +824,10 @@ const mapClick = (e) => {
locationY: y, locationY: y,
actualLocationX: actualLocationX, actualLocationX: actualLocationX,
actualLocationY: actualLocationY, actualLocationY: actualLocationY,
locationDeep: 40, locationDeep: 50,
locationWide: 40, locationWide: 50,
locationDeepPx: 8, locationDeepPx: 10,
locationWidePx: 8, locationWidePx: 10,
angle: 0, angle: 0,
draggable: true, draggable: true,
resizable: true, resizable: true,
@ -1155,22 +1078,16 @@ const state = reactive({
icon: 'ep:semi-select', icon: 'ep:semi-select',
isActive: false isActive: false
}, },
// {
// switchType: 'drawRoute',
// name: '',
// icon: 'ep:semi-select',
// isActive: false
// },
{ {
switchType: 'editRoute', switchType: 'drawRoute',
name: '编辑路线', name: '框选绘制',
icon: 'ep:semi-select', icon: 'ep:semi-select',
isActive: false isActive: false
}, },
{ {
switchType: 'generateLine', switchType: 'editRoute',
name: '生成直线', name: '编辑路线',
icon: 'ep:finished', icon: 'ep:semi-select',
isActive: false isActive: false
} }
], ],
@ -1221,14 +1138,7 @@ const state = reactive({
allMapPointInfo: [], // allMapPointInfo: [], //
mapRouteList: [], //线 mapRouteList: [], //线
currentIndex: 0, // currentIndex: 0, //
currentItemIndex: -1, // currentItemIndex: -1 //
markForm: {
macAddress: '', // mac
markProperty: '', //
originalNode: '', //
robotNo: '' //AGV
}, //
mapMarkCarList: [] //
}) })
const toolbarClick = async (item) => { const toolbarClick = async (item) => {
@ -1419,7 +1329,6 @@ const toolbarClick = async (item) => {
break break
case 'marker': case 'marker':
// //
mapMark()
break break
case 'grid': case 'grid':
// //
@ -1548,108 +1457,6 @@ const rotationFormSubmit = () => {
addEditHistory() addEditHistory()
} }
//
const mapMark = async () => {
state.mapMarkCarList = await MapApi.getListByMapId(imgBgObj.positionMapId)
if (state.currentItemIndex != -1) {
let item = state.allMapPointInfo[state.currentItemIndex]
state.markForm.originalNode = `[${item.locationX},${item.locationY}]`
if (item.type == 1) {
state.markForm.markProperty = '路径点'
} else if (item.type == 2) {
state.markForm.markProperty = '库位点'
} else if (item.type == 3) {
state.markForm.markProperty = '设备点'
} else if (item.type == 4) {
state.markForm.markProperty = '停车点'
} else if (item.type == 5) {
state.markForm.markProperty = '区域变更点'
} else if (item.type == 6) {
state.markForm.markProperty = '等待点'
}
} else {
state.markForm.markProperty = ''
state.markForm.originalNode = ''
}
}
//
const macAddressChange = (e) => {
const targetItem = state.mapMarkCarList.find((item) => item.macAddress === e)
if (targetItem) {
state.markForm.robotNo = targetItem.robotNo
}
}
const markFormSubmit = async () => {
if (!state.markForm.macAddress) {
message.warning('请选择车辆')
return
}
let res = await MapApi.getAGVPointInformation(state.markForm.macAddress)
if (res) {
let content = JSON.parse(res.content)
let point = JSON.parse(content[state.markForm.robotNo]) //
let pointPx = convertActualToBrowser(point.x, point.y)
let actualPoint = disposeEventPoint(pointPx.x, pointPx.y)
if (state.currentItemIndex !== -1) {
state.allMapPointInfo[state.currentItemIndex].locationX = pointPx.x
state.allMapPointInfo[state.currentItemIndex].locationY = pointPx.y
state.allMapPointInfo[state.currentItemIndex].actualLocationX = actualPoint.actualLocationX
state.allMapPointInfo[state.currentItemIndex].actualLocationY = actualPoint.actualLocationY
//线
let item = state.allMapPointInfo[state.currentItemIndex]
state.mapRouteList.forEach((route) => {
if (item.id === route.startingPointId) {
route.startPointX = pointPx.x
route.startPointY = pointPx.y
route.beginHigh = Number(item.locationDeepPx)
route.beginWidth = Number(item.locationWidePx)
route.actualStartPointX = actualPoint.actualLocationX
route.actualStartPointY = actualPoint.actualLocationY
}
if (item.id === route.endPointId) {
route.endPointX = pointPx.x
route.endPointY = pointPx.y
route.endHigh = Number(item.locationDeepPx)
route.endWidth = Number(item.locationWidePx)
route.actualEndPointX = actualPoint.actualLocationX
route.actualEndPointY = actualPoint.actualLocationY
}
})
addEditHistory()
} else {
message.warning('未采集到该AGV点位信息')
}
} else {
//
state.allMapPointInfo.push({
positionMapId: imgBgObj.positionMapId, //id
layerSelectionShow: true,
locationX: pointPx.x,
locationY: pointPx.y,
actualLocationX: actualPoint.actualLocationX,
actualLocationY: actualPoint.actualLocationY,
locationDeep: 40,
locationWide: 40,
locationDeepPx: 8,
locationWidePx: 8,
angle: 0,
draggable: true,
resizable: true,
rotatable: false,
lockAspectRatio: false, //
mapImageUrl: '',
type: 1, //1
dataList: [], //
dataObj: {} //
})
addEditHistory()
}
}
// //
// //
const startFromPoint = (index, event) => { const startFromPoint = (index, event) => {
@ -1675,33 +1482,32 @@ 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
@ -1726,17 +1532,16 @@ 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 })
@ -1831,6 +1636,7 @@ const endDrawSelection = (event) => {
state.currentDrawX = 0 state.currentDrawX = 0
state.currentDrawY = 0 state.currentDrawY = 0
} }
event.preventDefault() // event.preventDefault() //
return return
} }
@ -1880,7 +1686,6 @@ const clickDrawSelectionArea = () => {
item.id item.id
}) })
//线
if (toolbarSwitchType.value === 'createLineLibrary') { if (toolbarSwitchType.value === 'createLineLibrary') {
//线 //线
if (binLocation.length < 2) { if (binLocation.length < 2) {
@ -1917,7 +1722,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('只能选择两个路径点')
@ -1968,105 +1773,6 @@ 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
}
})
console.log(state.allMapPointInfo)
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
//
return {
...point,
locationY: newY
}
})
} }
//线 //线
const isStraightLine = (binLocation) => { const isStraightLine = (binLocation) => {
@ -2296,6 +2002,7 @@ const getMapList = async () => {
imgBgObj.positionMapId = res.id imgBgObj.positionMapId = res.id
imgBgObj.floor = res.floor imgBgObj.floor = res.floor
imgBgObj.area = res.area imgBgObj.area = res.area
imgBgObj.width = yamlJson.width imgBgObj.width = yamlJson.width
imgBgObj.height = yamlJson.height imgBgObj.height = yamlJson.height
imgBgObj.origin = yamlJson.origin imgBgObj.origin = yamlJson.origin
@ -2330,8 +2037,8 @@ const getAllNodeList = async () => {
if (item.type === 1) { if (item.type === 1) {
item.dataObj = {} item.dataObj = {}
item.dataList = [] item.dataList = []
item.locationDeep = 40 item.locationDeep = 50
item.locationWide = 40 item.locationWide = 50
item.draggable = true item.draggable = true
item.resizable = false item.resizable = false
item.rotatable = false item.rotatable = false
@ -2594,33 +2301,6 @@ 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)
} }
@ -2770,6 +2450,8 @@ 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,94 +0,0 @@
<template>
<div style="width: 600px; height: 300px; background: #dbeede; position: relative">
<div v-for="(item, index) in points" :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 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>
</template>
<script setup>
import { ref } from 'vue'
const points = ref([
{
x: 123.567,
y: 178.123
},
{
x: 255.567,
y: 79.123
},
{
x: 382.567,
y: 178.123
},
{
x: 481.567,
y: 238.123
}
])
const mapPointsToLine = (points) => {
if (points.length < 2) {
return points
}
//
const firstPoint = points[0]
const lastPoint = points[points.length - 1]
// 线
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)
console.log(mappedPoints)
</script>

View File

@ -23,14 +23,6 @@
> >
<el-input type="number" v-model="form.locationY" placeholder="请输入" :min="0" /> <el-input type="number" v-model="form.locationY" placeholder="请输入" :min="0" />
</el-form-item> </el-form-item>
<el-form-item
label="弧度"
prop="locationYaw"
required
:rules="{ required: true, message: '请输入弧度', trigger: 'change' }"
>
<el-input type="number" v-model="form.locationYaw" placeholder="请输入" :min="0" />
</el-form-item>
<el-form-item label="类型" prop="type" required> <el-form-item label="类型" prop="type" required>
<el-select v-model="form.type" placeholder="请选择类型" @change="typeChange"> <el-select v-model="form.type" placeholder="请选择类型" @change="typeChange">
<el-option label="路径点位" :value="1" /> <el-option label="路径点位" :value="1" />
@ -41,7 +33,6 @@
<el-option label="等待点" :value="6" /> <el-option label="等待点" :value="6" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<div v-if="form.type === 2 || form.type === 3 || form.type === 4"> <div v-if="form.type === 2 || form.type === 3 || form.type === 4">
<el-form-item <el-form-item
label="层数" label="层数"
@ -181,14 +172,12 @@ const form = ref({
dataList: [], // dataList: [], //
dataObj: {}, // dataObj: {}, //
positionMapId: undefined, positionMapId: undefined,
deviceId: undefined, //id deviceId: undefined
locationYaw: undefined //
}) })
const rules = reactive({ 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' }],
locationYaw: [{ required: true, message: '请输入弧度', 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' }] locationNumber: [{ required: true, message: '请输入排序', trigger: 'blur' }]
@ -267,7 +256,6 @@ const dialogClose = () => {
const equipmentList = ref([]) // const equipmentList = ref([]) //
const open = (item, list) => { const open = (item, list) => {
console.log(item)
form.value = item form.value = item
form.value.layersNumber = item.dataList?.length || '' form.value.layersNumber = item.dataList?.length || ''
form.value.deviceId = item?.deviceId || item?.dataObj?.id || '' form.value.deviceId = item?.deviceId || item?.dataObj?.id || ''

View File

@ -5,7 +5,7 @@
:style="{ :style="{
height: heightVal + 'px', height: heightVal + 'px',
cursor: isDrag ? 'pointer' : 'default', cursor: isDrag ? 'pointer' : 'default',
scale: isSizeRadio, scale: isSizeRaio,
transformOrigin: '0 0' transformOrigin: '0 0'
}" }"
> >
@ -17,7 +17,7 @@
ref="draggableElement" ref="draggableElement"
> >
<div class="indexpage-container-box"> <div class="indexpage-container-box">
<img :src="imgUrl" class="indexpage-container-box-img" /> <img :src="imgUrl" alt="" class="indexpage-container-box-img" />
<div class="indexpage-container-box-point"> <div class="indexpage-container-box-point">
<!-- 连线 --> <!-- 连线 -->
@ -27,27 +27,11 @@
<template v-for="(item, index) in lineList" :key="index"> <template v-for="(item, index) in lineList" :key="index">
<!-- 定义箭头 --> <!-- 定义箭头 -->
<defs> <defs>
<marker <marker id="forward-arrow" viewBox="0 0 10 10" refX="10" refY="5" orient="auto">
id="forward-arrow"
viewBox="0 0 10 10"
refX="10"
refY="5"
orient="auto"
markerWidth="2"
markerHeight="2"
>
<path d="M 0 0 L 10 5 L 0 10 z" fill="black" /> <path d="M 0 0 L 10 5 L 0 10 z" fill="black" />
</marker> </marker>
<!-- 反向箭头 --> <!-- 反向箭头 -->
<marker <marker id="backward-arrow" viewBox="0 0 10 10" refX="0" refY="5" orient="auto">
id="backward-arrow"
viewBox="0 0 10 10"
refX="0"
refY="5"
orient="auto"
markerWidth="2"
markerHeight="2"
>
<path d="M 10 0 L 0 5 L 10 10 z" fill="black" /> <path d="M 10 0 L 0 5 L 10 10 z" fill="black" />
</marker> </marker>
</defs> </defs>
@ -58,7 +42,7 @@
:x2="Number(item.endPointX) * radio" :x2="Number(item.endPointX) * radio"
:y2="Number(item.endPointY) * radio" :y2="Number(item.endPointY) * radio"
:stroke="item.isSelect ? '#f48924' : '#00329F'" :stroke="item.isSelect ? '#f48924' : '#00329F'"
:stroke-width="4 * radio" :stroke-width="5 * radio"
:marker-start="item.direction === 2 ? 'url(#double-arrow-start)' : ''" :marker-start="item.direction === 2 ? 'url(#double-arrow-start)' : ''"
marker-end="url(#single-arrow)" marker-end="url(#single-arrow)"
@click="handleChooseRoute(item, index)" @click="handleChooseRoute(item, index)"
@ -67,7 +51,7 @@
:d="getLineMidArrowPath(item)" :d="getLineMidArrowPath(item)"
stroke="none" stroke="none"
fill="black" fill="black"
:stroke-width="4 * radio" stroke-width="4"
:marker-start="item.direction === 2 ? 'url(#backward-arrow)' : ''" :marker-start="item.direction === 2 ? 'url(#backward-arrow)' : ''"
:marker-end=" :marker-end="
item.direction === 2 ? 'url(#forward-arrow)' : 'url(#forward-arrow)' item.direction === 2 ? 'url(#forward-arrow)' : 'url(#forward-arrow)'
@ -78,7 +62,7 @@
<path <path
:d="getCurvePath(item)" :d="getCurvePath(item)"
:stroke="item.isSelect ? '#f48924' : '#00329F'" :stroke="item.isSelect ? '#f48924' : '#00329F'"
:stroke-width="4 * radio" :stroke-width="5 * radio"
fill="none" fill="none"
:marker-start="item.direction === 2 ? 'url(#backward-arrow)' : ''" :marker-start="item.direction === 2 ? 'url(#backward-arrow)' : ''"
:marker-end=" :marker-end="
@ -113,6 +97,7 @@
> >
<img <img
src="@/assets/imgs/indexPage/chache-4备份 7@2x.png" src="@/assets/imgs/indexPage/chache-4备份 7@2x.png"
alt=""
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
/> />
</div> </div>
@ -122,93 +107,199 @@
:key="index" :key="index"
:style="{ :style="{
left: left:
(Number(item.locationX) - Number(item.locationWidePx) / 2) * Number(radio) + 'px', (item.locationX - item.locationWide / 2 / nowObject.showYamlJson.resolution / 100) *
radio +
'px',
top: top:
(Number(item.locationY) - Number(item.locationDeepPx) / 2) * Number(radio) + 'px', (item.locationY - item.locationDeep / 2 / nowObject.showYamlJson.resolution / 100) *
width: Number(item.locationWidePx) * Number(radio) + 'px', radio +
height: Number(item.locationDeepPx) * Number(radio) + 'px' 'px'
}" }"
> >
<!-- 1 路径点 --> <!-- 库位点 -->
<el-tooltip class="box-item" effect="dark" :content="item.sortNum + ''" placement="top"> <div
class="indexpage-container-box-point-item-inner"
v-if="item.showData"
:style="{
width:
(item.showData.locationWide / nowObject.showYamlJson.resolution / 100) * radio +
'px',
height:
(item.showData.locationDeep / nowObject.showYamlJson.resolution / 100) * radio +
'px'
}"
>
<!-- 库位 2-->
<div v-if="item.type == 2" style="width: 100%; height: 100%;vertical-align: top;">
<el-popover placement="top-start" trigger="hover" width="auto">
<template #reference>
<img
:src="item.imgUrl"
alt=""
style="width: 100%; height: 100%"
@dblclick="storeClick(item)"
/>
</template>
<div class="indexpage-container-box-point-item-inner-popover">
<div
class="indexpage-container-box-point-item-inner-popover-item"
style="margin-bottom: 8px"
>
<div class="indexpage-container-box-point-item-inner-popover-name">
库位名
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.locationNo || '' }}
</div>
</div>
<div
class="indexpage-container-box-point-item-inner-popover-item"
style="margin-bottom: 8px"
>
<div class="indexpage-container-box-point-item-inner-popover-name">
所属线库
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.laneName || '' }}
</div>
</div>
<div
class="indexpage-container-box-point-item-inner-popover-item"
style="margin-bottom: 8px"
>
<div class="indexpage-container-box-point-item-inner-popover-name">
所属区域
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.areaName || '' }}
</div>
</div>
</div>
</el-popover>
</div>
<!-- 设备点 -->
<div v-if="item.type == 3">
<img
:src="item.formattedData.mapImageUrl"
alt=""
style="width: 100%; height: 100%"
/>
</div>
</div>
<!-- 设备点 -->
<div
class="indexpage-container-box-point-item-inner"
v-if="item.type == 3"
:style="{
width:
(item.formattedData.locationWide / nowObject.showYamlJson.resolution / 100) *
radio +
'px',
height:
(item.formattedData.locationDeep / nowObject.showYamlJson.resolution / 100) *
radio +
'px'
}"
>
<div>
<img
:src="
item.formattedData.mapImageUrl
? item.formattedData.mapImageUrl
: 'https://api.znkjfw.com/admin-api/infra/file/4/get/设备点_png_179_1739327151877.png'
"
alt=""
style="width: 100%; height: 100%"
/>
</div>
</div>
<!-- 停车点 -->
<div
class="indexpage-container-box-point-item-inner"
v-if="item.type == 4"
:style="{
width:
(item.formattedData.locationWide / nowObject.showYamlJson.resolution / 100) *
radio +
'px',
height:
(item.formattedData.locationDeep / nowObject.showYamlJson.resolution / 100) *
radio +
'px'
}"
>
<div>
<img
:src="
item.formattedData.mapImageUrl
? item.formattedData.mapImageUrl
: 'https://api.znkjfw.com/admin-api/infra/file/4/get/停车场-01_png_179_1739326933020.png'
"
alt=""
style="width: 100%; height: 100%"
/>
</div>
</div>
<!-- 路径点 -->
<div
class="indexpage-container-box-point-item-inner"
v-if="item.type == 5"
:style="{
width: 150 * radio + 'px',
height: 150 * radio + 'px'
}"
>
<div>
<img
:src="
item.formattedData.mapImageUrl
? item.formattedData.mapImageUrl
: 'https://api.znkjfw.com/admin-api/infra/file/4/get/区域_png_179_1739327151876.png'
"
alt=""
style="width: 100%; height: 100%"
/>
</div>
</div>
<!-- 等待点 -->
<div
class="indexpage-container-box-point-item-inner"
v-if="item.type == 6"
:style="{
width: 150 * radio + 'px',
height: 150 * radio + 'px'
}"
>
<div>
<img
:src="
item.formattedData.mapImageUrl
? item.formattedData.mapImageUrl
: 'https://api.znkjfw.com/admin-api/infra/file/4/get/等待点_png_179_1739326991439.png'
"
alt=""
style="width: 100%; height: 100%"
/>
</div>
</div>
<!-- 普通点 -->
<el-tooltip
class="box-item"
effect="dark"
:content="item.sortNum + ''"
placement="top"
v-if="item.type == 1"
>
<div <div
v-if="item.type === 1"
:style="{ :style="{
width: Number(item.locationWidePx) * Number(radio) + 'px', width: 10 * radio + 'px',
height: Number(item.locationDeepPx) * Number(radio) + 'px', height: 10 * radio + 'px',
backgroundColor: '#000', background: '#000',
borderRadius: '50%' borderRadius: '50%'
}" }"
> >
</div> </div>
</el-tooltip> </el-tooltip>
<!-- 库位点 -->
<el-popover placement="top-start" trigger="hover" width="auto">
<template #reference>
<img
v-if="item.showData && item.type == 2"
:src="item.imgUrl"
:style="nodeStyle(item, index)"
@dblclick="storeClick(item)"
/>
</template>
<div>
<div class="indexpage-popover-item">
<div> 库位名 </div>
<div>
{{ item.showData?.locationNo || '' }}
</div>
</div>
<div class="indexpage-popover-item">
<div> 所属线库 </div>
<div>
{{ item.showData?.laneName || '' }}
</div>
</div>
<div class="indexpage-popover-item">
<div> 所属区域 </div>
<div>
{{ item.showData?.areaName || '' }}
</div>
</div>
</div>
</el-popover>
<!-- 设备点 -->
<img
v-if="item.type == 3"
:src="
item.formattedData.mapImageUrl ||
'https://api.znkjfw.com/admin-api/infra/file/4/get/设备点_png_179_1739327151877.png'
"
:style="nodeStyle(item, index)"
/>
<!-- 停车点 -->
<img
v-if="item.type == 4"
:src="
item.formattedData.mapImageUrl ||
'https://api.znkjfw.com/admin-api/infra/file/4/get/停车场-01_png_179_1739326933020.png'
"
:style="nodeStyle(item, index)"
/>
<!-- 路径点 -->
<img
v-if="item.type == 5"
:src="
item.formattedData.mapImageUrl ||
'https://api.znkjfw.com/admin-api/infra/file/4/get/区域_png_179_1739327151876.png'
"
:style="nodeStyle(item, index)"
/>
<!-- 等待点 -->
<img
v-if="item.type == 6"
:src="
item.formattedData.mapImageUrl ||
'https://api.znkjfw.com/admin-api/infra/file/4/get/等待点_png_179_1739326991439.png'
"
:style="nodeStyle(item, index)"
/>
</div> </div>
</div> </div>
</div> </div>
@ -220,7 +311,7 @@
<div <div
class="affix-container-left-box-item-box" class="affix-container-left-box-item-box"
:style="{ :style="{
height: legendObj.legendShow ? '5.25rem' : '0', height: legendObj.legendShow ? '84px' : '0',
overflow: 'hidden', overflow: 'hidden',
transition: 'all 0.3s ease-in-out' transition: 'all 0.3s ease-in-out'
}" }"
@ -229,12 +320,14 @@
<div class="affix-container-left-box-item-left"> 行驶路线 </div> <div class="affix-container-left-box-item-left"> 行驶路线 </div>
<img <img
src="@/assets/imgs/indexPage/yanjing_xianshi_o.png" src="@/assets/imgs/indexPage/yanjing_xianshi_o.png"
alt=""
class="affix-container-left-box-item-img" class="affix-container-left-box-item-img"
v-if="legendObj.driveLineShow" v-if="legendObj.driveLineShow"
@click="changDriveLineShow" @click="changDriveLineShow"
/> />
<img <img
src="@/assets/imgs/indexPage/yanjing_yincang_o.png" src="@/assets/imgs/indexPage/yanjing_yincang_o.png"
alt=""
class="affix-container-left-box-item-img" class="affix-container-left-box-item-img"
v-if="!legendObj.driveLineShow" v-if="!legendObj.driveLineShow"
@click="changDriveLineShow" @click="changDriveLineShow"
@ -244,12 +337,14 @@
<div class="affix-container-left-box-item-left"> 车辆 </div> <div class="affix-container-left-box-item-left"> 车辆 </div>
<img <img
src="@/assets/imgs/indexPage/yanjing_xianshi_o.png" src="@/assets/imgs/indexPage/yanjing_xianshi_o.png"
alt=""
class="affix-container-left-box-item-img" class="affix-container-left-box-item-img"
v-if="legendObj.carShow" v-if="legendObj.carShow"
@click="changCarShow" @click="changCarShow"
/> />
<img <img
src="@/assets/imgs/indexPage/yanjing_yincang_o.png" src="@/assets/imgs/indexPage/yanjing_yincang_o.png"
alt=""
class="affix-container-left-box-item-img" class="affix-container-left-box-item-img"
v-if="!legendObj.carShow" v-if="!legendObj.carShow"
@click="changCarShow" @click="changCarShow"
@ -263,6 +358,7 @@
<div class="affix-container-left-box-item-bottom-left"> 图例 </div> <div class="affix-container-left-box-item-bottom-left"> 图例 </div>
<img <img
src="@/assets/imgs/indexPage/zhankai@2x.png" src="@/assets/imgs/indexPage/zhankai@2x.png"
alt=""
class="affix-container-left-box-item-bottom-img" class="affix-container-left-box-item-bottom-img"
:style="{ :style="{
transform: legendObj.legendShow ? 'rotate(180deg)' : 'rotate(0deg)', transform: legendObj.legendShow ? 'rotate(180deg)' : 'rotate(0deg)',
@ -277,12 +373,13 @@
<div class="affix-container-right" v-if="!isAllBoard"> <div class="affix-container-right" v-if="!isAllBoard">
<!-- 拖拽 --> <!-- 拖拽 -->
<div class="affix-container-right-item" @click="changeIsDrag"> <div class="affix-container-right-item" @click="changeIsDrag">
<img src="@/assets/imgs/indexPage/编组 12.png" style="width: 100%; height: 100%" /> <img src="@/assets/imgs/indexPage/编组 12.png" alt="" style="width: 100%; height: 100%" />
</div> </div>
<!-- 放大 --> <!-- 放大 -->
<div class="affix-container-right-item"> <div class="affix-container-right-item">
<img <img
src="@/assets/imgs/indexPage/编组 14.png" src="@/assets/imgs/indexPage/编组 14.png"
alt=""
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
@click="changeSizeRaio(0.2)" @click="changeSizeRaio(0.2)"
/> />
@ -291,6 +388,7 @@
<div class="affix-container-right-item"> <div class="affix-container-right-item">
<img <img
src="@/assets/imgs/indexPage/编组 15.png" src="@/assets/imgs/indexPage/编组 15.png"
alt=""
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
@click="changeSizeRaio(-0.2)" @click="changeSizeRaio(-0.2)"
/> />
@ -299,6 +397,7 @@
<div class="affix-container-right-item"> <div class="affix-container-right-item">
<img <img
src="@/assets/imgs/indexPage/编组 22.png" src="@/assets/imgs/indexPage/编组 22.png"
alt=""
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
@click="toggleFullScreen" @click="toggleFullScreen"
/> />
@ -338,32 +437,25 @@ const nowObject = ref(null) // 地图当前对象 父组件传过来的
const testCarList = ref([]) // const testCarList = ref([]) //
const carWidth = ref(60) const carWidth = ref(60)
const carHeight = ref(32) const carHeight = ref(32)
const nodeStyle = (item, index) => {
return {
verticalAlign: 'top',
objectFit: 'cover',
width: Number(item.locationWidePx) * Number(radio.value) + 'px',
height: Number(item.locationDeepPx) * Number(radio.value) + 'px'
}
}
// //
const props = defineProps({ const props = defineProps({
// //
isAllBoard: propTypes.bool.def(false) isAllBoard: propTypes.bool.def(false)
}) })
const convertActualToBrowser = (pointX, pointY) => { const convertActualToBrowser = (pointX, pointY) => {
let resolution = Number(nowObject.value.showYamlJson.resolution) const y1 =
let origin = nowObject.value.showYamlJson.origin Number(nowObject.value.showYamlJson.origin[1]) +
Number(nowObject.value.showYamlJson.height) * Number(nowObject.value.showYamlJson.resolution)
const y1 = Number(origin[1]) + Number(nowObject.value.showYamlJson.height) * resolution let x = Math.max(Number(pointX) - Number(nowObject.value.showYamlJson.origin[0]), 0)
let x = Math.max(Number(pointX) - Number(origin[0]), 0)
let y = Math.max(y1 - Number(pointY), 0) let y = Math.max(y1 - Number(pointY), 0)
return { return {
x: x / resolution - carWidth.value / resolution / 100 / 2, x:
y: y / resolution - carHeight.value / 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
} }
} }
// //
@ -413,12 +505,12 @@ const getCurvePath = (curve) => {
return `M ${startPointX} ${startPointY} C ${curve.beginControlX * radio.value} ${curve.beginControlY * radio.value}, ${curve.endControlX * radio.value} ${curve.endControlY * radio.value}, ${endPointX} ${endPointY}` return `M ${startPointX} ${startPointY} C ${curve.beginControlX * radio.value} ${curve.beginControlY * radio.value}, ${curve.endControlX * radio.value} ${curve.endControlY * radio.value}, ${endPointX} ${endPointY}`
} }
// //
const isSizeRadio = ref(1) const isSizeRaio = ref(1)
const changeSizeRaio = (type) => { const changeSizeRaio = (type) => {
if (type < 0 && isSizeRadio.value + type <= 0) { if (type < 0 && isSizeRaio.value + type <= 0) {
return return
} }
isSizeRadio.value += type isSizeRaio.value += type
} }
// //
const legendObj = reactive({ const legendObj = reactive({
@ -524,22 +616,33 @@ const toggleFullScreen = () => {
// //
const storeClick = async (item) => { const storeClick = async (item) => {
// console.log(item)
let storeData = await MapApi.houseLocationGetByMapItemId({ let storeData = await MapApi.houseLocationGetByMapItemId({
mapId: item.positionMapId, mapId: item.positionMapId,
mapItemId: item.id mapItemId: item.id
}) })
// console.log(storeData)
storeDialogRef.value.open(JSON.parse(JSON.stringify(storeData))) storeDialogRef.value.open(JSON.parse(JSON.stringify(storeData)))
} }
const lineList = ref([]) const lineList = ref([])
const pointList = ref([]) const pointList = ref([])
const getPositionMapListFun = async (positionMapId) => { const getPositionMapListFun = async (positionMapId) => {
pointList.value = await MapApi.getPositionMapItemList({ positionMapId: positionMapId }) // console.log(positionMapId)
let data = await MapApi.getPositionMapItemList({ positionMapId: positionMapId })
pointList.value?.forEach((item) => { // console.log(data)
item.formattedData = item.dataJson ? JSON.parse(item.dataJson) : '' if (data && data.length > 0) {
item.showData = item.dataJson ? JSON.parse(item.dataJson)[0] : null data.forEach((item) => {
item.imgUrl = formatTypeImg(item.type) // console.log(JSON.parse(item.dataJson))
item.formattedData = item.dataJson ? JSON.parse(item.dataJson) : ''
item.showData = item.dataJson ? JSON.parse(item.dataJson)[0] : null
item.imgUrl = formatteTypeImg(item.type)
})
}
// console.log(data)
pointList.value = data
// console.log('=======================', pointList.value)
pointList.value.forEach((item) => {
if (item.type === 1) { if (item.type === 1) {
item.locationDeep = 40 item.locationDeep = 40
item.locationWide = 40 item.locationWide = 40
@ -559,25 +662,10 @@ const getPositionMapListFun = async (positionMapId) => {
item.dataObj = JSONBigInt({ storeAsString: true }).parse(item.dataJson) item.dataObj = JSONBigInt({ storeAsString: true }).parse(item.dataJson)
item.locationDeep = item.dataObj.locationDeep item.locationDeep = item.dataObj.locationDeep
item.locationWide = item.dataObj.locationWide item.locationWide = item.dataObj.locationWide
} } else if (item.type === 7) {
//cmpx
if (item.locationWide && item.locationDeep) {
let pxObj = cmConversionPx(item.locationWide, item.locationDeep)
item.locationWidePx = pxObj.pWidth
item.locationDeepPx = pxObj.pHeight
} }
}) })
} }
//cmpx
const cmConversionPx = (cWidth, cHeight) => {
let pWidth = Number(cWidth) / Number(nowObject.value.showYamlJson.resolution) / 100
let pHeight = Number(cHeight) / Number(nowObject.value.showYamlJson.resolution) / 100
return {
pWidth,
pHeight
}
}
const draggableElement = ref(null) const draggableElement = ref(null)
const resetPosition = () => { const resetPosition = () => {
if (draggableElement.value) { if (draggableElement.value) {
@ -630,7 +718,7 @@ const calculateDistanceAndAngle = (point1, point2) => {
} }
} }
const formatTypeImg = (type) => { const formatteTypeImg = (type) => {
switch (type) { switch (type) {
case 1: case 1:
return '' return ''
@ -688,7 +776,7 @@ const linkWebSocket = (url) => {
[ [
h( h(
'span', 'span',
{ style: 'color: rgba(255,255,255,0.88);font-size: .875rem;' }, { style: 'color: rgba(255,255,255,0.88);font-size: 14px;' },
`${JSON.parse(jsonMsg.content)}` `${JSON.parse(jsonMsg.content)}`
), ),
h( h(
@ -696,7 +784,7 @@ const linkWebSocket = (url) => {
{ {
onClick: () => lookError(), onClick: () => lookError(),
style: style:
'color: rgba(255,255,255,0.88);font-size: .875rem;cursor: pointer;text-decoration-line: underline;margin-left: 2rem;' 'color: rgba(255,255,255,0.88);font-size: 14px;cursor: pointer;text-decoration-line: underline;margin-left: 32px;'
}, },
'详情' '详情'
) )
@ -735,8 +823,9 @@ const getMapData = async (item) => {
testCarList.value = [] testCarList.value = []
nowObject.value = JSON.parse(JSON.stringify(item)) nowObject.value = JSON.parse(JSON.stringify(item))
nowObject.value.showYamlJson = JSON.parse(item.yamlJson) nowObject.value.showYamlJson = JSON.parse(item.yamlJson)
let websocketUrl = `${replaceHttpWithWs(import.meta.env.VITE_BASE_URL)}/infra/ws?type=map&floor=${nowObject.value.floor}&area=${nowObject.value.area}` let websoketUrl = `${replaceHttpWithWs(import.meta.env.VITE_BASE_URL)}/infra/ws?type=map&floor=${nowObject.value.floor}&area=${nowObject.value.area}`
linkWebSocket(websocketUrl) // console.log(websoketUrl)
linkWebSocket(websoketUrl)
getPositionMapListFun(nowObject.value.id) getPositionMapListFun(nowObject.value.id)
emit('transmitMapInfo', { emit('transmitMapInfo', {
id: item.id, id: item.id,
@ -767,14 +856,17 @@ const computedRatio = () => {
// yaml // yaml
getImageSize(imgUrl.value) getImageSize(imgUrl.value)
.then(({ width, height }) => { .then(({ width, height }) => {
// console.log("",JSON.parse(nowObject.value.yamlJson))
if (testCarList.value.length) { if (testCarList.value.length) {
testCarList.value.forEach((item) => { testCarList.value.forEach((item) => {
console.log('dayin', item)
item.originWidth = width item.originWidth = width
item.originHeight = height item.originHeight = height
item.origin = JSON.parse(nowObject.value.yamlJson).origin item.origin = JSON.parse(nowObject.value.yamlJson).origin
item.realX = convertActualToBrowser(item.data.pose2d.x, item.data.pose2d.y).x item.realX = convertActualToBrowser(item.data.pose2d.x, item.data.pose2d.y).x
item.realY = convertActualToBrowser(item.data.pose2d.x, item.data.pose2d.y).y item.realY = convertActualToBrowser(item.data.pose2d.x, item.data.pose2d.y).y
}) })
// console.log('', testCarList.value)
} }
}) })
.catch((error) => { .catch((error) => {
@ -799,8 +891,10 @@ const computedRatio = () => {
} }
}) })
getImageWidth(imgUrl.value, 'height').then((res) => { getImageWidth(imgUrl.value, 'height').then((res) => {
// console.log('', res)
heightVal.value = res * radio.value heightVal.value = res * radio.value
}) })
// console.log(width)
} }
}) })
} }
@ -808,6 +902,7 @@ const computedRatio = () => {
// 线 // 线
const getMapLineList = () => { const getMapLineList = () => {
MapApi.mapLineListGet({ positionMapId: nowObject.value.id }).then((res) => { MapApi.mapLineListGet({ positionMapId: nowObject.value.id }).then((res) => {
// console.log(res)
lineList.value = res lineList.value = res
}) })
} }
@ -952,9 +1047,9 @@ onUnmounted(() => {
} }
.indexpage-container .affix-container-top { .indexpage-container .affix-container-top {
width: 100%; width: 100%;
height: 5rem; height: 80px;
background-color: #fff; background-color: #fff;
border-bottom: 0.0625rem solid #f5f5f5; border-bottom: 1px solid #f5f5f5;
} }
.indexpage-container-box-point { .indexpage-container-box-point {
width: 100%; width: 100%;
@ -965,12 +1060,11 @@ onUnmounted(() => {
right: 0; right: 0;
} }
.indexpage-container-box-point-item { .indexpage-container-box-point-item {
box-sizing: border-box;
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
} }
.scrollbar-flex-content { .scrollbar-flex-content {
padding: 0.125rem 0.375rem; padding: 2px 6px;
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
@ -980,11 +1074,11 @@ onUnmounted(() => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 5.625rem; width: 90px;
height: 1.875rem; height: 30px;
margin: 0.625rem 0.375rem; margin: 10px 6px;
text-align: center; text-align: center;
border-radius: 0.25rem; border-radius: 4px;
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
color: var(--el-color-primary); color: var(--el-color-primary);
position: relative; position: relative;
@ -1005,15 +1099,14 @@ onUnmounted(() => {
width: 100%; width: 100%;
height: auto; height: auto;
} }
.indexpage-popover-item { .indexpage-container-box-point-item-inner-popover-item {
display: flex; display: flex;
font-family: font-family:
PingFangSC, PingFangSC,
PingFang SC; PingFang SC;
font-weight: 400; font-weight: 400;
font-size: 0.875rem; font-size: 14px;
color: #0d162a; color: #0d162a;
margin-bottom: 0.5rem;
} }
.line-box { .line-box {
position: absolute; position: absolute;
@ -1024,21 +1117,21 @@ onUnmounted(() => {
} }
.affix-container-left { .affix-container-left {
position: fixed; position: fixed;
bottom: 1.625rem; bottom: 26px;
z-index: 999; z-index: 999;
} }
.affix-container-left-box { .affix-container-left-box {
width: 9rem; width: 144px;
} }
.affix-container-left-box-item-box { .affix-container-left-box-item-box {
width: 100%; width: 100%;
border-bottom: 0.0625rem solid #eeeeee; border-bottom: 1px solid #eeeeee;
background: #ffffff; background: #ffffff;
} }
.affix-container-left-box-item { .affix-container-left-box-item {
width: 100%; width: 100%;
padding: 0 1.125rem; padding: 0 18px;
height: 2.625rem; height: 42px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -1048,18 +1141,18 @@ onUnmounted(() => {
PingFangSC, PingFangSC,
PingFang SC; PingFang SC;
font-weight: 400; font-weight: 400;
font-size: 0.875rem; font-size: 14px;
color: rgba(0, 0, 0, 0.88); color: rgba(0, 0, 0, 0.88);
} }
.affix-container-left-box-item-img { .affix-container-left-box-item-img {
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
width: 1.25rem; width: 20px;
height: 0.75rem; height: 12px;
} }
.affix-container-left-box-item-bottom { .affix-container-left-box-item-bottom {
width: 100%; width: 100%;
height: 2.25rem; height: 36px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -1069,8 +1162,8 @@ onUnmounted(() => {
.affix-container-left-box-item-bottom-img { .affix-container-left-box-item-bottom-img {
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
width: 0.75rem; width: 12px;
height: 0.4375rem; height: 7px;
} }
.affix-container-left-box-item-bottom-left { .affix-container-left-box-item-bottom-left {
cursor: pointer; cursor: pointer;
@ -1079,24 +1172,24 @@ onUnmounted(() => {
PingFangSC, PingFangSC,
PingFang SC; PingFang SC;
font-weight: 400; font-weight: 400;
font-size: 1rem; font-size: 16px;
color: #98a4bf; color: #98a4bf;
margin-right: 0.125rem; margin-right: 2px;
} }
.affix-container-right { .affix-container-right {
position: fixed; position: fixed;
z-index: 999; z-index: 999;
right: 2.5rem; right: 40px;
bottom: 1.25rem; bottom: 20px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
} }
.affix-container-right-item { .affix-container-right-item {
width: 1.75rem; width: 28px;
height: 1.75rem; height: 28px;
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
margin-left: 0.5rem; margin-left: 8px;
} }
</style> </style>

View File

@ -333,6 +333,7 @@
> >
<!-- 1 路径点 --> <!-- 1 路径点 -->
<el-tooltip <el-tooltip
class="box-item"
effect="dark" effect="dark"
:content="item.sortNum || '节点未保存'" :content="item.sortNum || '节点未保存'"
placement="top" placement="top"
@ -421,7 +422,7 @@
:x2="Number(state.currentDrawX)" :x2="Number(state.currentDrawX)"
:y2="Number(state.currentDrawY)" :y2="Number(state.currentDrawY)"
stroke="#00329F" stroke="#00329F"
stroke-width="4" stroke-width="3"
/> />
<template v-if="state.mapRouteList.length > 0"> <template v-if="state.mapRouteList.length > 0">
<template v-for="(curve, index) in state.mapRouteList" :key="index"> <template v-for="(curve, index) in state.mapRouteList" :key="index">
@ -1154,12 +1155,12 @@ const state = reactive({
icon: 'ep:semi-select', icon: 'ep:semi-select',
isActive: false isActive: false
}, },
// { {
// switchType: 'drawRoute', switchType: 'drawRoute',
// name: '', name: '框选绘制',
// icon: 'ep:semi-select', icon: 'ep:semi-select',
// isActive: false isActive: false
// }, },
{ {
switchType: 'editRoute', switchType: 'editRoute',
name: '编辑路线', name: '编辑路线',
@ -2025,45 +2026,45 @@ const clickDrawSelectionArea = () => {
} }
// 线 // 线
const mapPointsToLine = (points) => { const mapPointsToLine = (points) => {
// locationX if (points.length < 2) {
let minXPoint = points[0] return points
let maxXPoint = points[0] }
points.forEach((point) => { //
if (point.locationX < minXPoint.locationX) { const firstPoint = points[0]
minXPoint = point const lastPoint = points[points.length - 1]
}
if (point.locationX > maxXPoint.locationX) {
maxXPoint = point
}
})
const dx = maxXPoint.locationX - minXPoint.locationX // 线
const dy = maxXPoint.locationY - minXPoint.locationY const dx = lastPoint.locationX - firstPoint.locationX
const dy = lastPoint.locationY - firstPoint.locationY
// 线
if (dx === 0) { if (dx === 0) {
return points.map((point) => { // 线
if (point === minXPoint || point === maxXPoint) { return points.map((point, index) => {
if (index === 0 || index === points.length - 1) {
return point return point
} }
return { return {
...point, ...point,
locationX: minXPoint.locationX locationX: firstPoint.locationX,
locationY: point.locationY
} }
}) })
} }
const slope = dy / dx const slope = dy / dx
const intercept = minXPoint.locationY - slope * minXPoint.locationX // 线
const intercept = firstPoint.locationY - slope * firstPoint.locationX
return points.map((point) => { // 线
if (point === minXPoint || point === maxXPoint) { return points.map((point, index) => {
if (index === 0 || index === points.length - 1) {
return point return point
} }
const newY = slope * point.locationX + intercept const newY = slope * point.locationX + intercept
//
const roundedY = parseFloat(newY.toFixed(8))
return { return {
...point, ...point,
locationY: newY locationY: roundedY
} }
}) })
} }

View File

@ -1,130 +1,94 @@
<template> <template>
<div <div style="width: 600px; height: 300px; background: #dbeede; position: relative">
@mousedown="startSelection" <div v-for="(item, index) in points" :key="index">
@mousemove="updateSelection" <div
@mouseup="endSelection" :style="{
style="position: relative; width: 100vw; height: 100vh" position: 'absolute',
> width: '10px',
<!-- 绘制所有框选区域 --> height: '10px',
<div backgroundColor: '#000',
v-for="(rect, index) in selectionRects" borderRadius: '50%',
:key="index" zIndex: 999,
:style="{ left: item.x + 'px',
position: 'absolute', top: item.y + 'px'
left: `${rect.left}px`, }"
top: `${rect.top}px`, ></div>
width: `${rect.width}px`, </div>
height: `${rect.height}px`, </div>
backgroundColor: 'rgba(0, 0, 255, 0.2)', <div style="width: 600px; height: 300px; background: #b3dcff; position: relative">
border: '1px solid blue' <div v-for="(item, index) in mappedPoints" :key="index">
}" <div
></div> :style="{
position: 'absolute',
<!-- 绘制点位 --> width: '10px',
<div height: '10px',
v-for="(point, index) in points" backgroundColor: '#000',
:key="index" borderRadius: '50%',
:style="{ zIndex: 999,
position: 'absolute', left: item.x + 'px',
left: `${point.x}px`, top: item.y + 'px'
top: `${point.y}px`, }"
width: '10px', ></div>
height: '10px', </div>
backgroundColor: selectedPoints.includes(point) ? 'red' : 'green',
borderRadius: '50%'
}"
></div>
<!-- 确认按钮 -->
<button @click="confirmSelection" style="position: fixed; bottom: 20px; right: 20px">
确认
</button>
</div> </div>
</template> </template>
<script> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
export default { const points = ref([
setup() { {
const points = ref([ x: 123.567,
{ x: 10, y: 10 }, y: 178.123
{ x: 30, y: 100 }, },
{ x: 40, y: 40 }, {
{ x: 230, y: 400 }, x: 255.567,
{ x: 750, y: 640 } y: 79.123
]) },
{
const isSelecting = ref(false) x: 382.567,
const startPos = ref({ x: 0, y: 0 }) y: 178.123
const currentRect = ref({ left: 0, top: 0, width: 0, height: 0 }) },
const selectionRects = ref([]) // {
const selectedPoints = ref([]) // x: 481.567,
const selectedPointsInOrder = ref([]) // y: 238.123
//
const startSelection = (event) => {
isSelecting.value = true
startPos.value = { x: event.clientX, y: event.clientY }
currentRect.value = { left: event.clientX, top: event.clientY, width: 0, height: 0 }
}
//
const updateSelection = (event) => {
if (isSelecting.value) {
currentRect.value = {
left: Math.min(startPos.value.x, event.clientX),
top: Math.min(startPos.value.y, event.clientY),
width: Math.abs(event.clientX - startPos.value.x),
height: Math.abs(event.clientY - startPos.value.y)
}
}
}
//
const endSelection = () => {
if (isSelecting.value) {
isSelecting.value = false
selectionRects.value.push({ ...currentRect.value }) //
checkPointsInSelection(currentRect.value) //
}
}
//
const checkPointsInSelection = (rect) => {
points.value.forEach((point) => {
if (
point.x >= rect.left &&
point.x <= rect.left + rect.width &&
point.y >= rect.top &&
point.y <= rect.top + rect.height &&
!selectedPoints.value.includes(point) //
) {
selectedPoints.value.push(point)
selectedPointsInOrder.value.push(point) //
}
})
}
//
const confirmSelection = () => {
console.log('Selected Points in Order:', selectedPointsInOrder.value)
//
selectionRects.value = []
selectedPoints.value = []
selectedPointsInOrder.value = []
}
return {
points,
isSelecting,
selectionRects,
selectedPoints,
startSelection,
updateSelection,
endSelection,
confirmSelection
}
} }
])
const mapPointsToLine = (points) => {
if (points.length < 2) {
return points
}
//
const firstPoint = points[0]
const lastPoint = points[points.length - 1]
// 线
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)
console.log(mappedPoints)
</script> </script>

View File

@ -551,13 +551,13 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item <div style="width: 100%; display: flex; align-items: center">
required <el-form-item
label="放货位置" required
:prop="`taskDetailList[${index}].releaseId`" label="放货位置"
:rules="{ required: true, message: '放货位置不能为空', trigger: 'change' }" :prop="`taskDetailList[${index}].releaseId`"
> :rules="{ required: true, message: '放货位置不能为空', trigger: 'change' }"
<div style="width: 100%; display: flex; align-items: center"> >
<el-select <el-select
:disabled="!detailItem.releaseType" :disabled="!detailItem.releaseType"
v-model="detailItem.releaseId" v-model="detailItem.releaseId"
@ -579,15 +579,15 @@
:value="item.id" :value="item.id"
/> />
</el-select> </el-select>
<el-icon </el-form-item>
class="ml-2" <el-icon
size="20" class="ml-2"
color="#00329F" size="20"
@click="chooseLocation('release', detailItem, index)" color="#00329F"
><Location /> @click="chooseLocation('release', detailItem, index)"
</el-icon> ><Location />
</div> </el-icon>
</el-form-item> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="24"> <el-row :gutter="24">