zhudie 2 лет назад
Родитель
Сommit
29b794d49a

+ 8 - 0
src/hooks/useSceneInfos.ts

@@ -60,6 +60,14 @@ export function useSceneInfos() {
 
   const getCameraList = (workshop: number) => {
     return getCamerasByWorkSpace({ workshopId: workshop }).then((res) => {
+      res[0].cameraList.push({
+        name: 'C204',
+        code: 'C204',
+        cameraIp: '192.168.1.203',
+        remark: '',
+        status: 0,
+        pushstreamIp: 'http://192.168.1.138:8080/live/C203.flv',
+      });
       return res;
     });
   };

+ 298 - 60
src/views/map-config/mini-map/MapBase/KonvaMap.vue

@@ -1,30 +1,57 @@
 <template>
-  <div id="drawContainer">
+  <div>
     <v-stage :config="stageConfig" @click="handleStageClick">
-      <v-layer>
-        <v-image :config="bgConfig" v-if="props.bgImgUrl" />
+      <v-layer ref="layer">
+        <v-image :config="bgConfig" v-show="props.bgImgUrl" />
         <v-group
           v-for="camera in cameras"
           :key="camera.id"
+          :id="camera.id"
           :attrs="camera"
-          @dblclick="() => handleCameraDblClick(camera)"
+          :config="groupConfig"
+          @click="(e) => handleCameraClick(camera, e)"
+          @mouseover="(e) => handleMouseOver(camera, e)"
+          @mouseleave="(e) => handleMouseLeave(camera, e)"
+          @dragstart="(e) => handleDragStart(camera, e)"
         >
-          <v-image :config="cameraConfig" @dragend="(e) => handleCameraDragEnd(camera, e)" />
+          <v-image :config="camera.config" @dragend="(e) => handleCameraDragEnd(camera, e)" />
+          <!-- <v-image :config="defaultIconConfig2" /> -->
+          <v-image v-if="camera.isDefault" ref="defaultIcon" :config="defaultIconConfig" />
         </v-group>
-        <v-image :config="defaultIconConfig" v-if="defaultIconVisible" />
+        <v-image ref="defaultIcon" :config="defaultIconConfig" />
+        <v-transformer ref="transformer" />
       </v-layer>
     </v-stage>
+    <!-- <OptBar :disabled="defaultShow" /> -->
+    <div
+      @click="setDefaultCamera"
+      v-show="defaultShow"
+      class="opt-container"
+      :style="{ position: 'absolute', left: posX + 'px', top: posY + 'px' }"
+      ><div class="opt-item">设为默认相机</div></div
+    >
+    <DefaultTip
+      v-show="tipShow"
+      :position="pos"
+      :style="{ position: 'absolute', left: posTipX + 'px', top: posTipY + 'px' }"
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-  import { ref, onMounted, onBeforeUnmount } from 'vue';
+  import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
   import Konva from 'konva';
   import { ElMessage } from 'element-plus';
+  import OptBar from '../components/CameraOptBar.vue';
   import { useGlobSetting } from '@/hooks/setting';
+  import DefaultTip from '../components/DefaultTip.vue';
   import urlJoin from 'url-join';
   import cameraImgSrc from '@/assets/camera/cameraImg.png';
+  // import cameraImg from '@/assets/camera/cameraImg.png';
   import favoritesImgSrc from '@/assets/camera/favorites.png';
+  import { TipPositionEnum } from '../type';
+  // import { nextTick } from 'process';
+  // import { watch } from 'fs';
 
   const props = defineProps<{
     bgImgUrl?: string;
@@ -33,28 +60,59 @@
 
   const globSetting = useGlobSetting();
 
-  interface caremasType {
+  interface caremasImgType {
+    width: number;
+    height: number;
+    image: HTMLImageElement;
+    name: string;
+  }
+
+  interface caremasGroupType {
     id?: string;
+    config: caremasImgType;
+    isDefault?: boolean;
   }
 
-  const stageConfig = {
+  // const stageWidth = ref<number>(800);
+
+  // const stageHeight = ref<number>(600);
+
+  const stageConfig = ref({
     width: 800,
     height: 600,
-  };
+    fill: 'red',
+    // background: red,
+  });
 
   const cameraConfig = {};
 
   const bgImg = new Image();
   const cameraImg = new Image();
   const favoritesImg = new Image();
-  // bgImg.src = '';
-  cameraImg.src = cameraImgSrc;
   favoritesImg.src = favoritesImgSrc;
 
+  //右键点击是否出现
+  const defaultShow = ref<boolean>(false);
+  const posX = ref<number>();
+  const posY = ref<number>();
+  const posTipX = ref<number>();
+  const posTipY = ref<number>();
+  const pos = ref(TipPositionEnum.TOP);
+  //可能的默认相机
+  const caremaIdMay = ref('');
+  const lastClickedGroupId = ref<string | null>(null);
+
   const bgImgUrl = ref('');
-  const cameras = ref<caremasType[]>([]);
+  const cameras = ref<caremasGroupType[]>([]);
+  //默认相机id
   const defaultCameraId = ref('');
   const defaultIconVisible = ref(false);
+  const tipShow = ref(false);
+
+  //标签
+  const layer = ref();
+  const transformer = ref();
+  const defaultIcon = ref();
 
   const bgConfig = ref({
     x: 0,
@@ -63,31 +121,152 @@
     width: bgImg.width,
     height: bgImg.height,
     image: bgImg,
+    name: 'bgImg',
+    backgroundSize: 'cover',
+  });
+
+  // watch(
+  //   () => props.bgImgUrl,
+  //   (newValue) => {
+  //     console.log('22', newValue);
+  //     const stage = transformer.value.getNode().getStage();
+  //     const bg = stage.findOne('#bgImg');
+  //     // attrs.height;
+  //     console.log('bg', bg);
+  //     nextTick(() => {
+  //       console.log('height', bg.attrs.height);
+  //       console.log('width', bg.attrs.width);
+  //     });
+  //   },
+  //   // { immediate: true },
+  // );
+  const resizeContainer = (width, height) => {
+    // const newWidth = width > initWidth ? width : initWidth;
+    // const newHeight = height > initHeight ? height : initHeight;
+    // stage?.width(newWidth);
+    // stage?.height(newHeight);
+    // console.log('width', width);
+    // console.log('height', height);
+    // stageWidth.value = width;
+    // stageHeight.value = height;
+    stageConfig.value.width = width;
+    stageConfig.value.height = height;
+  };
+
+  const groupConfig = ref({
+    x: 50,
+    y: 50,
+    draggable: true,
+    name: 'group',
   });
 
-  const defaultIconConfig = {
+  const defaultIconConfig = ref({
     x: 18,
     y: -16,
     width: 16,
     height: 16,
-    visible: defaultIconVisible.value,
+    id: 'defaultIcon',
+    image: favoritesImg,
+    // visible: defaultIconVisible.value,
+  });
+
+  // const setDefaultCamera = () => {
+  //   defaultShow.value = false;
+  // };
+
+  const handleMouseOver = (camera, e) => {
+    document.oncontextmenu = () => {
+      return false;
+    };
+
+    const group = e.target.parent;
+    if (group.id() === defaultCameraId.value) {
+      tipShow.value = true;
+      const stage = transformer.value.getNode().getStage();
+      const defaultNode = stage.findOne('#defaultIcon');
+      const tipPosition = defaultNode.absolutePosition();
+
+      posTipX.value = Number(tipPosition?.x.toFixed(2)) || 0;
+      posTipY.value = Number(tipPosition?.y.toFixed(2)) || 0;
+      const angle = group.rotation() >= 0 ? group.rotation() : group.rotation() + 360;
+      if (angle >= 30) {
+        if (angle <= 150) {
+          pos.value = TipPositionEnum.RIGHT;
+          posTipX.value += 26;
+          posTipY.value -= 17;
+        } else if (angle <= 210) {
+          pos.value = TipPositionEnum.BOTTOM;
+          posTipY.value += 26;
+          posTipX.value -= 50;
+        } else {
+          pos.value = TipPositionEnum.LEFT;
+          posTipX.value -= 121;
+          posTipY.value -= 25;
+        }
+      } else {
+        posTipY.value -= 61;
+        posTipX.value -= 43;
+      }
+      // createDefaultTip(x, y, pos);
+    }
+  };
+  const handleMouseLeave = (camera, e) => {
+    document.oncontextmenu = () => {
+      return true;
+    };
+    tipShow.value = false;
+  };
+
+  const handleDragStart = (camera, e) => {
+    // document.oncontextmenu = () => {
+    //   return true;
+    // };
+    tipShow.value = false;
   };
 
   const handleStageClick = (e: any) => {
-    console.log('e', e);
+    console.log('e', e.target);
+    console.log('e', e.target.parent);
+    defaultShow.value = false;
+    // const clickedNode = e.target;
+    document.oncontextmenu = () => {
+      return false;
+    };
+    const parent = e.target.parent;
+    if (parent.hasName('group')) {
+      lastClickedGroupId.value = parent.id();
+      console.log('group');
+    } else {
+      console.log('stage');
+      //取消transformer选择
+      const transformerNode = transformer.value.getNode();
+      transformerNode.nodes([]);
+    }
 
-    // if (e.target === stage) {
-    //   stage.find('Transformer').destroy();
-    //   layer.batchDraw();
-    // }
+    // 判断是否为右键点击
+    if (e.evt.button === 2) {
+      console.log('右击');
+      console.log(parent.id());
+      // groupSelect =
+      caremaIdMay.value = parent.id();
+      posX.value = e.evt.offsetX + 20;
+      posY.value = e.evt.offsetY;
+      defaultShow.value = defaultCameraId.value !== parent.id();
+      console.log(defaultShow.value);
+    }
   };
 
-  const handleCameraDblClick = (camera: any) => {
-    const index = cameras.value.findIndex((c) => c.id === camera.id);
-    if (index === -1) return;
-    const updatedCameras = [...cameras.value];
-    updatedCameras.splice(index, 1);
-    cameras.value = updatedCameras;
+  const handleCameraClick = (camera: any, event) => {
+    tipShow.value = false;
+    const transformerNode = transformer.value.getNode();
+    const stage = transformerNode.getStage();
+    const cameraNode = stage.findOne('#' + camera.id);
+    console.log('cameraNode', cameraNode);
+
+    // 将变换器附加到点击的相机
+    transformerNode.nodes([cameraNode]);
+    transformerNode.moveToTop();
+    // camera.transformer = transformerNode;
   };
 
   const deleteCamera = () => {
@@ -98,22 +277,50 @@
     cameras.value = updatedCameras;
   };
 
-  const addCamera = (x: number, y: number) => {
-    const id = Math.random().toString(36).substr(2, 9);
-    cameras.value.push({ id, x, y, rotation: 0, scaleX: 1, scaleY: 1 });
+  const addCamera = (id: string) => {
+    const existingCamera = cameras.value.find((camera) => camera.id === id);
+    if (existingCamera) return;
+
+    const camImg = new Image();
+    camImg.src = cameraImgSrc;
+    const config = {
+      width: 52,
+      height: 37,
+      image: camImg,
+      name: 'image',
+    };
+    const cameraDetail = {
+      id,
+      config,
+      isDefault: false,
+    };
+    cameras.value.push(cameraDetail);
+    //可以加入判断,当只有一个相机时,自动设置默认相机
+    if (cameras.value.length === 1) {
+      cameras.value[0].isDefault = true;
+      defaultCameraId.value = id;
+    }
   };
 
-  const setDefaultCamera = (camera: any) => {
-    defaultCameraId.value = camera.id;
-    defaultIconVisible.value = true;
+  const setDefaultCamera = () => {
+    //选中的相机id号
+    defaultCameraId.value = caremaIdMay.value;
+    cameras.value.forEach((item) => {
+      if (item.id === defaultCameraId.value) {
+        item.isDefault = true;
+      } else {
+        item.isDefault = false;
+      }
+    });
+    defaultShow.value = false;
   };
 
   const handleCameraDragEnd = (camera: any, e: any) => {
-    if (camera.id === defaultCameraId.value) {
-      const tr = layer.findOne(`#tr_${camera.id}`);
-      tr.nodes([e.target]);
-      layer.batchDraw();
-    }
+    // if (camera.id === defaultCameraId.value) {
+    //   const tr = layer.findOne(`#tr_${camera.id}`);
+    //   tr.nodes([e.target]);
+    //   layer.batchDraw();
+    // }
   };
 
   const handleFileChange = (e: any) => {
@@ -122,22 +329,28 @@
     const reader = new FileReader();
     reader.onload = (event) => {
       bgImgUrl.value = event.target?.result;
-      addBg();
+      // addBg();
     };
     reader.readAsDataURL(file);
   };
 
-  const addBg = () => {
-    // bgImgUrl.value = bgImg;
-    bgImgUrl.value = urlJoin(globSetting.imgUrl!, props.bgImgUrl!);
-    console.log('bgImgUrl.value22 ', bgImgUrl.value);
-    // console.log('imgUrl', imgUrl);
+  const addBg = (imgBg) => {
+    bgImgUrl.value = urlJoin(globSetting.imgUrl!, imgBg) as string;
+
     bgImg.src = bgImgUrl.value;
-    // const img = new Image();
+    console.log('bgmin', bgImg);
+
     bgImg.onload = () => {
+      // const bgNode = layer.value?.findOne('#bgImg') as any;
       bgConfig.value.width = bgImg.width;
       bgConfig.value.height = bgImg.height;
-      // bgImg.src = bgImgUrl.value;
+      // stageConfig.value.width = bgImg.width;
+      // stageConfig.value.height = bgImg.height;
+      resizeContainer(bgImg.width, bgImg.height);
+      console.log('bgImg.width', bgImg.width);
+      console.log('bgImg.height', bgImg.height);
+      console.log('stageConfig', stageConfig.value);
+      console.log('bgConfig', bgConfig.value);
     };
   };
 
@@ -157,13 +370,28 @@
   };
   const handleKeyDown = () => {};
 
+  //重置
+  const resetMap = () => {
+    bgImgUrl.value = '';
+    // defaultIcon?.moveTo(copyLayer);
+    // layer?.clear();
+    // layer?.removeChildren();
+    // defaultIcon?.moveTo(layer);
+    // addedCameras.value = [];
+    // activeGroup.value = null;
+    // defaultCameraId.value = '';
+    // isTransform = false;
+    // bgImgUrl.value = '';
+  };
+
   /** 导入布局json */
   const createMap = (layout) => {
-    // const layout = JSON.parse(json);
-    bgImgUrl.value = layout.bgInfo.bgImg;
-    console.log('bgImgUrl.value11 ', bgImgUrl.value);
+    // bgImgUrl.value = layout.bgInfo.bgImg;
+
+    // console.log('bgImgUrl.value11 ', bgImgUrl.value);
+    console.log('layout.bgInfo.bgImg', layout.bgInfo.bgImg);
 
-    addBg();
+    addBg(layout.bgInfo.bgImg);
     // layout.cameraList.forEach((camera) => {
     //   const group = new Konva.Group({
     //     x: camera.x,
@@ -201,7 +429,7 @@
     // });
   };
 
-  defineExpose({ addBg, createMap });
+  defineExpose({ addBg, createMap, resetMap, addCamera, resizeContainer });
 
   onMounted(() => {
     // Add initial cameras, if needed
@@ -213,19 +441,29 @@
 </script>
 
 <style scoped>
-  #drawContainer {
+  .drawContainer {
     position: relative;
   }
-
-  input[type='file'] {
-    position: absolute;
-    top: 10px;
-    left: 10px;
+  .opt-container {
+    width: 160px;
+    padding: 10px;
+    border-radius: 5px;
+    background-color: #ffffff;
+    box-shadow: 5px 5px 5px #a3a5a5;
   }
+  .opt-item {
+    height: 30px;
+    font-size: 14px;
+    color: #404040;
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    padding-left: 8px;
+    border-radius: 3px;
+    cursor: pointer;
 
-  button {
-    position: absolute;
-    top: 40px;
-    left: 10px;
+    &:hover {
+      background-color: #f1f2f5;
+    }
   }
 </style>

+ 17 - 5
src/views/map-config/mini-map/MiniMapConfig.vue

@@ -83,8 +83,8 @@
         </el-scrollbar>
       </div>
       <!-- <div ref="drawContainer" id="drawContainer" class="draw-container"> -->
-      <div class="draw-container">
-        <KonvaMap ref="konvaMap" :bg-img-url="imgUrlBg" class="draw-container" />
+      <div ref="drawContainer" class="draw-container">
+        <KonvaMap ref="konvaMap" :bg-img-url="imgUrlBg" />
         <div id="editContainer" v-moveable:1></div>
         <el-upload
           v-if="!hasBg"
@@ -154,9 +154,7 @@
     //自己的
     imgUrlBg.value = e.data;
     console.log('imgUrlBg.value1', imgUrlBg.value);
-    nextTick(() => {
-      konvaMap.value.addBg();
-    });
+    konvaMap.value.addBg(imgUrlBg.value);
     // konvaMap.value.addBg();
     // mapEditor.addBg();
     hasBg.value = true;
@@ -164,6 +162,7 @@
 
   const changeShop = (code: string) => {
     mapEditor.resetMap();
+    konvaMap.value.resetMap();
     getShopContent(code);
     hasBg.value = false;
   };
@@ -176,6 +175,10 @@
       }
       hasBg.value = true;
       konvaMap.value.createMap(res);
+      imgUrlBg.value = res.bgInfo.bgImg;
+      // console.log();
+
+      console.log('res.bgInfo.bgImg', res.bgInfo.bgImg);
       mapEditor.createMap(res);
     });
   };
@@ -193,6 +196,13 @@
     //   width: drawContainer.value!.clientWidth,
     //   height: drawContainer.value!.clientHeight,
     // });
+    // console.log('drawContainer.value!.clientWidth', drawContainer.value!.clientWidth);
+    // console.log('drawContainer.value!.clientHeight', drawContainer.value!.clientHeight);
+
+    konvaMap.value.resizeContainer(
+      drawContainer.value!.clientWidth,
+      drawContainer.value!.clientHeight,
+    );
     if (selectedShopCode.value) {
       getShopContent(selectedShopCode.value);
     }
@@ -213,7 +223,9 @@
       });
       return;
     }
+    konvaMap.value.addCamera(cameraId);
     mapEditor.addCamera(cameraId);
+    // konvaMap.value.addCamera(cameraId);
   };
 
   const handleSave = () => {

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

@@ -80,8 +80,6 @@ export function useMapEditor() {
   /** 添加背景 */
   const addBg = () => {
     const imgUrl = urlJoin(globSetting.imgUrl!, bgImgUrl.value);
-    console.log('imgUrl', imgUrl);
-
     const bgNode = layer?.find('#bgImg')[0] as Konva.Image;
     const bgImg = new Image();
     bgImg.onload = () => {