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