地图编辑

This commit is contained in:
yyy 2025-02-26 17:41:03 +08:00
parent 6db5611af3
commit d74f617af9
9 changed files with 185 additions and 120 deletions

View File

@ -1,6 +1,12 @@
<template> <template>
<!-- 新增设备 --> <!-- 新增设备 -->
<Dialog v-model="dialogFormVisible" title="编辑路线" width="780" class="map-edit-route-dialog"> <Dialog
v-model="dialogFormVisible"
title="编辑路线"
width="780"
class="map-edit-route-dialog"
@close="dialogClose"
>
<el-form :model="form" label-width="120" ref="ruleFormRef"> <el-form :model="form" label-width="120" ref="ruleFormRef">
<el-row :gutter="30"> <el-row :gutter="30">
<el-col :span="12"> <el-col :span="12">
@ -215,7 +221,11 @@ const open = (item) => {
form.value = item form.value = item
} }
const emit = defineEmits(['editMapRouteDialogSubmit']) const dialogClose = () => {
emit('addEventListener')
}
const emit = defineEmits(['editMapRouteDialogSubmit', 'addEventListener'])
const submitForm = async (formEl) => { const submitForm = async (formEl) => {
if (!formEl) return if (!formEl) return
await formEl.validate(async (valid, fields) => { await formEl.validate(async (valid, fields) => {

View File

@ -1,5 +1,11 @@
<template> <template>
<Dialog v-model="dialogFormVisible" title="节点属性" width="540" class="node-form-dialog"> <Dialog
v-model="dialogFormVisible"
title="节点属性"
width="540"
class="node-form-dialog"
@close="dialogClose"
>
<el-form :model="form" label-width="auto" ref="ruleFormRef"> <el-form :model="form" label-width="auto" ref="ruleFormRef">
<el-form-item <el-form-item
label="X" label="X"
@ -169,7 +175,7 @@ const rules = reactive({
layersNumber: [{ required: true, message: '请输入层数', trigger: 'blur' }] layersNumber: [{ required: true, message: '请输入层数', trigger: 'blur' }]
}) })
const emit = defineEmits(['submitNodeSuccess']) const emit = defineEmits(['submitNodeSuccess', 'addEventListener'])
const submit = async (formEl) => { const submit = async (formEl) => {
if (!formEl) return if (!formEl) return
await formEl.validate((valid, fields) => { await formEl.validate((valid, fields) => {
@ -236,6 +242,10 @@ const submit = async (formEl) => {
}) })
} }
const dialogClose = () => {
emit('addEventListener')
}
const equipmentList = ref([]) // const equipmentList = ref([]) //
const open = (item, list) => { const open = (item, list) => {
form.value = item form.value = item

View File

@ -1,5 +1,11 @@
<template> <template>
<Dialog v-model="dialogFormVisible" title="设备" width="586" class="equipment-form-dialog"> <Dialog
v-model="dialogFormVisible"
title="设备"
width="586"
class="equipment-form-dialog"
@close="dialogClose"
>
<div class="device-list"> <div class="device-list">
<div class="device-item" v-for="(item, index) in deviceList" :key="index"> <div class="device-item" v-for="(item, index) in deviceList" :key="index">
<img class="img" :src="item.url" /> <img class="img" :src="item.url" />
@ -145,6 +151,11 @@ const open = (list) => {
getDeviceList() getDeviceList()
} }
const emit = defineEmits(['addEventListener'])
const dialogClose = () => {
emit('addEventListener')
}
const initAddForm = () => { const initAddForm = () => {
deviceInfo.value.deviceInfoId = '' deviceInfo.value.deviceInfoId = ''
deviceInfo.value.deviceType = '' deviceInfo.value.deviceType = ''

View File

@ -4,6 +4,7 @@
title="区域管理" title="区域管理"
width="600" width="600"
class="item-area-management-dialog" class="item-area-management-dialog"
@close="dialogClose"
> >
<el-table <el-table
:data="list" :data="list"
@ -55,6 +56,11 @@ const open = () => {
getWareHouseList() getWareHouseList()
} }
const emit = defineEmits(['addEventListener'])
const dialogClose = () => {
emit('addEventListener')
}
const loading = ref(true) // const loading = ref(true) //
const total = ref(0) // const total = ref(0) //
const list = ref() const list = ref()

View File

@ -5,6 +5,7 @@
title="物料区域设置" title="物料区域设置"
width="600" width="600"
class="equipment-form-dialog" class="equipment-form-dialog"
@close="dialogClose"
> >
<el-form :model="form" label-width="110" ref="ruleFormRef"> <el-form :model="form" label-width="110" ref="ruleFormRef">
<el-form-item label="物料区域名称" prop="skuInfo" required> <el-form-item label="物料区域名称" prop="skuInfo" required>
@ -64,6 +65,11 @@ const open = (list) => {
form.value.skuInfo = '' form.value.skuInfo = ''
} }
const emit = defineEmits(['addEventListener'])
const dialogClose = () => {
emit('addEventListener')
}
const submitForm = async (formEl) => { const submitForm = async (formEl) => {
if (!formEl) return if (!formEl) return
await formEl.validate(async (valid, fields) => { await formEl.validate(async (valid, fields) => {

View File

@ -4,6 +4,7 @@
title="线库管理" title="线库管理"
width="600" width="600"
class="line-library-management-dialog" class="line-library-management-dialog"
@close="dialogClose"
> >
<el-table <el-table
:data="list" :data="list"
@ -54,6 +55,11 @@ const open = () => {
getLineLibraryList() getLineLibraryList()
} }
const emit = defineEmits(['addEventListener'])
const dialogClose = () => {
emit('addEventListener')
}
const loading = ref(true) // const loading = ref(true) //
const total = ref(0) // const total = ref(0) //
const list = ref() const list = ref()

View File

@ -1,6 +1,12 @@
<template> <template>
<!-- 新增设备 --> <!-- 新增设备 -->
<Dialog v-model="dialogFormVisible" title="线库设置" width="600" class="equipment-form-dialog"> <Dialog
v-model="dialogFormVisible"
title="线库设置"
width="600"
class="equipment-form-dialog"
@close="dialogClose"
>
<el-form :model="form" label-width="110" ref="lineFormRef" :rules="rules"> <el-form :model="form" label-width="110" ref="lineFormRef" :rules="rules">
<el-form-item label="线库名称" prop="laneName" required> <el-form-item label="线库名称" prop="laneName" required>
<el-input v-model="form.laneName" placeholder="请输入线库名称" /> <el-input v-model="form.laneName" placeholder="请输入线库名称" />
@ -53,6 +59,11 @@ const open = (list) => {
form.value.laneName = '' form.value.laneName = ''
} }
const emit = defineEmits(['addEventListener'])
const dialogClose = () => {
emit('addEventListener')
}
const submitLineLibraryForm = async () => { const submitLineLibraryForm = async () => {
await lineFormRef.value.validate(async (valid, fields) => { await lineFormRef.value.validate(async (valid, fields) => {
if (valid) { if (valid) {

View File

@ -527,6 +527,7 @@
ref="editNodePropertiesRef" ref="editNodePropertiesRef"
:positionMapId="imgBgObj.positionMapId" :positionMapId="imgBgObj.positionMapId"
@submitNodeSuccess="submitNodeSuccess" @submitNodeSuccess="submitNodeSuccess"
@addEventListener="addEventListener"
/> />
<!-- 文字输入弹窗 --> <!-- 文字输入弹窗 -->
<textFormToolDialog <textFormToolDialog
@ -542,29 +543,41 @@
@layerSelectionSuccess="layerSelectionSuccess" @layerSelectionSuccess="layerSelectionSuccess"
/> />
<!-- 设备弹窗选择 --> <!-- 设备弹窗选择 -->
<equipmentToolDialog ref="equipmentToolDialogRef" :positionMapId="imgBgObj.positionMapId" /> <equipmentToolDialog
ref="equipmentToolDialogRef"
:positionMapId="imgBgObj.positionMapId"
@addEventListener="addEventListener"
/>
<!-- 区域选择 --> <!-- 区域选择 -->
<itemAreaSettingDialog ref="itemAreaSettingDialogRef" :positionMapId="imgBgObj.positionMapId" /> <itemAreaSettingDialog
ref="itemAreaSettingDialogRef"
:positionMapId="imgBgObj.positionMapId"
@addEventListener="addEventListener"
/>
<!-- 线库设置 --> <!-- 线库设置 -->
<lineLibrarySettingDialog <lineLibrarySettingDialog
ref="lineLibrarySettingDialogRef" ref="lineLibrarySettingDialogRef"
:positionMapId="imgBgObj.positionMapId" :positionMapId="imgBgObj.positionMapId"
@addEventListener="addEventListener"
/> />
<!-- 编辑地图路线 --> <!-- 编辑地图路线 -->
<editMapRouteDialog <editMapRouteDialog
ref="editMapRouteDialogRef" ref="editMapRouteDialogRef"
@editMapRouteDialogSubmit="editMapRouteDialogSubmit" @editMapRouteDialogSubmit="editMapRouteDialogSubmit"
@addEventListener="addEventListener"
:imgBgObj="imgBgObj" :imgBgObj="imgBgObj"
/> />
<!-- 线库管理 --> <!-- 线库管理 -->
<lineLibraryManagementDialog <lineLibraryManagementDialog
ref="lineLibraryManagementDialogRef" ref="lineLibraryManagementDialogRef"
:positionMapId="imgBgObj.positionMapId" :positionMapId="imgBgObj.positionMapId"
@addEventListener="addEventListener"
/> />
<!-- 区域管理 --> <!-- 区域管理 -->
<itemAreaManagementDialog <itemAreaManagementDialog
ref="itemAreaManagementDialogRef" ref="itemAreaManagementDialogRef"
:positionMapId="imgBgObj.positionMapId" :positionMapId="imgBgObj.positionMapId"
@addEventListener="addEventListener"
/> />
</div> </div>
</template> </template>
@ -693,6 +706,7 @@ const activatedHandle = (item, index) => {
// //
if (toolbarSwitchType.value === 'editNode' && item.type !== 7) { if (toolbarSwitchType.value === 'editNode' && item.type !== 7) {
let list = state.allMapPointInfo.filter((item) => item.type === 3) let list = state.allMapPointInfo.filter((item) => item.type === 3)
removeEventListener() //
editNodePropertiesRef.value.open(JSON.parse(JSON.stringify(item)), list) editNodePropertiesRef.value.open(JSON.parse(JSON.stringify(item)), list)
} }
} }
@ -1222,9 +1236,11 @@ const toolbarClick = async (item) => {
break break
case 'lineLibraryManage': case 'lineLibraryManage':
// 线 // 线
removeEventListener() //
lineLibraryManagementDialogRef.value.open() lineLibraryManagementDialogRef.value.open()
break break
case 'regionManage': case 'regionManage':
removeEventListener() //
itemAreaManagementDialogRef.value.open() itemAreaManagementDialogRef.value.open()
// //
break break
@ -1307,6 +1323,7 @@ const toolbarClick = async (item) => {
let equipmentList = state.allMapPointInfo.filter((item) => { let equipmentList = state.allMapPointInfo.filter((item) => {
return item.type === 3 return item.type === 3
}) })
removeEventListener() //
equipmentToolDialogRef.value.open(equipmentList) equipmentToolDialogRef.value.open(equipmentList)
break break
} }
@ -1628,6 +1645,7 @@ const clickDrawSelectionArea = () => {
message.warning('您选择的库位存在未保存的') message.warning('您选择的库位存在未保存的')
return return
} }
removeEventListener() //
lineLibrarySettingDialogRef.value.open(binLocation) lineLibrarySettingDialogRef.value.open(binLocation)
} }
// //
@ -1643,6 +1661,7 @@ const clickDrawSelectionArea = () => {
message.warning('您选择的库位存在未保存的') message.warning('您选择的库位存在未保存的')
return return
} }
removeEventListener() //
itemAreaSettingDialogRef.value.open(binLocation) itemAreaSettingDialogRef.value.open(binLocation)
} }
@ -1797,6 +1816,7 @@ const handleEditRoute = (item, index) => {
}) })
state.currentDragTarget.index = index state.currentDragTarget.index = index
state.selectedCurve = item state.selectedCurve = item
removeEventListener() //
editMapRouteDialogRef.value.open(JSON.parse(JSON.stringify(item))) editMapRouteDialogRef.value.open(JSON.parse(JSON.stringify(item)))
} }
// //
@ -1965,7 +1985,7 @@ const getAllNodeList = async () => {
item.dataList = [] item.dataList = []
item.locationDeep = 50 item.locationDeep = 50
item.locationWide = 50 item.locationWide = 50
item.draggable = false item.draggable = true
item.resizable = false item.resizable = false
item.rotatable = false item.rotatable = false
item.lockAspectRatio = true item.lockAspectRatio = true
@ -2137,6 +2157,22 @@ const cmConversionPx = (cWidth, cHeight) => {
pHeight pHeight
} }
} }
//
const getSingleArrowStart = (item) => {
let distance =
Math.sqrt((item.endPointX - item.startPointX) ** 2 + (item.endPointY - item.startPointY) ** 2) /
2 +
10
return distance
}
const getDoubleArrowStart = (item) => {
let distance =
Math.sqrt((item.endPointX - item.startPointX) ** 2 + (item.endPointY - item.startPointY) ** 2) /
2 -
10
return distance
}
document.onmousedown = function (e) { document.onmousedown = function (e) {
// //
@ -2153,7 +2189,6 @@ document.onmousedown = function (e) {
window.document.oncontextmenu = function () { window.document.oncontextmenu = function () {
return false return false
} }
// //
const handleKeyDown = (event) => { const handleKeyDown = (event) => {
if (event.ctrlKey) { if (event.ctrlKey) {
@ -2181,6 +2216,13 @@ const handleKeyDown = (event) => {
} }
} }
const addEventListener = () => {
window.addEventListener('keydown', handleKeyDown)
}
const removeEventListener = () => {
window.removeEventListener('keydown', handleKeyDown)
}
onMounted(() => { onMounted(() => {
getMapList() getMapList()
window.addEventListener('keydown', handleKeyDown) window.addEventListener('keydown', handleKeyDown)

View File

@ -1,32 +1,56 @@
<template> <template>
<div class="box"> <div>
<svg :width="boxWidth" :height="boxHeight"> <!-- 控制箭头朝向的选择框 -->
<select v-model="arrowDirection">
<option value="right">向右</option>
<option value="left">向左</option>
<option value="up">向上</option>
<option value="down">向下</option>
</select>
<!-- 控制单向或双向箭头的选择框 -->
<select v-model="isDoubleArrow">
<option value="false">单向箭头</option>
<option value="true">双向箭头</option>
</select>
<!-- 控制箭头大小的输入框 -->
<input type="number" v-model="arrowSize" min="1" max="50" placeholder="箭头大小" />
<!-- SVG容器 -->
<svg width="200" height="200">
<!-- 定义箭头样式 -->
<defs>
<!-- 单向箭头 -->
<marker
id="single-arrow"
viewBox="0 0 10 10"
refX="10"
refY="5"
markerWidth=":arrowSize"
markerHeight=":arrowSize"
orient="auto-start-reverse"
>
<path d="M 0 0 L 10 5 L 0 10 z" fill="black" />
</marker>
<!-- 双向箭头 -->
<marker
id="double-arrow-start"
viewBox="0 0 10 10"
refX="0"
refY="5"
markerWidth=":arrowSize"
markerHeight=":arrowSize"
orient="auto-start-reverse"
>
<path d="M 10 0 L 0 5 L 10 10 z" fill="black" />
</marker>
</defs>
<!-- 根据变量绘制线条 -->
<path <path
v-for="(curve, index) in curves" :d="getPath()"
:key="index" stroke="black"
:d="getCurvePath(curve)"
:stroke="curve.isSelected ? 'red' : 'blue'"
stroke-width="2" stroke-width="2"
fill="none" fill="none"
@mousedown="selectCurve(index)" :marker-start="isDoubleArrow === 'true' ? 'url(#double-arrow-start)' : ''"
/> :marker-end="isDoubleArrow === 'true' ? 'url(#single-arrow)' : 'url(#single-arrow)'"
<circle
v-for="(curve, index) in curves"
:key="'start-' + index"
:cx="curve.startControlX"
:cy="curve.startControlY"
r="5"
fill="green"
@mousedown="startDrag(index, 'start')"
/>
<circle
v-for="(curve, index) in curves"
:key="'end-' + index"
:cx="curve.endControlX"
:cy="curve.endControlY"
r="5"
fill="green"
@mousedown="startDrag(index, 'end')"
/> />
</svg> </svg>
</div> </div>
@ -35,93 +59,32 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
// //
const boxWidth = ref(800) const arrowDirection = ref('right')
const boxHeight = ref(600) const isDoubleArrow = ref('false')
const arrowSize = ref(10)
// //
const curves = ref([ const getPath = () => {
{ let startX = 20
startX: 100, let startY = 100
startY: 100, let endX = 180
endX: 300, let endY = 100
endY: 100,
startControlX: 100, switch (arrowDirection.value) {
startControlY: 100, case 'left':
endControlX: 300, ;[startX, endX] = [endX, startX]
endControlY: 100, break
isSelected: false case 'up':
}, startY = 180
{ endY = 20
startX: 200, break
startY: 200, case 'down':
endX: 400, startY = 20
endY: 200, endY = 180
startControlX: 200, break
startControlY: 200,
endControlX: 400,
endControlY: 400,
isSelected: false
} }
])
// 线 return `M ${startX} ${startY} L ${endX} ${endY}`
const dragging = ref({
index: null,
type: null
})
// 线
const getCurvePath = (curve) => {
return `M${curve.startX},${curve.startY} C${curve.startControlX},${curve.startControlY} ${curve.endControlX},${curve.endControlY} ${curve.endX},${curve.endY}`
}
// 线
const selectCurve = (index) => {
curves.value.forEach((curve, i) => {
curve.isSelected = i === index
})
console.log('Selected curve:', curves.value[index])
}
//
const startDrag = (index, type) => {
dragging.value = { index, type }
window.addEventListener('mousemove', handleDrag)
window.addEventListener('mouseup', endDrag)
}
//
const handleDrag = (event) => {
if (dragging.value.index !== null) {
const curve = curves.value[dragging.value.index]
let newX = event.offsetX
let newY = event.offsetY
//
newX = Math.max(0, Math.min(newX, boxWidth.value))
newY = Math.max(0, Math.min(newY, boxHeight.value))
if (dragging.value.type === 'start') {
curve.startControlX = newX
curve.startControlY = newY
} else {
curve.endControlX = newX
curve.endControlY = newY
}
}
}
//
const endDrag = () => {
dragging.value = { index: null, type: null }
window.removeEventListener('mousemove', handleDrag)
window.removeEventListener('mouseup', endDrag)
} }
</script> </script>
<style scoped>
.box {
border: 1px solid black;
}
</style>