1424 lines
37 KiB
Vue
Raw Normal View History

2026-03-27 17:47:09 +08:00
<template>
<div class="left-panel">
<!-- 智能研判头部 -->
2026-04-02 16:35:45 +08:00
<SectionHeader title="智能研判">
2026-03-31 18:10:34 +08:00
<template #left>
<div class="filter-header">
2026-04-02 16:35:45 +08:00
<span class="title">智能研判</span>
2026-03-31 18:10:34 +08:00
<img
class="filter-icon-ai"
src="../../assets/RiskWarning_img/AI1@2x.png"
alt=""
@click="handleAIClick"
/>
</div>
</template>
</SectionHeader>
2026-03-27 17:47:09 +08:00
<!-- 气象预警 -->
<div class="weather-warning-section">
<div class="section-title">气象预警</div>
<div class="warning-cards">
<div
v-for="(item, index) in weatherWarningData"
:key="index"
class="warning-card"
:class="item.class"
@click="handleWarningCardClick(item)"
2026-03-27 17:47:09 +08:00
>
<img
class="card-icon"
src="../../assets/RiskWarning_img/气象预警图标@2x.png"
alt=""
/>
<div class="card-info">
2026-04-02 16:35:45 +08:00
<div class="card-num mt_5">{{ item.value }}</div>
<div class="card-label mb_5">{{ item.label }}</div>
2026-03-27 17:47:09 +08:00
</div>
</div>
</div>
</div>
<!-- 影响点概况 -->
<div class="impact-section">
<div class="impact-header">
<div class="impact-title">影响点概况</div>
<div class="impact-detail clickable" @click="handleImpactDetailClick">
2026-03-31 18:10:34 +08:00
一键清单(影响点)
</div>
2026-03-27 17:47:09 +08:00
</div>
<div class="chart-container">
<div class="chart-y-label">数量</div>
<div class="bar-chart f1">
2026-03-31 18:10:34 +08:00
<div
v-for="(item, index) in impactData"
:key="index"
class="bar-item"
>
<div
class="bar"
2026-04-03 18:08:42 +08:00
:style="{ height: getBarHeight(item) + '%' }"
2026-03-31 18:10:34 +08:00
></div>
2026-04-03 18:08:42 +08:00
<div class="bar-value">{{ item.count }}</div>
<div class="bar-label">{{ item.name }}</div>
2026-03-27 17:47:09 +08:00
</div>
</div>
<div class="chart-x-label">类型</div>
</div>
</div>
2026-03-31 18:10:34 +08:00
<!-- 影响公路类型情况 -->
<div class="road-type-section">
<div class="section-title">影响公路类型情况</div>
<div class="road-type-cards">
2026-04-03 18:08:42 +08:00
<div
class="road-card"
v-for="(item, index) in roadTypeData"
:key="index"
>
<span class="card-label">{{ item.extension }}</span>
<span class="card-value">{{ item.count }}</span>
2026-03-31 18:10:34 +08:00
</div>
</div>
</div>
2026-03-27 17:47:09 +08:00
<!-- 区县统计表格 -->
<div class="district-table-section">
<el-table
:data="districtData"
2026-04-02 16:35:45 +08:00
style="
width: 100%;
background: transparent;
font-size: 12px;
height: 150px;
"
2026-03-27 17:47:09 +08:00
:header-cell-style="headerCellStyle"
:cell-style="cellStyle"
size="small"
2026-03-31 18:10:34 +08:00
:height="tableHeight"
:scroll="{ y: true }"
2026-03-27 17:47:09 +08:00
>
2026-03-31 18:10:34 +08:00
<el-table-column prop="name" label="区县名称" :min-width="vw(80)" />
2026-04-03 18:08:42 +08:00
<el-table-column
prop="roadSectionCount"
label="路段"
:min-width="vw(50)"
/>
<el-table-column prop="bridgeCount" label="桥梁" :min-width="vw(50)" />
<el-table-column prop="tunnelCount" label="隧道" :min-width="vw(50)" />
<el-table-column prop="slopeCount" label="边坡" :min-width="vw(50)" />
<el-table-column prop="projectCount" label="项目" :min-width="vw(50)" />
2026-03-27 17:47:09 +08:00
</el-table>
</div>
<!-- 响应调度 -->
<div class="response-section">
<SectionHeader title="响应调度">
<template #right>
<div class="header-filters">
<span class="filter-item active" @click="handleDateRangeClick()"
>本轮</span
>
2026-03-27 17:47:09 +08:00
<div class="date-range-wrapper">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
size="small"
popper-class="custom-date-picker"
:teleported="false"
2026-03-27 17:47:09 +08:00
:prefix-icon="Calendar"
/>
</div>
</div>
</template>
</SectionHeader>
<!-- 6个统计项 -->
<div class="stats-grid">
<div
v-for="(item, index) in responseStats"
:key="index"
class="stat-item"
:class="{
clickable:
item.label === '叫应总数' ||
item.label === '已回应数' ||
item.label === '调度区县数',
}"
@click="handleStatClick(item)"
>
2026-03-27 17:47:09 +08:00
<!-- <div class="stat-icon" :class="item.iconClass"></div> -->
<img class="stat-icon" :src="item.img" alt="" />
<div class="stat-info">
<div class="stat-num">{{ item.value }}</div>
<div class="stat-label">{{ item.label }}</div>
</div>
</div>
</div>
<!-- 3个调度清单卡片 -->
<div class="dispatch-cards">
<div
v-for="(item, index) in dispatchList"
:key="index"
2026-04-03 18:08:42 +08:00
class="dispatch-card clickable"
@click="handleDispatchCardClick(item)"
>
2026-03-31 18:10:34 +08:00
<div class="card-num">
{{ item.value }}<span class="unit"></span>
</div>
2026-03-27 17:47:09 +08:00
<div class="card-label">{{ item.label }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
2026-04-03 18:08:42 +08:00
import { ref, computed, onMounted, watch, inject } from "vue";
2026-04-02 17:27:59 +08:00
import { request } from "@/utils/request";
2026-03-27 17:47:09 +08:00
import SectionHeader from "./component/sectionHeader.vue";
2026-04-03 18:08:42 +08:00
// 导入图片资源
import imgCall from "../../assets/RiskWarning_img/回应icon@2x.png";
import imgReply from "../../assets/RiskWarning_img/已回应icon@2x.png";
import imgRate from "../../assets/RiskWarning_img/回应率icon@2x.png";
import imgDistrict from "../../assets/RiskWarning_img/区县icon@2x.png";
import imgHelp from "../../assets/RiskWarning_img/响应图标5@2x.png";
import imgCheck from "../../assets/RiskWarning_img/抽查人数icon@2x.png";
// 注入兄弟组件通信机制
const setRefreshLeftData = inject("setRefreshLeftData");
// 注入日期范围
const getdateRange = inject("getdateRange", ref([]));
2026-04-03 18:08:42 +08:00
// 监听日期范围变化,当获取到数据时重新加载
2026-04-03 18:08:42 +08:00
watch(
() => getdateRange.value,
2026-04-03 18:08:42 +08:00
(newVal) => {
console.log("left.vue 日期范围变化:", newVal);
init();
2026-04-03 18:08:42 +08:00
},
{ deep: true },
2026-04-03 18:08:42 +08:00
);
onMounted(() => {
init();
2026-04-03 18:08:42 +08:00
// 注册刷新函数给父组件
if (setRefreshLeftData) {
setRefreshLeftData(init);
}
});
const init = () => {
roadTypeLoad();
districtLoadLoad();
dispatchLoadLoad();
scheduleStatisticsByCountyLoad();
2026-04-03 18:08:42 +08:00
loadData();
loadBarChartData();
};
2026-03-27 17:47:09 +08:00
const emit = defineEmits([
"openWarningInfo",
"openImpactPoint",
"openWarningSituation",
"openResponseStatus",
"openDispatchDistrict",
"openImpactDetail",
"showCenterCard",
2026-04-16 14:03:39 +08:00
"warningClick",
]);
// 点击统计项
const handleStatClick = (item) => {
if (item.label === "叫应总数") {
emit("openWarningInfo");
} else if (item.label === "已回应数") {
emit("openResponseStatus");
} else if (item.label === "调度区县数") {
emit("openDispatchDistrict");
}
};
// 点击气象预警卡片
const handleWarningCardClick = (item) => {
2026-04-16 14:03:39 +08:00
console.log("item:", item);
emit("openWarningSituation", item);
2026-04-16 14:03:39 +08:00
// 传递日期范围
emit("warningClick", item);
};
// 点击影响点明细
const handleImpactDetailClick = () => {
emit("openImpactDetail");
};
// 点击调度清单卡片
const handleDispatchCardClick = (item) => {
2026-04-03 18:08:42 +08:00
if (item.label === dispatchList.value[0].label) {
emit("showCenterCard", {
2026-04-03 18:08:42 +08:00
type: "second",
value: item.value,
data: nationalarr.value,
});
2026-04-03 18:08:42 +08:00
} else if (item.label === dispatchList.value[1].label) {
emit("showCenterCard", {
2026-04-03 18:08:42 +08:00
type: "third",
value: item.value,
data: ruralarr.value,
});
2026-04-03 18:08:42 +08:00
} else if (item.label === dispatchList.value[2].label) {
emit("showCenterCard", {
2026-04-03 18:08:42 +08:00
type: "first",
value: item.value,
data: projectarr.value,
});
}
};
2026-03-27 17:47:09 +08:00
// 气象预警数据
2026-04-02 16:35:45 +08:00
const weatherWarningData = ref([
2026-04-03 18:08:42 +08:00
{ label: "红色预警", value: "0", class: "red" },
{ label: "橙色预警", value: "0", class: "orange" },
{ label: "黄色预警", value: "0", class: "yellow" },
{ label: "蓝色预警", value: "0", class: "blue" },
2026-04-02 16:35:45 +08:00
]);
2026-03-27 17:47:09 +08:00
// 影响点数据
2026-04-02 16:35:45 +08:00
const impactData = ref([
{ name: "路段", count: 0 },
{ name: "桥梁", count: 0 },
{ name: "隧道", count: 0 },
{ name: "边坡", count: 0 },
{ name: "项目", count: 0 },
2026-04-02 16:35:45 +08:00
]);
2026-03-27 17:47:09 +08:00
const dateRange = ref([]);
// 点击日期范围器
const handleDateRangeClick = (val) => {
dateRange.value = val;
dispatchLoadLoad();
};
2026-04-03 18:08:42 +08:00
// 调度清单数据
const dispatchLoadLoad = async () => {
try {
// 处理日期参数开始时间为当天00:00:00结束时间为当天23:59:59
let start = "";
let end = "";
2026-03-27 17:47:09 +08:00
2026-04-03 18:08:42 +08:00
if (dateRange.value && dateRange.value.length === 2) {
start = formatDateTime(dateRange.value[0]);
end = formatDateTime(dateRange.value[1]);
2026-04-03 18:08:42 +08:00
}
const res = await request({
url: "/snow-ops-platform/weather-warning/schedule-statistics",
method: "GET",
params: {
start: start,
end: end,
2026-04-03 18:08:42 +08:00
},
});
console.log(res);
if (res.code == "00000") {
const data = res.data;
if (data) {
responseStats.value.forEach((item) => {
if (item.label == "叫应总数") {
item.value = data["noticeCount"] || 0;
} else if (item.label == "已回应数") {
item.value = data["replyCount"] || 0;
} else if (item.label == "回应率") {
item.value =
data["replyPrecent"] >= 0 ? data["replyPrecent"] + "%" : 0;
} else if (item.label == "调度区县数") {
item.value = data["countyCount"] || 0;
} else if (item.label == "线下帮扶数") {
item.value = data["supportCount"] || 0;
} else if (item.label == "抽查人次") {
item.value = data["inspectionCount"] || 0;
}
});
dispatchList.value.forEach((item) => {
if (item.label == "国省道调度") {
item.value = data["nationalRoadCount"] || 0;
} else if (item.label == "农村公路调度") {
item.value = data["ruralRoadCount"] || 0;
} else if (item.label == "建设工程调度") {
item.value = data["projectCount"] || 0;
}
});
// responseStats.value = data;
// dispatchList.value = data;
} else {
responseStats.value.forEach((item) => {
item.value = 0;
});
dispatchList.value.forEach((item) => {
item.value = 0;
});
2026-04-03 18:08:42 +08:00
}
}
} catch (error) {
console.error("加载数据失败:", error);
}
};
// 格式化日期时间为接口所需格式
const formatDateTime = (date) => {
if (!date) return "";
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
const hours = String(d.getHours()).padStart(2, "0");
const minutes = String(d.getMinutes()).padStart(2, "0");
const seconds = String(d.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
const getdateRangeTime = () => {
// 处理日期参数开始时间为当天00:00:00结束时间为当天23:59:59
let start = "";
let end = "";
if (getdateRange.value && getdateRange.value.length === 2) {
start = formatDateTime(getdateRange.value[0]);
end = formatDateTime(getdateRange.value[1]);
}
return {
start: start,
end: end,
};
};
2026-04-03 18:08:42 +08:00
// 区县数据
const districtLoadLoad = async () => {
console.log("区县数据:", getdateRangeTime());
2026-04-03 18:08:42 +08:00
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count/_by_county",
method: "GET",
params: getdateRangeTime(),
2026-04-03 18:08:42 +08:00
});
console.log(res);
if (res.code == "00000") {
const data = res.data;
if (data) {
2026-04-17 17:23:51 +08:00
// 简化区县名称
const simplifyDistrictName = (name) => {
if (!name) return name;
return name
.replace("彭水苗族土家族自治县", "彭水县")
.replace("石柱土家族自治县", "石柱县")
.replace("秀山土家族苗族自治县", "秀山县")
.replace("酉阳土家族苗族自治县", "酉阳县");
};
// 处理数据,简化区县名称
const processedData = data.map((item) => ({
...item,
name: simplifyDistrictName(item.name),
}));
// 根据路段、桥梁、隧道、边坡、项目的总数进行排序(数值越大越靠前)
2026-04-17 17:23:51 +08:00
const sortedData = processedData.sort((a, b) => {
const totalA =
(a.roadSectionCount || 0) +
(a.bridgeCount || 0) +
(a.tunnelCount || 0) +
(a.slopeCount || 0) +
(a.projectCount || 0);
const totalB =
(b.roadSectionCount || 0) +
(b.bridgeCount || 0) +
(b.tunnelCount || 0) +
(b.slopeCount || 0) +
(b.projectCount || 0);
return totalB - totalA; // 降序排列,数值大的在前
});
districtData.value = sortedData;
} else {
districtData.value = [];
2026-04-03 18:08:42 +08:00
}
}
} catch (error) {
console.error("加载数据失败:", error);
}
};
const roadTypeData = ref([]);
// 调度统计区县数据
const projectarr = ref([]);
const nationalarr = ref([]);
const ruralarr = ref([]);
const scheduleStatisticsByCountyLoad = async () => {
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/schedule-statistics/_by_county",
method: "GET",
params: getdateRangeTime(),
});
console.log("调度统计区县数据:", res);
if (res.code == "00000") {
const data = res.data;
if (data) {
data.forEach((item) => {
if (item.countyName != "测试区县") {
if (item.type == "project") {
projectarr.value.push(item);
} else if (item.roadType == "national") {
nationalarr.value.push(item);
} else if (item.roadType == "rural") {
ruralarr.value.push(item);
}
}
});
console.log(projectarr.value);
console.log(nationalarr.value);
console.log(ruralarr.value);
// 合并渝北区和江北区为两江新区
const mergeLiangjiangNewArea = (arr) => {
const yubeiItems = arr.filter((item) => item.countyName === "渝北区");
const jiangbeiItems = arr.filter(
(item) => item.countyName === "江北区",
);
if (yubeiItems.length > 0 || jiangbeiItems.length > 0) {
// 计算合并后的数据
const mergedItem = {
countyName: "两江新区",
countyId:
yubeiItems[0]?.countyId || jiangbeiItems[0]?.countyId || "",
type: yubeiItems[0]?.type || jiangbeiItems[0]?.type || "",
roadType:
yubeiItems[0]?.roadType || jiangbeiItems[0]?.roadType || "",
// 数值字段累加
noticeCount: 0,
replyCount: 0,
population: 0,
entityCount: 0,
};
// 累加渝北区数据
yubeiItems.forEach((item) => {
mergedItem.noticeCount += item.noticeCount || 0;
mergedItem.replyCount += item.replyCount || 0;
mergedItem.population += item.population || 0;
mergedItem.entityCount += item.entityCount || 0;
});
// 累加江北区数据
jiangbeiItems.forEach((item) => {
mergedItem.noticeCount += item.noticeCount || 0;
mergedItem.replyCount += item.replyCount || 0;
mergedItem.population += item.population || 0;
mergedItem.entityCount += item.entityCount || 0;
});
// 移除渝北区和江北区的数据,添加合并后的两江新区数据
const filteredArr = arr.filter(
(item) =>
item.countyName !== "渝北区" && item.countyName !== "江北区",
);
filteredArr.push(mergedItem);
return filteredArr;
}
return arr;
};
// 对三个数组分别进行合并处理
projectarr.value = mergeLiangjiangNewArea(projectarr.value);
nationalarr.value = mergeLiangjiangNewArea(nationalarr.value);
ruralarr.value = mergeLiangjiangNewArea(ruralarr.value);
// 过滤出前15个项目、10个全国、5个农村
// projectarr.value = projectarr.value.filter((item, index) => index < 15);
// nationalarr.value = nationalarr.value.filter(
// (item, index) => index < 10,
// );
// ruralarr.value = ruralarr.value.filter((item, index) => index < 5);
} else {
projectarr.value = [];
nationalarr.value = [];
ruralarr.value = [];
}
}
} catch (error) {
console.error("加载调度统计区县数据失败:", error);
}
};
2026-04-03 18:08:42 +08:00
// 公路类型数据
const roadTypeLoad = async () => {
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count/_by_road",
method: "GET",
params: getdateRangeTime(),
2026-04-03 18:08:42 +08:00
});
console.log(res);
if (res.code == "00000") {
const data = res.data;
if (data) {
roadTypeData.value = data.reverse();
} else {
roadTypeData.value.forEach((item) => {
item.count = 0;
});
2026-04-03 18:08:42 +08:00
}
}
} catch (error) {
console.error("加载数据失败:", error);
}
};
2026-04-02 16:35:45 +08:00
// 加载气象预警和影响点数据
const loadData = async () => {
try {
2026-04-02 17:27:59 +08:00
const res = await request({
2026-04-03 18:08:42 +08:00
url: "/snow-ops-platform/weather-warning/warning-count",
2026-04-02 17:27:59 +08:00
method: "GET",
params: getdateRangeTime(),
2026-04-02 17:27:59 +08:00
});
if (res.code == "00000") {
const data = res.data;
if (data) {
2026-04-03 18:08:42 +08:00
let obj = {};
data.forEach((item) => {
obj[item.name] = item.count || 0;
});
console.log(obj);
2026-04-02 17:27:59 +08:00
weatherWarningData.value.forEach((item) => {
if (item.label == "红色预警") {
2026-04-03 18:08:42 +08:00
item.value =
obj["warning-red-count"] + "/" + obj["warning-red-total"] ||
"0/0";
2026-04-02 17:27:59 +08:00
} else if (item.label == "橙色预警") {
2026-04-03 18:08:42 +08:00
item.value =
obj["warning-orange-count"] + "/" + obj["warning-orange-total"] ||
"0/0";
2026-04-02 17:27:59 +08:00
} else if (item.label == "黄色预警") {
2026-04-03 18:08:42 +08:00
item.value =
obj["warning-yellow-count"] + "/" + obj["warning-yellow-total"] ||
"0/0";
2026-04-02 17:27:59 +08:00
} else if (item.label == "蓝色预警") {
2026-04-03 18:08:42 +08:00
item.value =
obj["warning-blue-count"] + "/" + obj["warning-blue-total"] ||
"0/0";
2026-04-02 17:27:59 +08:00
}
});
} else {
weatherWarningData.value.forEach((item) => {
if (item.label == "红色预警") {
item.value = "0/0";
} else if (item.label == "橙色预警") {
item.value = "0/0";
} else if (item.label == "黄色预警") {
item.value = "0/0";
} else if (item.label == "蓝色预警") {
item.value = "0/0";
}
});
2026-04-02 16:35:45 +08:00
}
}
} catch (error) {
console.error("加载数据失败:", error);
}
};
2026-04-03 18:08:42 +08:00
// 加载柱状图数据
const loadBarChartData = async () => {
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count",
method: "GET",
params: getdateRangeTime(),
2026-04-03 18:08:42 +08:00
});
if (res.code == "00000") {
const data = res.data;
if (data.length > 0) {
2026-04-03 18:08:42 +08:00
// 英文转中文映射
const nameMap = {
"road-section": "路段",
bridge: "桥梁",
tunnel: "隧道",
slope: "边坡",
project: "项目",
Road: "路段",
Bridge: "桥梁",
Tunnel: "隧道",
Slope: "边坡",
Project: "项目",
};
// 转换英文name为中文
const convertedData = data.map((item) => {
const name = nameMap[item.name] || item.name;
return { ...item, name };
});
convertedData.forEach((item) => {
if (item.name == "路段") {
impactData.value[0].count = item.count || 0;
} else if (item.name == "桥梁") {
impactData.value[1].count = item.count || 0;
} else if (item.name == "隧道") {
impactData.value[2].count = item.count || 0;
} else if (item.name == "边坡") {
impactData.value[3].count = item.count || 0;
} else if (item.name == "项目") {
impactData.value[4].count = item.count || 0;
}
});
} else {
// 影响点数据
impactData.value = JSON.parse(
JSON.stringify([
{ name: "路段", count: 0 },
{ name: "桥梁", count: 0 },
{ name: "隧道", count: 0 },
{ name: "边坡", count: 0 },
{ name: "项目", count: 0 },
]),
);
2026-04-03 18:08:42 +08:00
}
}
} catch (error) {
console.error("加载柱状图数据失败:", error);
}
};
2026-03-27 17:47:09 +08:00
// 计算最大值用于动态计算高度
2026-04-03 18:08:42 +08:00
// 计算所有影响点的总和
const totalValue = computed(() => {
let total = 0;
impactData.value.forEach((item) => {
total += item.count || 0;
});
return total;
2026-04-02 16:35:45 +08:00
});
2026-03-27 17:47:09 +08:00
// 计算每个柱子的高度百分比
const getBarHeight = (value) => {
2026-04-03 18:08:42 +08:00
const actualValue = value.count || value.value;
if (!actualValue || actualValue == 0) return "0";
2026-04-03 18:08:42 +08:00
// 确保最小高度为10%最大高度为100%
const height = (actualValue / totalValue.value) * 200;
// 确保高度差异明显至少有5%的差异
return Math.min(100, Math.max(10, Math.round(height)));
2026-03-27 17:47:09 +08:00
};
2026-03-31 18:10:34 +08:00
const handleAIClick = () => {
emit("openAIResult");
};
// 响应式单位转换函数基于1920px设计稿
const vw = (px) => {
return Math.round((px / 1920) * window.innerWidth);
};
// 表格高度计算
const tableHeight = computed(() => {
return vw(100);
});
2026-03-27 17:47:09 +08:00
// 区县数据
const districtData = ref([]);
2026-03-27 17:47:09 +08:00
// 响应调度统计数据
2026-04-03 18:08:42 +08:00
const responseStats = ref([
2026-03-27 17:47:09 +08:00
{
label: "叫应总数",
value: "15",
iconClass: "icon-call",
img: imgCall,
},
{
label: "已回应数",
value: "9",
iconClass: "icon-reply",
img: imgReply,
},
{
2026-03-31 18:10:34 +08:00
label: "回应率",
2026-03-27 17:47:09 +08:00
value: "100%",
iconClass: "icon-rate",
img: imgRate,
},
{
label: "调度区县数",
value: "21",
iconClass: "icon-district",
img: imgDistrict,
},
{
label: "线下帮扶数",
value: "12",
iconClass: "icon-help",
img: imgHelp,
},
{
label: "抽查人次",
value: "23",
iconClass: "icon-check",
img: imgCheck,
},
2026-04-03 18:08:42 +08:00
]);
2026-03-27 17:47:09 +08:00
// 调度清单数据
2026-04-03 18:08:42 +08:00
const dispatchList = ref([
{ label: "国省道调度", value: "341" },
{ label: "农村公路调度", value: "210" },
{ label: "建设工程调度", value: "120" },
]);
2026-03-27 17:47:09 +08:00
const headerCellStyle = () => ({
background: "rgba(64, 169, 255, 0.1)",
color: "rgba(255, 255, 255, 0.9)",
fontWeight: "normal",
borderBottom: "1px solid rgba(64, 169, 255, 0.2)",
padding: " 2px",
textAlign: "center",
lineHeight: "1.2",
});
const cellStyle = () => ({
background: "transparent",
color: "rgba(255, 255, 255, 0.8)",
borderBottom: "1px solid rgba(64, 169, 255, 0.1)",
padding: " 2px",
textAlign: "center",
lineHeight: "1.2",
});
</script>
<style lang="scss" scoped>
2026-03-31 18:10:34 +08:00
.filter-header {
2026-04-02 16:35:45 +08:00
margin-left: 2.667vw;
2026-03-31 18:10:34 +08:00
align-items: center;
color: #fff;
font-weight: bold;
2026-04-02 16:35:45 +08:00
display: flex;
align-items: center;
.title {
font-size: 1vw;
}
2026-03-31 18:10:34 +08:00
}
.filter-icon-ai {
2026-04-02 16:35:45 +08:00
width: 1.5em;
height: 1.5em;
2026-03-31 18:10:34 +08:00
margin-left: 10px;
}
// 视频屏幕自适应 - 基于视口宽度动态调整
// 基准宽度 1920px使用 vw 单位实现自适应
@function vw($px) {
@return calc($px / 1920 * 100vw);
}
2026-03-27 17:47:09 +08:00
.left-panel {
width: 100%;
height: 100%;
padding: vw(20);
2026-03-27 17:47:09 +08:00
box-sizing: border-box;
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
// 小屏幕适配
@media (max-width: 1366px) {
padding: 12px;
}
@media (max-width: 1024px) {
padding: 8px;
}
2026-03-27 17:47:09 +08:00
.section-header {
height: vw(50);
2026-03-27 17:47:09 +08:00
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: vw(20);
2026-03-27 17:47:09 +08:00
background-image: url("../../assets/RiskWarning_img/标题bg@2x.png");
background-size: cover;
background-position: left;
.header-left {
display: flex;
align-items: center;
gap: vw(8);
margin-left: vw(35);
2026-03-27 17:47:09 +08:00
color: #fff;
font-weight: bold;
.icon-back {
width: vw(20);
height: vw(20);
min-width: 16px;
min-height: 16px;
2026-04-02 16:35:45 +08:00
background: linear-gradient(135deg, #18f2f9 0%, #1890ff 100%);
2026-03-27 17:47:09 +08:00
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
&::before {
content: "←";
color: #fff;
}
}
}
.header-date {
font-size: vw(11);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.6);
}
}
// 气象预警
.weather-warning-section {
margin-bottom: vw(20);
2026-03-27 17:47:09 +08:00
.section-title {
font-size: vw(16);
2026-03-27 17:47:09 +08:00
font-weight: 600;
color: rgba(255, 255, 255, 0.9);
margin-bottom: vw(12);
2026-03-27 17:47:09 +08:00
}
.warning-cards {
display: grid;
grid-template-columns: repeat(2, 1fr);
display: flex;
2026-04-02 16:35:45 +08:00
gap: vw(5);
2026-03-27 17:47:09 +08:00
.warning-card {
display: flex;
align-items: center;
flex: 1;
// padding: 12px;
background: rgba(64, 169, 255, 0.1);
border: 1px solid rgba(64, 169, 255, 0.2);
.card-icon {
width: 100%;
max-width: vw(35);
2026-03-27 17:47:09 +08:00
height: auto;
display: flex;
align-items: center;
justify-content: center;
font-size: vw(24);
2026-03-27 17:47:09 +08:00
// &::before {
// content: "⛈️";
// }
}
.card-info {
flex: 1;
.card-num {
2026-04-02 16:35:45 +08:00
font-size: vw(18);
2026-03-27 17:47:09 +08:00
font-weight: bold;
margin-bottom: 2px;
}
.card-label {
2026-04-03 18:08:42 +08:00
font-size: vw(16);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.7);
}
}
&.red .card-num {
color: #ff4d4f;
}
&.orange .card-num {
color: #ff7a45;
}
&.yellow .card-num {
color: #ffc53d;
}
&.blue .card-num {
2026-04-02 16:35:45 +08:00
color: #379afd;
2026-03-27 17:47:09 +08:00
}
}
}
}
// 影响点概况
.impact-section {
margin-bottom: vw(40);
2026-03-27 17:47:09 +08:00
.impact-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: vw(20);
2026-03-27 17:47:09 +08:00
.impact-title {
font-size: vw(16);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.9);
}
.impact-detail {
font-size: vw(14);
2026-04-02 16:35:45 +08:00
color: #18f2f9;
2026-03-27 17:47:09 +08:00
cursor: pointer;
&.clickable {
transition: all 0.3s;
&:hover {
color: #69c0ff;
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
}
}
2026-03-27 17:47:09 +08:00
}
}
.chart-container {
position: relative;
2026-04-02 16:35:45 +08:00
height: vw(100);
2026-03-27 17:47:09 +08:00
display: flex;
// padding: 10px 0 30px 40px;
.chart-y-label {
position: absolute;
left: 0;
top: vw(-10);
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.6);
}
.bar-chart {
display: flex;
justify-content: space-around;
align-items: flex-end;
height: 100%;
border-bottom: 1px solid rgba(64, 169, 255, 0.3);
position: relative;
// 背景网格线
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
2026-03-31 18:10:34 +08:00
background-image:
linear-gradient(to right, transparent 0%, transparent 100%),
linear-gradient(
to bottom,
rgba(64, 169, 255, 0.1) 1px,
transparent 1px
);
2026-03-27 17:47:09 +08:00
background-size: 100% 25%;
pointer-events: none;
}
.bar-item {
height: 100%;
display: flex;
flex-direction: column-reverse;
align-items: center;
flex: 1;
cursor: pointer;
transition: all 0.3s ease;
padding: vw(5) 0;
2026-03-27 17:47:09 +08:00
border-radius: 4px;
&:hover {
background: rgba(64, 169, 255, 0.15);
.bar-value {
2026-04-02 16:35:45 +08:00
color: #18f2f9;
2026-03-27 17:47:09 +08:00
transform: scale(1.1);
}
.bar {
background: linear-gradient(
180deg,
#69c0ff 0%,
rgba(105, 192, 255, 0.5) 100%
);
box-shadow: 0 0 15px rgba(64, 169, 255, 0.6);
}
.bar-label {
color: #fff;
}
}
.bar-value {
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
font-weight: bold;
color: rgba(255, 255, 255, 0.9);
margin-bottom: vw(5);
2026-03-27 17:47:09 +08:00
transition: all 0.3s ease;
}
.bar {
width: vw(30);
min-width: 16px;
2026-03-31 18:10:34 +08:00
background: linear-gradient(
180deg,
2026-04-02 16:35:45 +08:00
#18f2f9 0%,
2026-03-31 18:10:34 +08:00
rgba(64, 169, 255, 0.3) 100%
);
2026-03-27 17:47:09 +08:00
border-radius: 2px 2px 0 0;
2026-04-03 18:08:42 +08:00
// min-height: 20px;
2026-03-27 17:47:09 +08:00
transition: all 0.3s ease;
}
.bar-label {
bottom: vw(-20);
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.7);
transition: all 0.3s ease;
position: absolute;
}
}
}
.chart-x-label {
position: absolute;
right: vw(-15);
2026-03-27 17:47:09 +08:00
bottom: 0;
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.6);
}
}
}
2026-03-31 18:10:34 +08:00
// 影响公路类型情况
.road-type-section {
margin-bottom: vw(20);
.section-title {
font-size: vw(16);
font-weight: 600;
color: rgba(255, 255, 255, 0.9);
margin-bottom: vw(12);
}
.road-type-cards {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: vw(10);
.road-card {
display: flex;
align-items: center;
padding: vw(12) vw(16);
background: rgba(64, 169, 255, 0.1);
2026-04-02 16:35:45 +08:00
border: 1px solid #1d4c60;
2026-03-31 18:10:34 +08:00
box-shadow: inset 0px 0px 8px 0px rgba(55, 155, 255, 0.2);
.card-label {
2026-04-02 16:35:45 +08:00
font-size: vw(18);
2026-03-31 18:10:34 +08:00
color: rgba(255, 255, 255, 0.7);
}
.card-value {
2026-04-02 16:35:45 +08:00
font-size: vw(22);
2026-03-31 18:10:34 +08:00
font-weight: bold;
2026-04-02 16:35:45 +08:00
color: #18f2f9;
2026-03-31 18:10:34 +08:00
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
}
}
}
}
2026-03-27 17:47:09 +08:00
// 区县统计表格
.district-table-section {
height: vw(150);
2026-03-31 18:10:34 +08:00
overflow: hidden;
:deep(.el-table__empty-block) {
max-height: 40px !important;
.el-table__empty-text {
line-height: 30px !important;
}
}
:deep(.el-table__empty-block) {
min-height: 40px !important;
}
2026-04-02 16:35:45 +08:00
2026-03-27 17:47:09 +08:00
:deep(.el-table) {
background: transparent;
&::before {
display: none;
}
.el-table__inner-wrapper {
background: transparent;
}
.el-table__inner-wrapper:before {
display: none;
}
.el-table__header-wrapper {
background: transparent;
2026-03-31 18:10:34 +08:00
position: sticky;
top: 0;
z-index: 1;
2026-03-27 17:47:09 +08:00
}
.el-table__body-wrapper {
background: transparent;
2026-03-31 18:10:34 +08:00
overflow-y: auto;
max-height: calc(#{vw(150)} - #{vw(0)}); /* 减去表头高度 */
2026-03-31 18:10:34 +08:00
scrollbar-width: none;
-ms-overflow-style: none;
2026-04-02 16:35:45 +08:00
2026-03-31 18:10:34 +08:00
&::-webkit-scrollbar {
display: none;
}
2026-03-27 17:47:09 +08:00
}
tr {
background: transparent;
&:hover {
background: rgba(64, 169, 255, 0.05) !important;
}
}
th.el-table__cell {
background: transparent;
}
td.el-table__cell {
background: transparent;
}
}
}
// 响应调度
.response-section {
padding: vw(15);
margin-top: vw(20);
2026-03-27 17:47:09 +08:00
.section-header {
2026-04-02 16:35:45 +08:00
height: vw(50);
2026-03-27 17:47:09 +08:00
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: vw(15);
2026-03-31 18:10:34 +08:00
background-image: url("../../assets/RiskWarning_img/标题bg@2x.png")
no-repeat;
2026-03-27 17:47:09 +08:00
background-size: cover;
background-position: left;
.header-left {
display: flex;
align-items: center;
gap: vw(8);
2026-03-27 17:47:09 +08:00
.icon-back {
width: vw(20);
height: vw(20);
min-width: 16px;
min-height: 16px;
2026-04-02 16:35:45 +08:00
background: linear-gradient(135deg, #18f2f9 0%, #1890ff 100%);
2026-03-27 17:47:09 +08:00
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
&::before {
content: "←";
color: #fff;
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
}
}
}
.header-filters {
display: flex;
align-items: center;
gap: vw(6);
font-size: vw(10);
2026-03-27 17:47:09 +08:00
.filter-item {
2026-04-02 16:35:45 +08:00
color: #fff;
padding: vw(8) vw(8);
background: #183c67;
box-shadow: inset 0px 0px 8px 0px #4fecff;
2026-03-27 17:47:09 +08:00
cursor: pointer;
}
.filter-separator {
color: rgba(255, 255, 255, 0.4);
}
}
}
// 6个统计项网格
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
2026-04-02 16:35:45 +08:00
// gap: vw(10);
background: rgba(64, 169, 255, 0.1);
border: 1px solid rgba(64, 169, 255, 0.2);
margin-bottom: vw(10);
2026-03-27 17:47:09 +08:00
.stat-item {
display: flex;
align-items: center;
2026-04-02 16:35:45 +08:00
// gap: vw(8);
padding: vw(12) vw(10);
2026-04-02 16:35:45 +08:00
// background: rgba(64, 169, 255, 0.08);
2026-03-27 17:47:09 +08:00
.stat-icon {
width: 100%;
max-width: vw(40);
2026-03-27 17:47:09 +08:00
height: auto;
display: flex;
align-items: center;
justify-content: center;
font-size: vw(18);
2026-03-27 17:47:09 +08:00
&.icon-call::before {
content: "💬";
}
&.icon-reply::before {
content: "✉️";
}
&.icon-rate::before {
content: "⏱️";
}
&.icon-district::before {
content: "📍";
}
&.icon-help::before {
content: "🤝";
}
&.icon-check::before {
content: "👥";
}
}
.stat-info {
.stat-num {
font-size: vw(24);
2026-03-27 17:47:09 +08:00
font-weight: bold;
2026-04-02 16:35:45 +08:00
color: #18f2f9;
2026-03-27 17:47:09 +08:00
margin-bottom: 2px;
}
.stat-label {
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
color: #ffffff;
}
}
&.clickable {
cursor: pointer;
transition: all 0.3s;
&:hover {
background: rgba(64, 169, 255, 0.2);
2026-04-02 16:35:45 +08:00
// transform: translateY(-2px);
.stat-num {
color: #69c0ff;
text-shadow: 0 0 10px rgba(105, 192, 255, 0.5);
}
}
}
2026-03-27 17:47:09 +08:00
}
}
// 3个调度清单卡片
.dispatch-cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: vw(10);
2026-03-27 17:47:09 +08:00
.dispatch-card {
padding: vw(12);
2026-03-27 17:47:09 +08:00
background: rgba(64, 169, 255, 0.1);
border: 1px solid rgba(64, 169, 255, 0.2);
text-align: center;
&.clickable {
cursor: pointer;
transition: all 0.3s;
&:hover {
background: rgba(64, 169, 255, 0.2);
transform: translateY(-2px);
.card-num {
color: #69c0ff;
text-shadow: 0 0 10px rgba(105, 192, 255, 0.5);
}
}
}
2026-03-27 17:47:09 +08:00
.card-num {
font-size: vw(20);
2026-03-27 17:47:09 +08:00
font-weight: bold;
2026-04-02 16:35:45 +08:00
color: #18f2f9;
margin-bottom: vw(6);
2026-03-27 17:47:09 +08:00
.unit {
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.7);
font-weight: normal;
margin-left: 2px;
}
}
.card-label {
2026-04-03 18:08:42 +08:00
font-size: vw(14);
2026-03-27 17:47:09 +08:00
color: rgba(255, 255, 255, 0.8);
}
}
}
}
}
.date-range-wrapper {
:deep(.el-date-editor) {
2026-04-02 16:35:45 +08:00
border-radius: 0px !important;
height: 3.1em !important;
}
:deep(.el-date-editor) {
width: 200px;
max-width: vw(200);
2026-03-27 17:47:09 +08:00
background: #183c67;
box-shadow: inset 0px 0px 8px 0px #4fecff;
.el-range-input {
background: transparent;
color: rgba(255, 255, 255, 0.8);
&::placeholder {
color: rgba(255, 255, 255, 0.5);
}
}
.el-range-separator {
color: rgba(255, 255, 255, 0.4);
}
.el-icon {
color: rgba(255, 255, 255, 0.5);
}
// &:hover {
// border-color: rgba(64, 169, 255, 0.5);
// }
}
}
</style>