Compare commits

..

2 Commits

Author SHA1 Message Date
Zzc
9dd95e306b Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev 2025-11-19 14:05:01 +08:00
Zzc
157bae2ea0 feat(situational-awareness): 添加场景标签和调度加载动画
- 添加SceneLabel组件,用于在对比模式下标记灾害场景
- 更新页面标题为“渝路智管-应急保通事件处置”
- 修改面板标题,并添加强制调度的事件处理
- 使用条件图标增强地图标记,用于应急中心
- 更新3D模型配置URL,并在调度开始时添加加载动画
- 替换面板和工具提示的背景图片
- 添加新的图片素材,包括危险图标和加载GIF
2025-11-19 14:04:48 +08:00
18 changed files with 210 additions and 20 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -10,7 +10,7 @@
</CollapsiblePanel> </CollapsiblePanel>
<CollapsiblePanel title="快速响应" subtitle="「力量调度」"> <CollapsiblePanel title="快速响应" subtitle="「力量调度」">
<ForceDispatch /> <ForceDispatch @start-dispatch="handleStartDispatch" />
</CollapsiblePanel> </CollapsiblePanel>
</div> </div>
@ -64,6 +64,16 @@ const isLocationOpen = ref(true)
const toggleLocation = () => { const toggleLocation = () => {
isLocationOpen.value = !isLocationOpen.value isLocationOpen.value = !isLocationOpen.value
} }
//
const emit = defineEmits(['start-dispatch'])
/**
* 处理力量调度启动事件向上传递给父组件
*/
const handleStartDispatch = (payload) => {
emit('start-dispatch', payload)
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -12,7 +12,7 @@
<div class="logo-section"> <div class="logo-section">
<img src="../assets/images/3ad857a9ed044c12b0e3b4345af6be59_mergeImage.png" alt="logo" class="logo-image" /> <img src="../assets/images/3ad857a9ed044c12b0e3b4345af6be59_mergeImage.png" alt="logo" class="logo-image" />
</div> </div>
<h1 class="page-title">渝路智管-公路安全畅通运行管理</h1> <h1 class="page-title">渝路智管-应急保通事件处置</h1>
</div> </div>
<!-- <div class="page-header__right"> <!-- <div class="page-header__right">
@ -123,7 +123,7 @@ const handleBack = () => {
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
font-size: fs(36); font-size: fs(36);
letter-spacing: vw(1.8); letter-spacing: vw(1.8);
font-family: FZLTTHJW--GB1-0, sans-serif; // font-family: FZLTTHJW--GB1-0, sans-serif;
white-space: nowrap; white-space: nowrap;
margin: 0; margin: 0;
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="right-panel"> <div class="right-panel">
<CollapsiblePanel title="现场处置" subtitle="「调度指挥」"> <CollapsiblePanel title="快速处置" subtitle="「调度指挥」">
<DispatchCommand /> <DispatchCommand />
</CollapsiblePanel> </CollapsiblePanel>

View File

@ -0,0 +1,85 @@
<template>
<div class="scene-label" :class="labelClass">
<div class="scene-label__content">
<img :src="iconSrc" alt="scene" class="scene-label__icon" />
<span class="scene-label__text">{{ text }}</span>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import sceneIcon from '../assets/images/SketchPng08621fb3b35614299e29352b8d67ad9c2c7dccf7b9c17d042492671e3bbe19f8.png'
const props = defineProps({
/**
* 标签文本
*/
text: {
type: String,
required: true
},
/**
* 标签位置
* - 'center-left': 对比模式中间分割线的左侧
* - 'right-left': 右侧面板的左边
*/
position: {
type: String,
default: 'right-left',
validator: (value) => ['center-left', 'right-left'].includes(value)
}
})
const labelClass = computed(() => {
return `scene-label--${props.position}`
})
const iconSrc = sceneIcon
</script>
<style scoped lang="scss">
@use '@/styles/mixins.scss' as *;
.scene-label {
position: absolute;
top: calc(var(--sa-header-height));
z-index: 10;
pointer-events: none;
// 线
&--center-left {
left: 50%;
transform: translateX(calc(-100% - vw(10)));
}
//
&--right-left {
left: calc(100% - var(--sa-right-width));
transform: translateX(calc(-100% - vw(10)));
}
&__content {
display: flex;
align-items: center;
gap: vw(6);
padding: vw(5) vw(10);
background: rgba(20, 53, 118, 1);
border: 1px solid var(--border-color);
border-radius: vw(8);
}
&__icon {
width: vw(32);
height: vw(32);
}
&__text {
color: var(--text-white);
font-size: fs(15);
font-family: SourceHanSansCN-Medium, sans-serif;
font-weight: 500;
white-space: nowrap;
}
}
</style>

View File

@ -218,7 +218,7 @@ function onAfterLeave(el) {
inset: 0; inset: 0;
border-style: solid; border-style: solid;
border-width: vh(25) vw(30); border-width: vh(25) vw(30);
border-image-source: url('../../assets/images/面板bg.png'); border-image-source: url('../../assets/images/通用卡片bg.png');
border-image-slice: 25 30 25 30 fill; border-image-slice: 25 30 25 30 fill;
border-image-width: vh(25) vw(30); border-image-width: vh(25) vw(30);
border-image-repeat: stretch; border-image-repeat: stretch;

View File

@ -268,7 +268,7 @@ const handleClose = () => {
.map-tooltip__background { .map-tooltip__background {
position: relative; position: relative;
padding: vh(14) vw(18); padding: vh(14) vw(18);
background: url('../../assets/images/Tooltip/tooltipBg.png') no-repeat; background: url('../../assets/images/Tooltip/弹窗bg.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
border-radius: vw(8); border-radius: vw(8);
box-shadow: 0 vw(8) vw(24) rgba(0, 0, 0, 0.5); box-shadow: 0 vw(8) vw(24) rgba(0, 0, 0, 0.5);

View File

@ -31,12 +31,12 @@ defineProps({
justify-content: space-between; justify-content: space-between;
width: vw(400); width: vw(400);
height: vh(43); height: vh(43);
background-image: url('../../assets/images/SketchPng2800be582615dbc26e07b4d56d3fc22a0517aa84065b4d6502827c05f18ca17d.png'); background-image: url('../../assets/images/标题栏bg1.png');
background-position: 0 -1px; background-position: 0 -1px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: vw(400) vh(45); background-size: vw(400) vh(45);
padding: 0 vw(20); padding: 0 vw(20);
margin-bottom: vh(20); margin-bottom: vw(10);
&__content { &__content {
display: flex; display: flex;

View File

@ -6,6 +6,7 @@ import { cesiumDataConfig } from '../config/cesiumData'
import soldierIcon from '../assets/images/SketchPngfbec927027ff9e49207749ebaafd229429315341fda199251b6dfb1723ff17fb.png' import soldierIcon from '../assets/images/SketchPngfbec927027ff9e49207749ebaafd229429315341fda199251b6dfb1723ff17fb.png'
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 emergencyCenterIcon from '../assets/images/应急中心.png'
// 默认高度偏移(米)- 与 WuRenJi 保持一致 // 默认高度偏移(米)- 与 WuRenJi 保持一致
const DEFAULT_HEIGHT_OFFSET = 100 const DEFAULT_HEIGHT_OFFSET = 100
@ -625,10 +626,15 @@ export function useMapMarkers() {
false false
) )
// 根据养护站名称选择图标
const stationIcon = station.stationName === '忠县公路交通应急物资储备中心'
? emergencyCenterIcon
: emergencyBaseIcon
const entity = viewer.entities.add({ const entity = viewer.entities.add({
position: result.position, position: result.position,
billboard: { billboard: {
image: emergencyBaseIcon, image: stationIcon,
width: 48, width: 48,
height: 48, height: 48,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, verticalOrigin: Cesium.VerticalOrigin.BOTTOM,

View File

@ -42,7 +42,9 @@ export const AFTER_3DTILES_CONFIG = {
name: '灾后3D模型', name: '灾后3D模型',
// 3D Tiles 服务 URL // 3D Tiles 服务 URL
url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/S107/terra_b3dms/tileset.json', // url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/S107/terra_b3dms/tileset.json',
url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/ylzg/zxyj1119/terra_b3dms/tileset.json',
// 默认可见性(初始化时灾后模型默认显示) // 默认可见性(初始化时灾后模型默认显示)
visible: true, visible: true,

View File

@ -26,6 +26,20 @@
<div class="situational-awareness__right-map"> <div class="situational-awareness__right-map">
<MapViewer @tool-change="handleMapToolChange" /> <MapViewer @tool-change="handleMapToolChange" />
</div> </div>
<!-- 场景标签层 -->
<!-- 灾前现场实景标签 - 在中间分割线左侧 -->
<SceneLabel
v-if="isCompareMode"
text="灾前现场实景"
position="center-left"
/>
<!-- 灾后现场实景标签 - 在右侧面板左边 -->
<SceneLabel
text="灾后现场实景"
position="right-left"
/>
</div> </div>
<!-- 地图遮罩层 --> <!-- 地图遮罩层 -->
@ -36,7 +50,7 @@
<div <div
class="situational-awareness__panel-column situational-awareness__panel-column--left" class="situational-awareness__panel-column situational-awareness__panel-column--left"
> >
<LeftPanel /> <LeftPanel @start-dispatch="handleStartDispatch" />
</div> </div>
<div <div
class="situational-awareness__center-spacer" class="situational-awareness__center-spacer"
@ -78,6 +92,15 @@
</template> </template>
</MapTooltip> </MapTooltip>
</div> </div>
<!-- 加载动画层 - 一键启动后显示 -->
<div v-if="showLoading" class="situational-awareness__loading-layer">
<img
src="./assets/images/加载gif.gif"
alt="加载中"
class="situational-awareness__loading-gif"
/>
</div>
</div> </div>
<!-- 弹窗组件 --> <!-- 弹窗组件 -->
@ -107,6 +130,7 @@ 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 MapTooltip from "./components/shared/MapTooltip.vue"; import MapTooltip from "./components/shared/MapTooltip.vue";
import SceneLabel from "./components/SceneLabel.vue";
import { useDisasterData } from "./composables/useDisasterData"; import { useDisasterData } from "./composables/useDisasterData";
import { useDualMapCompare } from "./composables/useDualMapCompare"; import { useDualMapCompare } from "./composables/useDualMapCompare";
import { useMapMarkers } from "./composables/useMapMarkers"; import { useMapMarkers } from "./composables/useMapMarkers";
@ -117,6 +141,7 @@ import { request } from "@shared/utils/request";
// //
import emergencyCenterIcon from "./assets/images/应急中心.png"; import emergencyCenterIcon from "./assets/images/应急中心.png";
import dangerIcon from "./assets/images/danger.png";
import soldierIcon from "./assets/images/SketchPngfbec927027ff9e49207749ebaafd229429315341fda199251b6dfb1723ff17fb.png"; import soldierIcon from "./assets/images/SketchPngfbec927027ff9e49207749ebaafd229429315341fda199251b6dfb1723ff17fb.png";
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";
@ -160,6 +185,9 @@ const { tooltipState: mapTooltip, showTooltip, hideTooltip, updateTooltipPositio
// tooltip // tooltip
const currentTooltipEntity = ref(null); const currentTooltipEntity = ref(null);
//
const showLoading = ref(false);
// 3D Tiles // 3D Tiles
const { load3DTileset, waitForTilesetReady } = use3DTiles(); const { load3DTileset, waitForTilesetReady } = use3DTiles();
@ -190,7 +218,12 @@ const setupMapClickHandler = (viewer) => {
} else if (type === 'device') { } else if (type === 'device') {
showMarkerTooltip(viewer, entity, click.position, deviceIcon); showMarkerTooltip(viewer, entity, click.position, deviceIcon);
} else if (type === 'emergencyBase' || type === 'station') { } else if (type === 'emergencyBase' || type === 'station') {
showMarkerTooltip(viewer, entity, click.position, emergencyBaseIcon); // 使
const stationName = entity.properties.name?.getValue() || '';
const icon = stationName === '忠县公路交通应急物资储备中心'
? emergencyCenterIcon
: emergencyBaseIcon;
showMarkerTooltip(viewer, entity, click.position, icon);
} }
} }
} else { } else {
@ -274,11 +307,26 @@ const showMarkerTooltip = (viewer, entity, screenPosition, icon) => {
{ label: '距离', value: properties.distance?.getValue() || '-' } { label: '距离', value: properties.distance?.getValue() || '-' }
); );
} else if (type === 'station') { } else if (type === 'station') {
title = '养护站'; const stationName = properties.name?.getValue() || '';
fields.push( const distance = properties.distance?.getValue() || 0;
{ label: '名称', value: properties.name?.getValue() || '-' },
{ label: '距离', value: `${properties.distance?.getValue() || 0}公里` } //
); if (stationName === '忠县公路交通应急物资储备中心') {
title = '应急中心';
fields.push(
{ label: '名称', value: '忠县应急中心' },
{ label: '行政等级', value: '国道' },
{ label: '隶属单位', value: '交通公路部门' },
{ label: '位置信息', value: `目前为止距离现场${distance}公里` }
);
} else {
// tooltip
title = '养护站';
fields.push(
{ label: '名称', value: stationName || '-' },
{ label: '距离', value: `${distance}公里` }
);
}
} }
// Tooltip使 // Tooltip使
@ -357,9 +405,9 @@ onMounted(() => {
0 0
), ),
billboard: { billboard: {
image: emergencyCenterIcon, image: dangerIcon,
width: 36, width: 36,
height: 40, height: 36,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance: Number.POSITIVE_INFINITY, disableDepthTestDistance: Number.POSITIVE_INFINITY,
@ -614,6 +662,22 @@ const handleMapTooltipClose = () => {
mapTooltip.value.visible = false; mapTooltip.value.visible = false;
}; };
/**
* 处理力量调度启动事件
* 显示加载动画3秒后自动隐藏
*/
const handleStartDispatch = (payload) => {
console.log('[index.vue] 启动力量调度:', payload);
//
showLoading.value = true;
// 3
setTimeout(() => {
showLoading.value = false;
}, 3000);
};
/** /**
* 在指定屏幕坐标显示地图 Tooltip * 在指定屏幕坐标显示地图 Tooltip
* *
@ -745,7 +809,7 @@ const showMapTooltip = ({ x, y, title = "", icon = "", data = null }) => {
--sa-gap: calc(16 / 1920 * var(--cq-inline-100, 100vw)); --sa-gap: calc(16 / 1920 * var(--cq-inline-100, 100vw));
--sa-padding: calc(16 / 1920 * var(--cq-inline-100, 100vw)); --sa-padding: calc(16 / 1920 * var(--cq-inline-100, 100vw));
--sa-header-height: calc( --sa-header-height: calc(
121 / 1080 * var(--cq-block-100, 100vh) 131 / 1080 * var(--cq-block-100, 100vh)
); // Header ); // Header
--sa-min-width: 1280px; --sa-min-width: 1280px;
--sa-min-height: 720px; --sa-min-height: 720px;
@ -908,6 +972,29 @@ const showMapTooltip = ({ x, y, title = "", icon = "", data = null }) => {
z-index: 4; // z-index: 4; //
pointer-events: none; // 穿 pointer-events: none; // 穿
} }
// -
&__loading-layer {
position: absolute;
top: calc(var(--sa-header-height) + vh(20));
left: 0;
right: 0;
// bottom: 0;
z-index: 5; // Tooltip
display: flex;
align-items: center;
justify-content: center;
pointer-events: none; // 穿
}
// GIF
&__loading-gif {
width: auto;
height: auto;
max-width: 80%;
max-height: 60%;
object-fit: contain;
}
} }
// Tooltip // Tooltip