Procházet zdrojové kódy

获取预置位的列表

louhangfei před 2 roky
rodič
revize
ed3f4344f4

+ 128 - 0
src/api/camera/camera-preview.ts

@@ -115,3 +115,131 @@ export const deleteCameraAlgoApi = (params: { cameraId: number; algoId: number }
     method: 'delete',
   });
 };
+
+export interface GetFenceParams {
+  algoId: number;
+  cameraId: number;
+  presetId: number;
+}
+
+/** 查询电子围栏 */
+export const getFenceApi = (
+  params: GetFenceParams,
+): Promise<{ id: number; electronicFencePolygon: string }> => {
+  return http.request({
+    url: '/cameraPreview/getFence',
+    method: 'GET',
+    params,
+  });
+};
+
+interface UpdateFenceParams {
+  algoId: number;
+  cameraId: number;
+  electronicFencePolygon: number;
+  id: number;
+  presetId: number;
+}
+/** 编辑电子围栏 */
+export const editFenceApi = (data: UpdateFenceParams) => {
+  return http.request({
+    url: '/cameraPreview/updateFence',
+    method: 'put',
+    data,
+  });
+};
+
+/** 删除电子围栏 */
+export const deleteFenceApi = (cameraAlgoPresetRelId: number) => {
+  return http.request({
+    url: `/cameraPreview/deleteFence?cameraAlgoPresetRelId=${cameraAlgoPresetRelId}`,
+    method: 'delete',
+  });
+};
+
+interface CreatePresetParam {
+  presetName: string;
+  cameraCode: string;
+}
+
+/** 创建预置位 */
+export const createPresetApi = (data: CreatePresetParam) => {
+  return http.request({
+    url: `/camera/createPreset`,
+    method: 'post',
+    data,
+  });
+};
+
+interface UpdatePresetNameParam {
+  presetToken: string;
+  presetName: string;
+  cameraCode: string;
+}
+/** 修改预置位名称 */
+export const changePresetNameApi = (data: UpdatePresetNameParam) => {
+  return http.request({
+    url: `/camera/changePresetName`,
+    method: 'post',
+    data,
+  });
+};
+
+/** 删除预置位 */
+export const deletePresetApi = (data: { presetToken: string; cameraCode: string }) => {
+  return http.request({
+    url: `/camera/deletePreset`,
+    method: 'post',
+    data,
+  });
+};
+
+interface PresetDetailItem {
+  name: string;
+  token: string;
+  ptzposition: {
+    panTilt: {
+      x: number;
+      y: number;
+      space: null;
+    };
+    zoom: {
+      x: number;
+      space: null;
+    };
+  };
+}
+
+/** 获取预置位列表 */
+export const getPresetListApi = (cameraId: number) => {
+  return http.request<PresetDetailItem[]>({
+    url: `/camera/getPresets`,
+    method: 'get',
+    params: { cameraCode: cameraId },
+  });
+};
+
+/** 跳转到对应的预置位 */
+export const goToPresetApi = (data: { presetToken: string; cameraCode: string }) => {
+  return http.request({
+    url: `/camera/gotoPreset`,
+    method: 'post',
+    data,
+  });
+};
+
+interface CameraMoveParam {
+  cameraCode: string;
+  x: number;
+  zoom: number;
+  y: number;
+}
+
+/** 移动相机 */
+export const cameraMoveApi = (data: CameraMoveParam) => {
+  return http.request({
+    url: `/camera/move`,
+    method: 'post',
+    data,
+  });
+};

+ 32 - 0
src/views/cameras/preview/components/AddPresetModal/AddPresetModal.vue

@@ -0,0 +1,32 @@
+<template>
+  <ElDialog title="添加预置位" :model-value="true" @close="emits('close')" width="500px">
+    <template #footer>
+      <el-button @click="emits('close')">取消</el-button>
+      <el-button type="primary" @click="handleSubmit" :loading="loading">确定</el-button>
+    </template>
+    <ElInput type="textarea" autosize v-model="presetName" />
+  </ElDialog>
+</template>
+<script lang="ts" setup>
+  import { createPresetApi } from '@/api/camera/camera-preview';
+  import { ElDialog, ElInput, ElMessage } from 'element-plus';
+  import { ref } from 'vue';
+  const presetName = ref('');
+  const loading = ref(false);
+  const emits = defineEmits<{ (e: 'close'): unknown; (e: 'ok'): unknown }>();
+
+  const handleSubmit = () => {
+    loading.value = true;
+    createPresetApi({ presetName: presetName.value, cameraCode: 'dev_01_01' })
+      .then(() => {
+        ElMessage.success('预置位创建成功');
+        emits('ok');
+      })
+      .finally(() => {
+        loading.value = false;
+      });
+  };
+
+  /** 先写死为dev_01_01 */
+</script>
+<style scoped></style>

+ 9 - 1
src/views/cameras/preview/components/AlgorithmsSetting/AlgorithmsSetting.vue

@@ -30,8 +30,10 @@
   import { useRouteQuery } from '@vueuse/router';
   import { ElMessage } from 'element-plus';
   import AlgoTag from './AlgoTag.vue';
+  import useFenceStore from '../../store/useFenceStore';
 
   const cameraAlgoStore = useCameraAlgoStore();
+  const fenceStore = useFenceStore();
 
   const { getCameraAlgoList, getAllAlgoList } = cameraAlgoStore;
   const { cameraAlgoList, selectedAlgoId } = storeToRefs(cameraAlgoStore);
@@ -43,7 +45,12 @@
   });
 
   const handleSelectAlgo = (id: number) => {
-    selectedAlgoId.value = id;
+    if (id !== selectedAlgoId.value) {
+      selectedAlgoId.value = id;
+      fenceStore.getFence({ algoId: id, cameraId: cameraId.value, presetId: 1 }).then((res) => {
+        console.log('fence detail', res);
+      });
+    }
   };
 
   const handleSubmit = (param) => {
@@ -83,3 +90,4 @@
     margin-right: 15px;
   }
 </style>
+../../store/useFenceStore

+ 0 - 0
src/views/cameras/preview/components/CameraDirectionControl/CameraDirectionControl.vue


+ 55 - 1
src/views/cameras/preview/components/CameraViewSetting/CameraViewSetting.vue

@@ -13,23 +13,45 @@
 
     <div class="cameraViewSettingWrapper">
       <FenceEditor ref="fenceEditorRef" />
+
       <div class="cameraVideo"><CameraLiveVideo /></div>
     </div>
+    <div>
+      <CameraDirectionControl />
+      <ElButton type="primary" @click="handleAddPreset">添加预置位</ElButton>
+      <AddPresetModal v-if="addPresetModalVisible" @close="handleClose" @ok="handleClose" />
+    </div>
   </div>
 </template>
 <script lang="ts" setup>
-  import { ref } from 'vue';
+  import { ref, watch } from 'vue';
   import FenceToolbar from '../FenceToolbar/FenceToolbar.vue';
   import FenceEditor from '../FenceEditor/FenceEditor.vue';
   import CameraLiveVideo from '../CameraLiveVideo/CameraLiveVideo.vue';
   import ViewWindowSetting from '../ViewWindowSetting/ViewWindowSetting.vue';
   import PresetSelect from '../PresetSelect/PresetSelect.vue';
   import { ViewType } from '../ViewWindowSetting/types';
+  import useFenceStore from '../../store/useFenceStore';
+  import AddPresetModal from '../AddPresetModal/AddPresetModal.vue';
+  import { createPresetApi } from '@/api/camera/camera-preview';
+  import { ElMessage } from 'element-plus';
+  import { onMounted } from 'vue';
+  import usePresetListStore from '../../store/usePresetListStore';
 
   const fenceEditorRef = ref<typeof FenceEditor | null>(null);
 
+  const fenceStore = useFenceStore();
+
+  const { data, getPresetList } = usePresetListStore();
+
   const viewType = ref<ViewType>(ViewType.window1);
 
+  const addPresetModalVisible = ref(false);
+
+  const handleClose = () => {
+    addPresetModalVisible.value = false;
+  };
+
   const handleRemove = () => {
     console.log('handleRemove');
     fenceEditorRef.value?.remove();
@@ -60,6 +82,38 @@
   const handleUpdatePreset = (val: string) => {
     console.log('val', val);
   };
+  watch(
+    () => fenceStore.serverFencePoints,
+    (newVal) => {
+      console.log('newVal', newVal);
+      if (!newVal) {
+        fenceEditorRef.value?.clear();
+        return;
+      }
+      // const rawLinePoints = newVal[0];
+
+      const rawLinePoints = newVal.map((x) => {
+        const points: number[] = [];
+        x.forEach((line) => {
+          points.push(line[0], line[1]);
+        });
+        return points;
+      });
+      if (!rawLinePoints) return;
+      /** 先清空原有的 */
+      fenceEditorRef.value?.clear();
+      fenceEditorRef.value?.createLines(rawLinePoints);
+    },
+    { immediate: true },
+  );
+
+  const handleAddPreset = () => {
+    addPresetModalVisible.value = true;
+  };
+
+  onMounted(() => {
+    getPresetList('dev_01_01');
+  });
 </script>
 <style scoped>
   .cameraViewSettingWrapper {

+ 15 - 2
src/views/cameras/preview/components/FenceEditor/FenceEditor.vue

@@ -605,11 +605,18 @@
       drawCircle(x, y, group, points);
     }
     // group.setAttrs({ x: groupData.attrs.x, y: groupData.attrs.y })
-
+    console.log('group', group);
     layer?.add(group);
     layer?.draw();
   }
 
+  /** 画多条线 */
+  function createLines(lines: Points[]) {
+    lines.forEach((line) => {
+      createGroupByPoints(line);
+    });
+  }
+
   const removeCurrent = () => {
     if (currentDel) {
       currentDel.destroy();
@@ -661,14 +668,20 @@
     isEdit = true;
   };
 
+  /** 清空所有元素 */
+  const clear = () => {
+    layer?.removeChildren();
+  };
+
   defineExpose({
     remove: removeCurrent,
     toObject,
     toRawObject,
-    createGroupByPoints,
+    createLines,
     initStageByJSON,
     exitEditMode,
     setEditMode,
+    clear,
   });
 </script>
 

+ 4 - 2
src/views/cameras/preview/components/FenceToolbar/FenceToolbar.vue

@@ -15,7 +15,7 @@
   </div>
 </template>
 <script setup lang="ts">
-  import { ref, defineEmits } from 'vue';
+  import { ref, defineEmits, watch } from 'vue';
   import { ElButton, ElSwitch } from 'element-plus';
   import PolygonEditor from '../FenceEditor/FenceEditor.vue';
   import { ServerLines } from '../FenceEditor/constants';
@@ -24,12 +24,14 @@
   import deleteIcon from '@/assets/images/camera/delete.png';
   import mousePointerIcon from '@/assets/images/camera/mousePointer.png';
   import editIcon from '@/assets/images/camera/pen.png';
+  import useFenceStore from '../../store/useFenceStore';
 
   const isFenceOn = ref(true);
   const props = defineProps<{ isEdit: boolean }>();
 
   const polygonEditorRef = ref<typeof PolygonEditor | null>(null);
 
+  const fenceStore = useFenceStore();
   const emits = defineEmits<{
     (e: 'toggleEditable', editState: boolean): unknown;
     (e: 'remove'): unknown;
@@ -61,7 +63,7 @@
     });
     console.log('points', points);
 
-    polygonEditorRef.value?.createGroupByPoints(points);
+    polygonEditorRef.value?.createLines(points);
   };
 
   const toggleEdit = () => {

+ 14 - 9
src/views/cameras/preview/components/PresetSelect/PresetSelect.vue

@@ -3,26 +3,31 @@
     <div style="margin-right: 10px">预置位</div>
     <div
       ><ElSelect
-        :model-value="props.modelValue"
+        v-model="currentPresetToken"
         size="small"
         @change="emits('update:modelValue', $event)"
       >
         <ElOption
           v-for="item in presetOptions"
-          :key="item.value"
-          :label="item.label"
-          :value="item.value"
+          :key="item.token"
+          :label="item.name"
+          :value="item.token"
         /> </ElSelect
     ></div>
   </div>
 </template>
 <script lang="ts" setup>
-  import { ref } from 'vue';
   import { ElSelect, ElOption } from 'element-plus';
-  const presetOptions = ref([
-    { label: '预置位1', value: 'p1' },
-    { label: '预置位2', value: 'p2' },
-  ]);
+  import usePresetListStore from '../../store/usePresetListStore';
+  import { storeToRefs } from 'pinia';
+  // const presetOptions = ref([
+  //   { label: '预置位1', value: 'p1' },
+  //   { label: '预置位2', value: 'p2' },
+  // ]);
+
+  const presetListStore = usePresetListStore();
+
+  const { data: presetOptions, currentPresetToken } = storeToRefs(presetListStore);
 
   const props = defineProps<{ modelValue: string }>();
   const emits = defineEmits<{ (e: 'update:modelValue', data: string): unknown }>();

+ 48 - 0
src/views/cameras/preview/store/useFenceStore.ts

@@ -0,0 +1,48 @@
+import { GetFenceParams, getFenceApi } from '@/api/camera/camera-preview';
+import { defineStore } from 'pinia';
+import { ref } from 'vue';
+import { ServerLines } from '../components/FenceEditor/constants';
+
+/** 当前电子围栏的store */
+export const useFenceStore = defineStore('electronicFencePolygonStore', () => {
+  /** 后端返回的电子围栏点 */
+  const serverFencePoints = ref<ServerLines>([]);
+  /** 当前编辑的电子围栏的点 */
+  const currentFencePoints = ref([]);
+  const currentFenceId = ref<number>();
+
+  /** 获取电子围栏 */
+  const getFence = (param: GetFenceParams) => {
+    return new Promise((resolve) => {
+      setTimeout(() => {
+        const res = {
+          id: 2,
+          electronicFencePolygon:
+            Math.random() > 0.5
+              ? ``
+              : `[[[150.9196038878118,103.42855053676564],[350.91958691002293,54.42855423815479],[464.91957723268325,211.42854237860183],[222.9195977758078,225.42854132106206],[60.91961152781679,175.42854509798977]],[[325.9195890322465,259.42853875275125],[534.9195712904572,249.42853950813677],[624.9195636504521,362.42853097228016],[509.91957341268073,380.4285296125862],[309.91959039046964,345.4285322564356]]]`,
+        };
+        currentFenceId.value = res.id;
+        const points = res.electronicFencePolygon
+          ? (JSON.parse(res.electronicFencePolygon) as [])
+          : [];
+        currentFencePoints.value = points;
+        serverFencePoints.value = points;
+        resolve();
+      }, 200);
+    });
+
+    // return getFenceApi(param).then((res) => {
+    //   currentFenceId.value = res.id;
+    //   const points = res.electronicFencePolygon
+    //     ? (JSON.parse(res.electronicFencePolygon) as [])
+    //     : [];
+    //   currentFencePoints.value = points;
+    //   serverFencePoints.value = points;
+    // });
+  };
+
+  return { serverFencePoints, currentFencePoints, currentFenceId, getFence };
+});
+
+export default useFenceStore;

+ 22 - 0
src/views/cameras/preview/store/usePresetListStore.ts

@@ -0,0 +1,22 @@
+import { GetFenceParams, getFenceApi, getPresetListApi } from '@/api/camera/camera-preview';
+import { defineStore } from 'pinia';
+import { ref } from 'vue';
+import { ServerLines } from '../components/FenceEditor/constants';
+import { useRequest } from 'vue-hooks-plus';
+
+/** 当前电子围栏的store */
+export const usePresetListStore = defineStore('presetListStore', () => {
+  /** 当前选中的预置位 */
+  const currentPresetToken = ref('');
+
+  const { data, loading, runAsync } = useRequest(
+    (cameraId: number) => {
+      return getPresetListApi(cameraId);
+    },
+    { manual: true },
+  );
+
+  return { data, currentPresetToken, getPresetList: runAsync };
+});
+
+export default usePresetListStore;