Przeglądaj źródła

Merge branch 'system-assemble' into 'master'

主页布局和小地图布局

See merge request tian-group/skyeye-admin-fe!20
楼航飞 2 lat temu
rodzic
commit
24196ac239

+ 108 - 105
index.html

@@ -1,121 +1,124 @@
 <!DOCTYPE html>
 <html lang="zh-cmn-Hans" id="htmlRoot" data-theme="light">
-<head>
-  <meta charset="UTF-8">
-  <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/>
-  <meta content="webkit" name="renderer"/>
-  <meta
-    content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
-    name="viewport"
-  />
-  <link href="/favicon.ico" rel="icon"/>
-  <title><%= title %></title>
-</head>
-<body>
-<div id="app">
-  <style>
-  .first-loading-wrap {
-    display: flex;
-    width: 100%;
-    height: 100vh;
-    justify-content: center;
-    align-items: center;
-    flex-direction: column;
-  }
+  <head>
+    <meta charset="UTF-8" />
+    <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible" />
+    <meta content="webkit" name="renderer" />
+    <meta
+      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
+      name="viewport"
+    />
+    <link href="/favicon.ico" rel="icon" />
+    <title><%= title %></title>
+  </head>
+  <body>
+    <div id="app">
+      <style>
+        .first-loading-wrap {
+          display: flex;
+          width: 100%;
+          height: 100vh;
+          justify-content: center;
+          align-items: center;
+          flex-direction: column;
+        }
 
-  .first-loading-wrap > h1 {
-    font-size: 128px
-  }
+        .first-loading-wrap > h1 {
+          font-size: 128px;
+        }
 
-  .first-loading-wrap .loading-wrap {
-    padding: 98px;
-    display: flex;
-    justify-content: center;
-    align-items: center
-  }
+        .first-loading-wrap .loading-wrap {
+          padding: 98px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+        }
 
-  .dot {
-    animation: antRotate 1.2s infinite linear;
-    transform: rotate(45deg);
-    position: relative;
-    display: inline-block;
-    font-size: 32px;
-    width: 32px;
-    height: 32px;
-    box-sizing: border-box
-  }
+        .dot {
+          animation: antRotate 1.2s infinite linear;
+          transform: rotate(45deg);
+          position: relative;
+          display: inline-block;
+          font-size: 32px;
+          width: 32px;
+          height: 32px;
+          box-sizing: border-box;
+        }
 
-  .dot i {
-    width: 14px;
-    height: 14px;
-    position: absolute;
-    display: block;
-    background-color: #1890ff;
-    border-radius: 100%;
-    transform: scale(.75);
-    transform-origin: 50% 50%;
-    opacity: .3;
-    animation: antSpinMove 1s infinite linear alternate
-  }
+        .dot i {
+          width: 14px;
+          height: 14px;
+          position: absolute;
+          display: block;
+          background-color: #1890ff;
+          border-radius: 100%;
+          transform: scale(0.75);
+          transform-origin: 50% 50%;
+          opacity: 0.3;
+          animation: antSpinMove 1s infinite linear alternate;
+        }
 
-  .dot i:nth-child(1) {
-    top: 0;
-    left: 0
-  }
+        .dot i:nth-child(1) {
+          top: 0;
+          left: 0;
+        }
 
-  .dot i:nth-child(2) {
-    top: 0;
-    right: 0;
-    -webkit-animation-delay: .4s;
-    animation-delay: .4s
-  }
+        .dot i:nth-child(2) {
+          top: 0;
+          right: 0;
+          -webkit-animation-delay: 0.4s;
+          animation-delay: 0.4s;
+        }
 
-  .dot i:nth-child(3) {
-    right: 0;
-    bottom: 0;
-    -webkit-animation-delay: .8s;
-    animation-delay: .8s
-  }
+        .dot i:nth-child(3) {
+          right: 0;
+          bottom: 0;
+          -webkit-animation-delay: 0.8s;
+          animation-delay: 0.8s;
+        }
 
-  .dot i:nth-child(4) {
-    bottom: 0;
-    left: 0;
-    -webkit-animation-delay: 1.2s;
-    animation-delay: 1.2s
-  }
+        .dot i:nth-child(4) {
+          bottom: 0;
+          left: 0;
+          -webkit-animation-delay: 1.2s;
+          animation-delay: 1.2s;
+        }
 
-  @keyframes antRotate {
-    to {
-      -webkit-transform: rotate(405deg);
-      transform: rotate(405deg)
-    }
-  }
+        @keyframes antRotate {
+          to {
+            -webkit-transform: rotate(405deg);
+            transform: rotate(405deg);
+          }
+        }
 
-  @-webkit-keyframes antRotate {
-    to {
-      -webkit-transform: rotate(405deg);
-      transform: rotate(405deg)
-    }
-  }
+        @-webkit-keyframes antRotate {
+          to {
+            -webkit-transform: rotate(405deg);
+            transform: rotate(405deg);
+          }
+        }
 
-  @keyframes antSpinMove {
-    to {
-      opacity: 1
-    }
-  }
+        @keyframes antSpinMove {
+          to {
+            opacity: 1;
+          }
+        }
 
-  @-webkit-keyframes antSpinMove {
-    to {
-      opacity: 1
-    }
-  }</style>
-  <div class="first-loading-wrap">
-    <div class="loading-wrap">
-      <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
+        @-webkit-keyframes antSpinMove {
+          to {
+            opacity: 1;
+          }
+        }
+      </style>
+      <div class="first-loading-wrap">
+        <div class="loading-wrap">
+          <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
+        </div>
+      </div>
     </div>
-  </div>
-</div>
-<script>var globalThis = window;</script> 
-<script src="/src/main.ts" type="module"></script>
-</body>
+    <script>
+      var globalThis = window;
+    </script>
+    <script src="/src/main.ts" type="module"></script>
+  </body>
 </html>

+ 10 - 0
src/api/camera/camera-overview.ts

@@ -58,6 +58,8 @@ export interface CameraDetailServer {
   status: number;
   /** 相机流 */
   pushstreamIp: string;
+  /** 工位code */
+  workspaceCode: string;
 }
 
 export const getCameraList = (params: CameraQueryParams) => {
@@ -92,3 +94,11 @@ export const updateCameraItem = (data: Partial<CameraIPItem>) => {
     data,
   });
 };
+
+export const deleteCameraItem = (params: { cameraId: number }) => {
+  return http.request({
+    url: `/cameraConfig/deleteCamera?cameraId=${params.cameraId}`,
+    method: 'delete',
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+  });
+};

+ 4 - 2
src/directives/moveable.ts

@@ -39,9 +39,11 @@ export const bindMoveTool = (el: HTMLElement, binding) => {
       e.preventDefault();
       calcTransOrigin(e.clientX, e.clientY);
       if (e.wheelDelta > 0) {
-        transInfo.zoom += 0.2;
+        const newZoom = transInfo.zoom + 0.2;
+        transInfo.zoom = newZoom > 10 ? 10 : newZoom;
       } else if (e.wheelDelta < 0) {
-        transInfo.zoom -= 0.2;
+        const newZoom = transInfo.zoom - 0.2;
+        transInfo.zoom = newZoom < 0.2 ? 0.2 : newZoom;
       }
       setBgStyle();
     }

+ 1 - 0
src/hooks/useSceneInfos.ts

@@ -54,6 +54,7 @@ export function useSceneInfos() {
     getShopSpaceList().then((res) => {
       scenesInfos.value = res;
       scenesTree.value = calculateTreeData(res, treeProps, 1);
+      console.log(scenesTree.value);
     });
   };
 

+ 18 - 1
src/views/cameras/overview/CamerasOverview.vue

@@ -54,6 +54,8 @@
   import useCameraOverview from './stores/useCameraOverview';
   import { storeToRefs } from 'pinia';
   import { CameraIPItem } from './type';
+  import { deleteCameraItem } from '@/api/camera/camera-overview';
+  import { ElMessage, ElMessageBox } from 'element-plus';
 
   const cameraOverview = useCameraOverview();
   const { cameraItems, loading, total, page, size } = storeToRefs(cameraOverview);
@@ -114,7 +116,22 @@
 
   const handlePreview = () => {};
 
-  const handleDelete = () => {};
+  const handleDelete = (row) => {
+    ElMessageBox.confirm(`您想删除相机${row.code}`, '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+      draggable: true,
+    })
+      .then(() => {
+        deleteCameraItem({ cameraId: row.id }).then(() => {
+          ElMessage.success('删除成功');
+
+          getCameraItems();
+        });
+      })
+      .catch(() => {});
+  };
 
   const handleEdit = (row) => {
     showEditPopover.value = true;

+ 8 - 1
src/views/cameras/overview/components/AddCameraByIP.vue

@@ -22,6 +22,7 @@
             style="width: 200px"
             :type="item.prop === 'password' ? 'password' : ''"
             :show-password="item.prop === 'password'"
+            :disabled="item.prop === 'principal' && props.formData !== undefined"
           />
           <el-select
             v-if="item.type === 'select'"
@@ -45,6 +46,7 @@
             check-strictly
             :placeholder="item.placeholder"
             style="width: 200px"
+            @change="handleTreeSelect"
           />
         </el-form-item>
       </el-form>
@@ -89,11 +91,16 @@
   const handleConfirm = () => {
     const copyData = cloneDeep(cameraIPData.value);
     copyData.workspaceId = flattendWorkspaces.value.find(
-      (item) => item.code === cameraIPData.value.workspaceId,
+      (item) => item.code === cameraIPData.value.workspaceCode,
     ).id;
+    delete (copyData as any).workspaceCode;
     emits('confirm-execute', copyData);
   };
 
+  const handleTreeSelect = (code: string) => {
+    cameraIPData.value.workspaceId = flattendWorkspaces.value.find((item) => item.code === code).id;
+  };
+
   onBeforeMount(() => {
     getScenesTree({ level: 3, valueKey: 'code', labelKey: 'name', disabled: true });
     if (props.formData) {

+ 1 - 0
src/views/cameras/overview/components/CameraAddPopover.vue

@@ -52,6 +52,7 @@
 
   const onAddCamera = (data) => {
     addCamera(data);
+    updateValue(false);
   };
 </script>
 

+ 8 - 5
src/views/cameras/overview/components/CameraEditPopover.vue

@@ -21,6 +21,7 @@
   import IPAddCamera from './AddCameraByIP.vue';
   import { CameraIPItem } from '../type';
   import useCameraOverview from '../stores/useCameraOverview';
+  import { cloneDeep } from 'lodash-es';
 
   const props = defineProps<{
     modelValue: boolean;
@@ -38,11 +39,13 @@
   };
 
   const onEditCamera = (data) => {
-    if (!props.confirmEvent) {
-      editCamera(data);
-    } else {
-      props.confirmEvent(data);
-    }
+    const temp = cloneDeep(data) as any;
+    delete temp.workshopName;
+    delete temp.workspaceName;
+    delete temp.principal;
+    editCamera(temp);
+    props.confirmEvent && props.confirmEvent(data);
+    updateValue(false);
   };
 </script>
 

+ 1 - 1
src/views/cameras/overview/constant.ts

@@ -94,7 +94,7 @@ export const cameraIPAddForm: CameraAddFormItem[] = [
   },
   {
     label: '场景:',
-    prop: 'workspaceId',
+    prop: 'workspaceCode',
     placeholder: '请输入场景名称',
     type: 'tree-select',
     required: true,

+ 2 - 0
src/views/cameras/overview/stores/useCameraOverview.ts

@@ -57,6 +57,8 @@ export const useCameraOverview = defineStore('camera-overview', () => {
   });
 
   const addCamera = (data: CameraIPItem) => {
+    console.log(data);
+
     addCameraItem(data).then(() => {
       getCameraItems();
     });

+ 4 - 0
src/views/cameras/overview/type.ts

@@ -21,6 +21,8 @@ export interface CameraIPItem {
   username?: string;
   /** 密码 */
   password?: string;
+  /** 相机工位code */
+  workspaceCode?: string;
 }
 
 export interface CameraShowItem extends CameraIPItem {
@@ -34,6 +36,8 @@ export interface CameraShowItem extends CameraIPItem {
   networkingState: number;
   /** 状态: 0-启用, 1-禁用 */
   status: number;
+  /** 工位code */
+  workspaceCode: string;
 }
 
 export interface CameraRangeItem {

+ 2 - 2
src/views/map-config/mini-map/MiniMapConfig.vue

@@ -20,7 +20,7 @@
           <!-- <el-button @click="mapEditor.toJson">tojson</el-button> -->
           <el-upload
             class="avatar-uploader flex justify-center items-center"
-            action="/api/layout/uploadPicture"
+            action="/skyeye-admin-api/layout/uploadPicture"
             :show-file-list="false"
             :on-success="handleAvatarSuccess"
             :with-credentials="true"
@@ -87,7 +87,7 @@
         <el-upload
           v-if="!hasBg"
           class="upload-icon flex justify-center items-center"
-          action="/api/layout/uploadPicture"
+          action="/skyeye-admin-api/layout/uploadPicture"
           :show-file-list="false"
           :before-upload="handleBeforeUpload"
           :on-success="handleAvatarSuccess"

+ 14 - 2
src/views/map-config/mini-map/hooks/useMapEditor.ts

@@ -14,6 +14,7 @@ export function useMapEditor() {
   // let initHeight; // 默认高度
   let stage: Konva.Stage | null = null;
   let layer: Konva.Layer | null = null;
+  let copyLayer: Konva.Layer | null = null;
   let defaultIcon: Konva.Image | null = null; // 默认相机的图标shape
   const addedCameras = ref<string[]>([]); // 已添加相机列表
   const activeGroup = ref<Konva.Group | null>(null); // transformer激活的相机
@@ -32,8 +33,11 @@ export function useMapEditor() {
     // initHeight = opt.height || 0;
     stage = new Konva.Stage(opt);
     stage.on('click tap', handleStageClick);
+    window.stage = stage;
     layer = new Konva.Layer();
+    copyLayer = new Konva.Layer();
     stage.add(layer);
+    stage.add(copyLayer);
     addDefaultIcon();
   };
 
@@ -334,7 +338,11 @@ export function useMapEditor() {
         };
       });
     const layout = {
-      bgImg: bgImgUrl.value,
+      bgInfo: {
+        bgImg: bgImgUrl.value,
+        width: layer?.find('#bgImg')[0].width(),
+        height: layer?.find('#bgImg')[0].height(),
+      },
       defaultCameraId: defaultCameraId.value,
       cameraList: cameras,
     };
@@ -345,7 +353,7 @@ export function useMapEditor() {
   /** 导入布局json */
   const createMap = (layout) => {
     // const layout = JSON.parse(json);
-    bgImgUrl.value = layout.bgImg;
+    bgImgUrl.value = layout.bgInfo.bgImg;
     addBg();
     layout.cameraList.forEach((camera) => {
       const group = new Konva.Group({
@@ -373,6 +381,7 @@ export function useMapEditor() {
 
         if (camera.cameraId === layout.defaultCameraId) {
           setDefaultCamera(group);
+          defaultIcon?.show();
         }
 
         if (addedCameras.value.length === layout.cameraList.length) {
@@ -384,7 +393,10 @@ export function useMapEditor() {
   };
 
   const resetMap = () => {
+    defaultIcon?.moveTo(copyLayer);
     layer?.clear();
+    layer?.removeChildren();
+    defaultIcon?.moveTo(layer);
     addedCameras.value = [];
     activeGroup.value = null;
     defaultCameraId.value = '';

+ 3 - 3
src/views/page-config/ConfigEdit.vue

@@ -43,7 +43,7 @@
           <!-- <el-button @click="toJson">tojson</el-button> -->
           <el-upload
             class="avatar-uploader flex justify-center items-center"
-            action="/api/homepageConfig/updateCompanyPicture"
+            action="/skyeye-admin-api/homepageConfig/updateCompanyPicture"
             :show-file-list="false"
             :on-success="handleAvatarSuccess"
             :with-credentials="true"
@@ -96,13 +96,13 @@
         </el-scrollbar>
       </div>
       <div ref="drawContainer" id="drawContainer" class="draw-container">
-        <div id="editContainer" v-moveable:1>
+        <div id="shopEditContainer" v-moveable:1>
           <MapContainer />
         </div>
         <el-upload
           v-if="!hasBg"
           class="upload-icon flex justify-center items-center"
-          action="/api/homepageConfig/uploadCompanyPicture"
+          action="/skyeye-admin-api/homepageConfig/uploadCompanyPicture"
           :show-file-list="false"
           :before-upload="handleBeforeUpload"
           :on-success="handleAvatarSuccess"

+ 0 - 468
src/views/page-config/ConfigEidt.vue

@@ -1,468 +0,0 @@
-<template>
-  <div style="position: relative">
-    <div class="top-content">
-      <div style="display: flex; position: relative">
-        <img src="~@/assets/icons/back.png" alt="" @click="backPage" class="back-btn" />
-        <el-select
-          v-model="companySelet"
-          class="m-2"
-          placeholder="请选择相关公司"
-          style="width: 216px"
-          @change="changeCom"
-        >
-          <el-option
-            v-for="item in companyList"
-            :key="item.id"
-            :label="item.value"
-            :value="item.value"
-          />
-        </el-select>
-        <div v-if="companySelet" style="display: flex; margin-top: 8px">
-          <div class="label-workshop">选择标签:</div>
-          <div>
-            <el-radio-group v-model="label" size="10px" :border="true" style="display: flex">
-              <el-radio-button
-                v-for="item in labelList"
-                :key="item.id"
-                :label="item.id!"
-                class="label-select"
-                >{{ item.value }}</el-radio-button
-              >
-            </el-radio-group></div
-          >
-        </div>
-        <el-upload
-          ref="upload"
-          class="upload-demo"
-          :limit="1"
-          :show-file-list="false"
-          :on-exceed="handleExceed"
-          :on-change="onSelectfile"
-          :auto-upload="false"
-          :before-upload="beforeAvatarUpload"
-        >
-          <template #trigger>
-            <el-button :icon="Refresh" plain class="btn-top-refresh">替换照片</el-button>
-          </template>
-        </el-upload>
-        <el-button v-if="saveSwitch" type="info" plain class="btn-top-save" @click="saveConfigPage"
-          >保存为主页</el-button
-        >
-        <el-button v-else type="info" plain class="btn-top-save" @click="saveConfigMap"
-          >保存为地图</el-button
-        >
-        <!-- <div>按钮</div> -->
-      </div>
-    </div>
-    <div style="display: flex">
-      <div class="workshop-content">
-        <div class="workshop-title">车间列表</div>
-        <el-input
-          v-model="searchWorkshop"
-          class="w-50 m-2"
-          placeholder="请输入搜索内容"
-          :suffix-icon="Search"
-          style="width: 255px; margin-top: 11px"
-        />
-        <ul v-if="workshopList"
-          ><li
-            v-for="item in workshopList"
-            :key="item.id"
-            class="workshop-list"
-            :class="{ 'active-workshop': activeId === item.id }"
-            @click="configWorkshop(item)"
-            ><el-icon><House /></el-icon
-            ><div style="margin-left: 5px; margin-top: -4px">{{ item.value }}</div></li
-          ></ul
-        >
-        <div v-else class="workshop-tip">提示:请先选择相应公司和照片</div>
-      </div>
-      <div>
-        <div class="upload" :class="{ 'avatar-show': imageUrl }">
-          <el-upload
-            class="avatar-uploader"
-            :auto-upload="false"
-            :on-change="onSelectfile"
-            :before-upload="beforeAvatarUpload"
-          >
-            <template #trigger>
-              <img src="~@/assets/icons/upload.png" alt="" class="upload-pic" />
-            </template>
-          </el-upload>
-          <!-- <div class="upload-tip">只支持.jpg格式</div> -->
-        </div>
-
-        <img v-if="imageUrl" :src="imageUrl" class="preview-image" />
-        <!-- <div>222</div> -->
-      </div></div
-    >
-    <el-tooltip
-      class="box-item position-tooltip"
-      effect="dark"
-      content="显示侧边栏"
-      offset="12"
-      placement="left"
-      @click="showEditConfig"
-    >
-      <div
-        v-if="leftShow"
-        class="circle-rectangle"
-        :class="{ 'shape-shadow': shadow }"
-        @mouseover="shadowAdd"
-        @mouseout="shadowRemove"
-        @click="dialogReopen"
-      >
-        <el-icon class="left-icon" size="16px"><ArrowLeftBold /></el-icon>
-        <el-icon style="margin-top: 7px" size="16px"><ArrowLeftBold /></el-icon>
-        <!-- <el-icon class="left-icon"><DArrowLeft /></el-icon> -->
-      </div>
-      <!-- <img src="~@/assets/icons/slide.png" alt="" class="dialog-btn" /> -->
-    </el-tooltip>
-
-    <ConfigDialog
-      ref="configDrawer"
-      :title="configTitle"
-      @on-close="onClose"
-      @save-config="saveConfig"
-      class="drawer-position"
-    />
-    <ConfigFinish
-      :visible="visibleResult"
-      :status="configStatus"
-      @on-close="closeResult"
-      class="feedback-position"
-    />
-  </div>
-</template>
-<script lang="ts" setup>
-  import { ref } from 'vue';
-  import { Refresh, Search, ArrowLeftBold, House } from '@element-plus/icons-vue';
-  import ConfigDialog from './component/ConfigDrawer.vue';
-  import ConfigFinish from './component/ConfigFinish.vue';
-  //   import { picList } from '../constant';
-  import { labelList, companyList, workshopList } from './constant';
-  import { ElMessage, genFileId } from 'element-plus';
-  import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
-  // import upload, { UploadRawFile, genFileId } from 'element-plus/es/components/upload';
-  import { useRouter } from 'vue-router';
-  const router = useRouter();
-
-  // const props = defineProps<{
-  //   pageShow: boolean;
-  //   // workshopTemplateList: WorkshopModuleType[];
-  // }>();
-
-  //   const emit = defineEmits<{
-  //     // (e: 'update:modelValue'): unknown;
-  //     (e: 'onClose'): unknown;
-  //   }>();
-
-  const label = ref('');
-
-  const companySelet = ref('');
-
-  const searchWorkshop = ref('');
-
-  const saveSwitch = ref<boolean>(true);
-
-  const changeCom = () => {
-    saveSwitch.value = true;
-  };
-  const configStatus = ref(true);
-  // const replacePic = () => {};
-  const saveConfigPage = () => {
-    saveSwitch.value = false;
-    // router.push('/page-config/config');
-  };
-
-  //总体的保存,将整个数据传过去
-  const visibleResult = ref(false);
-  const saveConfigMap = () => {
-    //这里需要控制成功或者失败的弹出框
-    visibleResult.value = true;
-    //configStatus修改状态,决定成功还是失败
-    // saveSwitch.value = true;
-    // router.push('/page-config/config');
-  };
-
-  const imageUrl = ref('');
-  const configDrawer = ref();
-
-  const backPage = () => {
-    router.push('/page-config/layout');
-  };
-
-  const beforeAvatarUpload = (rawFile) => {
-    if (rawFile.type !== 'image/jpeg') {
-      ElMessage.error('Avatar picture must be JPG format!');
-      return false;
-    }
-    // else if (rawFile.size / 1024 / 1024 > 2) {
-    //   ElMessage.error('Avatar picture size can not exceed 2MB!');
-    //   return false;
-    // }
-    return true;
-  };
-
-  const onSelectfile = (uploadFile) => {
-    imageUrl.value = URL.createObjectURL(uploadFile.raw!);
-  };
-
-  const upload = ref<UploadInstance>();
-  const handleExceed: UploadProps['onExceed'] = (files) => {
-    upload.value!.clearFiles();
-    const file = files[0] as UploadRawFile;
-    file.uid = genFileId();
-    upload.value!.handleStart(file);
-  };
-
-  const activeId = ref();
-  const configTitle = ref();
-  const visibleDrawer = ref();
-  //编辑车间
-  const configWorkshop = (item) => {
-    configDrawer.value.openDialog();
-    visibleDrawer.value = true;
-    configTitle.value = item.value;
-    activeId.value = item.id;
-  };
-
-  const showEditConfig = () => {};
-  // const label = ref('');
-
-  const shadow = ref(false);
-  const shadowAdd = () => {
-    shadow.value = true;
-  };
-  const shadowRemove = () => {
-    shadow.value = false;
-  };
-
-  const dialogReopen = () => {
-    configDrawer.value.openDialog();
-  };
-
-  //左边的浮动按钮
-  const leftShow = ref(false);
-  const onClose = (val) => {
-    leftShow.value = val;
-  };
-
-  //需要从子组件中获得当前保存的车间数据
-  const saveConfig = (val) => {
-    console.log(val);
-  };
-
-  const closeResult = () => {
-    visibleResult.value = false;
-  };
-</script>
-
-<style lang="scss" scoped>
-  // .proCard {
-  //   padding: 0px;
-  // }
-  .top-content {
-    padding: 0px;
-    background-color: white;
-    position: relative;
-  }
-
-  .back-btn {
-    width: 32px;
-    height: 32px;
-    margin-top: 7px;
-    margin-right: 20px;
-  }
-
-  .btn-top-refresh {
-    position: absolute;
-    margin-top: 14px;
-    right: 137px;
-    // left: 1437px;
-  }
-
-  .btn-top-save {
-    position: absolute;
-    // margin-top: 8px;
-    margin-top: 6px;
-    right: 15px;
-  }
-
-  .label-workshop {
-    font-size: 14px;
-    font-weight: 400;
-    margin-left: 36px;
-    margin-top: 6px;
-    margin-right: 16px;
-  }
-
-  .workshop-content {
-    margin-top: 10px;
-    background-color: white;
-    // padding-left: 15px;
-    // margin-left: 10px;
-    margin-right: 10px;
-    width: 271px;
-    height: 800px;
-    border: 1px solid #b3b3b3;
-  }
-
-  .workshop-title {
-    font-size: 14px;
-    margin-top: 25px;
-    margin-left: 15px;
-    font-weight: 500;
-    color: rgba(0, 0, 0, 0.85);
-  }
-
-  // .label-select {
-  // }
-  // .el-radio-button__inner
-  ::v-deep.el-radio-button {
-    margin-right: 8px;
-    box-shadow: none;
-    border-radius: 4px !important;
-    border: 1px solid #d9d9d9 !important;
-  }
-  .workshop-list {
-    font-size: 14px;
-    width: 211px;
-    margin-top: 10px;
-    margin-left: 15px;
-    font-weight: 400;
-    color: rgba(0, 0, 0, 0.85);
-    cursor: pointer;
-    display: flex;
-  }
-
-  .workshop-tip {
-    margin-left: 15px;
-    margin-top: 12px;
-    font-size: 14px;
-    font-weight: 400;
-    color: rgba(0, 0, 0, 0.65);
-  }
-
-  .upload-pic {
-    z-index: 99;
-    width: 593px;
-    height: 435px;
-    // margin-left: ;
-  }
-  .active-workshop {
-    background: rgba(24, 144, 255, 0.502);
-  }
-
-  .avatar-uploader .el-upload {
-    border: 1px dashed var(--el-border-color);
-    border-radius: 6px;
-    width: 593px;
-    height: 435px;
-    cursor: pointer;
-    position: relative;
-    overflow: hidden;
-    color: #8c939d;
-    transition: var(--el-transition-duration-fast);
-  }
-
-  .avatar-uploader .el-upload:hover {
-    border-color: var(--el-color-primary);
-  }
-
-  // .el-icon.avatar-uploader-icon {
-  //   font-size: 28px;
-  //   color: #8c939d;
-  //   width: 178px;
-  //   height: 178px;
-  //   text-align: center;
-  //   margin-top: -60px;
-  // }
-
-  .upload {
-    position: absolute;
-    left: 428px;
-    top: 174px;
-  }
-
-  // .upload-tip {
-  //   margin-top: 5px;
-  //   font-size: 22px;
-  //   font-weight: 350;
-  //   color: #3d3d3d;
-  //   opacity: 0.4;
-  //   text-align: center;
-  // }
-
-  .uploader-text {
-    margin-top: -60px;
-    margin-left: 50px;
-    font-size: 22px;
-    font-weight: 350;
-    color: #3d3d3d;
-    opacity: 0.4;
-  }
-
-  // .preview-container {
-  //   width: 178px;
-  //   height: 178px;
-  //   position: relative;
-  // }
-
-  .preview-image {
-    min-width: 100%;
-    min-height: 100%;
-    object-fit: contain;
-  }
-
-  .avatar-show {
-    display: none;
-  }
-
-  .drawer-position {
-    position: absolute;
-    right: 0px;
-    // left: 1150px;
-    top: 74px;
-    z-index: 99;
-    opacity: 1;
-    background: #ffffff;
-  }
-
-  .dialog-btn {
-    position: absolute;
-    right: 0px;
-    top: 66px;
-  }
-
-  .position-tooltip {
-    margin-right: -10px;
-  }
-
-  .circle-rectangle {
-    width: 40px;
-    height: 30px;
-    border-radius: 50% 0% 0% 50%;
-    position: absolute;
-    right: 0px;
-    top: 66px;
-    background-color: white;
-    display: flex;
-  }
-
-  .shape-shadow {
-    filter: drop-shadow(5px 5px 10px rgb(102, 100, 100));
-  }
-  .left-icon {
-    margin-top: 7px;
-    margin-left: 8px;
-    margin-right: -7px;
-  }
-
-  .feedback-position {
-    position: absolute;
-    left: 460px;
-    top: 150px;
-    z-index: 9999;
-  }
-</style>

+ 1 - 3
src/views/page-config/component/ConfigDrawer.vue

@@ -92,7 +92,7 @@
               />
             </el-select>
             <div class="color-fontsize-select"
-              ><el-color-picker v-model="fontSizeColor" size="small" /><div
+              ><el-color-picker v-model="editShop.fontColor" color-format="hex" size="small" /><div
                 class="color-fontSize-content"
                 >{{ editShop.fontColor }}</div
               ></div
@@ -164,8 +164,6 @@
 
   const fontSizeList = Array.from({ length: 11 }, (_, index) => index + 10);
 
-  const fontSizeColor = ref('');
-
   const saveWorkshopConfig = () => {
     addedShops.value = cloneDeep(showShops.value);
   };

+ 0 - 298
src/views/page-config/component/ConfigEidt.vue

@@ -1,298 +0,0 @@
-<template>
-  <div v-if="!props.pageShow" style="position: relative"
-    ><div style="display: flex; position: relative">
-      <!-- <el-input
-        v-model="searchCom"
-        class="w-50 m-2"
-        placeholder="搜索公司主页"
-        :prefix-icon="Search"
-        style="width: 274px"
-      /> -->
-      <el-select v-model="companySelet" class="m-2" placeholder="搜索公司" style="width: 274px">
-        <el-option
-          v-for="item in companyList"
-          :key="item.id"
-          :label="item.value"
-          :value="item.value"
-        />
-      </el-select>
-      <div v-if="companySelet" style="display: flex; margin-top: 8px">
-        <div style="font-size: 20px; margin-left: 29px; margin-right: 4px">选择标签</div>
-        <div>
-          <el-radio-group v-model="label" size="10px" :border="true" style="display: flex">
-            <el-radio-button
-              v-for="item in labelList"
-              :key="item.id"
-              :label="item.id!"
-              class="label-select"
-              >{{ item.value }}</el-radio-button
-            >
-          </el-radio-group></div
-        >
-      </div>
-      <el-upload
-        ref="upload"
-        class="upload-demo"
-        :limit="1"
-        :show-file-list="false"
-        :on-exceed="handleExceed"
-        :on-change="onSelectfile"
-        :auto-upload="false"
-        :before-upload="beforeAvatarUpload"
-      >
-        <template #trigger>
-          <el-button :icon="Refresh" plain class="btn-top-refresh">替换照片</el-button>
-        </template>
-      </el-upload>
-      <!-- <el-button type="info" :icon="Refresh" plain class="btn-top-refresh" @click="replacePic"
-        >替换照片</el-button
-      > -->
-      <el-button type="info" plain class="btn-top-save" @click="saveConfig">保存</el-button>
-      <!-- <div>按钮</div> -->
-    </div>
-    <div style="display: flex">
-      <div class="workshop-content">
-        <div class="workshop-title">车间列表</div>
-        <el-input
-          v-model="searchWorkshop"
-          class="w-50 m-2"
-          placeholder="搜索功能"
-          :prefix-icon="Search"
-          style="width: 255px; margin-top: 11px"
-        />
-        <ul
-          ><li
-            v-for="item in workshopList"
-            :key="item.id"
-            class="workshop-list"
-            :class="{ 'active-workshop': activeId === item.id }"
-            @click="configWorkshop(item)"
-            >{{ item.value }}</li
-          ></ul
-        >
-      </div>
-      <div>
-        <div class="upload" :class="{ 'avatar-show': imageUrl }">
-          <el-upload
-            class="avatar-uploader"
-            list-type="picture-card"
-            :auto-upload="false"
-            :on-change="onSelectfile"
-            :before-upload="beforeAvatarUpload"
-          >
-            <!-- list-type="picture-card" -->
-            <!-- <div class="el-upload__text"> Drop file here or </div> -->
-            <!-- <img v-if="imageUrl" :src="imageUrl" class="avatar" /> -->
-            <div>
-              <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
-              <div class="uploader-text">上传照片</div>
-            </div>
-            <!-- <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon> -->
-          </el-upload>
-          <div class="upload-tip">只支持.jpg格式</div></div
-        >
-
-        <img v-if="imageUrl" :src="imageUrl" class="preview-image" />
-        <!-- <div>222</div> -->
-      </div></div
-    >
-    <ConfigDrawer
-      :visible="visibleDrawer"
-      :title="configTitle"
-      :onClose="onClose"
-      class="drawer-position"
-    />
-  </div>
-</template>
-<script lang="ts" setup>
-  import { ref } from 'vue';
-  import { Refresh, Search, Delete, Plus } from '@element-plus/icons-vue';
-  import ConfigDrawer from './ConfigDrawer.vue';
-  import { picList } from '../constant';
-  import { labelList, companyList, workshopList } from '../constant';
-  import { ElMessage, genFileId } from 'element-plus';
-  import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
-  // import upload, { UploadRawFile, genFileId } from 'element-plus/es/components/upload';
-
-  const props = defineProps<{
-    pageShow: boolean;
-    // workshopTemplateList: WorkshopModuleType[];
-  }>();
-
-  const emit = defineEmits<{
-    // (e: 'update:modelValue'): unknown;
-    (e: 'onClose'): unknown;
-  }>();
-
-  const label = ref('');
-
-  const companySelet = ref('');
-
-  const searchWorkshop = ref('');
-
-  // const replacePic = () => {};
-  const saveConfig = () => {};
-
-  const imageUrl = ref('');
-
-  const beforeAvatarUpload = (rawFile) => {
-    if (rawFile.type !== 'image/jpeg') {
-      ElMessage.error('Avatar picture must be JPG format!');
-      return false;
-    }
-    // else if (rawFile.size / 1024 / 1024 > 2) {
-    //   ElMessage.error('Avatar picture size can not exceed 2MB!');
-    //   return false;
-    // }
-    return true;
-  };
-
-  const onSelectfile = (uploadFile) => {
-    console.log('2333');
-
-    imageUrl.value = URL.createObjectURL(uploadFile.raw!);
-    console.log('12333');
-  };
-
-  const upload = ref<UploadInstance>();
-  const handleExceed: UploadProps['onExceed'] = (files) => {
-    upload.value!.clearFiles();
-    const file = files[0] as UploadRawFile;
-    file.uid = genFileId();
-    upload.value!.handleStart(file);
-  };
-
-  const activeId = ref();
-  const configTitle = ref();
-  const visibleDrawer = ref();
-  //编辑车间
-  const configWorkshop = (item) => {
-    visibleDrawer.value = true;
-    configTitle.value = item.value;
-    activeId.value = item.id;
-  };
-  const leftShow = ref(false);
-  const onClose = (value) => {
-    leftShow.value = value;
-  };
-  // const label = ref('');
-</script>
-
-<style lang="scss" scoped>
-  .btn-top-refresh {
-    position: absolute;
-    margin-top: 19px;
-    right: 130px;
-    // left: 1437px;
-  }
-
-  .btn-top-save {
-    position: absolute;
-    margin-top: 8px;
-    right: 46px;
-  }
-
-  .workshop-content {
-    margin-top: 34px;
-    margin-left: 10px;
-    margin-right: 10px;
-    width: 271px;
-    height: 660px;
-    border: 1px solid #b3b3b3;
-  }
-
-  .workshop-title {
-    font-size: 20px;
-    margin-top: 15px;
-    margin-left: 13px;
-    font-weight: 900;
-    color: #3d3d3d;
-    opacity: 0.4;
-  }
-
-  .workshop-list {
-    font-size: 20px;
-    width: 211px;
-    margin-top: 15px;
-    margin-left: 13px;
-    font-weight: 350;
-    color: #3d3d3d;
-    opacity: 0.4;
-    cursor: pointer;
-  }
-  .active-workshop {
-    background: rgba(24, 144, 255, 0.502);
-  }
-
-  .avatar-uploader .el-upload {
-    border: 1px dashed var(--el-border-color);
-    border-radius: 6px;
-    width: 260px;
-    height: 280px;
-    cursor: pointer;
-    position: relative;
-    overflow: hidden;
-    color: #8c939d;
-    transition: var(--el-transition-duration-fast);
-  }
-
-  .avatar-uploader .el-upload:hover {
-    border-color: var(--el-color-primary);
-  }
-
-  .el-icon.avatar-uploader-icon {
-    font-size: 28px;
-    color: #8c939d;
-    width: 178px;
-    height: 178px;
-    text-align: center;
-    margin-top: -60px;
-  }
-
-  .upload {
-    position: absolute;
-    left: 635px;
-    top: 201px;
-  }
-
-  .upload-tip {
-    margin-top: 5px;
-    font-size: 22px;
-    font-weight: 350;
-    color: #3d3d3d;
-    opacity: 0.4;
-    text-align: center;
-  }
-
-  .uploader-text {
-    margin-top: -60px;
-    margin-left: 50px;
-    font-size: 22px;
-    font-weight: 350;
-    color: #3d3d3d;
-    opacity: 0.4;
-  }
-
-  // .preview-container {
-  //   width: 178px;
-  //   height: 178px;
-  //   position: relative;
-  // }
-
-  .preview-image {
-    min-width: 100%;
-    min-height: 100%;
-    object-fit: contain;
-  }
-
-  .avatar-show {
-    display: none;
-  }
-
-  .drawer-position {
-    position: absolute;
-    // left: 1603px;
-    right: 0px;
-    top: 0px;
-  }
-</style>

+ 5 - 5
src/views/page-config/component/mapContainer/LabelItem.vue

@@ -36,9 +36,9 @@
   }
 
   .test-icon {
-    width: 26.762px;
-    height: 32px;
-    margin-right: 10px;
+    width: 40.2px;
+    height: 48px;
+    margin-right: 15px;
   }
 
   .hover-img {
@@ -53,8 +53,8 @@
 
   .pos-rect {
     position: relative;
-    width: 161px;
-    height: 37px;
+    width: 241.5px;
+    height: 55.5px;
     display: flex;
     justify-content: center;
     align-items: center;

+ 23 - 17
src/views/page-config/component/mapContainer/Transformer.vue

@@ -2,8 +2,8 @@
   <div
     class="transformer-box flex"
     :style="{
-      left: `${transformShop.x - 2}px`,
-      top: `${transformShop.y - 2}px`,
+      left: `${transformShop.x - 4}px`,
+      top: `${transformShop.y - 4}px`,
     }"
     @click="activeShop = transformShop"
   >
@@ -99,20 +99,13 @@
   };
 
   const handleMouseDown = (e) => {
-    console.log(e);
-
-    console.log(transformShop.value.name);
-    console.log(activeShop.value.name);
-
+    // console.log(e);
     if (transformShop.value.id !== activeShop.value.id) {
-      console.log('0-0-0-0');
-
       return;
     }
 
     if (e.target === baffleRef.value) {
       console.log('move start');
-
       transform = TransformType.MOVE;
       originPos.x = e.clientX;
       originPos.y = e.clientY;
@@ -134,12 +127,25 @@
   };
 
   const handleMouseMove = (e) => {
-    const dx = e.clientX - originPos.x;
-    const dy = e.clientY - originPos.y;
+    let dx = e.clientX - originPos.x;
+    let dy = e.clientY - originPos.y;
     originPos.x = e.clientX;
     originPos.y = e.clientY;
     const shop = showShops.value.find((item) => item.id === props.shop.id)!;
     if (e.target === baffleRef.value && transform === TransformType.MOVE) {
+      const el = document.getElementById('shopEditContainer') as HTMLDivElement;
+      const style = window.getComputedStyle(el, null);
+      const transformInfo =
+        style.getPropertyValue('-webkit-transform') ||
+        style.getPropertyValue('-moz-transform') ||
+        style.getPropertyValue('-ms-transform') ||
+        style.getPropertyValue('-o-transform') ||
+        style.getPropertyValue('transform') ||
+        'FAIL';
+      const scale = Number(transformInfo.split('(')[1].split(',')[0]);
+      dx /= scale;
+      dy /= scale;
+
       shop.x = getNumByBound(shop.x + dx, 0, mapWidth.value - originRect.w);
       shop.y = getNumByBound(shop.y + dy, 0, mapHeight.value - originRect.h);
     } else if (transform === TransformType.SCALE) {
@@ -208,14 +214,14 @@
 <style scoped lang="scss">
   .transformer-box {
     position: absolute;
-    padding: 2px;
+    padding: 4px;
   }
 
   .baffle {
     position: absolute;
     width: 100%;
     height: 100%;
-    border: 1px solid black;
+    border: 2px solid #4573bd;
     top: 0;
     left: 0;
     cursor: move;
@@ -224,10 +230,10 @@
 
   .corner {
     position: absolute;
-    width: 8px;
-    height: 8px;
+    width: 12px;
+    height: 12px;
     background-color: #ffffff;
-    border: 1px solid black;
+    border: 2px solid #4573bd;
     cursor: crosshair;
 
     &.left-top {