Kaynağa Gözat

视频组件增加截图功能、bug修复

Hwf 4 ay önce
ebeveyn
işleme
7df55c7593

+ 1 - 4
src/api/PreventionResponsible/index.ts

@@ -1,14 +1,11 @@
 import { AxiosPromise } from 'axios';
-import { UserInfo } from '@/api/system/user/types';
 import request from '@/utils/request';
-import { data } from 'autoprefixer';
 
 //获取责任人类别
 export function getPersonRespon(): AxiosPromise<any> {
   return request({
     url: '/api/ThreeProofingResponsible/type_data/treeData',
-    method: 'get',
-    params: data
+    method: 'get'
   });
 }
 // 首页列表查询

+ 9 - 0
src/api/globalMap/forestDefenseVideo.ts

@@ -0,0 +1,9 @@
+import request from '@/utils/request';
+
+export const getPtzInfo = (params) => {
+  return request({
+    url: '/api/videoResource/hkvideo/get_ptz_info',
+    method: 'get',
+    params: params
+  });
+};

+ 0 - 21
src/api/setting/PreventionResponsible/tree.ts

@@ -1,21 +0,0 @@
-import request from '@/utils/request';
-import { AxiosPromise } from 'axios';
-import { data } from 'autoprefixer';
-
-//获取责任人类别
-export function getPersonRespon(): AxiosPromise<any> {
-  return request({
-    url: '/api/ThreeProofingResponsible/type_data/treeData',
-    method: 'get',
-    params: data
-  });
-}
-
-//提交新建责任人信息
-export function createNewPerson(data) {
-  return request({
-    url: '/api/ThreeProofingResponsible/person/create',
-    method: 'post',
-    data: data
-  });
-}

+ 48 - 23
src/components/HKVideo/hikvision-h5player.vue

@@ -8,6 +8,7 @@
 
 <script setup lang="ts">
 import { reactive, onMounted, onActivated, nextTick, onBeforeUnmount } from 'vue';
+import { parseTime } from '@/utils/ruoyi';
 
 const play = async (url) => {
   state.wsUrl = url;
@@ -19,30 +20,24 @@ const stop = async () => {
 };
 
 const playback = async (url, startTime, endTime) => {
-  console.log('playback', url, state.mode, startTime, endTime);
+  // console.log('playback', url, state.mode, startTime, endTime);
   startTime += 'Z';
   endTime += 'Z';
   state.player &&
     state.player.JS_Play(url, { playURL: url, mode: 1 }, 0, startTime, endTime).then(
       () => {
-        console.log('playback success 播放成功');
+        // console.log('playback success 播放成功');
         state.player && state.player.JS_Resize();
         state.isLoading = false;
         emits('onPlaying');
       },
       (e) => {
-        emits('onPlayError', e);
-        console.error('playerror', e);
+        emits('onPlayError');
+        // console.error('playerror', e);
       }
     );
 };
 
-defineExpose({
-  play,
-  stop,
-  playback
-});
-
 const emits = defineEmits(['onPlaying', 'onPlayError']);
 
 const state = reactive({
@@ -97,11 +92,11 @@ const createPlayer = () => {
   state.player.JS_SetWindowControlCallback({
     windowEventSelect: function (iWndIndex) {
       //插件选中窗口回调
-      console.log('windowSelect callback: ', iWndIndex);
+      // console.log('windowSelect callback: ', iWndIndex);
     },
     pluginErrorHandler: function (iWndIndex, iErrorCode, oError) {
       //插件错误回调
-      console.log('插件错误回调pluginError callback: ', iWndIndex, iErrorCode, oError);
+      // console.log('插件错误回调pluginError callback: ', iWndIndex, iErrorCode, oError);
       // setTimeout(() => {
       //   realplay(state.wsUrl);
       // }, 100);
@@ -122,18 +117,18 @@ const createPlayer = () => {
     },
     windowFullCcreenChange: function (bFull) {
       //全屏切换回调
-      console.log('全屏切换回调fullScreen callback: ', bFull);
-      if (!bFull) {
-        console.log('退出全屏');
-      }
+      // console.log('全屏切换回调fullScreen callback: ', bFull);
+      // if (!bFull) {
+      //   console.log('退出全屏');
+      // }
     },
     firstFrameDisplay: function (iWndIndex, iWidth, iHeight) {
       //首帧显示回调
-      console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight);
+      // console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight);
     },
     performanceLack: function () {
       //性能不足回调
-      console.log('performanceLack callback: ');
+      // console.log('performanceLack callback: ');
       stopPlay();
     }
   });
@@ -159,7 +154,7 @@ const realplay = async (url) => {
         emits('onPlaying');
       },
       (e) => {
-        emits('onPlayError', e);
+        emits('onPlayError');
         console.error('playerror', e);
       }
     );
@@ -190,6 +185,36 @@ const fullScreen = (type) => {
       }
     );
 };
+
+// 截图功能
+const handleScreenshot = (name) => {
+  const video = document.getElementById(state.id + '_playVideo0'); // 使用保存的引用或直接获取
+  if (!video) {
+    console.error('Video element not found!');
+    return;
+  }
+  const canvas = document.createElement('canvas');
+  canvas.width = video.videoWidth;
+  canvas.height = video.videoHeight;
+  const context = canvas.getContext('2d');
+  context.drawImage(video, 0, 0, canvas.width, canvas.height);
+
+  let time = new Date().getTime();
+  let fileName = name ? name : '';
+  fileName += '截图' + time + '.png';
+  const dataURL = canvas.toDataURL('image/png');
+  const a = document.createElement('a');
+  a.href = dataURL;
+  a.download = fileName;
+  a.click();
+};
+
+defineExpose({
+  play,
+  stop,
+  playback,
+  handleScreenshot
+});
 </script>
 
 <style lang="scss">
@@ -205,11 +230,11 @@ const fullScreen = (type) => {
     height: 100%;
   }
   .video-enlarge {
-    width: 14px;
-    height: 14px;
+    width: 34px;
+    height: 34px;
     position: absolute;
-    top: 10px;
-    right: 10px;
+    top: 20px;
+    right: 20px;
     z-index: 10;
   }
 

+ 29 - 16
src/components/HKVideo/index.vue

@@ -7,7 +7,7 @@
         style="width: 100%; height: 100%; object-fit: fill"
         @on-playing="onHkPlaying"
         @on-play-error="onHKPlayError"
-      ></HikvisionPlayer>
+      />
       <img v-if="posterVisible" class="video-play" src="@/assets/images/video/play.png" alt="" />
       <img v-if="posterVisible && dot_data.poster" class="video-poster" :src="dot_data.poster" />
       <div v-if="errBKVisible" class="err_bk">
@@ -44,11 +44,6 @@ const refresh_data = () => {
   // });
 };
 
-defineExpose({
-  play,
-  refresh_data
-});
-
 const emits = defineEmits(['propClick', 'videoPreviewClick', 'favorClick']);
 
 // https://blog.csdn.net/weixin_49826079/article/details/135147184
@@ -60,6 +55,13 @@ const isPlaying = ref(false);
 const errBKVisible = ref(false);
 const posterVisible = ref(true);
 
+const isShowTooltip = async () => {
+  if (contentRef.value.parentNode.offsetWidth > contentRef.value.offsetWidth) {
+    isShowTip.value = true;
+  } else {
+    isShowTip.value = false;
+  }
+};
 const onHkPlaying = async () => {
   console.log('onHkPlaying');
   errBKVisible.value = false;
@@ -116,7 +118,14 @@ const stop_now = async () => {
   }
   posterVisible.value = true;
 };
-
+const handleScreenshot = (name) => {
+  videoPlayer.value.handleScreenshot(name);
+};
+defineExpose({
+  play,
+  refresh_data,
+  handleScreenshot
+});
 onMounted(() => {
   if (!!props.autoplay) {
     play_now();
@@ -147,8 +156,8 @@ onMounted(() => {
     cursor: pointer;
   }
   .video-play {
-    width: 25px;
-    height: 25px;
+    width: 72px;
+    height: 72px;
     position: absolute;
     top: 50%;
     left: 50%;
@@ -166,13 +175,16 @@ onMounted(() => {
     height: 100%;
 
     .err_box {
-      display: flex;
+      display: inline-flex;
       justify-content: center;
       align-items: center;
       width: 100%;
       height: 100%;
 
       .err_inner_box {
+        width: 150px;
+        height: 120px;
+
         display: flex;
         flex-direction: column;
         justify-content: space-between;
@@ -182,21 +194,22 @@ onMounted(() => {
         align-items: center;
 
         .err_icon {
-          width: 18px;
-          height: 20px;
+          width: 39px;
+          height: 40px;
           background: url('@/assets/images/video/err_video.png') no-repeat;
           background-size: 100% 100%;
+          margin-bottom: 10px;
         }
 
         .err_text {
           font-size: 14px;
           color: #ffffffb3;
-          margin-bottom: 4px;
+          margin-bottom: 10px;
         }
 
         .refresh_btn {
-          width: 70px;
-          height: 25px;
+          width: 120px;
+          height: 30px;
           border: 1px solid #001b41;
           background: #006affcc;
           cursor: pointer;
@@ -206,7 +219,7 @@ onMounted(() => {
           font-size: 14px;
           font-style: normal;
           font-weight: 400;
-          line-height: 25px;
+          line-height: 30px;
         }
       }
     }

+ 23 - 0
src/types/components.d.ts

@@ -24,16 +24,24 @@ declare module 'vue' {
     DistributionMap: typeof import('./../components/Map/YztMap/DistributionMap.vue')['default']
     DrawMap: typeof import('./../components/Map/YztMap/DrawMap.vue')['default']
     Editor: typeof import('./../components/Editor/index.vue')['default']
+    ElAnchor: typeof import('element-plus/es')['ElAnchor']
+    ElAnchorLink: typeof import('element-plus/es')['ElAnchorLink']
     ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
     ElBadge: typeof import('element-plus/es')['ElBadge']
     ElButton: typeof import('element-plus/es')['ElButton']
+    ElCard: typeof import('element-plus/es')['ElCard']
     ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
     ElCheckboxButton: typeof import('element-plus/es')['ElCheckboxButton']
     ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
     ElCol: typeof import('element-plus/es')['ElCol']
+    ElCollapse: typeof import('element-plus/es')['ElCollapse']
+    ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
     ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
+    ElContainer: typeof import('element-plus/es')['ElContainer']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+    ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
+    ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
     ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDivider: typeof import('element-plus/es')['ElDivider']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
@@ -43,18 +51,29 @@ declare module 'vue' {
     ElEmpty: typeof import('element-plus/es')['ElEmpty']
     ElForm: typeof import('element-plus/es')['ElForm']
     ElFormItem: typeof import('element-plus/es')['ElFormItem']
+    ElHeader: typeof import('element-plus/es')['ElHeader']
     ElIcon: typeof import('element-plus/es')['ElIcon']
     ElImage: typeof import('element-plus/es')['ElImage']
     ElInput: typeof import('element-plus/es')['ElInput']
+    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
+    ElLink: typeof import('element-plus/es')['ElLink']
+    ElMain: typeof import('element-plus/es')['ElMain']
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
     ElPopover: typeof import('element-plus/es')['ElPopover']
+    ElRadio: typeof import('element-plus/es')['ElRadio']
+    ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
+    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
+    ElSegmented: typeof import('element-plus/es')['ElSegmented']
     ElSelect: typeof import('element-plus/es')['ElSelect']
+    ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
+    ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
     ElSlider: typeof import('element-plus/es')['ElSlider']
+    ElSpace: typeof import('element-plus/es')['ElSpace']
     ElStep: typeof import('element-plus/es')['ElStep']
     ElSteps: typeof import('element-plus/es')['ElSteps']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
@@ -69,6 +88,7 @@ declare module 'vue' {
     ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
     ElTooltip: typeof import('element-plus/es')['ElTooltip']
     ElTree: typeof import('element-plus/es')['ElTree']
+    ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
     ElUpload: typeof import('element-plus/es')['ElUpload']
     ExcelEditor: typeof import('./../components/ExcelEditor/index.vue')['default']
     FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
@@ -80,6 +100,9 @@ declare module 'vue' {
     HikvisionPlayer: typeof import('./../components/HKVideo/hikvision-player.vue')['default']
     HKVideo: typeof import('./../components/HKVideo/index.vue')['default']
     IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
+    IEpCaretBottom: typeof import('~icons/ep/caret-bottom')['default']
+    IEpCaretTop: typeof import('~icons/ep/caret-top')['default']
+    IEpUploadFilled: typeof import('~icons/ep/upload-filled')['default']
     IFrame: typeof import('./../components/iFrame/index.vue')['default']
     ImagePreview: typeof import('./../components/ImagePreview/index.vue')['default']
     ImageUpload: typeof import('./../components/ImageUpload/index.vue')['default']

+ 1 - 0
src/views/comprehensiveGuarantee/materialReserves/materialsDeclarationAdd.vue

@@ -119,6 +119,7 @@ const calcTotalAmount = () => {
 
 const handleAddRow = () => {
   const newRow = {
+    id: '',
     warehouse_name: '',
     material_name: '',
     material_type: '',

+ 1 - 1
src/views/dataManagement/dataManagementEdit.vue

@@ -80,7 +80,7 @@ const closeDialog = () => {
 // };
 const submitForm = async () => {
   // 假设表单已经通过验证
-  const response = await uploadPersonnel(props.eventId, formData.value );
+  const response = await uploadPersonnel(props.eventId, formData.value);
   if (response.code === 200) {
     ElMessage.success('提交成功');
     closeDialog();

+ 1 - 1
src/views/globalMap/index.vue

@@ -160,7 +160,7 @@ const clickMenu = (item, dataList) => {
         '易涝隐患点',
         '无人机',
         '铁塔运行监测',
-        '物资与装备',
+        // '物资与装备',
         '通讯保障',
         '路网视频',
         '江湖河库',