This commit is contained in:
huangchenhao 2026-04-13 14:04:58 +08:00
commit 97ca34d622
13 changed files with 1922 additions and 702 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,232 @@
<template>
<div class="center-info-card-container" v-if="visible" @click="handleClick">
<div
class="center-info-card"
:style="{ backgroundImage: `url(${districtIcon})` }"
>
<!-- 标题栏 -->
<div class="card-header">
<div class="header-left">
<img class="location-icon" :src="locationIcon" alt="" />
<span class="header-title">{{ title }}</span>
</div>
<span class="header-arrow">
<el-icon><ArrowRight /></el-icon>
</span>
</div>
<!-- 内容区域 -->
<div class="card-content">
<div class="info-row">
<span class="info-text">人数{{ item?.population || "-" }}</span>
<span class="info-text">
<span v-if="item?.type == 'project'">项目</span>
<span v-else>路段</span>
<span>{{ item?.entityCount || "-" }}</span>
<span v-if="item?.type == 'project'"></span>
<span v-else></span>
</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
import { ArrowRight, Close } from "@element-plus/icons-vue";
import districtIcon from "../../../assets/MaMap_img/区县弹窗背景@2x.png";
import locationIcon from "../../../assets/MaMap_img/区县icon@2x.png";
const props = defineProps({
//
visible: {
type: Boolean,
default: false,
},
// 'second' | 'third' | null
type: {
type: String,
default: null,
},
//
title: {
type: String,
default: "潼南",
},
//
dataList: {
type: Array,
default: () => [],
},
//
item: {
type: Object,
default: () => {},
},
//
peopleCount: {
type: [Number, String],
default: 0,
},
//
roadCount: {
type: [Number, String],
default: 117,
},
//
showClose: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(["click", "close", "itemClick", "onClick"]);
//
const showCard = computed(() => {
// visible 使
if (props.visible !== undefined) {
return props.visible;
}
// 使
return props.type === "second" || props.type === "third";
});
//
const getRoadTypeText = (roadType) => {
const roadTypeMap = {
national: "国省道",
rural: "农村公路",
};
return roadTypeMap[roadType] || roadType;
};
//
const handleClick = () => {
console.log("centerInfoCard clicked, type:", props.type);
// onClick
emit("onClick");
// click
emit("click", props.type);
};
//
const handleClose = () => {
emit("close");
};
//
const handleItemClick = (item) => {
emit("itemClick", item);
};
</script>
<style lang="scss" scoped>
@function vw($px) {
@return calc($px / 1920 * 100vw);
}
.center-info-card-container {
position: relative;
width: 100%;
min-width: 150px;
z-index: 1000;
cursor: pointer;
}
//
.center-info-card {
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
z-index: 50;
cursor: pointer;
transition: all 0.3s;
overflow: hidden;
border-radius: vw(8);
&:hover {
filter: brightness(1.1);
}
//
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: vw(10) vw(14);
.header-left {
display: flex;
align-items: center;
gap: vw(6);
.location-icon {
width: vw(16);
height: vw(16);
}
.header-title {
font-size: vw(14);
font-weight: 600;
color: #fff;
}
}
.header-arrow,
.header-close {
font-size: vw(14);
color: rgba(255, 255, 255, 0.7);
cursor: pointer;
transition: all 0.3s;
&:hover {
color: #fff;
}
}
}
//
.card-content {
padding: vw(8) vw(14) vw(12);
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
.info-text {
font-size: vw(12);
color: rgba(255, 255, 255, 0.9);
}
}
.data-list {
.data-item {
padding: vw(4) 0;
.item-row {
display: flex;
align-items: center;
margin-bottom: vw(2);
&:last-child {
margin-bottom: 0;
}
.item-label {
font-size: vw(11);
color: rgba(255, 255, 255, 0.7);
}
.item-value {
font-size: vw(11);
color: #fff;
font-weight: 500;
}
}
}
}
}
}
</style>

View File

@ -17,7 +17,13 @@
<div class="filter-row">
<div class="filter-item">
<span class="filter-label">影响区域</span>
<el-select :teleported="false" v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
<el-select
:teleported="false"
v-model="filterForm.district"
placeholder="请选择"
class="filter-select"
clearable
>
<el-option
v-for="item in regionOptions"
:key="item.value"
@ -28,7 +34,13 @@
</div>
<div class="filter-item">
<span class="filter-label">类型</span>
<el-select :teleported="false" v-model="filterForm.type" placeholder="请选择" class="filter-select" clearable>
<el-select
:teleported="false"
v-model="filterForm.type"
placeholder="请选择"
class="filter-select"
clearable
>
<el-option
v-for="item in typeOptions"
:key="item.value"
@ -39,7 +51,14 @@
</div>
<div class="filter-item">
<span class="filter-label">管控措施</span>
<el-select :teleported="false" v-model="filterForm.controlMeasure" placeholder="请选择" class="filter-select" clearable>
<el-select
:teleported="false"
v-model="filterForm.roadConditionType"
placeholder="请选择"
class="filter-select"
clearable
@change="handleFilterChange"
>
<el-option
v-for="item in controlMeasureOptions"
:key="item.value"
@ -66,8 +85,10 @@
</template>
<!-- 管控措施列插槽 -->
<template #controlMeasure="{ row }">
<span :class="['control-tag', getControlClass(row.controlMeasure)]">{{ row.controlMeasure }}</span>
<template #roadConditionType="{ row }">
<span :class="['control-tag', getControlClass(row.roadConditionType)]">{{
row.roadConditionType
}}</span>
</template>
<!-- 操作列插槽 -->
@ -80,8 +101,13 @@
<script setup>
import { ref, computed, watch } from "vue";
import { Close } from "@element-plus/icons-vue";
import { regionOptions, typeOptions, controlMeasureOptions } from "../component/index.js";
import {
regionOptions,
typeOptions,
controlMeasureOptions,
} from "../component/index.js";
import BaseDialog from "../component/baseDialog.vue";
import { request } from "@/utils/request";
const props = defineProps({
visible: {
@ -94,9 +120,9 @@ const emit = defineEmits(["update:visible", "close", "detail"]);
//
const filterForm = ref({
region: "",
district: "",
type: "",
controlMeasure: "",
roadConditionType: "",
});
//
@ -113,65 +139,25 @@ const tableHeight = ref(300);
//
const tableColumns = ref([
{ prop: 'id', label: '序号', width: '50' },
{ prop: 'region', label: '影响区域', width: '80' },
{ prop: 'routeNo', label: '线路编号', width: '80' },
{ prop: 'stakeNo', label: '起止桩号', width: '100', slot: 'stakeNo' },
{ prop: 'location', label: '路况位置', width: '100', slot: 'location' },
{ prop: 'occurrenceTime', label: '发生时间', width: '140' },
{ prop: 'routeNo2', label: '线路编号', width: '80' },
{ prop: 'type', label: '类型', width: '80' },
{ prop: 'controlMeasure', label: '管控措施', width: '100', slot: 'controlMeasure' },
{ prop: 'operation', label: '操作', width: '80', slot: 'operation' },
{ prop: "id", label: "序号", width: "" },
{ prop: "district", label: "影响区域", width: "" },
{ prop: "routeNo", label: "线路编号", width: "" },
{ prop: "stakeNo", label: "起止桩号", width: "", slot: "stakeNo" },
{ prop: "location", label: "路况位置", width: "", slot: "location" },
{ prop: "occurrenceTime", label: "发生时间", width: "" },
{ prop: "routeNo2", label: "线路编号", width: "" },
{ prop: "type", label: "类型", width: "" },
{
prop: "roadConditionType",
label: "管控措施",
width: "",
slot: "roadConditionType",
},
{ prop: "operation", label: "操作", width: "", slot: "operation" },
]);
//
const tableData = ref([
{
id: 1,
region: "巫溪县",
routeNo: "G242",
stakeNo: "336.800-338.850",
location: "三星乡五斗村",
occurrenceTime: "2025-08-11 04:53:42",
routeNo2: "G242",
type: "边坡坍塌",
controlMeasure: "全幅封闭",
},
{
id: 2,
region: "万州区",
routeNo: "G242",
stakeNo: "338.800-338.850",
location: "三星乡五斗村",
occurrenceTime: "2025-08-11 04:53:42",
routeNo2: "G242",
type: "边坡坍塌",
controlMeasure: "正常通行",
},
{
id: 3,
region: "沙坪坝区",
routeNo: "G319",
stakeNo: "120.500-122.000",
location: "沙坪坝镇",
occurrenceTime: "2025-08-10 14:30:00",
routeNo2: "G319",
type: "路面塌陷",
controlMeasure: "半幅封闭",
},
{
id: 4,
region: "渝中区",
routeNo: "G212",
stakeNo: "88.200-89.100",
location: "渝中大道",
occurrenceTime: "2025-08-09 09:15:30",
routeNo2: "G212",
type: "桥梁损坏",
controlMeasure: "限制通行",
},
]);
const tableData = ref([]);
//
const currentPage = ref(1);
@ -199,10 +185,10 @@ const visiblePages = computed(() => {
//
const getControlClass = (measure) => {
const classMap = {
"全幅封闭": "control-close",
"半幅封闭": "control-half",
"正常通行": "control-normal",
"限制通行": "control-limit",
全幅封闭: "control-close",
半幅封闭: "control-half",
正常通行: "control-normal",
限制通行: "control-limit",
};
return classMap[measure] || "";
};
@ -228,11 +214,59 @@ const handleCurrentChange = (val) => {
currentPage.value = val;
fetchData();
};
//
const handleFilterChange = () => {
currentPage.value = 1;
fetchData();
};
//
const fetchData = () => {
console.log("获取第", currentPage.value, "页数据");
// API
const fetchData = async () => {
try {
//
let measureType = 0;
if (filterForm.value.roadConditionType === "全幅封闭") {
measureType = 1;
} else if (filterForm.value.roadConditionType === "半幅封闭") {
measureType = 2;
} else if (filterForm.value.roadConditionType === "限速") {
measureType = 3;
} else if (filterForm.value.roadConditionType === "告警阻拦") {
measureType = 4;
}
const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/control-list",
method: "GET",
params: {
pageNum: currentPage.value,
pageSize: pageSize.value,
measureType: measureType,
},
});
if (res.code === "00000" && res.data) {
const data = res.data;
//
tableData.value = data.records.map((item) => {
return {
id: item.id,
district: item.district || "-",
routeNo: item.routeNo || "-",
stakeNo: `${item.startStakeNo}-${item.endStakeNo}` || "-",
location: item.occurLocation || "-",
occurrenceTime: item.occurTime || "-",
routeNo2: item.routeNo || "-",
type: item.roadConditionType || "-",
roadConditionType: item.roadConditionType || "-",
expectRecoverTime: item.expectRecoverTime || "-",
eventStatus: item.eventStatus || "-",
};
});
total.value = data.total;
}
} catch (error) {
console.error("获取抢通情况数据失败:", error);
}
};
// visible
@ -243,7 +277,7 @@ watch(
currentPage.value = 1;
fetchData();
}
}
},
);
</script>

View File

@ -19,78 +19,20 @@
<!-- 统计卡片 -->
<div class="stats-cards">
<div
@click="handleClick('0')"
v-for="(item, index) in impactData"
:key="index"
@click="handleClick(index)"
class="stat-card"
:style="{
backgroundImage: `url(${cardType === '0' ? selectedIcon : unselectedIcon})`,
backgroundImage: `url(${cardType == index ? selectedIcon : unselectedIcon})`,
backgroundSize: '100% 100%',
backgroundPosition: 'center',
}"
>
<div class="stat-icon"><img :src="Icon0" alt="" /></div>
<div class="stat-icon"><img :src="item.icon" alt="" /></div>
<div class="stat-content">
<span class="stat-label">影响桥梁</span>
<span class="stat-value">(1430)</span>
</div>
</div>
<div
@click="handleClick('1')"
class="stat-card"
:style="{
backgroundImage: `url(${cardType === '1' ? selectedIcon : unselectedIcon})`,
backgroundSize: '100% 100%',
backgroundPosition: 'center',
}"
>
<div class="stat-icon"><img :src="Icon1" alt="" /></div>
<div class="stat-content">
<span class="stat-label">影响边坡</span>
<span class="stat-value">(933)</span>
</div>
</div>
<div
@click="handleClick('2')"
class="stat-card"
:style="{
backgroundImage: `url(${cardType === '2' ? selectedIcon : unselectedIcon})`,
backgroundSize: '100% 100%',
backgroundPosition: 'center',
}"
>
<div class="stat-icon"><img :src="Icon2" alt="" /></div>
<div class="stat-content">
<span class="stat-label">影响隧道</span>
<span class="stat-value">(1033)</span>
</div>
</div>
<div
@click="handleClick('3')"
class="stat-card"
:style="{
backgroundImage: `url(${cardType === '3' ? selectedIcon : unselectedIcon})`,
backgroundSize: '100% 100%',
backgroundPosition: 'center',
}"
>
<div class="stat-icon"><img :src="Icon3" alt="" /></div>
<div class="stat-content">
<span class="stat-label">影响项目</span>
<span class="stat-value">(832)</span>
</div>
</div>
<div
@click="handleClick('4')"
class="stat-card"
:style="{
backgroundImage: `url(${cardType === '4' ? selectedIcon : unselectedIcon})`,
backgroundSize: '100% 100%',
backgroundPosition: 'center',
}"
>
<div class="stat-icon"><img :src="Icon4" alt="" /></div>
<div class="stat-content">
<span class="stat-label">影响路段</span>
<span class="stat-value">(832)</span>
<span class="stat-label">{{ item.name }}</span>
<span class="stat-value">{{ item.count }}</span>
</div>
</div>
</div>
@ -100,7 +42,8 @@
<template #filter>
<div class="filter-row">
<div class="filter-item">
<el-select :teleported="false"
<el-select
:teleported="false"
v-model="filterForm.pointType"
size="small"
placeholder="影响点类型"
@ -115,7 +58,8 @@
</el-select>
</div>
<div class="filter-item">
<el-select :teleported="false"
<el-select
:teleported="false"
v-model="filterForm.pointLevel"
size="small"
placeholder="影响点等级"
@ -130,7 +74,8 @@
</el-select>
</div>
<div class="filter-item">
<el-select :teleported="false"
<el-select
:teleported="false"
v-model="filterForm.region"
size="small"
placeholder="影响区域"
@ -191,16 +136,86 @@
</div>
</template>
<!-- 一般人员路长履职列插槽 -->
<template #generalStaff="{ row }">
<div class="person-info">
<span class="person-name">{{ row.generalStaff.name }}</span>
<span class="person-phone">{{ row.generalStaff.phone }}</span>
</div>
</template>
<!-- 项目类型专用插槽 -->
<!-- 吹哨人列插槽 -->
<template #whistleblower="{ row }">
<div class="person-info">
<span class="person-name">{{ row.whistleblower?.name || "-" }}</span>
<span class="person-phone">{{ row.whistleblower?.phone || "-" }}</span>
</div>
</template>
<!-- 建设单位包保责任人列插槽 -->
<template #constructionUnit="{ row }">
<div class="person-info">
<span class="person-name">{{ row.constructionUnit?.name || "-" }}</span>
<span class="person-phone">{{
row.constructionUnit?.phone || "-"
}}</span>
</div>
</template>
<!-- 施工单位包保责任人列插槽 -->
<template #constructionDept="{ row }">
<div class="person-info">
<span class="person-name">{{ row.constructionDept?.name || "-" }}</span>
<span class="person-phone">{{
row.constructionDept?.phone || "-"
}}</span>
</div>
</template>
<!-- 驻地包保责任人列插槽 -->
<template #siteResponsible="{ row }">
<div class="person-info">
<span class="person-name">{{ row.siteResponsible?.name || "-" }}</span>
<span class="person-phone">{{
row.siteResponsible?.phone || "-"
}}</span>
</div>
</template>
<!-- 区县级包保责任人列插槽 -->
<template #countyResponsible="{ row }">
<div class="person-info">
<span class="person-name">{{
row.countyResponsible?.name || "-"
}}</span>
<span class="person-phone">{{
row.countyResponsible?.phone || "-"
}}</span>
</div>
</template>
<!-- 市级包保责任人列插槽 -->
<template #cityResponsible="{ row }">
<div class="person-info">
<span class="person-name">{{ row.cityResponsible?.name || "-" }}</span>
<span class="person-phone">{{
row.cityResponsible?.phone || "-"
}}</span>
</div>
</template>
<!-- 操作列插槽 -->
<template #operation="{ row }">
<template #operation="{ row }" fixed="right">
<span class="detail-link" @click="handleDetail(row)">详情</span>
</template>
</base-dialog>
</template>
<script setup>
import { ref, computed, watch } from "vue";
import { ref, computed, watch, onMounted } from "vue";
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
import { request } from "@/utils/request";
import {
pointTypeOptions,
pointLevelOptions,
@ -235,8 +250,8 @@ const filterForm = ref({
region: "",
});
//
const tableColumns = ref([
// 使
const unifiedColumns = [
{ prop: "id", label: "序号", width: "" },
{ prop: "region", label: "影响区域", width: "" },
{ prop: "pointType", label: "影响点类型", width: "" },
@ -256,59 +271,171 @@ const tableColumns = ref([
slot: "maintenance",
},
{ prop: "roadKeeper", label: "护路员", width: "", slot: "roadKeeper" },
{ prop: "operation", label: "操作", width: "", slot: "operation" },
]);
{
prop: "generalStaff",
label: "一般人员(路长履职)",
width: "",
slot: "generalStaff",
},
{
prop: "operation",
label: "操作",
width: "80",
slot: "operation",
fixed: "right",
},
];
//
const projectColumns = [
{ prop: "id", label: "序号", width: "60" },
{ prop: "region", label: "影响区域", width: "" },
{ prop: "pointType", label: "影响点类型", width: "" },
{ prop: "siteName", label: "驻地名称", width: "" },
{
prop: "whistleblower",
label: "吹哨人",
width: "",
slot: "whistleblower",
},
{
prop: "constructionUnit",
label: "建设单位包保责任人",
width: "",
slot: "constructionUnit",
},
{
prop: "constructionDept",
label: "施工单位包保责任人",
width: "",
slot: "constructionDept",
},
{
prop: "siteResponsible",
label: "驻地包保责任人",
width: "",
slot: "siteResponsible",
},
{
prop: "countyResponsible",
label: "区县级包保责任人",
width: "",
slot: "countyResponsible",
},
{
prop: "cityResponsible",
label: "市级包保责任人",
width: "",
slot: "cityResponsible",
},
];
//
const bridgeColumns = unifiedColumns;
const slopeColumns = unifiedColumns;
const tunnelColumns = unifiedColumns;
const roadColumns = unifiedColumns;
//
const tableColumns = ref(bridgeColumns);
//
const tableData = ref([
{
id: 1,
region: "重庆市",
pointType: "边坡",
pointLocation: "武汉-大理(K1452+951至K1462+209)",
pointLevel: "一般隐患",
levelClass: "level-normal",
trafficDept: { name: "罗宸", phone: "17623865172" },
roadOrg: { name: "李海平", phone: "13708320801" },
maintenance: { name: "苏祖兵", phone: "13594331090" },
roadKeeper: { name: "凌承礼", phone: "1592393704" },
},
{
id: 2,
region: "重庆市",
pointType: "边坡",
pointLocation: "武汉-大理(K1452+951至K1462+209)",
pointLevel: "一般隐患",
levelClass: "level-normal",
trafficDept: { name: "罗宸", phone: "17623865172" },
roadOrg: { name: "李海平", phone: "13708320801" },
maintenance: { name: "苏祖兵", phone: "13594331090" },
roadKeeper: { name: "凌承礼", phone: "1592393704" },
},
{
id: 3,
region: "重庆市",
pointType: "边坡",
pointLocation: "武汉-大理(K1452+951至K1462+209)",
pointLevel: "一般隐患",
levelClass: "level-normal",
trafficDept: { name: "罗宸", phone: "17623865172" },
roadOrg: { name: "李海平", phone: "13708320801" },
maintenance: { name: "苏祖兵", phone: "13594331090" },
roadKeeper: { name: "凌承礼", phone: "1592393704" },
},
const tableData = ref([]);
//
const impactData = ref([
{ name: "影响桥梁", count: 0, icon: Icon0 },
{ name: "影响边坡", count: 0, icon: Icon1 },
{ name: "影响隧道", count: 0, icon: Icon2 },
{ name: "影响项目", count: 0, icon: Icon3 },
{ name: "影响路段", count: 0, icon: Icon4 },
]);
//
const loadBarChartData = async () => {
try {
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count",
method: "GET",
});
if (res.code == "00000") {
const data = res.data;
if (data && Array.isArray(data)) {
//
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) => {
impactData.value.forEach((stat) => {
if (stat.name.includes(item.extension)) {
stat.count = item.count || 0;
}
});
});
}
}
} catch (error) {
console.error("加载柱状图数据失败:", error);
}
};
const cardType = ref("0");
// cardType
const getColumnsByType = (type) => {
const typeMap = {
0: bridgeColumns,
1: slopeColumns,
2: tunnelColumns,
3: projectColumns,
4: roadColumns,
};
return typeMap[type] || bridgeColumns;
};
// cardType API
const getApiUrlByType = (type) => {
const urlMap = {
0: "/snow-ops-platform/weather-warning/affected-object/bridge",
1: "/snow-ops-platform/weather-warning/affected-object/slope",
2: "/snow-ops-platform/weather-warning/affected-object/tunnel",
3: "/snow-ops-platform/weather-warning/affected-object/project",
4: "/snow-ops-platform/weather-warning/affected-object/road-section",
};
return (
urlMap[type] || "/snow-ops-platform/weather-warning/affected-object/bridge"
);
};
const cardType = ref("");
//
const handleClick = (type) => {
cardType.value = type;
tableData.value = [];
cardType.value = type + "";
//
tableColumns.value = getColumnsByType(cardType.value);
//
currentPage.value = 1;
fetchData();
};
//
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(36);
const total = ref(0);
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
@ -358,11 +485,353 @@ const handleCurrentChange = (val) => {
currentPage.value = val;
fetchData();
};
//
const getTimeParams = () => {
// 1
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
return {
// start: `${year}-${month}-01 00:00:00`,
// end: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`,
start: "2025-07-01 00:00:00",
end: "2025-08-01 00:00:00",
limit: pageSize.value,
offset: currentPage.value,
};
};
//
const processUnifiedData = (item, type) => {
//
const typeMap = {
0: "桥梁",
1: "边坡",
2: "隧道",
3: "项目",
4: "路段",
};
//
const getLevelClass = (level) => {
const levelMap = {
红色预警: "level-red",
橙色预警: "level-orange",
黄色预警: "level-yellow",
蓝色预警: "level-blue",
高风险: "level-red",
中风险: "level-orange",
低风险: "level-blue",
};
return levelMap[level] || "";
};
//
const pointLevel =
item.riskLevel ||
item.warningLevel ||
item.level ||
item.GL1_PDDJ ||
item.GL1_JSDJ ||
"-";
//
const baseData = {
id: item.id,
//
region:
item.GL1_QXMC ||
item.COUNTY ||
item.county ||
item.region ||
item.ADMINISTRATIVE_REGION ||
"-",
//
pointType: typeMap[type] || "-",
//
pointLocation:
item.GL1_QLMC ||
item.NAME ||
item.GL1_SDMC ||
item.PROJECT_NAME ||
item.GL1_LXBH ||
item.name ||
"-",
//
pointLevel: pointLevel,
levelClass: getLevelClass(pointLevel),
//
trafficDept: {
// name: item.trafficDeptName || item.trafficManager || "-",
phone: item.trafficDeptPhone || item.trafficManagerPhone || "-",
name: "-",
phone: "-",
},
//
roadOrg: {
// name: item.roadOrgName || item.roadManager || "-",
// phone: item.roadOrgPhone || item.roadManagerPhone || "-",
name: "-",
phone: "-",
},
//
maintenance: {
// name: item.maintenanceName || item.maintenanceManager || "-",
// phone: item.maintenancePhone || item.maintenanceManagerPhone || "-",
name: "-",
phone: "-",
},
//
roadKeeper: {
// name: item.roadKeeperName || item.roadKeeper || "-",
// phone: item.roadKeeperPhone || item.roadKeeperPhone || "-",
name: "-",
phone: "-",
},
//
generalStaff: {
// name: item.generalStaffName || item.roadChief || "-",
// phone: item.generalStaffPhone || item.roadChiefPhone || "-",
name: "-",
phone: "-",
},
// 使
rawData: item,
};
// BASE_GLQL
if (type === "0") {
return {
...baseData,
// - 使
region: item.GL1_QXMC || "-",
// - 使
pointLocation: item.GL1_QLMC || "-",
// - 使
pointLevel: item.GL1_JSZKPJDJ || item.GL1_PDDJ || item.GL1_CSFXDJ || "-",
levelClass: getLevelClass(
item.GL1_JSZKPJDJ || item.GL1_PDDJ || item.GL1_CSFXDJ,
),
// // - GL1_DWFZR
// trafficDept: {
// name: item.GL1_DWFZR || "-",
// phone: item.GL1_GLDWDH || "-",
// },
// // - GL1_TJFZR
// roadOrg: {
// name: item.GL1_TJFZR || "-",
// phone: item.GL1_TJFZRDH || "-",
// },
// // - GL1_YHDWDH
// maintenance: {
// name: item.GL1_GLDWMC || "-",
// phone: item.GL1_YHDWDH || "-",
// },
// // -
// roadKeeper: {
// name: item.GL1_TBRXM || "-",
// phone: item.GL1_TBRDH || "-",
// },
// // - GL1_QLGCS
// generalStaff: {
// name: item.GL1_QLGCS || "-",
// phone: item.GL1_QLGCSDH || "-",
// },
};
}
// BASE_GLSD
if (type === "2") {
return {
...baseData,
// - 使
region: item.GL1_QXMC || item.GL1_QXBM || "-",
// - 使
pointLocation: item.GL1_SDMC || "-",
// - 使
pointLevel: item.GL1_PDDJ || item.GL1_TJJGPDDJ || item.GL1_SDYHDJ || "-",
levelClass: getLevelClass(
item.GL1_PDDJ || item.GL1_TJJGPDDJ || item.GL1_SDYHDJ,
),
// // - GL1_GYDWXZLD
// trafficDept: {
// name: item.GL1_GYDWXZLD || "-",
// phone: item.GL1_GYDWXZLDDH || "-",
// },
// // - GL1_SDLZY
// roadOrg: {
// name: item.GL1_SDLZY || "-",
// phone: item.GL1_SDLZYDH || "-",
// },
// // - GL1_SDYHG
// maintenance: {
// name: item.GL1_SDYHG || "-",
// phone: item.GL1_SDYHGDH || "-",
// },
// // - GL1_SDXXTBR
// roadKeeper: {
// name: item.GL1_SDXXTBR || "-",
// phone: item.GL1_SDXXTBRDH || "-",
// },
// // - GL1_GYDWYHGCS
// generalStaff: {
// name: item.GL1_GYDWYHGCS || "-",
// phone: item.GL1_GYDWYHGSCSDH || "-",
// },
};
}
// BASE_XJLD线
if (type === "4") {
return {
...baseData,
// - 使ID
region: item.GL1_QXMC || item.GL1_QXID || "-",
// - 使线+
pointLocation: item.GL1_LXMC || item.GL1_LXBH || item.name || "-",
// - 使
pointLevel: item.GL1_JSDJ || item.GL1_XZDJ || "-",
levelClass: getLevelClass(item.GL1_JSDJ || item.GL1_XZDJ),
// // - GL1_GLDW
// trafficDept: {
// name: item.GL1_GLDW || "-",
// phone: item.GL1_GLDWDH || "-",
// },
// // -
// roadOrg: {
// name: item.GL1_QDMC || "-",
// phone: item.GL1_QDZH ? String(item.GL1_QDZH) : "-",
// },
// // -
// maintenance: {
// name: item.GL1_ZDMC || "-",
// phone: item.GL1_ZDZH ? String(item.GL1_ZDZH) : "-",
// },
// // - 线
// roadKeeper: {
// name: item.GL1_LXBH || "-",
// phone: item.GL1_LXBM || "-",
// },
// // -
// generalStaff: {
// name: item.GL1_JSDJTXT || item.GL1_JSDJ || "-",
// phone: item.GL1_TZSJ || "-",
// },
};
}
// SQL
if (type === "3") {
return {
...baseData,
// - 使COUNTY
region: item.COUNTY || item.county || item.county_name || "-",
// - 使
pointLocation: item.PROJECT_NAME || item.projectName || item.name || "-",
//
siteName:
item.SITE_NAME ||
item.siteName ||
item.PROJECT_NAME ||
item.projectName ||
"-",
// - WHISTLEBLOWER_NAME / WHISTLEBLOWER_PHONE
whistleblower: {
name: item.WHISTLEBLOWER_NAME || item.whistleblowerName || "-",
phone: item.WHISTLEBLOWER_PHONE || item.whistleblowerPhone || "-",
},
// - OWNER_RESPONSIBLE_PERSON / OWNER_RESPONSIBLE_PHONE
constructionUnit: {
name:
item.OWNER_RESPONSIBLE_PERSON || item.ownerResponsiblePerson || "-",
phone:
item.OWNER_RESPONSIBLE_PHONE || item.ownerResponsiblePhone || "-",
},
// - CONSTRUCTOR_RESPONSIBLE_PERSON / CONSTRUCTOR_RESPONSIBLE_PHONE
constructionDept: {
name:
item.CONSTRUCTOR_RESPONSIBLE_PERSON ||
item.constructorResponsiblePerson ||
"-",
phone:
item.CONSTRUCTOR_RESPONSIBLE_PHONE ||
item.constructorResponsiblePhone ||
"-",
},
// - SITE_RESPONSIBLE_PERSON / SITE_RESPONSIBLE_PHONE
siteResponsible: {
name: item.SITE_RESPONSIBLE_PERSON || item.siteResponsiblePerson || "-",
phone: item.SITE_RESPONSIBLE_PHONE || item.siteResponsiblePhone || "-",
},
// - DISTRICT_RESPONSIBLE_PERSON / DISTRICT_RESPONSIBLE_PHONE
countyResponsible: {
name:
item.DISTRICT_RESPONSIBLE_PERSON ||
item.districtResponsiblePerson ||
"-",
phone:
item.DISTRICT_RESPONSIBLE_PHONE ||
item.districtResponsiblePhone ||
"-",
},
// - CITY_RESPONSIBLE_PERSON / CITY_RESPONSIBLE_PHONE
cityResponsible: {
name: item.CITY_RESPONSIBLE_PERSON || item.cityResponsiblePerson || "-",
phone: item.CITY_RESPONSIBLE_PHONE || item.cityResponsiblePhone || "-",
},
};
}
return baseData;
};
//
const processDataByType = (item, type) => {
return processUnifiedData(item, type);
};
//
const fetchData = () => {
console.log("获取第", currentPage.value, "页数据");
// API
const fetchData = async () => {
console.log("获取第", currentPage.value, "页数据, 类型:", cardType.value);
try {
const timeParams = getTimeParams();
// cardType API URL
const apiUrl = getApiUrlByType(cardType.value);
const res = await request({
url: apiUrl,
method: "GET",
params: timeParams,
});
if (res.code === "00000" && res.data) {
//
const allData = res.data;
total.value = allData.length || 0;
//
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
const currentPageData = allData.slice(startIndex, endIndex);
tableData.value = currentPageData.map((item, index) => ({
...processDataByType(item, cardType.value),
id: startIndex + index + 1,
}));
} else {
tableData.value = [];
total.value = 0;
}
} catch (error) {
console.error("获取影响点数据失败:", error);
tableData.value = [];
total.value = 0;
}
};
// visible
@ -370,6 +839,13 @@ watch(
() => props.visible,
(newVal) => {
if (newVal) {
filterForm.value = {
pointType: "",
pointLevel: "",
region: "",
};
cardType.value = "0";
loadBarChartData();
currentPage.value = 1;
fetchData();
}
@ -468,42 +944,6 @@ watch(
}
}
//
.level-tag {
display: inline-block;
padding: vw(2) vw(8);
border-radius: vw(4);
font-size: vw(11);
&.level-normal {
background-color: rgba(250, 219, 95, 0.2);
color: #fadb5f;
border: 1px solid rgba(250, 219, 95, 0.4);
}
&.level-serious {
background-color: rgba(255, 77, 79, 0.2);
color: #ff4d4f;
border: 1px solid rgba(255, 77, 79, 0.4);
}
}
.person-info {
display: flex;
flex-direction: column;
gap: vw(2);
.person-name {
font-size: vw(12);
color: rgba(255, 255, 255, 0.9);
}
.person-phone {
font-size: vw(11);
color: rgba(255, 255, 255, 0.6);
}
}
.detail-link {
color: #40a9ff;
cursor: pointer;

View File

@ -18,7 +18,7 @@
<div class="filter-item">
<span class="filter-label">预警等级</span>
<el-select
v-model="filterForm.warningLevel"
v-model="filterForm.riskLeve"
placeholder="请选择"
class="filter-select el-select"
clearable
@ -36,7 +36,7 @@
<div class="filter-item">
<span class="filter-label">影响区域</span>
<el-select
v-model="filterForm.region"
v-model="filterForm.countyName"
placeholder="请选择"
class="filter-select"
clearable
@ -89,9 +89,9 @@
</template>
<!-- 预警等级列插槽 -->
<template #warningLevel="{ row }">
<span :class="['warning-level-tag', getWarningClass(row.warningLevel)]">{{
row.warningLevel
<template #riskLeve="{ row }">
<span :class="['warning-level-tag', getWarningClass(row.riskLeve)]">{{
row.riskLeve
}}</span>
</template>
@ -105,14 +105,15 @@
</template>
<script setup>
import { ref, computed, watch } from "vue";
import { Close } from "@element-plus/icons-vue";
import { ref, computed, watch, onMounted } from "vue";
import { Close, Calendar } from "@element-plus/icons-vue";
import {
warningLevelOptions,
regionOptions,
isEndedOptions,
} from "../component/index.js";
import baseDialog from "../component/baseDialog.vue";
import { request } from "@/utils/request";
const props = defineProps({
visible: {
@ -121,24 +122,42 @@ const props = defineProps({
},
});
const emit = defineEmits(["update:visible", "close", "impactClick"]);
//
const getDefaultDateRange = () => {
const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth(), 1);
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
return [start, end];
return ['', ''];
};
onMounted(() => {
filterForm.value = {
riskLeve: "",
countyName: "",
isEnded: "",
dateRange: dateRange.value,
};
fetchWarningData();
});
//
const dateRange = ref([]);
const dateRange = ref(getDefaultDateRange());
//
const filterForm = ref({
riskLeve: "",
countyName: "",
isEnded: "",
dateRange: dateRange.value,
});
//
const handleDateChange = (val) => {
filterForm.value.dateRange = val;
};
const emit = defineEmits(["update:visible", "close", "impactClick"]);
//
const filterForm = ref({
warningLevel: "",
region: "",
isEnded: "",
dateRange: [],
});
//
// index.js
@ -155,13 +174,18 @@ const tableHeight = ref(300);
const tableColumns = ref([
{ prop: "index", label: "序号", width: "" },
{
prop: "warningLevel",
prop: "riskLeve",
label: "预警等级",
width: "",
slot: "warningLevel",
slot: "riskLeve",
},
{
label: "来源",
prop: "source",
width: "",
},
{ prop: "weatherType", label: "气象类型", width: "" },
{ prop: "region", label: "影响区域", width: "" },
{ prop: "countyName", label: "影响区域", width: "" },
{ prop: "warningTime", label: "生效时间", width: "" },
{ prop: "endTime", label: "失效时间", width: "" },
{
@ -173,54 +197,95 @@ const tableColumns = ref([
]);
//
const tableData = ref([
{
id: 1,
index: 1,
warningLevel: "红色预警",
weatherType: "暴雨",
region: "重庆市",
warningTime: "2025-08-11 04:53:42",
endTime: "2025-08-11 04:53:42",
impactCount: 0,
},
{
id: 2,
index: 2,
warningLevel: "橙色预警",
weatherType: "暴雨",
region: "万州区",
warningTime: "2025-08-11 04:53:42",
endTime: "2025-08-11 04:53:42",
impactCount: 1,
},
{
id: 3,
index: 3,
warningLevel: "黄色预警",
weatherType: "大风",
region: "沙坪坝区",
warningTime: "2025-08-10 16:20:15",
endTime: "2025-08-10 20:30:00",
impactCount: 3,
},
{
id: 4,
index: 4,
warningLevel: "蓝色预警",
weatherType: "雷电",
region: "渝中区",
warningTime: "2025-08-09 09:15:30",
endTime: "2025-08-09 12:00:00",
impactCount: 2,
},
]);
tableData.value.push(...tableData.value);
tableData.value.push(...tableData.value);
const tableData = ref([]);
//
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(36);
const total = ref(0);
//
const loading = ref(false);
//
const fetchWarningData = async () => {
loading.value = true;
try {
const params = {
offset: currentPage.value,
limit: pageSize.value,
start: "",
end: "",
riskLevel: "",
weatherType: "",
isExpire: "",
countyName: "",
};
//
if (filterForm.value.riskLeve) {
params.riskLevel = filterForm.value.riskLeve;
}
if (filterForm.value.countyName) {
params.countyName = filterForm.value.countyName;
}
if (
filterForm.value.isEnded !== undefined &&
filterForm.value.isEnded !== ""
) {
params.isExpire = filterForm.value.isEnded;
}
if (filterForm.value.dateRange && filterForm.value.dateRange.length === 2) {
params.start = formatDateTime(filterForm.value.dateRange[0]);
params.end = formatDateTime(filterForm.value.dateRange[1]);
}
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count/_by_weather",
method: "GET",
params,
});
if (res.code === "00000" && res.data) {
//
const list = res.data.data || res.data.records || [];
total.value = res.data.total || 0;
tableData.value = list.map((item, index) => ({
index: index + 1,
riskLeve: item.riskLeve || "-",
weatherType: item.weatherType || "-",
countyName: item.countyName || "-",
source: item.source || "-",
warningTime: item.startTime || "-",
endTime: item.endTime || "-",
impactCount: item.affectedCount || 0,
}));
} else {
tableData.value = [];
total.value = 0;
}
} catch (error) {
console.error("获取预警数据失败:", error);
tableData.value = [];
total.value = 0;
} finally {
loading.value = false;
}
};
//
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 getWarningClass = (level) => {
@ -247,18 +312,12 @@ const handleImpactClick = (item) => {
//
const handleSizeChange = (val) => {
pageSize.value = val;
fetchData();
fetchWarningData();
};
const handleCurrentChange = (val) => {
currentPage.value = val;
fetchData();
};
//
const fetchData = () => {
console.log("获取第", currentPage.value, "页数据");
// API
fetchWarningData();
};
// visible
@ -267,10 +326,37 @@ watch(
(newVal) => {
if (newVal) {
currentPage.value = 1;
fetchData();
fetchWarningData();
}
},
);
//
watch(
() => filterForm.value,
() => {
currentPage.value = 1;
fetchWarningData();
},
{ deep: true },
);
// dateRange filterForm.dateRange
watch(
() => dateRange.value,
(newVal) => {
filterForm.value.dateRange = newVal;
},
{ deep: true },
);
watch(
() => filterForm.value.dateRange,
(newVal) => {
dateRange.value = newVal;
},
{ deep: true },
);
</script>
<style lang="scss" scoped>
@ -415,6 +501,6 @@ watch(
:deep(.el-range-editor.el-input__wrapper) {
width: 240px !important;
height: 30px !important;
background-color: #122C46 !important;
background-color: #122c46 !important;
}
</style>

View File

@ -25,14 +25,30 @@
:type="mapInfoDialogType"
:data="mapInfoDialogData"
/>
<centerInfoCard
:visible="centerCardVisible"
:title="centerCardTitle"
:dataList="centerCardDataList"
@close="closeCenterCard"
@itemClick="handleCenterCardItemClick"
@click="handleCenterCardClick"
/>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch, defineExpose } from "vue";
import {
ref,
onMounted,
onUnmounted,
watch,
defineExpose,
h,
render,
} from "vue";
import axios from "axios";
import { request } from "@/utils/request";
import TongnanCenterCardDialog from "@/views/RiskWarning/Dialog/tongnanCenterCardDialog.vue";
import TongnanCenterCardDialog from "../Dialog/tongnanCenterCardDialog.vue";
import projectIcon from "../../../assets/MaMap_img/项目@2x.png";
import bridgeIcon from "../../../assets/MaMap_img/桥梁icon@2x.png";
@ -43,6 +59,7 @@ import rescueTeamIcon from "../../../assets/MaMap_img/队伍icon@2x.png";
import tunnelInfoDialog from "../Dialog/tunnelInfoDialog.vue";
import mapInfoDialog from "../Dialog/mapInfoDialog.vue";
import centerInfoCard from "../Dialog/centerInfoCard.vue";
const mapContainer = ref(null);
const loading = ref(false);
@ -62,7 +79,12 @@ const props = defineProps({
});
// emits
const emit = defineEmits(["districtClick"]);
const emit = defineEmits([
"districtClick",
"openTongnanTeam",
"openResponseSituation",
"openTongnanResponsible",
]);
//
const selectedDistrict = ref(null);
@ -77,6 +99,14 @@ const mapInfoDialogVisible = ref(false);
const mapInfoDialogType = ref("project");
const mapInfoDialogData = ref({});
//
const centerCardVisible = ref(false);
const centerCardTitle = ref("调度统计");
const centerCardDataList = ref([]);
//
let countyCardMarkers = [];
//
const openMapInfoDialog = (type, data) => {
mapInfoDialogType.value = type;
@ -84,6 +114,164 @@ const openMapInfoDialog = (type, data) => {
mapInfoDialogVisible.value = true;
};
//
const clearCountyCardMarkers = () => {
countyCardMarkers.forEach((marker) => {
// Vue
if (marker._vueContainer) {
render(null, marker._vueContainer);
}
if (mapInstance) {
mapInstance.removeLayer(marker);
}
});
countyCardMarkers = [];
};
//
const showCountyCardsOnMap = (dataList) => {
if (!mapInstance || !geoJsonLayer) {
console.warn("地图未初始化,无法显示区县卡片");
return;
}
//
clearCountyCardMarkers();
if (!dataList || dataList.length === 0) {
return;
}
//
const simplifyName = (name) => {
return name
.replace("土家族苗族自治县", "")
.replace("苗族土家族自治县", "")
.replace("自治县", "")
.replace("区", "")
.replace("县", "");
};
//
dataList.forEach((item) => {
const countyName = item.countyName || item.name;
if (!countyName) return;
const targetName = simplifyName(countyName);
//
let targetLayer = null;
geoJsonLayer.eachLayer((layer) => {
const layerName = layer.feature?.properties?.name || "";
if (simplifyName(layerName) === targetName) {
targetLayer = layer;
}
});
if (targetLayer) {
//
const bounds = targetLayer.getBounds();
const center = bounds.getCenter();
// Vue
const container = document.createElement("div");
container.className = "county-card-wrapper";
// 使 Vue h
const vnode = h(centerInfoCard, {
visible: true,
title: countyName,
dataList: [item],
item: item,
onClose: () => {
closeCenterCard();
},
onItemClick: (clickedItem) => {
handleCenterCardItemClick(clickedItem);
},
});
//
render(vnode, container);
// 使 HTML
const customIcon = window.L.divIcon({
className: "county-card-icon",
html: container.innerHTML,
iconSize: [150, 40],
iconAnchor: [110, 60],
});
//
const marker = window.L.marker(center, {
icon: customIcon,
interactive: true,
});
// marker
marker.on("click", () => {
console.log("centerInfoCard clicked, county:", countyName);
//
handleCenterCardItemClick(item);
//
mapInstance.setView(center, 10);
//
emit("districtClick", {
name: countyName,
data: item,
});
});
marker.addTo(mapInstance);
countyCardMarkers.push(marker);
// 便
marker._vueContainer = container;
}
});
//
if (countyCardMarkers.length > 0) {
const group = new window.L.featureGroup(countyCardMarkers);
mapInstance.fitBounds(group.getBounds().pad(0.2));
}
};
//
const getRoadTypeText = (roadType) => {
const roadTypeMap = {
national: "国省道",
rural: "农村公路",
};
return roadTypeMap[roadType] || roadType;
};
//
const openCenterCard = (data) => {
centerCardDataList.value = data.dataList || [];
centerCardTitle.value = data.title || "调度统计";
centerCardVisible.value = true;
//
showCountyCardsOnMap(data.dataList);
};
//
const closeCenterCard = () => {
centerCardVisible.value = false;
clearCountyCardMarkers();
};
//
const handleCenterCardItemClick = (item) => {
console.log("点击了卡片项:", item);
//
if (item.countyName || item.name) {
const countyName = item.countyName || item.name;
locateToDistrict(countyName);
}
};
//
const openTunnelDialog = (data) => {
openMapInfoDialog("tunnel", data);
@ -151,7 +339,7 @@ const getAffectedCountyData = async () => {
getAffectedTunnelData();
getAffectedBridgeData();
getAffectedRoadSectionData();
getEmergencyForceData();
// getEmergencyForceData();
loadMapData();
}
@ -330,7 +518,13 @@ const clearProjectMarkers = () => {
mapInstance.removeLayer(marker);
}
});
clearCountyCardMarkers();
projectMarkers = [];
//
tunnelDialogVisible.value = false;
mapInfoDialogVisible.value = false;
centerCardVisible.value = false;
};
//
@ -374,15 +568,6 @@ const addProjectMarkers = (data, iconUrl, type = "project") => {
const latNum = parseFloat(lat);
const lngNum = parseFloat(lng);
console.log(
"项目坐标:",
item.NAME || item.name,
"纬度:",
latNum,
"经度:",
lngNum,
);
if (!isNaN(latNum) && !isNaN(lngNum)) {
const marker = window.L.marker([latNum, lngNum], {
icon: projectIconObj,
@ -709,7 +894,7 @@ const initMap = (geoJsonData) => {
affectedCountyData.value.byName[districtName]
) {
const districtData = affectedCountyData.value.byName[districtName];
console.log(districtData.levels);
// console.log(districtData.levels);
fillColor = getMainWarningColor(districtData.levels);
fillOpacity = 1; //
}
@ -945,10 +1130,67 @@ onUnmounted(() => {
}
});
//
const locateToDistrict = (countyName) => {
if (!mapInstance || !geoJsonLayer) {
console.warn("地图未初始化,无法定位");
return;
}
//
const simplifyName = (name) => {
return name
.replace("土家族苗族自治县", "")
.replace("苗族土家族自治县", "")
.replace("自治县", "")
.replace("区", "")
.replace("县", "");
};
const targetName = simplifyName(countyName);
console.log("定位到区县:", countyName, "简化后:", targetName);
//
let targetLayer = null;
geoJsonLayer.eachLayer((layer) => {
const layerName = layer.feature?.properties?.name || "";
if (simplifyName(layerName) === targetName) {
targetLayer = layer;
}
});
if (targetLayer) {
//
const bounds = targetLayer.getBounds();
const center = bounds.getCenter();
//
mapInstance.setView(center, 10);
//
if (selectedLayer) {
geoJsonLayer.resetStyle(selectedLayer);
}
targetLayer.setStyle({
fillColor: "#ff7a00",
fillOpacity: 0.6,
weight: 3,
color: "#ff4d4f",
});
selectedLayer = targetLayer;
console.log("已定位到区县:", countyName, "中心点:", center);
} else {
console.warn("未找到区县:", countyName);
}
};
//
defineExpose({
getEmergencyForceData,
clearProjectMarkers,
openCenterCard,
locateToDistrict,
});
</script>
@ -1110,4 +1352,27 @@ defineExpose({
padding: 15px;
font-weight: 500;
}
//
:deep(.county-card-icon) {
background: transparent !important;
border: none !important;
.center-info-card-container {
width: 100%;
min-width: 150px;
}
.center-info-card {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
cursor: pointer;
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(24, 144, 255, 0.5);
filter: brightness(1.1);
}
}
}
</style>

View File

@ -34,11 +34,11 @@
<slot name="filter"></slot>
</div>
<!-- 数据表格 -->
<div class="table-section" v-if="props.tableData.length > 0">
<div class="table-section">
<el-table
:data="props.tableData"
:height="props.tableHeight"
style="width: 100%"
style="width: 100%; min-height: 300px"
:header-cell-style="headerCellStyle"
:cell-style="cellStyle"
size="small"
@ -59,10 +59,7 @@
</div>
<!-- 分页 -->
<div
class="pagination"
v-if="props.showPagination && props.tableData.length > 0"
>
<div class="pagination">
<el-pagination
:current-page="props.currentPage"
:page-size="props.pageSize"
@ -468,4 +465,9 @@ const cellStyle = () => {
:deep(.el-popper__arrow::after) {
border-color: #122c46 !important;
}
:deep(.el-pager li.is-active) {
background-color: #2598ff !important;
color: #fff !important;
}
</style>

View File

@ -7,6 +7,7 @@
/* 防止样式被覆盖,提高优先级 */
.custom-date-picker {
z-index: 10000 !important;
/* 弹出框整体背景色 */
background-color: #122C45 !important;
/* 弹出框边框(主题色) */
@ -14,9 +15,11 @@
/* 可选:阴影效果 */
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.3) !important;
}
.el-date-editor .el-range-input {
color: #289DFF !important;
}
/* ========== 1. 顶部栏(年月切换区域) ========== */
.custom-date-picker .el-date-picker__header,
.custom-date-picker .el-picker-panel__header {
@ -144,6 +147,7 @@
.custom-date-picker .popper__arrow {
border-bottom-color: #122C45 !important;
}
.custom-date-picker .popper__arrow::after {
border-bottom-color: #122C45 !important;
}
@ -156,7 +160,7 @@
/* 范围选择左右面板 */
.custom-date-picker .el-date-range-picker__content {
background-color: #122C45 !important;
background-color: #152D47 !important;
}
/* 范围选择头部 */
@ -172,10 +176,13 @@
color: #FFFFFF !important;
border-radius: 4px;
}
.el-date-table td.in-range .el-date-table-cell{
background-color: #27374A !important;
border-radius: 0;
}
/* 范围选择 - 中间区间 */
.custom-date-picker .el-date-table td.in-range .el-date-table-cell__text {
background-color: rgba(40, 157, 255, 0.25) !important;
background-color: #3E91BC !important;
color: #FFFFFF !important;
border-radius: 0;
}
@ -207,7 +214,7 @@
.custom-date-picker .el-time-spinner__item.active {
background-color: #289DFF !important;
color: #FFFFFF !important;
}
}
/* ========== 13. 快捷选项样式 ========== */
.custom-date-picker .el-picker-panel__shortcut {
@ -219,6 +226,7 @@
background-color: rgba(40, 157, 255, 0.2) !important;
color: #289DFF !important;
}
.el-range__icon{
color: #289DFF !important;
.el-range__icon {
color: #289DFF !important;
}

View File

@ -31,9 +31,9 @@ export const typeOptions = [
// 管控措施选项
export const controlMeasureOptions = [
{ label: "全幅封闭", value: "全幅封闭" },
{ label: "半幅封闭", value: "半幅封闭" },
{ label: "正常通行", value: "正常通行" },
{ label: "限制通行", value: "限制通行" },
{ label: "半幅通行", value: "半幅通行" },
{ label: "限速", value: "限速" },
{ label: "告警阻拦", value: "告警阻拦" },
];
// 风险等级选项
@ -79,8 +79,8 @@ export const warningLevelOptions = [
// 是否结束选项
export const isEndedOptions = [
{ label: "全部", value: "" },
{ label: "是", value: "yes" },
{ label: "否", value: "no" },
{ label: "是", value: true },
{ label: "否", value: false },
];
// 行政区域选项(带全部)

View File

@ -25,59 +25,12 @@
<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>
<centerInfoCard
:type="showCenterCard.type"
:peopleCount="showCenterCard.value"
roadCount="117"
@click="handleCenterCardClick"
/>
<div class="left">
<left
@ -88,7 +41,7 @@
@openWarningSituation="openDialog('warningSituation')"
@openResponseStatus="openDialog('responseStatus')"
@openDispatchDistrict="openDialog('dispatchDistrict')"
@showCenterCard="(item) => (showCenterCard = item)"
@showCenterCard="(item) => handleCenterCardClick(item)"
></left>
</div>
<div class="right">
@ -102,150 +55,163 @@
<div class="center">
<!-- 地图底层 -->
<div class="map-layer">
<ChongqingMap ref="chongqingMapRef" :activeIndex="activeIndex" :dateRange="dateRange" />
<ChongqingMap
ref="chongqingMapRef"
:activeIndex="activeIndex"
:dateRange="dateRange"
@districtClick="handleDistrictClick"
/>
</div>
<!-- 地图遮罩层 -->
<div class="map-mask" aria-hidden="true"></div>
</div>
<div class="bottom">
<bottom @changeActiveIndex="changeActiveIndex" @clearMapMarkers="clearMapMarkers"></bottom>
<bottom
@changeActiveIndex="changeActiveIndex"
@clearMapMarkers="clearMapMarkers"
></bottom>
</div>
<top class="top" @openAIResult="openDialog('aiWarningResult')" @dateRangeChange="handleDateRangeChange"></top>
<top
class="top"
@openAIResult="openDialog('aiWarningResult')"
@dateRangeChange="handleDateRangeChange"
></top>
<div>
<!-- 农村公路对话框 -->
<responseSituationDiaLog
v-model:visible="dialogVisible.responseSituation"
@close="closeDialog('responseSituation')"
/>
<!-- 响应情况对话框 -->
<responseSituationDiaLog
v-model:visible="dialogVisible.responseSituation"
@close="closeDialog('responseSituation')"
/>
<!-- 预警信息对话框 -->
<warningInfoDialog
v-model:visible="dialogVisible.warningInfo"
@close="closeDialog('warningInfo')"
@responseStatus="openDialog('responseStatus')"
/>
<!-- 预警信息对话框 -->
<warningInfoDialog
v-model:visible="dialogVisible.warningInfo"
@close="closeDialog('warningInfo')"
@responseStatus="openDialog('responseStatus')"
/>
<!-- 事件详情对话框 -->
<eventDetailDialog
v-model:visible="dialogVisible.eventDetail"
@close="closeDialog('eventDetail')"
/>
<!-- 事件详情对话框 -->
<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')"
/>
<!-- 确认对话框 -->
<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')"
/>
<!-- 风险点详情对话框 -->
<riskPointDetailDialog
v-model:visible="dialogVisible.riskPointDetail"
@close="closeDialog('riskPointDetail')"
/>
<!-- 影响点情况对话框 -->
<impactPointDialog
v-model:visible="dialogVisible.impactPoint"
@close="closeDialog('impactPoint')"
@detail="openDialog('impactPointDetail')"
/>
<!-- 影响点情况对话框 -->
<impactPointDialog
v-model:visible="dialogVisible.impactPoint"
@close="closeDialog('impactPoint')"
@detail="openDialog('impactPointDetail')"
/>
<!-- 影响点详情对话框 -->
<impactPointDetailDialog
v-model:visible="dialogVisible.impactPointDetail"
@close="closeDialog('impactPointDetail')"
/>
<!-- 响点详情对话框 -->
<impactPointDetailDialog
v-model:visible="dialogVisible.impactPointDetail"
@close="closeDialog('impactPointDetail')"
/>
<!-- 点详情对话框 -->
<responsePointDetailDialog
v-model:visible="dialogVisible.responsePointDetail"
@close="closeDialog('responsePointDetail')"
/>
<!-- 响应点详情对话框 -->
<responsePointDetailDialog
v-model:visible="dialogVisible.responsePointDetail"
@close="closeDialog('responsePointDetail')"
/>
<!-- 响应点信息对话框 -->
<responsePointInfoDialog
v-model:visible="dialogVisible.responsePointInfo"
@close="closeDialog('responsePointInfo')"
/>
<!-- 响应点信息对话框 -->
<responsePointInfoDialog
v-model:visible="dialogVisible.responsePointInfo"
@close="closeDialog('responsePointInfo')"
/>
<!-- 响应状态对话框 -->
<responseStatusDialog
v-model:visible="dialogVisible.responseStatus"
@close="closeDialog('responseStatus')"
@detail="openDialog('impactPointDetail')"
/>
<!-- 响应状态对话框 -->
<responseStatusDialog
v-model:visible="dialogVisible.responseStatus"
@close="closeDialog('responseStatus')"
@detail="openDialog('impactPointDetail')"
/>
<!-- AI预警处理结果对话框 -->
<aiWarningResultDialog
v-model:visible="dialogVisible.aiWarningResult"
@close="closeDialog('aiWarningResult')"
/>
<!-- AI预警处理结果对话框 -->
<aiWarningResultDialog
v-model:visible="dialogVisible.aiWarningResult"
@close="closeDialog('aiWarningResult')"
/>
<!-- 潼南基本信息对话框 -->
<tongnanInfoDialog
v-model:visible="dialogVisible.tongnanInfo"
@close="closeDialog('tongnanInfo')"
@call="openDialog('confirm')"
/>
<!-- 潼南基本信息对话框 -->
<tongnanInfoDialog
v-model:visible="dialogVisible.tongnanInfo"
@close="closeDialog('tongnanInfo')"
@call="openDialog('confirm')"
/>
<!-- 项目对话框 -->
<tongnanResponsibleDialog
v-model:visible="dialogVisible.tongnanResponsible"
@close="closeDialog('tongnanResponsible')"
@detail="openDialog('tongnanInfo')"
/>
<!-- 潼南建设项目责任人明细对话框 -->
<tongnanResponsibleDialog
v-model:visible="dialogVisible.tongnanResponsible"
@close="closeDialog('tongnanResponsible')"
@detail="openDialog('tongnanInfo')"
/>
<!-- 抢通情况对话框 -->
<clearanceSituationDialog
v-model:visible="dialogVisible.clearanceSituation"
@close="closeDialog('clearanceSituation')"
@detail="openDialog('eventDetail')"
/>
<!-- 抢通情况对话框 -->
<clearanceSituationDialog
v-model:visible="dialogVisible.clearanceSituation"
@close="closeDialog('clearanceSituation')"
@detail="openDialog('eventDetail')"
/>
<!-- 管控情况对话框 -->
<controlSituationDialog
v-model:visible="dialogVisible.controlSituation"
@close="closeDialog('controlSituation')"
/>
<!-- 管控情况对话框 -->
<controlSituationDialog
v-model:visible="dialogVisible.controlSituation"
@close="closeDialog('controlSituation')"
/>
<!-- 调度详情对话框 -->
<dispatchDetailDialog
v-model:visible="dialogVisible.dispatchDetail"
@close="closeDialog('dispatchDetail')"
/>
<!-- 调度详情对话框 -->
<dispatchDetailDialog
v-model:visible="dialogVisible.dispatchDetail"
@close="closeDialog('dispatchDetail')"
/>
<!-- 调度区县情况对话框 -->
<dispatchDistrictDialog
v-model:visible="dialogVisible.dispatchDistrict"
@close="closeDialog('dispatchDistrict')"
@dispatchClick="openDialog('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')"
/>
<!-- 潼南护路团队成员对话框 -->
<tongnanTeamDialog
v-model:visible="dialogVisible.tongnanTeam"
@close="closeDialog('tongnanTeam')"
@view="openDialog('tongnanInfo')"
/>
<!-- 预警情况对话框 -->
<warningSituationDialog
v-model:visible="dialogVisible.warningSituation"
@close="closeDialog('warningSituation')"
@impactClick="openDialog('impactPoint')"
/>
<!-- 预警情况对话框 -->
<warningSituationDialog
v-model:visible="dialogVisible.warningSituation"
@close="closeDialog('warningSituation')"
@impactClick="openDialog('impactPoint')"
/>
<!-- 隧道信息对话框 -->
<tunnelInfoDialog
v-model:visible="dialogVisible.tunnelInfo"
@close="closeDialog('tunnelInfo')"
/>
<!-- 隧道信息对话框 -->
<tunnelInfoDialog
v-model:visible="dialogVisible.tunnelInfo"
@close="closeDialog('tunnelInfo')"
/>
</div>
</div>
</template>
@ -280,9 +246,10 @@ 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'
import "./component/el-select.scss";
import "./component/date-picker-theme.scss";
//
const dialogVisible = ref({
@ -304,8 +271,8 @@ const dialogVisible = ref({
dispatchDetail: false,
dispatchDistrict: false,
tongnanTeam: false,
warningSituation: false,
tunnelInfo: false
warningSituation: false,
tunnelInfo: false,
});
const activeIndex = ref(0);
@ -376,10 +343,67 @@ const openConfirm = (config) => {
confirmConfig.value = { ...confirmConfig.value, ...config };
dialogVisible.value.confirm = true;
};
//
const showCenterCard = ref(false);
//
const handleDistrictClick = (item) => {
console.log("区县点击:", item.data);
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);
@ -396,8 +420,8 @@ const triggerRefreshLeftData = () => {
};
//
provide('setRefreshLeftData', setRefreshLeftData);
provide('triggerRefreshLeftData', triggerRefreshLeftData);
provide("setRefreshLeftData", setRefreshLeftData);
provide("triggerRefreshLeftData", triggerRefreshLeftData);
// ==================== ====================
@ -483,7 +507,7 @@ onMounted(() => {
top: vw(60);
width: 25%;
height: calc(100% - #{vw(60)});
z-index: 2;
z-index: 3;
}
.right {
@ -492,7 +516,7 @@ onMounted(() => {
top: vw(60);
width: 25%;
height: calc(100% - #{vw(60)});
z-index: 2;
z-index: 3;
}
.bottom {
@ -508,7 +532,7 @@ onMounted(() => {
top: vw(100);
left: 25%;
width: 50%;
z-index: 2;
z-index: 4;
// height: 15%;
// background-color: #15293B;
}
@ -519,7 +543,7 @@ onMounted(() => {
// left: 25%;
width: 100%;
height: 100%;
z-index: 1;
z-index: 2;
}
/* 地图底层 - 填满整个容器 */
@ -579,91 +603,6 @@ onMounted(() => {
}
}
.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 {
//

View File

@ -125,7 +125,8 @@
start-placeholder="开始时间"
end-placeholder="结束时间"
size="small"
popper-class="dark-date-picker"
popper-class="custom-date-picker"
:teleported="false"
:prefix-icon="Calendar"
@change="handleDateChange"
/>
@ -222,6 +223,7 @@ const init = () => {
roadTypeLoad();
districtLoadLoad();
dispatchLoadLoad();
scheduleStatisticsByCountyLoad();
loadData();
loadBarChartData();
};
@ -263,16 +265,19 @@ const handleDispatchCardClick = (item) => {
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,
});
}
};
@ -401,6 +406,100 @@ const districtLoadLoad = async () => {
}
};
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",
});
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);
// 15105
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);
}
}
} catch (error) {
console.error("加载调度统计区县数据失败:", error);
}
};
//
const roadTypeLoad = async () => {
try {
@ -491,15 +590,19 @@ const loadBarChartData = async () => {
const name = nameMap[item.name] || item.name;
return { ...item, name };
});
//
const roadIndex = convertedData.findIndex((item) => item.name === "路段");
if (roadIndex > 0) {
const roadItem = convertedData.splice(roadIndex, 1)[0];
convertedData.unshift(roadItem);
}
impactData.value = convertedData;
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;
}
});
}
}
} catch (error) {

View File

@ -125,7 +125,8 @@
start-placeholder="开始时间"
end-placeholder="结束时间"
size="small"
popper-class="dark-date-picker"
popper-class="custom-date-picker"
:teleported="false"
:prefix-icon="Calendar"
/>
</div>
@ -226,6 +227,9 @@ const emit = defineEmits([
onMounted(() => {
getYhYjllList();
getYhYjllListMaterials();
getControlStats();
getRescueInputStats();
getDisasterStats();
});
//
@ -312,6 +316,168 @@ const getYhYjllListMaterials = async () => {
}
};
//
const getControlStats = async () => {
try {
const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/control-stats",
method: "GET",
});
console.log("管控统计数据:", res);
if (res.code == "00000" && res.data) {
const data = res.data;
// controlData1value
controlData1.value.forEach((item) => {
if (item.label === "封闭管控数") {
item.value = data.fullClosureCount || "0";
} else if (item.label === "半幅通行数") {
item.value = data.halfClosureCount || "0";
} else if (item.label === "限速(限车型)数") {
item.value = data.speedLimitCount || "0";
} else if (item.label === "告警阻拦处数") {
item.value = data.warningBlockCount || "0";
}
});
}
} catch (error) {
console.error("获取管控统计数据失败:", error);
}
};
//
const getRescueInputStats = async () => {
try {
const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/rescue-input-stats",
method: "GET",
});
console.log("抢险投入统计数据:", res);
if (res.code == "00000" && res.data) {
const data = res.data;
// rescueDatavalue
rescueData.value.forEach((item) => {
if (item.label === "本轮出动人次") {
item.value = data.investedManpower || "0";
item.unit = "人";
if (item.value > 10000) {
item.value = (item.value / 10000).toFixed(2);
item.unit = "万人";
}
} else if (item.label === "本轮出动设备") {
item.value = data.investedMachinery || "0";
item.unit = "台";
if (item.value > 10000) {
item.value = (item.value / 10000).toFixed(2);
item.unit = "万台";
}
} else if (item.label === "清理塌方") {
//
item.value = data.clearedLandslide.toFixed(2) || 0;
item.unit = "立方米";
if (item.value > 10000) {
item.value = (item.value / 10000).toFixed(2);
item.unit = "万立方米";
}
}
});
}
} catch (error) {
console.error("获取抢险投入统计数据失败:", error);
}
};
//
const getDisasterStats = async () => {
try {
const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/disaster-stats",
method: "GET",
});
console.log("灾害统计数据:", res);
if (res.code == "00000" && res.data) {
const data = res.data;
// blockDatavalue
blockData.value.forEach((item) => {
if (item.label === "今日新增阻断数") {
item.current = data.todayNormalCount || "0";
item.total = data.todayTotalCount || "0";
} else if (item.label === "本轮累计阻断数") {
item.current = data.roundNormalCount || "0";
item.total = data.roundTotalCount || "0";
}
});
// deathDatavalue
deathData.value.value = data.roundDeadCount || "0";
// damageDatavalue
damageData.value.forEach((item) => {
if (item.label === "本轮塌方量") {
data.roundLandslideVolume = data.roundLandslideVolume.toFixed(2);
if (data.roundLandslideVolume > 10000) {
item.value = (data.roundLandslideVolume / 10000).toFixed(2) || "0";
item.unit = "万立方米";
} else {
item.value = data.roundLandslideVolume || "0";
item.unit = "立方米";
}
} else if (item.label === "汛期塌方量") {
data.floodSeasonLandslideVolume =
data.floodSeasonLandslideVolume.toFixed(2);
if (data.floodSeasonLandslideVolume > 10000) {
item.value =
(data.floodSeasonLandslideVolume / 10000).toFixed(2) || "0";
item.unit = "万立方米";
} else {
item.value = data.floodSeasonLandslideVolume || "0";
item.unit = "立方米";
}
} else if (item.label === "当年塌方量") {
data.yearLandslideVolume = data.yearLandslideVolume.toFixed(2);
if (data.yearLandslideVolume > 10000) {
item.value = (data.yearLandslideVolume / 10000).toFixed(2) || "0";
item.unit = "万立方米";
} else {
item.value = data.yearLandslideVolume || "0";
item.unit = "立方米";
}
} else if (item.label === "本轮已损失") {
data.roundTotalLossAmount = data.roundTotalLossAmount.toFixed(2);
if (data.roundTotalLossAmount > 10000) {
item.value = (data.roundTotalLossAmount / 10000).toFixed(2) || "0";
item.unit = "亿元";
} else {
item.value = data.roundTotalLossAmount || "0";
item.unit = "万元";
}
} else if (item.label === "汛期已损失") {
data.floodSeasonTotalLossAmount =
data.floodSeasonTotalLossAmount.toFixed(2);
if (data.floodSeasonTotalLossAmount > 10000) {
item.value =
(data.floodSeasonTotalLossAmount / 10000).toFixed(2) || "0";
item.unit = "亿元";
} else {
item.value = data.floodSeasonTotalLossAmount || "0";
item.unit = "万元";
}
} else if (item.label === "当年已损失") {
data.yearTotalLossAmount = data.yearTotalLossAmount.toFixed(2);
if (data.yearTotalLossAmount > 10000) {
item.value = (data.yearTotalLossAmount / 10000).toFixed(2) || "0";
item.unit = "亿元";
} else {
item.value = data.yearTotalLossAmount || "0";
item.unit = "万元";
}
}
});
}
} catch (error) {
console.error("获取灾害统计数据失败:", error);
}
};
//
const extractAndSumNumbers = (value) => {
//
@ -382,12 +548,12 @@ const handleResourceClick = (item) => {
};
//
const controlData1 = [
const controlData1 = ref([
{ label: "封闭管控数", value: "40" },
{ label: "半幅通行数", value: "40" },
{ label: "限速(限车型)数", value: "24" },
{ label: "告警阻拦处数", value: "32" },
];
]);
const controlData2 = [
{ label: "停工项目数", value: "30" },
{ label: "关闭驻地数", value: "42" },
@ -404,7 +570,7 @@ const patrolData = [
];
//
const rescueData = [
const rescueData = ref([
{
label: "本轮出动人次",
value: "22341",
@ -422,30 +588,30 @@ const rescueData = [
{
label: "清理塌方",
value: "1367",
unit: "立方米",
unit: "立方米",
iconClass: "icon-rescue-clear",
img: icon13,
},
];
]);
// -
const blockData = [
const blockData = ref([
{ label: "今日新增阻断数", current: "19", total: "23" },
{ label: "本轮累计阻断数", current: "10", total: "23" },
];
]);
//
const deathData = { label: "本轮因灾死亡人数", value: "5" };
const deathData = ref({ label: "本轮因灾死亡人数", value: "5" });
//
const damageData = [
const damageData = ref([
{ label: "本轮塌方量", value: "23", unit: "万立方米", class: "blue" },
{ label: "汛期塌方量", value: "23", unit: "万立方米", class: "blue" },
{ label: "当年塌方量", value: "23", unit: "万立方米", class: "blue" },
{ label: "本轮已损失", value: "80", unit: "万元", class: "red" },
{ label: "汛期已损失", value: "18", unit: "万元", class: "red" },
{ label: "当年已损失", value: "350", unit: "万元", class: "red" },
];
]);
//
const majorEvent = "0";

View File

@ -10,7 +10,8 @@
start-placeholder="开始时间"
end-placeholder="结束时间"
size="small"
popper-class="dark-date-picker"
popper-class="custom-date-picker"
:teleported="false"
:prefix-icon="Calendar"
/>
</div>
@ -26,7 +27,7 @@ import { Calendar } from "@element-plus/icons-vue";
const emit = defineEmits(["openAIResult", "dateRangeChange"]);
//
const triggerRefreshLeftData = inject('triggerRefreshLeftData');
const triggerRefreshLeftData = inject("triggerRefreshLeftData");
const dateRange = ref([]);
@ -39,24 +40,28 @@ const setEndOfDay = (date) => {
};
// dateRange
watch(dateRange, (newVal, oldVal) => {
//
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
console.log('dateRange 发生变化:', newVal);
// 23:59:59
if (newVal && newVal.length === 2 && newVal[1]) {
newVal[1] = setEndOfDay(newVal[1]);
watch(
dateRange,
(newVal, oldVal) => {
//
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
console.log("dateRange 发生变化:", newVal);
// 23:59:59
if (newVal && newVal.length === 2 && newVal[1]) {
newVal[1] = setEndOfDay(newVal[1]);
}
//
if (triggerRefreshLeftData) {
triggerRefreshLeftData();
}
//
emit("dateRangeChange", newVal);
}
//
if (triggerRefreshLeftData) {
triggerRefreshLeftData();
}
//
emit("dateRangeChange", newVal);
}
}, { deep: true });
},
{ deep: true },
);
const handleAIClick = () => {
emit("openAIResult");
@ -89,6 +94,7 @@ const handleAIClick = () => {
.filter-container {
display: flex;
align-items: center;
width: 100%;
height: vw(20);
min-height: 18px;
gap: vw(8);
@ -154,65 +160,4 @@ const handleAIClick = () => {
min-height: 48px;
cursor: pointer;
}
//
.dark-date-picker {
background: rgba(21, 41, 59, 0.95) !important;
border: 1px solid rgba(64, 169, 255, 0.3) !important;
.el-picker-panel__content {
background: transparent;
}
.el-date-table {
th {
color: rgba(255, 255, 255, 0.7);
}
td {
color: rgba(255, 255, 255, 0.9);
&.prev-month,
&.next-month {
color: rgba(255, 255, 255, 0.4);
}
&:hover {
color: #40a9ff;
}
&.current:not(.disabled) {
span {
background: #40a9ff;
}
}
&.start-date,
&.end-date {
span {
background: #40a9ff;
}
}
&.in-range {
background: rgba(64, 169, 255, 0.2);
}
}
}
.el-picker-panel__icon-btn {
color: rgba(255, 255, 255, 0.7);
&:hover {
color: #40a9ff;
}
}
.el-date-picker__header-label {
color: rgba(255, 255, 255, 0.9);
&:hover {
color: #40a9ff;
}
}
}
</style>