feat(screen): 在地图工具提示中添加视频监控功能

为支持视频的实体(如应急中心、储备中心和预设点)在MapTooltip组件中添加视频图标按钮。包含VideoModal集成,用于显示带控制功能的视频流。
This commit is contained in:
Zzc 2025-11-24 13:47:51 +08:00
parent 8fdc23d76d
commit 58fe72f717
3 changed files with 151 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

View File

@ -65,6 +65,20 @@
> >
{{ title }} {{ title }}
</span> </span>
<!-- 视频图标按钮 -->
<button
v-if="showVideoIcon && videoIconSrc"
type="button"
class="map-tooltip__video-btn"
:aria-label="videoIconAriaLabel"
@click.stop="emit('video-icon-click')"
>
<img
:src="videoIconSrc"
alt=""
class="map-tooltip__video-icon"
/>
</button>
</div> </div>
</slot> </slot>
</div> </div>
@ -197,6 +211,30 @@ const props = defineProps({
closable: { closable: {
type: Boolean, type: Boolean,
default: true default: true
},
/**
* 是否在标题右侧显示视频图标
*/
showVideoIcon: {
type: Boolean,
default: false
},
/**
* 视频图标的图片路径
*/
videoIconSrc: {
type: String,
default: ''
},
/**
* 视频图标的无障碍标签
*/
videoIconAriaLabel: {
type: String,
default: '打开视频监控'
} }
}) })
@ -211,7 +249,11 @@ const emit = defineEmits([
/** /**
* 支持 v-model:visible 双向绑定 * 支持 v-model:visible 双向绑定
*/ */
'update:visible' 'update:visible',
/**
* 用户点击视频图标时触发
*/
'video-icon-click'
]) ])
/** /**
@ -354,6 +396,47 @@ const handleClose = () => {
line-height: 1.4; line-height: 1.4;
} }
/**
* 视频图标按钮
* 显示在标题右侧用于打开视频监控
*/
.map-tooltip__video-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: vw(24);
height: vw(24);
padding: 0;
border: none;
background: transparent;
cursor: pointer;
flex-shrink: 0;
transition: all 0.3s ease;
&:hover {
transform: scale(1.15);
filter: brightness(1.2);
}
&:active {
transform: scale(1.05);
}
&:focus-visible {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
border-radius: 2px;
}
}
.map-tooltip__video-icon {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
pointer-events: none;
}
/** /**
* 关闭按钮 * 关闭按钮
* 使用纯 CSS 实现 X 图标避免额外的图片资源 * 使用纯 CSS 实现 X 图标避免额外的图片资源

View File

@ -116,6 +116,9 @@
:title="mapTooltip.title" :title="mapTooltip.title"
:icon="mapTooltip.icon" :icon="mapTooltip.icon"
:z-index="mapTooltip.zIndex" :z-index="mapTooltip.zIndex"
:show-video-icon="mapTooltip.data && mapTooltip.data.supportVideo"
:video-icon-src="mediaIcon"
@video-icon-click="handleVideoIconClick"
@close="handleMapTooltipClose" @close="handleMapTooltipClose"
> >
<!-- Tooltip 内容插槽 - 根据实际业务数据渲染 --> <!-- Tooltip 内容插槽 - 根据实际业务数据渲染 -->
@ -168,6 +171,14 @@
@close="showCenterDetail = false" @close="showCenterDetail = false"
/> />
<!-- 视频监控弹窗 -->
<VideoModal
v-if="showVideoModal"
:visible="showVideoModal"
:monitor="selectedVideoMonitor"
@close="handleVideoModalClose"
/>
<!-- 智能应急方案弹窗 --> <!-- 智能应急方案弹窗 -->
<StretchableModal <StretchableModal
v-model:visible="showStretchableModal" v-model:visible="showStretchableModal"
@ -203,6 +214,7 @@ import MapViewer from "./components/MapViewer/index.vue";
import RightPanel from "./components/RightPanel/index.vue"; import RightPanel from "./components/RightPanel/index.vue";
import PersonnelDetail from "./components/Popups/PersonnelDetail.vue"; import PersonnelDetail from "./components/Popups/PersonnelDetail.vue";
import EmergencyCenterDetail from "./components/Popups/EmergencyCenterDetail.vue"; import EmergencyCenterDetail from "./components/Popups/EmergencyCenterDetail.vue";
import VideoModal from "./components/RightPanel/VideoModal.vue";
import MapTooltip from "./components/shared/MapTooltip.vue"; import MapTooltip from "./components/shared/MapTooltip.vue";
import SceneLabel from "./components/SceneLabel.vue"; import SceneLabel from "./components/SceneLabel.vue";
import StretchableModal from "./components/shared/StretchableModal.vue"; import StretchableModal from "./components/shared/StretchableModal.vue";
@ -224,6 +236,7 @@ import soldierIcon from "./assets/images/SketchPngfbec927027ff9e49207749ebaafd22
import deviceIcon from "./assets/images/SketchPng860d54f2a31f5f441fc6a88081224f1e98534bf6d5ca1246e420983bdf690380.png"; import deviceIcon from "./assets/images/SketchPng860d54f2a31f5f441fc6a88081224f1e98534bf6d5ca1246e420983bdf690380.png";
import emergencyBaseIcon from "./assets/images/应急基地.png"; import emergencyBaseIcon from "./assets/images/应急基地.png";
import reserveCenterIcon from "./assets/images/储备中心.png"; import reserveCenterIcon from "./assets/images/储备中心.png";
import mediaIcon from "./assets/images/media.png";
// //
import collapseLeftArrow from "./assets/images/折叠面板左箭头.png"; import collapseLeftArrow from "./assets/images/折叠面板左箭头.png";
@ -459,6 +472,9 @@ const showMarkerTooltip = (viewer, entity, screenPosition, icon) => {
let title = ''; let title = '';
const fields = []; const fields = [];
const actions = []; const actions = [];
let supportVideo = false;
let videoTitle = '';
const videoSrc = 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/demo/ylzg/单兵视角.mp4';
if (type === 'soldier') { if (type === 'soldier') {
// //
@ -510,6 +526,8 @@ const showMarkerTooltip = (viewer, entity, screenPosition, icon) => {
{ label: '隶属单位', value: '交通公路部门' }, { label: '隶属单位', value: '交通公路部门' },
{ label: '位置信息', value: `目前为止距离现场${distance}公里` } { label: '位置信息', value: `目前为止距离现场${distance}公里` }
); );
supportVideo = true;
videoTitle = '应急中心';
} else { } else {
// tooltip // tooltip
title = '养护站'; title = '养护站';
@ -525,6 +543,8 @@ const showMarkerTooltip = (viewer, entity, screenPosition, icon) => {
{ label: '名称', value: properties.name?.getValue() || '-' }, { label: '名称', value: properties.name?.getValue() || '-' },
{ label: '位置信息', value: properties.location?.getValue() || '-' } { label: '位置信息', value: properties.location?.getValue() || '-' }
); );
supportVideo = true;
videoTitle = '储备中心';
} else if (type === 'presetPoint') { } else if (type === 'presetPoint') {
// //
title = '预置点'; title = '预置点';
@ -532,6 +552,8 @@ const showMarkerTooltip = (viewer, entity, screenPosition, icon) => {
{ label: '名称', value: properties.name?.getValue() || '-' }, { label: '名称', value: properties.name?.getValue() || '-' },
{ label: '位置信息', value: properties.location?.getValue() || '-' } { label: '位置信息', value: properties.location?.getValue() || '-' }
); );
supportVideo = true;
videoTitle = '预置点';
} }
// Tooltip使 // Tooltip使
@ -540,7 +562,13 @@ const showMarkerTooltip = (viewer, entity, screenPosition, icon) => {
y: canvasPosition.y, y: canvasPosition.y,
title, title,
icon, icon,
data: { fields, actions: actions.length > 0 ? actions : undefined } data: {
fields,
actions: actions.length > 0 ? actions : undefined,
supportVideo,
videoTitle,
videoSrc
}
}); });
// //
@ -989,6 +1017,7 @@ const handleMapToolChange = async ({ tool, active }) => {
const showPersonnelDetail = ref(false); const showPersonnelDetail = ref(false);
const showCenterDetail = ref(false); const showCenterDetail = ref(false);
const showStretchableModal = ref(false); const showStretchableModal = ref(false);
const showVideoModal = ref(false);
// //
const selectedPersonnel = ref({ const selectedPersonnel = ref({
@ -1007,6 +1036,16 @@ const selectedCenter = ref({
image: null, image: null,
}); });
const selectedVideoMonitor = ref({
id: '',
title: '',
videoSrc: '',
dateRange: '',
hasMegaphone: false,
hasAudio: true,
hasDirectionControl: false
});
// //
const handleBack = () => { const handleBack = () => {
console.log("返回驾驶舱"); console.log("返回驾驶舱");
@ -1080,6 +1119,33 @@ const handleMapTooltipClose = () => {
mapTooltip.value.visible = false; mapTooltip.value.visible = false;
}; };
/**
* 处理视频图标点击事件
* 打开视频弹窗并设置视频源
*/
const handleVideoIconClick = () => {
const { data } = mapTooltip.value;
if (data && data.supportVideo) {
selectedVideoMonitor.value = {
id: Date.now().toString(),
title: data.videoTitle || '视频监控',
videoSrc: data.videoSrc || '',
dateRange: new Date().toLocaleDateString(),
hasMegaphone: false,
hasAudio: true,
hasDirectionControl: false
};
showVideoModal.value = true;
}
};
/**
* 处理视频弹窗关闭事件
*/
const handleVideoModalClose = () => {
showVideoModal.value = false;
};
// 线 // 线
const pathLineEntities = ref([]); const pathLineEntities = ref([]);