解决冲突
This commit is contained in:
commit
8ef2938d10
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Dialog v-model="dialogFormVisible" title="节点属性" width="540" class="node-form-dialog">
|
<Dialog v-model="dialogFormVisible" title="节点属性" width="540" class="node-form-dialog">
|
||||||
<el-form :model="form" label-width="auto">
|
<el-form :model="form" label-width="auto" ref="ruleFormRef">
|
||||||
<el-form-item label="X" prop="locationX" required>
|
<el-form-item label="X" prop="locationX" required>
|
||||||
<el-input v-model="form.locationX" placeholder="请输入" />
|
<el-input v-model="form.locationX" placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -17,8 +17,14 @@
|
|||||||
<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 !== 1 && form.type !== 6">
|
<div v-if="form.type === 2 || form.type === 3 || form.type === 4">
|
||||||
<el-form-item label="层数" prop="layersNumber" required v-if="form.type === 2">
|
<el-form-item
|
||||||
|
label="层数"
|
||||||
|
prop="layersNumber"
|
||||||
|
:rules="{ required: true, message: '请输入层数', trigger: 'change' }"
|
||||||
|
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" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
@ -102,7 +108,7 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="submit"> 确认 </el-button>
|
<el-button type="primary" @click="submit(ruleFormRef)"> 确认 </el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@ -113,6 +119,7 @@ import { reactive, ref } from 'vue'
|
|||||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import * as MapApi from '@/api/map/map'
|
import * as MapApi from '@/api/map/map'
|
||||||
|
|
||||||
|
const ruleFormRef = ref()
|
||||||
const dialogFormVisible = ref(false)
|
const dialogFormVisible = ref(false)
|
||||||
const message = useMessage() // 消息弹窗
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
@ -124,75 +131,93 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const form = ref({
|
const form = ref({
|
||||||
type: 1,
|
type: 1, //类型 1.路径点位 2.库位点 3.充电桩 4.停车点 5.区域变更点 6.等待点
|
||||||
layersNumber: 1, //层数
|
layersNumber: 1, //层数
|
||||||
locationX: undefined,
|
locationX: undefined, //库位坐标x轴
|
||||||
locationY: undefined,
|
locationY: undefined, //库位坐标y轴
|
||||||
locationDeep: undefined, //长度
|
locationDeep: undefined, //长度
|
||||||
locationWide: undefined, //宽度
|
locationWide: undefined, //宽度
|
||||||
direction: 1, //方向
|
direction: undefined, //库位方向(1:单向、2:双向、3:三向、4:四向)
|
||||||
inDirection: undefined,
|
inDirection: undefined, //进入方向(0:尾入、1:头入)
|
||||||
outDirection: undefined,
|
outDirection: undefined, //离开方向(0:尾出、1:头出)
|
||||||
list: []
|
dataList: [], //存库位的
|
||||||
|
dataObj: {}, //存 设备点 停车点 文字
|
||||||
|
positionMapId: 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' }],
|
||||||
type: [{ required: true, message: '请选择类型', trigger: 'blur' }],
|
type: [{ required: true, message: '请选择类型', trigger: 'blur' }],
|
||||||
direction: [{ required: true, message: '请输入层数', trigger: 'blur' }],
|
layersNumber: [{ required: true, message: '请输入层数', trigger: 'blur' }],
|
||||||
id: [{ required: true, message: '请选择设备编号', trigger: 'blur' }]
|
id: [{ required: true, message: '请选择设备编号', trigger: 'blur' }]
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['submitNodeSuccess'])
|
const emit = defineEmits(['submitNodeSuccess'])
|
||||||
const submit = () => {
|
const submit = async (formEl) => {
|
||||||
if (form.value.type === 1 || form.value.type === 6) {
|
if (!formEl) return
|
||||||
form.value.dataJson = ''
|
await formEl.validate((valid, fields) => {
|
||||||
} else if (form.value.type === 2) {
|
if (!valid) return
|
||||||
//在这边把数据处理好
|
//在这边把数据处理好
|
||||||
let list = []
|
if (form.value.type === 1 || form.value.type === 5 || form.value.type === 6) {
|
||||||
for (let index = 0; index < form.value.layersNumber; index++) {
|
//不需要dataJson的类型
|
||||||
list.push({
|
form.value.dataJson = ''
|
||||||
locationWide: form.value.locationWide || undefined,
|
} else if (form.value.type === 2) {
|
||||||
locationDeep: form.value.locationDeep || undefined,
|
//库位点 类型为数组
|
||||||
direction: form.value.direction || undefined, //方向
|
for (let index = 0; index < form.value.layersNumber; index++) {
|
||||||
inDirection: form.value.inDirection || undefined, //进入方向
|
if (
|
||||||
outDirection: form.value.outDirection || undefined, //离开方向
|
form.value.dataList.length > 0 &&
|
||||||
locationStorey: index + 1 //层数
|
form.value.dataList[index] &&
|
||||||
})
|
form.value.dataList[index].laneId
|
||||||
|
) {
|
||||||
|
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 //层数
|
||||||
|
} else {
|
||||||
|
form.value.dataList.push({
|
||||||
|
positionMapId: props.positionMapId,
|
||||||
|
locationWide: form.value.locationWide || undefined,
|
||||||
|
locationDeep: form.value.locationDeep || undefined,
|
||||||
|
direction: form.value.direction || undefined, //方向
|
||||||
|
inDirection: form.value.inDirection || undefined, //进入方向
|
||||||
|
outDirection: form.value.outDirection || undefined, //离开方向
|
||||||
|
locationStorey: index + 1 //层数
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//dataJson数据
|
||||||
|
form.value.dataJson = JSON.stringify(form.value.dataList)
|
||||||
|
} else {
|
||||||
|
//类型为路径点位 区域变更点 等待点 值为对象
|
||||||
|
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
|
||||||
|
//dataJson数据
|
||||||
|
form.value.dataJson = JSON.stringify(form.value.dataObj)
|
||||||
}
|
}
|
||||||
form.value.dataJson = JSON.stringify(list)
|
emit('submitNodeSuccess', form.value)
|
||||||
} else {
|
dialogFormVisible.value = false
|
||||||
let obj = {
|
})
|
||||||
id: form.value.id || undefined,
|
|
||||||
mapId: props.positionMapId,
|
|
||||||
locationWide: form.value.locationWide || undefined,
|
|
||||||
locationDeep: form.value.locationDeep || undefined,
|
|
||||||
direction: form.value.direction || undefined, //方向
|
|
||||||
inDirection: form.value.inDirection || undefined, //进入方向
|
|
||||||
outDirection: form.value.outDirection || undefined //离开方向
|
|
||||||
}
|
|
||||||
form.value.dataJson = JSON.stringify(obj)
|
|
||||||
}
|
|
||||||
console.log(form.value, '保存')
|
|
||||||
emit('submitNodeSuccess', form.value)
|
|
||||||
dialogFormVisible.value = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const open = (item) => {
|
const open = (item) => {
|
||||||
form.value = item
|
form.value = item
|
||||||
form.value.locationX = item.locationX
|
form.value.layersNumber = item.layersNumber || 1 //初始化的时候给个1层
|
||||||
form.value.locationY = item.locationY
|
form.value.positionMapId = props.positionMapId
|
||||||
form.value.type = item.type || 1
|
|
||||||
dialogFormVisible.value = true
|
dialogFormVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
//类型改变
|
//类型改变
|
||||||
const typeChange = () => {
|
const typeChange = () => {
|
||||||
if (form.value.type === 1 || form.value.type === 6) {
|
if (form.value.type === 1 || form.value.type === 5 || form.value.type === 6) {
|
||||||
form.value.layersNumber = undefined
|
form.value.layersNumber = undefined
|
||||||
form.value.dataJson = ''
|
form.value.dataJson = ''
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//方向改变
|
//方向改变
|
||||||
@ -203,16 +228,19 @@ const directionChange = (e) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取设备信息
|
//设备信息
|
||||||
const deviceInfo = ref({
|
const deviceInfo = ref({
|
||||||
positionMapId: '',
|
positionMapId: '',
|
||||||
deviceType: ''
|
deviceType: ''
|
||||||
})
|
})
|
||||||
|
//设备列表
|
||||||
const deviceList = ref([])
|
const deviceList = ref([])
|
||||||
|
//获取设备列表
|
||||||
const getDeviceList = async () => {
|
const getDeviceList = async () => {
|
||||||
deviceInfo.value.positionMapId = props.positionMapId
|
deviceInfo.value.positionMapId = props.positionMapId
|
||||||
deviceList.value = await MapApi.getDeviceInformationList(deviceInfo.value)
|
deviceList.value = await MapApi.getDeviceInformationList(deviceInfo.value)
|
||||||
}
|
}
|
||||||
|
//设备类型切换
|
||||||
const deviceTypeChange = () => {
|
const deviceTypeChange = () => {
|
||||||
getDeviceList()
|
getDeviceList()
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,29 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
inputBoxStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
fontFamily: 'SimSun',
|
||||||
|
fontSize: '14',
|
||||||
|
fontColor: '#000000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.inputBoxStyle,
|
||||||
|
(val) => {
|
||||||
|
form.fontFamily = props.inputBoxStyle.fontFamily
|
||||||
|
form.fontSize = props.inputBoxStyle.fontSize
|
||||||
|
form.fontColor = props.inputBoxStyle.fontColor
|
||||||
|
},
|
||||||
|
{ immediate: false }
|
||||||
|
)
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
fontFamily: 'SimSun',
|
fontFamily: 'SimSun',
|
||||||
fontSize: '14',
|
fontSize: '14',
|
||||||
|
@ -41,7 +41,12 @@ import { ref, defineComponent, reactive, nextTick, onMounted } from 'vue'
|
|||||||
import * as MapApi from '@/api/map/map'
|
import * as MapApi from '@/api/map/map'
|
||||||
import WebSocketClient from '../webSocket.js';
|
import WebSocketClient from '../webSocket.js';
|
||||||
const imgUrl = ref('')
|
const imgUrl = ref('')
|
||||||
|
|
||||||
const socketClient = ref(null)
|
const socketClient = ref(null)
|
||||||
|
|
||||||
|
const emit = defineEmits(['transmitMapId'])
|
||||||
|
|
||||||
|
|
||||||
const list = ref([])
|
const list = ref([])
|
||||||
const nowObject = ref(null)
|
const nowObject = ref(null)
|
||||||
//获取地图区域
|
//获取地图区域
|
||||||
@ -62,8 +67,9 @@ const getList = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPositionMapList = async () => {
|
const getPositionMapListFun = async (positionMapId) => {
|
||||||
let data = await MapApi.getPositionMap()
|
console.log(positionMapId)
|
||||||
|
let data = await MapApi.getPositionMapItemList({positionMapId:positionMapId})
|
||||||
console.log(data)
|
console.log(data)
|
||||||
}
|
}
|
||||||
const replaceHttpWithWs = (str) => {
|
const replaceHttpWithWs = (str) => {
|
||||||
@ -89,17 +95,24 @@ const disconnect = () => {
|
|||||||
};
|
};
|
||||||
//获取扫描图
|
//获取扫描图
|
||||||
const getMapData = async (item) => {
|
const getMapData = async (item) => {
|
||||||
let data = await MapApi.getPositionMapdDwnloadPngBase64({
|
|
||||||
floor: item.floor,
|
|
||||||
area: item.area
|
|
||||||
})
|
|
||||||
|
|
||||||
let base64Url = 'data:image/png;base64,'
|
|
||||||
imgUrl.value = data
|
|
||||||
nowObject.value = JSON.parse(JSON.stringify(item))
|
nowObject.value = JSON.parse(JSON.stringify(item))
|
||||||
let websoketUrl = `${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}`
|
||||||
console.log(websoketUrl)
|
console.log(websoketUrl)
|
||||||
linkWebSocket(websoketUrl)
|
linkWebSocket(websoketUrl)
|
||||||
|
getPositionMapListFun(nowObject.value.id)
|
||||||
|
emit('transmitMapInfo', {
|
||||||
|
id: item.id,
|
||||||
|
floor: item.floor,
|
||||||
|
area: item.area
|
||||||
|
})
|
||||||
|
let data = await MapApi.getPositionMapdDwnloadPngBase64({
|
||||||
|
floor: item.floor,
|
||||||
|
area: item.area
|
||||||
|
})
|
||||||
|
imgUrl.value = data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -102,13 +102,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- @mousewheel.prevent="rollImg" -->
|
<div class="map-box" ref="imgWrap" :style="{ cursor: state.cursorStyle }">
|
||||||
<div
|
|
||||||
class="map-box"
|
|
||||||
ref="imgWrap"
|
|
||||||
style="overflow: hidden"
|
|
||||||
:style="{ cursor: state.cursorStyle }"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="map-box-inner"
|
class="map-box-inner"
|
||||||
ref="image"
|
ref="image"
|
||||||
@ -116,11 +110,22 @@
|
|||||||
@mousemove.stop="updateDrawSelection"
|
@mousemove.stop="updateDrawSelection"
|
||||||
@mouseup.stop="endDrawSelection"
|
@mouseup.stop="endDrawSelection"
|
||||||
>
|
>
|
||||||
<img :src="imgBgObj.imgUrl" class="map-box-img" id="mapBg" />
|
<img
|
||||||
|
:src="imgBgObj.imgUrl"
|
||||||
|
:style="{
|
||||||
|
width: imgBgObj.width + 'px',
|
||||||
|
height: imgBgObj.height + 'px'
|
||||||
|
}"
|
||||||
|
id="mapBg"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="map-box-inner-dot"
|
class="map-box-inner-dot"
|
||||||
@click="mapClick"
|
@click="mapClick"
|
||||||
:class="state.isShowGrid ? 'grid-show' : ''"
|
:class="state.isShowGrid ? 'grid-show' : ''"
|
||||||
|
:style="{
|
||||||
|
width: imgBgObj.width + 'px',
|
||||||
|
height: imgBgObj.height + 'px'
|
||||||
|
}"
|
||||||
v-if="interfaceRefreshed"
|
v-if="interfaceRefreshed"
|
||||||
>
|
>
|
||||||
<VueDragResizeRotate
|
<VueDragResizeRotate
|
||||||
@ -143,31 +148,83 @@
|
|||||||
:lock-aspect-ratio="item.lockAspectRatio"
|
:lock-aspect-ratio="item.lockAspectRatio"
|
||||||
style="border: none"
|
style="border: none"
|
||||||
>
|
>
|
||||||
|
<!-- 1 路径点 -->
|
||||||
<div
|
<div
|
||||||
class="sdiv"
|
v-if="item.type === 1"
|
||||||
:style="
|
:style="{
|
||||||
currentItemIndex === index ? 'border: 1px dashed #000;box-sizing: border-box;' : ''
|
width: item.locationWide + 'px',
|
||||||
"
|
height: item.locationDeep + 'px',
|
||||||
|
border: ' 1px dashed #000',
|
||||||
|
borderRadius: '50%',
|
||||||
|
backgroundColor: '#000'
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<!-- <img
|
</div>
|
||||||
:src="item.img"
|
<!-- 2 库位点 -->
|
||||||
alt=""
|
<img
|
||||||
style="width: 100%; height: 100%"
|
v-if="item.type === 2"
|
||||||
/> -->
|
src="https://api.znkjfw.com/admin-api/infra/file/4/get/库位库存_png_179_1739326653035.png"
|
||||||
<div
|
alt=""
|
||||||
v-if="item.type !== 7"
|
:style="{
|
||||||
style="width: 100%; height: 100%; background-color: #000; border-radius: 50%"
|
width: item.locationWide + 'px',
|
||||||
></div>
|
height: item.locationDeep + 'px',
|
||||||
<div
|
border: currentItemIndex === index ? '1px dashed #000' : 'none'
|
||||||
v-if="item.type === 7"
|
}"
|
||||||
:style="{
|
/>
|
||||||
fontSize: item.fontSize + 'px',
|
<!-- 3 设备点 -->
|
||||||
fontFamily: item.fontFamily,
|
<img
|
||||||
color: item.fontColor
|
v-if="item.type === 3"
|
||||||
}"
|
src="https://api.znkjfw.com/admin-api/infra/file/4/get/设备点_png_179_1739327151877.png"
|
||||||
>
|
alt=""
|
||||||
{{ item.text }}
|
:style="{
|
||||||
</div>
|
width: item.locationWide + 'px',
|
||||||
|
height: item.locationDeep + 'px',
|
||||||
|
border: currentItemIndex === index ? '1px dashed #000' : 'none'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<!-- 4 停车点 -->
|
||||||
|
<img
|
||||||
|
v-if="item.type === 4"
|
||||||
|
src="https://api.znkjfw.com/admin-api/infra/file/4/get/停车场-01_png_179_1739326933020.png"
|
||||||
|
alt=""
|
||||||
|
:style="{
|
||||||
|
width: item.locationWide + 'px',
|
||||||
|
height: item.locationDeep + 'px',
|
||||||
|
border: currentItemIndex === index ? '1px dashed #000' : 'none'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<!-- 5 区域变更点 -->
|
||||||
|
<img
|
||||||
|
v-if="item.type === 5"
|
||||||
|
src="https://api.znkjfw.com/admin-api/infra/file/4/get/区域_png_179_1739327151876.png"
|
||||||
|
alt=""
|
||||||
|
:style="{
|
||||||
|
width: item.locationWide + 'px',
|
||||||
|
height: item.locationDeep + 'px',
|
||||||
|
border: currentItemIndex === index ? '1px dashed #000' : 'none'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<!-- 6 等待点 -->
|
||||||
|
<img
|
||||||
|
v-if="item.type === 6"
|
||||||
|
src="https://api.znkjfw.com/admin-api/infra/file/4/get/等待点_png_179_1739326991439.png"
|
||||||
|
alt=""
|
||||||
|
:style="{
|
||||||
|
width: item.locationWide + 'px',
|
||||||
|
height: item.locationDeep + 'px',
|
||||||
|
border: currentItemIndex === index ? '1px dashed #000' : 'none'
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="item.type === 7"
|
||||||
|
:style="{
|
||||||
|
color: item.fontColor,
|
||||||
|
fontSize: item.fontSize + 'px',
|
||||||
|
fontFamily: item.fontFamily,
|
||||||
|
border: currentItemIndex === index ? '1px dashed #000' : 'none'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ item.text }}
|
||||||
</div>
|
</div>
|
||||||
</VueDragResizeRotate>
|
</VueDragResizeRotate>
|
||||||
<!-- 文档 https://github.com/a7650/vue3-draggable-resizable/blob/main/docs/document_zh.md#resizable -->
|
<!-- 文档 https://github.com/a7650/vue3-draggable-resizable/blob/main/docs/document_zh.md#resizable -->
|
||||||
@ -215,6 +272,7 @@
|
|||||||
<textFormToolDialog
|
<textFormToolDialog
|
||||||
ref="textFormToolDialogRef"
|
ref="textFormToolDialogRef"
|
||||||
v-if="state.textFormToolShow"
|
v-if="state.textFormToolShow"
|
||||||
|
:inputBoxStyle="inputBoxStyle"
|
||||||
@textFormSuccess="textFormSuccess"
|
@textFormSuccess="textFormSuccess"
|
||||||
/>
|
/>
|
||||||
<!-- 图层选择 -->
|
<!-- 图层选择 -->
|
||||||
@ -278,12 +336,11 @@ const rotateEnd = (angle, item, index) => {
|
|||||||
//选中
|
//选中
|
||||||
const editNodePropertiesRef = ref()
|
const editNodePropertiesRef = ref()
|
||||||
const activatedHandle = (item, index) => {
|
const activatedHandle = (item, index) => {
|
||||||
// console.log('选中', item, index)
|
|
||||||
currentItemIndex.value = index
|
currentItemIndex.value = index
|
||||||
|
|
||||||
//节点编辑
|
//节点编辑
|
||||||
if (toolbarSwitchType.value === 'editNode' && item.type !== 7) {
|
if (toolbarSwitchType.value === 'editNode' && item.type !== 7) {
|
||||||
editNodePropertiesRef.value.open(item)
|
editNodePropertiesRef.value.open(JSON.parse(JSON.stringify(item)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//非选中
|
//非选中
|
||||||
@ -329,9 +386,11 @@ const backNextStep = () => {
|
|||||||
|
|
||||||
//地图点击
|
//地图点击
|
||||||
const mapClick = (e) => {
|
const mapClick = (e) => {
|
||||||
|
//节点
|
||||||
if (toolbarSwitchType.value === 'drawNodes') {
|
if (toolbarSwitchType.value === 'drawNodes') {
|
||||||
//绘制节点
|
//绘制节点
|
||||||
allMapPointInfo.value.push({
|
allMapPointInfo.value.push({
|
||||||
|
positionMapId: imgBgObj.positionMapId, //地图的id
|
||||||
locationX: e.offsetX,
|
locationX: e.offsetX,
|
||||||
locationY: e.offsetY,
|
locationY: e.offsetY,
|
||||||
locationDeep: 16,
|
locationDeep: 16,
|
||||||
@ -342,7 +401,9 @@ const mapClick = (e) => {
|
|||||||
rotatable: false,
|
rotatable: false,
|
||||||
lockAspectRatio: false, //横纵比
|
lockAspectRatio: false, //横纵比
|
||||||
img: '',
|
img: '',
|
||||||
type: 1 //默认类型1 路径节点
|
type: 1, //默认类型1 路径节点
|
||||||
|
dataList: [], //存库位的
|
||||||
|
dataObj: {} //存 设备点 停车点 文字
|
||||||
})
|
})
|
||||||
currentIndex.value++
|
currentIndex.value++
|
||||||
allHistoryList.value.push(JSON.parse(JSON.stringify(allMapPointInfo.value)))
|
allHistoryList.value.push(JSON.parse(JSON.stringify(allMapPointInfo.value)))
|
||||||
@ -350,13 +411,8 @@ const mapClick = (e) => {
|
|||||||
//文字输入
|
//文字输入
|
||||||
if (toolbarSwitchType.value === 'text') {
|
if (toolbarSwitchType.value === 'text') {
|
||||||
state.showInputBox = true
|
state.showInputBox = true
|
||||||
state.inputBoxStyle = {
|
state.inputBoxStyle.locationX = e.offsetX
|
||||||
fontSize: state.textForm.fontSize,
|
state.inputBoxStyle.locationY = e.offsetY
|
||||||
fontFamily: state.textForm.fontFamily,
|
|
||||||
fontColor: state.textForm.fontColor,
|
|
||||||
locationX: e.offsetX,
|
|
||||||
locationY: e.offsetY
|
|
||||||
}
|
|
||||||
|
|
||||||
// 聚焦输入框
|
// 聚焦输入框
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -366,7 +422,6 @@ const mapClick = (e) => {
|
|||||||
}
|
}
|
||||||
//输入文字样式改变
|
//输入文字样式改变
|
||||||
const textFormSuccess = (form) => {
|
const textFormSuccess = (form) => {
|
||||||
state.textForm = JSON.parse(JSON.stringify(form))
|
|
||||||
state.inputBoxStyle = {
|
state.inputBoxStyle = {
|
||||||
fontSize: `${form.fontSize}`,
|
fontSize: `${form.fontSize}`,
|
||||||
fontFamily: `${form.fontFamily}`,
|
fontFamily: `${form.fontFamily}`,
|
||||||
@ -379,7 +434,7 @@ const handleInputEnd = () => {
|
|||||||
state.showInputBox = false
|
state.showInputBox = false
|
||||||
allMapPointInfo.value.push({
|
allMapPointInfo.value.push({
|
||||||
type: 7, //类型 7文字
|
type: 7, //类型 7文字
|
||||||
mapId: '', //地图的id
|
positionMapId: imgBgObj.positionMapId, //地图的id
|
||||||
locationX: state.inputBoxStyle.locationX, //x
|
locationX: state.inputBoxStyle.locationX, //x
|
||||||
locationY: state.inputBoxStyle.locationY, //y
|
locationY: state.inputBoxStyle.locationY, //y
|
||||||
locationDeep: '', //h
|
locationDeep: '', //h
|
||||||
@ -393,44 +448,16 @@ const handleInputEnd = () => {
|
|||||||
text: state.inputBoxValue, //文字内容
|
text: state.inputBoxValue, //文字内容
|
||||||
fontColor: state.inputBoxStyle.fontColor, //文字颜色
|
fontColor: state.inputBoxStyle.fontColor, //文字颜色
|
||||||
fontFamily: state.inputBoxStyle.fontFamily, //字体类型
|
fontFamily: state.inputBoxStyle.fontFamily, //字体类型
|
||||||
fontSize: state.inputBoxStyle.fontSize
|
fontSize: state.inputBoxStyle.fontSize,
|
||||||
|
dataObj: {} //存 设备点 停车点 文字
|
||||||
})
|
})
|
||||||
addEditHistory()
|
addEditHistory()
|
||||||
state.inputBoxValue = ''
|
state.inputBoxValue = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//保存地图
|
|
||||||
const saveMap = async () => {
|
|
||||||
//节点的保存
|
|
||||||
await saveNodeList()
|
|
||||||
}
|
|
||||||
//节点的保存
|
|
||||||
const saveNodeList = async () => {
|
|
||||||
formLoading.value = true
|
|
||||||
|
|
||||||
let list = allHistoryList.value[currentIndex.value]
|
|
||||||
|
|
||||||
list.forEach((item, index) => {
|
|
||||||
item.locationX = item.locationX
|
|
||||||
item.locationY = item.locationY
|
|
||||||
item.type = item.type || 1
|
|
||||||
if (item.type === 1) {
|
|
||||||
item.dataJson = ''
|
|
||||||
} else {
|
|
||||||
item.dataJson = item.dataJson
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
|
||||||
await MapApi.batchSaveOrEditOrDelMapItem(imgBgObj.positionMapId, list)
|
|
||||||
message.success('创建成功')
|
|
||||||
} finally {
|
|
||||||
formLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//编辑节点成功
|
//编辑节点成功
|
||||||
const submitNodeSuccess = (item) => {
|
const submitNodeSuccess = (item) => {
|
||||||
|
allMapPointInfo.value[currentItemIndex.value] = item
|
||||||
allHistoryList.value[currentIndex.value][currentItemIndex.value] = item
|
allHistoryList.value[currentIndex.value][currentItemIndex.value] = item
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,14 +639,15 @@ const state = reactive({
|
|||||||
drawSelectionAreaBox: { x: 0, y: 0, width: 0, height: 0 }, //绘制区域的位置,长宽
|
drawSelectionAreaBox: { x: 0, y: 0, width: 0, height: 0 }, //绘制区域的位置,长宽
|
||||||
drawSelectionAreaStartPos: { x: 0, y: 0 }, //开始绘制的点位
|
drawSelectionAreaStartPos: { x: 0, y: 0 }, //开始绘制的点位
|
||||||
drawSelectionAreaSelectedPoints: [], //绘制选中的list
|
drawSelectionAreaSelectedPoints: [], //绘制选中的list
|
||||||
textForm: {
|
|
||||||
fontFamily: 'SimSun',
|
|
||||||
fontSize: '14',
|
|
||||||
fontColor: '#000000'
|
|
||||||
}, //默认宋体,14,#000000
|
|
||||||
textFormToolShow: false, //文字表单显示隐藏
|
textFormToolShow: false, //文字表单显示隐藏
|
||||||
showInputBox: false, //输入框显示隐藏
|
showInputBox: false, //输入框显示隐藏
|
||||||
inputBoxStyle: {}, //输入框的样式
|
inputBoxStyle: {
|
||||||
|
fontFamily: 'SimSun',
|
||||||
|
fontSize: '14',
|
||||||
|
fontColor: '#000000',
|
||||||
|
locationX: 0,
|
||||||
|
locationY: 0
|
||||||
|
}, //输入框的样式
|
||||||
inputBoxValue: '', //输入的值
|
inputBoxValue: '', //输入的值
|
||||||
isShowLayer: false //图层显示
|
isShowLayer: false //图层显示
|
||||||
})
|
})
|
||||||
@ -759,9 +787,21 @@ const toolbarClick = (item) => {
|
|||||||
break
|
break
|
||||||
case 'larger':
|
case 'larger':
|
||||||
//放大
|
//放大
|
||||||
|
if (imgBgObj.width < 10000) {
|
||||||
|
imgBgObj.width *= 1.2
|
||||||
|
imgBgObj.height *= 1.2
|
||||||
|
} else {
|
||||||
|
message.warning('不能在放大了')
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'smaller':
|
case 'smaller':
|
||||||
//缩小
|
//缩小
|
||||||
|
if (imgBgObj.width > 500) {
|
||||||
|
imgBgObj.width *= 0.8
|
||||||
|
imgBgObj.height *= 0.8
|
||||||
|
} else {
|
||||||
|
message.warning('不能在缩小了')
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'withdraw':
|
case 'withdraw':
|
||||||
//上一步
|
//上一步
|
||||||
@ -824,22 +864,22 @@ const endDrawSelection = () => {
|
|||||||
state.drawSelectionArea = false
|
state.drawSelectionArea = false
|
||||||
state.drawSelectionAreaSelectedPoints = points.filter((point) => {
|
state.drawSelectionAreaSelectedPoints = points.filter((point) => {
|
||||||
return (
|
return (
|
||||||
point.x >=
|
point.locationX >=
|
||||||
Math.min(
|
Math.min(
|
||||||
state.drawSelectionAreaStartPos.x,
|
state.drawSelectionAreaStartPos.x,
|
||||||
state.drawSelectionAreaStartPos.x + state.drawSelectionAreaBox.width
|
state.drawSelectionAreaStartPos.x + state.drawSelectionAreaBox.width
|
||||||
) &&
|
) &&
|
||||||
point.x <=
|
point.locationX <=
|
||||||
Math.max(
|
Math.max(
|
||||||
state.drawSelectionAreaStartPos.x,
|
state.drawSelectionAreaStartPos.x,
|
||||||
state.drawSelectionAreaStartPos.x + state.drawSelectionAreaBox.width
|
state.drawSelectionAreaStartPos.x + state.drawSelectionAreaBox.width
|
||||||
) &&
|
) &&
|
||||||
point.y >=
|
point.locationY >=
|
||||||
Math.min(
|
Math.min(
|
||||||
state.drawSelectionAreaStartPos.y,
|
state.drawSelectionAreaStartPos.y,
|
||||||
state.drawSelectionAreaStartPos.y + state.drawSelectionAreaBox.height
|
state.drawSelectionAreaStartPos.y + state.drawSelectionAreaBox.height
|
||||||
) &&
|
) &&
|
||||||
point.y <=
|
point.locationY <=
|
||||||
Math.max(
|
Math.max(
|
||||||
state.drawSelectionAreaStartPos.y,
|
state.drawSelectionAreaStartPos.y,
|
||||||
state.drawSelectionAreaStartPos.y + state.drawSelectionAreaBox.height
|
state.drawSelectionAreaStartPos.y + state.drawSelectionAreaBox.height
|
||||||
@ -849,75 +889,130 @@ const endDrawSelection = () => {
|
|||||||
console.log(state.drawSelectionAreaSelectedPoints, '选中的')
|
console.log(state.drawSelectionAreaSelectedPoints, '选中的')
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取地图点位
|
//获取扫描图 地图背景相关的信息
|
||||||
const list = ref([])
|
|
||||||
const getMapList = async () => {
|
|
||||||
let data = await MapApi.getPositionMapGetMap()
|
|
||||||
let mapList = []
|
|
||||||
for (let key in data) {
|
|
||||||
mapList.push({
|
|
||||||
floor: key,
|
|
||||||
children: data[key]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
list.value = mapList
|
|
||||||
|
|
||||||
//默认取第一个
|
|
||||||
if (data[1][0]) {
|
|
||||||
getMapData(data[1][0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取扫描图
|
|
||||||
//地图背景
|
|
||||||
const imgBgObj = reactive({
|
const imgBgObj = reactive({
|
||||||
imgUrl: '',
|
imgUrl: '',
|
||||||
positionMapId: '',
|
positionMapId: '',
|
||||||
width: '',
|
width: '',
|
||||||
height: ''
|
height: '',
|
||||||
|
floor: '',
|
||||||
|
area: ''
|
||||||
})
|
})
|
||||||
const getMapData = async (item) => {
|
//接收参数
|
||||||
|
const { query } = useRoute() // 查询参数
|
||||||
|
//获取地图点位
|
||||||
|
const getMapList = async () => {
|
||||||
|
if (query.mapId) {
|
||||||
|
imgBgObj.positionMapId = query.mapId
|
||||||
|
imgBgObj.floor = query.floor
|
||||||
|
imgBgObj.area = query.area
|
||||||
|
//调转换成png的接口
|
||||||
|
getMapData(imgBgObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//调转换成png的接口
|
||||||
|
const getMapData = async (mapInfo) => {
|
||||||
let data = await MapApi.getPositionMapdDwnloadPngBase64({
|
let data = await MapApi.getPositionMapdDwnloadPngBase64({
|
||||||
floor: item.floor,
|
floor: mapInfo.floor,
|
||||||
area: item.area
|
area: mapInfo.area
|
||||||
})
|
})
|
||||||
|
|
||||||
imgBgObj.imgUrl = data
|
imgBgObj.imgUrl = data
|
||||||
imgBgObj.positionMapId = item.id
|
|
||||||
|
|
||||||
|
//获取一下图片的宽高
|
||||||
const img = new Image()
|
const img = new Image()
|
||||||
img.src = imgBgObj.imgUrl
|
img.src = imgBgObj.imgUrl
|
||||||
imgBgObj.width = img.naturalWidth
|
//加载图片成功
|
||||||
imgBgObj.height = img.naturalHeight
|
img.onload = () => {
|
||||||
|
imgBgObj.width = img.naturalWidth
|
||||||
console.log(imgBgObj)
|
imgBgObj.height = img.naturalHeight
|
||||||
|
getAllNodeList()
|
||||||
getAllNodeList()
|
}
|
||||||
|
//加载图片失败
|
||||||
|
img.onerror = () => {
|
||||||
|
console.error('图片加载失败')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//获取所有的点位 处理七种类型的
|
||||||
//获取所有的点位
|
|
||||||
const getAllNodeList = async () => {
|
const getAllNodeList = async () => {
|
||||||
let list = await MapApi.getPositionMapItemList({
|
let list = await MapApi.getPositionMapItemList({
|
||||||
positionMapId: imgBgObj.positionMapId
|
positionMapId: imgBgObj.positionMapId
|
||||||
})
|
})
|
||||||
list.forEach((item) => {
|
list.forEach((item) => {
|
||||||
if (item.type === 2) {
|
if (item.type === 1 || item.type === 5 || item.type === 6) {
|
||||||
|
item.dataObj = {}
|
||||||
|
item.dataList = []
|
||||||
|
item.locationDeep = 16
|
||||||
|
item.locationWide = 16
|
||||||
|
item.draggable = true
|
||||||
|
item.resizable = false
|
||||||
|
item.rotatable = false
|
||||||
|
item.lockAspectRatio = false
|
||||||
|
} else if (item.type === 2) {
|
||||||
//库位点
|
//库位点
|
||||||
let obj = JSON.parse(item.dataJson)[0]
|
item.dataList = JSON.parse(item.dataJson)
|
||||||
|
item.locationDeep = item.dataList[0].locationDeep
|
||||||
|
item.locationWide = item.dataList[0].locationWide
|
||||||
|
item.draggable = true
|
||||||
|
item.resizable = false
|
||||||
|
item.rotatable = false
|
||||||
|
item.lockAspectRatio = false
|
||||||
|
} else if (item.type === 3 || item.type === 4) {
|
||||||
|
item.dataObj = JSON.parse(item.dataJson)
|
||||||
|
item.dataList = []
|
||||||
|
item.locationDeep = item.dataObj.locationDeep
|
||||||
|
item.locationWide = item.dataObj.locationWide
|
||||||
|
item.draggable = true
|
||||||
|
item.resizable = false
|
||||||
|
item.rotatable = false
|
||||||
|
item.lockAspectRatio = false
|
||||||
|
} else if (item.type === 7) {
|
||||||
|
item.dataObj = JSON.parse(item.dataJson)
|
||||||
|
item.text = item.dataObj.text
|
||||||
|
item.fontColor = item.dataObj.fontColor
|
||||||
|
item.fontFamily = item.dataObj.fontFamily
|
||||||
|
item.fontSize = item.dataObj.fontSize
|
||||||
|
item.angle = item.dataObj.angle
|
||||||
|
item.draggable = true
|
||||||
|
item.resizable = false
|
||||||
|
item.rotatable = false
|
||||||
|
item.lockAspectRatio = false
|
||||||
|
}
|
||||||
|
allMapPointInfo.value.push(item)
|
||||||
|
})
|
||||||
|
allHistoryList.value[0] = JSON.parse(JSON.stringify(allMapPointInfo.value))
|
||||||
|
}
|
||||||
|
|
||||||
// allMapPointInfo.value.push()
|
//保存地图按钮
|
||||||
|
const saveMap = async () => {
|
||||||
|
//节点的保存
|
||||||
|
await saveNodeList()
|
||||||
|
//路线的保存
|
||||||
|
}
|
||||||
|
//节点的保存
|
||||||
|
const saveNodeList = async () => {
|
||||||
|
formLoading.value = true
|
||||||
|
let list = allHistoryList.value[currentIndex.value]
|
||||||
|
|
||||||
|
list.forEach((item) => {
|
||||||
|
if (item.type === 7) {
|
||||||
|
item.dataObj.positionMapId = imgBgObj.positionMapId
|
||||||
|
item.dataObj.text = item.text
|
||||||
|
item.dataObj.fontColor = item.fontColor
|
||||||
|
item.dataObj.fontType = item.fontType
|
||||||
|
item.dataObj.fontFamily = item.fontFamily
|
||||||
|
item.dataObj.rotatable = item.rotatable
|
||||||
|
item.dataObj.angle = item.angle
|
||||||
|
//dataJson数据
|
||||||
|
item.dataJson = JSON.stringify(item.dataObj)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// allMapPointInfo.value = list.map((item) => {
|
try {
|
||||||
// return {
|
await MapApi.batchSaveOrEditOrDelMapItem(imgBgObj.positionMapId, list)
|
||||||
// ...JSON.parse(item.dataJson)
|
message.success('创建成功')
|
||||||
// }
|
} finally {
|
||||||
// })
|
formLoading.value = false
|
||||||
// allMapPointInfo.value = allMapPointInfo.value
|
}
|
||||||
// console.log(allMapPointInfo.value)
|
|
||||||
allHistoryList.value[0] = JSON.parse(JSON.stringify(allMapPointInfo.value))
|
|
||||||
console.log(allHistoryList.value[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -929,20 +1024,15 @@ onMounted(() => {
|
|||||||
.map-box {
|
.map-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.map-box-inner {
|
.map-box-inner {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.map-box-img {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.map-box-inner-dot {
|
.map-box-inner-dot {
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-show {
|
.grid-show {
|
||||||
@ -955,12 +1045,6 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sdiv {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-tool {
|
.top-tool {
|
||||||
.top-tool-list {
|
.top-tool-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -989,6 +1073,7 @@ onMounted(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
|
cursor: pointer;
|
||||||
font-family:
|
font-family:
|
||||||
PingFangSC,
|
PingFangSC,
|
||||||
PingFang SC;
|
PingFang SC;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<!-- <div @click="downAgv">导出zip</div> -->
|
<!-- <div @click="downAgv">导出zip</div> -->
|
||||||
<!-- 首页 -->
|
<!-- 首页 -->
|
||||||
<indexPage ref="indexPageRef" />
|
<indexPage ref="indexPageRef" @transmitMapInfo="transmitMapInfo" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 新建任务的弹窗 -->
|
<!-- 新建任务的弹窗 -->
|
||||||
@ -46,9 +46,23 @@ const router = useRouter() // 路由
|
|||||||
const editMap = () => {
|
const editMap = () => {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'editMapPageRealTimeMap',
|
name: 'editMapPageRealTimeMap',
|
||||||
query: {}
|
query: {
|
||||||
|
mapId: mapInfo.value.id,
|
||||||
|
floor: mapInfo.value.floor,
|
||||||
|
area: mapInfo.value.area
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//传输地图信息
|
||||||
|
const mapInfo = ref({
|
||||||
|
mapId: '',
|
||||||
|
floor: '',
|
||||||
|
area: ''
|
||||||
|
})
|
||||||
|
const transmitMapInfo = (map) => {
|
||||||
|
mapInfo.value = map
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
93
src/views/mapPage/realTimeMap/test copy.vue
Normal file
93
src/views/mapPage/realTimeMap/test copy.vue
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
@mousedown="startSelection"
|
||||||
|
@mousemove="updateSelection"
|
||||||
|
@mouseup="endSelection"
|
||||||
|
style="position: relative; width: 100%; height: 900px"
|
||||||
|
>
|
||||||
|
<!-- 绘制框选区域 -->
|
||||||
|
<div
|
||||||
|
v-if="isSelecting"
|
||||||
|
:style="{
|
||||||
|
position: 'absolute',
|
||||||
|
left: `${selectionBox.x}px`,
|
||||||
|
top: `${selectionBox.y}px`,
|
||||||
|
width: `${selectionBox.width}px`,
|
||||||
|
height: `${selectionBox.height}px`,
|
||||||
|
border: '1px solid blue',
|
||||||
|
backgroundColor: 'rgba(0, 0, 255, 0.1)'
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<!-- 绘制点位 -->
|
||||||
|
<div
|
||||||
|
v-for="(point, index) in points"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
position: 'absolute',
|
||||||
|
left: `${point.x}px`,
|
||||||
|
top: `${point.y}px`,
|
||||||
|
width: '100px',
|
||||||
|
height: '100px',
|
||||||
|
backgroundColor: selectedPoints.includes(point) ? 'red' : '#fff'
|
||||||
|
}"
|
||||||
|
>设备{{ index }}</div
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const points = ref([
|
||||||
|
{ x: 210, y: 210 },
|
||||||
|
{ x: 330, y: 500 },
|
||||||
|
{ x: 840, y: 440 },
|
||||||
|
{ x: 230, y: 400 },
|
||||||
|
{ x: 750, y: 640 }
|
||||||
|
])
|
||||||
|
|
||||||
|
const isSelecting = ref(false)
|
||||||
|
const selectionBox = ref({ x: 0, y: 0, width: 0, height: 0 })
|
||||||
|
const startPos = ref({ x: 0, y: 0 })
|
||||||
|
const selectedPoints = ref([])
|
||||||
|
|
||||||
|
const startSelection = (event) => {
|
||||||
|
isSelecting.value = true
|
||||||
|
startPos.value = { x: event.offsetX, y: event.offsetY }
|
||||||
|
selectionBox.value = { x: event.offsetX, y: event.offsetY, width: 0, height: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateSelection = (event) => {
|
||||||
|
if (isSelecting.value) {
|
||||||
|
selectionBox.value.width = event.offsetX - startPos.value.x
|
||||||
|
selectionBox.value.height = event.offsetY - startPos.value.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const endSelection = () => {
|
||||||
|
isSelecting.value = false
|
||||||
|
selectedPoints.value = points.value.filter((point) => {
|
||||||
|
return (
|
||||||
|
point.x >= Math.min(startPos.value.x, startPos.value.x + selectionBox.value.width) &&
|
||||||
|
point.x <= Math.max(startPos.value.x, startPos.value.x + selectionBox.value.width) &&
|
||||||
|
point.y >= Math.min(startPos.value.y, startPos.value.y + selectionBox.value.height) &&
|
||||||
|
point.y <= Math.max(startPos.value.y, startPos.value.y + selectionBox.value.height)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
points,
|
||||||
|
isSelecting,
|
||||||
|
selectionBox,
|
||||||
|
selectedPoints,
|
||||||
|
startSelection,
|
||||||
|
updateSelection,
|
||||||
|
endSelection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,93 +1,180 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div>
|
||||||
@mousedown="startSelection"
|
<!-- SVG 画布 -->
|
||||||
@mousemove="updateSelection"
|
<svg
|
||||||
@mouseup="endSelection"
|
ref="svg"
|
||||||
style="position: relative; width: 100%; height: 900px"
|
width="500"
|
||||||
>
|
height="300"
|
||||||
<!-- 绘制框选区域 -->
|
@mousedown="handleMouseDown"
|
||||||
<div
|
@mousemove="handleMouseMove"
|
||||||
v-if="isSelecting"
|
@mouseup="handleMouseUp"
|
||||||
:style="{
|
|
||||||
position: 'absolute',
|
|
||||||
left: `${selectionBox.x}px`,
|
|
||||||
top: `${selectionBox.y}px`,
|
|
||||||
width: `${selectionBox.width}px`,
|
|
||||||
height: `${selectionBox.height}px`,
|
|
||||||
border: '1px solid blue',
|
|
||||||
backgroundColor: 'rgba(0, 0, 255, 0.1)'
|
|
||||||
}"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<!-- 绘制点位 -->
|
|
||||||
<div
|
|
||||||
v-for="(point, index) in points"
|
|
||||||
:key="index"
|
|
||||||
:style="{
|
|
||||||
position: 'absolute',
|
|
||||||
left: `${point.x}px`,
|
|
||||||
top: `${point.y}px`,
|
|
||||||
width: '100px',
|
|
||||||
height: '100px',
|
|
||||||
backgroundColor: selectedPoints.includes(point) ? 'red' : '#fff'
|
|
||||||
}"
|
|
||||||
>设备{{ index }}</div
|
|
||||||
>
|
>
|
||||||
|
<!-- 绘制所有曲线 -->
|
||||||
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
const svg = ref(null) // SVG 元素的引用
|
||||||
|
const curves = ref([]) // 存储所有曲线
|
||||||
|
const selectedCurve = ref(null) // 当前选中的曲线
|
||||||
|
const isDragging = ref(false) // 是否正在拖拽
|
||||||
|
const dragTarget = ref(null) // 当前拖拽的目标(起点、终点、控制点)
|
||||||
|
|
||||||
export default {
|
// 获取鼠标位置
|
||||||
setup() {
|
const getMousePos = (event) => {
|
||||||
const points = ref([
|
const rect = svg.value.getBoundingClientRect()
|
||||||
{ x: 210, y: 210 },
|
return {
|
||||||
{ x: 330, y: 500 },
|
x: event.clientX - rect.left,
|
||||||
{ x: 840, y: 440 },
|
y: event.clientY - rect.top
|
||||||
{ x: 230, y: 400 },
|
|
||||||
{ x: 750, y: 640 }
|
|
||||||
])
|
|
||||||
|
|
||||||
const isSelecting = ref(false)
|
|
||||||
const selectionBox = ref({ x: 0, y: 0, width: 0, height: 0 })
|
|
||||||
const startPos = ref({ x: 0, y: 0 })
|
|
||||||
const selectedPoints = ref([])
|
|
||||||
|
|
||||||
const startSelection = (event) => {
|
|
||||||
isSelecting.value = true
|
|
||||||
startPos.value = { x: event.offsetX, y: event.offsetY }
|
|
||||||
selectionBox.value = { x: event.offsetX, y: event.offsetY, width: 0, height: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateSelection = (event) => {
|
|
||||||
if (isSelecting.value) {
|
|
||||||
selectionBox.value.width = event.offsetX - startPos.value.x
|
|
||||||
selectionBox.value.height = event.offsetY - startPos.value.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const endSelection = () => {
|
|
||||||
isSelecting.value = false
|
|
||||||
selectedPoints.value = points.value.filter((point) => {
|
|
||||||
return (
|
|
||||||
point.x >= Math.min(startPos.value.x, startPos.value.x + selectionBox.value.width) &&
|
|
||||||
point.x <= Math.max(startPos.value.x, startPos.value.x + selectionBox.value.width) &&
|
|
||||||
point.y >= Math.min(startPos.value.y, startPos.value.y + selectionBox.value.height) &&
|
|
||||||
point.y <= Math.max(startPos.value.y, startPos.value.y + selectionBox.value.height)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
points,
|
|
||||||
isSelecting,
|
|
||||||
selectionBox,
|
|
||||||
selectedPoints,
|
|
||||||
startSelection,
|
|
||||||
updateSelection,
|
|
||||||
endSelection
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 开始拖拽
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
svg {
|
||||||
|
border: 1px solid #000;
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.selected {
|
||||||
|
stroke: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.points {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -356,17 +356,8 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item label="所选车辆电量" label-width="96">
|
||||||
required
|
<el-input v-model="detailItem.electricity" :disabled="true" />
|
||||||
label="所选车辆电量"
|
|
||||||
:prop="`taskDetailList[${index}].electricity`"
|
|
||||||
:rules="{ required: true, message: '所选车辆电量不能为空', trigger: 'change' }"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="detailItem.electricity"
|
|
||||||
placeholder="请输入车辆电量"
|
|
||||||
:disabled="true"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
Loading…
Reference in New Issue
Block a user