From aaff187cbf5bbdbf0a5e4e6a5b3ee44980889454 Mon Sep 17 00:00:00 2001
From: fajiao <1519100073@qq.com>
Date: Thu, 27 Oct 2022 10:02:43 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E8=B0=83=E7=94=A8?=
 =?UTF-8?q?=E5=90=8E=E7=AB=AF=EF=BC=8C=E5=AE=9E=E7=8E=B0=E6=A0=87=E7=AD=BE?=
 =?UTF-8?q?=E8=BF=BD=E8=B8=AA=E5=B1=95=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
 Frontend/package.json                         |   3 +
 Frontend/src/api/cameraBase/cameraApi.ts      |   7 +-
 .../{cameraGroupApi.ts => markGroupApi.ts}    |   7 +-
 .../{cameraLabelApi.ts => markLabelApi.ts}    |  22 +-
 Frontend/src/api/cameraMark/markSearchApi.ts  |  25 ++-
 Frontend/src/api/index.ts                     |   1 +
 Frontend/src/api/onvif/onvif.ts               |   0
 .../src/api/webrtcStreamer/webrtcStreamer.ts  |   0
 Frontend/src/utils/axios.ts                   |   4 +-
 Frontend/src/views/page/cameraCenter.vue      | 211 +++++++++++++++---
 10 files changed, 223 insertions(+), 57 deletions(-)
 rename Frontend/src/api/cameraMark/{cameraGroupApi.ts => markGroupApi.ts} (87%)
 rename Frontend/src/api/cameraMark/{cameraLabelApi.ts => markLabelApi.ts} (55%)
 create mode 100644 Frontend/src/api/onvif/onvif.ts
 create mode 100644 Frontend/src/api/webrtcStreamer/webrtcStreamer.ts
diff --git a/Frontend/package.json b/Frontend/package.json
index 1aeb401..69b0110 100644
--- a/Frontend/package.json
+++ b/Frontend/package.json
@@ -9,9 +9,12 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@types/qs": "^6.9.7",
     "ant-design-vue": "^3.2.13",
     "axios": "^1.1.3",
+    "less": "^4.1.3",
     "pinia": "^2.0.23",
+    "qs": "^6.11.0",
     "vue": "^3.2.37",
     "vue-router": "^4.1.5"
   },
diff --git a/Frontend/src/api/cameraBase/cameraApi.ts b/Frontend/src/api/cameraBase/cameraApi.ts
index 4aebedd..069dc87 100644
--- a/Frontend/src/api/cameraBase/cameraApi.ts
+++ b/Frontend/src/api/cameraBase/cameraApi.ts
@@ -1,5 +1,6 @@
 import {axios} from '@/utils/axios';
 import {apiUrl} from "@/api";
+import qs from "qs";
 
 enum Api {
     Add = '/cbCamera/add',
@@ -12,11 +13,11 @@ enum Api {
 
 const CisApiUrl = apiUrl.CisApiUrl;
 
-export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, params)
+export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, qs.stringify(params))
 
-export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, params)
+export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, qs.stringify(params))
 
-export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, params)
+export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, qs.stringify(params))
 
 export const Get = (params?: any) => axios.get(CisApiUrl + Api.Get, {params: params})
 
diff --git a/Frontend/src/api/cameraMark/cameraGroupApi.ts b/Frontend/src/api/cameraMark/markGroupApi.ts
similarity index 87%
rename from Frontend/src/api/cameraMark/cameraGroupApi.ts
rename to Frontend/src/api/cameraMark/markGroupApi.ts
index 414e6f0..d83d409 100644
--- a/Frontend/src/api/cameraMark/cameraGroupApi.ts
+++ b/Frontend/src/api/cameraMark/markGroupApi.ts
@@ -1,5 +1,6 @@
 import {axios} from '@/utils/axios';
 import {apiUrl} from "@/api";
+import qs from "qs";
 
 enum Api {
     Add = '/cmMarkGroup/add',
@@ -12,11 +13,11 @@ enum Api {
 
 const CisApiUrl = apiUrl.CisApiUrl;
 
-export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, params)
+export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, qs.stringify(params))
 
-export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, params)
+export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, qs.stringify(params))
 
-export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, params)
+export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, qs.stringify(params))
 
 export const Get = (params?: any) => axios.get(CisApiUrl + Api.Get, {params: params})
 
diff --git a/Frontend/src/api/cameraMark/cameraLabelApi.ts b/Frontend/src/api/cameraMark/markLabelApi.ts
similarity index 55%
rename from Frontend/src/api/cameraMark/cameraLabelApi.ts
rename to Frontend/src/api/cameraMark/markLabelApi.ts
index 414e6f0..c9fd79d 100644
--- a/Frontend/src/api/cameraMark/cameraLabelApi.ts
+++ b/Frontend/src/api/cameraMark/markLabelApi.ts
@@ -1,22 +1,26 @@
 import {axios} from '@/utils/axios';
 import {apiUrl} from "@/api";
+import qs from 'qs';
 
 enum Api {
-    Add = '/cmMarkGroup/add',
-    Update = '/cmMarkGroup/update',
-    Delete = '/cmMarkGroup/delete',
-    Get = '/cmMarkGroup/get',
-    GetList = '/cmMarkGroup/getList',
-    GetPageList = '/cmMarkGroup/getPageList',
+    Add = '/cmMarkLabel/add',
+    AddReturnId = '/cmMarkLabel/addReturnId',
+    Update = '/cmMarkLabel/update',
+    Delete = '/cmMarkLabel/delete',
+    Get = '/cmMarkLabel/get',
+    GetList = '/cmMarkLabel/getList',
+    GetPageList = '/cmMarkLabel/getPageList',
 }
 
 const CisApiUrl = apiUrl.CisApiUrl;
 
-export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, params)
+export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, qs.stringify(params))
 
-export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, params)
+export const AddReturnId = (params?: any) => axios.post(CisApiUrl + Api.AddReturnId, qs.stringify(params))
 
-export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, params)
+export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, qs.stringify(params))
+
+export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, qs.stringify(params))
 
 export const Get = (params?: any) => axios.get(CisApiUrl + Api.Get, {params: params})
 
diff --git a/Frontend/src/api/cameraMark/markSearchApi.ts b/Frontend/src/api/cameraMark/markSearchApi.ts
index e2a5d0c..4c22de0 100644
--- a/Frontend/src/api/cameraMark/markSearchApi.ts
+++ b/Frontend/src/api/cameraMark/markSearchApi.ts
@@ -1,22 +1,29 @@
 import {axios} from '@/utils/axios';
 import {apiUrl} from "@/api";
+import qs from 'qs';
 
 enum Api {
-    ActiveCamera = '/markSearch/activeCamera',
-    DeActiveCamera = '/markSearch/deActiveCamera',
-    AddCameraMarkLabel = '/markSearch/addCameraMarkLabel',
-    DeleteCameraMarkLabel = '/markSearch/deleteCameraMarkLabel',
-    GetMarkLabelCalcResultList = '/markSearch/GetMarkLabelCalcResultList',
+    ActivateSearcher = '/markSearch/activateSearcher',
+    DeActiveSearcher = '/markSearch/deActiveSearcher',
+    IsExistSearcher = '/markSearch/isExistSearcher',
+    ActivateMarkLabel = '/markSearch/activateMarkLabel',
+    DeactivateMarkLabel = '/markSearch/deactivateMarkLabel',
+    IsExistMarkLabel = '/markSearch/isExistMarkLabel',
+    GetMarkLabelCalcResultList = '/markSearch/getMarkLabelCalcResultList',
 }
 
 const CisApiUrl = apiUrl.CisApiUrl;
 
-export const ActiveCamera = (params?: any) => axios.post(CisApiUrl + Api.ActiveCamera, params)
+export const ActiveSearcher = (params?: any) => axios.post(CisApiUrl + Api.ActivateSearcher, qs.stringify(params))
 
-export const DeActiveCamera = (params?: any) => axios.post(CisApiUrl + Api.DeActiveCamera, params)
+export const DeActiveSearcher = (params?: any) => axios.post(CisApiUrl + Api.DeActiveSearcher, qs.stringify(params))
 
-export const AddCameraMarkLabel = (params?: any) => axios.post(CisApiUrl + Api.AddCameraMarkLabel, params)
+export const IsExistSearcher = (params?: any) => axios.get(CisApiUrl + Api.IsExistSearcher, {params: params})
 
-export const DeleteCameraMarkLabel = (params?: any) => axios.post(CisApiUrl + Api.DeleteCameraMarkLabel, params)
+export const ActivateMarkLabel = (params?: any) => axios.post(CisApiUrl + Api.ActivateMarkLabel, qs.stringify(params))
+
+export const DeactivateMarkLabel = (params?: any) => axios.post(CisApiUrl + Api.DeactivateMarkLabel, qs.stringify(params))
+
+export const IsExistMarkLabel = (params?: any) => axios.get(CisApiUrl + Api.IsExistMarkLabel, {params: params})
 
 export const GetMarkLabelCalcResultList = (params?: any) => axios.get(CisApiUrl + Api.GetMarkLabelCalcResultList, {params: params})
diff --git a/Frontend/src/api/index.ts b/Frontend/src/api/index.ts
index 216ba89..3b5f431 100644
--- a/Frontend/src/api/index.ts
+++ b/Frontend/src/api/index.ts
@@ -1,5 +1,6 @@
 export const apiUrl = {
     CisApiUrl: 'http://192.168.1.119:5000/api',
     WebRtcUrl: 'http://192.168.1.119:8000',
+    OnvifApiUrl: ''
     // CisApiUrl: 'https://192.168.1.119:5001/api'
 }
diff --git a/Frontend/src/api/onvif/onvif.ts b/Frontend/src/api/onvif/onvif.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Frontend/src/api/webrtcStreamer/webrtcStreamer.ts b/Frontend/src/api/webrtcStreamer/webrtcStreamer.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Frontend/src/utils/axios.ts b/Frontend/src/utils/axios.ts
index 8a918b0..1dbc6b1 100644
--- a/Frontend/src/utils/axios.ts
+++ b/Frontend/src/utils/axios.ts
@@ -4,8 +4,8 @@ let apiBaseUrl = "/api";
 
 const service = axios.create({
     baseURL: apiBaseUrl, // api base_url
-    timeout: 9000 // 请求超时时间
-})
+    timeout: 9000, // 请求超时时间
+});
 
 export {
     service as axios,
diff --git a/Frontend/src/views/page/cameraCenter.vue b/Frontend/src/views/page/cameraCenter.vue
index bbd439f..c700f39 100644
--- a/Frontend/src/views/page/cameraCenter.vue
+++ b/Frontend/src/views/page/cameraCenter.vue
@@ -4,26 +4,35 @@
     
 
       
 
       
 
     
 
-    
+    
 
       
 
     
@@ -35,36 +44,41 @@
 import {defineComponent, ref} from 'vue';
 import type {TreeProps} from 'ant-design-vue';
 import * as cameraApi from '@/api/cameraBase/cameraApi';
+import * as markLabelApi from '@/api/cameraMark/markLabelApi';
+import * as markSearchApi from '@/api/cameraMark/markSearchApi';
 import {apiUrl} from "@/api";
 
 export default defineComponent({
   data() {
     return {
+      player: document.querySelector('#videoPlayer'),
+      canvas: document.querySelector('#videoCanvas'),
+      canvasWidth: 0,
+      canvasHeight: 0,
       curSelectKey: '',
+      treeData: ref([]),
       cameraMap: new Map(),
-      webRtcServer: WebRtcStreamer
+      webRtcServer: WebRtcStreamer,
+      isActiveChoose: false,
     }
   },
-  setup() {
-    let treeData = ref([]);
-    return {
-      treeData,
-    };
-  },
   created() {
     this.$nextTick(() => {
+      this.player = document.querySelector('#videoPlayer');
+      this.canvas = document.querySelector('#videoCanvas');
+
       this.loadTreeData();
       this.loadVideoPlayer();
+      this.loadVideoCanvas();
     });
   },
   methods: {
     loadTreeData() {
-      let that: any = this;
       cameraApi.GetList().then((res) => {
-        let list = res.data.data;
+        let list: Array = res.data.data;
         for (let item of list) {
           this.cameraMap.set(item.id, item);
-          that.treeData.push({title: item.ip, key: item.id});
+          this.treeData!.push({title: item.ip, key: item.id});
         }
       });
     },
@@ -73,43 +87,170 @@ export default defineComponent({
       let key = selectedKeys[0];
       if (this.curSelectKey !== key) {
         this.curSelectKey = key;
-        this.switchCamera(key);
+        // 模拟稳定选中相机功能,避免频繁切换
+        setTimeout(() => {
+          if (this.curSelectKey === key) {
+            this.switchCamera(key);
+          }
+        }, 1000);
       }
     },
     loadVideoPlayer() {
       let elmId = 'videoPlayer';
       let url = apiUrl.WebRtcUrl;
       this.webRtcServer = new WebRtcStreamer(elmId, url);
-      document.querySelector('#videoPlayer').addEventListener('loadmetadata',function (){
-        console.log("============================================================");
-        console.log(this);
-        console.log("============================================================");
+    },
+    loadVideoCanvas() {
+      window.addEventListener('resize', () => {
+        this.changeVideoCanvasSize();
       });
     },
+    changeVideoCanvasSize() {
+      this.canvasWidth = this.player.clientWidth;
+      this.canvasHeight = this.player.clientHeight;
+    },
+    mouseOverVideo() {
+      if (!this.isActiveChoose) return;
+      this.player.classList.add('activeChoose');
+    },
+    mouseOutVideo() {
+      if (!this.isActiveChoose) return;
+      this.player.classList.remove('activeChoose');
+    },
+    mouseDownVideo(e: MouseEvent) {
+      if (!this.isActiveChoose) return;
+      let cameraId = this.cameraMap.get(this.curSelectKey).id;
+      let name = 'markLabel-' + Date.now();
+      let videoWidth = this.player.videoWidth | 1920;
+      let videoHeight = this.player.videoHeight | 1080;
+      let canvasWidth = this.player.clientWidth;
+      let canvasHeight = this.player.clientHeight;
+      let canvasLeft = e.offsetX;
+      let canvasTop = e.offsetY;
+      let canvasLeftRatio = canvasLeft / canvasWidth;
+      let canvasTopRatio = canvasTop / canvasHeight;
+      let entity = {
+        CbCameraId: cameraId,
+        Name: name,
+        VideoWidth: videoWidth,
+        VideoHeight: videoHeight,
+        CanvasLeftRatio: canvasLeftRatio,
+        CanvasTopRatio: canvasTopRatio
+      }
+      console.log(entity);
+      markLabelApi.AddReturnId({
+        'entity': entity
+      }).then((res) => {
+        let markLabelId: number = res.data.data;
+        if (markLabelId <= 0) return;
+        markSearchApi.ActivateMarkLabel({
+          'cameraId': cameraId,
+          'markLabelId': markLabelId
+        }).then((res) => {
+          let ret: boolean = res.data.data;
+        });
+      })
+    },
+    activateChoose() {
+      if (this.curSelectKey.length == 0) return;
+      this.isActiveChoose = true;
+    },
+    deactivateChoose() {
+      if (this.curSelectKey.length == 0) return;
+      this.isActiveChoose = false;
+    },
     switchCamera(cameraId: string) {
       console.log('camera switch.');
-      let cameraObj = this.cameraMap.get(cameraId);
+
       // step1, get camera obj.
-      if (cameraObj == null) {
-        console.log('camera not found.');
+      console.log('get camera obj.');
+      let cameraObj = this.cameraMap.get(cameraId);
+      if (!cameraObj) {
+        console.log('camera obj not found.');
         return;
       }
+      // object to proxy, ?
+      console.log(cameraObj,);
 
       // step2, get camera rtsp url.
+      console.log('get camera rtsp url.');
       let rtspUrl = this.getRtspUrl(cameraObj);
 
       // step3, connect webrtc-steamer.
+      console.log('connect webrtc-steamer.');
       this.webRtcServer.disconnect();
       this.webRtcServer.connect(rtspUrl);
 
+      // step4, active camera searcher.
+      markSearchApi.IsExistSearcher({
+        'cameraId': cameraObj.id
+      }).then((res) => {
+        let flag: boolean = res.data.data;
+        if (!flag) {
+          console.log('not exist searcher.');
+          markSearchApi.ActiveSearcher({
+            'cameraId': cameraObj.id
+          }).then((res) => {
+            let flag: boolean = res.data.data;
+            console.log('activate searcher : ', flag);
+            if (flag) {
+              console.log('load camera labels');
+              this.loadMarkLabelsByLoop(cameraObj);
+            }
+          });
+        } else {
+          console.log('load camera labels');
+          this.loadMarkLabelsByLoop(cameraObj);
+        }
+      })
+
+      // step5, load camera labels.
     },
     getRtspUrl(cameraObj: any): string {
-      return "rtsp://admin:hk123456@192.168.1.65:554/Streaming/Channels/101?transportmode=unicast&profile=Profile_1"
-    }
+      // 模拟 onvif
+      return "rtsp://admin:hk123456@192.168.1.65:554/Streaming/Channels/101?transportmode=unicast&profile=Profile_1";
+    },
+    loadMarkLabelsByLoop(cameraObj: any, ms: number = 1000) {
+      if (this.curSelectKey !== cameraObj.id) {
+        console.log('load camera labels end.');
+        return;
+      }
+      this.loadMarkLabels(cameraObj);
+      setTimeout(() => {
+        this.loadMarkLabelsByLoop(cameraObj, ms);
+      }, ms);
+    },
+    loadMarkLabels(cameraObj: any) {
+      markSearchApi.GetMarkLabelCalcResultList({
+        'cameraId': cameraObj.id
+      }).then((res) => {
+        let list: Array = res.data.data;
+        this.drawMarkLabels(list);
+      });
+    },
+    drawMarkLabels(markLabels: Array) {
+      let ctx = this.canvas.getContext('2d');
+      if (!ctx) return;
+      ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+      for (let markLabel of markLabels) {
+        if (!markLabel.inFlag) continue;
+        let x = Math.round(this.canvasWidth * markLabel.canvasLeftRatio);
+        let y = Math.round(this.canvasHeight * markLabel.canvasTopRatio);
+        x = this.canvasWidth * markLabel.canvasLeftRatio;
+        y = this.canvasHeight * markLabel.canvasTopRatio;
+        console.log(markLabel);
+        ctx.beginPath();
+        ctx.arc(x, y, 5, 0, 2 * Math.PI);
+        ctx.fillStyle = "red";
+        ctx.fill();
+        ctx.closePath();
+      }
+    },
   },
-  beforeDestroy() {
+  beforeUnmount() {
+    console.log('beforeUnmount.');
     // 释放 webRtcServer
-    if (this.webRtcServer === null) return;
+    if (!this.webRtcServer) return;
     this.webRtcServer.disconnect();
     this.webRtcServer = null;
   }
@@ -117,5 +258,13 @@ export default defineComponent({
 
 
 
\ No newline at end of file