|
|
@@ -2,17 +2,28 @@
|
|
|
<div class="min-map">
|
|
|
<header class="min-map__header">
|
|
|
<section class="min-map__btn" @click="router.back">
|
|
|
- <img :src="rollback">
|
|
|
+ <img :src="rollback" />
|
|
|
<span>返回</span>
|
|
|
</section>
|
|
|
<section class="workshop-name">{{ selectedName }}</section>
|
|
|
<section class="operate-btn">
|
|
|
- <el-upload class="avatar-uploader" :action="actionUrl" :show-file-list="false" :on-success="handleAvatarSuccess"
|
|
|
- :with-credentials="true" name="file" :headers="getHeaders()">
|
|
|
+ <a @click="downloadImage(imgUrlBg, selectedName + '.png')" v-if="imgUrlBg">下载底图</a>
|
|
|
+ <el-upload
|
|
|
+ class="avatar-uploader"
|
|
|
+ :action="actionUrl"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-success="handleAvatarSuccess"
|
|
|
+ :with-credentials="true"
|
|
|
+ name="file"
|
|
|
+ :headers="getHeaders()"
|
|
|
+ >
|
|
|
<el-button :icon="UploadFilled" :disabled="!hasBg"> 替换照片 </el-button>
|
|
|
</el-upload>
|
|
|
- <el-button :icon="Refresh" @click="openMessageBox('提示', '是否重置当前设置', refreshUploadBg, '重置成功!')"
|
|
|
- :disabled="!hasBg">
|
|
|
+ <el-button
|
|
|
+ :icon="Refresh"
|
|
|
+ @click="openMessageBox('提示', '是否重置当前设置', refreshUploadBg, '重置成功!')"
|
|
|
+ :disabled="!hasBg"
|
|
|
+ >
|
|
|
重置布局
|
|
|
</el-button>
|
|
|
<el-button @click="handleSave" type="primary">保存</el-button>
|
|
|
@@ -24,14 +35,18 @@
|
|
|
<header class="camera-list__title">相机列表:</header>
|
|
|
<ElInput class="camera-list__search" placeholder="请输入搜索内容" v-model="searchKey" :suffix-icon="Search" />
|
|
|
<main class="camera-item">
|
|
|
- <span class="camera-item__empty" v-show="filterShopCameraList.length == 0">
|
|
|
- 提示:该车间还未配置相机
|
|
|
- </span>
|
|
|
- <div v-for="(item, index) in filterShopCameraList" :key="item.code" class="camera-item__list" :class="{
|
|
|
- isAdded: isAddedCamera(item.code),
|
|
|
- isActive: item.code === caremaActiveId,
|
|
|
- integrationState: item.integrationState === 1,
|
|
|
- }" @click="handleAddCamera(item.code, index)">
|
|
|
+ <span class="camera-item__empty" v-show="filterShopCameraList.length == 0"> 提示:该车间还未配置相机 </span>
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in filterShopCameraList"
|
|
|
+ :key="item.code"
|
|
|
+ class="camera-item__list"
|
|
|
+ :class="{
|
|
|
+ isAdded: isAddedCamera(item.code),
|
|
|
+ isActive: item.code === caremaActiveId,
|
|
|
+ integrationState: item.integrationState === 1,
|
|
|
+ }"
|
|
|
+ @click="handleAddCamera(item.code, index)"
|
|
|
+ >
|
|
|
<span class="camera-id">{{ item.name }}</span>
|
|
|
<el-popover placement="right-start" trigger="hover" :content="item.workSpaceName" :teleported="false">
|
|
|
<template #reference>
|
|
|
@@ -43,413 +58,448 @@
|
|
|
</section>
|
|
|
|
|
|
<section class="workshop-map" ref="drawContainer">
|
|
|
- <el-upload v-if="!hasBg" :action="actionUrl" :show-file-list="false" :before-upload="handleBeforeUpload"
|
|
|
- :on-success="handleAvatarSuccess" :with-credentials="true" name="file" :headers="getHeaders()">
|
|
|
+ <el-upload
|
|
|
+ v-if="!hasBg"
|
|
|
+ :action="actionUrl"
|
|
|
+ :show-file-list="false"
|
|
|
+ :before-upload="handleBeforeUpload"
|
|
|
+ :on-success="handleAvatarSuccess"
|
|
|
+ :with-credentials="true"
|
|
|
+ name="file"
|
|
|
+ :headers="getHeaders()"
|
|
|
+ >
|
|
|
<img src="~@/assets/images/img-upload.png" />
|
|
|
</el-upload>
|
|
|
- <KonvaMap ref="konvaMap" :filter-data="filterShopCameraList" :camera-list="shopCameraList"
|
|
|
- :map-config="mapConfig" :is-knova-destroy="isKnovaDestroy" @change-default-camera="changeDefault"
|
|
|
- @send-camera-id="sendCameras" @change="changeMap" v-else />
|
|
|
+ <KonvaMap
|
|
|
+ ref="konvaMap"
|
|
|
+ :filter-data="filterShopCameraList"
|
|
|
+ :camera-list="shopCameraList"
|
|
|
+ :map-config="mapConfig"
|
|
|
+ :is-knova-destroy="isKnovaDestroy"
|
|
|
+ @change-default-camera="changeDefault"
|
|
|
+ @send-camera-id="sendCameras"
|
|
|
+ @change="changeMap"
|
|
|
+ v-else
|
|
|
+ />
|
|
|
</section>
|
|
|
</main>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ElMessage, ElInput, ElMessageBox } from 'element-plus';
|
|
|
-import { Search, Refresh, UploadFilled } from '@element-plus/icons-vue';
|
|
|
-import rollback from '@/assets/rollback.png'
|
|
|
-import { onMounted, onUnmounted, ref, computed, reactive, nextTick } from 'vue';
|
|
|
-import { updateMinMapViewLayoutApi, getCamerasByWorkShopId, getWorkshopMiniMapLayoutPCApi, getWorkshopMiniMapLayoutMobileApi } from '@/api/scene/scene';
|
|
|
-import KonvaMap from './MapBase/KonvaMap.vue';
|
|
|
-import useCameraStatus from '@/views/cameras/preview/store/useCameraStatus';
|
|
|
-import { onBeforeRouteLeave,useRoute } from 'vue-router';
|
|
|
-import urlJoin from 'url-join';
|
|
|
-import { useGlobSetting } from '@/hooks/setting';
|
|
|
-import { getHeaders } from '@/utils/http/axios';
|
|
|
-import router from '@/router';
|
|
|
-import { ShopMapCamera } from '@/types/scene/type'
|
|
|
-import { ViewType } from '@/types/page-config/type';
|
|
|
-import { openMessageBox } from '@/views/system-config/business-scene/components/MessageBox';
|
|
|
-
|
|
|
-const cameraStatus = useCameraStatus();
|
|
|
-const { openIntervalNew, closeInterval } = cameraStatus;
|
|
|
-
|
|
|
-const drawContainer = ref<HTMLDivElement>();
|
|
|
-const konvaMap = ref();
|
|
|
-const caremaActiveId = ref<string>('');
|
|
|
-const camerasAdded = ref<string[]>([]);
|
|
|
-const imgUrlBg = ref<string>('');
|
|
|
-const searchKey = ref('');
|
|
|
-
|
|
|
-// 是否已有背景图
|
|
|
-const hasBg = ref(false);
|
|
|
-//是否修改
|
|
|
-const isChange = ref<boolean>(false);
|
|
|
-//单个相机时是否上传图片
|
|
|
-const isUploadBg = ref<boolean>(true);
|
|
|
-
|
|
|
-const isMap = ref(false);
|
|
|
-const { urlPrefix } = useGlobSetting();
|
|
|
-
|
|
|
-const actionUrl = computed(() => {
|
|
|
- return urlJoin(urlPrefix!, `/admin/minimap/uploadPicture`);
|
|
|
-});
|
|
|
-
|
|
|
-function updataState(data, updateData) {
|
|
|
- for (let i = 0; i < data.length; i++) {
|
|
|
- const camera = data[i];
|
|
|
- const matchedCamera = updateData.find((item) => item.cameraCode === camera.code);
|
|
|
- if (matchedCamera) {
|
|
|
- camera.status = matchedCamera.status;
|
|
|
- camera.integrationState = matchedCamera.integrationState;
|
|
|
+ import { ElMessage, ElInput, ElMessageBox } from 'element-plus';
|
|
|
+ import { Search, Refresh, UploadFilled } from '@element-plus/icons-vue';
|
|
|
+ import rollback from '@/assets/rollback.png';
|
|
|
+ import { onMounted, onUnmounted, ref, computed, reactive, nextTick } from 'vue';
|
|
|
+ import {
|
|
|
+ updateMinMapViewLayoutApi,
|
|
|
+ getCamerasByWorkShopId,
|
|
|
+ getWorkshopMiniMapLayoutPCApi,
|
|
|
+ getWorkshopMiniMapLayoutMobileApi,
|
|
|
+ } from '@/api/scene/scene';
|
|
|
+ import KonvaMap from './MapBase/KonvaMap.vue';
|
|
|
+ import useCameraStatus from '@/views/cameras/preview/store/useCameraStatus';
|
|
|
+ import { onBeforeRouteLeave, useRoute } from 'vue-router';
|
|
|
+ import urlJoin from 'url-join';
|
|
|
+ import { useGlobSetting } from '@/hooks/setting';
|
|
|
+ import { getHeaders } from '@/utils/http/axios';
|
|
|
+ import router from '@/router';
|
|
|
+ import { ShopMapCamera } from '@/types/scene/type';
|
|
|
+ import { ViewType } from '@/types/page-config/type';
|
|
|
+ import { openMessageBox } from '@/views/system-config/business-scene/components/MessageBox';
|
|
|
+
|
|
|
+ const cameraStatus = useCameraStatus();
|
|
|
+ const { openIntervalNew, closeInterval } = cameraStatus;
|
|
|
+
|
|
|
+ const drawContainer = ref<HTMLDivElement>();
|
|
|
+ const konvaMap = ref();
|
|
|
+ const caremaActiveId = ref<string>('');
|
|
|
+ const camerasAdded = ref<string[]>([]);
|
|
|
+ const imgUrlBg = ref<string>('');
|
|
|
+ const searchKey = ref('');
|
|
|
+
|
|
|
+ // 是否已有背景图
|
|
|
+ const hasBg = ref(false);
|
|
|
+ //是否修改
|
|
|
+ const isChange = ref<boolean>(false);
|
|
|
+ //单个相机时是否上传图片
|
|
|
+ const isUploadBg = ref<boolean>(true);
|
|
|
+
|
|
|
+ const isMap = ref(false);
|
|
|
+ const { urlPrefix } = useGlobSetting();
|
|
|
+
|
|
|
+ const actionUrl = computed(() => {
|
|
|
+ return urlJoin(urlPrefix!, `/admin/minimap/uploadPicture`);
|
|
|
+ });
|
|
|
+
|
|
|
+ function updataState(data, updateData) {
|
|
|
+ for (let i = 0; i < data.length; i++) {
|
|
|
+ const camera = data[i];
|
|
|
+ const matchedCamera = updateData.find((item) => item.cameraCode === camera.code);
|
|
|
+ if (matchedCamera) {
|
|
|
+ camera.status = matchedCamera.status;
|
|
|
+ camera.integrationState = matchedCamera.integrationState;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-const refreshUploadBg = () => {
|
|
|
- konvaMap.value.resetMap();
|
|
|
- hasBg.value = false;
|
|
|
-};
|
|
|
+ function downloadImage(url: string, filename: string) {
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = filename;
|
|
|
|
|
|
-const handleBeforeUpload = () => {
|
|
|
- if (!selectedShopId.value) {
|
|
|
- ElMessage.error({
|
|
|
- message: '请先选择车间',
|
|
|
- });
|
|
|
- return false;
|
|
|
+ // 触发点击事件
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
}
|
|
|
-};
|
|
|
|
|
|
-const sendCameras = (camerasList) => {
|
|
|
- camerasAdded.value = camerasList.map((item) => {
|
|
|
- return item.id;
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-/** 判断相机是否已经添加 */
|
|
|
-const isAddedCamera = (cameraId: string) => {
|
|
|
- const index = camerasAdded.value.findIndex((item) => item === cameraId);
|
|
|
- return index >= 0;
|
|
|
-};
|
|
|
-
|
|
|
-const changeDefault = (defaultCameraId) => {
|
|
|
- caremaActiveId.value = defaultCameraId;
|
|
|
-};
|
|
|
-
|
|
|
-const isKnovaDestroy = ref<boolean>(false) //重新上传图片之后将knova销毁
|
|
|
-const handleAvatarSuccess = (e) => {
|
|
|
- isKnovaDestroy.value = true;
|
|
|
- imgUrlBg.value = e.data;
|
|
|
- hasBg.value = true;
|
|
|
- nextTick(() => {
|
|
|
- konvaMap.value.addBg(imgUrlBg.value).then(() => {
|
|
|
- isKnovaDestroy.value = false;
|
|
|
- isChange.value = true;
|
|
|
- });
|
|
|
- })
|
|
|
-};
|
|
|
-
|
|
|
-const getMapLayoutAPIMap = {
|
|
|
- [ViewType.minimap_PC]: getWorkshopMiniMapLayoutPCApi,
|
|
|
- [ViewType.minimap_phone]: getWorkshopMiniMapLayoutMobileApi,
|
|
|
-}
|
|
|
-
|
|
|
-const getMapLayout = async (id: number) => {
|
|
|
- const api = getMapLayoutAPIMap[viewType.value];
|
|
|
- const res = await api(id);
|
|
|
- if (!res) return;
|
|
|
- const layoutJSON = JSON.parse(res.layout);
|
|
|
- return layoutJSON;
|
|
|
-}
|
|
|
-
|
|
|
-const getShopContent = async (id: number) => {
|
|
|
- await getShowCameras(id);
|
|
|
- const idList = filterShopCameraList.value.map((item) => item.id);
|
|
|
- const res = await getMapLayout(id);
|
|
|
- if (!res) return;
|
|
|
- hasBg.value = true;
|
|
|
- isMap.value = res.isUploadBg;
|
|
|
- nextTick(() => {
|
|
|
- if (res.isUploadBg) {
|
|
|
- isUploadBg.value = true;
|
|
|
- konvaMap.value.createMap(res, selectedShopId.value);
|
|
|
- } else {
|
|
|
- hasBg.value = false;
|
|
|
- isUploadBg.value = res.isUploadBg;
|
|
|
+ const refreshUploadBg = () => {
|
|
|
+ konvaMap.value.resetMap();
|
|
|
+ hasBg.value = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleBeforeUpload = () => {
|
|
|
+ if (!selectedShopId.value) {
|
|
|
+ ElMessage.error({
|
|
|
+ message: '请先选择车间',
|
|
|
+ });
|
|
|
+ return false;
|
|
|
}
|
|
|
- openIntervalNew(idList, (targetData) => {
|
|
|
- updataState(filterShopCameraList.value, targetData);
|
|
|
+ };
|
|
|
+
|
|
|
+ const sendCameras = (camerasList) => {
|
|
|
+ camerasAdded.value = camerasList.map((item) => {
|
|
|
+ return item.id;
|
|
|
});
|
|
|
- })
|
|
|
-};
|
|
|
-
|
|
|
-const selectedShopId = ref();
|
|
|
-const selectedName = ref();
|
|
|
-const viewType = ref();
|
|
|
-const shopCameraList = ref<ShopMapCamera[]>([]);
|
|
|
-const route = useRoute();
|
|
|
-
|
|
|
-const getShowCameras = async (id: number) => {
|
|
|
- const res = await getCamerasByWorkShopId({ workshopId: id });
|
|
|
- if (!res) return;
|
|
|
- res.children.forEach((item) => {
|
|
|
- if (!item.children || item.children.length <= 0) return
|
|
|
- item.children.forEach(camera => {
|
|
|
- shopCameraList.value.push({ ...camera, isSet: 0, workSpaceName: item.name })
|
|
|
- })
|
|
|
- })
|
|
|
-};
|
|
|
-
|
|
|
-const mapConfig = reactive({
|
|
|
- width: 0,
|
|
|
- height: 0
|
|
|
-});
|
|
|
-
|
|
|
-onMounted(async () => {
|
|
|
- selectedShopId.value = Number(route.query.workshopId);
|
|
|
- selectedName.value = route.query.workshopName;
|
|
|
- viewType.value = route.query.viewType;
|
|
|
- mapConfig.width = drawContainer.value?.clientWidth || 0;
|
|
|
- mapConfig.height = drawContainer.value?.clientHeight || 0;
|
|
|
- await getShopContent(selectedShopId.value);
|
|
|
-});
|
|
|
-
|
|
|
-onUnmounted(() => {
|
|
|
- closeInterval();
|
|
|
-});
|
|
|
-
|
|
|
-const filterShopCameraList = computed(() => {
|
|
|
- const k = searchKey.value.trim();
|
|
|
- if (!k) return shopCameraList.value;
|
|
|
- return shopCameraList.value.filter(
|
|
|
- (x) => x.code?.includes(k) || x.name?.includes(k) || x.workSpaceName?.includes(k),
|
|
|
- );
|
|
|
-});
|
|
|
-
|
|
|
-const handleAddCamera = (cameraId: string, index: number) => {
|
|
|
- if (isAddedCamera(cameraId)) {
|
|
|
- const camera = konvaMap.value.findCamera(cameraId);
|
|
|
- konvaMap.value.handleCameraClick(camera);
|
|
|
- return;
|
|
|
- }
|
|
|
- if (!hasBg.value) {
|
|
|
- ElMessage.warning({
|
|
|
- message: '请先添加车间地图',
|
|
|
+ };
|
|
|
+
|
|
|
+ /** 判断相机是否已经添加 */
|
|
|
+ const isAddedCamera = (cameraId: string) => {
|
|
|
+ const index = camerasAdded.value.findIndex((item) => item === cameraId);
|
|
|
+ return index >= 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ const changeDefault = (defaultCameraId) => {
|
|
|
+ caremaActiveId.value = defaultCameraId;
|
|
|
+ };
|
|
|
+
|
|
|
+ const isKnovaDestroy = ref<boolean>(false); //重新上传图片之后将knova销毁
|
|
|
+ const handleAvatarSuccess = (e) => {
|
|
|
+ isKnovaDestroy.value = true;
|
|
|
+ imgUrlBg.value = e.data;
|
|
|
+ hasBg.value = true;
|
|
|
+ nextTick(() => {
|
|
|
+ konvaMap.value.addBg(imgUrlBg.value).then(() => {
|
|
|
+ isKnovaDestroy.value = false;
|
|
|
+ isChange.value = true;
|
|
|
+ });
|
|
|
});
|
|
|
- return;
|
|
|
- }
|
|
|
- konvaMap.value.addCamera(cameraId, index);
|
|
|
-};
|
|
|
-
|
|
|
-const handleSave = () => {
|
|
|
- isMap.value = true;
|
|
|
- if(!hasBg.value && isMap.value){
|
|
|
- ElMessage.error('请先添加车间地图');
|
|
|
- return false;
|
|
|
- }
|
|
|
- const layout = konvaMap.value.saveLayout();
|
|
|
- const cameraList = JSON.parse(layout).cameraList;
|
|
|
- if (cameraList.length === 0 && hasBg.value) {
|
|
|
- ElMessage.error('请至少添加1个相机标签后发布');
|
|
|
- return false;
|
|
|
- }
|
|
|
- updateMinMapViewLayoutApi({
|
|
|
- layout: JSON.stringify({ ...JSON.parse(layout), isUploadBg: hasBg.value }),
|
|
|
- targetId: String(selectedShopId.value),
|
|
|
- viewType: viewType.value,
|
|
|
- }).then(() => {
|
|
|
- ElMessage.success('保存成功');
|
|
|
- });
|
|
|
- return true;
|
|
|
-};
|
|
|
-
|
|
|
-const changeMap = (val) => {
|
|
|
- isChange.value = val;
|
|
|
-};
|
|
|
-onBeforeRouteLeave((to,from,next)=>{
|
|
|
- if(!isChange.value) {
|
|
|
- next();
|
|
|
- return;
|
|
|
- }
|
|
|
- setTimeout(()=>{
|
|
|
- ElMessageBox.confirm('是否保存当前修改?', '提示', {
|
|
|
- confirmButtonText: '是',
|
|
|
- cancelButtonText: '否',
|
|
|
- customClass: 'elMessageBox__custom--warning',
|
|
|
- }).then(async () => {
|
|
|
- const isSaveSuccess = await handleSave();
|
|
|
- if(isSaveSuccess) {
|
|
|
- next();
|
|
|
+ };
|
|
|
+
|
|
|
+ const getMapLayoutAPIMap = {
|
|
|
+ [ViewType.minimap_PC]: getWorkshopMiniMapLayoutPCApi,
|
|
|
+ [ViewType.minimap_phone]: getWorkshopMiniMapLayoutMobileApi,
|
|
|
+ };
|
|
|
+
|
|
|
+ const getMapLayout = async (id: number) => {
|
|
|
+ const api = getMapLayoutAPIMap[viewType.value];
|
|
|
+ const res = await api(id);
|
|
|
+ if (!res) return;
|
|
|
+ const layoutJSON = JSON.parse(res.layout);
|
|
|
+ return layoutJSON;
|
|
|
+ };
|
|
|
+
|
|
|
+ const getShopContent = async (id: number) => {
|
|
|
+ await getShowCameras(id);
|
|
|
+ const idList = filterShopCameraList.value.map((item) => item.id);
|
|
|
+ const res = await getMapLayout(id);
|
|
|
+ if (!res) return;
|
|
|
+ hasBg.value = true;
|
|
|
+ isMap.value = res.isUploadBg;
|
|
|
+ imgUrlBg.value = res.bgImgUrl;
|
|
|
+ nextTick(() => {
|
|
|
+ if (res.isUploadBg) {
|
|
|
+ isUploadBg.value = true;
|
|
|
+ konvaMap.value.createMap(res, selectedShopId.value);
|
|
|
+ } else {
|
|
|
+ hasBg.value = false;
|
|
|
+ isUploadBg.value = res.isUploadBg;
|
|
|
}
|
|
|
- next(false);
|
|
|
- }).catch(() => {
|
|
|
- next()
|
|
|
- })
|
|
|
- },200)
|
|
|
-})
|
|
|
-</script>
|
|
|
+ openIntervalNew(idList, (targetData) => {
|
|
|
+ updataState(filterShopCameraList.value, targetData);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const selectedShopId = ref();
|
|
|
+ const selectedName = ref();
|
|
|
+ const viewType = ref();
|
|
|
+ const shopCameraList = ref<ShopMapCamera[]>([]);
|
|
|
+ const route = useRoute();
|
|
|
+
|
|
|
+ const getShowCameras = async (id: number) => {
|
|
|
+ const res = await getCamerasByWorkShopId({ workshopId: id });
|
|
|
+ if (!res) return;
|
|
|
+ res.children.forEach((item) => {
|
|
|
+ if (!item.children || item.children.length <= 0) return;
|
|
|
+ item.children.forEach((camera) => {
|
|
|
+ shopCameraList.value.push({ ...camera, isSet: 0, workSpaceName: item.name });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
|
|
|
-<style scoped lang="scss">
|
|
|
-.min-map {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 4px;
|
|
|
- width: 100%;
|
|
|
- height: calc(100vh - 64px - 14px);
|
|
|
- background: #f5f7f9;
|
|
|
- border-radius: 6px;
|
|
|
- box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.12);
|
|
|
-
|
|
|
- &__header {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 20px;
|
|
|
- width: inherit;
|
|
|
- height: 54px;
|
|
|
- padding: 0 15px 0 15px;
|
|
|
- background: #ffffff;
|
|
|
- border-radius: 6px 6px 0 0;
|
|
|
- }
|
|
|
+ const mapConfig = reactive({
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+ });
|
|
|
|
|
|
- &__btn {
|
|
|
- display: flex;
|
|
|
- gap: 10px;
|
|
|
- align-items: center;
|
|
|
- font-size: 14px;
|
|
|
- cursor: pointer;
|
|
|
+ onMounted(async () => {
|
|
|
+ selectedShopId.value = Number(route.query.workshopId);
|
|
|
+ selectedName.value = route.query.workshopName;
|
|
|
+ viewType.value = route.query.viewType;
|
|
|
+ mapConfig.width = drawContainer.value?.clientWidth || 0;
|
|
|
+ mapConfig.height = drawContainer.value?.clientHeight || 0;
|
|
|
+ await getShopContent(selectedShopId.value);
|
|
|
+ });
|
|
|
|
|
|
- img {
|
|
|
- width: 14px;
|
|
|
+ onUnmounted(() => {
|
|
|
+ closeInterval();
|
|
|
+ });
|
|
|
+
|
|
|
+ const filterShopCameraList = computed(() => {
|
|
|
+ const k = searchKey.value.trim();
|
|
|
+ if (!k) return shopCameraList.value;
|
|
|
+ return shopCameraList.value.filter(
|
|
|
+ (x) => x.code?.includes(k) || x.name?.includes(k) || x.workSpaceName?.includes(k),
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ const handleAddCamera = (cameraId: string, index: number) => {
|
|
|
+ if (isAddedCamera(cameraId)) {
|
|
|
+ const camera = konvaMap.value.findCamera(cameraId);
|
|
|
+ konvaMap.value.handleCameraClick(camera);
|
|
|
+ return;
|
|
|
}
|
|
|
- }
|
|
|
+ if (!hasBg.value) {
|
|
|
+ ElMessage.warning({
|
|
|
+ message: '请先添加车间地图',
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ konvaMap.value.addCamera(cameraId, index);
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSave = () => {
|
|
|
+ isMap.value = true;
|
|
|
+ if (!hasBg.value && isMap.value) {
|
|
|
+ ElMessage.error('请先添加车间地图');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const layout = konvaMap.value.saveLayout();
|
|
|
+ const cameraList = JSON.parse(layout).cameraList;
|
|
|
+ if (cameraList.length === 0 && hasBg.value) {
|
|
|
+ ElMessage.error('请至少添加1个相机标签后发布');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ updateMinMapViewLayoutApi({
|
|
|
+ layout: JSON.stringify({ ...JSON.parse(layout), isUploadBg: hasBg.value }),
|
|
|
+ targetId: String(selectedShopId.value),
|
|
|
+ viewType: viewType.value,
|
|
|
+ }).then(() => {
|
|
|
+ ElMessage.success('保存成功');
|
|
|
+ });
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ const changeMap = (val) => {
|
|
|
+ isChange.value = val;
|
|
|
+ };
|
|
|
+ onBeforeRouteLeave((to, from, next) => {
|
|
|
+ if (!isChange.value) {
|
|
|
+ next();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setTimeout(() => {
|
|
|
+ ElMessageBox.confirm('是否保存当前修改?', '提示', {
|
|
|
+ confirmButtonText: '是',
|
|
|
+ cancelButtonText: '否',
|
|
|
+ customClass: 'elMessageBox__custom--warning',
|
|
|
+ })
|
|
|
+ .then(async () => {
|
|
|
+ const isSaveSuccess = await handleSave();
|
|
|
+ if (isSaveSuccess) {
|
|
|
+ next();
|
|
|
+ }
|
|
|
+ next(false);
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ next();
|
|
|
+ });
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+</script>
|
|
|
|
|
|
- &__main {
|
|
|
+<style scoped lang="scss">
|
|
|
+ .min-map {
|
|
|
display: flex;
|
|
|
- gap: 5px;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
width: 100%;
|
|
|
- height: calc(100% - 60px);
|
|
|
+ height: calc(100vh - 64px - 14px);
|
|
|
+ background: #f5f7f9;
|
|
|
border-radius: 6px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.workshop-name {
|
|
|
- font-size: 14px;
|
|
|
- color: #3f3f3f;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-
|
|
|
-.operate-btn {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
- align-items: center;
|
|
|
- flex: 1;
|
|
|
- height: inherit;
|
|
|
- gap: 20px;
|
|
|
-
|
|
|
- .el-button {
|
|
|
- margin: 0;
|
|
|
-
|
|
|
- img {
|
|
|
- width: 14px;
|
|
|
+ box-shadow: 0px 0px 6px 0px rgba(0, 0, 0, 0.12);
|
|
|
+
|
|
|
+ &__header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 20px;
|
|
|
+ width: inherit;
|
|
|
+ height: 54px;
|
|
|
+ padding: 0 15px 0 15px;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 6px 6px 0 0;
|
|
|
}
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
-.camera-list {
|
|
|
- width: 250px;
|
|
|
- height: 100%;
|
|
|
- border-radius: 0 0 0 6px;
|
|
|
- padding: 10px 10px;
|
|
|
- background-color: #ffffff;
|
|
|
+ &__btn {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
|
|
|
- &__title {
|
|
|
- margin-left: 5px;
|
|
|
+ img {
|
|
|
+ width: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__main {
|
|
|
+ display: flex;
|
|
|
+ gap: 5px;
|
|
|
+ width: 100%;
|
|
|
+ height: calc(100% - 60px);
|
|
|
+ border-radius: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .workshop-name {
|
|
|
font-size: 14px;
|
|
|
+ color: #3f3f3f;
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
- &__search {
|
|
|
- margin-top: 10px;
|
|
|
+ .operate-btn {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ flex: 1;
|
|
|
+ height: inherit;
|
|
|
+ gap: 20px;
|
|
|
|
|
|
- :deep(.el-input__wrapper) {
|
|
|
- background-color: #f0f2f5;
|
|
|
+ .el-button {
|
|
|
+ margin: 0;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 14px;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-.workshop-map {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
- flex: 1;
|
|
|
- height: 100%;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-
|
|
|
-.camera-item {
|
|
|
- width: 100%;
|
|
|
- max-height: calc(100% - 65px);
|
|
|
- overflow-y: auto;
|
|
|
- margin-top: 10px;
|
|
|
- margin-left: 5px;
|
|
|
-
|
|
|
- &__empty {
|
|
|
- color: #3f3f3f;
|
|
|
+
|
|
|
+ .camera-list {
|
|
|
+ width: 250px;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 0 0 0 6px;
|
|
|
+ padding: 10px 10px;
|
|
|
+ background-color: #ffffff;
|
|
|
+
|
|
|
+ &__title {
|
|
|
+ margin-left: 5px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__search {
|
|
|
+ margin-top: 10px;
|
|
|
+
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
+ background-color: #f0f2f5;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- &__list {
|
|
|
+ .workshop-map {
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
+ justify-content: center;
|
|
|
align-items: center;
|
|
|
+ flex: 1;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .camera-item {
|
|
|
width: 100%;
|
|
|
- height: 32px;
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 400;
|
|
|
- color: #404040;
|
|
|
- line-height: 14px;
|
|
|
- cursor: pointer;
|
|
|
+ max-height: calc(100% - 65px);
|
|
|
+ overflow-y: auto;
|
|
|
+ margin-top: 10px;
|
|
|
+ margin-left: 5px;
|
|
|
|
|
|
- &:hover {
|
|
|
- background-color: #e6f7ff;
|
|
|
- color: #1890ff;
|
|
|
+ &__empty {
|
|
|
+ color: #3f3f3f;
|
|
|
}
|
|
|
|
|
|
- .camera-id {
|
|
|
- width: 110px;
|
|
|
- }
|
|
|
+ &__list {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 32px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #404040;
|
|
|
+ line-height: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: #e6f7ff;
|
|
|
+ color: #1890ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .camera-id {
|
|
|
+ width: 110px;
|
|
|
+ }
|
|
|
|
|
|
- .camera-space {
|
|
|
- width: 120px;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
+ .camera-space {
|
|
|
+ width: 120px;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-popover) {
|
|
|
- width: unset !important;
|
|
|
- min-width: 110px;
|
|
|
- text-align: center;
|
|
|
- font-weight: 400;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-popper__arrow) {
|
|
|
- display: none;
|
|
|
-}
|
|
|
-
|
|
|
-.isAdded {
|
|
|
- color: #1890ff;
|
|
|
-}
|
|
|
-
|
|
|
-.isActive {
|
|
|
- background-color: #e6f7ff;
|
|
|
- color: #1890ff;
|
|
|
-}
|
|
|
-
|
|
|
-.integrationState {
|
|
|
- cursor: not-allowed;
|
|
|
- color: #ccc;
|
|
|
-}
|
|
|
+
|
|
|
+ :deep(.el-popover) {
|
|
|
+ width: unset !important;
|
|
|
+ min-width: 110px;
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 400;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-popper__arrow) {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .isAdded {
|
|
|
+ color: #1890ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .isActive {
|
|
|
+ background-color: #e6f7ff;
|
|
|
+ color: #1890ff;
|
|
|
+ }
|
|
|
+
|
|
|
+ .integrationState {
|
|
|
+ cursor: not-allowed;
|
|
|
+ color: #ccc;
|
|
|
+ }
|
|
|
</style>
|