673 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>
<!-- 中心数据展示卡片 -->
<centerInfoCard
:type="showCenterCard.type"
:peopleCount="showCenterCard.value"
roadCount="117"
@click="handleCenterCardClick"
/>
<div class="left">
<left
:dateRange="getdateRange"
@openImpactDetail="openDialog('impactPoint')"
@openWarningInfo="openDialog('warningInfo')"
@openImpactPoint="openDialog('impactPoint')"
@openAIResult="openDialog('aiWarningResult')"
@openWarningSituation="openDialog('warningSituation')"
@openResponseStatus="openDialog('responseStatus')"
@openDispatchDistrict="openDialog('dispatchDistrict')"
@showCenterCard="(item) => handleCenterCardClick(item)"
></left>
</div>
<div class="right">
<right
:dateRange="getdateRange"
@openResourceDetail="openResourceDetail"
@openClearanceSituation="openDialog('clearanceSituation')"
@openControlSituation="openDialog('controlSituation')"
></right>
</div>
<!-- 地图中心 -->
<div class="center">
<!-- 地图底层 -->
<div class="map-layer">
<ChongqingMap
ref="chongqingMapRef"
:activeitem="activeitem"
:dateRange="getdateRange"
:roadItem="roadItem"
@districtClick="handleDistrictClick"
/>
</div>
<!-- 地图遮罩层 -->
<div class="map-mask" aria-hidden="true"></div>
</div>
<div class="bottom">
<bottom
@roadItemClick="roadItemClick"
@changeActiveIndex="changeActiveIndex"
@clearMapMarkers="clearMapMarkers"
></bottom>
</div>
<top
class="top"
@openAIResult="openDialog('aiWarningResult')"
@dateRangeChange="handleDateRangeChange"
></top>
<div>
<!-- 农村公路对话框 -->
<responseSituationDiaLog
v-model:visible="dialogVisible.responseSituation"
:allCountyData="allCountyData"
@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
:handleImpactItem="handleImpactItem"
v-model:visible="dialogVisible.impactPoint"
@close="closeDialog('impactPoint')"
@detail="openDialog('impactPointDetail')"
@itemClick="handleImpactPointClick"
/>
<!-- 影响点详情对话框 -->
<impactPointDetailDialog
:item="impactPointDetailItem"
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('responsePointDetail')"
/>
<!-- 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"
:allCountyData="allCountyData"
@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"
:allCountyData="allCountyData"
@close="closeDialog('tongnanTeam')"
@view="openDialog('tongnanInfo')"
/>
<!-- 预警情况对话框 -->
<warningSituationDialog
v-model:visible="dialogVisible.warningSituation"
@close="closeDialog('warningSituation')"
@impactClick="openDialog('impactPoint')"
@impactClickItem="handleImpactClickItem"
/>
<!-- 隧道信息对话框 -->
<tunnelInfoDialog
v-model:visible="dialogVisible.tunnelInfo"
@close="closeDialog('tunnelInfo')"
/>
</div>
</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 centerInfoCard from "./Dialog/centerInfoCard.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 activeitem = ref({});
// 日期范围
const getdateRange = ref([]);
// 处理日期范围变化
const handleDateRangeChange = (val) => {
console.log("日期范围变化:", val);
getdateRange.value = val;
};
// 地图组件引用
const chongqingMapRef = ref(null);
// 切换导航项时触发
const changeActiveIndex = (index) => {
activeitem.value = index;
};
const roadItem = ref({});
const roadItemClick = (item) => {
console.log("点击路段:", item);
roadItem.value = item;
};
// 打开资源详情(队伍、人员、装备、物资)
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 impactPointDetailItem = ref({});
// 处理影响点点击
const handleImpactPointClick = (item) => {
console.log("影响点点击:", item);
impactPointDetailItem.value = item;
};
const handleImpactItem = ref({});
const handleImpactClickItem = (item) => {
console.log("影响点点击详情:", item);
handleImpactItem.value = item;
};
// 关闭弹窗
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 allCountyData = ref({});
// 处理区县点击
const handleDistrictClick = (item) => {
console.log("区县点击:", item);
allCountyData.value = item;
if (item.data.roadType == "national") {
// 国省道
openDialog("tongnanTeam");
} else if (item.data.roadType == "rural") {
openDialog("responseSituation");
} else if (item.data.type == "project" && item.data.roadType == "-") {
// 项目
openDialog("tongnanResponsible");
}
};
// 处理中心卡片点击
const handleCenterCardClick = (item) => {
console.log("中心卡片点击:", item);
// 调用地图组件的方法打开中心信息卡片弹窗
if (chongqingMapRef.value && item.data) {
const cardData = {
title: getCardTitleByType(item.type),
dataList: item.data,
};
chongqingMapRef.value.openCenterCard(cardData);
// 如果数据中包含区县信息,定位到第一个区县
if (
item.data.length > 0 &&
(item.data[0].countyName || item.data[0].name)
) {
const firstCounty = item.data[0].countyName || item.data[0].name;
chongqingMapRef.value.locateToDistrict(firstCounty);
}
}
};
// 根据类型获取卡片标题
const getCardTitleByType = (type) => {
const titleMap = {
first: "国省道调度",
second: "农村公路调度",
third: "建设工程调度",
};
return titleMap[type] || "调度统计";
};
const handleCenterCardClickType = (item) => {
console.log(item.data);
showCenterCard.value = true;
// if (item.type === "second") {
// openDialog("tongnanTeam");
// } else if (item.type === "third") {
// openDialog("responseSituation");
// } else if (item.type === "first") {
// openDialog("warningSituation");
// }
};
// 兄弟组件通信机制
const refreshLeftData = ref(null);
const refreshRightData = ref(null);
// 提供刷新函数给子组件
const setRefreshLeftData = (callback) => {
refreshLeftData.value = callback;
};
// 提供刷新函数给 right.vue
const setRefreshRightData = (callback) => {
refreshRightData.value = callback;
};
// 触发刷新函数
const triggerRefreshLeftData = () => {
if (refreshLeftData.value) {
refreshLeftData.value();
}
// 同时触发 right.vue 刷新
if (refreshRightData.value) {
refreshRightData.value();
}
};
// 提供通信机制给子组件
provide("setRefreshLeftData", setRefreshLeftData);
provide("triggerRefreshLeftData", triggerRefreshLeftData);
provide("setRefreshRightData", setRefreshRightData);
provide("getdateRange", getdateRange);
// ==================== 地图状态管理 ====================
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: 3;
}
.right {
position: absolute;
right: 0;
top: vw(60);
width: 25%;
height: calc(100% - #{vw(60)});
z-index: 3;
}
.bottom {
position: absolute;
bottom: 5px;
left: 25%;
width: 50%;
height: 43%;
}
.top {
position: absolute;
top: vw(100);
left: 25%;
width: 50%;
z-index: 4;
// height: 15%;
// background-color: #15293B;
}
.center {
position: absolute;
top: 0;
// left: 25%;
width: 100%;
height: 100%;
z-index: 2;
}
/* 地图底层 - 填满整个容器 */
.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;
}
}
// 下拉选项浮窗
.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>