Jelajahi Sumber

fix: 自定义地图页面ui实现

sunhongyao341504 2 tahun lalu
induk
melakukan
f4048f463c

TEMPAT SAMPAH
src/assets/images/img-upload.png


+ 23 - 0
src/layout/components/Sider/Sider.vue

@@ -171,3 +171,26 @@
     updateMenu();
   });
 </script>
+
+<style scoped lang="scss">
+  .my-icon {
+    position: relative;
+    margin-right: 5px;
+    width: 0.75em;
+    height: 0.75em;
+    filter: drop-shadow(var(--el-menu-text-color) 80px 0);
+    transform: translate(-80px);
+  }
+  :deep(.el-menu-item.is-active) {
+    .my-icon {
+      filter: drop-shadow(var(--el-menu-hover-text-color) 80px 0);
+      transform: translate(-80px);
+    }
+  }
+  :deep(.el-menu-item:hover) {
+    .my-icon {
+      filter: drop-shadow(var(--el-menu-hover-text-color) 80px 0);
+      transform: translate(-80px);
+    }
+  }
+</style>

+ 1 - 1
src/layout/index.vue

@@ -316,7 +316,7 @@
         }
 
         &-main {
-          padding: 10px;
+          padding: 10px 0 0 10px;
           height: calc(100vh - 64px);
           position: relative;
           overflow-y: auto;

+ 6 - 0
src/utils/index.ts

@@ -12,6 +12,12 @@ import { TargetContext } from '/#/index';
 export function renderIcon(icon) {
   return () => h(ElIcon, null, { default: () => h(icon) });
 }
+/**
+ * render 图片
+ * */
+export function renderImg(imgSrc: string) {
+  return () => h('img', { src: imgSrc, class: 'my-icon' });
+}
 
 /**
  * render new Tag

+ 141 - 61
src/views/map-config/mini-map/MiniMapConfig.vue

@@ -1,16 +1,43 @@
 <template>
   <div class="page">
-    <div class="flex">
-      <div class="flex items-center">
-        <span>场景:</span>
-        <el-tree-select
-          v-model="selectedShopId"
-          :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="selectedShopId"
+            :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: selectedShopId }"
+          >
+            <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="!selectedShopId"
+            >保存为布局
+          </el-button>
+        </div>
       </div>
     </div>
     <div class="paint-tool flex">
@@ -18,27 +45,40 @@
         <div>
           <span class="label-text flex">相机列表:</span>
           <ElInput
-            style="margin: 10px; width: 230px"
-            placeholder="输入相机id或工位"
+            class="search-put"
+            style="margin: 10px 0; width: 230px"
+            placeholder="请输入搜索内容"
             v-model="searchKey"
             :suffix-icon="Search"
           />
         </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
             v-for="item in filterShopCameraList"
             :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)"
           >
             <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>
         </el-scrollbar>
       </div>
       <div class="draw-container">
-        <div style="display: flex; margin-bottom: 20px">
+        <!-- <div style="display: flex; margin-bottom: 20px">
           <div>
             默认摄像头:
             <ElSelect v-model="defaultCameraId">
@@ -50,28 +90,8 @@
               />
             </ElSelect>
           </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: selectedShopId }"
-          >
-            <el-button style="font-size: 12px">+ 更换/上传背景图片</el-button>
-          </el-upload>
-
-          <el-button
-            @click="handleSave"
-            style="margin-left: 40px"
-            type="primary"
-            :disabled="!selectedShopId"
-            >保存布局</el-button
-          >
-        </div>
-        <div>
+        </div> -->
+        <!-- <div>
           <div style="height: 20px; margin-bottom: 10px">
             <div v-if="selectedCamera">
               已选中相机<span>: {{ selectedCamera?.cameraId }}</span>
@@ -80,15 +100,22 @@
               </span>
             </div>
           </div>
-        </div>
+        </div> -->
         <div style="overflow: auto">
-          <canvas
-            width="400"
-            height="400"
-            id="mapEditCanvas"
-            style="border: 1px solid #ccc"
-          ></canvas>
+          <canvas width="400" height="400" id="mapEditCanvas"></canvas>
         </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: selectedShopId }"
+        >
+          <img src="~@/assets/images/img-upload.png" />
+        </el-upload>
       </div>
     </div>
   </div>
@@ -101,12 +128,12 @@
   import urlJoin from 'url-join';
   import { onMounted, ref, toRaw } from 'vue';
   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 { onUnmounted } from 'vue';
   import { useGlobSetting } from '@/hooks/setting';
   import { computed } from 'vue';
-  import { Search } from '@element-plus/icons-vue';
+  import { Search, ArrowLeft, Refresh } from '@element-plus/icons-vue';
 
   const miniMap = useMiniMap();
   const globSetting = useGlobSetting();
@@ -118,14 +145,18 @@
   const cameraOptions = ref<{ label: string; value: string }[]>([]);
   const defaultCameraId = ref('');
   const searchKey = ref('');
+  // 是否已有背景图
+  const hasBg = ref(false);
 
   const handleAvatarSuccess = (e) => {
     const imgPath = e.data;
     const imgUrl = urlJoin(globSetting.imgUrl!, imgPath);
+    hasBg.value = true;
     map.uploadBg(imgUrl);
   };
 
   const changeShop = (_) => {
+    hasBg.value = false;
     getShopContent();
   };
 
@@ -187,6 +218,7 @@
   };
 
   const handleAddCamera = (cameraId: string) => {
+    if (!hasBg.value) return;
     if (map.hasCamera(cameraId)) {
       ElMessage.warning({ message: '相机已添加' });
       return;
@@ -207,6 +239,9 @@
 
   const mapJSONToOptions = () => {
     const objects = map.toJSON()?.objects || [];
+    if (map.toJSON()?.backgroundImage.src) {
+      hasBg.value = true;
+    }
     console.log('objects', objects);
     cameraOptions.value = objects?.map((x) => ({
       label: x.cameraId,
@@ -242,10 +277,20 @@
 
 <style scoped>
   .page {
-    margin: 10px 0;
-    padding: 10px;
+    /* margin: 10px 0; */
+    padding: 10px 0 0 10px;
+  }
+  .page-head {
+    height: 54px;
+    padding-left: 15px;
     background-color: #ffffff;
   }
+  .head-opt {
+    margin-left: 20px;
+    padding-right: 15px;
+    font-size: 14px;
+    color: #3f3f3f;
+  }
 
   .avatar-uploader {
     /* width: 120px; */
@@ -254,18 +299,25 @@
     border-radius: 4px;
     margin-left: 30px;
   }
+  .upload-icon {
+    position: absolute;
+    top: 0;
+    right: 0;
+    left: 0;
+    bottom: 0;
+    margin: auto;
+  }
 
   .paint-tool {
     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 {
     width: 250px;
-    border-right: 1px solid #c0c4cc;
+    padding: 0 10px;
+    background-color: #ffffff;
   }
   .label-text {
     font-size: 14px;
@@ -273,21 +325,49 @@
     margin: 10px 0 5px 10px;
   }
   .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;
   }
+  .camera-item-disabled {
+    color: #c6c6c6;
+  }
   .camera-id {
-    width: 130px;
+    width: 110px;
+  }
+  .space-name {
+    width: 120px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
   }
 
   .draw-container {
+    position: relative;
     width: calc(100% - 300px);
     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 {