feat: 设备关联布点接口联调完成

develop
donghao 10 months ago
parent b90f29af6a
commit 8c1b3d5463

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-08-02 10:40:49
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-08-14 17:09:46
* @LastEditTime: 2024-08-15 16:14:24
* @FilePath: \General-AI-Platform-Web-Client\src\api\workshops.ts
* @Description:
*/
@ -75,3 +75,17 @@ export const addWorkshopDevicesApi = (data?: object) => {
data
});
};
/** 编辑布点设备 data有id */
export const editWorkshopDevicesApi = (data?: object) => {
return http.request<Result>("post", baseUrlApi("workshop_devices/"), {
data
});
};
/** 删除布点设备 status: 1 */
export const deleteWorkshopDevicesApi = (data?: object) => {
return http.request<Result>("post", baseUrlApi("workshop_devices/"), {
data: { ...data, status: 1 }
});
};

@ -2,7 +2,7 @@
* @Author:
* @Date: 2023-06-13 23:00:43
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-08-07 17:17:54
* @LastEditTime: 2024-08-15 16:28:40
* @Description:
*/
@ -174,9 +174,15 @@ function deleteControl(canvas: fabric.Canvas) {
if (target.action === "rotate") return true;
const activeObject = canvas.getActiveObjects();
if (activeObject) {
activeObject.map(item => canvas.remove(item));
canvas.requestRenderAll();
canvas.discardActiveObject();
// 发送删除事件
canvas.fire("object:deleteObject", {
...activeObject,
deleteCallback: () => {
activeObject.map(item => canvas.remove(item));
canvas.requestRenderAll();
canvas.discardActiveObject();
}
});
}
return true;
}

@ -2,12 +2,13 @@
* @Author:
* @Date: 2023-06-20 12:57:35
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-08-06 17:14:38
* @LastEditTime: 2024-08-15 15:51:16
* @Description:
*/
import { fabric } from "fabric";
import Editor from "../core";
type IEditor = Editor;
// import { v4 as uuid } from 'uuid';

@ -6,34 +6,45 @@ import { textTypeConf } from "@/config/attribute/baseType";
import video_type_1 from "@/assets/modelSetting/video_type_1.png";
import video_type_2 from "@/assets/modelSetting/video_type_2.png";
import video_type_3 from "@/assets/modelSetting/video_type_3.png";
import {
deleteWorkshopDevicesApi,
editWorkshopDevicesApi
} from "@/api/workshops";
import { isSuccessApi } from "@/utils/forApi";
const props = defineProps({
pointInfo: {
type: Object as Record<string, any>
}
});
const event = inject("event");
const update = getCurrentInstance();
const { mixinState, canvasEditor } = useSelect();
/**业务属性 */
const formData = ref({
iconType: 1
icon: 1
});
const rules = {
iconType: [{ required: true, message: "请选择图标类型", trigger: "change" }]
icon: [{ required: true, message: "请选择图标类型", trigger: "change" }]
};
const iconOptions = ref([
{
value: 1,
value: "1",
label: "图标1",
type: "1",
url: video_type_1
},
{
value: 2,
value: "2",
label: "图标2",
type: "2",
url: video_type_2
},
{
value: 3,
value: "3",
label: "图标3",
type: "3",
url: video_type_3
@ -181,10 +192,43 @@ const getObjectAttr = e => {
const animateObject = activeObject.get("animation");
animationAttr.type = animateObject.type;
}
//
if (activeObject.get("deviceInfo")) {
formData.value = activeObject.get("deviceInfo");
}
}
};
//
async function deleteDeviceObject(deleteObject) {
const currDeviceInfo = deleteObject[0].get("deviceInfo");
console.log(currDeviceInfo, "deleteDeviceObject", deleteObject);
const resp = await deleteWorkshopDevicesApi({
id: currDeviceInfo.id
});
if (isSuccessApi(resp)) {
deleteObject.deleteCallback();
}
}
const selectCancel = () => {
//
async function editDeviceObject(callback) {
const activeObject = canvasEditor.canvas.getActiveObject();
const currDeviceInfo = activeObject.get("deviceInfo");
console.log(activeObject, "editDeviceObject_activeObject", currDeviceInfo);
const resp = await editWorkshopDevicesApi({
id: currDeviceInfo.id,
device_id: currDeviceInfo.device_id,
workshop_id: currDeviceInfo.workshop_id,
x_ordinate: activeObject.get("left"),
y_ordinate: activeObject.get("top"),
icon: formData.value.icon
});
if (isSuccessApi(resp)) {
console.log("编辑完成");
callback(resp);
}
}
const selectCancel = e => {
baseAttr.fill = "";
update?.proxy?.$forceUpdate();
};
@ -193,10 +237,15 @@ const init = () => {
//
event.on("selectCancel", selectCancel);
event.on("selectOne", getObjectAttr);
canvasEditor.canvas.on("object:deleteObject", deleteDeviceObject);
canvasEditor.canvas.on("mouse:up", () => {
editDeviceObject();
});
canvasEditor.canvas.on("object:modified", getObjectAttr);
// object:moving
canvasEditor.canvas.on("object:moving", e => {
const activeObject = e.target;
// console.log(activeObject, "activeObject_moving");
if (activeObject) {
constrainObjectWithinCanvas(activeObject);
canvasEditor.canvas.renderAll();
@ -238,7 +287,7 @@ const changeCommon = (key, value) => {
canvasEditor.canvas.renderAll();
return;
}
if (key === "iconType") {
if (key === "icon") {
// group fabric.Image
const imageObject = activeObject._objects[1];
@ -250,16 +299,18 @@ const changeCommon = (key, value) => {
if (targetIcon) {
//
imageObject.setSrc(
targetIcon.url,
() => {
//
console.log("Image loaded successfully activeObject_iconType");
activeObject.addWithUpdate(); //
canvasEditor.canvas.renderAll();
},
{ crossOrigin: "anonymous" }
);
editDeviceObject(() => {
imageObject.setSrc(
targetIcon.url,
() => {
//
console.log("Image loaded successfully activeObject_iconType");
activeObject.addWithUpdate(); //
canvasEditor.canvas.renderAll();
},
{ crossOrigin: "anonymous" }
);
});
//
// fabric.Image.fromURL(
@ -302,12 +353,14 @@ onMounted(init);
onBeforeUnmount(() => {
event.off("selectCancel", selectCancel);
event.off("selectOne", getObjectAttr);
canvasEditor.canvas.off("object:deleteObject");
canvasEditor.canvas.off("mouse:up");
canvasEditor.canvas.off("object:modified", getObjectAttr);
canvasEditor.canvas.off("object:moving");
});
</script>
<template>
<div class="box" v-if="mixinState.mSelectMode === 'one'">
<div class="deviceAtrr_toolbar" v-if="mixinState.mSelectMode === 'one'">
<!-- 字体属性 -->
<div v-show="textTypeConf.includes(mixinState.mSelectOneType)">
<!-- 字体属性 -->
@ -334,20 +387,21 @@ onBeforeUnmount(() => {
class="demo-form-inline"
label-position="top"
>
<el-form-item label="选择图标" class="w-full" prop="iconType">
<el-form-item label="选择图标" class="w-full" prop="icon">
<el-radio-group
v-model="formData.iconType"
@change="changeCommon('iconType', formData.iconType)"
v-model="formData.icon"
@change="changeCommon('icon', formData.icon)"
>
<el-radio
v-for="option in iconOptions"
:key="option.value"
:label="option.value"
>
<i>
<!-- 图标 -->
</i>
{{ option.label }}
<el-image
:src="option?.url || ''"
:fit="'contain'"
class="w-[24px]"
/>
</el-radio>
</el-radio-group>
</el-form-item>

@ -1,40 +1,10 @@
<!--
* @Description: 设备选择
-->
<template>
<div v-if="!mixinState.mSelectMode">
<div class="px-[12px] deviceSelect_toolbar">
<div>
<h4 class="hf-1 py-[12px]">设备列表</h4>
<p class="pf-2">
可直接点击拖拽设备名称至图中目标位置鼠标悬停可查看设备详情
</p>
<ul class="mt-[8px] deviceSelect_list">
<li
class="flex items-center px-[16px] mb-[12px]"
:class="detailInfo?.id === info.id ? 'active' : ''"
v-for="(info, i) in props.deviceList"
:key="`${i}-logo1-button`"
:draggable="true"
@click="addItem(info)"
@dragend="event => dragItem(event, info)"
>
<span>
{{ info.name }}
</span>
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup name="CanvasSize" lang="ts">
// import { Modal } from "view-ui-plus";
import useSelect from "@/hooks/select";
// import { cloneDeep } from "lodash-es";
import { v4 as uuid } from "uuid";
// import { useI18n } from "vue-i18n";
import { useDeviceObject } from "../hooks/useDeviceObject";
@ -48,6 +18,8 @@ const props = defineProps({
}
});
const emit = defineEmits(["addDevice"]);
const { fabric, mixinState, canvasEditor } = useSelect();
const { initDeviceGroupObjects } = useDeviceObject();
// const { t } = useI18n();
@ -104,6 +76,7 @@ canvasEditor.getMaterialType("svg").then((list: materialTypeI[]) => {
function fetchDetail(record) {
detailInfo.value = record;
console.log(detailInfo.value, "fetchDetail");
emit("addDevice", record);
}
/**
@ -126,7 +99,6 @@ const dragItem = (event, deviceItem) => {
...defaultPosition,
shadow: "",
fontFamily: "arial",
id: uuid(),
name: "svg元素",
...initDeviceGroupObjects(deviceItem)
}
@ -143,7 +115,8 @@ const dragItem = (event, deviceItem) => {
// var canvas = new fabric.Canvas('canvas-id');
// canvas.add(group);
canvasEditor.dragAddItem(event, item);
fetchDetail(deviceItem);
console.log(event, item, "dragItem");
// fetchDetail(deviceItem);
// Canvas
// canvas.renderAll();
}
@ -155,16 +128,15 @@ const addItem = deviceItem => {
if (isValidAdd(deviceItem)) {
return;
}
console.log(deviceItem, "addItem_deviceItem");
fabric.util.enlivenObjects(
[
{
...defaultPosition,
id: uuid(),
// name: "svg",
...initDeviceGroupObjects(deviceItem)
}
],
function (objects) {
// objects JSONGroup
const item = objects[0];
@ -189,13 +161,43 @@ const addItem = deviceItem => {
// const item = fabric.util.groupSVGElements(objects, {
// ...options,
// ...defaultPosition,
// id: uuid(),
// name: "svg"
// });
// });
};
//
function renderDeviceToCanvas(record) {
const startArr = record;
const finalArr = [];
startArr.map(deviceItem => {
const fullDeviceItem = {
...defaultPosition,
...deviceItem,
left: Number(deviceItem.x_ordinate),
top: Number(deviceItem.y_ordinate),
name: deviceItem.device_name
};
finalArr.push({
...fullDeviceItem,
...initDeviceGroupObjects(fullDeviceItem)
});
});
fabric.util.enlivenObjects([...finalArr], function (enlivenedObjects) {
enlivenedObjects.forEach(groupObject => {
if (groupObject.type === "group") {
// group canvas
canvasEditor.canvas.add(groupObject);
}
});
// objects JSONGroup
const item = enlivenedObjects[0];
canvasEditor.canvas.setActiveObject(item);
canvasEditor.canvas.requestRenderAll();
});
}
// const DefaultSize = {
// width: 1200,
// height: 900
@ -234,17 +236,16 @@ const addItem = deviceItem => {
// height: 1200
// }
// ]);
const DefaultSize = {
width: 947,
height: 642
};
// const DefaultSize = {
// width: 977,
// height: 670
// };
onMounted(() => {
canvasEditor.setSize(DefaultSize.width, DefaultSize.height);
canvasEditor.on("sizeChange", (width, height) => {
width.value = width;
height.value = height;
});
// canvasEditor.setSize(DefaultSize.width, DefaultSize.height);
// canvasEditor.on("sizeChange", (width, height) => {
// width.value = width;
// height.value = height;
// });
// canvas.editor.editorWorkspace.setSize(width.value, height.value);
// canvas.editor.editorWorkspace = new EditorWorkspace(canvas.c, {
// width: width.value,
@ -272,17 +273,45 @@ onMounted(() => {
// handleClose();
// };
watch(
() => props.deviceList,
() => {
console.log(props.deviceList, "watch_deviceList");
},
{
immediate: true,
deep: true
}
);
// watch(
// () => props.deviceList,
// () => {
// console.log(props.deviceList, "watch_deviceList");
// },
// {
// immediate: true,
// deep: true
// }
// );
defineExpose({ renderDeviceToCanvas });
</script>
<template>
<div v-if="!mixinState.mSelectMode">
<div class="px-[12px] deviceSelect_toolbar">
<div>
<h4 class="hf-1 py-[12px]">设备列表</h4>
<p class="pf-2">
可直接点击拖拽设备名称至图中目标位置鼠标悬停可查看设备详情
</p>
<ul class="mt-[8px] deviceSelect_list">
<li
class="flex items-center px-[16px] mb-[12px]"
:class="detailInfo?.id === info.id ? 'active' : ''"
v-for="(info, i) in props.deviceList"
:key="`${i}-logo1-button`"
:draggable="true"
@click="addItem(info)"
@dragend="event => dragItem(event, info)"
>
<span>
{{ info.name }}
</span>
</li>
</ul>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.search-box {
@ -312,4 +341,3 @@ watch(
margin-bottom: 10px;
}
</style>
../hooks/useWatchModels../hooks/useDeviceObject

@ -4,31 +4,32 @@
*/
// https://t7.baidu.com/it/u=2757924858,1404466263&fm=193
import video_type_1 from "@/assets/modelSetting/video_type_1.png";
import video_type_2 from "@/assets/modelSetting/video_type_2.png";
import video_type_3 from "@/assets/modelSetting/video_type_3.png";
import { v4 as uuid } from "uuid";
export const useDeviceObject = () => {
const initDeviceGroupObjects: Record<string, any> = (record: {
id: string;
value: string;
}) => {
const initDeviceGroupObjects: Record<string, any> = record => {
console.log(record, "initDeviceGroupObjects");
// const { value } = record;
// let watchIconObject = watchIcon2;
// switch (value) {
// case "watchError":
// watchIconObject = watchIcon1;
// break;
// case "watchOnline":
// watchIconObject = watchIcon2;
// break;
// case "watchOutline":
// watchIconObject = watchIcon3;
// break;
// case "watchWarn":
// default:
// watchIconObject = watchIcon4;
// break;
// }
let iconObjectSrc = video_type_1;
switch (record?.icon) {
case "3":
iconObjectSrc = video_type_3;
break;
case "2":
iconObjectSrc = video_type_2;
break;
case "1":
default:
iconObjectSrc = video_type_1;
break;
}
return {
id: uuid(),
deviceInfo: record, // 设备信息
left: record?.x_ordinate ? Number(record?.x_ordinate) : 0,
top: record?.y_ordinate ? Number(record?.y_ordinate) : 0,
selectable: true,
hasControls: true,
lockUniScaling: true, // 当设置为trueObject将无法被锁定比例进行缩放。默认值为false。
@ -39,8 +40,7 @@ export const useDeviceObject = () => {
version: "5.3.0",
originX: "left",
originY: "top",
left: 87.4695,
top: 85.8002,
width: 113,
height: 66,
fill: "rgb(0,0,0)",
@ -66,7 +66,6 @@ export const useDeviceObject = () => {
globalCompositeOperation: "source-over",
skewX: 0,
skewY: 0,
id: "520579bf-b8b3-451b-b3aa-5b8a9d6cd1a8",
objects: [
{
type: "image",
@ -144,7 +143,7 @@ export const useDeviceObject = () => {
cropY: 0,
selectable: false,
hasControls: false,
src: video_type_1,
src: iconObjectSrc,
crossOrigin: null,
filters: []
},

@ -1,5 +1,14 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-08-14 11:26:47
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-08-15 13:25:48
* @FilePath: \General-AI-Platform-Web-Client\src\views\deviceSetting\hooks\usePointObject.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export const usePointObject = () => {
function getPointObject(record) {
function getPointObject(record, objectOptions) {
const { width, height } = objectOptions;
const { picture } = record;
// TODO: 获取点位对象
return JSON.stringify({
@ -12,9 +21,9 @@ export const usePointObject = () => {
originY: "top",
left: 0,
top: 0,
width: 947,
height: 610,
fill: "rgba(255,35,255,1)",
width: width,
height: height,
fill: "rgba(21, 77, 221, 0.1)",
stroke: null,
strokeWidth: 0,
strokeDashArray: null,
@ -48,8 +57,10 @@ export const usePointObject = () => {
version: "5.3.0",
originX: "left",
originY: "top",
width: 947,
height: 610,
left: 0,
top: 0,
width: width,
height: height,
fill: "rgb(0,0,0)",
stroke: null,
strokeWidth: 0,

@ -60,12 +60,12 @@
padding-top: 40px;
.bg_preview {
height: 412px;
background-color: red;
border: 1px dashed #ddd;
}
}
.point_detail_wrap {
.deviceOfPoint_wrap {
background-color: goldenrod;
border: 1px dashed #ddd;
height: calc(100vh - 290px);
}
.footer_btns {
@ -78,8 +78,8 @@
.right-bar {
margin-left: 16px;
width: 241px;
height: 100%;
overflow-y: auto;
height: calc(100vh - 300px);
overflow-y: scroll;
}
#workspace {
flex: 1;
@ -100,3 +100,10 @@
}
}
}
/* 设备属性栏位 */
.deviceAtrr_toolbar {
.el-radio__label {
display: flex;
align-items: center;
}
}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-08-02 10:52:32
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-08-14 17:10:19
* @LastEditTime: 2024-08-15 17:11:29
* @FilePath: \General-AI-Platform-Web-Client\src\views\deviceSetting\index.vue
* @Description: 设备点位管理设置
@ 交互说明
@ -19,7 +19,13 @@ import DeviceSettingAdd from "./components/add.vue";
import DeviceSelect from "./components/deviceSelect.vue";
import { IsDelete } from "@/components/Action";
import { usePointObject } from "./hooks/usePointObject";
import { getWorkshopsApi, deleteWorkshopsApi } from "@/api/workshops";
import {
getWorkshopsApi,
deleteWorkshopsApi,
addWorkshopDevicesApi,
getWorkshopDevicesApi
} from "@/api/workshops";
import { getLinkDevicesApi } from "@/api/device";
import { isSuccessApi } from "@/utils/forApi";
@ -68,30 +74,37 @@ const state = reactive({
* @设备点位
*/
const { getPointObject } = usePointObject();
const pointList = ref([]);
const deviceSettingAddRef = ref("");
const deviceSelectRef = ref("");
const activePointId = ref("");
const activePoint = ref({
name: ""
});
const deviceList = ref([]);
const deviceList = ref([]); //
const currDeviceList = ref([]); //
const isDeleteVisible = ref(false);
//
const initFile = () => {
// console.log("canvasEditor");
canvasEditor.insertSvgFile(getPointObject(toRaw(activePoint.value)));
//
const refreshCanvas = () => {
const currWorkSpace = document.getElementById("workspace");
canvasEditor.insertSvgFile(
getPointObject(toRaw(activePoint.value), {
width: currWorkSpace.clientWidth,
height: currWorkSpace.clientHeight
})
);
fetchDeviceByPoint();
console.log("插入文件");
};
// fabric&
const initFabric = () => {
const canvas = new fabric.Canvas("canvas", {
fireRightClick: true, // button3
fireRightClick: false, // button3
stopContextMenu: true, //
controlsAboveOverlay: true // clipPath
});
canvas.loadFromJSON(
getPointObject(toRaw(activePoint.value)),
canvas.renderAll.bind(canvas)
);
//
canvasEditor.init(canvas);
canvasEditor.use(DringPlugin);
@ -116,7 +129,7 @@ const initFabric = () => {
event.init(canvas);
state.showFabric = true;
nextTick(() => {
initFile();
refreshCanvas();
});
};
@ -157,10 +170,12 @@ async function fetchPointList() {
}
//
async function fetchDeviceList() {
const { data } = await getLinkDevicesApi();
// TODO 使loading
deviceList.value = data;
console.log(deviceList.value, "fetchDeviceList_data", data);
const { data, ...resp } = await getLinkDevicesApi();
if (isSuccessApi(resp)) {
// TODO 使loading
deviceList.value = data;
console.log(deviceList.value, "fetchDeviceList_data", data);
}
}
//
function tabPoint(tab) {
@ -168,7 +183,7 @@ function tabPoint(tab) {
activePoint.value = selectedTab;
console.log(tab.props.name, "tabPoint", activePoint.value);
nextTick(() => {
initFile();
refreshCanvas();
});
}
@ -185,7 +200,7 @@ function afterFinishAdd(record) {
activePoint.value = record;
console.log("afterFinishAdd", record);
nextTick(() => {
initFile();
refreshCanvas();
});
}
@ -193,11 +208,11 @@ function afterFinishAdd(record) {
function editPoint() {
deviceSettingAddRef.value?.openDialog();
}
//
//
function beforeDeletePoint() {
isDeleteVisible.value = true;
}
//
function afterFinishDelete() {
// pointList
const currPointList = toRaw(pointList.value);
@ -220,10 +235,10 @@ function afterFinishDelete() {
activePointId.value = currPointList[0].id;
}
nextTick(() => {
initFile();
refreshCanvas();
});
}
//
async function deletePoint() {
const resp = await deleteWorkshopsApi({
id: activePointId.value
@ -235,6 +250,53 @@ async function deletePoint() {
//
}
//
async function fetchDeviceByPoint() {
const resp = await getWorkshopDevicesApi({
workshop_id: activePointId.value,
is_binding: true
});
if (isSuccessApi(resp)) {
currDeviceList.value = resp.data.results;
}
console.log("fetchDeviceByPoint_resp", resp);
deviceSelectRef.value?.renderDeviceToCanvas(resp.data.results);
}
//
async function addDevice(record) {
const resp = await addWorkshopDevicesApi({
workshop_id: activePointId.value,
device_id: record.id,
x_ordinate: record?.x_ordinate || 0,
y_ordinate: record?.y_ordinate || 0,
icon: record?.type || 1
});
if (isSuccessApi(resp)) {
// isAddDeviceVisible.value = false;
// afterFinishAddDevice();
}
}
// //
// async function deleteDevice(record) {
// const resp = await deleteWorkshopDeviceApi({
// id: record.id
// });
// if (isSuccessApi(resp)) {
// isDeleteDeviceVisible.value = false;
// afterFinishDeleteDevice();
// }
// }
// //
// async function updateDevice(record) {
// const resp = await updateWorkshopDeviceApi({
// id: record.id,
// });
// }
//
watch(
() => pointList.value,
@ -254,7 +316,7 @@ watch(
// console.log("activePoint", activePoint);
// if (activePoint.value?.id) {
// nextTick(() => {
// initFile();
// refreshCanvas();
// });
// }
// }
@ -311,20 +373,20 @@ provide("canvasEditor", canvasEditor);
<div class="flex w-full h-full">
<!-- 左侧画布区域 -->
<div id="workspace" class="h-full deviceOfPoint_wrap">
<div class="canvas-box">
<!-- <div class="inside-shadow"></div> -->
<canvas
id="canvas"
:class="state.ruler ? 'design-stage-grid' : ''"
/>
<!-- <dragMode v-if="state.showFabric"></dragMode>
<!-- <div class="inside-shadow"></div> -->
<canvas id="canvas" />
<!-- <dragMode v-if="state.showFabric"></dragMode>
<zoom></zoom> -->
<!-- <mouseMenu></mouseMenu> -->
</div>
<!-- <mouseMenu></mouseMenu> -->
</div>
<!-- 右侧属性区域-->
<div class="right-bar" v-if="state.showFabric">
<DeviceSelect :deviceList="deviceList" />
<DeviceSelect
ref="deviceSelectRef"
:deviceList="deviceList"
@addDevice="addDevice"
:pointInfo="activePoint"
/>
<DeviceAttr />
</div>
</div>
@ -339,6 +401,7 @@ provide("canvasEditor", canvasEditor);
v-if="pointList.length"
>删除位置</el-button
>
<!-- //TODO -->
<IsDelete
v-model="isDeleteVisible"
@update:visible="val => (isDeleteVisible = val)"

Loading…
Cancel
Save