620 lines
16 KiB
Vue
Raw Normal View History

2026-03-27 17:47:09 +08:00
<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">
2026-04-02 16:35:45 +08:00
<img
class="title_img1"
src="../../assets/RiskWarning_img/位图@2x.png"
alt=""
/>
<img
class="title_img2"
src="../../assets/RiskWarning_img/渝路畅行-风险预警一键响应@2x.png"
alt=""
/>
</div>
</div>
2026-03-27 17:47:09 +08:00
<!-- 四个角的装饰 -->
<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"
2026-04-02 16:35:45 +08:00
v-if="
showCenterCard.type === 'second' || showCenterCard.type === 'third'
"
>
<div
class="card-title"
@click="
showCenterCard.type === 'second'
? openDialog('tongnanTeam')
: showCenterCard.type === 'third'
2026-04-02 16:35:45 +08:00
? 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>
2026-03-27 17:47:09 +08:00
<div class="left">
<left
2026-03-30 15:36:12 +08:00
@openImpactDetail="openDialog('impactPoint')"
@openWarningInfo="openDialog('warningInfo')"
@openImpactPoint="openDialog('impactPoint')"
2026-03-31 18:10:34 +08:00
@openAIResult="openDialog('aiWarningResult')"
@openWarningSituation="openDialog('warningSituation')"
@openResponseStatus="openDialog('responseStatus')"
@openDispatchDistrict="openDialog('dispatchDistrict')"
@showCenterCard="(item) => (showCenterCard = item)"
></left>
2026-03-27 17:47:09 +08:00
</div>
<div class="right">
<right
@openClearanceSituation="openDialog('clearanceSituation')"
@openControlSituation="openDialog('controlSituation')"
></right>
2026-03-27 17:47:09 +08:00
</div>
<!-- 地图中心 -->
<div class="center">
2026-03-30 15:36:12 +08:00
<!-- 地图底层 -->
<div class="map-layer">
2026-03-31 18:10:34 +08:00
<ChongqingMap />
2026-03-30 15:36:12 +08:00
</div>
<!-- 地图遮罩层 -->
<div class="map-mask" aria-hidden="true"></div>
2026-03-27 17:47:09 +08:00
</div>
<div class="bottom">
<bottom></bottom>
</div>
<top class="top" @openAIResult="openDialog('aiWarningResult')"></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')"
/>
2026-03-31 18:10:34 +08:00
<!-- 隧道信息对话框 -->
<tunnelInfoDialog
v-model:visible="dialogVisible.tunnelInfo"
@close="closeDialog('tunnelInfo')"
/>
2026-03-27 17:47:09 +08:00
</div>
</template>
<script setup>
2026-04-03 18:08:42 +08:00
import { ref, onMounted, provide } from "vue";
2026-04-02 16:35:45 +08:00
import useMapStore from "@/map/stores/mapStore";
import { useMapBase } from "../cockpit/composables/useMapBase";
2026-03-27 17:47:09 +08:00
import left from "./left.vue";
import right from "./right.vue";
import bottom from "./bottom.vue";
import top from "./top.vue";
2026-03-31 18:10:34 +08:00
import ChongqingMap from "./component/ChongqingMap.vue";
// 引入所有弹窗组件
2026-04-03 18:08:42 +08:00
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";
// 弹窗显示状态
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,
2026-04-03 18:08:42 +08:00
warningSituation: false,
tunnelInfo: false
});
// 打开弹窗
const openDialog = (dialogName) => {
dialogVisible.value[dialogName] = true;
};
// 关闭弹窗
const closeDialog = (dialogName) => {
2026-03-31 18:10:34 +08:00
// 关闭弹窗时,重置弹窗数据
2026-04-02 16:35:45 +08:00
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);
2026-03-30 15:36:12 +08:00
2026-04-03 18:08:42 +08:00
// 兄弟组件通信机制
const refreshLeftData = ref(null);
// 提供刷新函数给子组件
const setRefreshLeftData = (callback) => {
refreshLeftData.value = callback;
};
// 触发刷新函数
const triggerRefreshLeftData = () => {
if (refreshLeftData.value) {
refreshLeftData.value();
}
};
// 提供通信机制给子组件
provide('setRefreshLeftData', setRefreshLeftData);
provide('triggerRefreshLeftData', triggerRefreshLeftData);
2026-03-30 15:36:12 +08:00
// ==================== 地图状态管理 ====================
2026-04-02 16:35:45 +08:00
const mapStore = useMapStore();
2026-03-30 15:36:12 +08:00
/**
* 加载地图的业务底图与聚焦中心点
*/
2026-04-02 16:35:45 +08:00
const mapBase = useMapBase(mapStore);
2026-03-30 15:36:12 +08:00
// ==================== 生命周期 ====================
/**
* 组件挂载后初始化地图
*/
onMounted(() => {
// 加载地图业务底图 并 聚焦中心点
2026-04-02 16:35:45 +08:00
mapBase.loadBaseData();
});
2026-03-27 17:47:09 +08:00
</script>
<style lang="scss" scoped>
// 视频屏幕自适应 - 基于视口宽度动态调整
// 基准宽度 1920px使用 vw 单位实现自适应
@function vw($px) {
@return calc($px / 1920 * 100vw);
}
2026-03-27 17:47:09 +08:00
.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);
}
2026-03-27 17:47:09 +08:00
.title_img1 {
width: vw(40);
height: vw(40);
min-width: 28px;
min-height: 28px;
2026-03-31 18:10:34 +08:00
object-fit: contain;
}
.title_img2 {
height: vw(40);
2026-04-03 18:08:42 +08:00
min-height: 40px;
2026-03-31 18:10:34 +08:00
width: auto;
2026-04-03 18:08:42 +08:00
width: vw(550);
2026-03-31 18:10:34 +08:00
object-fit: contain;
}
}
2026-03-27 17:47:09 +08:00
.left {
position: absolute;
left: 0;
2026-04-03 18:08:42 +08:00
top: vw(60);
width: 25%;
2026-04-03 18:08:42 +08:00
height: calc(100% - #{vw(60)});
2026-04-02 16:35:45 +08:00
z-index: 2;
2026-03-27 17:47:09 +08:00
}
.right {
position: absolute;
right: 0;
2026-04-03 18:08:42 +08:00
top: vw(60);
width: 25%;
2026-04-03 18:08:42 +08:00
height: calc(100% - #{vw(60)});
2026-04-02 16:35:45 +08:00
z-index: 2;
2026-03-27 17:47:09 +08:00
}
.bottom {
position: absolute;
2026-04-02 16:35:45 +08:00
bottom: 5px;
left: 25%;
width: 50%;
height: 43%;
2026-03-27 17:47:09 +08:00
}
.top {
position: absolute;
2026-04-02 16:35:45 +08:00
top: vw(100);
left: 25%;
width: 50%;
z-index: 2;
// height: 15%;
2026-03-27 17:47:09 +08:00
// background-color: #15293B;
}
.center {
position: absolute;
top: 0;
// left: 25%;
width: 100%;
height: 100%;
2026-04-02 16:35:45 +08:00
z-index: 1;
2026-03-27 17:47:09 +08:00
}
2026-03-30 15:36:12 +08:00
/* 地图底层 - 填满整个容器 */
.map-layer {
position: absolute;
inset: 0;
z-index: 0;
/* 不设置 pointer-events让地图保持可交互 */
}
/* 地图遮罩层 - 覆盖在地图之上 */
.map-mask {
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
/* 不阻挡交互 */
2026-04-02 16:35:45 +08:00
background: url(../../assets/RiskWarning_img/遮罩层.png) no-repeat
center/cover;
2026-03-30 15:36:12 +08:00
}
2026-03-27 17:47:09 +08:00
// 四个角的装饰
.corner {
position: absolute;
2026-04-02 16:35:45 +08:00
width: vw(20);
height: vw(20);
border: 1px solid #40a9ff;
2026-03-27 17:47:09 +08:00
z-index: 100;
pointer-events: none;
&.corner-top-left {
2026-04-03 18:08:42 +08:00
top: vw(60);
left: vw(10);
2026-03-27 17:47:09 +08:00
border-right: none;
border-bottom: none;
}
&.corner-top-right {
2026-04-03 18:08:42 +08:00
top: vw(60);
right: vw(10);
2026-03-27 17:47:09 +08:00
border-left: none;
border-bottom: none;
}
&.corner-bottom-left {
bottom: vw(10);
left: vw(10);
2026-03-27 17:47:09 +08:00
border-right: none;
border-top: none;
}
&.corner-bottom-right {
bottom: 0;
right: vw(10);
2026-03-27 17:47:09 +08:00
border-left: none;
border-top: none;
}
}
.center-info-card-container {
position: absolute;
top: 30%;
2026-04-02 16:35:45 +08:00
left: 32%;
transform: translate(-50%, -50%);
2026-04-02 16:35:45 +08:00
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;
2026-04-02 16:35:45 +08:00
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);
2026-04-02 16:35:45 +08:00
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 {
2026-04-03 18:08:42 +08:00
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;
}
}
}
}
}
}
2026-03-27 17:47:09 +08:00
</style>