2026-04-09 14:53:44 +08:00

694 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="main">
<div class="top_title">
<img
class="title_bg"
src="../../assets/RiskWarning_img/一级标题栏bg@2x.png"
alt=""
/>
<div class="title_img_box">
<img
class="title_img1"
src="../../assets/RiskWarning_img/位图@2x.png"
alt=""
/>
<img
class="title_img2"
src="../../assets/RiskWarning_img/渝路畅行-风险预警一键响应@2x.png"
alt=""
/>
</div>
</div>
<!-- 四个角的装饰 -->
<div class="corner corner-top-left"></div>
<div class="corner corner-top-right"></div>
<div class="corner corner-bottom-left"></div>
<div class="corner corner-bottom-right"></div>
<!-- 中心数据展示卡片 -->
<div class="center-info-card-container">
<!-- <div
class="center-info-card"
@click="openDialog('tongnanResponsible')"
v-if="showCenterCard.type === 'first'"
>
<div class="card-title">潼南</div>
<div class="card-content">
<div class="info-item clickable">
<span class="info-label">人数</span>
<span class="info-value">{{ showCenterCard.value }}</span>
<span class="info-unit"></span>
</div>
<div class="info-item">
<span class="info-label">项目</span>
<span class="info-value">2</span>
<span class="info-unit"></span>
</div>
</div>
</div> -->
<div
class="center-info-card"
v-if="
showCenterCard.type === 'second' || showCenterCard.type === 'third'
"
>
<div
class="card-title"
@click="
showCenterCard.type === 'second'
? openDialog('tongnanTeam')
: showCenterCard.type === 'third'
? openDialog('responseSituation')
: ''
"
>
潼南
</div>
<div class="card-content">
<div class="info-item">
<span class="info-label">人数</span>
<span class="info-value">{{ showCenterCard.value }}</span>
<span class="info-unit">人</span>
</div>
<div class="info-item clickable">
<span class="info-label">路段</span>
<span class="info-value">117</span>
<span class="info-unit">条</span>
</div>
</div>
</div>
</div>
<div class="left">
<left
@openImpactDetail="openDialog('impactPoint')"
@openWarningInfo="openDialog('warningInfo')"
@openImpactPoint="openDialog('impactPoint')"
@openAIResult="openDialog('aiWarningResult')"
@openWarningSituation="openDialog('warningSituation')"
@openResponseStatus="openDialog('responseStatus')"
@openDispatchDistrict="openDialog('dispatchDistrict')"
@showCenterCard="(item) => (showCenterCard = item)"
></left>
</div>
<div class="right">
<right
@openResourceDetail="openResourceDetail"
@openClearanceSituation="openDialog('clearanceSituation')"
@openControlSituation="openDialog('controlSituation')"
></right>
</div>
<!-- 地图中心 -->
<div class="center">
<!-- 地图底层 -->
<div class="map-layer">
<ChongqingMap ref="chongqingMapRef" :activeIndex="activeIndex" :dateRange="dateRange" />
</div>
<!-- 地图遮罩层 -->
<div class="map-mask" aria-hidden="true"></div>
</div>
<div class="bottom">
<bottom @changeActiveIndex="changeActiveIndex" @clearMapMarkers="clearMapMarkers"></bottom>
</div>
<top class="top" @openAIResult="openDialog('aiWarningResult')" @dateRangeChange="handleDateRangeChange"></top>
<!-- 响应情况对话框 -->
<responseSituationDiaLog
v-model:visible="dialogVisible.responseSituation"
@close="closeDialog('responseSituation')"
/>
<!-- 预警信息对话框 -->
<warningInfoDialog
v-model:visible="dialogVisible.warningInfo"
@close="closeDialog('warningInfo')"
@responseStatus="openDialog('responseStatus')"
/>
<!-- 事件详情对话框 -->
<eventDetailDialog
v-model:visible="dialogVisible.eventDetail"
@close="closeDialog('eventDetail')"
/>
<!-- 确认对话框 -->
<confirmDialog
v-model:visible="dialogVisible.confirm"
:title="confirmConfig.title"
:message="confirmConfig.message"
:confirm-text="confirmConfig.confirmText"
:cancel-text="confirmConfig.cancelText"
@confirm="closeDialog('confirm')"
@cancel="closeDialog('confirm')"
/>
<!-- 风险点详情对话框 -->
<riskPointDetailDialog
v-model:visible="dialogVisible.riskPointDetail"
@close="closeDialog('riskPointDetail')"
/>
<!-- 影响点情况对话框 -->
<impactPointDialog
v-model:visible="dialogVisible.impactPoint"
@close="closeDialog('impactPoint')"
@detail="openDialog('impactPointDetail')"
/>
<!-- 影响点详情对话框 -->
<impactPointDetailDialog
v-model:visible="dialogVisible.impactPointDetail"
@close="closeDialog('impactPointDetail')"
/>
<!-- 响应点详情对话框 -->
<responsePointDetailDialog
v-model:visible="dialogVisible.responsePointDetail"
@close="closeDialog('responsePointDetail')"
/>
<!-- 响应点信息对话框 -->
<responsePointInfoDialog
v-model:visible="dialogVisible.responsePointInfo"
@close="closeDialog('responsePointInfo')"
/>
<!-- 响应状态对话框 -->
<responseStatusDialog
v-model:visible="dialogVisible.responseStatus"
@close="closeDialog('responseStatus')"
@detail="openDialog('impactPointDetail')"
/>
<!-- AI预警处理结果对话框 -->
<aiWarningResultDialog
v-model:visible="dialogVisible.aiWarningResult"
@close="closeDialog('aiWarningResult')"
/>
<!-- 潼南基本信息对话框 -->
<tongnanInfoDialog
v-model:visible="dialogVisible.tongnanInfo"
@close="closeDialog('tongnanInfo')"
@call="openDialog('confirm')"
/>
<!-- 潼南建设项目责任人明细对话框 -->
<tongnanResponsibleDialog
v-model:visible="dialogVisible.tongnanResponsible"
@close="closeDialog('tongnanResponsible')"
@detail="openDialog('tongnanInfo')"
/>
<!-- 抢通情况对话框 -->
<clearanceSituationDialog
v-model:visible="dialogVisible.clearanceSituation"
@close="closeDialog('clearanceSituation')"
@detail="openDialog('eventDetail')"
/>
<!-- 管控情况对话框 -->
<controlSituationDialog
v-model:visible="dialogVisible.controlSituation"
@close="closeDialog('controlSituation')"
/>
<!-- 调度详情对话框 -->
<dispatchDetailDialog
v-model:visible="dialogVisible.dispatchDetail"
@close="closeDialog('dispatchDetail')"
/>
<!-- 调度区县情况对话框 -->
<dispatchDistrictDialog
v-model:visible="dialogVisible.dispatchDistrict"
@close="closeDialog('dispatchDistrict')"
@dispatchClick="openDialog('dispatchDetail')"
/>
<!-- 潼南护路团队成员对话框 -->
<tongnanTeamDialog
v-model:visible="dialogVisible.tongnanTeam"
@close="closeDialog('tongnanTeam')"
@view="openDialog('tongnanInfo')"
/>
<!-- 预警情况对话框 -->
<warningSituationDialog
v-model:visible="dialogVisible.warningSituation"
@close="closeDialog('warningSituation')"
@impactClick="openDialog('impactPoint')"
/>
<!-- 隧道信息对话框 -->
<tunnelInfoDialog
v-model:visible="dialogVisible.tunnelInfo"
@close="closeDialog('tunnelInfo')"
/>
</div>
</template>
<script setup>
import { ref, onMounted, provide } from "vue";
import useMapStore from "@/map/stores/mapStore";
import { useMapBase } from "../cockpit/composables/useMapBase";
import left from "./left.vue";
import right from "./right.vue";
import bottom from "./bottom.vue";
import top from "./top.vue";
import ChongqingMap from "./component/ChongqingMap.vue";
// 引入所有弹窗组件
import responseSituationDiaLog from "./Dialog/responseSituationDiaLog.vue";
import warningInfoDialog from "./Dialog/warningInfoDialog.vue";
import eventDetailDialog from "./Dialog/eventDetailDialog.vue";
import confirmDialog from "./Dialog/confirmDialog.vue";
import riskPointDetailDialog from "./Dialog/riskPointDetailDialog.vue";
import impactPointDialog from "./Dialog/impactPointDialog.vue";
import impactPointDetailDialog from "./Dialog/impactPointDetailDialog.vue";
import responsePointDetailDialog from "./Dialog/responsePointDetailDialog.vue";
import responsePointInfoDialog from "./Dialog/responsePointInfoDialog.vue";
import responseStatusDialog from "./Dialog/responseStatusDialog.vue";
import aiWarningResultDialog from "./Dialog/aiWarningResultDialog.vue";
import tongnanInfoDialog from "./Dialog/tongnanInfoDialog.vue";
import tongnanResponsibleDialog from "./Dialog/tongnanResponsibleDialog.vue";
import clearanceSituationDialog from "./Dialog/clearanceSituationDialog.vue";
import controlSituationDialog from "./Dialog/controlSituationDialog.vue";
import dispatchDetailDialog from "./Dialog/dispatchDetailDialog.vue";
import dispatchDistrictDialog from "./Dialog/dispatchDistrictDialog.vue";
import tongnanTeamDialog from "./Dialog/tongnanTeamDialog.vue";
import warningSituationDialog from "./Dialog/warningSituationDialog.vue";
import tunnelInfoDialog from "./Dialog/tunnelInfoDialog.vue";
import './component/el-select.scss'
import './component/date-picker-theme.scss'
// 弹窗显示状态
const dialogVisible = ref({
responseSituation: false,
warningInfo: false,
eventDetail: false,
confirm: false,
riskPointDetail: false,
impactPoint: false,
impactPointDetail: false,
responsePointDetail: false,
responsePointInfo: false,
responseStatus: false,
aiWarningResult: false,
tongnanInfo: false,
tongnanResponsible: false,
clearanceSituation: false,
controlSituation: false,
dispatchDetail: false,
dispatchDistrict: false,
tongnanTeam: false,
warningSituation: false,
tunnelInfo: false
});
const activeIndex = ref(0);
// 日期范围
const dateRange = ref([]);
// 处理日期范围变化
const handleDateRangeChange = (val) => {
console.log("日期范围变化:", val);
dateRange.value = val;
};
// 地图组件引用
const chongqingMapRef = ref(null);
// 切换导航项时触发
const changeActiveIndex = (index) => {
activeIndex.value = index;
};
// 打开资源详情(队伍、人员、装备、物资)
const openResourceDetail = (item) => {
console.log("打开资源详情:", item);
// 判断是否为队伍或人员
if (item.label === "全市普通公路抢险队伍" || item.label === "人员") {
// 调用地图组件的获取应急力量方法
if (chongqingMapRef.value) {
chongqingMapRef.value.getEmergencyForceData();
}
}
// 打开对应的弹窗
const key = item.label.toLowerCase().replace(/[^a-z]/g, "");
if (dialogVisible.value[key] !== undefined) {
dialogVisible.value[key] = true;
}
};
// 清除地图标记
const clearMapMarkers = () => {
console.log("清除地图标记");
if (chongqingMapRef.value) {
chongqingMapRef.value.clearProjectMarkers();
}
};
// 打开弹窗
const openDialog = (dialogName) => {
dialogVisible.value[dialogName] = true;
};
// 关闭弹窗
const closeDialog = (dialogName) => {
// 关闭弹窗时,重置弹窗数据
console.log("关闭弹窗", dialogName);
dialogVisible.value[dialogName] = false;
};
// 确认对话框配置
const confirmConfig = ref({
title: "提示",
message: "是否拨打电话?",
confirmText: "确定",
cancelText: "取消",
});
// 打开确认对话框
const openConfirm = (config) => {
confirmConfig.value = { ...confirmConfig.value, ...config };
dialogVisible.value.confirm = true;
};
// 中心信息卡片显示状态
const showCenterCard = ref(false);
// 兄弟组件通信机制
const refreshLeftData = ref(null);
// 提供刷新函数给子组件
const setRefreshLeftData = (callback) => {
refreshLeftData.value = callback;
};
// 触发刷新函数
const triggerRefreshLeftData = () => {
if (refreshLeftData.value) {
refreshLeftData.value();
}
};
// 提供通信机制给子组件
provide('setRefreshLeftData', setRefreshLeftData);
provide('triggerRefreshLeftData', triggerRefreshLeftData);
// ==================== 地图状态管理 ====================
const mapStore = useMapStore();
/**
* 加载地图的业务底图与聚焦中心点
*/
const mapBase = useMapBase(mapStore);
// ==================== 生命周期 ====================
/**
* 组件挂载后初始化地图
*/
onMounted(() => {
// 加载地图业务底图 并 聚焦中心点
mapBase.loadBaseData();
});
</script>
<style lang="scss" scoped>
// 视频屏幕自适应 - 基于视口宽度动态调整
// 基准宽度 1920px使用 vw 单位实现自适应
@function vw($px) {
@return calc($px / 1920 * 100vw);
}
.main {
position: relative;
width: 100%;
height: 100%;
background-image: url("../../assets/RiskWarning_img/遮罩层.png");
background-size: cover;
background-position: center;
}
.top_title {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: vw(100);
z-index: 100;
.title_bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.title_img_box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
gap: vw(10);
}
.title_img1 {
width: vw(40);
height: vw(40);
min-width: 28px;
min-height: 28px;
object-fit: contain;
}
.title_img2 {
height: vw(40);
min-height: 40px;
width: auto;
width: vw(550);
object-fit: contain;
}
}
.left {
position: absolute;
left: 0;
top: vw(60);
width: 25%;
height: calc(100% - #{vw(60)});
z-index: 2;
}
.right {
position: absolute;
right: 0;
top: vw(60);
width: 25%;
height: calc(100% - #{vw(60)});
z-index: 2;
}
.bottom {
position: absolute;
bottom: 5px;
left: 25%;
width: 50%;
height: 43%;
}
.top {
position: absolute;
top: vw(100);
left: 25%;
width: 50%;
z-index: 2;
// height: 15%;
// background-color: #15293B;
}
.center {
position: absolute;
top: 0;
// left: 25%;
width: 100%;
height: 100%;
z-index: 1;
}
/* 地图底层 - 填满整个容器 */
.map-layer {
position: absolute;
inset: 0;
z-index: 0;
/* 不设置 pointer-events让地图保持可交互 */
}
/* 地图遮罩层 - 覆盖在地图之上 */
.map-mask {
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
/* 不阻挡交互 */
background: url(../../assets/RiskWarning_img/遮罩层.png) no-repeat
center/cover;
}
// 四个角的装饰
.corner {
position: absolute;
width: vw(20);
height: vw(20);
border: 1px solid #40a9ff;
z-index: 100;
pointer-events: none;
&.corner-top-left {
top: vw(60);
left: vw(10);
border-right: none;
border-bottom: none;
}
&.corner-top-right {
top: vw(60);
right: vw(10);
border-left: none;
border-bottom: none;
}
&.corner-bottom-left {
bottom: vw(10);
left: vw(10);
border-right: none;
border-top: none;
}
&.corner-bottom-right {
bottom: 0;
right: vw(10);
border-left: none;
border-top: none;
}
}
.center-info-card-container {
position: absolute;
top: 30%;
left: 32%;
transform: translate(-50%, -50%);
width: vw(200);
min-width: 200px;
z-index: 200;
}
// 中心数据展示卡片
.center-info-card {
background: rgba(64, 169, 255, 0.2);
border: 1px solid rgba(64, 169, 255, 0.3);
z-index: 50;
box-shadow:
0 4px 20px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
cursor: pointer;
transition: all 0.3s;
margin-bottom: vw(10);
// &:hover {
// border-color: rgba(64, 169, 255, 0.6);
// box-shadow: 0 6px 30px rgba(64, 169, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1);
// transform: translate(-50%, -52%);
// }
.card-title {
font-size: vw(16);
font-weight: 600;
color: #fff;
margin-bottom: vw(12);
background: rgba(64, 169, 255, 0.8);
padding: vw(16) vw(20);
border-bottom: 1px solid rgba(64, 169, 255, 0.1);
}
.card-content {
padding: 0 vw(20) vw(16) vw(20);
display: flex;
justify-content: space-between;
align-items: center;
.info-item {
display: flex;
align-items: baseline;
gap: vw(4);
.info-label {
font-size: vw(13);
color: rgba(255, 255, 255, 0.7);
}
.info-value {
font-size: vw(24);
font-weight: 700;
color: #40a9ff;
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
}
.info-unit {
font-size: vw(14);
color: rgba(255, 255, 255, 0.6);
}
&.clickable {
cursor: pointer;
transition: all 0.3s;
&:hover {
.info-value {
color: #69c0ff;
text-shadow: 0 0 15px rgba(105, 192, 255, 0.8);
}
.info-label,
.info-unit {
color: #fff;
}
}
}
}
}
}
// 下拉选项浮窗
.el-popper {
// 下拉选项
.el-select-dropdown {
background: #122c46;
.el-select-dropdown__item {
display: flex;
align-items: center;
color: #fff;
background-color: #122c46;
text-stroke: 0px #3a6fbf;
-webkit-text-stroke: 0px #3a6fbf;
height: 40px;
&.is-hovering {
background: #0f2e6d;
font-weight: bold;
color: #7bc8ef;
text-stroke: 0px #7bc8ef;
font-style: normal;
text-transform: none;
-webkit-text-stroke: 0px #7bc8ef;
}
}
}
}
</style>