|
@@ -1,5 +1,5 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <div class="page">
|
|
|
|
|
|
|
+ <div class="page" @click="handleWholeClick">
|
|
|
<div class="page-head flex items-center">
|
|
<div class="page-head flex items-center">
|
|
|
<el-icon size="20"><ArrowLeft /></el-icon>
|
|
<el-icon size="20"><ArrowLeft /></el-icon>
|
|
|
<div class="head-opt flex-1 flex justify-between items-center">
|
|
<div class="head-opt flex-1 flex justify-between items-center">
|
|
@@ -17,6 +17,7 @@
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="flex">
|
|
<div class="flex">
|
|
|
|
|
+ <el-button @click="mapEditor.toJson">tojson</el-button>
|
|
|
<el-upload
|
|
<el-upload
|
|
|
class="avatar-uploader flex justify-center items-center"
|
|
class="avatar-uploader flex justify-center items-center"
|
|
|
action="/temp/api/layout/uploadPicture"
|
|
action="/temp/api/layout/uploadPicture"
|
|
@@ -60,10 +61,10 @@
|
|
|
<div
|
|
<div
|
|
|
v-for="item in filterShopCameraList"
|
|
v-for="item in filterShopCameraList"
|
|
|
:key="item.code"
|
|
:key="item.code"
|
|
|
- class="camera-item flex justify-start"
|
|
|
|
|
|
|
+ class="camera-item flex justify-start items-center"
|
|
|
:class="{
|
|
:class="{
|
|
|
- isAdded: isAddedToMap(item.code),
|
|
|
|
|
- isActive: item.code === selectedCamera?.cameraId,
|
|
|
|
|
|
|
+ isAdded: isAddedCamera(item.code),
|
|
|
|
|
+ isActive: item.code === activeCameraId,
|
|
|
}"
|
|
}"
|
|
|
@click="handleAddCamera(item.code)"
|
|
@click="handleAddCamera(item.code)"
|
|
|
>
|
|
>
|
|
@@ -81,52 +82,21 @@
|
|
|
</div>
|
|
</div>
|
|
|
</el-scrollbar>
|
|
</el-scrollbar>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="draw-container">
|
|
|
|
|
- <div style="overflow: auto">
|
|
|
|
|
- <canvas width="400" height="400" id="mapEditCanvas"></canvas>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div ref="drawContainer" id="drawContainer" class="draw-container">
|
|
|
|
|
+ <div id="editContainer" v-moveable:1></div>
|
|
|
<el-upload
|
|
<el-upload
|
|
|
v-if="!hasBg"
|
|
v-if="!hasBg"
|
|
|
class="upload-icon flex justify-center items-center"
|
|
class="upload-icon flex justify-center items-center"
|
|
|
- action="/temp/api/layout/uploadPicture"
|
|
|
|
|
|
|
+ action="/api/layout/uploadPicture"
|
|
|
:show-file-list="false"
|
|
:show-file-list="false"
|
|
|
|
|
+ :before-upload="handleBeforeUpload"
|
|
|
:on-success="handleAvatarSuccess"
|
|
:on-success="handleAvatarSuccess"
|
|
|
:with-credentials="true"
|
|
:with-credentials="true"
|
|
|
name="file"
|
|
name="file"
|
|
|
- :data="{ workshopId: selectedShopCode }"
|
|
|
|
|
|
|
+ :data="{ workshopId: selectedShopDetail?.id }"
|
|
|
>
|
|
>
|
|
|
<img src="~@/assets/images/img-upload.png" />
|
|
<img src="~@/assets/images/img-upload.png" />
|
|
|
</el-upload>
|
|
</el-upload>
|
|
|
- <div>
|
|
|
|
|
- <div style="height: 20px; margin-bottom: 10px">
|
|
|
|
|
- <div v-if="selectedCamera">
|
|
|
|
|
- <SelectedCameraToolbar
|
|
|
|
|
- @render-map="renderMap"
|
|
|
|
|
- :selected-camera="selectedCamera!"
|
|
|
|
|
- :key="selectedPositionHash"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div style="overflow: auto">
|
|
|
|
|
- <canvas width="400" height="400" id="mapEditCanvas"></canvas>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div style="overflow: auto; position: relative">
|
|
|
|
|
- <canvas
|
|
|
|
|
- width="400"
|
|
|
|
|
- height="400"
|
|
|
|
|
- id="mapEditCanvas"
|
|
|
|
|
- style="border: 1px solid #ccc"
|
|
|
|
|
- ></canvas>
|
|
|
|
|
- <ContextMenu
|
|
|
|
|
- :visible="menuVisible"
|
|
|
|
|
- :position="mousePosition"
|
|
|
|
|
- :set-default="handleSetDefault"
|
|
|
|
|
- />
|
|
|
|
|
- <DefaultCameraIcon :position="favPosition" />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <CameraPreview :json="cameraJSON" />
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -136,93 +106,43 @@
|
|
|
import useMiniMap from './use-mini-map';
|
|
import useMiniMap from './use-mini-map';
|
|
|
import { storeToRefs } from 'pinia';
|
|
import { storeToRefs } from 'pinia';
|
|
|
import { ElMessage, ElInput } from 'element-plus';
|
|
import { ElMessage, ElInput } from 'element-plus';
|
|
|
- import urlJoin from 'url-join';
|
|
|
|
|
import { onMounted, ref } from 'vue';
|
|
import { onMounted, ref } from 'vue';
|
|
|
- import useCameraMap from './MapBase/useCameraMap';
|
|
|
|
|
import { updateMinMapViewLayoutApi } from '@/api/scene/scene';
|
|
import { updateMinMapViewLayoutApi } from '@/api/scene/scene';
|
|
|
- import { onUnmounted, watchEffect } from 'vue';
|
|
|
|
|
- import { useGlobSetting } from '@/hooks/setting';
|
|
|
|
|
import { computed } from 'vue';
|
|
import { computed } from 'vue';
|
|
|
- import ContextMenu from './MapBase/ContextMenu.vue';
|
|
|
|
|
- import DefaultCameraIcon from './MapBase/DefaultCameraIcon.vue';
|
|
|
|
|
- import { CameraImage } from './MapBase/types';
|
|
|
|
|
- import { createSelectedPositionHash, getFavPositionByCamera } from './MapBase/utils';
|
|
|
|
|
- import SelectedCameraToolbar from './components/SelectedCameraToolbar.vue';
|
|
|
|
|
- import CameraPreview from './MapBase/CameraPreview.vue';
|
|
|
|
|
import { Search, Refresh } from '@element-plus/icons-vue';
|
|
import { Search, Refresh } from '@element-plus/icons-vue';
|
|
|
|
|
+ import useMapEditor from './hooks/useMapEditor';
|
|
|
|
|
|
|
|
|
|
+ const mapEditor = useMapEditor();
|
|
|
|
|
+ const { activeCameraId, addedCameras, bgImgUrl } = mapEditor;
|
|
|
const miniMap = useMiniMap();
|
|
const miniMap = useMiniMap();
|
|
|
- const globSetting = useGlobSetting();
|
|
|
|
|
const { scenesTree, shopCameraList, selectedShopCode, selectedShopDetail } = storeToRefs(miniMap);
|
|
const { scenesTree, shopCameraList, selectedShopCode, selectedShopDetail } = storeToRefs(miniMap);
|
|
|
const { getScenesTree, getShowCameras, getMapLayout } = miniMap;
|
|
const { getScenesTree, getShowCameras, getMapLayout } = miniMap;
|
|
|
- const selectedPositionHash = ref('');
|
|
|
|
|
- const allObjects = ref<CameraImage[]>([]);
|
|
|
|
|
-
|
|
|
|
|
- const onSelectCamera = () => {
|
|
|
|
|
- menuVisible.value = false;
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
- const handleRightClick = (e) => {
|
|
|
|
|
- mousePosition.value = { left: e.pointer.x, top: e.pointer.y };
|
|
|
|
|
- menuVisible.value = true;
|
|
|
|
|
- rightSelectedCamera.value = e.target;
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const drawContainer = ref<HTMLDivElement>();
|
|
|
|
|
|
|
|
- const handleMoving = (e) => {
|
|
|
|
|
- const target = e.transform.target;
|
|
|
|
|
- selectedPositionHash.value = createSelectedPositionHash(target);
|
|
|
|
|
- if (target?.cameraId === defaultCamera.value?.cameraId) {
|
|
|
|
|
- favPosition.value = getFavPositionByCamera(target);
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const searchKey = ref('');
|
|
|
|
|
+ // 是否已有背景图
|
|
|
|
|
+ const hasBg = ref(false);
|
|
|
|
|
|
|
|
- const handleRoating = (e) => {
|
|
|
|
|
- const target = e.transform.target;
|
|
|
|
|
- selectedPositionHash.value = createSelectedPositionHash(target);
|
|
|
|
|
- if (target.cameraId === defaultCamera.value?.cameraId) {
|
|
|
|
|
- favPosition.value = getFavPositionByCamera(target);
|
|
|
|
|
|
|
+ const handleBeforeUpload = () => {
|
|
|
|
|
+ if (!selectedShopCode.value) {
|
|
|
|
|
+ ElMessage.error({
|
|
|
|
|
+ message: '请先选择车间',
|
|
|
|
|
+ });
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- const handleSetSelectedCameara = (target: CameraImage | null) => {
|
|
|
|
|
- selectedCamera.value = target;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const handleObjectsAdded = () => {
|
|
|
|
|
- allObjects.value = map.getObjects();
|
|
|
|
|
|
|
+ /** 判断相机是否已经添加 */
|
|
|
|
|
+ const isAddedCamera = (cameraId: string) => {
|
|
|
|
|
+ const index = addedCameras.value.findIndex((item) => item === cameraId);
|
|
|
|
|
+ return index >= 0;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- const map = useCameraMap({
|
|
|
|
|
- onSelect: onSelectCamera,
|
|
|
|
|
- onRightClick: handleRightClick,
|
|
|
|
|
- onMoving: handleMoving,
|
|
|
|
|
- onRotating: handleRoating,
|
|
|
|
|
- setSelectedCamera: handleSetSelectedCameara,
|
|
|
|
|
- onObjectsAdded: handleObjectsAdded,
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const selectedCamera = ref<CameraImage | null>();
|
|
|
|
|
- /** 右键选中的摄像机 */
|
|
|
|
|
- const rightSelectedCamera = ref<CameraImage | null>(null);
|
|
|
|
|
- const defaultCamera = ref<CameraImage | null>();
|
|
|
|
|
- const searchKey = ref('');
|
|
|
|
|
- // 是否已有背景图
|
|
|
|
|
- const hasBg = ref(false);
|
|
|
|
|
-
|
|
|
|
|
- const mousePosition = ref<{ left: number; top: number }>({ left: 0, top: 0 });
|
|
|
|
|
- const menuVisible = ref(false);
|
|
|
|
|
- const favPosition = ref<{ left: number; top: number } | null>(null);
|
|
|
|
|
-
|
|
|
|
|
const handleAvatarSuccess = (e) => {
|
|
const handleAvatarSuccess = (e) => {
|
|
|
- const imgPath = e.data;
|
|
|
|
|
- const imgUrl = urlJoin(globSetting.imgUrl!, imgPath);
|
|
|
|
|
|
|
+ bgImgUrl.value = e.data;
|
|
|
|
|
+ mapEditor.addBg();
|
|
|
hasBg.value = true;
|
|
hasBg.value = true;
|
|
|
- map.uploadBg(imgUrl);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const renderMap = () => {
|
|
|
|
|
- map.renderCamera();
|
|
|
|
|
- favPosition.value = getFavPositionByCamera(defaultCamera.value);
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const changeShop = (code: string) => {
|
|
const changeShop = (code: string) => {
|
|
@@ -230,52 +150,35 @@
|
|
|
hasBg.value = false;
|
|
hasBg.value = false;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- const cameraJSON = ref();
|
|
|
|
|
|
|
+ const mapJSON = ref();
|
|
|
|
|
|
|
|
const getShopContent = (code: string) => {
|
|
const getShopContent = (code: string) => {
|
|
|
getShowCameras(code);
|
|
getShowCameras(code);
|
|
|
getMapLayout(code).then((res) => {
|
|
getMapLayout(code).then((res) => {
|
|
|
if (!res) {
|
|
if (!res) {
|
|
|
- map.clear();
|
|
|
|
|
- defaultCamera.value = null;
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- cameraJSON.value = res;
|
|
|
|
|
-
|
|
|
|
|
- map.loadFromJSON(res).then(() => {
|
|
|
|
|
- console.log('loadFromJSON', res);
|
|
|
|
|
- if (res.defaultCameraId) {
|
|
|
|
|
- defaultCamera.value = map.getCameraById(res.defaultCameraId);
|
|
|
|
|
- console.log('defaultCamera', defaultCamera.value);
|
|
|
|
|
- } else {
|
|
|
|
|
- defaultCamera.value = map.getObjects()?.[0] as CameraImage;
|
|
|
|
|
- }
|
|
|
|
|
- renderMap();
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ mapJSON.value = res;
|
|
|
|
|
+ console.log(mapJSON);
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const handleWholeClick = (e) => {
|
|
|
|
|
+ if (e.button === 0) {
|
|
|
|
|
+ mapEditor.destoryOptBlock();
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
getScenesTree({ level: 2, valueKey: 'code', labelKey: 'name', disabled: true });
|
|
getScenesTree({ level: 2, valueKey: 'code', labelKey: 'name', disabled: true });
|
|
|
|
|
+ mapEditor.initContainer({
|
|
|
|
|
+ container: 'editContainer',
|
|
|
|
|
+ width: drawContainer.value!.clientWidth,
|
|
|
|
|
+ height: drawContainer.value!.clientHeight,
|
|
|
|
|
+ });
|
|
|
if (selectedShopCode.value) {
|
|
if (selectedShopCode.value) {
|
|
|
getShopContent(selectedShopCode.value);
|
|
getShopContent(selectedShopCode.value);
|
|
|
}
|
|
}
|
|
|
- map.createMap('mapEditCanvas');
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- const keyupListener = (e) => {
|
|
|
|
|
- const keyCode = e.code;
|
|
|
|
|
- if (keyCode === 'Delete') {
|
|
|
|
|
- handleDeleteCamera();
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- onMounted(() => {
|
|
|
|
|
- document.addEventListener('keyup', keyupListener);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- onUnmounted(() => {
|
|
|
|
|
- document.removeEventListener('keyup', keyupListener);
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const filterShopCameraList = computed(() => {
|
|
const filterShopCameraList = computed(() => {
|
|
@@ -284,32 +187,18 @@
|
|
|
return shopCameraList.value.filter((x) => x.code?.includes(k) || x.workSpaceName?.includes(k));
|
|
return shopCameraList.value.filter((x) => x.code?.includes(k) || x.workSpaceName?.includes(k));
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- /** 摄像机是否已添加到底图 */
|
|
|
|
|
- const isAddedToMap = (cameraId: string): boolean => {
|
|
|
|
|
- return !!allObjects.value.find((item) => item.cameraId === cameraId);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
const handleAddCamera = (cameraId: string) => {
|
|
const handleAddCamera = (cameraId: string) => {
|
|
|
- if (!hasBg.value) return;
|
|
|
|
|
- if (map.hasCamera(cameraId)) {
|
|
|
|
|
- ElMessage.warning({ message: '相机已添加' });
|
|
|
|
|
|
|
+ if (!hasBg.value) {
|
|
|
|
|
+ ElMessage.warning({
|
|
|
|
|
+ message: '请先添加背景图片',
|
|
|
|
|
+ });
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- map.addCamera(cameraId).then((cameraImg) => {
|
|
|
|
|
- if (!defaultCamera.value?.cameraId) {
|
|
|
|
|
- defaultCamera.value = cameraImg;
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ mapEditor.addCamera(cameraId);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleSave = () => {
|
|
const handleSave = () => {
|
|
|
- const json = map.toJSON();
|
|
|
|
|
- console.log('save json', json);
|
|
|
|
|
- if (!json?.backgroundImage) {
|
|
|
|
|
- ElMessage.error('背景图片未添加');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- const layout = JSON.stringify({ ...json, defaultCameraId: defaultCamera.value?.cameraId });
|
|
|
|
|
|
|
+ const layout = mapEditor.toJson();
|
|
|
updateMinMapViewLayoutApi({ layout, targetId: String(selectedShopDetail.value?.id) }).then(
|
|
updateMinMapViewLayoutApi({ layout, targetId: String(selectedShopDetail.value?.id) }).then(
|
|
|
(res) => {
|
|
(res) => {
|
|
|
console.log('updateMinMapViewLayoutApi', res);
|
|
console.log('updateMinMapViewLayoutApi', res);
|
|
@@ -317,35 +206,9 @@
|
|
|
},
|
|
},
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
- const handleDeleteCamera = () => {
|
|
|
|
|
- if (!selectedCamera.value) return;
|
|
|
|
|
- /** 如果删除的是默认选中的摄像头,那么先清空默认的摄像头再 */
|
|
|
|
|
- if (selectedCamera.value?.cameraId === defaultCamera.value?.cameraId) {
|
|
|
|
|
- defaultCamera.value = map.getObjects()?.[0];
|
|
|
|
|
- }
|
|
|
|
|
- map.removeActiveCamera();
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const handleSetDefault = () => {
|
|
|
|
|
- const cameraId = rightSelectedCamera.value?.cameraId;
|
|
|
|
|
- if (!cameraId) return;
|
|
|
|
|
- defaultCamera.value = rightSelectedCamera.value;
|
|
|
|
|
-
|
|
|
|
|
- /** 选择完成后隐藏 */
|
|
|
|
|
- menuVisible.value = false;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- watchEffect(() => {
|
|
|
|
|
- if (!defaultCamera.value) {
|
|
|
|
|
- favPosition.value = null;
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- favPosition.value = getFavPositionByCamera(defaultCamera.value);
|
|
|
|
|
- });
|
|
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
-<style scoped>
|
|
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
.page {
|
|
.page {
|
|
|
}
|
|
}
|
|
|
.page-head {
|
|
.page-head {
|
|
@@ -395,10 +258,23 @@
|
|
|
.camera-item {
|
|
.camera-item {
|
|
|
height: 32px;
|
|
height: 32px;
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
|
|
|
+ padding-left: 8px;
|
|
|
font-weight: 400;
|
|
font-weight: 400;
|
|
|
color: #404040;
|
|
color: #404040;
|
|
|
line-height: 14px;
|
|
line-height: 14px;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background-color: #e6f7ff;
|
|
|
|
|
+ color: #1890ff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .isAdded {
|
|
|
|
|
+ color: #1890ff;
|
|
|
|
|
+ }
|
|
|
|
|
+ .isActive {
|
|
|
|
|
+ background-color: #e6f7ff;
|
|
|
|
|
+ color: #1890ff;
|
|
|
}
|
|
}
|
|
|
.camera-item-disabled {
|
|
.camera-item-disabled {
|
|
|
color: #c6c6c6;
|
|
color: #c6c6c6;
|
|
@@ -417,6 +293,7 @@
|
|
|
position: relative;
|
|
position: relative;
|
|
|
width: calc(100% - 300px);
|
|
width: calc(100% - 300px);
|
|
|
margin: 20px;
|
|
margin: 20px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
:deep(.search-put .el-input__wrapper) {
|
|
:deep(.search-put .el-input__wrapper) {
|
|
@@ -437,12 +314,5 @@
|
|
|
text-align: center;
|
|
text-align: center;
|
|
|
font-weight: 400;
|
|
font-weight: 400;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- .isAdded {
|
|
|
|
|
- color: #409eff;
|
|
|
|
|
- }
|
|
|
|
|
- .isActive {
|
|
|
|
|
- background-color: #eee;
|
|
|
|
|
- }
|
|
|
|
|
</style>
|
|
</style>
|
|
|
./MapBase/useCameraMap ./MapBase/CameraMapBak
|
|
./MapBase/useCameraMap ./MapBase/CameraMapBak
|