2026-04-16 14:03:39 +08:00

1408 lines
36 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="left-panel">
<!-- 智能研判头部 -->
<SectionHeader title="智能研判">
<template #left>
<div class="filter-header">
<span class="title">智能研判</span>
<img
class="filter-icon-ai"
src="../../assets/RiskWarning_img/AI1@2x.png"
alt=""
@click="handleAIClick"
/>
</div>
</template>
</SectionHeader>
<!-- 气象预警 -->
<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)"
>
<img
class="card-icon"
src="../../assets/RiskWarning_img/气象预警图标@2x.png"
alt=""
/>
<div class="card-info">
<div class="card-num mt_5">{{ item.value }}</div>
<div class="card-label mb_5">{{ item.label }}</div>
</div>
</div>
</div>
</div>
<!-- 影响点概况 -->
<div class="impact-section">
<div class="impact-header">
<div class="impact-title">影响点概况</div>
<div class="impact-detail clickable" @click="handleImpactDetailClick">
一键清单(影响点)
</div>
</div>
<div class="chart-container">
<div class="chart-y-label">数量</div>
<div class="bar-chart f1">
<div
v-for="(item, index) in impactData"
:key="index"
class="bar-item"
>
<div
class="bar"
:style="{ height: getBarHeight(item) + '%' }"
></div>
<div class="bar-value">{{ item.count }}</div>
<div class="bar-label">{{ item.name }}</div>
</div>
</div>
<div class="chart-x-label">类型</div>
</div>
</div>
<!-- 影响公路类型情况 -->
<div class="road-type-section">
<div class="section-title">影响公路类型情况</div>
<div class="road-type-cards">
<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>
</div>
</div>
</div>
<!-- 区县统计表格 -->
<div class="district-table-section">
<el-table
:data="districtData"
style="
width: 100%;
background: transparent;
font-size: 12px;
height: 150px;
"
:header-cell-style="headerCellStyle"
:cell-style="cellStyle"
size="small"
:height="tableHeight"
:scroll="{ y: true }"
>
<el-table-column prop="name" label="区县名称" :min-width="vw(80)" />
<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)" />
</el-table>
</div>
<!-- 响应调度 -->
<div class="response-section">
<SectionHeader title="响应调度">
<template #right>
<div class="header-filters">
<span class="filter-item active" @click="handleDateRangeClick()"
>本轮</span
>
<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"
: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)"
>
<!-- <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"
class="dispatch-card clickable"
@click="handleDispatchCardClick(item)"
>
<div class="card-num">
{{ item.value }}<span class="unit"></span>
</div>
<div class="card-label">{{ item.label }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, watch, inject } from "vue";
import { request } from "@/utils/request";
import SectionHeader from "./component/sectionHeader.vue";
// 导入图片资源
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([]));
// 监听日期范围变化,当获取到数据时重新加载
watch(
() => getdateRange.value,
(newVal) => {
console.log("left.vue 日期范围变化:", newVal);
init();
},
{ deep: true },
);
onMounted(() => {
init();
// 注册刷新函数给父组件
if (setRefreshLeftData) {
setRefreshLeftData(init);
}
});
const init = () => {
roadTypeLoad();
districtLoadLoad();
dispatchLoadLoad();
scheduleStatisticsByCountyLoad();
loadData();
loadBarChartData();
};
const emit = defineEmits([
"openWarningInfo",
"openImpactPoint",
"openWarningSituation",
"openResponseStatus",
"openDispatchDistrict",
"openImpactDetail",
"showCenterCard",
"warningClick",
]);
// 点击统计项
const handleStatClick = (item) => {
if (item.label === "叫应总数") {
emit("openWarningInfo");
} else if (item.label === "已回应数") {
emit("openResponseStatus");
} else if (item.label === "调度区县数") {
emit("openDispatchDistrict");
}
};
// 点击气象预警卡片
const handleWarningCardClick = (item) => {
console.log("item:", item);
emit("openWarningSituation", item);
// 传递日期范围
emit("warningClick", item);
};
// 点击影响点明细
const handleImpactDetailClick = () => {
emit("openImpactDetail");
};
// 点击调度清单卡片
const handleDispatchCardClick = (item) => {
if (item.label === dispatchList.value[0].label) {
emit("showCenterCard", {
type: "second",
value: item.value,
data: nationalarr.value,
});
} else if (item.label === dispatchList.value[1].label) {
emit("showCenterCard", {
type: "third",
value: item.value,
data: ruralarr.value,
});
} else if (item.label === dispatchList.value[2].label) {
emit("showCenterCard", {
type: "first",
value: item.value,
data: projectarr.value,
});
}
};
// 气象预警数据
const weatherWarningData = ref([
{ label: "红色预警", value: "0", class: "red" },
{ label: "橙色预警", value: "0", class: "orange" },
{ label: "黄色预警", value: "0", class: "yellow" },
{ label: "蓝色预警", value: "0", class: "blue" },
]);
// 影响点数据
const impactData = ref([
{ name: "路段", count: 0 },
{ name: "桥梁", count: 0 },
{ name: "隧道", count: 0 },
{ name: "边坡", count: 0 },
{ name: "项目", count: 0 },
]);
const dateRange = ref([]);
// 点击日期范围器
const handleDateRangeClick = (val) => {
dateRange.value = val;
dispatchLoadLoad();
};
// 调度清单数据
const dispatchLoadLoad = async () => {
try {
// 处理日期参数开始时间为当天00:00:00结束时间为当天23:59:59
let start = "";
let end = "";
if (dateRange.value && dateRange.value.length === 2) {
start = formatDateTime(dateRange.value[0]);
end = formatDateTime(dateRange.value[1]);
}
const res = await request({
url: "/snow-ops-platform/weather-warning/schedule-statistics",
method: "GET",
params: {
start: start,
end: end,
},
});
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;
});
}
}
} 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,
};
};
// 区县数据
const districtLoadLoad = async () => {
console.log("区县数据:", getdateRangeTime());
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count/_by_county",
method: "GET",
params: getdateRangeTime(),
});
console.log(res);
if (res.code == "00000") {
const data = res.data;
if (data) {
// 根据路段、桥梁、隧道、边坡、项目的总数进行排序(数值越大越靠前)
const sortedData = data.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 = [];
}
}
} 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);
}
};
// 公路类型数据
const roadTypeLoad = async () => {
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count/_by_road",
method: "GET",
params: getdateRangeTime(),
});
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;
});
}
}
} catch (error) {
console.error("加载数据失败:", error);
}
};
// 加载气象预警和影响点数据
const loadData = async () => {
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/warning-count",
method: "GET",
params: getdateRangeTime(),
});
if (res.code == "00000") {
const data = res.data;
if (data) {
let obj = {};
data.forEach((item) => {
obj[item.name] = item.count || 0;
});
console.log(obj);
weatherWarningData.value.forEach((item) => {
if (item.label == "红色预警") {
item.value =
obj["warning-red-count"] + "/" + obj["warning-red-total"] ||
"0/0";
} else if (item.label == "橙色预警") {
item.value =
obj["warning-orange-count"] + "/" + obj["warning-orange-total"] ||
"0/0";
} else if (item.label == "黄色预警") {
item.value =
obj["warning-yellow-count"] + "/" + obj["warning-yellow-total"] ||
"0/0";
} else if (item.label == "蓝色预警") {
item.value =
obj["warning-blue-count"] + "/" + obj["warning-blue-total"] ||
"0/0";
}
});
} 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";
}
});
}
}
} catch (error) {
console.error("加载数据失败:", error);
}
};
// 加载柱状图数据
const loadBarChartData = async () => {
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count",
method: "GET",
params: getdateRangeTime(),
});
if (res.code == "00000") {
const data = res.data;
if (data.length > 0) {
// 英文转中文映射
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 },
]),
);
}
}
} catch (error) {
console.error("加载柱状图数据失败:", error);
}
};
// 计算最大值用于动态计算高度
// 计算所有影响点的总和
const totalValue = computed(() => {
let total = 0;
impactData.value.forEach((item) => {
total += item.count || 0;
});
return total;
});
// 计算每个柱子的高度百分比
const getBarHeight = (value) => {
const actualValue = value.count || value.value;
if (!actualValue || actualValue == 0) return "0";
// 确保最小高度为10%最大高度为100%
const height = (actualValue / totalValue.value) * 200;
// 确保高度差异明显至少有5%的差异
return Math.min(100, Math.max(10, Math.round(height)));
};
const handleAIClick = () => {
emit("openAIResult");
};
// 响应式单位转换函数基于1920px设计稿
const vw = (px) => {
return Math.round((px / 1920) * window.innerWidth);
};
// 表格高度计算
const tableHeight = computed(() => {
return vw(100);
});
// 区县数据
const districtData = ref([]);
// 响应调度统计数据
const responseStats = ref([
{
label: "叫应总数",
value: "15",
iconClass: "icon-call",
img: imgCall,
},
{
label: "已回应数",
value: "9",
iconClass: "icon-reply",
img: imgReply,
},
{
label: "回应率",
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,
},
]);
// 调度清单数据
const dispatchList = ref([
{ label: "国省道调度", value: "341" },
{ label: "农村公路调度", value: "210" },
{ label: "建设工程调度", value: "120" },
]);
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>
.filter-header {
margin-left: 2.667vw;
align-items: center;
color: #fff;
font-weight: bold;
display: flex;
align-items: center;
.title {
font-size: 1vw;
}
}
.filter-icon-ai {
width: 1.5em;
height: 1.5em;
margin-left: 10px;
}
// 视频屏幕自适应 - 基于视口宽度动态调整
// 基准宽度 1920px使用 vw 单位实现自适应
@function vw($px) {
@return calc($px / 1920 * 100vw);
}
.left-panel {
width: 100%;
height: 100%;
padding: vw(20);
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;
}
.section-header {
height: vw(50);
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: vw(20);
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);
color: #fff;
font-weight: bold;
.icon-back {
width: vw(20);
height: vw(20);
min-width: 16px;
min-height: 16px;
background: linear-gradient(135deg, #18f2f9 0%, #1890ff 100%);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
&::before {
content: "←";
color: #fff;
}
}
}
.header-date {
font-size: vw(11);
color: rgba(255, 255, 255, 0.6);
}
}
// 气象预警
.weather-warning-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);
}
.warning-cards {
display: grid;
grid-template-columns: repeat(2, 1fr);
display: flex;
gap: vw(5);
.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);
height: auto;
display: flex;
align-items: center;
justify-content: center;
font-size: vw(24);
// &::before {
// content: "⛈️";
// }
}
.card-info {
flex: 1;
.card-num {
font-size: vw(18);
font-weight: bold;
margin-bottom: 2px;
}
.card-label {
font-size: vw(16);
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 {
color: #379afd;
}
}
}
}
// 影响点概况
.impact-section {
margin-bottom: vw(40);
.impact-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: vw(20);
.impact-title {
font-size: vw(16);
color: rgba(255, 255, 255, 0.9);
}
.impact-detail {
font-size: vw(14);
color: #18f2f9;
cursor: pointer;
&.clickable {
transition: all 0.3s;
&:hover {
color: #69c0ff;
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
}
}
}
}
.chart-container {
position: relative;
height: vw(100);
display: flex;
// padding: 10px 0 30px 40px;
.chart-y-label {
position: absolute;
left: 0;
top: vw(-10);
font-size: vw(14);
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;
background-image:
linear-gradient(to right, transparent 0%, transparent 100%),
linear-gradient(
to bottom,
rgba(64, 169, 255, 0.1) 1px,
transparent 1px
);
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;
border-radius: 4px;
&:hover {
background: rgba(64, 169, 255, 0.15);
.bar-value {
color: #18f2f9;
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 {
font-size: vw(14);
font-weight: bold;
color: rgba(255, 255, 255, 0.9);
margin-bottom: vw(5);
transition: all 0.3s ease;
}
.bar {
width: vw(30);
min-width: 16px;
background: linear-gradient(
180deg,
#18f2f9 0%,
rgba(64, 169, 255, 0.3) 100%
);
border-radius: 2px 2px 0 0;
// min-height: 20px;
transition: all 0.3s ease;
}
.bar-label {
bottom: vw(-20);
font-size: vw(14);
color: rgba(255, 255, 255, 0.7);
transition: all 0.3s ease;
position: absolute;
}
}
}
.chart-x-label {
position: absolute;
right: vw(-15);
bottom: 0;
font-size: vw(14);
color: rgba(255, 255, 255, 0.6);
}
}
}
// 影响公路类型情况
.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);
border: 1px solid #1d4c60;
box-shadow: inset 0px 0px 8px 0px rgba(55, 155, 255, 0.2);
.card-label {
font-size: vw(18);
color: rgba(255, 255, 255, 0.7);
}
.card-value {
font-size: vw(22);
font-weight: bold;
color: #18f2f9;
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
}
}
}
}
// 区县统计表格
.district-table-section {
height: vw(150);
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;
}
: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;
position: sticky;
top: 0;
z-index: 1;
}
.el-table__body-wrapper {
background: transparent;
overflow-y: auto;
max-height: calc(#{vw(150)} - #{vw(0)}); /* 减去表头高度 */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
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);
.section-header {
height: vw(50);
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: vw(15);
background-image: url("../../assets/RiskWarning_img/标题bg@2x.png")
no-repeat;
background-size: cover;
background-position: left;
.header-left {
display: flex;
align-items: center;
gap: vw(8);
.icon-back {
width: vw(20);
height: vw(20);
min-width: 16px;
min-height: 16px;
background: linear-gradient(135deg, #18f2f9 0%, #1890ff 100%);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
&::before {
content: "←";
color: #fff;
font-size: vw(14);
}
}
}
.header-filters {
display: flex;
align-items: center;
gap: vw(6);
font-size: vw(10);
.filter-item {
color: #fff;
padding: vw(8) vw(8);
background: #183c67;
box-shadow: inset 0px 0px 8px 0px #4fecff;
cursor: pointer;
}
.filter-separator {
color: rgba(255, 255, 255, 0.4);
}
}
}
// 6个统计项网格
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
// gap: vw(10);
background: rgba(64, 169, 255, 0.1);
border: 1px solid rgba(64, 169, 255, 0.2);
margin-bottom: vw(10);
.stat-item {
display: flex;
align-items: center;
// gap: vw(8);
padding: vw(12) vw(10);
// background: rgba(64, 169, 255, 0.08);
.stat-icon {
width: 100%;
max-width: vw(40);
height: auto;
display: flex;
align-items: center;
justify-content: center;
font-size: vw(18);
&.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);
font-weight: bold;
color: #18f2f9;
margin-bottom: 2px;
}
.stat-label {
font-size: vw(14);
color: #ffffff;
}
}
&.clickable {
cursor: pointer;
transition: all 0.3s;
&:hover {
background: rgba(64, 169, 255, 0.2);
// transform: translateY(-2px);
.stat-num {
color: #69c0ff;
text-shadow: 0 0 10px rgba(105, 192, 255, 0.5);
}
}
}
}
}
// 3个调度清单卡片
.dispatch-cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: vw(10);
.dispatch-card {
padding: vw(12);
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);
}
}
}
.card-num {
font-size: vw(20);
font-weight: bold;
color: #18f2f9;
margin-bottom: vw(6);
.unit {
font-size: vw(14);
color: rgba(255, 255, 255, 0.7);
font-weight: normal;
margin-left: 2px;
}
}
.card-label {
font-size: vw(14);
color: rgba(255, 255, 255, 0.8);
}
}
}
}
}
.date-range-wrapper {
:deep(.el-date-editor) {
border-radius: 0px !important;
height: 3.1em !important;
}
:deep(.el-date-editor) {
width: 200px;
max-width: vw(200);
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>