地图编辑
This commit is contained in:
parent
c4a5ea4bb1
commit
2853959c19
@ -4,7 +4,7 @@ NODE_ENV=development
|
|||||||
VITE_DEV=true
|
VITE_DEV=true
|
||||||
|
|
||||||
# 请求路径
|
# 请求路径
|
||||||
VITE_BASE_URL='http://192.168.0.74:48080'
|
VITE_BASE_URL='http://192.168.0.66:48080'
|
||||||
# VITE_BASE_URL='http://192.168.0.189:48080'
|
# VITE_BASE_URL='http://192.168.0.189:48080'
|
||||||
|
|
||||||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
|
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
|
||||||
|
@ -79,3 +79,11 @@ export const getDeviceInformationList = async (params) => {
|
|||||||
export const mapBindDeviceInfo = async (data) => {
|
export const mapBindDeviceInfo = async (data) => {
|
||||||
return await request.post({ url: `/system/device/information/mapBindDeviceInfo`, 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 })
|
||||||
|
}
|
||||||
|
@ -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>
|
@ -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>
|
@ -72,14 +72,27 @@
|
|||||||
<Icon :icon="item.icon" :size="24" />
|
<Icon :icon="item.icon" :size="24" />
|
||||||
<div class="name"> {{ item.name }} </div>
|
<div class="name"> {{ item.name }} </div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 分隔线 -->
|
||||||
<div
|
<div
|
||||||
class="line"
|
class="line"
|
||||||
v-if="
|
v-if="
|
||||||
item.switchType === 'saveAs' ||
|
item.switchType === 'saveAs' ||
|
||||||
item.switchType === 'delete' ||
|
item.switchType === 'delete' ||
|
||||||
item.switchType === 'grid'
|
item.switchType === 'grid' ||
|
||||||
|
(item.switchType === 'next' &&
|
||||||
|
(toolbarSwitchType === 'lineLibrary' || toolbarSwitchType === 'region'))
|
||||||
"
|
"
|
||||||
></div>
|
></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>
|
</div>
|
||||||
<div class="right-tool-list" v-if="state.isShowToolbar">
|
<div class="right-tool-list" v-if="state.isShowToolbar">
|
||||||
@ -230,9 +243,24 @@
|
|||||||
<!-- 文档 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 -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 绘制框选区域 -->
|
<!-- 框选区域 -->
|
||||||
<div
|
<div
|
||||||
v-if="state.drawSelectionAreaSelectedPoints"
|
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="{
|
:style="{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: `${state.drawSelectionAreaBox.x}px`,
|
left: `${state.drawSelectionAreaBox.x}px`,
|
||||||
@ -241,10 +269,10 @@
|
|||||||
height: `${state.drawSelectionAreaBox.height}px`,
|
height: `${state.drawSelectionAreaBox.height}px`,
|
||||||
border: '2px dashed #007bff',
|
border: '2px dashed #007bff',
|
||||||
backgroundColor: 'rgba(0, 123, 255, 0.1)',
|
backgroundColor: 'rgba(0, 123, 255, 0.1)',
|
||||||
zIndex: 99999
|
zIndex: 999
|
||||||
}"
|
}"
|
||||||
@click="clickDrawSelectionArea"
|
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<!-- 文字输入区域 -->
|
<!-- 文字输入区域 -->
|
||||||
<input
|
<input
|
||||||
v-if="state.showInputBox"
|
v-if="state.showInputBox"
|
||||||
@ -259,6 +287,7 @@
|
|||||||
left: state.inputBoxStyle.locationX + 'px',
|
left: state.inputBoxStyle.locationX + 'px',
|
||||||
top: state.inputBoxStyle.locationY + 'px'
|
top: state.inputBoxStyle.locationY + 'px'
|
||||||
}"
|
}"
|
||||||
|
:maxlength="30"
|
||||||
class="input-box-class"
|
class="input-box-class"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -284,6 +313,13 @@
|
|||||||
/>
|
/>
|
||||||
<!-- 设备弹窗选择 -->
|
<!-- 设备弹窗选择 -->
|
||||||
<equipmentToolDialog ref="equipmentToolDialogRef" :positionMapId="imgBgObj.positionMapId" />
|
<equipmentToolDialog ref="equipmentToolDialogRef" :positionMapId="imgBgObj.positionMapId" />
|
||||||
|
<!-- 区域选择 -->
|
||||||
|
<itemAreaSettingDialog ref="itemAreaSettingDialogRef" :positionMapId="imgBgObj.positionMapId" />
|
||||||
|
<!-- 线库设置 -->
|
||||||
|
<lineLibrarySettingDialog
|
||||||
|
ref="lineLibrarySettingDialogRef"
|
||||||
|
:positionMapId="imgBgObj.positionMapId"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -291,6 +327,8 @@ import { ref, defineComponent, reactive, nextTick, onMounted } from 'vue'
|
|||||||
import editNodeProperties from './components-tool/editNodeProperties.vue'
|
import editNodeProperties from './components-tool/editNodeProperties.vue'
|
||||||
import textFormToolDialog from './components-tool/textFormToolDialog.vue'
|
import textFormToolDialog from './components-tool/textFormToolDialog.vue'
|
||||||
import equipmentToolDialog from './components-tool/equipmentToolDialog.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 layerSelectionToolDialog from './components-tool/layerSelectionToolDialog.vue'
|
||||||
|
|
||||||
import * as MapApi from '@/api/map/map'
|
import * as MapApi from '@/api/map/map'
|
||||||
@ -298,6 +336,8 @@ import cursorCollection from './cursorCollection'
|
|||||||
|
|
||||||
defineOptions({ name: 'editMapPageRealTimeMap' })
|
defineOptions({ name: 'editMapPageRealTimeMap' })
|
||||||
|
|
||||||
|
const lineLibrarySettingDialogRef = ref() //线库设置
|
||||||
|
const itemAreaSettingDialogRef = ref() //物料区域设置
|
||||||
const equipmentToolDialogRef = ref() //设备弹窗
|
const equipmentToolDialogRef = ref() //设备弹窗
|
||||||
const textFormToolDialogRef = ref() //文字输入弹窗
|
const textFormToolDialogRef = ref() //文字输入弹窗
|
||||||
const inputBoxRef = ref() //文字输入框
|
const inputBoxRef = ref() //文字输入框
|
||||||
@ -643,9 +683,10 @@ const state = reactive({
|
|||||||
copyMapItem: '', //复制的值
|
copyMapItem: '', //复制的值
|
||||||
cursorStyle: 'auto',
|
cursorStyle: 'auto',
|
||||||
drawSelectionAreaShow: false, //绘制框选区域
|
drawSelectionAreaShow: false, //绘制框选区域
|
||||||
|
allDrawSelectionAreaBox: [], // 所有框选区域
|
||||||
drawSelectionAreaBox: { x: 0, y: 0, width: 0, height: 0 }, //绘制区域的位置,长宽
|
drawSelectionAreaBox: { x: 0, y: 0, width: 0, height: 0 }, //绘制区域的位置,长宽
|
||||||
drawSelectionAreaStartPos: { x: 0, y: 0 }, //开始绘制的点位
|
drawSelectionStartPoint: { x: 0, y: 0 }, //开始绘制的点位
|
||||||
drawSelectionAreaSelectedPoints: [], //绘制选中的list
|
drawSelectionPointList: [], //绘制选中的list
|
||||||
textFormToolShow: false, //文字表单显示隐藏
|
textFormToolShow: false, //文字表单显示隐藏
|
||||||
showInputBox: false, //输入框显示隐藏
|
showInputBox: false, //输入框显示隐藏
|
||||||
inputBoxStyle: {
|
inputBoxStyle: {
|
||||||
@ -689,6 +730,13 @@ const toolbarClick = (item) => {
|
|||||||
state.inputBoxValue = ''
|
state.inputBoxValue = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//工具切换 不适用框选的 要把框选的信息都删掉
|
||||||
|
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') {
|
||||||
|
state.drawSelectionAreaShow = false
|
||||||
|
state.allDrawSelectionAreaBox = []
|
||||||
|
state.drawSelectionPointList = []
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'open':
|
case 'open':
|
||||||
// 打开
|
// 打开
|
||||||
@ -869,57 +917,69 @@ const rotationFormSubmit = () => {
|
|||||||
const startDrawSelection = (event) => {
|
const startDrawSelection = (event) => {
|
||||||
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
|
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
|
||||||
state.drawSelectionAreaShow = true
|
state.drawSelectionAreaShow = true
|
||||||
state.drawSelectionAreaStartPos = { x: event.offsetX, y: event.offsetY }
|
state.drawSelectionStartPoint = { x: event.offsetX, y: event.offsetY }
|
||||||
state.drawSelectionAreaBox = { x: event.offsetX, y: event.offsetY, width: 0, height: 0 }
|
state.drawSelectionAreaBox = { x: event.offsetX, y: event.offsetY, width: 0, height: 0 }
|
||||||
|
// 阻止默认行为(避免选中图片或文本)
|
||||||
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
// 更新框选区域
|
||||||
const updateDrawSelection = (event) => {
|
const updateDrawSelection = (event) => {
|
||||||
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
|
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
|
||||||
if (state.drawSelectionAreaShow) {
|
if (state.drawSelectionAreaShow) {
|
||||||
state.drawSelectionAreaBox.width = event.offsetX - state.drawSelectionAreaStartPos.x
|
state.drawSelectionAreaBox.width = event.offsetX - state.drawSelectionStartPoint.x
|
||||||
state.drawSelectionAreaBox.height = event.offsetY - state.drawSelectionAreaStartPos.y
|
state.drawSelectionAreaBox.height = event.offsetY - state.drawSelectionStartPoint.y
|
||||||
}
|
}
|
||||||
|
// 阻止默认行为(避免选中图片或文本)
|
||||||
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
//结束框选绘制
|
//结束框选绘制
|
||||||
const endDrawSelection = () => {
|
const endDrawSelection = () => {
|
||||||
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
|
if (toolbarSwitchType.value !== 'lineLibrary' && toolbarSwitchType.value !== 'region') return
|
||||||
state.drawSelectionAreaShow = false
|
state.drawSelectionAreaShow = false
|
||||||
let points = allHistoryList.value[currentIndex.value]
|
state.allDrawSelectionAreaBox.push({ ...state.drawSelectionAreaBox })
|
||||||
state.drawSelectionAreaSelectedPoints = points.filter((point) => {
|
state.drawSelectionAreaBox = { x: 0, y: 0, width: 0, height: 0 }
|
||||||
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
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
//点击区域
|
//点击区域
|
||||||
const clickDrawSelectionArea = () => {
|
const clickDrawSelectionArea = () => {
|
||||||
|
let points = allHistoryList.value[currentIndex.value]
|
||||||
|
|
||||||
|
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.drawSelectionPointList, '选中的')
|
||||||
|
|
||||||
|
// 清空框选区域
|
||||||
|
state.allDrawSelectionAreaBox = []
|
||||||
|
//只要库位的
|
||||||
|
let binLocation = state.drawSelectionPointList.filter((item) => item.type === 2)
|
||||||
|
|
||||||
if (toolbarSwitchType.value === 'lineLibrary') {
|
if (toolbarSwitchType.value === 'lineLibrary') {
|
||||||
//线库
|
//线库
|
||||||
|
if (binLocation.length < 2) {
|
||||||
|
message.warning('至少选择两个库位')
|
||||||
|
} else {
|
||||||
|
lineLibrarySettingDialogRef.value.open(binLocation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (toolbarSwitchType.value === 'region') {
|
if (toolbarSwitchType.value === 'region') {
|
||||||
//区域
|
//区域
|
||||||
|
if (binLocation.length < 1) {
|
||||||
|
message.warning('至少选择两个库位')
|
||||||
|
} else {
|
||||||
|
itemAreaSettingDialogRef.value.open(binLocation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(state.drawSelectionAreaSelectedPoints, '选中的')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取扫描图 地图背景相关的信息
|
//获取扫描图 地图背景相关的信息
|
||||||
@ -989,7 +1049,7 @@ const getAllNodeList = async () => {
|
|||||||
item.dataList = JSON.parse(item.dataJson)
|
item.dataList = JSON.parse(item.dataJson)
|
||||||
item.locationDeep = item.dataList[0].locationDeep
|
item.locationDeep = item.dataList[0].locationDeep
|
||||||
item.locationWide = item.dataList[0].locationWide
|
item.locationWide = item.dataList[0].locationWide
|
||||||
item.draggable = false
|
item.draggable = true
|
||||||
item.resizable = false
|
item.resizable = false
|
||||||
item.rotatable = false
|
item.rotatable = false
|
||||||
item.lockAspectRatio = true
|
item.lockAspectRatio = true
|
||||||
@ -998,7 +1058,7 @@ const getAllNodeList = async () => {
|
|||||||
item.dataList = []
|
item.dataList = []
|
||||||
item.locationDeep = item.dataObj.locationDeep
|
item.locationDeep = item.dataObj.locationDeep
|
||||||
item.locationWide = item.dataObj.locationWide
|
item.locationWide = item.dataObj.locationWide
|
||||||
item.draggable = false
|
item.draggable = true
|
||||||
item.resizable = false
|
item.resizable = false
|
||||||
item.rotatable = false
|
item.rotatable = false
|
||||||
item.lockAspectRatio = true
|
item.lockAspectRatio = true
|
||||||
@ -1185,4 +1245,9 @@ onMounted(() => {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selection-area-btn {
|
||||||
|
width: 80px;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -19,20 +19,21 @@
|
|||||||
}"
|
}"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<!-- 坐标点 -->
|
<!-- 图片 -->
|
||||||
<div
|
<img
|
||||||
v-for="(point, index) in points"
|
v-for="(img, index) in images"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
:src="img.src"
|
||||||
:style="{
|
:style="{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: `${point.x}px`,
|
left: `${img.x}px`,
|
||||||
top: `${point.y}px`,
|
top: `${img.y}px`,
|
||||||
width: '10px',
|
width: '100px',
|
||||||
height: '10px',
|
height: '100px',
|
||||||
backgroundColor: selectedPoints.includes(point) ? 'red' : 'blue',
|
userSelect: isSelecting ? 'none' : 'auto', // 动态禁用选择
|
||||||
borderRadius: '50%'
|
pointerEvents: isSelecting ? 'none' : 'auto' // 动态禁用鼠标事件
|
||||||
}"
|
}"
|
||||||
></div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -41,13 +42,11 @@ import { ref } from 'vue'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
// 坐标数组
|
// 图片数据
|
||||||
const points = ref([
|
const images = ref([
|
||||||
{ x: 300, y: 400 },
|
{ src: 'https://via.placeholder.com/100', x: 100, y: 100 },
|
||||||
{ x: 400, y: 400 },
|
{ src: 'https://via.placeholder.com/100', x: 300, y: 200 },
|
||||||
{ x: 200, y: 360 },
|
{ src: 'https://via.placeholder.com/100', x: 500, y: 300 }
|
||||||
{ x: 570, y: 260 },
|
|
||||||
{ x: 600, y: 477 }
|
|
||||||
])
|
])
|
||||||
|
|
||||||
// 框选区域
|
// 框选区域
|
||||||
@ -61,64 +60,52 @@ export default {
|
|||||||
// 是否正在框选
|
// 是否正在框选
|
||||||
const isSelecting = ref(false)
|
const isSelecting = ref(false)
|
||||||
|
|
||||||
// 选中的点
|
|
||||||
const selectedPoints = ref([])
|
|
||||||
|
|
||||||
// 框选起始位置
|
// 框选起始位置
|
||||||
const startPos = ref({ x: 0, y: 0 })
|
const startPos = ref({ x: 0, y: 0 })
|
||||||
|
|
||||||
// 开始框选
|
// 开始框选
|
||||||
const startSelection = (event) => {
|
const startSelection = (event) => {
|
||||||
isSelecting.value = true
|
isSelecting.value = true
|
||||||
startPos.value = { x: event.offsetX, y: event.offsetY }
|
startPos.value = { x: event.clientX, y: event.clientY }
|
||||||
selectionBox.value = {
|
selectionBox.value = {
|
||||||
x: event.offsetX,
|
x: event.clientX,
|
||||||
y: event.offsetY,
|
y: event.clientY,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0
|
height: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 阻止默认行为(避免选中图片或文本)
|
||||||
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新框选区域
|
// 更新框选区域
|
||||||
const updateSelection = (event) => {
|
const updateSelection = (event) => {
|
||||||
if (!isSelecting.value) return
|
if (!isSelecting.value) return
|
||||||
|
|
||||||
const offsetX = event.offsetX
|
const currentX = event.clientX
|
||||||
const offsetY = event.offsetY
|
const currentY = event.clientY
|
||||||
|
|
||||||
selectionBox.value = {
|
selectionBox.value = {
|
||||||
x: Math.min(startPos.value.x, offsetX),
|
x: Math.min(startPos.value.x, currentX),
|
||||||
y: Math.min(startPos.value.y, offsetY),
|
y: Math.min(startPos.value.y, currentY),
|
||||||
width: Math.abs(offsetX - startPos.value.x),
|
width: Math.abs(currentX - startPos.value.x),
|
||||||
height: Math.abs(offsetY - startPos.value.y)
|
height: Math.abs(currentY - startPos.value.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 阻止默认行为(避免选中图片或文本)
|
||||||
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 结束框选
|
// 结束框选
|
||||||
const endSelection = () => {
|
const endSelection = () => {
|
||||||
isSelecting.value = false
|
isSelecting.value = false
|
||||||
checkSelectedPoints()
|
console.log('框选区域:', selectionBox.value)
|
||||||
}
|
|
||||||
|
|
||||||
// 判断哪些点在框选区域内
|
|
||||||
const checkSelectedPoints = () => {
|
|
||||||
selectedPoints.value = points.value.filter((point) => {
|
|
||||||
return (
|
|
||||||
point.x >= selectionBox.value.x &&
|
|
||||||
point.x <= selectionBox.value.x + selectionBox.value.width &&
|
|
||||||
point.y >= selectionBox.value.y &&
|
|
||||||
point.y <= selectionBox.value.y + selectionBox.value.height
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('选中的点:', selectedPoints.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
points,
|
images,
|
||||||
selectionBox,
|
selectionBox,
|
||||||
isSelecting,
|
isSelecting,
|
||||||
selectedPoints,
|
|
||||||
startSelection,
|
startSelection,
|
||||||
updateSelection,
|
updateSelection,
|
||||||
endSelection
|
endSelection
|
||||||
@ -128,5 +115,11 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 可选:添加一些样式 */
|
/* 禁用用户选择 */
|
||||||
|
img {
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user