This commit is contained in:
huangchenhao 2026-04-15 18:00:53 +08:00
commit 1acd60700b
31 changed files with 1403 additions and 621 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -2,7 +2,7 @@ import axios from 'axios'
const service = axios.create({
baseURL: '',
timeout: 10000
timeout: 120000
})
// 请求拦截器

View File

@ -9,6 +9,7 @@
:current-page="1"
:page-size="10"
:z-index="2200"
:tableShow="false"
@close="handleClose"
>
<!-- 标题栏下方自定义插槽 -->
@ -18,7 +19,7 @@
<!-- AI处理前预警 -->
<div class="panel">
<div class="center">
<div class="panel-title" style="color: #18EFF7">AI处理前预警</div>
<div class="panel-title" style="color: #18eff7">AI处理前预警</div>
</div>
<div class="panel-content">
<div class="info-container">
@ -57,7 +58,7 @@
<!-- AI处理后预警 -->
<div class="panel after-panel panel1">
<div class="center">
<div class="panel-title" style="color: #18EFF7">AI处理后预警</div>
<div class="panel-title" style="color: #18eff7">AI处理后预警</div>
</div>
<div class="panel-content">
<!-- 标签页 -->

View File

@ -129,7 +129,7 @@ const handleItemClick = (item) => {
.center-info-card-container {
position: relative;
width: 100%;
min-width: 150px;
min-width: 140px;
z-index: 1000;
cursor: pointer;
}
@ -143,7 +143,6 @@ const handleItemClick = (item) => {
cursor: pointer;
transition: all 0.3s;
overflow: hidden;
border-radius: vw(8);
&:hover {
filter: brightness(1.1);

View File

@ -7,12 +7,14 @@
:table-height="0"
:total="0"
:current-page="1"
:tableShow="false"
:page-size="10"
:z-index="2200"
@close="handleClose"
>
<!-- 标题栏下方自定义插槽 -->
<template #header>
<div class="content-wrapper">
<!-- 事件基本信息 -->
<div class="section">
<div class="section-title">
@ -104,7 +106,9 @@
<div class="feedback-detail">
<div class="detail-row">
<span class="detail-label">预计开始时间</span>
<span class="detail-value">{{ item.estimatedStartTime }}</span>
<span class="detail-value">{{
item.estimatedStartTime
}}</span>
<span class="detail-label" style="margin-left: 40px"
>预计结束时间</span
>
@ -134,6 +138,7 @@
</div>
</div>
</div>
</div>
</template>
</base-dialog>
@ -250,6 +255,33 @@ watch(
</script>
<style lang="scss" scoped>
.content-wrapper{
height: 500px;
overflow-y: auto;
//
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: rgba(20, 46, 73, 0.3);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #142E49;
border-radius: 3px;
&:hover {
background: #1a3a5c;
}
}
// Firefox
scrollbar-width: thin;
scrollbar-color: #142E49 rgba(20, 46, 73, 0.3);
}
//
.section {
margin-bottom: 24px;

View File

@ -10,10 +10,12 @@
:page-size="10"
:z-index="2500"
:max-width="650"
:tableShow="false"
@close="handleClose"
>
<!-- 标题栏下方自定义插槽 -->
<template #header>
<div class="content-wrapper">
<!-- 隐患点基本信息 -->
<div class="section">
<div class="section-title">
@ -134,6 +136,7 @@
</div>
</div>
</div>
</div>
</template>
</base-dialog>
@ -156,6 +159,7 @@
import { ref, watch } from "vue";
import { Close } from "@element-plus/icons-vue";
import baseDialog from "../component/baseDialog.vue";
import { request } from "@/utils/request";
const props = defineProps({
visible: {
@ -166,6 +170,10 @@ const props = defineProps({
type: Object,
default: () => ({}),
},
item: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(["update:visible", "close"]);
@ -183,9 +191,7 @@ const basicInfo = ref({
});
//
const photoList = ref([
"https://via.placeholder.com/120x80/40a9ff/ffffff?text=照片",
]);
const photoList = ref([]);
//
const dynamicRecords = ref([
@ -233,21 +239,257 @@ const handleClose = () => {
emit("update:visible", false);
emit("close");
};
const leveltext = (level) => {
if (level.includes("一") || level.includes("1")) return "一类";
if (level.includes("二") || level.includes("2")) return "二类";
if (level.includes("三") || level.includes("3")) return "三类";
if (level.includes("四") || level.includes("4")) return "四类";
if (level.includes("五") || level.includes("5")) return "五类";
if (level.includes("9")) return "未评定";
return "未评定";
};
// base-dialog
//
const getAffectedObjectTypeId = (data) => {
let pointType = props.item.pointType;
if (!data) {
basicInfo.value = {};
photoList.value = [];
dynamicRecords.value = [];
return;
}
if (pointType === "桥梁") {
// -
basicInfo.value = {
district: data.GL1_QXMC || "-", //
level: leveltext(data.GL1_JSZKPJDJ) || "未评定", //
levelClass:
data.GL1_JSZKPJDJ === "一类" || data.GL1_JSZKPJDJ === "二类"
? "level-normal"
: "level-serious", //
roadCode: data.GL1_LXBH || "-", // 线
location: data.GL1_QLMC || "-", //
riskDesc: data.GL1_DQBH || "-", //
discoverTime: data.GL1_JSZKPDRQ || "-", //
};
// - 使
const photos = [];
if (data.GL1_QLZMZFJ) {
photos.push(data.GL1_QLZMZFJ); //
}
if (data.GL1_QLLMZFJ) {
photos.push(data.GL1_QLLMZFJ); //
}
if (data.GL1_QLDXZFJ) {
photos.push(data.GL1_QLDXZFJ); //
}
if (data.GL1_QLZP) {
photos.push(data.GL1_QLZP); //
}
photoList.value = photos.length > 0 ? photos : [];
// - 使
dynamicRecords.value = [
{
type: "桥梁信息",
patrolTime: data.GL1_JCTCRQ || "-", //
patrolPerson: data.GL1_QLZRR || "-", //
description: `桥梁全长:${data.GL1_QLQC || "-"}m跨径总长${data.GL1_KJZC || "-"}m上部结构${data.GL1_SBJGLXMC || "-"}`,
hasProblem: false,
image: null,
},
];
} else if (pointType === "边坡") {
//
const data = resData || {};
// -
basicInfo.value = {
district: data.GL1_QXMC || "-", //
level: leveltext(data.GL1_FXDJ) || "未评定", //
levelClass:
data.GL1_FXDJ?.includes("一级") || data.GL1_FXDJ?.includes("二级")
? "level-normal"
: "level-serious", //
roadCode: data.GL1_LXBM || "-", // 线
location: data.GL1_BPGC || "-", //
riskDesc: data.GL1_JCSSSZ || "-", //
discoverTime: data.GL1_ZRRXM || "-", //
};
// -
const photos = [];
if (data.GL1_ZRLXFS) {
photos.push(data.GL1_ZRLXFS); // URL
}
photoList.value = photos.length > 0 ? photos : [];
// -
dynamicRecords.value = [
{
type: "边坡信息",
patrolTime: data.GL1_BPPGC || "-", //
patrolPerson: data.GL1_ZRRXM || "-", //
description: `起点桩号:${data.GL1_QDZH || "-"},终点桩号:${data.GL1_ZDZH || "-"},起点经度:${data.GL1_QDJD || "-"},起点纬度:${data.GL1_QDWD || "-"},监测设施:${data.GL1_JCSSSZ || "-"},综合措施:${data.GL1_ZHXS || "-"}`,
hasProblem: data.GL1_JCSSSZ !== "无" && data.GL1_JCSSSZ !== null,
image: null,
},
];
} else if (pointType === "隧道") {
// -
basicInfo.value = {
district: data.GL1_QXMC || "-", //
level: leveltext(data.GL1_PDDJ) || "未评定", //
levelClass:
data.GL1_PDDJ === "一级" || data.GL1_PDDJ === "二级"
? "level-normal"
: "level-serious", //
roadCode: data.GL1_LXBH || "-", // 线
location: data.GL1_SDMC || "-", //
riskDesc: data.GL1_BHMS || "-", //
discoverTime: data.GL1_PDRQ || "-", //
};
// - 使
const photos = [];
if (data.GL1_SDJDKFJS) {
photos.push(data.GL1_SDJDKFJS); //
}
if (data.GL1_SDCDKFJS) {
photos.push(data.GL1_SDCDKFJS); //
}
if (data.GL1_SDDXZP) {
photos.push(data.GL1_SDDXZP); //
}
if (data.GL1_TP) {
photos.push(data.GL1_TP); //
}
photoList.value = photos.length > 0 ? photos : [];
// -
dynamicRecords.value = [
{
type: "隧道信息",
patrolTime: data.GL1_XCTCSJ || "-", //
patrolPerson: data.GL1_GLDW || "-", //
description: `隧道全长:${data.GL1_SDC || "-"}m隧道净宽${data.GL1_SDJK || "-"}m围岩等级${data.GL1_WYDJ || "-"},衬砌类型:${data.GL1_CQLXMC || "-"}`,
hasProblem: false,
image: null,
},
];
} else if (pointType === "路段") {
//
const data = resData || {};
// -
basicInfo.value = {
district: data.GL1_QDMC || "-", //
level: leveltext(data.GL1_JSDJ) || "未评定", //
levelClass:
data.GL1_JSDJ === "一级" || data.GL1_JSDJ === "二级"
? "level-normal"
: "level-serious", //
roadCode: data.GL1_LXBH || "-", // 线
location: `${data.GL1_QDMC || "-"} - ${data.GL1_ZDMC || "-"}`, //
riskDesc: data.GL1_TZSJ || "-", // /
discoverTime: data.GL1_XZDJ || "-", //
};
// -
photoList.value = [];
// -
dynamicRecords.value = [
{
type: "路段信息",
patrolTime: data.GL1_TZSJ || "-", //
patrolPerson: data.GL1_XZDJ || "-", //
description: `路段长度:${data.GL1_LDLC || "-"}km路面宽度${data.GL1_LMKD || "-"}m路面类型${data.GL1_LMLX || "-"},车道数量:${data.GL1_CDSL || "-"}`,
hasProblem: false,
image: null,
},
];
}
};
//
const getAffectedObjectDetail = async () => {
try {
let id = "";
let apiUrl = "";
const pointType = props.item?.pointType;
if (pointType === "桥梁") {
id = props.item?.rawData?.GL1_ZJ || "";
apiUrl = `/snow-ops-platform/weather-warning/affected-object/bridge/${id}`;
} else if (pointType === "边坡") {
id = props.item?.rawData?.GL1_ID || "";
apiUrl = `/snow-ops-platform/weather-warning/affected-object/slope/${id}`;
} else if (pointType === "隧道") {
id = props.item?.rawData?.GL1_ZJ || "";
apiUrl = `/snow-ops-platform/weather-warning/affected-object/tunnel/${id}`;
} else if (pointType === "路段") {
id = props.item?.rawData?.GL1ZJ || "";
apiUrl = `/snow-ops-platform/weather-warning/affected-object/road-section/${id}`;
}
if (!id || !apiUrl) {
console.warn("未找到影响点ID或API地址");
return;
}
const res = await request({
url: apiUrl,
method: "GET",
});
console.log("影响点详情数据:", res);
if (res.code === "00000") {
getAffectedObjectTypeId(res.data || {});
}
} catch (error) {
console.error("获取影响点详情数据失败:", error);
}
};
// visible
watch(
() => props.visible,
(newVal) => {
if (newVal && props.pointData) {
Object.assign(basicInfo.value, props.pointData);
if (newVal) {
//
getAffectedObjectDetail();
}
},
);
</script>
<style lang="scss" scoped>
.content-wrapper {
height: 500px;
overflow-y: auto;
//
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: rgba(20, 46, 73, 0.3);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #142e49;
border-radius: 3px;
&:hover {
background: #1a3a5c;
}
}
// Firefox
scrollbar-width: thin;
scrollbar-color: #142e49 rgba(20, 46, 73, 0.3);
}
//
.section {
margin-bottom: 20px;
@ -325,17 +567,17 @@ watch(
font-weight: 500;
width: fit-content;
&.level-normal {
background-color: rgba(250, 219, 95, 0.2);
color: #fadb5f;
border: 1px solid rgba(250, 219, 95, 0.4);
}
// &.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);
}
// &.level-serious {
// background-color: rgba(255, 77, 79, 0.2);
// color: #ff4d4f;
// border: 1px solid rgba(255, 77, 79, 0.4);
// }
}
&.status-unresponse {

View File

@ -8,6 +8,7 @@
:total="total"
:current-page="currentPage"
:page-size="pageSize"
showFilter="true"
:z-index="2000"
:max-width="1200"
@size-change="handleSizeChange"
@ -234,14 +235,20 @@ import Icon2 from "../../../assets/xiangying/未选中2@2x.png";
import Icon3 from "../../../assets/xiangying/未选中3@2x.png";
import Icon4 from "../../../assets/xiangying/未选中4@2x.png";
import { formatDateTime } from "../component/index.js";
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
handleImpactItem: {
type: Object,
default: () => {},
},
});
const emit = defineEmits(["update:visible", "close", "detail"]);
const emit = defineEmits(["update:visible", "close", "detail", "itemClick"]);
//
const filterForm = ref({
@ -473,6 +480,7 @@ const handleSearch = () => {
//
const handleDetail = (item) => {
emit("detail", item);
emit("itemClick", item);
};
//
@ -487,22 +495,14 @@ const handleCurrentChange = (val) => {
};
//
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");
console.log("原始时间范围:", props.handleImpactItem);
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",
start: formatDateTime(props.handleImpactItem.dateRange?.[0] || ""),
end: formatDateTime(props.handleImpactItem.dateRange?.[1] || ""),
limit: pageSize.value,
offset: currentPage.value,
offset: (currentPage.value - 1) * pageSize.value,
};
};
//
@ -689,38 +689,38 @@ const processUnifiedData = (item, type) => {
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 || "-",
// },
// - 使
region: item.GL1_QXMC || "-",
// - 使线+
pointLocation: `${item.GL1_GLMC || item.GL1_GLBH || "-"} (${item.GL1_QDZH || "-"} - ${item.GL1_ZDZH || "-"})`,
// - 使
pointLevel: item.GL1_FXDJ || "-",
levelClass: getLevelClass(item.GL1_FXDJ),
// - 使GL1_JTXMGL1_JTDH
trafficDept: {
name: item.GL1_JTXM || "-",
phone: item.GL1_JTDH || "-",
},
// - 使GL1_JGXMGL1_JGDH
roadOrg: {
name: item.GL1_JGXM || "-",
phone: item.GL1_JGDH || "-",
},
// - 使GL1_YHXMGL1_YHDH
maintenance: {
name: item.GL1_YHXM || "-",
phone: item.GL1_YHDH || "-",
},
// - 使GL1_HLXMGL1_HLDH
roadKeeper: {
name: item.GL1_HLXM || "-",
phone: item.GL1_HLDH || "-",
},
// - 使
generalStaff: {
name: item.GL1_FXLX || "-",
phone: item.GL1_FXMS || "-",
},
};
}

View File

@ -1,19 +1,22 @@
<template>
<!-- 响应点详情对话框 标题是影响点详情 -->
<base-dialog
v-model:visible="props.visible"
title="点详情"
title="响点详情"
:table-data="[]"
:table-columns="[]"
:table-height="0"
:total="0"
:current-page="1"
:page-size="10"
:z-index="1000"
:z-index="2300"
:max-width="700"
:tableShow="false"
@close="handleClose"
>
<!-- 标题栏下方自定义插槽 -->
<template #header>
<div class="content-wrapper">
<!-- 隐患点基本信息 -->
<div class="section">
<div class="section-title">
@ -28,7 +31,11 @@
</div>
<div class="info-item">
<span class="info-label">影响点等级</span>
<span class="info-value level-tag" :class="basicInfo.levelClass">{{ basicInfo.level }}</span>
<span
class="info-value level-tag"
:class="basicInfo.levelClass"
>{{ basicInfo.level }}</span
>
</div>
<div class="info-item">
<span class="info-label">公路编号</span>
@ -42,11 +49,11 @@
</div>
<div class="info-item">
<span class="info-label">风险点描述</span>
<span class="info-value" :class="getStatusClass(basicInfo.riskDesc)">{{ basicInfo.riskDesc }}</span>
<span class="info-value">{{ basicInfo.riskDesc }}</span>
</div>
<div class="info-item">
<span class="info-label">发现时间</span>
<span class="info-value">{{ basicInfo.discoverTime }}</span>
<span class="info-label">采取措施</span>
<span class="info-value">{{ basicInfo.measures }}</span>
</div>
</div>
</div>
@ -76,44 +83,40 @@
<span class="title-icon"></span>
巡查记录
</div>
<div class="timeline-list">
<!-- 巡查记录详情 -->
<div class="timeline-item patrol-item">
<div class="timeline-marker patrol"></div>
<div class="timeline-content">
<div class="timeline-header">
<span class="timeline-type">巡查记录</span>
<span class="timeline-person">{{ patrolRecord.person }}</span>
<span class="timeline-time">{{ patrolRecord.time }}</span>
<div class="patrol-list">
<!-- 巡查记录列表 -->
<div
v-for="(record, index) in patrolRecords"
:key="index"
class="patrol-record-item"
>
<div class="patrol-number">{{ index + 1 }}</div>
<div class="patrol-content">
<div class="patrol-row">
<div class="patrol-info">
<span class="patrol-label">巡查时间</span>
<span class="patrol-value">{{ record.time }}</span>
</div>
<div class="timeline-detail">
<div class="detail-row">
<span class="detail-label">巡查轨迹</span>
<span class="detail-link" @click="viewTrack">查看轨迹</span>
</div>
<div class="detail-row">
<span class="detail-label">现场情况</span>
<span class="detail-text">{{ patrolRecord.situation }}</span>
<div v-if="patrolRecord.image" class="detail-image" @click="previewImage(patrolRecord.image)">
<img :src="patrolRecord.image" alt="现场照片" />
<div class="patrol-info">
<span class="patrol-label">巡查人</span>
<span class="patrol-value">{{ record.person }}</span>
</div>
</div>
<div class="patrol-row">
<span class="patrol-label">现场情况描述</span>
<span class="patrol-value">{{ record.situation }}</span>
</div>
<div class="patrol-row">
<span class="patrol-label">是否发现问题</span>
<span class="patrol-value">{{ record.hasIssue }}</span>
</div>
</div>
</div>
<!-- 动态记录列表 -->
<div v-for="(record, index) in dynamicRecords" :key="index" class="timeline-item">
<div class="timeline-marker" :class="record.type"></div>
<div class="timeline-content">
<div class="timeline-header">
<span class="timeline-type">{{ record.typeName }}</span>
<span class="timeline-person">{{ record.person }}</span>
<span class="timeline-time">{{ record.time }}</span>
<span v-if="record.status" class="timeline-status" :class="record.statusClass">{{ record.status }}</span>
<span v-if="record.target" class="timeline-target">
<span class="target-name">{{ record.target }}</span> {{ record.targetPhone }}
</span>
<div
v-if="record.image"
class="patrol-image"
@click="previewImage(record.image)"
>
<img :src="record.image" alt="现场照片" />
</div>
</div>
</div>
@ -123,7 +126,11 @@
</base-dialog>
<!-- 图片预览弹窗 -->
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
<div
v-if="previewVisible"
class="image-preview-overlay"
@click="closePreview"
>
<div class="image-preview-container" @click.stop>
<img :src="previewImageUrl" alt="预览" />
<div class="close-preview-btn" @click="closePreview">
@ -158,8 +165,10 @@ const basicInfo = ref({
levelClass: "level-normal",
roadCode: "G348",
location: "丁吴路(K116+656至K116+739)",
riskDesc: "未回应",
discoverTime: "立即启动防汛Ⅰ级应急响应,立即转移危险区群众,医疗机构做好应急准备",
riskDesc:
"泥岩风化严重,受雨水冲刷影响,常有强风化岩体散落于边沟或塌散于路面(路面处落石已清理),影响道路正常使用。[类型:路内风险点-边坡]",
measures:
"拟对开裂边坡进行清方处理后,采取挂网喷射混凝土处理,部分路段增设挡土墙",
});
//
@ -168,49 +177,21 @@ const photoList = ref([
"https://via.placeholder.com/120x80/40a9ff/ffffff?text=照片2",
]);
//
const patrolRecord = ref({
person: "蒋汉成 18702307964",
time: "2025-10-14 15:43:24",
situation: "收到暴雨黄色预警信息,开展公路夜间巡查排查,道路滑坡涉灾点,无明显变化",
image: "https://via.placeholder.com/80x60/40a9ff/ffffff?text=现场",
});
//
const dynamicRecords = ref([
//
const patrolRecords = ref([
{
type: "dispatch",
typeName: "调度记录",
person: "蒋汉成",
time: "2025-10-13 15:43:24",
status: "【已接通语音】",
statusClass: "status-success",
target: "养护站负责人",
targetPhone: "刘孝万13609403931",
time: "2026-03-28 14:30:00",
person: "刘伟",
situation: "现场通行正常、无异常情况发生。",
hasIssue: "否",
image: "https://via.placeholder.com/80x60/40a9ff/ffffff?text=现场1",
},
{
type: "warning",
typeName: "预警记录",
person: "蒋汉成18702307964",
time: "2025-10-13 15:43:24",
status: "审核驳回",
statusClass: "status-reject",
},
{
type: "warning",
typeName: "预警记录",
person: "蒋汉成18702307964",
time: "2025-10-13 15:43:24",
status: "审核通过",
statusClass: "status-success",
},
{
type: "warning",
typeName: "预警记录",
person: "蒋汉成18702307964",
time: "2025-10-13 15:43:24",
status: "响应预警",
statusClass: "status-success",
time: "2026-03-28 14:30:00",
person: "刘伟",
situation: "现场通行正常、无异常情况发生。",
hasIssue: "否",
image: "https://via.placeholder.com/80x60/40a9ff/ffffff?text=现场2",
},
]);
@ -255,13 +236,38 @@ watch(
if (newVal && props.pointData) {
Object.assign(basicInfo.value, props.pointData);
}
}
},
);
</script>
<style lang="scss" scoped>
.content-wrapper {
height: 500px;
overflow-y: auto;
//
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: rgba(20, 46, 73, 0.3);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #142e49;
border-radius: 3px;
&:hover {
background: #1a3a5c;
}
}
// Firefox
scrollbar-width: thin;
scrollbar-color: #142e49 rgba(20, 46, 73, 0.3);
}
//
.section {
margin-bottom: 20px;
@ -382,6 +388,89 @@ watch(
}
}
//
.patrol-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.patrol-record-item {
display: flex;
align-items: flex-start;
gap: 12px;
background-color: rgba(30, 70, 120, 0.2);
border-radius: 8px;
padding: 16px;
}
.patrol-number {
width: 28px;
height: 28px;
border-radius: 50%;
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
color: #fff;
font-size: 14px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.patrol-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
.patrol-row {
display: flex;
flex-wrap: wrap;
gap: 16px;
&:first-child {
gap: 24px;
}
}
.patrol-info {
display: flex;
align-items: center;
gap: 8px;
}
.patrol-label {
font-size: 13px;
color: rgba(255, 255, 255, 0.6);
}
.patrol-value {
font-size: 13px;
color: rgba(255, 255, 255, 0.9);
}
.patrol-image {
width: 80px;
height: 60px;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
border: 1px solid rgba(64, 169, 255, 0.3);
flex-shrink: 0;
&:hover {
border-color: #40a9ff;
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
//
.timeline-list {
display: flex;
@ -413,7 +502,7 @@ watch(
position: relative;
&::after {
content: '';
content: "";
position: absolute;
top: 12px;
left: 50%;
@ -599,6 +688,4 @@ watch(
color: #fff;
}
}
</style>

View File

@ -10,6 +10,7 @@
:page-size="10"
:z-index="1000"
:max-width="800"
:tableShow="false"
@close="handleClose"
>
<!-- 标题栏下方自定义插槽 -->
@ -42,17 +43,27 @@
</div>
<div class="info-item">
<span class="info-label">回应状态</span>
<span class="info-value" :class="getStatusClass(basicInfo.responseStatus)">{{ basicInfo.responseStatus }}</span>
<span
class="info-value"
:class="getStatusClass(basicInfo.responseStatus)"
>{{ basicInfo.responseStatus }}</span
>
</div>
<div class="info-item">
<span class="info-label">审核状态</span>
<span class="info-value" :class="getAuditClass(basicInfo.auditStatus)">{{ basicInfo.auditStatus }}</span>
<span
class="info-value"
:class="getAuditClass(basicInfo.auditStatus)"
>{{ basicInfo.auditStatus }}</span
>
</div>
</div>
<div class="info-row three-col">
<div class="info-item">
<span class="info-label">预警等级</span>
<span class="info-value level-red">{{ basicInfo.warningLevel }}</span>
<span class="info-value level-red">{{
basicInfo.warningLevel
}}</span>
</div>
<div class="info-item">
<span class="info-label">起点桩号-止点桩号</span>
@ -115,7 +126,9 @@
:class="{ 'row-even': index % 2 === 1 }"
>
<div class="td" style="width: 30%">{{ item.type }}</div>
<div class="td" style="width: 40%">{{ item.name }} {{ item.phone }}</div>
<div class="td" style="width: 40%">
{{ item.name }} {{ item.phone }}
</div>
<div class="td" style="width: 30%">{{ item.frequency }}</div>
</div>
</div>
@ -146,7 +159,11 @@
<div class="detail-row">
<span class="detail-label">现场情况</span>
<span class="detail-text">{{ patrolRecord.situation }}</span>
<div v-if="patrolRecord.image" class="detail-image" @click="previewImage(patrolRecord.image)">
<div
v-if="patrolRecord.image"
class="detail-image"
@click="previewImage(patrolRecord.image)"
>
<img :src="patrolRecord.image" alt="现场照片" />
</div>
</div>
@ -155,16 +172,26 @@
</div>
<!-- 动态记录列表 -->
<div v-for="(record, index) in dynamicRecords" :key="index" class="timeline-item">
<div
v-for="(record, index) in dynamicRecords"
:key="index"
class="timeline-item"
>
<div class="timeline-marker" :class="record.type"></div>
<div class="timeline-content">
<div class="timeline-header">
<span class="timeline-type">{{ record.typeName }}</span>
<span class="timeline-person">{{ record.person }}</span>
<span class="timeline-time">{{ record.time }}</span>
<span v-if="record.status" class="timeline-status" :class="record.statusClass">{{ record.status }}</span>
<span
v-if="record.status"
class="timeline-status"
:class="record.statusClass"
>{{ record.status }}</span
>
<span v-if="record.target" class="timeline-target">
<span class="target-name">{{ record.target }}</span> {{ record.targetPhone }}
<span class="target-name">{{ record.target }}</span>
{{ record.targetPhone }}
</span>
</div>
</div>
@ -175,7 +202,11 @@
</base-dialog>
<!-- 图片预览弹窗 -->
<div v-if="previewVisible" class="image-preview-overlay" @click="closePreview">
<div
v-if="previewVisible"
class="image-preview-overlay"
@click="closePreview"
>
<div class="image-preview-container" @click.stop>
<img :src="previewImageUrl" alt="预览" />
<div class="close-preview-btn" @click="closePreview">
@ -220,7 +251,8 @@ const basicInfo = ref({
auditStatus: "未审核",
warningLevel: "红色预警",
stakeRange: "三级治理中心发布发布暴雨红色预警信号",
discoverTime: "立即启动防汛Ⅰ级应急响应,立即转移危险区群众,医疗机构做好应急准备",
discoverTime:
"立即启动防汛Ⅰ级应急响应,立即转移危险区群众,医疗机构做好应急准备",
warningContent: "",
});
@ -234,17 +266,38 @@ const photoList = ref([
//
const responsibleList = ref([
{ type: "交通主管部门负责人", name: "胡雷", phone: "18983923577", frequency: "半年巡查一次" },
{ type: "公路机构负责人", name: "刘孝万", phone: "13609403931", frequency: "每月巡查一次" },
{ type: "养护站负责人", name: "彭应成", phone: "18323031454", frequency: "每周巡查一次" },
{ type: "护路员", name: "蒋汉成", phone: "1870230796", frequency: "每周巡查两次" },
{
type: "交通主管部门负责人",
name: "胡雷",
phone: "18983923577",
frequency: "半年巡查一次",
},
{
type: "公路机构负责人",
name: "刘孝万",
phone: "13609403931",
frequency: "每月巡查一次",
},
{
type: "养护站负责人",
name: "彭应成",
phone: "18323031454",
frequency: "每周巡查一次",
},
{
type: "护路员",
name: "蒋汉成",
phone: "1870230796",
frequency: "每周巡查两次",
},
]);
//
const patrolRecord = ref({
person: "蒋汉成 18702307964",
time: "2025-10-14 15:43:24",
situation: "收到暴雨黄色预警信息,开展公路夜间巡查排查,道路滑坡涉灾点,无明显变化",
situation:
"收到暴雨黄色预警信息,开展公路夜间巡查排查,道路滑坡涉灾点,无明显变化",
image: "https://via.placeholder.com/80x60/40a9ff/ffffff?text=现场",
});
@ -334,13 +387,11 @@ watch(
if (newVal && props.riskData) {
Object.assign(basicInfo.value, props.riskData);
}
}
},
);
</script>
<style lang="scss" scoped>
//
.section {
margin-bottom: 20px;
@ -529,7 +580,7 @@ watch(
position: relative;
&::after {
content: '';
content: "";
position: absolute;
top: 12px;
left: 50%;
@ -718,6 +769,4 @@ watch(
color: #fff;
}
}
</style>

View File

@ -105,7 +105,7 @@
</template>
<script setup>
import { ref, computed, watch, onMounted } from "vue";
import { ref, computed, watch, onMounted, inject } from "vue";
import { Close, Calendar } from "@element-plus/icons-vue";
import {
warningLevelOptions,
@ -115,6 +115,9 @@ import {
import baseDialog from "../component/baseDialog.vue";
import { request } from "@/utils/request";
//
const getdateRange = inject("getdateRange", ref([]));
const props = defineProps({
visible: {
type: Boolean,
@ -130,8 +133,11 @@ const getDefaultDateRange = () => {
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 ['', ''];
};
//
const dateRange = ref(getDefaultDateRange());
onMounted(() => {
filterForm.value = {
riskLeve: "",
@ -142,8 +148,20 @@ onMounted(() => {
fetchWarningData();
});
//
const dateRange = ref(getDefaultDateRange());
//
watch(
() => getdateRange.value,
(newVal) => {
console.log("warningSituationDialog.vue 日期范围变化:", newVal);
if (newVal && newVal.length === 2) {
dateRange.value = newVal;
filterForm.value.dateRange = newVal;
//
fetchWarningData();
}
},
{ deep: true, immediate: true },
);
//
const filterForm = ref({
@ -307,6 +325,11 @@ const handleClose = () => {
//
const handleImpactClick = (item) => {
emit("impactClick", item);
emit("impactClickItem", {
...item,
dateRange: filterForm.value.dateRange || [],
riskLeve: filterForm.value.riskLeve || "",
});
};
//

View File

@ -6,15 +6,47 @@
:key="index"
class="nav-item"
:class="{ active: activeIndex === index }"
@click="handleClick(index)"
@click="handleClick(item, index)"
>
<div class="nav-icon-box">
<div class="nav-icon-box" :ref="(el) => setNavIconRef(el, index)">
<!-- <i :class="item.icon"></i> -->
<img :src="activeIndex === index ? item.icon1 : item.icon" alt="" />
</div>
<div class="nav-label">{{ item.label }}</div>
</div>
</div>
<!-- 涉灾隐患点图片弹窗 -->
<div v-if="showHazardPopup" class="hazard-popup" :style="popupStyle">
<div class="hazard-popup-content">
<div
v-for="(item, index) in hazardItems"
:key="index"
class="hazard-item"
@click="handleHazardItemClick(item)"
>
<img :src="item.icon" :alt="item.label" />
<span>{{ item.label }}</span>
</div>
</div>
</div>
<!-- 路段图片弹窗 -->
<div
v-if="showRoadPopup"
class="hazard-popup road-popup"
:style="roadPopupStyle"
>
<div class="hazard-popup-content">
<div
v-for="(item, index) in roadItems"
:key="index"
class="hazard-item"
@click="handleRoadItemClick(item)"
>
<img :src="item.icon" :alt="item.label" />
<span>{{ item.label }}</span>
</div>
</div>
</div>
<!-- 气象预警监测表格 -->
<div class="weather-warning-wrapper">
<div class="weather-warning-panel">
@ -110,6 +142,7 @@ import slopeIconIcon from "../../assets/RiskWarning_img/边坡icon@2x.png";
import bridgeIconIcon from "../../assets/RiskWarning_img/桥梁icon@2x.png";
import roadIconIcon from "../../assets/RiskWarning_img/线路路段icon@2x.png";
import teamIconIcon from "../../assets/RiskWarning_img/队伍icon@2x.png";
import hazardIconIconIcon from "../../assets/RiskWarning_img/隐患点icon@2x.png";
import warningIconIcon1 from "../../assets/RiskWarning_img/风险预警icon1@2x.png";
import tunnelIconIcon1 from "../../assets/RiskWarning_img/隧道icon1@2x.png";
@ -117,10 +150,37 @@ import slopeIconIcon1 from "../../assets/RiskWarning_img/边坡icon1@2x.png";
import bridgeIconIcon1 from "../../assets/RiskWarning_img/桥梁icon1@2x.png";
import roadIconIcon1 from "../../assets/RiskWarning_img/线路路段icon1@2x.png";
import teamIconIcon1 from "../../assets/RiskWarning_img/队伍icon1@2x.png";
import hazardIconIcon from "../../assets/RiskWarning_img/隐患点icon1@2x.png";
import hazardIconIcon1 from "../../assets/MaMap_img/一般路内隐患点@2x.png";
import hazardIconIcon2 from "../../assets/MaMap_img/一般路外隐患点@2x.png";
import hazardIconIcon3 from "../../assets/MaMap_img/较大路内隐患点@2x.png";
import hazardIconIcon4 from "../../assets/MaMap_img/较大路外隐患点@2x.png";
import hazardIconIcon5 from "../../assets/MaMap_img/重大路内隐患点@2x.png";
import hazardIconIcon6 from "../../assets/MaMap_img/重大路外隐患点@2x.png";
import tunnelLineIcon3 from "../../assets/MaMap_img/高风险路段@2x.png";
import tunnelLineIcon2 from "../../assets/MaMap_img/较高风险路段@2x.png";
import tunnelLineIcon1 from "../../assets/MaMap_img/中风险路段@2x.png";
import tunnelLineIcon from "../../assets/MaMap_img/线路icon定位@2x.png";
const activeIndex = ref(-1);
const menuItems = [
{
label: "涉灾隐患点",
icon: "icon-hazard",
iconClass: "hazard",
icon: hazardIconIconIcon,
icon1: hazardIconIcon,
},
{
label: "路段",
icon: "icon-road",
iconClass: "road",
icon: roadIconIcon,
icon1: roadIconIcon1,
},
{
label: "项目",
icon: "icon-warning",
@ -149,13 +209,6 @@ const menuItems = [
icon: bridgeIconIcon,
icon1: bridgeIconIcon1,
},
{
label: "路段",
icon: "icon-road",
iconClass: "road",
icon: roadIconIcon,
icon1: roadIconIcon1,
},
{
label: "队伍",
icon: "icon-team",
@ -165,6 +218,40 @@ const menuItems = [
},
];
//
const showHazardPopup = ref(false);
const popupStyle = ref({});
const navIconRefs = ref([]);
//
const hazardItems = ref([
{ icon: hazardIconIcon5, label: "重大路内隐患点" },
{ icon: hazardIconIcon6, label: "重大路外隐患点" },
{ icon: hazardIconIcon3, label: "较大路内隐患点" },
{ icon: hazardIconIcon4, label: "较大路外隐患点" },
{ icon: hazardIconIcon1, label: "一般路内隐患点" },
{ icon: hazardIconIcon2, label: "一般路外隐患点" },
]);
//
const showRoadPopup = ref(false);
const roadPopupStyle = ref({});
//
const roadItems = ref([
{ icon: tunnelLineIcon3, label: "高风险路段" },
{ icon: tunnelLineIcon2, label: "较高风险路段" },
{ icon: tunnelLineIcon1, label: "中风险路段" },
{ icon: tunnelLineIcon, label: "低风险路段" },
]);
// nav-icon-boxref
const setNavIconRef = (el, index) => {
if (el) {
navIconRefs.value[index] = el;
}
};
//
const filters = ref({
red: false,
@ -242,11 +329,83 @@ const cellStyle = () => ({
const rowClassName = ({ rowIndex }) => {
return rowIndex % 2 === 0 ? "even-row" : "odd-row";
};
const emit = defineEmits(["changeActiveIndex", "clearMapMarkers"]);
const emit = defineEmits([
"changeActiveIndex",
"clearMapMarkers",
"hazardItemClick",
"roadItemClick",
]);
//
const handleClick = (index) => {
const handleClick = (item, index) => {
//
if (item.label === "涉灾隐患点") {
//
showHazardPopup.value = !showHazardPopup.value;
if (showHazardPopup.value) {
showRoadPopup.value = false;
}
if (showHazardPopup.value) {
//
const navIconBox = navIconRefs.value[index];
if (navIconBox) {
const rect = navIconBox.getBoundingClientRect();
popupStyle.value = {
position: "fixed",
left: rect.right + 10 + "px",
top: rect.top + "px",
zIndex: 2,
};
}
}
} else if (item.label === "路段") {
//
//
showRoadPopup.value = !showRoadPopup.value;
if (showRoadPopup.value) {
showHazardPopup.value = false;
}
if (showRoadPopup.value) {
//
const navIconBox = navIconRefs.value[index];
if (navIconBox) {
const rect = navIconBox.getBoundingClientRect();
roadPopupStyle.value = {
position: "fixed",
left: rect.right + 10 + "px",
top: rect.top + "px",
zIndex: 3,
};
}
}
} else {
showHazardPopup.value = false;
showRoadPopup.value = false;
}
activeIndex.value = index;
emit("changeActiveIndex", index);
emit("changeActiveIndex", {
...item,
});
};
//
const handleHazardItemClick = (item) => {
console.log("点击隐患点:", item);
emit("hazardItemClick", item);
//
// showHazardPopup.value = false;
};
const roadItem = ref({});
//
const handleRoadItemClick = (item) => {
console.log("点击路段:", item);
roadItem.value = item;
emit("roadItemClick", item);
//
// showRoadPopup.value = false;
};
//
@ -396,9 +555,48 @@ onUnmounted(() => {
padding: vw(6);
}
}
//
.hazard-popup {
background: rgba(20, 46, 73, 0.95);
border: 1px solid rgba(64, 169, 255, 0.4);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
.hazard-popup-content {
display: flex;
flex-direction: column;
gap: vw(8);
.hazard-item {
display: flex;
align-items: center;
gap: vw(8);
padding: vw(5) vw(10);
// border-radius: 4px;
transition: background 0.3s;
cursor: pointer;
&:hover {
background: rgba(64, 169, 255, 0.2);
}
img {
width: vw(40);
height: vw(40);
object-fit: contain;
}
span {
color: rgba(255, 255, 255, 0.9);
font-size: vw(16);
white-space: nowrap;
}
}
}
}
.nav-menu {
width: vw(50);
min-width: vw(40);
width: vw(80);
min-width: vw(80);
height: 100%;
display: flex;
flex-direction: column;
@ -436,8 +634,7 @@ onUnmounted(() => {
min-height: vw(36);
margin-bottom: vw(5);
background: rgba(64, 169, 255, 0.1);
border: 1px solid rgba(64, 169, 255, 0.3);
border-radius: vw(8);
// border: 1px solid rgba(64, 169, 255, 0.3);
display: flex;
align-items: center;
justify-content: center;

View File

@ -53,10 +53,21 @@ import TongnanCenterCardDialog from "../Dialog/tongnanCenterCardDialog.vue";
import projectIcon from "../../../assets/MaMap_img/项目@2x.png";
import bridgeIcon from "../../../assets/MaMap_img/桥梁icon@2x.png";
import tunnelIcon from "../../../assets/MaMap_img/蓝色@2x1.png";
import tunnelLineIcon from "../../../assets/MaMap_img/线路icon定位@2x.png";
import tunnelIcon2 from "../../../assets/MaMap_img/隧洞icon@2x.png";
import rescueTeamIcon from "../../../assets/MaMap_img/队伍icon@2x.png";
import hazardIconIcon1 from "../../../assets/MaMap_img/一般路内隐患点@2x.png";
import hazardIconIcon2 from "../../../assets/MaMap_img/一般路外隐患点@2x.png";
import hazardIconIcon3 from "../../../assets/MaMap_img/较大路内隐患点@2x.png";
import hazardIconIcon4 from "../../../assets/MaMap_img/较大路外隐患点@2x.png";
import hazardIconIcon5 from "../../../assets/MaMap_img/重大路内隐患点@2x.png";
import hazardIconIcon6 from "../../../assets/MaMap_img/重大路外隐患点@2x.png";
import tunnelLineIcon3 from "../../../assets/MaMap_img/高风险路段@2x.png";
import tunnelLineIcon2 from "../../../assets/MaMap_img/较高风险路段@2x.png";
import tunnelLineIcon1 from "../../../assets/MaMap_img/中风险路段@2x.png";
import tunnelLineIcon 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";
@ -68,14 +79,19 @@ let mapInstance = null;
let geoJsonLayer = null;
const props = defineProps({
activeIndex: {
type: Number,
default: -1,
activeitem: {
type: Object,
default: () => {},
},
dateRange: {
type: Array,
default: () => [],
},
roadItem: {
//
type: Object,
default: () => {},
},
});
// emits
@ -198,7 +214,7 @@ const showCountyCardsOnMap = (dataList) => {
const customIcon = window.L.divIcon({
className: "county-card-icon",
html: container.innerHTML,
iconSize: [150, 40],
iconSize: [140, 40],
iconAnchor: [110, 60],
});
@ -292,25 +308,20 @@ const formatDateTime = (date) => {
};
//
const getTimeParams = () => {
const getTimeParams = (type) => {
let start = "";
let end = "";
if (props.dateRange && props.dateRange.length === 2) {
return {
start: formatDateTime(props.dateRange[0]),
end: formatDateTime(props.dateRange[1]),
};
start = formatDateTime(props.dateRange[0]) || "";
end = formatDateTime(props.dateRange[1]) || "";
}
//
if(props.roadItem && type === "road"){
// end = props.roadItem.endTime || "";
}
// 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: start,
end: end,
};
};
@ -362,11 +373,18 @@ const getAffectedBridgeData = async () => {
if (res.code === "00000" && res.data) {
res.data.forEach((item) => {
item.COORDINATE_POINT = [item.GL1_QLJD, item.GL1_QLWD];
if (
Number(item.GL1_JSZKPJDM) > 3 ||
item.GL1_AKJFLLX == "大桥" ||
item.GL1_AKJFLLX == "特大桥"
) {
affectedBridgeData.value.push(item);
}
});
}
affectedBridgeData.value = res.data;
// affectedBridgeData.value = res.data;
addProjectMarkers(res.data, bridgeIcon, "bridge");
addProjectMarkers(affectedBridgeData.value, bridgeIcon, "bridge");
} catch (error) {
console.error("获取受影响桥梁数据失败:", error);
return [];
@ -392,11 +410,14 @@ const getAffectedTunnelData = async () => {
Number(item.GL1_SDJD2),
Number(item.GL1_SDWD2),
];
if (Number(item.GL1_PDDJ) > 3 || item.GL1_SDLX == "特长隧道") {
tunnelInfoDialogRef.value.push(item);
}
});
tunnelInfoDialogRef.value = res.data;
// tunnelInfoDialogRef.value = res.data;
console.log("受影响隧道数据:", res.data);
addProjectMarkers(res.data, tunnelIcon2, "tunnel");
addProjectMarkers(tunnelInfoDialogRef.value, tunnelIcon2, "tunnel");
}
return [];
} catch (error) {
@ -452,7 +473,7 @@ const affectedRoadSectionData = ref([]);
//
const getAffectedRoadSectionData = async () => {
try {
const timeParams = getTimeParams();
const timeParams = getTimeParams(road);
const res = await request({
url: "/snow-ops-platform/weather-warning/affected-object/road-section",
method: "GET",
@ -1038,25 +1059,29 @@ const initMap = (geoJsonData) => {
}
};
// activeIndex
// activeitem
watch(
() => props.activeIndex,
() => props.activeitem,
async (newVal) => {
console.log("activeIndex 变化:", newVal);
switch (newVal) {
case 0:
console.log("activeitem 变化:", newVal);
switch (newVal.label) {
case "涉灾隐患点":
break;
case "项目":
await getAffectedProjectData();
break;
case 1:
case "隧道":
await getAffectedTunnelData();
break;
case 3:
case "边坡":
break;
case "桥梁":
await getAffectedBridgeData();
break;
case 4:
case "路段":
await getAffectedRoadSectionData();
break;
case 5:
case "队伍":
await getEmergencyForceData();
break;
default:
@ -1073,24 +1098,6 @@ watch(
console.log("dateRange 变化:", newVal, oldVal);
//
await getAffectedCountyData();
// activeIndex
switch (props.activeIndex) {
case 0:
await getAffectedProjectData();
break;
case 1:
await getAffectedTunnelData();
break;
case 3:
await getAffectedBridgeData();
break;
case 4:
await getEmergencyForceData();
break;
default:
break;
}
},
{ deep: true },
);
@ -1357,10 +1364,10 @@ defineExpose({
background: transparent !important;
border: none !important;
.center-info-card-container {
width: 100%;
min-width: 150px;
}
// .center-info-card-container {
// width: 100%;
// min-width: 120px;
// }
.center-info-card {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);

View File

@ -8,7 +8,10 @@
<div
class="base-dialog"
@click.stop
:style="{ maxWidth: `${props.maxWidth}px` }"
:style="{
maxWidth: `${props.maxWidth}px`,
maxHeight: `${props.maxHeight}px`,
}"
>
<!-- 四个角的装饰 -->
<div class="corner corner-top-left"></div>
@ -34,7 +37,7 @@
<slot name="filter"></slot>
</div>
<!-- 数据表格 -->
<div class="table-section">
<div class="table-section" v-if="props.tableShow">
<el-table
v-if="props.tableData.length > 0"
:data="props.tableData"
@ -60,7 +63,7 @@
</div>
<!-- 分页 -->
<div class="pagination">
<div class="pagination" v-if="props.tableShow">
<el-pagination
v-if="props.tableData.length > 0 && props.showPagination"
:current-page="props.currentPage"
@ -81,55 +84,78 @@ import { ref, watch } from "vue";
import { Close } from "@element-plus/icons-vue";
const props = defineProps({
tableShow: {
//
type: Boolean,
default: true,
},
visible: {
//
type: Boolean,
default: false,
},
title: {
//
type: String,
default: "弹窗标题",
},
zIndex: {
// z-index
type: Number,
default: 1000,
},
maxWidth: {
//
type: Number,
default: 1000,
},
maxHeight: {
//
type: Number,
default: 800,
},
showFilter: {
//
type: Boolean,
default: true,
},
showPagination: {
//
type: Boolean,
default: true,
},
tableData: {
//
type: Array,
default: () => [],
},
tableColumns: {
//
type: Array,
default: () => [],
},
tableHeight: {
//
type: Number,
default: 300,
},
currentPage: {
//
type: Number,
default: 1,
},
pageSize: {
//
type: Number,
default: 10,
},
pageSizes: {
//
type: Array,
default: () => [10, 20, 30, 40],
},
total: {
//
type: Number,
default: 0,
},
@ -308,7 +334,7 @@ const cellStyle = () => {
.header-slot {
margin-bottom: 20px;
padding: 0 24px;
overflow-y: auto;
// overflow-y: auto;
max-height: 70vh;
scrollbar-width: none;
-ms-overflow-style: none;
@ -331,6 +357,7 @@ const cellStyle = () => {
.table-section {
width: 100%;
padding: 0 24px;
min-height: 320px;
background: #16334e;
}
@ -344,6 +371,8 @@ const cellStyle = () => {
align-items: center;
justify-content: flex-end;
padding: 12px 24px;
box-sizing: border-box;
min-height: 56px;
:deep(.btn-prev) {
background: #19334b !important;
color: #fff;

View File

@ -4,10 +4,26 @@
文字色: #FFFFFF
主题色/选中背景色: #289DFF
======================================== */
.el-picker__popper {
z-index: 9999 !important;
}
/* 全局样式中 */
:root {
--el-popper-z-index: 9999;
}
/* 兼容部分版本的遮罩层/选择器容器 */
.el-date-picker {
z-index: 9999 !important;
}
:deep(.el-picker__popper) {
z-index: 9999 !important;
}
/* 防止样式被覆盖,提高优先级 */
.custom-date-picker {
z-index: 10000 !important;
/* 弹出框整体背景色 */
background-color: #122C45 !important;
/* 弹出框边框(主题色) */
@ -176,10 +192,12 @@
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: #3E91BC !important;

View File

@ -70,10 +70,10 @@ export const isRespondedOptions = [
// 预警等级选项
export const warningLevelOptions = [
{ label: "全部", value: "" },
{ label: "红色预警", value: "red" },
{ label: "橙色预警", value: "orange" },
{ label: "黄色预警", value: "yellow" },
{ label: "蓝色预警", value: "blue" },
{ label: "红色预警", value: "红色预警" },
{ label: "橙色预警", value: "橙色预警" },
{ label: "黄色预警", value: "黄色预警" },
{ label: "蓝色预警", value: "蓝色预警" },
];
// 是否结束选项
@ -94,6 +94,19 @@ export const regionOptionsWithAll = [
{ label: "城口区", value: "chengkou" },
];
// 格式化日期时间为接口所需格式
export 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}`;
};
// 默认导出所有选项
export default {
regionOptions,
@ -106,4 +119,5 @@ export default {
warningLevelOptions,
isEndedOptions,
regionOptionsWithAll,
formatDateTime,
};

View File

@ -34,6 +34,7 @@
<div class="left">
<left
:dateRange="getdateRange"
@openImpactDetail="openDialog('impactPoint')"
@openWarningInfo="openDialog('warningInfo')"
@openImpactPoint="openDialog('impactPoint')"
@ -46,6 +47,7 @@
</div>
<div class="right">
<right
:dateRange="getdateRange"
@openResourceDetail="openResourceDetail"
@openClearanceSituation="openDialog('clearanceSituation')"
@openControlSituation="openDialog('controlSituation')"
@ -57,8 +59,9 @@
<div class="map-layer">
<ChongqingMap
ref="chongqingMapRef"
:activeIndex="activeIndex"
:dateRange="dateRange"
:activeitem="activeitem"
:dateRange="getdateRange"
:roadItem="roadItem"
@districtClick="handleDistrictClick"
/>
</div>
@ -68,6 +71,7 @@
</div>
<div class="bottom">
<bottom
@roadItemClick="roadItemClick"
@changeActiveIndex="changeActiveIndex"
@clearMapMarkers="clearMapMarkers"
></bottom>
@ -117,13 +121,16 @@
<!-- 影响点情况对话框 -->
<impactPointDialog
:handleImpactItem="handleImpactItem"
v-model:visible="dialogVisible.impactPoint"
@close="closeDialog('impactPoint')"
@detail="openDialog('impactPointDetail')"
@itemClick="handleImpactPointClick"
/>
<!-- 影响点详情对话框 -->
<impactPointDetailDialog
:item="impactPointDetailItem"
v-model:visible="dialogVisible.impactPointDetail"
@close="closeDialog('impactPointDetail')"
/>
@ -144,7 +151,7 @@
<responseStatusDialog
v-model:visible="dialogVisible.responseStatus"
@close="closeDialog('responseStatus')"
@detail="openDialog('impactPointDetail')"
@detail="openDialog('responsePointDetail')"
/>
<!-- AI预警处理结果对话框 -->
@ -207,6 +214,7 @@
v-model:visible="dialogVisible.warningSituation"
@close="closeDialog('warningSituation')"
@impactClick="openDialog('impactPoint')"
@impactClickItem="handleImpactClickItem"
/>
<!-- 隧道信息对话框 -->
@ -277,15 +285,15 @@ const dialogVisible = ref({
warningSituation: false,
tunnelInfo: false,
});
const activeIndex = ref(0);
const activeitem = ref({});
//
const dateRange = ref([]);
const getdateRange = ref([]);
//
const handleDateRangeChange = (val) => {
console.log("日期范围变化:", val);
dateRange.value = val;
getdateRange.value = val;
};
//
@ -293,7 +301,12 @@ const chongqingMapRef = ref(null);
//
const changeActiveIndex = (index) => {
activeIndex.value = index;
activeitem.value = index;
};
const roadItem = ref({});
const roadItemClick = (item) => {
console.log("点击路段:", item);
roadItem.value = item;
};
//
@ -325,6 +338,17 @@ const clearMapMarkers = () => {
const openDialog = (dialogName) => {
dialogVisible.value[dialogName] = true;
};
const impactPointDetailItem = ref({});
//
const handleImpactPointClick = (item) => {
console.log("影响点点击:", item);
impactPointDetailItem.value = item;
};
const handleImpactItem = ref({});
const handleImpactClickItem = (item) => {
console.log("影响点点击详情:", item);
handleImpactItem.value = item;
};
//
const closeDialog = (dialogName) => {
@ -435,8 +459,9 @@ const triggerRefreshLeftData = () => {
//
provide("setRefreshLeftData", setRefreshLeftData);
provide("setRefreshRightData", setRefreshRightData);
provide("triggerRefreshLeftData", triggerRefreshLeftData);
provide("setRefreshRightData", setRefreshRightData);
provide("getdateRange", getdateRange);
// ==================== ====================

View File

@ -130,7 +130,6 @@
popper-class="custom-date-picker"
:teleported="false"
:prefix-icon="Calendar"
@change="handleDateChange"
/>
</div>
</div>
@ -192,29 +191,21 @@ import imgCheck from "../../assets/RiskWarning_img/抽查人数icon@2x.png";
//
const setRefreshLeftData = inject("setRefreshLeftData");
//
const getdateRange = inject("getdateRange", ref([]));
const props = defineProps({
visible: {
type: Boolean,
default: true,
},
});
// visible
//
watch(
() => props.visible,
() => getdateRange.value,
(newVal) => {
if (newVal) {
// loadData();
// loadBarChartData();
}
console.log("left.vue 日期范围变化:", newVal);
init();
},
{ deep: true },
);
onMounted(() => {
if (props.visible) {
init();
}
//
if (setRefreshLeftData) {
@ -294,51 +285,37 @@ const weatherWarningData = ref([
//
const impactData = ref([
{ name: "路段", count: 11 },
{ name: "桥梁", count: 312 },
{ name: "隧道", count: 405 },
{ name: "边坡", count: 634 },
{ name: "项目", count: 523 },
{ name: "路段", count: 0 },
{ name: "桥梁", count: 0 },
{ name: "隧道", count: 0 },
{ name: "边坡", count: 0 },
{ name: "项目", count: 0 },
]);
//
const handleDateChange = (val) => {
const dateRange = ref([]);
//
const handleDateRangeClick = (val) => {
dateRange.value = val;
dispatchLoadLoad();
};
//
const handleDateRangeClick = (val) => {
dateRange.value = [];
dispatchLoadLoad();
};
//
const dateRange = ref([]);
//
const dispatchLoadLoad = async () => {
try {
// 00:00:0023:59:59
let startTime = "";
let endTime = "";
let start = "";
let end = "";
if (dateRange.value && dateRange.value.length === 2) {
const startDate = new Date(dateRange.value[0]);
const endDate = new Date(dateRange.value[1]);
// 00:00:00
startDate.setHours(0, 0, 0, 0);
startTime = startDate.getTime();
// 23:59:59
endDate.setHours(23, 59, 59, 999);
endTime = endDate.getTime();
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: startTime,
end: endTime,
start: start,
end: end,
},
});
console.log(res);
@ -372,18 +349,52 @@ const dispatchLoadLoad = async () => {
});
// 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:0023: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") {
@ -406,6 +417,8 @@ const districtLoadLoad = async () => {
return totalB - totalA; //
});
districtData.value = sortedData;
} else {
districtData.value = [];
}
}
} catch (error) {
@ -423,6 +436,7 @@ const scheduleStatisticsByCountyLoad = async () => {
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") {
@ -500,11 +514,15 @@ const scheduleStatisticsByCountyLoad = async () => {
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);
// 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) {
@ -518,12 +536,17 @@ const roadTypeLoad = async () => {
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) {
@ -536,6 +559,7 @@ const loadData = async () => {
const res = await request({
url: "/snow-ops-platform/weather-warning/warning-count",
method: "GET",
params: getdateRangeTime(),
});
if (res.code == "00000") {
@ -565,6 +589,18 @@ const loadData = async () => {
"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) {
@ -578,11 +614,12 @@ const loadBarChartData = async () => {
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 && Array.isArray(data)) {
if (data.length > 0) {
//
const nameMap = {
"road-section": "路段",
@ -615,6 +652,18 @@ const loadBarChartData = async () => {
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) {

View File

@ -197,7 +197,7 @@
</template>
<script setup>
import { ref, computed, onMounted, inject } from "vue";
import { ref, computed, onMounted, inject, watch } from "vue";
import { request } from "@/utils/request";
import SectionHeader from "./component/sectionHeader.vue";
@ -228,25 +228,8 @@ const emit = defineEmits([
//
const setRefreshRightData = inject("setRefreshRightData");
const getdateRange = inject("getdateRange", ref([]));
//
const refreshData = () => {
console.log("right.vue 刷新数据");
getYhYjllList();
getYhYjllListMaterials();
getControlStats();
getRescueInputStats();
getDisasterStats();
};
//
onMounted(() => {
refreshData();
//
if (setRefreshRightData) {
setRefreshRightData(refreshData);
}
});
//
const handleDateChange = (val) => {
dateRange.value = val;
@ -641,6 +624,36 @@ const damageData = ref([
//
const majorEvent = "0";
// watch
const init = () => {
console.log("right.vue 刷新数据");
getYhYjllList();
getYhYjllListMaterials();
getControlStats();
getRescueInputStats();
getDisasterStats();
};
//
onMounted(() => {
init();
//
if (setRefreshRightData) {
setRefreshRightData(init);
}
});
watch(
() => getdateRange.value,
(newVal) => {
console.log("right.vue 日期范围变化:", newVal);
if (newVal && newVal.length === 2) {
}
init();
},
{ deep: true, immediate: true },
);
</script>
<style lang="scss" scoped>

View File

@ -30,7 +30,6 @@ const emit = defineEmits(["openAIResult", "dateRangeChange"]);
//
const triggerRefreshLeftData = inject("triggerRefreshLeftData");
const dateRange = ref([]);
// 23:59:59
@ -40,11 +39,11 @@ const setEndOfDay = (date) => {
d.setHours(23, 59, 59, 999);
return d;
};
//
//
const handleDateRangeClick = () => {
dateRange.value = [];
triggerRefreshLeftData();
emit("dateRangeChange", []);
// triggerRefreshLeftData();
// emitwatch dateRange emit
};
// dateRange
watch(
@ -54,16 +53,14 @@ watch(
console.log("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();
}
// if (triggerRefreshLeftData) {
// triggerRefreshLeftData();
// }
//
emit("dateRangeChange", newVal);
}