This commit is contained in:
xhf 2025-02-13 17:39:31 +08:00
commit 168c463451
10 changed files with 761 additions and 262 deletions

View File

@ -79,3 +79,11 @@ export const getDeviceInformationList = async (params) => {
export const mapBindDeviceInfo = async (data) => {
return await request.post({ url: `/system/device/information/mapBindDeviceInfo`, data })
}
//创建修改删除库区
export const createOrEditOrDelHouseArea = async (data) => {
return await request.post({ url: `/system/ware/house-area/createOrEditOrDel`, data })
}
//创建修改删除线库
export const createOrEditOrDelHouseLane = async (data) => {
return await request.post({ url: `/system/ware/house-lane/createOrEditOrDel`, data })
}

View File

@ -25,7 +25,12 @@
required
v-if="form.type === 2"
>
<el-input-number v-model="form.layersNumber" :min="1" :max="3" />
<el-input-number
v-model="form.layersNumber"
:min="1"
:max="3"
@change="layersNumberChange"
/>
</el-form-item>
<el-form-item
label="编号"
@ -77,31 +82,33 @@
<span class="ml-2">cm</span>
</div>
</el-form-item>
<el-form-item label="库位方向" prop="direction">
<el-select
v-model="form.direction"
placeholder="请选择库位方向"
@change="directionChange"
>
<el-option label="单向" :value="1" />
<el-option label="双向" :value="2" />
<el-option label="三向" :value="3" />
<el-option label="四向" :value="4" />
</el-select>
</el-form-item>
<div v-if="form.direction !== 1">
<el-form-item label="进入方向" prop="inDirection">
<el-select v-model="form.inDirection" placeholder="请选择进入方向">
<el-option label="尾入" :value="0" />
<el-option label="头入" :value="1" />
</el-select>
</el-form-item>
<el-form-item label="离开方向" prop="outDirection">
<el-select v-model="form.outDirection" placeholder="请选择离开方向">
<el-option label="尾出" :value="0" />
<el-option label="头出" :value="1" />
<div v-if="form.type === 2 || form.type === 4">
<el-form-item label="库位方向" prop="direction">
<el-select
v-model="form.direction"
placeholder="请选择库位方向"
@change="directionChange"
>
<el-option label="单向" :value="1" />
<el-option label="双向" :value="2" />
<el-option label="三向" :value="3" />
<el-option label="四向" :value="4" />
</el-select>
</el-form-item>
<div v-if="form.direction !== 1">
<el-form-item label="进入方向" prop="inDirection">
<el-select v-model="form.inDirection" placeholder="请选择进入方向">
<el-option label="尾入" :value="0" />
<el-option label="头入" :value="1" />
</el-select>
</el-form-item>
<el-form-item label="离开方向" prop="outDirection">
<el-select v-model="form.outDirection" placeholder="请选择离开方向">
<el-option label="尾出" :value="0" />
<el-option label="头出" :value="1" />
</el-select>
</el-form-item>
</div>
</div>
</div>
</el-form>
@ -164,20 +171,17 @@ const submit = async (formEl) => {
form.value.dataJson = ''
} else if (form.value.type === 2) {
//
let list = []
for (let index = 0; index < form.value.layersNumber; index++) {
if (
form.value.dataList.length > 0 &&
form.value.dataList[index] &&
form.value.dataList[index].laneId
form.value.dataList[index].id
) {
form.value.dataList[index].locationWide = form.value.locationWide
form.value.dataList[index].locationDeep = form.value.locationDeep
form.value.dataList[index].direction = form.value.direction //
form.value.dataList[index].inDirection = form.value.inDirection //
form.value.dataList[index].outDirection = form.value.outDirection //
form.value.dataList[index].locationStorey = index + 1 //
list.push(form.value.dataList[index])
} else {
form.value.dataList.push({
list.push({
positionMapId: props.positionMapId,
locationWide: form.value.locationWide || undefined,
locationDeep: form.value.locationDeep || undefined,
@ -188,8 +192,18 @@ const submit = async (formEl) => {
})
}
}
form.value.dataList = list
//dataJson
form.value.dataJson = JSON.stringify(form.value.dataList)
} else if (form.value.type === 3) {
//
form.value.dataObj.positionMapId = props.positionMapId
form.value.dataObj.locationWide = form.value.locationWide
form.value.dataObj.locationDeep = form.value.locationDeep
form.value.dataObj.direction = form.value.direction
form.value.dataObj.inDirection = form.value.inDirection
form.value.dataObj.outDirection = form.value.outDirection
form.value.dataObj.deviceType = deviceInfo.value.deviceType //
} else {
//
form.value.dataObj.positionMapId = props.positionMapId
@ -206,9 +220,13 @@ const submit = async (formEl) => {
})
}
//
const layersNumberChange = (e) => {}
const open = (item) => {
console.log(item)
form.value = item
form.value.layersNumber = item.layersNumber || 1 //1
form.value.layersNumber = item.dataList.length || ''
form.value.positionMapId = props.positionMapId
dialogFormVisible.value = true
}
@ -219,6 +237,12 @@ const typeChange = () => {
form.value.layersNumber = undefined
form.value.dataJson = ''
}
if (form.value.type !== 2 && form.value.type !== 4) {
form.value.direction = undefined
form.value.inDirection = undefined
form.value.outDirection = undefined
}
}
//
const directionChange = (e) => {

View File

@ -0,0 +1,78 @@
<template>
<!-- 新增设备 -->
<Dialog
v-model="dialogFormVisible"
title="物料区域设置"
width="600"
class="equipment-form-dialog"
>
<el-form :model="form" label-width="110">
<el-form-item label="物料区域名称" prop="skuInfo" required>
<el-input v-model="form.skuInfo" placeholder="请输入物料区域名称" />
</el-form-item>
<el-form-item label="物料名称" prop="areaName" required>
<el-input v-model="form.areaName" placeholder="请输入物料名称" />
</el-form-item>
<el-form-item label="库位数量" prop="areaNumber">
<el-input v-model="form.areaNumber" :disabled="true" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm"> 确定 </el-button>
</div>
</template>
</Dialog>
</template>
<script setup>
import { reactive, ref } from 'vue'
import * as MapApi from '@/api/map/map'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
const message = useMessage() //
const props = defineProps({
positionMapId: {
type: String,
default: () => ''
}
})
const dialogFormVisible = ref(false) //
//
const form = ref({
positionMapId: '',
skuInfo: '', //
areaName: '', //
areaNumber: 0,
mapItemIds: []
})
const open = (list) => {
dialogFormVisible.value = true
form.value.mapItemIds = list.map((item) => item.id)
form.value.areaNumber = form.value.mapItemIds.length
}
const submitForm = async () => {
form.value.positionMapId = props.positionMapId
await MapApi.createOrEditOrDelHouseArea(form.value)
dialogFormVisible.value = false
message.success('设置成功')
}
defineExpose({ open }) // open
</script>
<style lang="scss">
.equipment-form-dialog {
padding: 0px;
.el-dialog__footer {
padding: 0px 20px 20px 0;
border-top: none !important;
}
}
</style>

View File

@ -18,23 +18,26 @@
<script setup>
import { reactive, ref } from 'vue'
const emit = defineEmits(['layerSelectionSuccess'])
const list = ref([
{
labelType: 'locationPoint',
type: 2,
name: '库位点',
isShow: true
},
{
labelType: 'wayPoint',
type: 5,
name: '路径点',
isShow: true
},
{
labelType: 'devicePoint',
type: 3,
name: '设备点',
isShow: true
}
])
const isUnfold = ref(true)
const changeUnfold = () => {
@ -42,6 +45,8 @@ const changeUnfold = () => {
}
const changeSelectList = (item) => {
item.isShow = !item.isShow
const types = list.value.filter((item) => !item.isShow).map((item) => item.type)
emit('layerSelectionSuccess', types)
}
const open = (item) => {}

View File

@ -0,0 +1,74 @@
<template>
<!-- 新增设备 -->
<Dialog
v-model="dialogFormVisible"
title="物料区域设置"
width="600"
class="equipment-form-dialog"
>
<el-form :model="form" label-width="110">
<el-form-item label="线库名称" prop="laneName" required>
<el-input v-model="form.laneName" placeholder="请输入线库名称" />
</el-form-item>
<el-form-item label="库位数量" prop="areaNumber" required>
<el-input v-model="form.areaNumber" :disabled="true" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm"> 确定 </el-button>
</div>
</template>
</Dialog>
</template>
<script setup>
import { reactive, ref } from 'vue'
import * as MapApi from '@/api/map/map'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
const message = useMessage() //
const props = defineProps({
positionMapId: {
type: String,
default: () => ''
}
})
const dialogFormVisible = ref(false) //
//
const form = ref({
positionMapId: '',
laneName: '', //线
areaNumber: 0,
mapItemIds: []
})
const open = (list) => {
dialogFormVisible.value = true
form.value.mapItemIds = list.map((item) => item.id)
form.value.areaNumber = form.value.mapItemIds.length
}
const submitForm = async () => {
form.value.positionMapId = props.positionMapId
await MapApi.createOrEditOrDelHouseLane(form.value)
dialogFormVisible.value = false
message.success('设置成功')
}
defineExpose({ open }) // open
</script>
<style lang="scss">
.equipment-form-dialog {
padding: 0px;
.el-dialog__footer {
padding: 0px 20px 20px 0;
border-top: none !important;
}
}
</style>

View File

@ -72,14 +72,27 @@
<Icon :icon="item.icon" :size="24" />
<div class="name"> {{ item.name }} </div>
</div>
<!-- 分隔线 -->
<div
class="line"
v-if="
item.switchType === 'saveAs' ||
item.switchType === 'delete' ||
item.switchType === 'grid'
item.switchType === 'grid' ||
(item.switchType === 'next' &&
(toolbarSwitchType === 'lineLibrary' || toolbarSwitchType === 'region'))
"
></div>
<el-button
v-if="
item.switchType === 'next' &&
(toolbarSwitchType === 'lineLibrary' || toolbarSwitchType === 'region')
"
type="danger"
class="selection-area-btn"
@click="clickDrawSelectionArea"
>确定</el-button
>
</div>
</div>
<div class="right-tool-list" v-if="state.isShowToolbar">
@ -130,7 +143,7 @@
>
<VueDragResizeRotate
v-for="(item, index) in allHistoryList[currentIndex]"
:key="index"
:key="item.locationX"
:parent="true"
:x="item.locationX"
:y="item.locationY"
@ -150,7 +163,7 @@
>
<!-- 1 路径点 -->
<div
v-if="item.type === 1"
v-if="item.type === 1 && item.layerSelectionShow"
:style="{
width: item.locationWide + 'px',
height: item.locationDeep + 'px',
@ -162,7 +175,7 @@
</div>
<!-- 2 库位点 -->
<img
v-if="item.type === 2"
v-if="item.type === 2 && item.layerSelectionShow"
src="https://api.znkjfw.com/admin-api/infra/file/4/get/库位库存_png_179_1739326653035.png"
alt=""
:style="{
@ -173,7 +186,7 @@
/>
<!-- 3 设备点 -->
<img
v-if="item.type === 3"
v-if="item.type === 3 && item.layerSelectionShow"
src="https://api.znkjfw.com/admin-api/infra/file/4/get/设备点_png_179_1739327151877.png"
alt=""
:style="{
@ -184,7 +197,7 @@
/>
<!-- 4 停车点 -->
<img
v-if="item.type === 4"
v-if="item.type === 4 && item.layerSelectionShow"
src="https://api.znkjfw.com/admin-api/infra/file/4/get/停车场-01_png_179_1739326933020.png"
alt=""
:style="{
@ -195,7 +208,7 @@
/>
<!-- 5 区域变更点 -->
<img
v-if="item.type === 5"
v-if="item.type === 5 && item.layerSelectionShow"
src="https://api.znkjfw.com/admin-api/infra/file/4/get/区域_png_179_1739327151876.png"
alt=""
:style="{
@ -206,7 +219,7 @@
/>
<!-- 6 等待点 -->
<img
v-if="item.type === 6"
v-if="item.type === 6 && item.layerSelectionShow"
src="https://api.znkjfw.com/admin-api/infra/file/4/get/等待点_png_179_1739326991439.png"
alt=""
:style="{
@ -216,7 +229,7 @@
}"
/>
<div
v-if="item.type === 7"
v-if="item.type === 7 && item.layerSelectionShow"
:style="{
color: item.fontColor,
fontSize: item.fontSize + 'px',
@ -230,20 +243,36 @@
<!-- 文档 https://github.com/a7650/vue3-draggable-resizable/blob/main/docs/document_zh.md#resizable -->
</div>
<!-- 绘制框选区域 -->
<!-- 框选区域 -->
<div
v-if="state.drawSelectionArea"
v-for="(box, index) in state.allDrawSelectionAreaBox"
:key="index"
:style="{
position: 'absolute',
left: `${box.x}px`,
top: `${box.y}px`,
width: `${box.width}px`,
height: `${box.height}px`,
border: '2px dashed #007bff',
backgroundColor: 'rgba(0, 123, 255, 0.1)',
zIndex: 999
}"
></div>
<!-- 当前框选区域 -->
<div
v-if="state.drawSelectionAreaShow"
:style="{
position: 'absolute',
left: `${state.drawSelectionAreaBox.x}px`,
top: `${state.drawSelectionAreaBox.y}px`,
width: `${state.drawSelectionAreaBox.width}px`,
height: `${state.drawSelectionAreaBox.height}px`,
border: '1px solid blue',
backgroundColor: 'rgba(0, 0, 255, 0.1)',
zIndex: 99999
border: '2px dashed #007bff',
backgroundColor: 'rgba(0, 123, 255, 0.1)',
zIndex: 999
}"
></div>
<!-- 文字输入区域 -->
<input
v-if="state.showInputBox"
@ -258,6 +287,7 @@
left: state.inputBoxStyle.locationX + 'px',
top: state.inputBoxStyle.locationY + 'px'
}"
:maxlength="30"
class="input-box-class"
/>
</div>
@ -276,9 +306,20 @@
@textFormSuccess="textFormSuccess"
/>
<!-- 图层选择 -->
<layerSelectionToolDialog v-if="state.isShowLayer" ref="layerSelectionToolDialogRef" />
<layerSelectionToolDialog
v-if="state.isShowLayer"
ref="layerSelectionToolDialogRef"
@layerSelectionSuccess="layerSelectionSuccess"
/>
<!-- 设备弹窗选择 -->
<equipmentToolDialog ref="equipmentToolDialogRef" :positionMapId="imgBgObj.positionMapId" />
<!-- 区域选择 -->
<itemAreaSettingDialog ref="itemAreaSettingDialogRef" :positionMapId="imgBgObj.positionMapId" />
<!-- 线库设置 -->
<lineLibrarySettingDialog
ref="lineLibrarySettingDialogRef"
:positionMapId="imgBgObj.positionMapId"
/>
</template>
<script setup>
@ -286,6 +327,8 @@ import { ref, defineComponent, reactive, nextTick, onMounted } from 'vue'
import editNodeProperties from './components-tool/editNodeProperties.vue'
import textFormToolDialog from './components-tool/textFormToolDialog.vue'
import equipmentToolDialog from './components-tool/equipmentToolDialog.vue'
import itemAreaSettingDialog from './components-tool/itemAreaSettingDialog.vue'
import lineLibrarySettingDialog from './components-tool/lineLibrarySettingDialog.vue'
import layerSelectionToolDialog from './components-tool/layerSelectionToolDialog.vue'
import * as MapApi from '@/api/map/map'
@ -293,6 +336,8 @@ import cursorCollection from './cursorCollection'
defineOptions({ name: 'editMapPageRealTimeMap' })
const lineLibrarySettingDialogRef = ref() //线
const itemAreaSettingDialogRef = ref() //
const equipmentToolDialogRef = ref() //
const textFormToolDialogRef = ref() //
const inputBoxRef = ref() //
@ -391,6 +436,7 @@ const mapClick = (e) => {
//
allMapPointInfo.value.push({
positionMapId: imgBgObj.positionMapId, //id
layerSelectionShow: true,
locationX: e.offsetX,
locationY: e.offsetY,
locationDeep: 16,
@ -449,7 +495,8 @@ const handleInputEnd = () => {
fontColor: state.inputBoxStyle.fontColor, //
fontFamily: state.inputBoxStyle.fontFamily, //
fontSize: state.inputBoxStyle.fontSize,
dataObj: {} //
dataObj: {}, //
layerSelectionShow: true
})
addEditHistory()
state.inputBoxValue = ''
@ -523,7 +570,7 @@ const state = reactive({
switchType: 'tools',
name: '工具',
icon: 'ep:briefcase',
isActive: false
isActive: true
},
{
switchType: 'lineLibrary',
@ -571,7 +618,7 @@ const state = reactive({
switchType: 'grid',
name: '网格',
icon: 'ep:grid',
isActive: false
isActive: true
},
{
switchType: 'larger',
@ -624,8 +671,8 @@ const state = reactive({
isActive: false
}
],
isShowToolbar: false, //
isShowGrid: false, //
isShowToolbar: true, //
isShowGrid: true, //
moveForm: {
locationX: '',
locationY: ''
@ -635,10 +682,11 @@ const state = reactive({
}, //
copyMapItem: '', //
cursorStyle: 'auto',
drawSelectionArea: false, //
drawSelectionAreaShow: false, //
allDrawSelectionAreaBox: [], //
drawSelectionAreaBox: { x: 0, y: 0, width: 0, height: 0 }, //
drawSelectionAreaStartPos: { x: 0, y: 0 }, //
drawSelectionAreaSelectedPoints: [], //list
drawSelectionStartPoint: { x: 0, y: 0 }, //
drawSelectionPointList: [], //list
textFormToolShow: false, //
showInputBox: false, //
inputBoxStyle: {
@ -654,7 +702,7 @@ const state = reactive({
const toolbarClick = (item) => {
let type = item.switchType
if (
currentItemIndex.value &&
currentItemIndex.value === -1 &&
(type === 'move' || type === 'revolve' || type === 'copy' || type === 'delete')
) {
message.warning('请先选择要操作的对象')
@ -682,6 +730,13 @@ const toolbarClick = (item) => {
state.inputBoxValue = ''
}
//
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') {
state.drawSelectionAreaShow = false
state.allDrawSelectionAreaBox = []
state.drawSelectionPointList = []
}
switch (type) {
case 'open':
//
@ -716,13 +771,29 @@ const toolbarClick = (item) => {
break
case 'copy':
//
state.copyMapItem = allHistoryList.value[currentIndex.value][currentItemIndex.value]
let copyMapItem = allHistoryList.value[currentIndex.value][currentItemIndex.value]
state.copyMapItem = {
positionMapId: copyMapItem.positionMapId,
locationX: copyMapItem.locationX,
locationY: copyMapItem.locationY,
type: copyMapItem.type,
dataJson: copyMapItem.dataJson || '',
dataObj: copyMapItem.dataObj || {},
dataList: copyMapItem.dataList || [],
locationDeep: copyMapItem.locationDeep,
locationWide: copyMapItem.locationWide,
draggable: copyMapItem.draggable,
resizable: copyMapItem.resizable,
rotatable: copyMapItem.rotatable,
lockAspectRatio: copyMapItem.lockAspectRatio
}
message.success('复制成功')
break
case 'paste':
//
let copyObj = JSON.parse(JSON.stringify(state.copyMapItem))
copyObj.locationX = copyObj.locationX + 50
copyObj.locationY = copyObj.locationY + 50
copyObj.locationX = Number(copyObj.locationX) + 50
copyObj.locationY = Number(copyObj.locationY) + 50
allMapPointInfo.value.push(copyObj)
addEditHistory()
break
@ -845,48 +916,70 @@ const rotationFormSubmit = () => {
//
const startDrawSelection = (event) => {
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
state.drawSelectionArea = true
state.drawSelectionAreaStartPos = { x: event.offsetX, y: event.offsetY }
state.drawSelectionAreaShow = true
state.drawSelectionStartPoint = { x: event.offsetX, y: event.offsetY }
state.drawSelectionAreaBox = { x: event.offsetX, y: event.offsetY, width: 0, height: 0 }
//
event.preventDefault()
}
//
const updateDrawSelection = (event) => {
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
if (state.drawSelectionArea) {
state.drawSelectionAreaBox.width = event.offsetX - state.drawSelectionAreaStartPos.x
state.drawSelectionAreaBox.height = event.offsetY - state.drawSelectionAreaStartPos.y
if (state.drawSelectionAreaShow) {
state.drawSelectionAreaBox.width = event.offsetX - state.drawSelectionStartPoint.x
state.drawSelectionAreaBox.height = event.offsetY - state.drawSelectionStartPoint.y
}
//
event.preventDefault()
}
//
const endDrawSelection = () => {
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
state.drawSelectionAreaShow = false
state.allDrawSelectionAreaBox.push({ ...state.drawSelectionAreaBox })
state.drawSelectionAreaBox = { x: 0, y: 0, width: 0, height: 0 }
}
//
const clickDrawSelectionArea = () => {
let points = allHistoryList.value[currentIndex.value]
state.drawSelectionArea = false
state.drawSelectionAreaSelectedPoints = points.filter((point) => {
return (
point.locationX >=
Math.min(
state.drawSelectionAreaStartPos.x,
state.drawSelectionAreaStartPos.x + state.drawSelectionAreaBox.width
) &&
point.locationX <=
Math.max(
state.drawSelectionAreaStartPos.x,
state.drawSelectionAreaStartPos.x + state.drawSelectionAreaBox.width
) &&
point.locationY >=
Math.min(
state.drawSelectionAreaStartPos.y,
state.drawSelectionAreaStartPos.y + state.drawSelectionAreaBox.height
) &&
point.locationY <=
Math.max(
state.drawSelectionAreaStartPos.y,
state.drawSelectionAreaStartPos.y + state.drawSelectionAreaBox.height
)
)
state.drawSelectionPointList = []
state.allDrawSelectionAreaBox.forEach((box) => {
points.forEach((point) => {
if (
point.locationX >= box.x &&
point.locationX <= box.x + box.width &&
point.locationY >= box.y &&
point.locationY <= box.y + box.height
) {
state.drawSelectionPointList.push(point)
}
})
})
console.log(state.drawSelectionAreaSelectedPoints, '选中的')
console.log(state.drawSelectionPointList, '选中的')
//
state.allDrawSelectionAreaBox = []
//
let binLocation = state.drawSelectionPointList.filter((item) => item.type === 2)
if (toolbarSwitchType.value === 'lineLibrary') {
//线
if (binLocation.length < 2) {
message.warning('至少选择两个库位')
} else {
lineLibrarySettingDialogRef.value.open(binLocation)
}
}
if (toolbarSwitchType.value === 'region') {
//
if (binLocation.length < 1) {
message.warning('至少选择两个库位')
} else {
itemAreaSettingDialogRef.value.open(binLocation)
}
}
}
//
@ -938,15 +1031,19 @@ const getAllNodeList = async () => {
positionMapId: imgBgObj.positionMapId
})
list.forEach((item) => {
item.layerSelectionShow = true //
item.locationX = Number(item.locationX)
item.locationY = Number(item.locationY)
if (item.type === 1 || item.type === 5 || item.type === 6) {
item.dataObj = {}
item.dataList = []
item.locationDeep = 16
item.locationWide = 16
item.draggable = true
item.draggable = false
item.resizable = false
item.rotatable = false
item.lockAspectRatio = false
item.lockAspectRatio = true
} else if (item.type === 2) {
//
item.dataList = JSON.parse(item.dataJson)
@ -955,7 +1052,7 @@ const getAllNodeList = async () => {
item.draggable = true
item.resizable = false
item.rotatable = false
item.lockAspectRatio = false
item.lockAspectRatio = true
} else if (item.type === 3 || item.type === 4) {
item.dataObj = JSON.parse(item.dataJson)
item.dataList = []
@ -964,7 +1061,7 @@ const getAllNodeList = async () => {
item.draggable = true
item.resizable = false
item.rotatable = false
item.lockAspectRatio = false
item.lockAspectRatio = true
} else if (item.type === 7) {
item.dataObj = JSON.parse(item.dataJson)
item.text = item.dataObj.text
@ -974,8 +1071,8 @@ const getAllNodeList = async () => {
item.angle = item.dataObj.angle
item.draggable = true
item.resizable = false
item.rotatable = false
item.lockAspectRatio = false
item.rotatable = true
item.lockAspectRatio = true
}
allMapPointInfo.value.push(item)
})
@ -1015,6 +1112,18 @@ const saveNodeList = async () => {
}
}
//
const layerSelectionSuccess = (typeList) => {
allHistoryList.value[currentIndex.value].forEach((item) => {
// type layerSelectionShow false
if (typeList.includes(item.type)) {
item.layerSelectionShow = false
} else {
item.layerSelectionShow = true
}
})
}
onMounted(() => {
getMapList()
})
@ -1136,4 +1245,9 @@ onMounted(() => {
padding: 4px;
outline: none;
}
.selection-area-btn {
width: 80px;
margin-left: 6px;
}
</style>

View File

@ -1,180 +1,125 @@
<template>
<div>
<!-- SVG 画布 -->
<svg
ref="svg"
width="500"
height="300"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
>
<!-- 绘制所有曲线 -->
<path
v-for="(curve, index) in curves"
:key="index"
:d="getCurvePath(curve)"
stroke="#000"
fill="none"
stroke-width="2"
:class="{ selected: selectedCurve === curve }"
@click="svgClick(curve)"
/>
<!-- 绘制控制点和连线 -->
<line
v-if="selectedCurve"
:x1="selectedCurve.start.x"
:y1="selectedCurve.start.y"
:x2="selectedCurve.control1.x"
:y2="selectedCurve.control1.y"
stroke="gray"
stroke-dasharray="2"
/>
<line
v-if="selectedCurve"
:x1="selectedCurve.end.x"
:y1="selectedCurve.end.y"
:x2="selectedCurve.control2.x"
:y2="selectedCurve.control2.y"
stroke="gray"
stroke-dasharray="2"
/>
<!-- 绘制起点终点和控制点 -->
<circle
v-for="(curve, index) in curves"
:key="'start' + index"
:cx="curve.start.x"
:cy="curve.start.y"
r="5"
fill="red"
@mousedown="startDrag($event, curve, 'start')"
/>
<circle
v-for="(curve, index) in curves"
:key="'end' + index"
:cx="curve.end.x"
:cy="curve.end.y"
r="5"
fill="red"
@mousedown="startDrag($event, curve, 'end')"
/>
<circle
v-if="selectedCurve"
:cx="selectedCurve.control1.x"
:cy="selectedCurve.control1.y"
r="5"
fill="green"
@mousedown="startDrag($event, selectedCurve, 'control1')"
/>
<circle
v-if="selectedCurve"
:cx="selectedCurve.control2.x"
:cy="selectedCurve.control2.y"
r="5"
fill="green"
@mousedown="startDrag($event, selectedCurve, 'control2')"
/>
</svg>
<div
@mousedown="startSelection"
@mousemove="updateSelection"
@mouseup="endSelection"
style="position: relative; height: 100vh; border: 1px solid #ccc"
>
<!-- 框选区域 -->
<div
v-if="isSelecting || selectionBox.width > 0"
:style="{
position: 'absolute',
left: `${selectionBox.x}px`,
top: `${selectionBox.y}px`,
width: `${selectionBox.width}px`,
height: `${selectionBox.height}px`,
border: '2px dashed #007bff',
backgroundColor: 'rgba(0, 123, 255, 0.1)'
}"
></div>
<!-- 显示控制点坐标 -->
<div class="points" v-if="selectedCurve">
<p>起点: ({{ selectedCurve.start.x }}, {{ selectedCurve.start.y }})</p>
<p>控制点 1: ({{ selectedCurve.control1.x }}, {{ selectedCurve.control1.y }})</p>
<p>控制点 2: ({{ selectedCurve.control2.x }}, {{ selectedCurve.control2.y }})</p>
<p>终点: ({{ selectedCurve.end.x }}, {{ selectedCurve.end.y }})</p>
</div>
<!-- 图片 -->
<img
v-for="(img, index) in images"
:key="index"
:src="img.src"
:style="{
position: 'absolute',
left: `${img.x}px`,
top: `${img.y}px`,
width: '100px',
height: '100px',
userSelect: isSelecting ? 'none' : 'auto', //
pointerEvents: isSelecting ? 'none' : 'auto' //
}"
/>
</div>
</template>
<script setup>
<script>
import { ref } from 'vue'
const svg = ref(null) // SVG
const curves = ref([]) // 线
const selectedCurve = ref(null) // 线
const isDragging = ref(false) //
const dragTarget = ref(null) //
//
const getMousePos = (event) => {
const rect = svg.value.getBoundingClientRect()
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top
}
}
export default {
setup() {
//
const images = ref([
{ src: 'https://via.placeholder.com/100', x: 100, y: 100 },
{ src: 'https://via.placeholder.com/100', x: 300, y: 200 },
{ src: 'https://via.placeholder.com/100', x: 500, y: 300 }
])
//
const startDrag = (event, curve, target) => {
event.preventDefault()
isDragging.value = true
selectedCurve.value = curve
dragTarget.value = target
}
//
const selectionBox = ref({
x: 0,
y: 0,
width: 0,
height: 0
})
//
const handleMouseDown = (event) => {
const mousePos = getMousePos(event)
//
const isSelecting = ref(false)
// 线
if (!isDragging.value && curves.value.length === 0) {
const newCurve = {
start: mousePos,
end: mousePos,
control1: { x: mousePos.x + 50, y: mousePos.y - 50 },
control2: { x: mousePos.x + 100, y: mousePos.y - 50 }
//
const startPos = ref({ x: 0, y: 0 })
//
const startSelection = (event) => {
isSelecting.value = true
startPos.value = { x: event.clientX, y: event.clientY }
selectionBox.value = {
x: event.clientX,
y: event.clientY,
width: 0,
height: 0
}
//
event.preventDefault()
}
//
const updateSelection = (event) => {
if (!isSelecting.value) return
const currentX = event.clientX
const currentY = event.clientY
selectionBox.value = {
x: Math.min(startPos.value.x, currentX),
y: Math.min(startPos.value.y, currentY),
width: Math.abs(currentX - startPos.value.x),
height: Math.abs(currentY - startPos.value.y)
}
//
event.preventDefault()
}
//
const endSelection = () => {
isSelecting.value = false
console.log('框选区域:', selectionBox.value)
}
return {
images,
selectionBox,
isSelecting,
startSelection,
updateSelection,
endSelection
}
curves.value.push(newCurve)
selectedCurve.value = newCurve
dragTarget.value = 'end'
isDragging.value = true
}
}
//
const handleMouseMove = (event) => {
if (!isDragging.value || !selectedCurve.value) return
const mousePos = getMousePos(event)
//
if (dragTarget.value === 'start') {
selectedCurve.value.start = mousePos
} else if (dragTarget.value === 'end') {
selectedCurve.value.end = mousePos
} else if (dragTarget.value === 'control1') {
selectedCurve.value.control1 = mousePos
} else if (dragTarget.value === 'control2') {
selectedCurve.value.control2 = mousePos
}
}
//
const handleMouseUp = () => {
isDragging.value = false
dragTarget.value = null
}
// 线
const getCurvePath = (curve) => {
return `M ${curve.start.x} ${curve.start.y} C ${curve.control1.x} ${curve.control1.y}, ${curve.control2.x} ${curve.control2.y}, ${curve.end.x} ${curve.end.y}`
}
const svgClick = (item) => {
console.log(item)
}
</script>
<style scoped>
svg {
border: 1px solid #000;
cursor: crosshair;
}
path.selected {
stroke: blue;
}
.points {
margin-top: 10px;
font-size: 14px;
/* 禁用用户选择 */
img {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
</style>

View File

@ -18,3 +18,74 @@
fontFamily: '' //字体类型
}
```
```
1.普通节点 dataJson 不传数据
2.库位点 dataJson 数据格式:
[
{
"id": 1881176241622024200, //库位id - 编辑的时候会有需要传过来 新增的时候没有则不传
"laneId": 1881177420829642800, //线库id - 编辑的时候有就传过来 新增的时候没有就不传
"laneName": "测试33", //线库名称 - 编辑的时候有就传过来 新增的时候没有就不传
"locationX": "2", //库位坐标x轴 - 编辑的时候有就传过来 新增的时候不用传
"locationY": "7", //库位坐标y轴 - 编辑的时候有就传过来 新增的时候不用传
"locationWide": 10, //宽度 - 编辑的时候有就传过来 新增的时候需要传
"locationDeep": 10, //高度 - 编辑的时候有就传过来 新增的时候需要传
"direction": 1, //库位方向1单向、2双向、3三向、4四向 编辑的时候有就传过来 新增的时候需要传
"inDirection": 1, //进入方向0尾入、1头入 编辑的时候有就传过来 新增的时候需要传
"outDirection": 1, //离开方向0尾出、1头出 编辑的时候有就传过来 新增的时候需要传
"locationStorey": 3, //层数 编辑的时候有就传过来 新增的时候需要传
"mapId": 1, //地图id 编辑的时候有就传过来 新增的时候不需要传
"mapItemId": 1881176241622024200 //地图子表id 编辑的时候有就传过来 新增的时候不需要传
},
{
"id": 1881176241622024200,
"laneId": 1881177420829642800,
"laneName": "测试33",
"locationX": "2",
"locationY": "7",
"locationWide": 10,
"locationDeep": 10,
"direction": 1,
"inDirection": 1,
"outDirection": 1,
"locationStorey": 3,
"mapId": 1,
"mapItemId": 1881176241622024200
}
]
3.设备点 dataJson 数据格式:
{
"id": 1881176241622024200, //设备id - 新增编辑都需要传 - 根据选择的设备获取到
"locationX": "2", //库位坐标x轴 - 编辑的时候有就传过来 新增的时候不用传
"locationY": "7", //库位坐标y轴 - 编辑的时候有就传过来 新增的时候不用传
"locationWide": 10, //宽度 - 编辑的时候有就传过来 新增的时候需要传
"locationDeep": 10, //高度 - 编辑的时候有就传过来 新增的时候需要传
"mapId": 1, //地图id 编辑的时候有就传过来 新增的时候不需要传
"mapItemId": 1881176241622024200 //地图子表id 编辑的时候有就传过来 新增的时候不需要传
}
4.停车点 dataJson 数据格式:
{
"id": 1881176241622024200, //停车点id - 编辑的时候会有需要传过来 新增的时候没有则不传
"locationX": "2", //库位坐标x轴 - 编辑的时候有就传过来 新增的时候不用传
"locationY": "7", //库位坐标y轴 - 编辑的时候有就传过来 新增的时候不用传
"locationWide": 10, //宽度 - 编辑的时候有就传过来 新增的时候需要传
"locationDeep": 10, //高度 - 编辑的时候有就传过来 新增的时候需要传
"direction": 1, //库位方向1单向、2双向、3三向、4四向 编辑的时候有就传过来 新增的时候需要传
"inDirection": 1, //进入方向0尾入、1头入 编辑的时候有就传过来 新增的时候需要传
"outDirection": 1, //离开方向0尾出、1头出 编辑的时候有就传过来 新增的时候需要传
"mapId": 1, //地图id 编辑的时候有就传过来 新增的时候不需要传
"mapItemId": 1881176241622024200 //地图子表id 编辑的时候有就传过来 新增的时候不需要传
},
5.路径点 dataJson 不传数据
6.等待点 dataJson 不传数据
```

View File

@ -0,0 +1,180 @@
<template>
<div>
<!-- SVG 画布 -->
<svg
ref="svg"
width="500"
height="300"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
>
<!-- 绘制所有曲线 -->
<path
v-for="(curve, index) in curves"
:key="index"
:d="getCurvePath(curve)"
stroke="#000"
fill="none"
stroke-width="2"
:class="{ selected: selectedCurve === curve }"
@click="svgClick(curve)"
/>
<!-- 绘制控制点和连线 -->
<line
v-if="selectedCurve"
:x1="selectedCurve.start.x"
:y1="selectedCurve.start.y"
:x2="selectedCurve.control1.x"
:y2="selectedCurve.control1.y"
stroke="gray"
stroke-dasharray="2"
/>
<line
v-if="selectedCurve"
:x1="selectedCurve.end.x"
:y1="selectedCurve.end.y"
:x2="selectedCurve.control2.x"
:y2="selectedCurve.control2.y"
stroke="gray"
stroke-dasharray="2"
/>
<!-- 绘制起点终点和控制点 -->
<circle
v-for="(curve, index) in curves"
:key="'start' + index"
:cx="curve.start.x"
:cy="curve.start.y"
r="5"
fill="red"
@mousedown="startDrag($event, curve, 'start')"
/>
<circle
v-for="(curve, index) in curves"
:key="'end' + index"
:cx="curve.end.x"
:cy="curve.end.y"
r="5"
fill="red"
@mousedown="startDrag($event, curve, 'end')"
/>
<circle
v-if="selectedCurve"
:cx="selectedCurve.control1.x"
:cy="selectedCurve.control1.y"
r="5"
fill="green"
@mousedown="startDrag($event, selectedCurve, 'control1')"
/>
<circle
v-if="selectedCurve"
:cx="selectedCurve.control2.x"
:cy="selectedCurve.control2.y"
r="5"
fill="green"
@mousedown="startDrag($event, selectedCurve, 'control2')"
/>
</svg>
<!-- 显示控制点坐标 -->
<div class="points" v-if="selectedCurve">
<p>起点: ({{ selectedCurve.start.x }}, {{ selectedCurve.start.y }})</p>
<p>控制点 1: ({{ selectedCurve.control1.x }}, {{ selectedCurve.control1.y }})</p>
<p>控制点 2: ({{ selectedCurve.control2.x }}, {{ selectedCurve.control2.y }})</p>
<p>终点: ({{ selectedCurve.end.x }}, {{ selectedCurve.end.y }})</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const svg = ref(null) // SVG
const curves = ref([]) // 线
const selectedCurve = ref(null) // 线
const isDragging = ref(false) //
const dragTarget = ref(null) //
//
const getMousePos = (event) => {
const rect = svg.value.getBoundingClientRect()
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top
}
}
//
const startDrag = (event, curve, target) => {
event.preventDefault()
isDragging.value = true
selectedCurve.value = curve
dragTarget.value = target
}
//
const handleMouseDown = (event) => {
const mousePos = getMousePos(event)
// 线
if (!isDragging.value && curves.value.length === 0) {
const newCurve = {
start: mousePos,
end: mousePos,
control1: { x: mousePos.x + 50, y: mousePos.y - 50 },
control2: { x: mousePos.x + 100, y: mousePos.y - 50 }
}
curves.value.push(newCurve)
selectedCurve.value = newCurve
dragTarget.value = 'end'
isDragging.value = true
}
}
//
const handleMouseMove = (event) => {
if (!isDragging.value || !selectedCurve.value) return
const mousePos = getMousePos(event)
//
if (dragTarget.value === 'start') {
selectedCurve.value.start = mousePos
} else if (dragTarget.value === 'end') {
selectedCurve.value.end = mousePos
} else if (dragTarget.value === 'control1') {
selectedCurve.value.control1 = mousePos
} else if (dragTarget.value === 'control2') {
selectedCurve.value.control2 = mousePos
}
}
//
const handleMouseUp = () => {
isDragging.value = false
dragTarget.value = null
}
// 线
const getCurvePath = (curve) => {
return `M ${curve.start.x} ${curve.start.y} C ${curve.control1.x} ${curve.control1.y}, ${curve.control2.x} ${curve.control2.y}, ${curve.end.x} ${curve.end.y}`
}
const svgClick = (item) => {
console.log(item)
}
</script>
<style scoped>
svg {
border: 1px solid #000;
cursor: crosshair;
}
path.selected {
stroke: blue;
}
.points {
margin-top: 10px;
font-size: 14px;
}
</style>