|
@@ -1,16 +1,43 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="page">
|
|
<div class="page">
|
|
|
- <div class="flex">
|
|
|
|
|
- <div class="flex items-center">
|
|
|
|
|
- <span>场景:</span>
|
|
|
|
|
- <el-tree-select
|
|
|
|
|
- v-model="selectedShopCode"
|
|
|
|
|
- :data="scenesTree"
|
|
|
|
|
- accordion
|
|
|
|
|
- :render-after-expand="false"
|
|
|
|
|
- placeholder="请选择场景"
|
|
|
|
|
- @change="changeShop"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <div class="page-head flex items-center">
|
|
|
|
|
+ <el-icon size="20"><ArrowLeft /></el-icon>
|
|
|
|
|
+ <div class="head-opt flex-1 flex justify-between items-center">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <span>场景:</span>
|
|
|
|
|
+ <el-tree-select
|
|
|
|
|
+ v-model="selectedShopCode"
|
|
|
|
|
+ :data="scenesTree"
|
|
|
|
|
+ accordion
|
|
|
|
|
+ :render-after-expand="false"
|
|
|
|
|
+ :teleported="false"
|
|
|
|
|
+ placeholder="请选择相关场景"
|
|
|
|
|
+ @change="changeShop"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="flex">
|
|
|
|
|
+ <el-upload
|
|
|
|
|
+ class="avatar-uploader flex justify-center items-center"
|
|
|
|
|
+ action="/temp/api/layout/uploadPicture"
|
|
|
|
|
+ :show-file-list="false"
|
|
|
|
|
+ :on-success="handleAvatarSuccess"
|
|
|
|
|
+ :with-credentials="true"
|
|
|
|
|
+ name="file"
|
|
|
|
|
+ :data="{ workshopId: selectedShopCode }"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-button style="font-size: 12px" :icon="Refresh" :disabled="!hasBg">
|
|
|
|
|
+ 替换照片
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-upload>
|
|
|
|
|
+
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ @click="handleSave"
|
|
|
|
|
+ style="margin-left: 40px"
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ :disabled="!selectedShopCode"
|
|
|
|
|
+ >保存为布局
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="paint-tool flex">
|
|
<div class="paint-tool flex">
|
|
@@ -18,27 +45,40 @@
|
|
|
<div>
|
|
<div>
|
|
|
<span class="label-text flex">相机列表:</span>
|
|
<span class="label-text flex">相机列表:</span>
|
|
|
<ElInput
|
|
<ElInput
|
|
|
- style="margin: 10px; width: 230px"
|
|
|
|
|
- placeholder="输入相机id或工位"
|
|
|
|
|
|
|
+ class="search-put"
|
|
|
|
|
+ style="margin: 10px 0; width: 230px"
|
|
|
|
|
+ placeholder="请输入搜索内容"
|
|
|
v-model="searchKey"
|
|
v-model="searchKey"
|
|
|
:suffix-icon="Search"
|
|
:suffix-icon="Search"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
- <el-scrollbar style="height: calc(100% - 90px)">
|
|
|
|
|
|
|
+ <span v-if="filterShopCameraList.length == 0" class="ml-1" style="color: #3f3f3f">
|
|
|
|
|
+ 提示:请先选择相应场景和图片
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <el-scrollbar v-else style="position: relative; height: calc(100% - 90px)">
|
|
|
<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="{ isAdded: isAddedToMap(item.code) }"
|
|
|
|
|
|
|
+ class="camera-item flex justify-start items-center"
|
|
|
|
|
+ :class="{ isAdded: isAddedToMap(item.code), 'camera-item-disabled': !hasBg }"
|
|
|
@click="handleAddCamera(item.code)"
|
|
@click="handleAddCamera(item.code)"
|
|
|
>
|
|
>
|
|
|
<span class="camera-id">{{ item.name }}</span>
|
|
<span class="camera-id">{{ item.name }}</span>
|
|
|
- <span>{{ item.workSpaceName }}</span>
|
|
|
|
|
|
|
+ <el-popover
|
|
|
|
|
+ placement="bottom-start"
|
|
|
|
|
+ trigger="hover"
|
|
|
|
|
+ :content="item.name"
|
|
|
|
|
+ :teleported="false"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #reference>
|
|
|
|
|
+ <span class="space-name">{{ item.workSpaceName }}</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-popover>
|
|
|
</div>
|
|
</div>
|
|
|
</el-scrollbar>
|
|
</el-scrollbar>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="draw-container">
|
|
<div class="draw-container">
|
|
|
- <div style="display: flex; margin-bottom: 20px">
|
|
|
|
|
|
|
+ <!-- <div style="display: flex; margin-bottom: 20px">
|
|
|
<div>
|
|
<div>
|
|
|
默认摄像头:
|
|
默认摄像头:
|
|
|
<ElSelect v-model="defaultCameraId">
|
|
<ElSelect v-model="defaultCameraId">
|
|
@@ -50,28 +90,8 @@
|
|
|
/>
|
|
/>
|
|
|
</ElSelect>
|
|
</ElSelect>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
- <el-upload
|
|
|
|
|
- class="avatar-uploader flex justify-center items-center"
|
|
|
|
|
- action="/temp/api/layout/uploadPicture"
|
|
|
|
|
- :show-file-list="false"
|
|
|
|
|
- :on-success="handleAvatarSuccess"
|
|
|
|
|
- :with-credentials="true"
|
|
|
|
|
- name="file"
|
|
|
|
|
- :data="{ workshopId: selectedShopDetail?.id }"
|
|
|
|
|
- >
|
|
|
|
|
- <el-button style="font-size: 12px">+ 更换/上传背景图片</el-button>
|
|
|
|
|
- </el-upload>
|
|
|
|
|
-
|
|
|
|
|
- <el-button
|
|
|
|
|
- @click="handleSave"
|
|
|
|
|
- style="margin-left: 40px"
|
|
|
|
|
- type="primary"
|
|
|
|
|
- :disabled="!selectedShopCode"
|
|
|
|
|
- >保存布局</el-button
|
|
|
|
|
- >
|
|
|
|
|
- </div>
|
|
|
|
|
- <div>
|
|
|
|
|
|
|
+ </div> -->
|
|
|
|
|
+ <!-- <div>
|
|
|
<div style="height: 20px; margin-bottom: 10px">
|
|
<div style="height: 20px; margin-bottom: 10px">
|
|
|
<div v-if="selectedCamera">
|
|
<div v-if="selectedCamera">
|
|
|
已选中相机<span>: {{ selectedCamera?.cameraId }}</span>
|
|
已选中相机<span>: {{ selectedCamera?.cameraId }}</span>
|
|
@@ -80,20 +100,22 @@
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ </div> -->
|
|
|
|
|
+ <div style="overflow: auto">
|
|
|
|
|
+ <canvas width="400" height="400" id="mapEditCanvas"></canvas>
|
|
|
</div>
|
|
</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"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <el-upload
|
|
|
|
|
+ v-if="!hasBg"
|
|
|
|
|
+ class="upload-icon flex justify-center items-center"
|
|
|
|
|
+ action="/temp/api/layout/uploadPicture"
|
|
|
|
|
+ :show-file-list="false"
|
|
|
|
|
+ :on-success="handleAvatarSuccess"
|
|
|
|
|
+ :with-credentials="true"
|
|
|
|
|
+ name="file"
|
|
|
|
|
+ :data="{ workshopId: selectedShopCode }"
|
|
|
|
|
+ >
|
|
|
|
|
+ <img src="~@/assets/images/img-upload.png" />
|
|
|
|
|
+ </el-upload>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -106,13 +128,13 @@
|
|
|
import urlJoin from 'url-join';
|
|
import urlJoin from 'url-join';
|
|
|
import { onMounted, ref, toRaw } from 'vue';
|
|
import { onMounted, ref, toRaw } from 'vue';
|
|
|
import CameraMap, { CameraImage } from './MapBase/CameraMap';
|
|
import CameraMap, { CameraImage } from './MapBase/CameraMap';
|
|
|
- import { ElSelect, ElOption } from 'element-plus';
|
|
|
|
|
|
|
+ // import { ElSelect, ElOption } from 'element-plus';
|
|
|
import { updateMinMapViewLayoutApi } from '@/api/scene/scene';
|
|
import { updateMinMapViewLayoutApi } from '@/api/scene/scene';
|
|
|
import { onUnmounted } from 'vue';
|
|
import { onUnmounted } from 'vue';
|
|
|
import { useGlobSetting } from '@/hooks/setting';
|
|
import { useGlobSetting } from '@/hooks/setting';
|
|
|
import { computed } from 'vue';
|
|
import { computed } from 'vue';
|
|
|
- import { Search } from '@element-plus/icons-vue';
|
|
|
|
|
import ContextMenu from './MapBase/ContextMenu.vue';
|
|
import ContextMenu from './MapBase/ContextMenu.vue';
|
|
|
|
|
+ import { Search, ArrowLeft, Refresh } from '@element-plus/icons-vue';
|
|
|
|
|
|
|
|
const miniMap = useMiniMap();
|
|
const miniMap = useMiniMap();
|
|
|
const globSetting = useGlobSetting();
|
|
const globSetting = useGlobSetting();
|
|
@@ -126,6 +148,8 @@
|
|
|
const cameraOptions = ref<{ label: string; value: string }[]>([]);
|
|
const cameraOptions = ref<{ label: string; value: string }[]>([]);
|
|
|
const defaultCameraId = ref('');
|
|
const defaultCameraId = ref('');
|
|
|
const searchKey = ref('');
|
|
const searchKey = ref('');
|
|
|
|
|
+ // 是否已有背景图
|
|
|
|
|
+ const hasBg = ref(false);
|
|
|
|
|
|
|
|
const mousePosition = ref<{ left: number; top: number }>({ left: 0, top: 0 });
|
|
const mousePosition = ref<{ left: number; top: number }>({ left: 0, top: 0 });
|
|
|
const menuVisible = ref(false);
|
|
const menuVisible = ref(false);
|
|
@@ -133,11 +157,13 @@
|
|
|
const handleAvatarSuccess = (e) => {
|
|
const handleAvatarSuccess = (e) => {
|
|
|
const imgPath = e.data;
|
|
const imgPath = e.data;
|
|
|
const imgUrl = urlJoin(globSetting.imgUrl!, imgPath);
|
|
const imgUrl = urlJoin(globSetting.imgUrl!, imgPath);
|
|
|
|
|
+ hasBg.value = true;
|
|
|
map.uploadBg(imgUrl);
|
|
map.uploadBg(imgUrl);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const changeShop = (code: string) => {
|
|
const changeShop = (code: string) => {
|
|
|
getShopContent(code);
|
|
getShopContent(code);
|
|
|
|
|
+ hasBg.value = false;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const getShopContent = (code: string) => {
|
|
const getShopContent = (code: string) => {
|
|
@@ -202,6 +228,7 @@
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleAddCamera = (cameraId: string) => {
|
|
const handleAddCamera = (cameraId: string) => {
|
|
|
|
|
+ if (!hasBg.value) return;
|
|
|
if (map.hasCamera(cameraId)) {
|
|
if (map.hasCamera(cameraId)) {
|
|
|
ElMessage.warning({ message: '相机已添加' });
|
|
ElMessage.warning({ message: '相机已添加' });
|
|
|
return;
|
|
return;
|
|
@@ -229,6 +256,9 @@
|
|
|
|
|
|
|
|
const mapJSONToOptions = () => {
|
|
const mapJSONToOptions = () => {
|
|
|
const objects = map.toJSON()?.objects || [];
|
|
const objects = map.toJSON()?.objects || [];
|
|
|
|
|
+ if (map.toJSON()?.backgroundImage.src) {
|
|
|
|
|
+ hasBg.value = true;
|
|
|
|
|
+ }
|
|
|
console.log('objects', objects);
|
|
console.log('objects', objects);
|
|
|
cameraOptions.value = objects?.map((x) => ({
|
|
cameraOptions.value = objects?.map((x) => ({
|
|
|
label: x.cameraId,
|
|
label: x.cameraId,
|
|
@@ -272,10 +302,20 @@
|
|
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
.page {
|
|
.page {
|
|
|
- margin: 10px 0;
|
|
|
|
|
- padding: 10px;
|
|
|
|
|
|
|
+ /* margin: 10px 0; */
|
|
|
|
|
+ padding: 10px 0 0 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .page-head {
|
|
|
|
|
+ height: 54px;
|
|
|
|
|
+ padding-left: 15px;
|
|
|
background-color: #ffffff;
|
|
background-color: #ffffff;
|
|
|
}
|
|
}
|
|
|
|
|
+ .head-opt {
|
|
|
|
|
+ margin-left: 20px;
|
|
|
|
|
+ padding-right: 15px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #3f3f3f;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
.avatar-uploader {
|
|
.avatar-uploader {
|
|
|
/* width: 120px; */
|
|
/* width: 120px; */
|
|
@@ -284,18 +324,25 @@
|
|
|
border-radius: 4px;
|
|
border-radius: 4px;
|
|
|
margin-left: 30px;
|
|
margin-left: 30px;
|
|
|
}
|
|
}
|
|
|
|
|
+ .upload-icon {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ margin: auto;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
.paint-tool {
|
|
.paint-tool {
|
|
|
position: relative;
|
|
position: relative;
|
|
|
- height: calc(100vh - 185px);
|
|
|
|
|
- margin: 0 10px;
|
|
|
|
|
- margin-top: 20px;
|
|
|
|
|
- border: 1px solid #c0c4cc;
|
|
|
|
|
|
|
+ height: calc(100vh - 140px);
|
|
|
|
|
+ margin-top: 2px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.camera-list {
|
|
.camera-list {
|
|
|
width: 250px;
|
|
width: 250px;
|
|
|
- border-right: 1px solid #c0c4cc;
|
|
|
|
|
|
|
+ padding: 0 10px;
|
|
|
|
|
+ background-color: #ffffff;
|
|
|
}
|
|
}
|
|
|
.label-text {
|
|
.label-text {
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
@@ -303,21 +350,49 @@
|
|
|
margin: 10px 0 5px 10px;
|
|
margin: 10px 0 5px 10px;
|
|
|
}
|
|
}
|
|
|
.camera-item {
|
|
.camera-item {
|
|
|
- padding: 10px 0 10px 10px;
|
|
|
|
|
- margin: 0 8px 1px 8px;
|
|
|
|
|
- border: 1px solid #c0c4cc;
|
|
|
|
|
|
|
+ height: 32px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: 400;
|
|
|
|
|
+ color: #404040;
|
|
|
|
|
+ line-height: 14px;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
}
|
|
}
|
|
|
|
|
+ .camera-item-disabled {
|
|
|
|
|
+ color: #c6c6c6;
|
|
|
|
|
+ }
|
|
|
.camera-id {
|
|
.camera-id {
|
|
|
- width: 130px;
|
|
|
|
|
|
|
+ width: 110px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .space-name {
|
|
|
|
|
+ width: 120px;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.draw-container {
|
|
.draw-container {
|
|
|
|
|
+ position: relative;
|
|
|
width: calc(100% - 300px);
|
|
width: calc(100% - 300px);
|
|
|
margin: 20px;
|
|
margin: 20px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- :deep(.avatar-uploader .el-upload) {
|
|
|
|
|
|
|
+ :deep(.search-put .el-input__wrapper) {
|
|
|
|
|
+ background-color: #f0f2f5;
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.el-popper__arrow) {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.el-tree-node__content:hover) {
|
|
|
|
|
+ background: #e6f4ff;
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.el-button--primary) {
|
|
|
|
|
+ --el-button-disabled-bg-color: #bfbfbf;
|
|
|
|
|
+ }
|
|
|
|
|
+ :deep(.el-popover) {
|
|
|
|
|
+ width: unset !important;
|
|
|
|
|
+ min-width: 110px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ font-weight: 400;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.isAdded {
|
|
.isAdded {
|