Compare commits

..

2 Commits

Author SHA1 Message Date
Zzc
43f7657a53 Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev 2025-11-19 17:06:17 +08:00
Zzc
51e7be95bd feat: 细节调整 2025-11-19 17:06:05 +08:00
13 changed files with 330 additions and 66 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 KiB

View File

@ -82,7 +82,7 @@ const locationInfo = [
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-rows: repeat(2, minmax(0, 1fr));
gap: clamp(10px, vh(14), 18px) clamp(12px, vw(16), 20px);
gap: clamp(4px, vh(6), 8px) clamp(4px, vw(6), 8px);
width: 100%;
height: 100%;
}
@ -91,7 +91,7 @@ const locationInfo = [
.info-card {
display: flex;
align-items: center;
gap: clamp(8px, vw(12), 14px);
gap: 3px;
// padding: clamp(10px, vh(12), 16px) clamp(12px, vw(14), 18px);
// background: rgba(10, 95, 165, 0.15);
border-radius: clamp(6px, vw(8), 10px);
@ -137,9 +137,9 @@ const locationInfo = [
//
.info-value {
margin: 0;
font-size: clamp(15px, vw(18), 22px);
font-size: 12px;
color: #e8f4ff;
font-weight: 600;
// font-weight: 600;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;

View File

@ -2,7 +2,7 @@
<div class="left-panel-wrapper">
<div class="left-panel">
<CollapsiblePanel title="快速感知" subtitle="「灾害分析」">
<template #header-right>
<template #title-icon>
<img
src="../../assets/images/摄像头.png"
alt="摄像头"
@ -96,10 +96,11 @@ const handleStartDispatch = (payload) => {
.left-panel {
// width: vw(464);
height: 100%;
background: url('../../assets/images/SketchPng7ba5c49d9f8f79e6b559d62cfb6b0b0c79616dd8b289f8b62b5cb8adc18c30e7.png') no-repeat;
background: url('../../assets/images/框架左边.png') no-repeat;
background-size: 100% 100%;
overflow-y: auto;
overscroll-behavior: contain;
padding-left: vw(40); //
&::-webkit-scrollbar {
width: vw(6);
@ -128,7 +129,7 @@ const handleStartDispatch = (payload) => {
flex-direction: column;
align-items: flex-start;
gap: vh(12);
width: vw(368);
width: vw(220);
z-index: 10;
}
@ -187,11 +188,12 @@ const handleStartDispatch = (payload) => {
}
.camera-icon {
width: vw(24);
height: vw(24);
margin-right: vw(8);
width: vw(20);
height: vw(20);
margin-left: vw(6);
cursor: pointer;
transition: opacity 0.2s ease;
vertical-align: middle;
&:hover {
opacity: 0.8;

View File

@ -31,9 +31,9 @@
<span class="col-name">{{ item.name }}</span>
<span class="col-dept">{{ item.department || item.type || '-' }}</span>
<span class="col-location">{{ item.distance || item.altitude || '-' }}</span>
<button class="col-action" @click="linkToItem(item)">
<span class="col-action" @click="linkToItem(item)">
联动
</button>
</span>
</div>
</div>
</div>
@ -127,7 +127,8 @@ const getColumnName = (type) => {
}
.table-body {
max-height: vh(200);
min-height: vh(205);
max-height: vh(205);
overflow-y: auto;
&::-webkit-scrollbar {
@ -165,15 +166,15 @@ const getColumnName = (type) => {
.col-action {
padding: vh(4) vw(12);
background: transparent;
border: 1px solid var(--primary-color);
border-radius: vw(4);
// border: 1px solid var(--primary-color);
// border-radius: vw(4);
color: var(--primary-color);
font-size: fs(12);
cursor: pointer;
transition: all 0.3s;
&:hover {
background: var(--primary-color);
// background: var(--primary-color);
color: var(--text-white);
}
}

View File

@ -1,15 +1,17 @@
<template>
<div class="video-monitor-item">
<div class="video-monitor-item__header">
<div class="video-monitor-item" :class="{ 'is-collapsed': isCollapsed }">
<div class="video-monitor-item__header" @click="toggleCollapse">
<span class="video-title">{{ monitor.title }}</span>
<img
src="../../assets/images/展开icon.png"
alt="collapse"
class="collapse-icon"
:class="{ 'is-collapsed': isCollapsed }"
/>
</div>
<div class="video-monitor-item__content">
<transition name="collapse">
<div v-show="!isCollapsed" class="video-monitor-item__content">
<div class="video-placeholder">
<!-- 视频播放器 -->
<video
@ -77,6 +79,7 @@
</div>
</div>
</div>
</transition>
</div>
</template>
@ -92,6 +95,16 @@ const props = defineProps({
defineEmits(['megaphone', 'audio', 'zoom'])
// /
const isCollapsed = ref(false)
/**
* 切换收起/展开状态
*/
const toggleCollapse = () => {
isCollapsed.value = !isCollapsed.value
}
const currentTime = ref('')
const updateTime = () => {
@ -132,6 +145,13 @@ onUnmounted(() => {
padding: 2px;
// border-radius: vw(8);
overflow: hidden;
transition: all 0.3s ease;
//
&.is-collapsed {
background: none;
padding: 0;
}
&__header {
display: flex;
@ -140,6 +160,7 @@ onUnmounted(() => {
padding: vh(10) vw(16);
background: rgba(20, 53, 118, 0.5);
border-bottom: 1px solid var(--border-color);
transition: all 0.3s ease;
.video-title {
color: var(--text-white);
@ -152,11 +173,30 @@ onUnmounted(() => {
width: vw(26);
height: vw(26);
cursor: pointer;
transition: transform 0.3s;
transition: transform 0.3s ease;
// &:hover {
&.is-collapsed {
// transform: rotate(180deg);
// }
}
&:hover {
opacity: 0.8;
}
}
}
// header
&.is-collapsed &__header {
border-bottom: none;
border-radius: vw(8);
}
&__header {
cursor: pointer;
user-select: none;
&:hover {
background: rgba(20, 53, 118, 0.7);
}
}
@ -266,4 +306,23 @@ onUnmounted(() => {
}
}
}
//
.collapse-enter-active,
.collapse-leave-active {
transition: all 0.3s ease;
overflow: hidden;
}
.collapse-enter-from,
.collapse-leave-to {
max-height: 0;
opacity: 0;
}
.collapse-enter-to,
.collapse-leave-from {
max-height: 500px;
opacity: 1;
}
</style>

View File

@ -36,10 +36,11 @@ import CollaborationInfo from './CollaborationInfo.vue'
.right-panel {
// width: vw(486);
height: 100%;
background: url('../../assets/images/SketchPngab2bc23b7e477ddbee76b880e28c1c97d6afb9261784dec29ed08c4e0a34d5b3.png') no-repeat;
background: url('../../assets/images/框架右边.png') no-repeat;
background-size: 100% 100%;
overflow-y: auto;
overscroll-behavior: contain;
padding-right: vw(40); //
&::-webkit-scrollbar {
width: vw(6);

View File

@ -6,6 +6,9 @@
@click="collapsible && toggle()"
>
<PanelHeader :title="title" :subtitle="subtitle">
<template #title-icon>
<slot name="title-icon" />
</template>
<template #extra>
<slot name="header-right" />
<button
@ -16,20 +19,12 @@
:aria-label="isCollapsed ? '展开面板' : '收起面板'"
@click.stop="toggle"
>
<svg
<img
:src="toggleIcon"
alt=""
class="collapsible-panel__toggle-icon"
:class="{ 'is-collapsed': isCollapsed }"
viewBox="0 0 12 12"
fill="none"
>
<path
d="M3 5L6 8L9 5"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</template>
</PanelHeader>
@ -56,6 +51,7 @@
<script setup>
import { computed, ref } from 'vue'
import PanelHeader from './PanelHeader.vue'
import toggleIcon from '../../assets/images/展开icon.png'
const props = defineProps({
/** 面板标题 */
@ -196,13 +192,12 @@ function onAfterLeave(el) {
}
&__toggle-icon {
width: vw(12);
height: vh(12);
color: var(--primary-color);
width: vw(24);
height: auto;
transition: transform 0.3s ease;
&.is-collapsed {
transform: rotate(-90deg);
// transform: rotate(-90deg);
}
}

View File

@ -3,6 +3,7 @@
<div class="panel-header__content">
<span class="panel-header__title">{{ title }}</span>
<span v-if="subtitle" class="panel-header__subtitle">{{ subtitle }}</span>
<slot name="title-icon"></slot>
</div>
<slot name="extra"></slot>
</div>

View File

@ -69,7 +69,8 @@ export const BEFORE_IMAGERY_CONFIG = {
// 影像服务URL
// 格式支持标准瓦片服务的URL模板{z}/{x}/{y} 为瓦片坐标占位符
// url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
// url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/ylzg/zxyj1119/terra_b3dms/tileset.json',
// 图层类型
type: 'UrlTemplate',

View File

@ -26,8 +26,13 @@
<div class="situational-awareness__right-map">
<MapViewer @tool-change="handleMapToolChange" />
</div>
</div>
<!-- 场景标签层 -->
<!-- 地图遮罩层 -->
<div class="situational-awareness__map-mask" aria-hidden="true"></div>
<!-- 场景标签层 - 独立层级显示在遮罩层之上 -->
<div class="situational-awareness__scene-labels-layer">
<!-- 灾前现场实景标签 - 在中间分割线左侧 -->
<SceneLabel
v-if="isCompareMode"
@ -42,25 +47,56 @@
/>
</div>
<!-- 地图遮罩层 -->
<div class="situational-awareness__map-mask" aria-hidden="true"></div>
<!-- 浮动面板层 -->
<div class="situational-awareness__panels-layer">
<Transition name="panel-slide-left">
<div
v-show="!isLeftPanelCollapsed"
class="situational-awareness__panel-column situational-awareness__panel-column--left"
>
<LeftPanel @start-dispatch="handleStartDispatch" />
</div>
</Transition>
<Transition name="panel-slide-right">
<div
class="situational-awareness__center-spacer"
aria-hidden="true"
></div>
<div
v-show="!isRightPanelCollapsed"
class="situational-awareness__panel-column situational-awareness__panel-column--right"
>
<RightPanel />
</div>
</Transition>
</div>
<!-- 折叠按钮层 -->
<div class="situational-awareness__collapse-buttons-layer">
<!-- 左侧折叠按钮 -->
<button
class="situational-awareness__collapse-btn situational-awareness__collapse-btn--left"
:class="{ 'is-collapsed': isLeftPanelCollapsed }"
@click="toggleLeftPanel"
:aria-label="isLeftPanelCollapsed ? '展开左侧面板' : '收起左侧面板'"
>
<img
:src="isLeftPanelCollapsed ? collapseRightArrow : collapseLeftArrow"
alt=""
class="collapse-arrow"
/>
</button>
<!-- 右侧折叠按钮 -->
<button
class="situational-awareness__collapse-btn situational-awareness__collapse-btn--right"
:class="{ 'is-collapsed': isRightPanelCollapsed }"
@click="toggleRightPanel"
:aria-label="isRightPanelCollapsed ? '展开右侧面板' : '收起右侧面板'"
>
<img
:src="isRightPanelCollapsed ? collapseLeftArrow : collapseRightArrow"
alt=""
class="collapse-arrow"
/>
</button>
</div>
<!-- 地图控件层 - 高于遮罩和面板 -->
@ -146,6 +182,10 @@ import soldierIcon from "./assets/images/SketchPngfbec927027ff9e49207749ebaafd22
import deviceIcon from "./assets/images/SketchPng860d54f2a31f5f441fc6a88081224f1e98534bf6d5ca1246e420983bdf690380.png";
import emergencyBaseIcon from "./assets/images/应急基地.png";
//
import collapseLeftArrow from "./assets/images/折叠面板左箭头.png";
import collapseRightArrow from "./assets/images/折叠面板右箭头.png";
// 使
const disasterData = useDisasterData();
@ -196,6 +236,20 @@ const showLoading = ref(false);
//
const rangeCircleEntity = ref(null);
//
const isLeftPanelCollapsed = ref(false);
const isRightPanelCollapsed = ref(false);
//
const toggleLeftPanel = () => {
isLeftPanelCollapsed.value = !isLeftPanelCollapsed.value;
};
//
const toggleRightPanel = () => {
isRightPanelCollapsed.value = !isRightPanelCollapsed.value;
};
// 3D Tiles
const { load3DTileset, waitForTilesetReady } = use3DTiles();
@ -216,6 +270,48 @@ const setupMapClickHandler = (viewer) => {
if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id)) {
const entity = pickedObject.id;
//
if (entity === rangeCircleEntity.value) {
console.log('[index.vue] 点击了范围圈,忽略');
// 穿
const drillPickedObjects = viewer.scene.drillPick(click.position);
let foundMarker = false;
for (const pickedObj of drillPickedObjects) {
if (Cesium.defined(pickedObj.id) && pickedObj.id !== rangeCircleEntity.value) {
const markerEntity = pickedObj.id;
if (markerEntity.properties) {
const type = markerEntity.properties.type?.getValue();
// Tooltip
if (type === 'soldier') {
showMarkerTooltip(viewer, markerEntity, click.position, soldierIcon);
foundMarker = true;
break;
} else if (type === 'device') {
showMarkerTooltip(viewer, markerEntity, click.position, deviceIcon);
foundMarker = true;
break;
} else if (type === 'emergencyBase' || type === 'station') {
const stationName = markerEntity.properties.name?.getValue() || '';
const icon = stationName === '忠县公路交通应急物资储备中心'
? emergencyCenterIcon
: emergencyBaseIcon;
showMarkerTooltip(viewer, markerEntity, click.position, icon);
foundMarker = true;
break;
}
}
}
}
if (!foundMarker) {
hideTooltip();
currentTooltipEntity.value = null;
}
return;
}
// properties
if (entity.properties) {
const type = entity.properties.type?.getValue();
@ -769,6 +865,11 @@ const createOrUpdateRangeCircle = (viewer, radiusKm) => {
}
});
// 穿
if (rangeCircleEntity.value) {
rangeCircleEntity.value.allowPicking = false;
}
console.log(`[index.vue] 已创建/更新范围圈: ${radiusKm}km`);
};
@ -950,7 +1051,9 @@ const showMapTooltip = ({ x, y, title = "", icon = "", data = null }) => {
.situational-awareness__left-map {
width: 0;
visibility: hidden;
opacity: 0;
pointer-events: none;
overflow: hidden;
}
}
@ -958,8 +1061,9 @@ const showMapTooltip = ({ x, y, title = "", icon = "", data = null }) => {
&.is-compare-mode {
.situational-awareness__left-map {
width: 50%;
visibility: visible;
transition: width 0.3s ease;
opacity: 1;
pointer-events: auto;
transition: width 0.3s ease, opacity 0.3s ease;
}
.situational-awareness__right-map {
@ -1010,28 +1114,46 @@ const showMapTooltip = ({ x, y, title = "", icon = "", data = null }) => {
no-repeat;
}
// - grid pointer-events
// -
&__scene-labels-layer {
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none; //
}
// - 使
&__panels-layer {
position: absolute;
inset: 0;
z-index: 2;
display: grid;
grid-template-columns: var(--sa-left-width) 1fr var(--sa-right-width);
grid-auto-rows: 1fr;
gap: var(--sa-gap); //
height: 100%;
padding-top: var(--sa-header-height); // Header
pointer-events: none; //
}
// -
&__panel-column {
position: absolute;
top: var(--sa-header-height); // header
bottom: 0;
display: flex;
flex-direction: column;
gap: var(--sa-gap); //
min-width: 0; //
min-height: 0; // flex
pointer-events: auto; //
//
&--left {
left: 0;
width: var(--sa-left-width);
}
//
&--right {
right: 0;
width: var(--sa-right-width);
}
}
// - 穿
@ -1039,6 +1161,88 @@ const showMapTooltip = ({ x, y, title = "", icon = "", data = null }) => {
pointer-events: none;
}
// -
&__collapse-buttons-layer {
position: absolute;
inset: 0;
z-index: 11; //
pointer-events: none; //
padding-top: var(--sa-header-height); // Header
}
//
&__collapse-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: transparent;
border: none;
cursor: pointer;
pointer-events: auto;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
z-index: 11;
padding: 0;
&:hover {
opacity: 0.8;
}
&:active {
transform: translateY(-50%) scale(0.95);
}
.collapse-arrow {
width: vw(30);
height: auto;
transition: all 0.3s ease;
}
// -
&--left {
left: 0;
}
// -
&--right {
right: 0;
}
}
// -
.panel-slide-left-enter-active,
.panel-slide-left-leave-active {
transition: all 0.3s ease;
}
.panel-slide-left-enter-from {
transform: translateX(-100%);
opacity: 0;
}
.panel-slide-left-leave-to {
transform: translateX(-100%);
opacity: 0;
}
// -
.panel-slide-right-enter-active,
.panel-slide-right-leave-active {
transition: all 0.3s ease;
}
.panel-slide-right-enter-from {
transform: translateX(100%);
opacity: 0;
}
.panel-slide-right-leave-to {
transform: translateX(100%);
opacity: 0;
}
// -
&__controls-layer {
position: absolute;