Bläddra i källkod

视频监控选择播放

Hwf 4 dagar sedan
förälder
incheckning
6f0abb67d6

+ 17 - 0
package-lock.json

@@ -67,6 +67,7 @@
         "vue-router": "^4.5.0",
         "vue-types": "5.1.1",
         "vue3-print-nb": "^0.1.4",
+        "vuedraggable": "^4.1.0",
         "vxe-table": "^4.6.21",
         "xlsx": "^0.18.5"
       },
@@ -15215,6 +15216,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/sortablejs": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz",
+      "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="
+    },
     "node_modules/source-map": {
       "version": "0.6.1",
       "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@@ -18675,6 +18681,17 @@
         "vue": "^3.0.5"
       }
     },
+    "node_modules/vuedraggable": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
+      "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+      "dependencies": {
+        "sortablejs": "1.14.0"
+      },
+      "peerDependencies": {
+        "vue": "^3.0.1"
+      }
+    },
     "node_modules/vxe-table": {
       "version": "4.6.21",
       "resolved": "https://registry.npmmirror.com/vxe-table/-/vxe-table-4.6.21.tgz",

+ 1 - 0
package.json

@@ -76,6 +76,7 @@
     "vue-router": "^4.5.0",
     "vue-types": "5.1.1",
     "vue3-print-nb": "^0.1.4",
+    "vuedraggable": "^4.1.0",
     "vxe-table": "^4.6.21",
     "xlsx": "^0.18.5"
   },

BIN
src/assets/images/video/add.png


BIN
src/assets/images/video/remove.png


+ 3 - 1
src/components/Dialog/index.vue

@@ -9,7 +9,7 @@
     }"
     class="common-dialog"
     :class="customClass"
-    :style="{ width: computedWidth, height: computedHeight, zIndex: zIndex }"
+    :style="{ width: computedWidth, height: computedHeight, zIndex: zIndex, left: left ? left : '50%', top: top ? top : '50%' }"
   >
     <div :class="type === 'xs' || headerType === 'header2' ? 'dialog-header2' : 'dialog-header'">
       <div class="header-left">
@@ -71,6 +71,8 @@ interface Props {
   customClass?: string;
   showFull?: boolean;
   fullScreen?: boolean;
+  left?: string;
+  top?: string;
 }
 const full = ref(false);
 const containerScale = inject('containerScale');

+ 16 - 2
src/components/HKVideo/index2.vue

@@ -22,6 +22,8 @@
       <div class="video-header">
         <div class="label" :title="dot_data.name">{{ dot_data.name }}</div>
         <div class="video-header-right">
+          <img v-if="add" class="add" src="@/assets/images/video/add.png" @click.stop="handleAdd('add')" />
+          <img v-if="remove" class="add" src="@/assets/images/video/remove.png" @click.stop="handleAdd('remove')" />
           <i v-if="!hiddenCollect" :class="dot_data.tag && dot_data.tag.length > 0 ? 'collectFill' : 'collect'" @click.stop="handleCollect" />
           <img class="video-enlarge" src="@/assets/images/video/enlarge.png" alt="" @click.stop="handleFullScreen" />
         </div>
@@ -87,10 +89,12 @@ interface Props {
   hiddenCollect?: boolean;
   isNoLive?: boolean;
   fullScreen?: boolean;
+  add?: boolean;
+  remove?: boolean;
 }
 
 const props = withDefaults(defineProps<Props>(), {});
-const emits = defineEmits(['update:dot_data', 'propClick', 'videoPreviewClick', 'favorClick', 'change']);
+const emits = defineEmits(['update:dot_data', 'propClick', 'videoPreviewClick', 'favorClick', 'change', 'changeSelect']);
 
 const wsUrl = ref('');
 const isPlaying = ref(false);
@@ -201,6 +205,11 @@ const getPlayer = (name) => {
   return videoPlayer.value.getPlayer(name);
 };
 
+// 选中数据
+const handleAdd = (type) => {
+  emits('changeSelect', { type: type, data: props.dot_data });
+};
+
 onMounted(() => {
   if (!!props.autoplay) {
     play_now(true);
@@ -345,7 +354,12 @@ defineExpose({
       background-size: 100% 100%;
       cursor: pointer;
     }
-
+    .add {
+      width: 14px;
+      height: 14px;
+      cursor: pointer;
+      margin-right: 6px;
+    }
     .video-enlarge {
       width: 14px;
       height: 14px;

+ 79 - 0
src/views/emergencyCommandMap/LeftSection/FullVideos.vue

@@ -0,0 +1,79 @@
+<template>
+  <Dialog custom-show type="xl" title="视频监控" class="dialog" full-screen hide-footer draggable @close="reset">
+    <div class="video-list2">
+      <div v-for="(item, index) in data" :key="index" class="video-box">
+        <HKVideo :dot_data="item" autoplay fullScreen />
+      </div>
+    </div>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import HKVideo from '@/components/HKVideo/index2.vue';
+
+const props = defineProps({
+  data: Array
+});
+const emits = defineEmits(['close']);
+
+const reset = () => {
+  emits('close');
+};
+</script>
+
+<style lang="scss" scoped>
+.video-list2 {
+  height: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+  .video-box {
+    width: calc(25% - 12px);
+    height: calc(50% - 15px);
+    margin-right: 15px;
+    cursor: pointer;
+    cursor: pointer;
+    background: url('@/assets/images/video/videoBg.png') no-repeat;
+    background-size: 100% 100%;
+    padding: 9.5px 3.8px 9px 5.5px;
+    position: relative;
+    margin-bottom: 15px;
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    &:nth-child(4),
+    &:nth-child(8) {
+      margin-right: 0 !important;
+    }
+    .video-label {
+      position: absolute;
+      bottom: 8px;
+      right: 4px;
+      z-index: 901;
+      display: flex;
+      .label {
+        width: 186px;
+        height: 24px;
+        padding-right: 5px;
+        line-height: 24px;
+        font-size: 14px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        padding-left: 10px;
+        color: #fff;
+        background-color: rgba(0, 0, 0, 0.4);
+        text-align: right;
+      }
+      &::before {
+        content: '';
+        width: 0;
+        height: 0;
+        border-bottom: 24px solid rgba(0, 0, 0, 0.4);
+        border-left: 24px solid transparent;
+      }
+    }
+  }
+}
+</style>

+ 104 - 0
src/views/emergencyCommandMap/LeftSection/SelectVideoDialog.vue

@@ -0,0 +1,104 @@
+<template>
+  <Dialog
+    custom-show
+    type="xs"
+    :title="'已选择视频(' + data.length + '/8)'"
+    class="dialog"
+    height="500px"
+    left="1450px"
+    top="298px"
+    hide-footer
+    draggable
+    @close="reset"
+  >
+    <div class="custom-table">
+      <div class="th">
+        <div class="td">名称</div>
+        <div class="td" style="flex: unset; width: 100px">操作</div>
+      </div>
+      <div class="table-content">
+        <draggable v-model="localData" item-key="id" :animation="200" @end="onDragEnd">
+          <template #item="{ element, index }">
+            <div class="tr">
+              <div class="td">{{ element.name }}</div>
+              <div class="td" style="flex: unset; width: 100px">
+                <div style="color: #ff2f3c; cursor: pointer" @click="handleDelete(index)">移除</div>
+              </div>
+            </div>
+          </template>
+        </draggable>
+      </div>
+    </div>
+  </Dialog>
+</template>
+
+<script lang="ts" setup name="SelectVideoDialog">
+import draggable from 'vuedraggable';
+const props = defineProps({
+  data: Array
+});
+const localData = ref([]);
+const emits = defineEmits(['update:data', 'close']);
+
+const reset = () => {
+  emits('close');
+};
+
+watch(
+  () => props.data,
+  (newData) => {
+    localData.value = [...newData];
+  },
+  {
+    immediate: true,
+    deep: true
+  }
+);
+
+// 拖拽结束时通知父组件
+const onDragEnd = () => {
+  emits('update:data', localData.value);
+};
+
+const handleDelete = (index) => {
+  localData.value.splice(index, 1);
+  emits('update:data', localData.value);
+};
+</script>
+
+<style lang="scss" scoped>
+.custom-table {
+  width: 362px;
+  .table-content {
+    height: 290px;
+    overflow-y: auto;
+    overflow-x: hidden;
+  }
+  .th {
+    background: url('@/assets/images/map/rightMenu/th.png') no-repeat;
+    background-size: 100% 100%;
+    display: flex;
+    padding: 7px 12px;
+    min-height: 32px;
+  }
+  .tr {
+    background: url('@/assets/images/map/rightMenu/td.png') no-repeat;
+    background-size: 100% 100%;
+    display: flex;
+    padding: 7px 12px;
+    &:hover {
+      background: url('@/assets/images/map/rightMenu/td_checked.png') no-repeat;
+      background-size: 100% 100%;
+    }
+  }
+  .td {
+    flex: 1;
+    color: #edfaff;
+    font-size: 14px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+  }
+}
+</style>

+ 63 - 2
src/views/emergencyCommandMap/LeftSection/VideoMonitorEdit.vue

@@ -1,5 +1,16 @@
 <template>
-  <Dialog custom-show type="xl" title="视频监控" class="dialog" hide-footer draggable showFull @changeFull="handleFull" @close="reset">
+  <Dialog
+    v-if="!showVideos"
+    custom-show
+    type="xl"
+    title="视频监控"
+    class="dialog"
+    hide-footer
+    draggable
+    showFull
+    @changeFull="handleFull"
+    @close="reset"
+  >
     <div class="flex-box">
       <div class="search-box">
         <div class="box-left">
@@ -50,6 +61,9 @@
         </div>
       </div>
       <div style="display: flex; justify-content: flex-end; margin-bottom: 12px; margin-top: -20px">
+        <div v-show="!editVideo && selectVideos.length > 0" class="common-btn-primary2 edit-icon" style="margin-right: 10px" @click="handleShowFull">
+          播放选择视频
+        </div>
         <div v-show="!editVideo" class="common-btn-primary2 edit-icon" @click="activeEdit">编辑首页视频</div>
         <div v-show="editVideo" class="edit-box">
           <div class="flex">
@@ -84,7 +98,17 @@
                 <span class="label">{{ item.name }}</span>
               </div>
             </div>
-            <HKVideo v-else :dot_data="item" autoplay fullScreen :is-index="item.isUserVideos" @change="(data) => handleUpdateTags(item, data)" />
+            <HKVideo
+              v-else
+              :dot_data="item"
+              autoplay
+              fullScreen
+              :add="!getSelectStatus(item)"
+              :remove="getSelectStatus(item)"
+              :is-index="item.isUserVideos"
+              @change="(data) => handleUpdateTags(item, data)"
+              @change-select="handleSelect"
+            />
           </div>
         </div>
       </div>
@@ -101,7 +125,9 @@
       </div>
       <div id="container" style="display: none"></div>
     </div>
+    <SelectVideoDialog v-if="showSelectVideoDialog && !showVideos" v-model:data="selectVideos" @close="showSelectVideoDialog = false" />
   </Dialog>
+  <FullVideos v-if="showVideos" :data="selectVideos" @close="showVideos = false" />
   <div v-if="showTip" class="danger-tip" :style="{ zIndex: zIndex }">首页视频数量已达6个上限,如需继续操作请先取消已选择视频。</div>
 </template>
 
@@ -110,6 +136,8 @@ import { getUserVideoPoints, getVideoFromList, getVideoListNew, updateUserVideoP
 import useAppStore from '@/store/modules/app';
 import useMapStore from '@/store/modules/map';
 import HKVideo from '@/components/HKVideo/index2.vue';
+import FullVideos from './FullVideos.vue';
+import SelectVideoDialog from './SelectVideoDialog.vue';
 
 interface LngLat {
   longitude: number;
@@ -255,11 +283,44 @@ const handleUpdateTags = (item, data) => {
   item.tagLabels = labels.toString();
   emits('change');
 };
+// 选择的视频
+const showSelectVideoDialog = ref(false);
+const selectVideos = ref([]);
+const showVideos = ref(false);
+const getSelectStatus = (obj) => {
+  const index = selectVideos.value.findIndex((item) => item.video_code === obj.video_code);
+  return index > -1;
+};
+const handleSelect = (obj) => {
+  if (obj.type === 'add') {
+    if (selectVideos.value.length >= 8) {
+      proxy?.$modal.msgError('选择视频数量已达8个上限,如需继续操作请先取消已选择视频。');
+    } else {
+      selectVideos.value.push(obj.data);
+    }
+    if (!showSelectVideoDialog.value) {
+      showSelectVideoDialog.value = true;
+    }
+  } else {
+    const index = selectVideos.value.findIndex((item) => item.video_code === obj.data.video_code);
+    if (index > -1) {
+      selectVideos.value.splice(index, 1);
+    }
+    if (selectVideos.value.length === 0) {
+      showSelectVideoDialog.value = false;
+    }
+  }
+};
 const getUserPoint = () => {
   getUserVideoPoints().then((res) => {
     editData.value = res.data.videoInfos;
   });
 };
+
+//
+const handleShowFull = () => {
+  showVideos.value = true;
+};
 const videoParams = ref({
   width: '288px',
   height: '200px',