Просмотр исходного кода

fix: incident detail needs live video

Jiang, Wim 3 лет назад
Родитель
Сommit
0f728ea9d4

+ 24 - 19
src/components/MarkerMap/dialog.ts

@@ -20,8 +20,7 @@ export const GET_INCIDENT_DIALOG_HTML = (
   
   <i class="card-border-bottom-left"></i>
   <i class="card-border-bottom-right"></i>
-</div>
-`;
+</div>`;
 
   const action = document.createElement('div');
   action.className = 'action';
@@ -41,15 +40,18 @@ export const GET_INCIDENT_DIALOG_HTML = (
 // b.视频点位地点
 // c.按钮可以打开一个窗口,然后窗口中显示摄像头拍摄内容 (目前还无该项目数据,暂定为该内容)
 
-export const GET_VIDEO_DIALOG_HTML = ({
-  name,
-  addr,
-  link,
-}: {
-  name: string;
-  addr: string;
-  link: string;
-}) => {
+export const GET_VIDEO_DIALOG_HTML = (
+  {
+    name,
+    addr,
+    link,
+  }: {
+    name: string;
+    addr: string;
+    link: string;
+  },
+  callback = () => {},
+) => {
   const el = document.createElement('div');
   el.innerHTML = `
   <div>
@@ -58,16 +60,19 @@ export const GET_VIDEO_DIALOG_HTML = ({
         <div><span>编号:</span><span>${name ?? '-'}</span></div>
         <div><span>地点:</span><span>${addr ?? '-'}</span></div>
     </div>
-    <div class="action">
-        <button class="el-button el-button--primary el-button--small" type="button">
-            <span>查看</span>
-        </button>
-    </div>
     <i class="card-border-bottom-left"></i>
     <i class="card-border-bottom-right"></i>
-  
-  </div>
-  `;
+  </div>`;
+
+  const action = document.createElement('div');
+  action.className = 'action';
+  const button = document.createElement('button');
+  button.className = 'el-button el-button--primary el-button--small';
+  button.innerHTML = '查看';
+  action.appendChild(button);
+  button.addEventListener('click', callback);
+
+  el.appendChild(action);
   return el;
 };
 

+ 3 - 4
src/components/MarkerMap/index.scss

@@ -2,9 +2,10 @@
 
 .card-bg-container {
   box-sizing: border-box;
-  background-image: url('../../assets/card-bg/frame_filter.png');
+  background-image: url('../../assets/card-bg/frame_filter_center@2x.png');
   background-position: top center;
   background-repeat: repeat-y;
+  background-size: cover;
   .card-border-bottom-left,
   .card-border-bottom-right,
   &::before,
@@ -46,6 +47,7 @@
       padding: unset;
       width: px2rem(332px);
       width: 332px;
+      border-radius: unset;
 
       @extend .card-bg-container;
 
@@ -83,7 +85,6 @@
     position: absolute;
     top: px2rem(83px);
     right: px2rem(30px);
-    width: max-content;
     min-width: px2rem(178px);
     min-height: px2rem(293px);
     width: max-content;
@@ -92,8 +93,6 @@
     padding: px2rem(27px) px2rem(36px);
     box-sizing: border-box;
 
-    @extend .card-bg-container;
-
     .el-checkbox__inner {
       background-color: transparent;
     }

+ 89 - 35
src/components/MarkerMap/index.tsx

@@ -40,6 +40,8 @@ import {
 } from './dialog';
 import { IncidentItemDetail } from '@/api/incident';
 import { useIncidentStore } from '@/store';
+import Popup from '../Popup';
+import { ElMessage } from 'element-plus';
 
 const MARKER_MAP_TYPES = [
   // '待派发事件',
@@ -99,6 +101,7 @@ export default defineComponent({
 
     const store = useMarkerStore();
     const incidentStore = useIncidentStore();
+    const markerStore = useMarkerStore();
     const router = useRouter();
     const route = useRoute();
 
@@ -147,7 +150,7 @@ export default defineComponent({
       },
     ]);
 
-    const getMarkerPopupHTML = (type: MarkerMapType, marker?: MarkerType) => {
+    const getMarkerPopupHTML = (type: MarkerMapType, marker: MarkerType) => {
       switch (type) {
         case '应急事件':
         // case '待派发事件':
@@ -160,13 +163,7 @@ export default defineComponent({
             },
             () => {
               router.push(`/incidentDetail?id=${marker?.id}`);
-              handleRemoveAllMarkers();
-              handleAddMarkers(
-                '应急事件',
-                [{ location: marker?.location, name: '中心庄' }],
-                icon_map_dpf,
-              );
-              state.markers[0].marker.togglePopup();
+              handleSetDetailMarker(marker);
             },
           );
         case '应急仓库':
@@ -193,11 +190,25 @@ export default defineComponent({
           });
 
         case '视频监控':
-          return GET_VIDEO_DIALOG_HTML({
-            name: '12312313',
-            addr: 'su qian',
-            link: '',
-          });
+          return GET_VIDEO_DIALOG_HTML(
+            {
+              name: '12312313',
+              addr: 'su qian',
+              link: '',
+            },
+            () => {
+              if (route.query.id) {
+                markerStore.livevideovisible = true;
+                if (
+                  markerStore.livevideos.findIndex(
+                    (item) => item.location === marker.location,
+                  ) < 0
+                ) {
+                  markerStore.livevideos.push(marker);
+                }
+              }
+            },
+          );
       }
     };
     const updateTrafficSource = () => {
@@ -249,7 +260,7 @@ export default defineComponent({
         ...markers.map((i) => {
           const popup = new window.minemap.Popup({
             anchor: 'left',
-            closeOnClick: false,
+            closeOnClick: true,
             closeButton: false,
             offset: [10, 25],
             maxWidth: 'max-content',
@@ -316,6 +327,8 @@ export default defineComponent({
       type: MarkerMapType,
       markers: State['markers'],
     ) => {
+      state.hasTypes = state.hasTypes.filter((t) => t !== type);
+
       const locations = markers.map((i) => i.location);
       state.markers.forEach((m) => {
         if (locations.includes(m.location)) {
@@ -340,7 +353,54 @@ export default defineComponent({
       state.markers = [];
       state.positions = [];
     };
-    onMounted(() => {
+
+    const handleSetDetailMarker = (marker: MarkerType) => {
+      handleRemoveAllMarkers();
+      const location = marker.location?.split(',').map(Number);
+
+      if (!location) {
+        ElMessage.error({ message: '该点位无地址经纬度' });
+        return;
+      }
+
+      // 获取事件周围的 5km 内的 监控点
+      const bounds: number[][] = new window.minemap.LngLat(...location)
+        .toBounds(10000)
+        .toArray();
+
+      const videos = markerStore.videoSurveillance.reduce((carry, next) => {
+        const [lng, lat] = next.location?.split(',') ?? [];
+        // bounds [right-bottom[lng, lat],left-top[lng, lat], ]
+        if (
+          Number(lng) > bounds[0][0] &&
+          Number(lng) < bounds[1][0] &&
+          Number(lat) > bounds[0][1] &&
+          Number(lat) < bounds[1][1]
+        ) {
+          carry.push(next);
+        }
+        return carry;
+      }, [] as MarkerType[]);
+
+      console.log(location, bounds, videos, markerStore.videoSurveillance);
+
+      // 开启路况信息
+      if (!state.types.includes('路况信息')) {
+        state.types.push('路况信息');
+        state.hasTypes.push('路况信息');
+        toggleControlTraffic();
+      }
+
+      handleAddMarkers(
+        '应急事件',
+        [{ location: marker?.location, name: '中心庄' }],
+        icon_map_dpf,
+      );
+      handleAddMarkers('视频监控', videos, icon_map_spjk);
+      // state.markers[0].marker.togglePopup();
+    };
+
+    onMounted(async () => {
       window.minemap.util.getJSON(
         'https://minedata.cn/service/solu/style/id/12878',
         function (error, data) {
@@ -394,22 +454,20 @@ export default defineComponent({
         state.trafficLayerIds.push('trafficlines');
         state.trafficStatus = false;
         updateTrafficLayerVisibility('none');
-      });
 
-      if (!route.query.id) return;
-      // 如果存在id
-      handleAddMarkers(
-        '应急事件',
-        [{ location: '118.752399,34.118339', name: '中心庄' }],
-        icon_map_dpf,
-      );
-
-      state.markers[0].marker.togglePopup();
+        if (!route.query.id) return;
+        // 如果存在id
+        handleSetDetailMarker({
+          location: '118.288721,33.951047',
+          name: '中心庄',
+        });
+      });
     });
 
     watch(
       () => route.query.id,
       (next) => {
+        // 返回首页时 需要清除事件相关的
         if (!next) {
           handleRemoveAllMarkers();
           if (state.types.includes('应急事件')) {
@@ -438,13 +496,10 @@ export default defineComponent({
       () => props.marker?.baseInfo?.locations,
       (next) => {
         if (next && !state.positions.includes(next)) {
-          handleRemoveAllMarkers();
-          handleAddMarkers(
-            '应急事件',
-            [{ location: '118.288721,33.951047', name: '中心庄' }],
-            icon_map_dpf,
-          );
-          state.markers[0].marker.togglePopup();
+          handleSetDetailMarker({
+            location: '118.288721,33.951047',
+            name: '中心庄',
+          });
         }
       },
     );
@@ -458,7 +513,6 @@ export default defineComponent({
             item.action();
           }
           if (!next.includes(item.type) && item.hasActioned) {
-            state.hasTypes = state.hasTypes.filter((t) => t !== item.type);
             item.remove();
           }
         });
@@ -469,7 +523,7 @@ export default defineComponent({
       <div class="task-map-container">
         <MapView v-model:map={state.map} />
         {!props.readonly && (
-          <div class="address-type-card">
+          <Popup class="address-type-card">
             <el-checkbox-group v-model={state.types}>
               {props.adrsMapTypes &&
                 props.adrsMapTypes.map((t) => (
@@ -478,7 +532,7 @@ export default defineComponent({
             </el-checkbox-group>
             <i class="card-border-bottom-left"></i>
             <i class="card-border-bottom-right"></i>
-          </div>
+          </Popup>
         )}
       </div>
     );

+ 5 - 0
src/store/useMarkerStore.ts

@@ -24,6 +24,9 @@ export interface MarkerStateType {
   emergencyVehicles: MarkerType[];
   emergencyTeam: MarkerType[];
   emergencyWarehouse: MarkerType[];
+  /** 详情页面 点击监控点位 打开视频 */
+  livevideovisible: boolean;
+  livevideos: MarkerType[];
 }
 
 export interface MainActionsType {}
@@ -39,6 +42,8 @@ export default defineStore<'marker', MarkerStateType, {}, MainActionsType>(
       emergencyVehicles: EMERGENCY_VEHICLES,
       emergencyTeam: EMERGENCY_TEAM,
       emergencyWarehouse: [],
+      livevideovisible: false,
+      livevideos: [],
     }),
     actions: {},
   },

+ 2 - 8
src/views/IncidentDetail/LiveMonitoringCard/index.tsx

@@ -4,19 +4,13 @@ import { computed, defineComponent, ref } from 'vue-demi';
 
 export default defineComponent({
   name: 'LiveMonitoringCard',
-  setup(props) {
+  setup() {
     const store = useIncidentStore();
 
-    const medias = computed(() =>
-      (store.incidentDetail?.baseInfo?.pic?.split(',') ?? []).concat(
-        store.incidentDetail?.baseInfo?.video?.split(',') ?? [],
-      ),
-    );
-
     return () => (
       <Card cardType="live-monitoring">
         <div class="live-container">
-          <div style={{width: 'calc((1.0911458333rem + 10px) * 6) '}}>
+          <div style={{ width: 'calc((1.0911458333rem + 10px) * 6) ' }}>
             {(store.incidentDetail?.baseInfo?.pic?.split(',') ?? []).map(
               (item) => (
                 <div class="live-item">

+ 24 - 0
src/views/IncidentDetail/LiveVideoCard/index.tsx

@@ -0,0 +1,24 @@
+import Card from '@/components/Card';
+import Popup from '@/components/Popup';
+import { useIncidentStore, useMarkerStore } from '@/store';
+import { computed, defineComponent, ref } from 'vue-demi';
+
+export default defineComponent({
+  name: 'LiveVideoCard',
+  setup() {
+    const store = useIncidentStore();
+    const markerStore = useMarkerStore();
+
+    return () => (
+      <>
+        {markerStore.livevideos.map((item) => (
+          <Popup>
+            <video
+              controls
+              src="https://www.w3school.com.cn/i/movie.ogg"></video>
+          </Popup>
+        ))}
+      </>
+    );
+  },
+});

+ 39 - 0
src/views/IncidentDetail/index.scss

@@ -1,6 +1,45 @@
 @use 'sass:math';
 @import '../../styles/utils.scss';
 
+.live-video-container-left {
+  position: absolute;
+  z-index: 1;
+  height: 100%;
+  width: px2rem(481px) * 2 + px2rem(25px);
+  animation: fadeInLeft 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
+}
+
+.live-video-container {
+  position: absolute;
+  left: px2rem(30px);
+  top: calc(50% + px2rem(52px));
+  transform: translateY(calc(-50% - px2rem(52px / 2)));
+  width: px2rem(481px) * 2 + px2rem(25px);
+  height: px2rem(301px) * 3 + px2rem(31px);
+  display: flex;
+  flex-wrap: wrap;
+  .popup-container {
+    &:first-child,
+    &:nth-child(3),
+    &:nth-child(5) {
+      margin-bottom: px2rem(31px);
+      margin-right: px2rem(25px);
+    }
+    &:nth-child(5) {
+      margin-bottom: unset;
+    }
+    width: px2rem(481px);
+    height: px2rem(301px);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    video {
+      max-height: 100%;
+      max-width: 100%;
+    }
+  }
+}
+
 .incident-detail-page-container {
   flex: 1;
   position: absolute;

+ 35 - 14
src/views/IncidentDetail/index.tsx

@@ -1,12 +1,13 @@
-import { onMounted, onUnmounted, defineComponent } from 'vue';
+import { onMounted, onUnmounted, defineComponent, ref } from 'vue';
 import { useRoute } from 'vue-router';
-import { useCommonStore, useIncidentStore } from '@/store';
+import { useCommonStore, useIncidentStore, useMarkerStore } from '@/store';
 import IncidentInfoCard from './IncidentInfoCard';
 import CommandChainCard from './CommandChainCard';
 import EmergencyLinkageCard from './EmergencyLinkageCard';
 import IncidentPlanCard from './IncidentPlanCard';
 import LiveMonitoringCard from './LiveMonitoringCard';
 import ExecutionLogCard from './ExecutionLogCard';
+import LiveVideoCard from './LiveVideoCard';
 import './index.scss';
 
 export default defineComponent({
@@ -15,7 +16,11 @@ export default defineComponent({
   setup() {
     const store = useIncidentStore();
     const commonStore = useCommonStore();
+    const markerStore = useMarkerStore();
     const route = useRoute();
+
+    const livevisible = ref(false);
+
     onMounted(() => {
       commonStore.getGlobalDict('zhdd_incident_type');
       commonStore.getGlobalDict('zhdd_incident_source');
@@ -23,20 +28,36 @@ export default defineComponent({
       commonStore.getGlobalDict('zhdd_incident_level');
       store.getIncidentItem(route.query.id as string);
     });
-    onUnmounted(() => (store.incidentDetail = {}));
+    onUnmounted(() => {
+      store.incidentDetail = {};
+      markerStore.livevideovisible = false;
+      markerStore.livevideos = [];
+    });
     return () => (
-      <div class="incident-detail-page-container">
-        <div class="detail-left">
-          <IncidentInfoCard />
-          <CommandChainCard />
-          <IncidentPlanCard />
-          <EmergencyLinkageCard />
+      <>
+        <div class="incident-detail-page-container">
+          {!markerStore.livevideovisible && (
+            <div class="detail-left">
+              <IncidentInfoCard />
+              <CommandChainCard />
+              <IncidentPlanCard />
+              <EmergencyLinkageCard />
+            </div>
+          )}
+          <div class="detail-right">
+            <ExecutionLogCard />
+            <LiveMonitoringCard />
+          </div>
         </div>
-        <div class="detail-right">
-          <ExecutionLogCard />
-          <LiveMonitoringCard />
-        </div>
-      </div>
+
+        {markerStore.livevideovisible && (
+          <div class="live-video-container-left">
+            <div class="live-video-container">
+              <LiveVideoCard />
+            </div>
+          </div>
+        )}
+      </>
     );
   },
 });