This commit is contained in:
niedongsheng 2026-04-17 18:16:36 +08:00
commit 285bc95b91
29 changed files with 3547 additions and 1690 deletions

10
.prettierrc Normal file
View File

@ -0,0 +1,10 @@
{
"printWidth": 100,
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"arrowParens": "avoid",
"htmlWhitespaceSensitivity": "ignore",
"vueIndentScriptAndStyle": false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -190,6 +190,17 @@ const routes = [
parentRoute: 'warningManagement3' parentRoute: 'warningManagement3'
} }
}, },
{
path: '/messageManagement',
name: 'messageManagement',
component: () => import('../views/WarningManagement/law/messageManagement/index.vue'),
meta: {
title: '消息推送设置',
breadcrumb: true,
parentRoute: 'warningManagement3'
}
},
// 项目管理 - 区县 // 项目管理 - 区县
{ {

View File

@ -16,7 +16,7 @@
<template #filter> <template #filter>
<div class="filter-row"> <div class="filter-row">
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">影响区域</span> <span class="filter-label">行政区域</span>
<el-select <el-select
:teleported="false" :teleported="false"
v-model="filterForm.district" v-model="filterForm.district"
@ -86,9 +86,9 @@
<!-- 管控措施列插槽 --> <!-- 管控措施列插槽 -->
<template #roadConditionType="{ row }"> <template #roadConditionType="{ row }">
<span :class="['control-tag', getControlClass(row.roadConditionType)]">{{ <span :class="['control-tag', getControlClass(row.roadConditionType)]">
row.roadConditionType {{ row.roadConditionType }}
}}</span> </span>
</template> </template>
<!-- 操作列插槽 --> <!-- 操作列插槽 -->
@ -99,15 +99,11 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, watch } from "vue"; import { ref, computed, watch } from 'vue';
import { Close } from "@element-plus/icons-vue"; import { Close } from '@element-plus/icons-vue';
import { import { regionOptions, typeOptions, controlMeasureOptions } from '../component/index.js';
regionOptions, import BaseDialog from '../component/baseDialog.vue';
typeOptions, import { request } from '@/utils/request';
controlMeasureOptions,
} from "../component/index.js";
import BaseDialog from "../component/baseDialog.vue";
import { request } from "@/utils/request";
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -116,13 +112,13 @@ const props = defineProps({
}, },
}); });
const emit = defineEmits(["update:visible", "close", "detail"]); const emit = defineEmits(['update:visible', 'close', 'detail']);
// //
const filterForm = ref({ const filterForm = ref({
district: "", district: '',
type: "", type: '',
roadConditionType: "", roadConditionType: '',
}); });
// //
@ -139,21 +135,21 @@ const tableHeight = ref(300);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: "id", label: "序号", width: "" }, { prop: 'id', label: '序号', width: '' },
{ prop: "district", label: "影响区域", width: "" }, { prop: 'district', label: '行政区域', width: '' },
{ prop: "routeNo", label: "线路编号", width: "" }, { prop: 'routeNo', label: '线路编号', width: '' },
{ prop: "stakeNo", label: "起止桩号", width: "", slot: "stakeNo" }, { prop: 'stakeNo', label: '起止桩号', width: '', slot: 'stakeNo' },
{ prop: "location", label: "路况位置", width: "", slot: "location" }, { prop: 'location', label: '路况位置', width: '', slot: 'location' },
{ prop: "occurrenceTime", label: "发生时间", width: "" }, { prop: 'occurrenceTime', label: '发生时间', width: '' },
// { prop: "routeNo2", label: "线", width: "" }, // { prop: "routeNo2", label: "线", width: "" },
{ prop: "type", label: "类型", width: "" }, { prop: 'type', label: '类型', width: '' },
{ {
prop: "roadConditionType", prop: 'roadConditionType',
label: "管控措施", label: '管控措施',
width: "", width: '',
slot: "roadConditionType", slot: 'roadConditionType',
}, },
{ prop: "operation", label: "操作", width: "", slot: "operation" }, { prop: 'operation', label: '操作', width: '', slot: 'operation' },
]); ]);
// //
@ -183,34 +179,34 @@ const visiblePages = computed(() => {
}); });
// //
const getControlClass = (measure) => { const getControlClass = measure => {
const classMap = { const classMap = {
全幅封闭: "control-close", 全幅封闭: 'control-close',
半幅封闭: "control-half", 半幅封闭: 'control-half',
正常通行: "control-normal", 正常通行: 'control-normal',
限制通行: "control-limit", 限制通行: 'control-limit',
}; };
return classMap[measure] || ""; return classMap[measure] || '';
}; };
// //
const handleClose = () => { const handleClose = () => {
emit("update:visible", false); emit('update:visible', false);
emit("close"); emit('close');
}; };
// //
const handleDetail = (item) => { const handleDetail = item => {
emit("detail", item); emit('detail', item);
}; };
// //
const handleSizeChange = (val) => { const handleSizeChange = val => {
pageSize.value = val; pageSize.value = val;
fetchData(); fetchData();
}; };
const handleCurrentChange = (val) => { const handleCurrentChange = val => {
currentPage.value = val; currentPage.value = val;
fetchData(); fetchData();
}; };
@ -224,19 +220,19 @@ const fetchData = async () => {
try { try {
// //
let measureType = 0; let measureType = 0;
if (filterForm.value.roadConditionType === "全幅封闭") { if (filterForm.value.roadConditionType === '全幅封闭') {
measureType = 1; measureType = 1;
} else if (filterForm.value.roadConditionType === "半幅封闭") { } else if (filterForm.value.roadConditionType === '半幅封闭') {
measureType = 2; measureType = 2;
} else if (filterForm.value.roadConditionType === "限速") { } else if (filterForm.value.roadConditionType === '限速') {
measureType = 3; measureType = 3;
} else if (filterForm.value.roadConditionType === "告警阻拦") { } else if (filterForm.value.roadConditionType === '告警阻拦') {
measureType = 4; measureType = 4;
} }
const res = await request({ const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/control-list", url: '/snow-ops-platform/sm-event/dashboard/control-list',
method: "GET", method: 'GET',
params: { params: {
pageNum: currentPage.value, pageNum: currentPage.value,
pageSize: pageSize.value, pageSize: pageSize.value,
@ -244,40 +240,40 @@ const fetchData = async () => {
}, },
}); });
if (res.code === "00000" && res.data) { if (res.code === '00000' && res.data) {
const data = res.data; const data = res.data;
// //
tableData.value = data.records.map((item) => { tableData.value = data.records.map((item, index) => {
return { return {
id: item.id, id: currentPage.value * pageSize.value - (pageSize.value - index - 1),
district: item.district || "-", district: item.affectedArea || '-',
routeNo: item.routeNo || "-", routeNo: item.routeNo || '-',
stakeNo: `${item.startStakeNo}-${item.endStakeNo}` || "-", stakeNo: `${item.startStakeNo}-${item.endStakeNo}` || '-',
location: item.occurLocation || "-", location: item.occurLocation || '-',
occurrenceTime: item.occurTime || "-", occurrenceTime: item.occurTime || '-',
// routeNo2: item.routeNo || "-", // routeNo2: item.routeNo || "-",
type: item.roadConditionType || "-", type: item.roadConditionType || '-',
roadConditionType: item.roadConditionType || "-", roadConditionType: item.processingMeasure || '-',
expectRecoverTime: item.expectRecoverTime || "-", expectRecoverTime: item.expectRecoverTime || '-',
eventStatus: item.eventStatus || "-", eventStatus: item.eventStatus || '-',
}; };
}); });
total.value = data.total; total.value = data.total;
} }
} catch (error) { } catch (error) {
console.error("获取抢通情况数据失败:", error); console.error('获取抢通情况数据失败:', error);
} }
}; };
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
(newVal) => { newVal => {
if (newVal) { if (newVal) {
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
} }
}, }
); );
</script> </script>

View File

@ -17,7 +17,7 @@
<template #filter> <template #filter>
<div class="filter-row"> <div class="filter-row">
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">影响区域</span> <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.region" placeholder="请选择" class="filter-select" clearable>
<el-option <el-option
v-for="item in regionOptions" v-for="item in regionOptions"
@ -83,7 +83,7 @@ const filterForm = ref({
riskLevel: "", riskLevel: "",
}); });
// //
// index.js // index.js
// //
@ -95,7 +95,7 @@ const tableHeight = ref(300);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: 'id', label: '序号', width: '60' }, { prop: 'id', label: '序号', width: '60' },
{ prop: 'region', label: '影响区域', width: '100' }, { prop: 'region', label: '行政区域', width: '100' },
{ prop: 'stationName', label: '驻地名称', width: '200', slot: 'stationName' }, { prop: 'stationName', label: '驻地名称', width: '200', slot: 'stationName' },
{ prop: 'project', label: '所属项目', width: '200', slot: 'project' }, { prop: 'project', label: '所属项目', width: '200', slot: 'project' },
{ prop: 'peopleCount', label: '驻地人数', width: '80' }, { prop: 'peopleCount', label: '驻地人数', width: '80' },

View File

@ -17,7 +17,7 @@
<template #filter> <template #filter>
<div class="filter-row"> <div class="filter-row">
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">影响区域</span> <span class="filter-label">行政区域</span>
<el-select :teleported="false" <el-select :teleported="false"
v-model="filterForm.region" v-model="filterForm.region"
placeholder="请选择" placeholder="请选择"
@ -76,7 +76,7 @@ const filterForm = ref({
type: "", type: "",
}); });
// //
// index.js // index.js
// //

View File

@ -17,7 +17,7 @@
<template #filter> <template #filter>
<div class="filter-row"> <div class="filter-row">
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">影响区域</span> <span class="filter-label">行政区域</span>
<el-select :teleported="false" <el-select :teleported="false"
v-model="filterForm.region" v-model="filterForm.region"
placeholder="请选择" placeholder="请选择"
@ -68,7 +68,7 @@ const filterForm = ref({
region: "", region: "",
}); });
// //
// index.js // index.js
// //
@ -77,7 +77,7 @@ const tableHeight = ref(300);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: "id", label: "序号", width: "" }, { prop: "id", label: "序号", width: "" },
{ prop: "region", label: "影响区域", width: "" }, { prop: "region", label: "行政区域", width: "" },
{ prop: "dispatchCount", label: "调度数", width: "", slot: "dispatchCount" }, { prop: "dispatchCount", label: "调度数", width: "", slot: "dispatchCount" },
{ prop: "lastDispatchTime", label: "最近调度时间", width: "" }, { prop: "lastDispatchTime", label: "最近调度时间", width: "" },
]); ]);

View File

@ -0,0 +1,451 @@
<template>
<base-dialog
v-model:visible="props.visible"
title="涉灾隐患点情况"
:table-data="tableData"
:table-columns="tableColumns"
:table-height="450"
:total="total"
:current-page="currentPage"
:page-size="pageSize"
:z-index="2000"
:max-width="900"
:show-filter="false"
:table-show="false"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@close="handleClose"
>
<!-- 自定义内容区域 -->
<template #header>
<div class="hazard-info-panel">
<!-- 基本信息 -->
<div class="info-section">
<div class="info-row">
<div class="info-item">
<span class="info-label">区县名称</span>
<span class="info-value">{{ hazardData.district }}</span>
</div>
<div class="info-item">
<span class="info-label">风险等级</span>
<span class="info-value">{{ hazardData.riskLevel }}</span>
</div>
</div>
<div class="info-row">
<div class="info-item">
<span class="info-label">公路编号</span>
<span class="info-value">{{ hazardData.roadCode }}</span>
</div>
<div class="info-item">
<span class="info-label">位置</span>
<span class="info-value">{{ hazardData.location }}</span>
</div>
</div>
</div>
<!-- 风险描述 -->
<div class="info-block">
<div class="block-title">风险描述</div>
<div class="block-content">{{ hazardData.riskDescription }}</div>
</div>
<!-- 采取措施 -->
<div class="info-block">
<div class="block-title">采取措施</div>
<div class="block-content">{{ hazardData.measures }}</div>
</div>
<!-- 三级包保责任人 -->
<div class="info-block">
<div class="block-title">三级包保责任人</div>
<div class="responsibility-list">
<div class="responsibility-item">
<span class="responsibility-label">交通主管部门责任人</span>
<span class="responsibility-name">{{ hazardData.trafficDept.name }}</span>
<span class="responsibility-phone">{{ hazardData.trafficDept.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.trafficDept.frequency }}</span>
</div>
<div class="responsibility-item">
<span class="responsibility-label">公路机构责任人</span>
<span class="responsibility-name">{{ hazardData.roadOrg.name }}</span>
<span class="responsibility-phone">{{ hazardData.roadOrg.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.roadOrg.frequency }}</span>
</div>
<div class="responsibility-item">
<span class="responsibility-label">养护站责任人</span>
<span class="responsibility-name">{{ hazardData.maintenance.name }}</span>
<span class="responsibility-phone">{{ hazardData.maintenance.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.maintenance.frequency }}</span>
</div>
</div>
</div>
<!-- 护路员 -->
<div class="info-row simple-row">
<span class="row-label">护路员</span>
<span class="row-value name">{{ hazardData.roadKeeper.name }}</span>
<span class="row-value phone">{{ hazardData.roadKeeper.phone }}</span>
<span class="row-value frequency">{{ hazardData.roadKeeper.frequency }}</span>
</div>
<!-- 预警预报关 -->
<div class="info-row simple-row">
<span class="row-label">预警预报关</span>
<span class="row-value">{{ hazardData.earlyWarning }}</span>
</div>
<!-- 线下巡查关 -->
<div class="info-row simple-row">
<span class="row-label">线下巡查关</span>
<span class="row-value">{{ hazardData.offlinePatrol }}</span>
</div>
<!-- 交通管控关 -->
<div class="info-row simple-row">
<span class="row-label">交通管控关</span>
<span class="row-value">{{ hazardData.trafficControl }}</span>
</div>
<!-- 力量预置关 -->
<div class="info-row simple-row">
<span class="row-label">力量预置关</span>
<span class="row-value">{{ hazardData.forcePreposition }}</span>
<el-icon class="location-icon"><Location /></el-icon>
</div>
<!-- 告警阻拦关 -->
<div class="info-row simple-row">
<span class="row-label">告警阻拦关</span>
<span class="row-value">{{ hazardData.alarmBlocking }}</span>
</div>
</div>
</template>
</base-dialog>
</template>
<script setup>
import { ref, watch } from 'vue';
import { Location } from '@element-plus/icons-vue';
import baseDialog from '../component/baseDialog.vue';
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
data: {
type: Object,
default: () => ({}),
},
});
const emit = defineEmits(['update:visible', 'close']);
// 使
const tableColumns = ref([]);
const tableData = ref([]);
const total = ref(0);
const currentPage = ref(1);
const pageSize = ref(10);
//
const hazardData = ref({
//
district: '', // GL1_QXMC
riskLevel: '', // GL1_FXDJ
roadCode: '', // GL1_GLBH 线
roadName: '', // GL1_GLMC 线
location: '', // GL1_QDZH + GL1_ZDZH
riskDescription: '', // GL1_FXMS
riskType: '', // GL1_FXLX
measures: '', // GL1_CQCS
isWithinRedLine: '', // GL1_SFHXN 线
//
trafficDept: {
name: '', // GL1_JTXM
phone: '', // GL1_JTDH
frequency: '',
},
roadOrg: {
name: '', // GL1_JGXM
phone: '', // GL1_JGDH
frequency: '',
},
maintenance: {
name: '', // GL1_YHXM
phone: '', // GL1_YHDH
frequency: '',
},
roadKeeper: {
name: '', // GL1_HLXM
phone: '', // GL1_HLDH
frequency: '',
},
//
earlyWarning: '', // GL1_YJDJ
offlinePatrol: '', // GL1_SFJCD
trafficControl: '', // GL1_SFZCQS
forcePreposition: '', // GL1_ZT
alarmBlocking: '', // GL1_SFZZWC
//
isMeasureTaken: '', // GL1_SFCQCS
completeDeadline: '', // GL1_WCSX
expertOpinion: '', // GL1_ZJYJ
isTransferred: '', // GL1_SFGZYJ
auditStatus: '', // GL1_SHZT
auditUnit: '', // GL1_SHDW
reporter: '', // GL1_SBR
reportTime: '', // GL1_SBSJ
remark: '', // GL1_BZ
//
longitude: '', // GL1_LON
latitude: '', // GL1_LAT
});
//
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
//
const handleSizeChange = val => {
pageSize.value = val;
};
const handleCurrentChange = val => {
currentPage.value = val;
};
// visible
watch(
() => props.visible,
newVal => {
if (newVal && props.data) {
//
const data = props.data;
hazardData.value = {
//
district: data.GL1_QXMC || data.district || '',
riskLevel: data.GL1_FXDJ || data.riskLevel || '',
roadCode: data.GL1_GLBH || data.roadCode || '',
roadName: data.GL1_GLMC || data.roadName || '',
location:
data.GL1_QDZH && data.GL1_ZDZH
? `${data.GL1_QDZH}${data.GL1_ZDZH}`
: data.location || '',
riskDescription: data.GL1_FXMS || data.riskDescription || '',
riskType: data.GL1_FXLX || data.riskType || '',
measures: data.GL1_CQCS || data.measures || '',
isWithinRedLine: data.GL1_SFHXN || data.isWithinRedLine || '',
//
trafficDept: {
name: data.GL1_JTXM || data.trafficDept?.name || '',
phone: data.GL1_JTDH || data.trafficDept?.phone || '',
frequency: data.trafficDept?.frequency || '',
},
roadOrg: {
name: data.GL1_JGXM || data.roadOrg?.name || '',
phone: data.GL1_JGDH || data.roadOrg?.phone || '',
frequency: data.roadOrg?.frequency || '',
},
maintenance: {
name: data.GL1_YHXM || data.maintenance?.name || '',
phone: data.GL1_YHDH || data.maintenance?.phone || '',
frequency: data.maintenance?.frequency || '',
},
roadKeeper: {
name: data.GL1_HLXM || data.roadKeeper?.name || '',
phone: data.GL1_HLDH || data.roadKeeper?.phone || '',
frequency: data.roadKeeper?.frequency || '',
},
//
earlyWarning: data.GL1_YJDJ || data.earlyWarning || '',
offlinePatrol: data.GL1_SFJCD || data.offlinePatrol || '',
trafficControl: data.GL1_SFZCQS || data.trafficControl || '',
forcePreposition: data.GL1_ZT || data.forcePreposition || '',
alarmBlocking: data.GL1_SFZZWC || data.alarmBlocking || '',
//
isMeasureTaken: data.GL1_SFCQCS || data.isMeasureTaken || '',
completeDeadline: data.GL1_WCSX || data.completeDeadline || '',
expertOpinion: data.GL1_ZJYJ || data.expertOpinion || '',
isTransferred: data.GL1_SFGZYJ || data.isTransferred || '',
auditStatus: data.GL1_SHZT || data.auditStatus || '',
auditUnit: data.GL1_SHDW || data.auditUnit || '',
reporter: data.GL1_SBR || data.reporter || '',
reportTime: data.GL1_SBSJ || data.reportTime || '',
remark: data.GL1_BZ || data.remark || '',
//
longitude: data.GL1_LON || data.longitude || '',
latitude: data.GL1_LAT || data.latitude || '',
};
}
},
{ immediate: true }
);
</script>
<style lang="scss" scoped>
.hazard-info-panel {
height: 500px;
color: rgba(255, 255, 255, 0.9);
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);
.info-section {
margin-bottom: 16px;
}
.info-row {
display: flex;
margin-bottom: 12px;
&.simple-row {
align-items: center;
padding: 8px 0;
border-bottom: 1px solid rgba(64, 169, 255, 0.1);
.row-label {
width: 100px;
color: rgba(255, 255, 255, 0.6);
font-size: 14px;
}
.row-value {
flex: 1;
color: rgba(255, 255, 255, 0.9);
font-size: 14px;
&.name {
color: #40a9ff;
width: auto;
flex: none;
margin-right: 8px;
}
&.phone {
color: #40a9ff;
width: auto;
flex: none;
margin-right: 16px;
}
&.frequency {
color: rgba(255, 255, 255, 0.6);
width: auto;
flex: none;
}
}
.location-icon {
color: #40a9ff;
font-size: 16px;
cursor: pointer;
margin-left: 8px;
}
}
}
.info-item {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
.info-label {
color: rgba(255, 255, 255, 0.6);
font-size: 13px;
}
.info-value {
color: rgba(255, 255, 255, 0.9);
font-size: 14px;
font-weight: 500;
}
}
.info-block {
margin-bottom: 16px;
padding: 12px;
background: rgba(64, 169, 255, 0.05);
border-radius: 4px;
.block-title {
color: rgba(255, 255, 255, 0.6);
font-size: 13px;
margin-bottom: 8px;
}
.block-content {
color: rgba(255, 255, 255, 0.9);
font-size: 14px;
line-height: 1.6;
}
}
.responsibility-list {
display: flex;
flex-direction: column;
gap: 8px;
.responsibility-item {
display: flex;
align-items: center;
gap: 8px;
.responsibility-label {
width: 140px;
color: rgba(255, 255, 255, 0.6);
font-size: 13px;
}
.responsibility-name {
color: #40a9ff;
font-size: 14px;
width: 60px;
}
.responsibility-phone {
color: #40a9ff;
font-size: 14px;
width: 120px;
}
.responsibility-frequency {
color: rgba(255, 255, 255, 0.6);
font-size: 13px;
flex: 1;
}
}
}
}
</style>

View File

@ -79,7 +79,7 @@
:teleported="false" :teleported="false"
v-model="filterForm.region" v-model="filterForm.region"
size="small" size="small"
placeholder="影响区域" placeholder="行政区域"
class="filter-select" class="filter-select"
> >
<el-option <el-option
@ -260,7 +260,7 @@ const filterForm = ref({
// 使 // 使
const unifiedColumns = [ const unifiedColumns = [
{ prop: "id", label: "序号", width: "" }, { prop: "id", label: "序号", width: "" },
{ prop: "region", label: "影响区域", width: "" }, { prop: "region", label: "行政区域", width: "" },
{ prop: "pointType", label: "影响点类型", width: "" }, { prop: "pointType", label: "影响点类型", width: "" },
{ prop: "pointLocation", label: "影响点位置", width: "" }, { prop: "pointLocation", label: "影响点位置", width: "" },
{ prop: "pointLevel", label: "影响点等级", width: "", slot: "pointLevel" }, { prop: "pointLevel", label: "影响点等级", width: "", slot: "pointLevel" },
@ -296,7 +296,7 @@ const unifiedColumns = [
// //
const projectColumns = [ const projectColumns = [
{ prop: "id", label: "序号", width: "60" }, { prop: "id", label: "序号", width: "60" },
{ prop: "region", label: "影响区域", width: "" }, { prop: "region", label: "行政区域", width: "" },
{ prop: "pointType", label: "影响点类型", width: "" }, { prop: "pointType", label: "影响点类型", width: "" },
{ prop: "siteName", label: "驻地名称", width: "" }, { prop: "siteName", label: "驻地名称", width: "" },
{ {
@ -535,7 +535,7 @@ const processUnifiedData = (item, type) => {
// //
const baseData = { const baseData = {
id: item.id, id: item.id,
// //
region: region:
item.GL1_QXMC || item.GL1_QXMC ||
item.COUNTY || item.COUNTY ||
@ -600,7 +600,7 @@ const processUnifiedData = (item, type) => {
if (cardTypeVal.value === "桥梁") { if (cardTypeVal.value === "桥梁") {
return { return {
...baseData, ...baseData,
// - 使 // - 使
region: item.GL1_QXMC || "-", region: item.GL1_QXMC || "-",
// - 使 // - 使
pointLocation: item.GL1_QLMC || "-", pointLocation: item.GL1_QLMC || "-",
@ -641,7 +641,7 @@ const processUnifiedData = (item, type) => {
if (cardTypeVal.value === "隧道") { if (cardTypeVal.value === "隧道") {
return { return {
...baseData, ...baseData,
// - 使 // - 使
region: item.GL1_QXMC || item.GL1_QXBM || "-", region: item.GL1_QXMC || item.GL1_QXBM || "-",
// - 使 // - 使
pointLocation: item.GL1_SDMC || "-", pointLocation: item.GL1_SDMC || "-",
@ -682,8 +682,8 @@ const processUnifiedData = (item, type) => {
if (cardTypeVal.value === "路段") { if (cardTypeVal.value === "路段") {
return { return {
...baseData, ...baseData,
// - 使 // - 使
region: item.GL1_QXMC || "-", region: item.GL1_ZDMC || "-",
// - 使线+ // - 使线+
pointLocation: `${item.GL1_GLMC || item.GL1_GLBH || "-"} (${item.GL1_QDZH || "-"} - ${item.GL1_ZDZH || "-"})`, pointLocation: `${item.GL1_GLMC || item.GL1_GLBH || "-"} (${item.GL1_QDZH || "-"} - ${item.GL1_ZDZH || "-"})`,
// - 使 // - 使
@ -721,7 +721,7 @@ const processUnifiedData = (item, type) => {
if (cardTypeVal.value === "项目") { if (cardTypeVal.value === "项目") {
return { return {
...baseData, ...baseData,
// - 使COUNTY // - 使COUNTY
region: item.COUNTY || item.county || item.county_name || "-", region: item.COUNTY || item.county || item.county_name || "-",
// - 使 // - 使
pointLocation: item.PROJECT_NAME || item.projectName || item.name || "-", pointLocation: item.PROJECT_NAME || item.projectName || item.name || "-",

View File

@ -19,78 +19,20 @@
<!-- 统计卡片 --> <!-- 统计卡片 -->
<div class="stats-cards"> <div class="stats-cards">
<div <div
@click="handleClick('0')" v-for="(item, index) in statsCardsData"
:key="index"
@click="handleClick(item.type)"
class="stat-card" class="stat-card"
:style="{ :style="{
backgroundImage: `url(${cardType === '0' ? selectedIcon : unselectedIcon})`, backgroundImage: `url(${cardType === item.type ? selectedIcon : unselectedIcon})`,
backgroundSize: '100% 100%', backgroundSize: '100% 100%',
backgroundPosition: 'center', 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"> <div class="stat-content">
<span class="stat-label">影响桥梁</span> <span class="stat-label">{{ item.label }}</span>
<span class="stat-value">(1430)</span> <span class="stat-value">{{ item.value }}</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>
</div> </div>
</div> </div>
</div> </div>
@ -115,7 +57,8 @@
</div> --> </div> -->
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">影响点等级</span> <span class="filter-label">影响点等级</span>
<el-select :teleported="false" <el-select
:teleported="false"
v-model="filterForm.pointLevel" v-model="filterForm.pointLevel"
placeholder="影响点等级" placeholder="影响点等级"
class="filter-select" class="filter-select"
@ -130,7 +73,8 @@
</div> </div>
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">是否回应</span> <span class="filter-label">是否回应</span>
<el-select :teleported="false" <el-select
:teleported="false"
v-model="filterForm.isResponded" v-model="filterForm.isResponded"
placeholder="是否回应" placeholder="是否回应"
class="filter-select" class="filter-select"
@ -148,9 +92,7 @@
<!-- 影响点等级列插槽 --> <!-- 影响点等级列插槽 -->
<template #pointLevel="{ row }"> <template #pointLevel="{ row }">
<span class="level-tag" :class="row.levelClass">{{ <span class="level-tag" :class="row.levelClass">{{ row.pointLevel }}</span>
row.pointLevel
}}</span>
</template> </template>
<!-- 交通主管部门负责人列插槽 --> <!-- 交通主管部门负责人列插槽 -->
@ -160,11 +102,7 @@
<span style="margin-right: 5px">{{ row.trafficDept.name }}</span> <span style="margin-right: 5px">{{ row.trafficDept.name }}</span>
<img <img
class="response-icon" class="response-icon"
:src=" :src="row.trafficDept.isResponded ? row.trafficDept.img : row.trafficDept.img"
row.trafficDept.isResponded
? row.trafficDept.img
: row.trafficDept.img
"
alt alt
/> />
</div> </div>
@ -197,11 +135,11 @@
</template> </template>
<!-- 回应状态列插槽 --> <!-- 回应状态列插槽 -->
<template #responseStatus="{ row }"> <!-- <template #responseStatus="{ row }">
<span class="response-status" :class="row.responseClass">{{ <span class="response-status" :class="row.responseClass">{{
row.responseStatus row.responseStatus
}}</span> }}</span>
</template> </template> -->
<!-- 最新催告时间列插槽 --> <!-- 最新催告时间列插槽 -->
<template #urgeTime="{ row }"> <template #urgeTime="{ row }">
@ -219,25 +157,22 @@
</template> </template>
<script setup> <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 { Close, ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
import { import { pointTypeOptions, pointLevelOptions, isRespondedOptions } from '../component/index.js';
pointTypeOptions, import baseDialog from '../component/baseDialog.vue';
pointLevelOptions, import { request } from '@/utils/request.js';
isRespondedOptions,
} from "../component/index.js";
import baseDialog from "../component/baseDialog.vue";
import respondedIcon from "../../../assets/xiangying/有回应@2x.png"; import respondedIcon from '../../../assets/xiangying/有回应@2x.png';
import notRespondedIcon from "../../../assets/xiangying/无回应@2x.png"; import notRespondedIcon from '../../../assets/xiangying/无回应@2x.png';
import selectedIcon from "../../../assets/xiangying/选中bg@2x.png"; import selectedIcon from '../../../assets/xiangying/选中bg@2x.png';
import unselectedIcon from "../../../assets/xiangying/未选中bg@2x.png"; import unselectedIcon from '../../../assets/xiangying/未选中bg@2x.png';
import Icon0 from "../../../assets/xiangying/选中@2x.png"; import Icon0 from '../../../assets/xiangying/选中@2x.png';
import Icon1 from "../../../assets/xiangying/未选中1@2x.png"; import Icon1 from '../../../assets/xiangying/未选中1@2x.png';
import Icon2 from "../../../assets/xiangying/未选中2@2x.png"; import Icon2 from '../../../assets/xiangying/未选中2@2x.png';
import Icon3 from "../../../assets/xiangying/未选中3@2x.png"; import Icon3 from '../../../assets/xiangying/未选中3@2x.png';
import Icon4 from "../../../assets/xiangying/未选中4@2x.png"; import Icon4 from '../../../assets/xiangying/未选中4@2x.png';
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -246,108 +181,94 @@ const props = defineProps({
}, },
}); });
const emit = defineEmits(["update:visible", "close", "detail"]); const emit = defineEmits(['update:visible', 'close', 'detail']);
// //
const filterForm = ref({ const filterForm = ref({
pointType: "", pointType: '',
pointLevel: "", pointLevel: '',
isResponded: "", isResponded: '',
}); });
const cardType = ref("0"); const cardType = ref('0');
//
const statsCardsData = ref([
{ type: '桥梁', label: '影响桥梁', value: 0, icon: Icon0 },
{ type: '路段', label: '影响路段', value: 0, icon: Icon4 },
{ type: '隧道', label: '影响隧道', value: 0, icon: Icon2 },
{ type: '边坡', label: '影响边坡', value: 0, icon: Icon1 },
{ type: '项目', label: '影响项目', value: 0, icon: Icon3 },
]);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: "id", label: "序号", width: "50px" }, { prop: 'id', label: '序号', width: '' },
{ prop: "pointType", label: "影响点类型", width: "80px" }, { prop: 'pointType', label: '影响点类型', width: '' },
{ prop: "pointLocation", label: "影响点位置", width: "150px" }, { prop: 'pointLocation', label: '影响点位置', width: '' },
{ { prop: 'pointLevel', label: '影响点等级', width: '', slot: 'pointLevel' },
prop: "pointLevel", { prop: 'checkCount', label: '查次数', width: '' },
label: "影响点等级", { prop: 'trafficDept', label: '交通主管部门负责人', width: '', slot: 'trafficDept' },
width: "90px", { prop: 'roadOrg', label: '公路机构责任人', width: '', slot: 'roadOrg' },
slot: "pointLevel", { prop: 'maintenance', label: '养护站负责人', width: '', slot: 'maintenance' },
}, { prop: 'roadKeeper', label: '护路员', width: '', slot: 'roadKeeper' },
{ prop: "checkCount", label: "查次数", width: "60px" }, { prop: 'urgeTime', label: '最新催告时间', width: '', slot: 'urgeTime' },
{ { prop: 'operation', label: '操作', width: '', slot: 'operation' },
prop: "trafficDept",
label: "交通主管部门负责人",
width: "120px",
slot: "trafficDept",
},
{ prop: "roadOrg", label: "公路机构责任人", width: "110px", slot: "roadOrg" },
{
prop: "maintenance",
label: "养护站负责人",
width: "110px",
slot: "maintenance",
},
{ prop: "roadKeeper", label: "护路员", width: "80px", slot: "roadKeeper" },
{
prop: "responseStatus",
label: "回应状态",
width: "70px",
slot: "responseStatus",
},
{ prop: "urgeTime", label: "最新催告时间", width: "110px", slot: "urgeTime" },
{ prop: "operation", label: "操作", width: "50px", slot: "operation" },
]); ]);
// //
const tableData = ref([ const tableData = ref([
{ {
id: 1, id: 1,
pointType: "边坡", pointType: '边坡',
pointLocation: "武汉-大理(K1452+951至K1462+209)", pointLocation: '武汉-大理(K1452+951至K1462+209)',
pointLevel: "一般隐患", pointLevel: '一般隐患',
levelClass: "level-normal", levelClass: 'level-normal',
checkCount: 2, checkCount: 2,
trafficDept: { trafficDept: {
name: "罗宸", name: '罗宸',
phone: "17623865172", phone: '17623865172',
img: respondedIcon, img: respondedIcon,
isResponded: true, isResponded: true,
}, },
roadOrg: { roadOrg: {
name: "李海平", name: '李海平',
phone: "1372386532", phone: '1372386532',
img: notRespondedIcon, img: notRespondedIcon,
isResponded: false, isResponded: false,
}, },
maintenance: { maintenance: {
name: "苏祖兵", name: '苏祖兵',
phone: "13594331090", phone: '13594331090',
img: notRespondedIcon, img: notRespondedIcon,
isResponded: false, isResponded: false,
}, },
roadKeeper: { roadKeeper: {
name: "凌承礼", name: '凌承礼',
phone: "1592393704", phone: '1592393704',
img: respondedIcon, img: respondedIcon,
isResponded: true, isResponded: true,
}, },
responseStatus: "已回应", responseStatus: '已回应',
responseClass: "status-responded", responseClass: 'status-responded',
urgeTime: { date: "2026-03-28", time: "12:30:00" }, urgeTime: { date: '2026-03-28', time: '12:30:00' },
}, },
{ {
id: 12, id: 12,
pointType: "边坡", pointType: '边坡',
pointLocation: "武汉-大理(K1452+951至K1462+209)", pointLocation: '武汉-大理(K1452+951至K1462+209)',
pointLevel: "一般隐患", pointLevel: '一般隐患',
levelClass: "level-normal", levelClass: 'level-normal',
checkCount: 2, checkCount: 2,
trafficDept: { name: "罗宸", phone: "17623865172" }, trafficDept: { name: '罗宸', phone: '17623865172' },
roadOrg: { name: "李海平", phone: "1372386532" }, roadOrg: { name: '李海平', phone: '1372386532' },
maintenance: { name: "苏祖兵", phone: "13594331090" }, maintenance: { name: '苏祖兵', phone: '13594331090' },
roadKeeper: { name: "凌承礼", phone: "1592393704" }, roadKeeper: { name: '凌承礼', phone: '1592393704' },
responseStatus: "已回应", responseStatus: '已回应',
responseClass: "status-responded", responseClass: 'status-responded',
urgeTime: { date: "2026-03-28", time: "12:30:00" }, urgeTime: { date: '2026-03-28', time: '12:30:00' },
}, },
]); ]);
tableData.value.push(...tableData.value);
tableData.value.push(...tableData.value);
// //
const currentPage = ref(1); const currentPage = ref(1);
@ -356,49 +277,90 @@ const total = ref(36);
// //
const handleClose = () => { const handleClose = () => {
emit("update:visible", false); emit('update:visible', false);
emit("close"); emit('close');
}; };
// //
const handleClick = (type) => { const handleClick = type => {
cardType.value = type; cardType.value = type;
}; };
//
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: '项目',
};
statsCardsData.value.forEach(item => {
data.forEach(stat => {
if (stat.extension == item.type) {
item.value = stat.count || 0;
}
});
});
}
}
} catch (error) {
console.error('加载柱状图数据失败:', error);
}
};
// base-dialog // base-dialog
// //
const handleDetail = (item) => { const handleDetail = item => {
emit("detail", item); emit('detail', item);
}; };
// //
const handleSizeChange = (val) => { const handleSizeChange = val => {
pageSize.value = val; pageSize.value = val;
fetchData(); fetchData();
}; };
const handleCurrentChange = (val) => { const handleCurrentChange = val => {
currentPage.value = val; currentPage.value = val;
fetchData(); fetchData();
}; };
// //
const fetchData = () => { const fetchData = () => {
console.log("获取第", currentPage.value, "页数据"); console.log('获取第', currentPage.value, '页数据');
// API // API
}; };
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
(newVal) => { newVal => {
if (newVal) { if (newVal) {
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
} }
}, }
); );
onMounted(() => {
//
loadBarChartData();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,7 +1,7 @@
<template> <template>
<base-dialog <base-dialog
v-model:visible="props.visible" v-model:visible="props.visible"
title="潼南基本信息表" :title="props.allCountyData.name + '基本信息表'"
:table-data="tableData" :table-data="tableData"
:table-columns="tableColumns" :table-columns="tableColumns"
:table-height="320" :table-height="320"
@ -32,70 +32,83 @@
<!-- 驻地名称列插槽 --> <!-- 驻地名称列插槽 -->
<template #stationName="{ row }"> <template #stationName="{ row }">
<el-tooltip :content="row.stationName" placement="top" :show-after="500"> <el-tooltip :content="row.stationName" placement="top" :show-after="500">
<span class="station-name-text" @click="handleStationNameClick(row)">{{ row.stationName }}</span> <span class="station-name-text" @click="handleStationNameClick(row)">
{{ row.stationName }}
</span>
</el-tooltip> </el-tooltip>
</template> </template>
</base-dialog> </base-dialog>
</template> </template>
<script setup> <script setup>
import { ref, computed, watch } from "vue"; import { ref, computed, watch } from 'vue';
import { VideoCamera, Microphone, Phone } from "@element-plus/icons-vue"; import { VideoCamera, Microphone, Phone } from '@element-plus/icons-vue';
import baseDialog from "../component/baseDialog.vue"; import baseDialog from '../component/baseDialog.vue';
const props = defineProps({ const props = defineProps({
visible: { visible: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
allCountyData: {
type: Object,
default: () => {},
},
tongnanInfoItemData: {
type: Object,
default: () => ({
name: '',
}),
},
}); });
const emit = defineEmits(["update:visible", "close", "video", "voice", "call", "stationNameClick"]); const emit = defineEmits(['update:visible', 'close', 'video', 'voice', 'call', 'stationNameClick']);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: "id", label: "序号", width: "60px" }, { prop: 'id', label: '序号', width: '60px' },
{ prop: "region", label: "区县/镇街", width: "140px" }, { prop: 'region', label: '区县/镇街', width: '140px' },
{ prop: "name", label: "姓名", width: "100px" }, { prop: 'name', label: '姓名', width: '100px' },
{ prop: "phone", label: "电话", width: "120px" }, { prop: 'phone', label: '电话', width: '120px' },
{ prop: "stationName", label: "驻地名称", width: "180px", slot: "stationName" }, { prop: 'stationName', label: '驻地名称', width: '180px', slot: 'stationName' },
{ prop: "type", label: "类型", width: "auto" }, { prop: 'type', label: '类型', width: 'auto' },
{ prop: "operation", label: "调度", width: "140px", slot: "operation" }, { prop: 'operation', label: '调度', width: '140px', slot: 'operation' },
]); ]);
// //
const tableData = ref([ const tableData = ref([
{ {
id: 1, id: 1,
region: "沙坪坝区", region: '沙坪坝区',
name: "赵海浪", name: '赵海浪',
phone: "18623520688", phone: '18623520688',
stationName: "沙坪坝区S545茅山峡公路桥新建工程渝黔铁路扩能改造工程项目经理部", stationName: '沙坪坝区S545茅山峡公路桥新建工程渝黔铁路扩能改造工程项目经理部',
type: "交通主管部门", type: '交通主管部门',
}, },
{ {
id: 2, id: 2,
region: "沙坪坝区", region: '沙坪坝区',
name: "府效能", name: '府效能',
phone: "18623520688", phone: '18623520688',
stationName: "沙坪坝区S545茅山峡公路桥新建工程渝黔铁路扩能改造工程项目经理部", stationName: '沙坪坝区S545茅山峡公路桥新建工程渝黔铁路扩能改造工程项目经理部',
type: "公路机构", type: '公路机构',
}, },
{ {
id: 3, id: 3,
region: "万州区柏梓镇", region: '万州区柏梓镇',
name: "王鑫", name: '王鑫',
phone: "18623520688", phone: '18623520688',
stationName: "万州区项目经理部", stationName: '万州区项目经理部',
type: "公路机构", type: '公路机构',
}, },
{ {
id: 4, id: 4,
region: "万州区柏梓镇", region: '万州区柏梓镇',
name: "王鑫", name: '王鑫',
phone: "18623520688", phone: '18623520688',
stationName: "万州区项目经理部", stationName: '万州区项目经理部',
type: "公路机构", type: '公路机构',
}, },
]); ]);
@ -124,52 +137,52 @@ const visiblePages = computed(() => {
// //
const handleClose = () => { const handleClose = () => {
emit("update:visible", false); emit('update:visible', false);
emit("close"); emit('close');
}; };
// base-dialog // base-dialog
// //
const handleVideo = (item) => { const handleVideo = item => {
emit("video", item); emit('video', item);
}; };
const handleVoice = (item) => { const handleVoice = item => {
emit("voice", item); emit('voice', item);
}; };
const handleCall = (item) => { const handleCall = item => {
emit("call", item); emit('call', item);
}; };
// //
const handleStationNameClick = (item) => { const handleStationNameClick = item => {
emit("stationNameClick", item); emit('stationNameClick', item);
}; };
// //
const handleSizeChange = (size) => { const handleSizeChange = size => {
pageSize.value = size; pageSize.value = size;
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
}; };
const handleCurrentChange = (page) => { const handleCurrentChange = page => {
currentPage.value = page; currentPage.value = page;
fetchData(); fetchData();
}; };
// //
const fetchData = () => { const fetchData = () => {
console.log("获取第", currentPage.value, "页数据"); console.log('获取第', currentPage.value, '页数据');
// API // API
}; };
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
(newVal) => { newVal => {
if (newVal) { if (newVal) {
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
@ -189,7 +202,7 @@ watch(
width: 28px; width: 28px;
height: 28px; height: 28px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
cursor: pointer; cursor: pointer;

View File

@ -0,0 +1,238 @@
<template>
<base-dialog
v-model:visible="props.visible"
:title="`${props.allCountyData.name}建设项目责任人详情`"
:table-data="tableData"
:table-columns="tableColumns"
:table-height="350"
:total="total"
:current-page="currentPage"
:page-size="pageSize"
:z-index="1000"
:max-width="1100"
:show-filter="false"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@close="handleClose"
>
<!-- 调度列插槽 -->
<template #dispatch="{ row }">
<div class="dispatch-actions">
<div class="action-btns">
<div class="action-btn" @click="handleView(row)">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(row)">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(row)">
<el-icon><Phone /></el-icon>
</div>
</div>
</div>
</template>
</base-dialog>
</template>
<script setup>
import { ref, watch } from 'vue';
import baseDialog from '../component/baseDialog.vue';
import {
Close,
VideoCamera,
Microphone,
Phone,
ArrowLeft,
ArrowRight,
User,
OfficeBuilding,
MapLocation,
} from '@element-plus/icons-vue';
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
allCountyData: {
type: Object,
default: () => {},
},
});
const emit = defineEmits(['update:visible', 'close']);
//
const tableColumns = ref([
{ prop: 'id', label: '序号', width: '' },
{ prop: 'district', label: '区县/镇街', width: '' },
{ prop: 'totalCount', label: '总人数', width: '' },
{ prop: 'whistleblower', label: '吹哨人', width: '' },
{ prop: 'constructionUnit', label: '建设单位包保责任人', width: '' },
{ prop: 'constructionDept', label: '施工单位包保责任人', width: '' },
{ prop: 'stationUnit', label: '驻地包保责任人', width: '' },
{ prop: 'districtUnit', label: '区县级包保责任人', width: '' },
{ prop: 'cityUnit', label: '市级包保责任人', width: '' },
{ prop: 'dispatch', label: '调度', width: '', slot: 'dispatch' },
]);
//
const tableData = ref([
{
id: 1,
district: '万州区',
totalCount: 6,
whistleblower: 2,
constructionUnit: '罗宸\n17623865172',
constructionDept: '李海平\n1372386532',
stationUnit: '苏祖兵\n13594331090',
districtUnit: '凌承礼\n1592393704',
cityUnit: '周刚\n1892395467',
},
{
id: 2,
district: '涪陵区',
totalCount: 8,
whistleblower: 3,
constructionUnit: '张三\n13800138000',
constructionDept: '李四\n13900139000',
stationUnit: '王五\n13700137000',
districtUnit: '赵六\n13600136000',
cityUnit: '孙七\n13500135000',
},
{
id: 3,
district: '渝中区',
totalCount: 5,
whistleblower: 2,
constructionUnit: '周八\n13400134000',
constructionDept: '吴九\n13300133000',
stationUnit: '郑十\n13200132000',
districtUnit: '钱十一\n13100131000',
cityUnit: '陈十二\n13000130000',
},
{
id: 4,
district: '江北区',
totalCount: 7,
whistleblower: 3,
constructionUnit: '刘一\n12900129000',
constructionDept: '黄二\n12800128000',
stationUnit: '林三\n12700127000',
districtUnit: '杨四\n12600126000',
cityUnit: '何五\n12500125000',
},
{
id: 5,
district: '沙坪坝区',
totalCount: 6,
whistleblower: 2,
constructionUnit: '高六\n12400124000',
constructionDept: '马七\n12300123000',
stationUnit: '罗八\n12200122000',
districtUnit: '梁九\n12100121000',
cityUnit: '宋十\n12000120000',
},
]);
const total = ref(36);
const currentPage = ref(1);
const pageSize = ref(10);
//
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
//
const handleSizeChange = val => {
pageSize.value = val;
fetchData();
};
const handleCurrentChange = val => {
currentPage.value = val;
fetchData();
};
//
const fetchData = () => {
console.log('获取第', currentPage.value, '页数据');
// API
};
//
const handleView = item => {
console.log('查看视频:', item);
};
const handleVoice = item => {
console.log('语音通话:', item);
};
const handleCall = item => {
console.log('拨打电话:', item);
};
// visible
watch(
() => props.visible,
newVal => {
if (newVal) {
currentPage.value = 1;
fetchData();
}
}
);
</script>
<style lang="scss" scoped>
.dispatch-actions {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
.dispatch-icon {
width: 24px;
height: 24px;
cursor: pointer;
transition: transform 0.2s;
&:hover {
transform: scale(1.1);
}
}
}
:deep(.el-table .cell) {
white-space: pre-line;
line-height: 1.5;
}
//
.action-btns {
display: flex;
justify-content: center;
gap: 8px;
.action-btn {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(64, 169, 255, 0.15);
border-radius: 2px;
color: #40a9ff;
cursor: pointer;
transition: all 0.3s;
&:hover {
background-color: rgba(64, 169, 255, 0.3);
transform: scale(1.1);
}
}
}
</style>

View File

@ -1,7 +1,7 @@
<template> <template>
<base-dialog <base-dialog
v-model:visible="props.visible" v-model:visible="props.visible"
:title="props.allCountyData.name + '建设责任人明细'" :title="props.allCountyData.name + '建设项目责任人明细'"
:table-data="tableData" :table-data="tableData"
:table-columns="tableColumns" :table-columns="tableColumns"
:table-height="400" :table-height="400"
@ -22,8 +22,8 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, watch } from "vue"; import { ref, computed, watch } from 'vue';
import baseDialog from "../component/baseDialog.vue"; import baseDialog from '../component/baseDialog.vue';
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -33,32 +33,38 @@ const props = defineProps({
allCountyData: { allCountyData: {
type: Object, type: Object,
default: () => ({ default: () => ({
name: "", name: '',
}),
},
tongnanInfoItemData: {
type: Object,
default: () => ({
name: '',
}), }),
}, },
}); });
const emit = defineEmits(["update:visible", "close", "detail"]); const emit = defineEmits(['update:visible', 'close', 'detail']);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: "id", label: "序号", width: "" }, { prop: 'id', label: '序号', width: '' },
{ prop: "region", label: "区县/镇街", width: "" }, { prop: 'region', label: '区县/镇街', width: '' },
{ prop: "totalCount", label: "总人数", width: "" }, { prop: 'totalCount', label: '总人数', width: '' },
{ prop: "whistleblower", label: "吹哨人", width: "" }, { prop: 'whistleblower', label: '吹哨人', width: '' },
{ prop: "constructionUnit", label: "建设单位包保责任人", width: "" }, { prop: 'constructionUnit', label: '建设单位包保责任人', width: '' },
{ prop: "contractorUnit", label: "施工单位包保责任人", width: "" }, { prop: 'contractorUnit', label: '施工单位包保责任人', width: '' },
{ prop: "stationed", label: "驻地包保责任人", width: "" }, { prop: 'stationed', label: '驻地包保责任人', width: '' },
{ prop: "districtLevel", label: "区县级包保责任人", width: "" }, { prop: 'districtLevel', label: '区县级包保责任人', width: '' },
{ prop: "cityLevel", label: "市级包保责任人", width: "" }, { prop: 'cityLevel', label: '市级包保责任人', width: '' },
{ prop: "operation", label: "操作", width: "60px", slot: "operation" }, { prop: 'operation', label: '操作', width: '60px', slot: 'operation' },
]); ]);
// //
const tableData = ref([ const tableData = ref([
{ {
id: 1, id: 1,
region: "万州区", region: '万州区',
totalCount: 6, totalCount: 6,
whistleblower: 2, whistleblower: 2,
constructionUnit: 2, constructionUnit: 2,
@ -69,7 +75,7 @@ const tableData = ref([
}, },
{ {
id: 2, id: 2,
region: "柏梓镇", region: '柏梓镇',
totalCount: 6, totalCount: 6,
whistleblower: 2, whistleblower: 2,
constructionUnit: 2, constructionUnit: 2,
@ -105,44 +111,44 @@ const visiblePages = computed(() => {
// //
const handleClose = () => { const handleClose = () => {
emit("update:visible", false); emit('update:visible', false);
emit("close"); emit('close');
}; };
// base-dialog // base-dialog
// //
const handleDetail = (item) => { const handleDetail = item => {
emit("detail", item); emit('detail', item);
}; };
// //
const handleSizeChange = (size) => { const handleSizeChange = size => {
pageSize.value = size; pageSize.value = size;
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
}; };
const handleCurrentChange = (page) => { const handleCurrentChange = page => {
currentPage.value = page; currentPage.value = page;
fetchData(); fetchData();
}; };
// //
const fetchData = () => { const fetchData = () => {
console.log("获取第", currentPage.value, "页数据"); console.log('获取第', currentPage.value, '页数据');
// API // API
}; };
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
(newVal) => { newVal => {
if (newVal) { if (newVal) {
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
} }
}, }
); );
</script> </script>

View File

@ -22,8 +22,8 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, watch } from "vue"; import { ref, computed, watch } from 'vue';
import baseDialog from "../component/baseDialog.vue"; import baseDialog from '../component/baseDialog.vue';
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -33,30 +33,30 @@ const props = defineProps({
allCountyData: { allCountyData: {
type: Object, type: Object,
default: () => ({ default: () => ({
name: "", name: '',
}), }),
}, },
}); });
const emit = defineEmits(["update:visible", "close", "view"]); const emit = defineEmits(['update:visible', 'close', 'view', 'itemdata']);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: "id", label: "序号", width: "60px" }, { prop: 'id', label: '序号', width: '60px' },
{ prop: "district", label: "区县", width: "100px" }, { prop: 'district', label: '区县', width: '100px' },
{ prop: "totalCount", label: "总人数", width: "80px" }, { prop: 'totalCount', label: '总人数', width: '80px' },
{ prop: "trafficDept", label: "交通主管部门责任人", width: "140px" }, { prop: 'trafficDept', label: '交通主管部门责任人', width: '140px' },
{ prop: "roadOrg", label: "公路机构责任人", width: "120px" }, { prop: 'roadOrg', label: '公路机构责任人', width: '120px' },
{ prop: "maintenance", label: "养护站道班责任人", width: "140px" }, { prop: 'maintenance', label: '养护站道班责任人', width: '140px' },
{ prop: "roadKeeper", label: "护路员", width: "80px" }, { prop: 'roadKeeper', label: '护路员', width: '80px' },
{ prop: "operation", label: "操作", width: "auto", slot: "operation" }, { prop: 'operation', label: '操作', width: 'auto', slot: 'operation' },
]); ]);
// //
const tableData = ref([ const tableData = ref([
{ {
id: 1, id: 1,
district: "潼南", district: '潼南',
totalCount: 128, totalCount: 128,
trafficDept: 2, trafficDept: 2,
roadOrg: 3, roadOrg: 3,
@ -65,7 +65,7 @@ const tableData = ref([
}, },
{ {
id: 2, id: 2,
district: "万州", district: '万州',
totalCount: 96, totalCount: 96,
trafficDept: 1, trafficDept: 1,
roadOrg: 2, roadOrg: 2,
@ -74,7 +74,7 @@ const tableData = ref([
}, },
{ {
id: 3, id: 3,
district: "沙坪坝", district: '沙坪坝',
totalCount: 156, totalCount: 156,
trafficDept: 3, trafficDept: 3,
roadOrg: 4, roadOrg: 4,
@ -83,7 +83,7 @@ const tableData = ref([
}, },
{ {
id: 4, id: 4,
district: "渝中", district: '渝中',
totalCount: 64, totalCount: 64,
trafficDept: 1, trafficDept: 1,
roadOrg: 2, roadOrg: 2,
@ -117,44 +117,48 @@ const visiblePages = computed(() => {
// //
const handleClose = () => { const handleClose = () => {
emit("update:visible", false); emit('update:visible', false);
emit("close"); emit('close');
}; };
// base-dialog // base-dialog
// //
const handleView = (item) => { const handleView = item => {
emit("view", item); emit('view');
emit('itemdata', {
...item,
allCountyData: props.allCountyData,
});
}; };
// //
const handleSizeChange = (size) => { const handleSizeChange = size => {
pageSize.value = size; pageSize.value = size;
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
}; };
const handleCurrentChange = (page) => { const handleCurrentChange = page => {
currentPage.value = page; currentPage.value = page;
fetchData(); fetchData();
}; };
// //
const fetchData = () => { const fetchData = () => {
console.log("获取第", currentPage.value, "页数据"); console.log('获取第', currentPage.value, '页数据');
// API // API
}; };
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
(newVal) => { newVal => {
if (newVal) { if (newVal) {
currentPage.value = 1; currentPage.value = 1;
fetchData(); fetchData();
} }
}, }
); );
</script> </script>

View File

@ -34,7 +34,7 @@
<div class="filter-item"> <div class="filter-item">
<el-select :teleported="false" <el-select :teleported="false"
v-model="filterForm.region" v-model="filterForm.region"
placeholder="影响区域" placeholder="行政区域"
class="filter-select" class="filter-select"
> >
<el-option <el-option
@ -128,7 +128,7 @@ const tableColumns = ref([
{ prop: "id", label: "序号", width: "" }, { prop: "id", label: "序号", width: "" },
{ prop: "weatherSource", label: "气象来源", width: "" }, { prop: "weatherSource", label: "气象来源", width: "" },
{ prop: "warningLevel", label: "预警等级", width: "", slot: "warningLevel" }, { prop: "warningLevel", label: "预警等级", width: "", slot: "warningLevel" },
{ prop: "region", label: "影响区域", width: "" }, { prop: "region", label: "行政区域", width: "" },
{ prop: "warningTime", label: "预警时间", width: "" }, { prop: "warningTime", label: "预警时间", width: "" },
{ prop: "endTime", label: "结束时间", width: "" }, { prop: "endTime", label: "结束时间", width: "" },
{ prop: "impactPoints", label: "影响点数量", width: "" }, { prop: "impactPoints", label: "影响点数量", width: "" },

View File

@ -34,7 +34,7 @@
</el-select> </el-select>
</div> </div>
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">影响区域</span> <span class="filter-label">行政区域</span>
<el-select <el-select
v-model="filterForm.countyName" v-model="filterForm.countyName"
placeholder="请选择" placeholder="请选择"
@ -90,33 +90,25 @@
<!-- 预警等级列插槽 --> <!-- 预警等级列插槽 -->
<template #riskLeve="{ row }"> <template #riskLeve="{ row }">
<span :class="['warning-level-tag', getWarningClass(row.riskLeve)]">{{ <span :class="['warning-level-tag', getWarningClass(row.riskLeve)]">{{ row.riskLeve }}</span>
row.riskLeve
}}</span>
</template> </template>
<!-- 影响点数量列插槽 --> <!-- 影响点数量列插槽 -->
<template #impactCount="{ row }"> <template #impactCount="{ row }">
<span class="impact-count" @click="handleImpactClick(row)">{{ <span class="impact-count" @click="handleImpactClick(row)">{{ row.impactCount }}</span>
row.impactCount
}}</span>
</template> </template>
</base-dialog> </base-dialog>
</template> </template>
<script setup> <script setup>
import { ref, computed, watch, onMounted, inject } from "vue"; import { ref, computed, watch, onMounted, inject } from 'vue';
import { Close, Calendar } from "@element-plus/icons-vue"; import { Close, Calendar } from '@element-plus/icons-vue';
import { import { warningLevelOptions, regionOptions, isEndedOptions } from '../component/index.js';
warningLevelOptions, import baseDialog from '../component/baseDialog.vue';
regionOptions, import { request } from '@/utils/request';
isEndedOptions,
} from "../component/index.js";
import baseDialog from "../component/baseDialog.vue";
import { request } from "@/utils/request";
// //
const getdateRange = inject("getdateRange", ref([])); const getdateRange = inject('getdateRange', ref([]));
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -129,7 +121,7 @@ const props = defineProps({
}, },
}); });
const emit = defineEmits(["update:visible", "close", "impactClick"]); const emit = defineEmits(['update:visible', 'close', 'impactClick']);
// //
const dateRange = ref([]); const dateRange = ref([]);
@ -143,39 +135,39 @@ onMounted(() => {
// warningitem // warningitem
watch( watch(
() => props.warningitem, () => props.warningitem,
(newVal) => { newVal => {
console.log("warningitem 变化:", newVal); console.log('warningitem 变化:', newVal);
if (newVal && Object.keys(newVal).length > 0) { if (newVal && Object.keys(newVal).length > 0) {
filterForm.value.riskLeve = newVal.label || ""; filterForm.value.riskLeve = newVal.label || '';
currentPage.value = 1; currentPage.value = 1;
} }
}, },
{ deep: true }, { deep: true }
); );
// //
watch( watch(
() => getdateRange.value, () => getdateRange.value,
(newVal) => { newVal => {
console.log("warningSituationDialog.vue 日期范围变化:", newVal); console.log('warningSituationDialog.vue 日期范围变化:', newVal);
if (newVal && newVal.length === 2) { if (newVal && newVal.length === 2) {
dateRange.value = newVal; dateRange.value = newVal;
filterForm.value.dateRange = newVal; filterForm.value.dateRange = newVal;
} }
}, },
{ deep: true }, { deep: true }
); );
// //
const filterForm = ref({ const filterForm = ref({
riskLeve: "", riskLeve: '',
countyName: "", countyName: '',
isEnded: "", isEnded: '',
dateRange: dateRange.value, dateRange: dateRange.value,
}); });
// //
const handleDateChange = (val) => { const handleDateChange = val => {
filterForm.value.dateRange = val; filterForm.value.dateRange = val;
}; };
@ -193,28 +185,14 @@ const tableHeight = ref(300);
// //
const tableColumns = ref([ const tableColumns = ref([
{ prop: "index", label: "序号", width: "" }, { prop: 'index', label: '序号', width: '' },
{ { prop: 'riskLeve', label: '预警等级', width: '', slot: 'riskLeve' },
prop: "riskLeve", { label: '来源', prop: 'source', width: '' },
label: "预警等级", { prop: 'weatherType', label: '气象类型', width: '' },
width: "", { prop: 'countyName', label: '影响区域', width: '' },
slot: "riskLeve", { prop: 'warningTime', label: '生效时间', width: '' },
}, { prop: 'endTime', label: '失效时间', width: '' },
{ { prop: 'impactCount', label: '影响点数量', width: '', slot: 'impactCount' },
label: "来源",
prop: "source",
width: "",
},
{ prop: "weatherType", label: "气象类型", width: "" },
{ prop: "countyName", label: "影响区域", width: "" },
{ prop: "warningTime", label: "生效时间", width: "" },
{ prop: "endTime", label: "失效时间", width: "" },
{
prop: "impactCount",
label: "影响点数量",
width: "",
slot: "impactCount",
},
]); ]);
// //
@ -235,12 +213,12 @@ const fetchWarningData = async () => {
const params = { const params = {
offset: (currentPage.value - 1) * pageSize.value, offset: (currentPage.value - 1) * pageSize.value,
limit: pageSize.value, limit: pageSize.value,
start: "", start: '',
end: "", end: '',
riskLevel: "", riskLevel: '',
weatherType: "", weatherType: '',
isExpire: "", isExpire: '',
countyName: "", countyName: '',
}; };
// //
@ -250,10 +228,7 @@ const fetchWarningData = async () => {
if (filterForm.value.countyName) { if (filterForm.value.countyName) {
params.countyName = filterForm.value.countyName; params.countyName = filterForm.value.countyName;
} }
if ( if (filterForm.value.isEnded !== undefined && filterForm.value.isEnded !== '') {
filterForm.value.isEnded !== undefined &&
filterForm.value.isEnded !== ""
) {
params.isExpire = filterForm.value.isEnded; params.isExpire = filterForm.value.isEnded;
} }
if (filterForm.value.dateRange && filterForm.value.dateRange.length === 2) { if (filterForm.value.dateRange && filterForm.value.dateRange.length === 2) {
@ -262,24 +237,24 @@ const fetchWarningData = async () => {
} }
const res = await request({ const res = await request({
url: "/snow-ops-platform/weather-warning/affected-count/_by_weather", url: '/snow-ops-platform/weather-warning/affected-count/_by_weather',
method: "GET", method: 'GET',
params, params,
}); });
if (res.code === "00000" && res.data) { if (res.code === '00000' && res.data) {
// //
const list = res.data.data || res.data.records || []; const list = res.data.data || res.data.records || [];
total.value = res.data.total || 0; total.value = res.data.total || 0;
tableData.value = list.map((item, index) => ({ tableData.value = list.map((item, index) => ({
index: index + 1, index: index + 1,
riskLeve: item.riskLeve || "-", riskLeve: item.riskLeve || '-',
weatherType: item.weatherType || "-", weatherType: item.weatherType || '-',
countyName: item.countyName || "-", countyName: item.countyName || '-',
source: item.source || "-", source: item.source || '-',
warningTime: item.startTime || "-", warningTime: item.startTime || '-',
endTime: item.endTime || "-", endTime: item.endTime || '-',
impactCount: item.affectedCount || 0, impactCount: item.affectedCount || 0,
})); }));
} else { } else {
@ -287,7 +262,7 @@ const fetchWarningData = async () => {
total.value = 0; total.value = 0;
} }
} catch (error) { } catch (error) {
console.error("获取预警数据失败:", error); console.error('获取预警数据失败:', error);
tableData.value = []; tableData.value = [];
total.value = 0; total.value = 0;
} finally { } finally {
@ -296,55 +271,55 @@ const fetchWarningData = async () => {
}; };
// //
const formatDateTime = (date) => { const formatDateTime = date => {
if (!date) return ""; if (!date) return '';
const d = new Date(date); const d = new Date(date);
const year = d.getFullYear(); const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, "0"); const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, "0"); const day = String(d.getDate()).padStart(2, '0');
const hours = String(d.getHours()).padStart(2, "0"); const hours = String(d.getHours()).padStart(2, '0');
const minutes = String(d.getMinutes()).padStart(2, "0"); const minutes = String(d.getMinutes()).padStart(2, '0');
const seconds = String(d.getSeconds()).padStart(2, "0"); const seconds = String(d.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}; };
// //
const getWarningClass = (level) => { const getWarningClass = level => {
const classMap = { const classMap = {
红色预警: "warning-red", 红色预警: 'warning-red',
橙色预警: "warning-orange", 橙色预警: 'warning-orange',
黄色预警: "warning-yellow", 黄色预警: 'warning-yellow',
蓝色预警: "warning-blue", 蓝色预警: 'warning-blue',
}; };
return classMap[level] || ""; return classMap[level] || '';
}; };
// //
const handleClose = () => { const handleClose = () => {
emit("update:visible", false); emit('update:visible', false);
emit("close"); emit('close');
}; };
// //
const handleImpactClick = (item) => { const handleImpactClick = item => {
emit("impactClick", item); emit('impactClick', item);
emit("impactClickItem", { emit('impactClickItem', {
...item, ...item,
dateRange: filterForm.value.dateRange || [], dateRange: filterForm.value.dateRange || [],
riskLeve: filterForm.value.riskLeve || "", riskLeve: filterForm.value.riskLeve || '',
}); });
}; };
// //
const handleSizeChange = (val) => { const handleSizeChange = val => {
pageSize.value = val; pageSize.value = val;
console.log("分页大小变化:", val); console.log('分页大小变化:', val);
currentPage.value = 1; currentPage.value = 1;
fetchWarningData(); fetchWarningData();
}; };
const handleCurrentChange = (val) => { const handleCurrentChange = val => {
console.log("当前页码变化:", val); console.log('当前页码变化:', val);
currentPage.value = val; currentPage.value = val;
fetchWarningData(); fetchWarningData();
}; };
@ -359,23 +334,23 @@ const initDialogData = () => {
// warningitem // warningitem
if (props.warningitem && Object.keys(props.warningitem).length > 0) { if (props.warningitem && Object.keys(props.warningitem).length > 0) {
filterForm.value = { filterForm.value = {
riskLeve: props.warningitem.label || "", riskLeve: props.warningitem.label || '',
countyName: props.warningitem.countyName || "", countyName: props.warningitem.countyName || '',
isEnded: "", isEnded: '',
dateRange: dateRange.value, dateRange: dateRange.value,
}; };
} else { } else {
filterForm.value = { filterForm.value = {
riskLeve: "", riskLeve: '',
countyName: "", countyName: '',
isEnded: "", isEnded: '',
dateRange: dateRange.value, dateRange: dateRange.value,
}; };
} }
// //
currentPage.value = 1; currentPage.value = 1;
console.log("初始化筛选条件:", filterForm.value); console.log('初始化筛选条件:', filterForm.value);
fetchWarningData(); fetchWarningData();
}; };
@ -387,9 +362,9 @@ const resetData = () => {
currentPage.value = 1; currentPage.value = 1;
// //
filterForm.value = { filterForm.value = {
riskLeve: "", riskLeve: '',
countyName: "", countyName: '',
isEnded: "", isEnded: '',
dateRange: [], dateRange: [],
}; };
// //
@ -399,7 +374,7 @@ const resetData = () => {
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
(newVal) => { newVal => {
if (newVal) { if (newVal) {
// //
initDialogData(); initDialogData();
@ -407,38 +382,38 @@ watch(
// //
resetData(); resetData();
} }
}, }
); );
// //
watch( watch(
() => filterForm.value, () => filterForm.value,
(newVal, oldVal) => { (newVal, oldVal) => {
console.log("筛选条件变化:===========", newVal, oldVal); console.log('筛选条件变化:===========', newVal, oldVal);
// //
if (oldVal && Object.keys(oldVal).length > 0) { if (oldVal && Object.keys(oldVal).length > 0) {
currentPage.value = 1; currentPage.value = 1;
fetchWarningData(); fetchWarningData();
} }
}, },
{ deep: true }, { deep: true }
); );
// dateRange filterForm.dateRange // dateRange filterForm.dateRange
watch( watch(
() => dateRange.value, () => dateRange.value,
(newVal) => { newVal => {
filterForm.value.dateRange = newVal; filterForm.value.dateRange = newVal;
}, },
{ deep: true }, { deep: true }
); );
watch( watch(
() => filterForm.value.dateRange, () => filterForm.value.dateRange,
(newVal) => { newVal => {
dateRange.value = newVal; dateRange.value = newVal;
}, },
{ deep: true }, { deep: true }
); );
</script> </script>

View File

@ -8,13 +8,15 @@
:class="{ active: activeIndex === index }" :class="{ active: activeIndex === index }"
@click="handleClick(item, index)" @click="handleClick(item, index)"
> >
<div class="nav-icon-box" :ref="(el) => setNavIconRef(el, index)"> <div class="nav-icon-box" :ref="el => setNavIconRef(el, index)">
<!-- <i :class="item.icon"></i> --> <!-- <i :class="item.icon"></i> -->
<img :src="activeIndex === index ? item.icon1 : item.icon" alt="" /> <img :src="activeIndex === index ? item.icon1 : item.icon" alt="" />
</div> </div>
<div class="nav-label">{{ item.label }}</div> <div class="nav-label">{{ item.label }}</div>
</div> </div>
</div> </div>
<!-- 气象预警监测表格组件 -->
<WeatherWarningTable ref="weatherWarningTableRef" @clearFilters="handleClearFilters" />
<!-- 涉灾隐患点图片弹窗 --> <!-- 涉灾隐患点图片弹窗 -->
<div v-if="showHazardPopup" class="hazard-popup" :style="popupStyle"> <div v-if="showHazardPopup" class="hazard-popup" :style="popupStyle">
<div class="hazard-popup-content"> <div class="hazard-popup-content">
@ -30,11 +32,7 @@
</div> </div>
</div> </div>
<!-- 路段图片弹窗 --> <!-- 路段图片弹窗 -->
<div <div v-if="showRoadPopup" class="hazard-popup road-popup" :style="roadPopupStyle">
v-if="showRoadPopup"
class="hazard-popup road-popup"
:style="roadPopupStyle"
>
<div class="hazard-popup-content"> <div class="hazard-popup-content">
<div <div
v-for="(item, index) in roadItems" v-for="(item, index) in roadItems"
@ -47,172 +45,98 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 气象预警监测表格 -->
<div class="weather-warning-wrapper">
<div class="weather-warning-panel">
<img
class="clear-icon"
src="../../assets/RiskWarning_img/清除icon@2x.png"
alt=""
@click="clearFilters"
/>
<div class="panel-header">
<div class="header-title">气象预警监测</div>
<div class="filter-tags">
<label class="tag">
<input type="checkbox" v-model="filters.red" />
<span class="">红色预警</span>
</label>
<label class="tag">
<input type="checkbox" v-model="filters.blue" />
<span class="">蓝色预警</span>
</label>
<label class="tag">
<input type="checkbox" v-model="filters.orange" />
<span class="">橙色预警</span>
</label>
<label class="tag">
<input type="checkbox" v-model="filters.yellow" />
<span class="">黄色预警</span>
</label>
</div>
</div>
<div class="table-container">
<el-table
:data="filteredData"
height="100%"
style="width: 100%; background: transparent"
:header-cell-style="headerCellStyle"
:cell-style="cellStyle"
:row-class-name="rowClassName"
>
<el-table-column prop="time" label="预警时间" min-width="vw(140)" />
<el-table-column
prop="type"
label="类型"
min-width="vw(80)"
align="center"
/>
<el-table-column
label="预警等级"
min-width="vw(100)"
align="center"
>
<template #default="{ row }">
<div class="warning-level">
<img
:src="
row.levelClass === 'red'
? redIcon
: row.levelClass === 'blue'
? blueIcon
: row.levelClass === 'orange'
? orangeIcon
: yellowIcon
"
alt=""
/>
<span class="ml_10">{{ row.level }}</span>
</div>
</template>
</el-table-column>
<el-table-column
prop="district"
label="预警区县"
min-width="vw(80)"
/>
</el-table>
</div>
</div>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue"; import { ref, computed, nextTick } from 'vue';
import { ElTable } from "element-plus"; import WeatherWarningTable from './component/WeatherWarningTable.vue';
import orangeIcon from "../../assets/RiskWarning_img/橙色@2x.png";
import yellowIcon from "../../assets/RiskWarning_img/黄色@2x.png";
import redIcon from "../../assets/RiskWarning_img//红色@2x.png";
import blueIcon from "../../assets/RiskWarning_img/蓝色@2x.png";
import warningIconIcon from "../../assets/RiskWarning_img/风险预警icon@2x.png"; import warningIconIcon from '../../assets/RiskWarning_img/风险预警icon@2x.png';
import tunnelIconIcon from "../../assets/RiskWarning_img/隧道icon@2x.png"; import tunnelIconIcon from '../../assets/RiskWarning_img/隧道icon@2x.png';
import slopeIconIcon from "../../assets/RiskWarning_img/边坡icon@2x.png"; import slopeIconIcon from '../../assets/RiskWarning_img/边坡icon@2x.png';
import bridgeIconIcon 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 roadIconIcon from '../../assets/RiskWarning_img/线路路段icon@2x.png';
import teamIconIcon 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 hazardIconIconIcon from '../../assets/RiskWarning_img/隐患点icon@2x.png';
import warningIconIcon1 from "../../assets/RiskWarning_img/风险预警icon1@2x.png"; import warningIconIcon1 from '../../assets/RiskWarning_img/风险预警icon1@2x.png';
import tunnelIconIcon1 from "../../assets/RiskWarning_img/隧道icon1@2x.png"; import tunnelIconIcon1 from '../../assets/RiskWarning_img/隧道icon1@2x.png';
import slopeIconIcon1 from "../../assets/RiskWarning_img/边坡icon1@2x.png"; import slopeIconIcon1 from '../../assets/RiskWarning_img/边坡icon1@2x.png';
import bridgeIconIcon1 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 roadIconIcon1 from '../../assets/RiskWarning_img/线路路段icon1@2x.png';
import teamIconIcon1 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 hazardIconIcon from '../../assets/RiskWarning_img/隐患点icon1@2x.png';
import hazardIconIcon1 from "../../assets/MaMap_img/一般路内隐患点@2x.png"; import hazardIconIcon1 from '../../assets/MaMap_img/一般路内隐患点@2x.png';
import hazardIconIcon2 from "../../assets/MaMap_img/一般路外隐患点@2x.png"; import hazardIconIcon2 from '../../assets/MaMap_img/一般路外隐患点@2x.png';
import hazardIconIcon3 from "../../assets/MaMap_img/较大路内隐患点@2x.png"; import hazardIconIcon3 from '../../assets/MaMap_img/较大路内隐患点@2x.png';
import hazardIconIcon4 from "../../assets/MaMap_img/较大路外隐患点@2x.png"; import hazardIconIcon4 from '../../assets/MaMap_img/较大路外隐患点@2x.png';
import hazardIconIcon5 from "../../assets/MaMap_img/重大路内隐患点@2x.png"; import hazardIconIcon5 from '../../assets/MaMap_img/重大路内隐患点@2x.png';
import hazardIconIcon6 from "../../assets/MaMap_img/重大路外隐患点@2x.png"; import hazardIconIcon6 from '../../assets/MaMap_img/重大路外隐患点@2x.png';
import tunnelLineIcon3 from "../../assets/MaMap_img/高风险路段@2x.png"; import tunnelLineIcon3 from '../../assets/MaMap_img/高风险路段@2x.png';
import tunnelLineIcon2 from "../../assets/MaMap_img/较高风险路段@2x.png"; import tunnelLineIcon2 from '../../assets/MaMap_img/较高风险路段@2x.png';
import tunnelLineIcon1 from "../../assets/MaMap_img/中风险路段@2x.png"; import tunnelLineIcon1 from '../../assets/MaMap_img/中风险路段@2x.png';
import tunnelLineIcon from "../../assets/MaMap_img/线路icon定位@2x.png"; import tunnelLineIcon from '../../assets/MaMap_img/线路icon定位@2x.png';
const emit = defineEmits([
'changeActiveIndex',
'clearMapMarkers',
'hazardItemClick',
'roadItemClick',
'showHazardPopupfn',
]);
const activeIndex = ref(-1); const activeIndex = ref(-1);
const menuItems = [ const menuItems = [
{ {
label: "涉灾隐患点", label: '涉灾隐患点',
icon: "icon-hazard", icon: 'icon-hazard',
iconClass: "hazard", iconClass: 'hazard',
icon: hazardIconIconIcon, icon: hazardIconIconIcon,
icon1: hazardIconIcon, icon1: hazardIconIcon,
}, },
{ {
label: "路段", label: '路段',
icon: "icon-road", icon: 'icon-road',
iconClass: "road", iconClass: 'road',
icon: roadIconIcon, icon: roadIconIcon,
icon1: roadIconIcon1, icon1: roadIconIcon1,
}, },
{ {
label: "项目", label: '项目',
icon: "icon-warning", icon: 'icon-warning',
iconClass: "warning", iconClass: 'warning',
icon: warningIconIcon, icon: warningIconIcon,
icon1: warningIconIcon1, icon1: warningIconIcon1,
}, },
{ {
label: "隧道", label: '隧道',
icon: "icon-tunnel", icon: 'icon-tunnel',
iconClass: "tunnel", iconClass: 'tunnel',
icon: tunnelIconIcon, icon: tunnelIconIcon,
icon1: tunnelIconIcon1, icon1: tunnelIconIcon1,
}, },
{ {
label: "边坡", label: '边坡',
icon: "icon-slope", icon: 'icon-slope',
iconClass: "slope", iconClass: 'slope',
icon: slopeIconIcon, icon: slopeIconIcon,
icon1: slopeIconIcon1, icon1: slopeIconIcon1,
}, },
{ {
label: "桥梁", label: '桥梁',
icon: "icon-bridge", icon: 'icon-bridge',
iconClass: "bridge", iconClass: 'bridge',
icon: bridgeIconIcon, icon: bridgeIconIcon,
icon1: bridgeIconIcon1, icon1: bridgeIconIcon1,
}, },
{ {
label: "队伍", label: '队伍',
icon: "icon-team", icon: 'icon-team',
iconClass: "team", iconClass: 'team',
icon: teamIconIcon, icon: teamIconIcon,
icon1: teamIconIcon1, icon1: teamIconIcon1,
}, },
@ -225,12 +149,12 @@ const navIconRefs = ref([]);
// //
const hazardItems = ref([ const hazardItems = ref([
{ icon: hazardIconIcon5, label: "重大路内隐患点" }, { icon: hazardIconIcon5, label: '重大路内隐患点', isWithinRedLine: '是' },
{ icon: hazardIconIcon6, label: "重大路外隐患点" }, { icon: hazardIconIcon6, label: '重大路外隐患点', isWithinRedLine: '否' },
{ icon: hazardIconIcon3, label: "较大路内隐患点" }, { icon: hazardIconIcon3, label: '较大路内隐患点', isWithinRedLine: '是' },
{ icon: hazardIconIcon4, label: "较大路外隐患点" }, { icon: hazardIconIcon4, label: '较大路外隐患点', isWithinRedLine: '否' },
{ icon: hazardIconIcon1, label: "一般路内隐患点" }, { icon: hazardIconIcon1, label: '一般路内隐患点', isWithinRedLine: '是' },
{ icon: hazardIconIcon2, label: "一般路外隐患点" }, { icon: hazardIconIcon2, label: '一般路外隐患点', isWithinRedLine: '否' },
]); ]);
// //
@ -239,10 +163,10 @@ const roadPopupStyle = ref({});
// //
const roadItems = ref([ const roadItems = ref([
{ icon: tunnelLineIcon3, label: "高风险路段" }, { icon: tunnelLineIcon3, label: '高风险路段' },
{ icon: tunnelLineIcon2, label: "较高风险路段" }, { icon: tunnelLineIcon2, label: '较高风险路段' },
{ icon: tunnelLineIcon1, label: "中风险路段" }, { icon: tunnelLineIcon1, label: '中风险路段' },
{ icon: tunnelLineIcon, label: "低风险路段" }, { icon: tunnelLineIcon, label: '低风险路段' },
]); ]);
// nav-icon-boxref // nav-icon-boxref
@ -251,94 +175,12 @@ const setNavIconRef = (el, index) => {
navIconRefs.value[index] = el; navIconRefs.value[index] = el;
} }
}; };
const weatherWarningTableRef = ref(null);
//
const filters = ref({
red: false,
blue: false,
orange: false,
yellow: false,
});
//
const warningData = ref([
{
time: "2025-11-18 09:24:81",
type: "暴雨",
level: "蓝色预警",
levelClass: "blue",
district: "合川区",
},
{
time: "2025-11-12 09:24:81",
type: "冰雪",
level: "红色预警",
levelClass: "red",
district: "万州区",
},
{
time: "2025-11-12 09:24:81",
type: "大雾",
level: "橙色预警",
levelClass: "orange",
district: "涪陵区",
},
{
time: "2025-11-12 09:24:81",
type: "大风",
level: "黄色预警",
levelClass: "yellow",
district: "城口县",
},
]);
//
const filteredData = computed(() => {
const hasFilter =
filters.value.red ||
filters.value.blue ||
filters.value.orange ||
filters.value.yellow;
if (!hasFilter) return warningData.value;
return warningData.value.filter((item) => {
if (filters.value.red && item.levelClass === "red") return true;
if (filters.value.blue && item.levelClass === "blue") return true;
if (filters.value.orange && item.levelClass === "orange") return true;
if (filters.value.yellow && item.levelClass === "yellow") return true;
return false;
});
});
// el-table
const headerCellStyle = () => ({
background: "#17466F",
color: "rgba(255, 255, 255, 0.6)",
fontWeight: "normal",
borderBottom: "1px solid rgba(64, 169, 255, 0.2)",
padding: "5px 20px",
});
const cellStyle = () => ({
background: "#142E49",
color: "rgba(255, 255, 255, 0.9)",
borderBottom: "1px solid rgba(64, 169, 255, 0.1)",
padding: "5px 5px",
});
const rowClassName = ({ rowIndex }) => {
return rowIndex % 2 === 0 ? "even-row" : "odd-row";
};
const emit = defineEmits([
"changeActiveIndex",
"clearMapMarkers",
"hazardItemClick",
"roadItemClick",
]);
// //
const handleClick = (item, index) => { const handleClick = (item, index) => {
// //
if (item.label === "涉灾隐患点") { if (item.label === '涉灾隐患点') {
// //
showHazardPopup.value = !showHazardPopup.value; showHazardPopup.value = !showHazardPopup.value;
if (showHazardPopup.value) { if (showHazardPopup.value) {
@ -350,14 +192,14 @@ const handleClick = (item, index) => {
if (navIconBox) { if (navIconBox) {
const rect = navIconBox.getBoundingClientRect(); const rect = navIconBox.getBoundingClientRect();
popupStyle.value = { popupStyle.value = {
position: "fixed", position: 'fixed',
left: rect.right + 10 + "px", left: rect.right + 10 + 'px',
top: rect.top + "px", top: rect.top + 'px',
zIndex: 2, zIndex: 2,
}; };
} }
} }
} else if (item.label === "路段") { } else if (item.label === '路段') {
// //
// //
@ -372,165 +214,59 @@ const handleClick = (item, index) => {
if (navIconBox) { if (navIconBox) {
const rect = navIconBox.getBoundingClientRect(); const rect = navIconBox.getBoundingClientRect();
roadPopupStyle.value = { roadPopupStyle.value = {
position: "fixed", position: 'fixed',
left: rect.right + 10 + "px", left: rect.right + 10 + 'px',
top: rect.top + "px", top: rect.top + 'px',
zIndex: 3, zIndex: 2,
}; };
} }
} }
emit('showHazardPopupfn', false);
} else { } else {
showHazardPopup.value = false; showHazardPopup.value = false;
showRoadPopup.value = false; showRoadPopup.value = false;
emit('showHazardPopupfn', false);
//
emit('hideRoadStats');
} }
activeIndex.value = index; activeIndex.value = index;
emit("changeActiveIndex", { emit('changeActiveIndex', {
...item, ...item,
}); });
}; };
// //
const handleHazardItemClick = (item) => { const handleHazardItemClick = item => {
console.log("点击隐患点:", item); console.log('点击隐患点:', item);
emit("hazardItemClick", item); emit('hazardItemClick', item);
// //
// showHazardPopup.value = false; // showHazardPopup.value = false;
emit('showHazardPopupfn', true);
}; };
const roadItem = ref({}); const roadItem = ref({});
// //
const handleRoadItemClick = (item) => { const handleRoadItemClick = item => {
console.log("点击路段:", item); console.log('点击路段:', item);
roadItem.value = item; roadItem.value = item;
emit("roadItemClick", item); emit('roadItemClick', item);
// //
// showRoadPopup.value = false; // showRoadPopup.value = false;
}; };
// //
const clearFilters = () => { const handleClearFilters = () => {
filters.value = { console.log('清除筛选条件');
red: false, //
blue: false,
orange: false,
yellow: false,
};
activeIndex.value = -1; activeIndex.value = -1;
//
showHazardPopup.value = false;
showRoadPopup.value = false;
// //
emit("clearMapMarkers"); emit('clearMapMarkers');
emit('showHazardPopupfn', false);
}; };
//
const tableRef = ref(null);
const isScrolling = ref(true);
const scrollTimer = ref(null);
const scrollSpeed = 50; //
const scrollStep = 1; //
//
const hasFilter = computed(() => {
return (
filters.value.red ||
filters.value.blue ||
filters.value.orange ||
filters.value.yellow
);
});
//
const startAutoScroll = () => {
if (scrollTimer.value) {
clearInterval(scrollTimer.value);
}
if (!isScrolling.value || hasFilter.value) return;
const tableBody = document.querySelector(
".weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap",
);
if (!tableBody) return;
scrollTimer.value = setInterval(() => {
if (tableBody) {
tableBody.scrollTop += scrollStep;
// 使 >=
const maxScroll = tableBody.scrollHeight - tableBody.clientHeight;
if (tableBody.scrollTop >= maxScroll - 2) {
tableBody.scrollTop = 0;
}
}
}, scrollSpeed);
};
//
const stopAutoScroll = () => {
if (scrollTimer.value) {
clearInterval(scrollTimer.value);
scrollTimer.value = null;
}
};
//
const resetScrollToTop = () => {
const tableBody = document.querySelector(
".weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap",
);
if (tableBody) {
tableBody.scrollTop = 0;
}
};
//
const handleMouseEnter = () => {
stopAutoScroll();
};
//
const handleMouseLeave = () => {
if (!hasFilter.value) {
isScrolling.value = true;
startAutoScroll();
}
};
//
watch(hasFilter, (newVal) => {
if (newVal) {
//
stopAutoScroll();
resetScrollToTop();
} else {
//
isScrolling.value = true;
nextTick(() => {
startAutoScroll();
});
}
});
onMounted(() => {
nextTick(() => {
startAutoScroll();
//
const tableContainer = document.querySelector(
".weather-warning-panel .table-container",
);
if (tableContainer) {
tableContainer.addEventListener("mouseenter", handleMouseEnter);
tableContainer.addEventListener("mouseleave", handleMouseLeave);
}
});
});
onUnmounted(() => {
stopAutoScroll();
const tableContainer = document.querySelector(
".weather-warning-panel .table-container",
);
if (tableContainer) {
tableContainer.removeEventListener("mouseenter", handleMouseEnter);
tableContainer.removeEventListener("mouseleave", handleMouseLeave);
}
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -653,27 +389,27 @@ onUnmounted(() => {
// 使 emoji // 使 emoji
&.warning::before { &.warning::before {
content: "📍"; content: '📍';
font-size: vw(24); font-size: vw(24);
} }
&.tunnel::before { &.tunnel::before {
content: "🚇"; content: '🚇';
font-size: vw(24); font-size: vw(24);
} }
&.slope::before { &.slope::before {
content: "⛰️"; content: '⛰️';
font-size: vw(24); font-size: vw(24);
} }
&.bridge::before { &.bridge::before {
content: "🌉"; content: '🌉';
font-size: vw(24); font-size: vw(24);
} }
&.road::before { &.road::before {
content: "🛣️"; content: '🛣️';
font-size: vw(24); font-size: vw(24);
} }
} }
@ -688,198 +424,4 @@ onUnmounted(() => {
} }
} }
} }
//
.weather-warning-wrapper {
display: flex;
flex-direction: column;
justify-content: flex-end;
width: 92%;
height: 50%;
position: absolute;
z-index: 2;
right: 0px;
bottom: 0px;
}
//
.weather-warning-panel {
// border-radius: vw(8);
display: flex;
flex-direction: column;
height: 100%;
.clear-icon {
position: absolute;
top: vw(-50);
right: 0px;
width: vw(40) !important;
height: vw(40) !important;
min-width: vw(28);
min-height: vw(28);
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
background-image: url("../../assets/RiskWarning_img/二级标题栏bg1@2x.png");
background-size: 100% 100%;
background-position: left top;
padding: vw(15);
.header-title {
font-size: vw(18);
font-weight: 500;
color: #fff;
position: relative;
}
.filter-tags {
display: flex;
gap: vw(15);
.tag {
display: flex;
align-items: center;
gap: vw(5);
cursor: pointer;
input {
width: vw(14);
height: vw(14);
min-width: vw(12);
min-height: vw(12);
accent-color: #40a9ff;
}
span {
font-size: vw(14);
color: rgba(255, 255, 255, 0.8);
&.tag-red {
color: #ff4d4f;
}
&.tag-blue {
color: #40a9ff;
}
&.tag-orange {
color: #ff7a45;
}
&.tag-yellow {
color: #ffc53d;
}
}
}
}
}
.table-container {
background: rgb(20, 46, 74, 0.95);
flex: 1;
overflow: hidden;
:deep(.el-table__body-wrapper) {
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
}
// el-table
:deep(.el-table) {
background: transparent;
&::before {
display: none;
}
.el-table__inner-wrapper {
background: transparent;
}
.el-table__inner-wrapper:before {
width: 0%;
}
.el-table__header-wrapper {
background: transparent;
th.el-table__cell {
background: transparent;
font-size: vw(14);
color: rgba(255, 255, 255, 0.6);
padding: vw(10) vw(8);
}
}
.el-table__body-wrapper {
background: transparent;
td.el-table__cell {
background: transparent;
font-size: vw(14);
color: rgba(255, 255, 255, 0.9);
padding: vw(5) vw(5);
}
&::-webkit-scrollbar {
display: none !important;
}
}
tr {
background: transparent;
&:hover {
background: rgba(64, 169, 255, 0.05) !important;
}
}
}
.warning-level {
display: flex;
align-items: center;
justify-content: center;
img {
width: vw(15);
height: vw(15);
min-width: vw(10);
min-height: vw(10);
}
// .level-icon {
// width: 0;
// height: 0;
// border-left: 6px solid transparent;
// border-right: 6px solid transparent;
// border-bottom: 10px solid currentColor;
// }
&.red {
color: #ff4d4f;
background: rgba(255, 77, 79, 0.1);
}
&.blue {
color: #40a9ff;
background: rgba(64, 169, 255, 0.1);
}
&.orange {
color: #ff7a45;
background: rgba(255, 122, 69, 0.1);
}
&.yellow {
color: #ffc53d;
background: rgba(255, 197, 61, 0.1);
}
}
}
</style> </style>

View File

@ -0,0 +1,448 @@
<template>
<!-- 气象预警监测表格 -->
<div class="weather-warning-wrapper">
<div class="weather-warning-panel">
<img
class="clear-icon"
src="../../../assets/RiskWarning_img/清除icon@2x.png"
alt=""
@click="clearFilters"
/>
<div class="panel-header">
<div class="header-title">气象预警监测</div>
<div class="filter-tags">
<label class="tag">
<input type="checkbox" v-model="filters.red" />
<span class="">红色预警</span>
</label>
<label class="tag">
<input type="checkbox" v-model="filters.blue" />
<span class="">蓝色预警</span>
</label>
<label class="tag">
<input type="checkbox" v-model="filters.orange" />
<span class="">橙色预警</span>
</label>
<label class="tag">
<input type="checkbox" v-model="filters.yellow" />
<span class="">黄色预警</span>
</label>
</div>
</div>
<div class="table-container">
<el-table
v-loading="loading"
element-loading-text="加载中..."
element-loading-background="#1A3E5E"
:data="filteredData"
height="100%"
style="width: 100%; background: transparent"
:header-cell-style="headerCellStyle"
:cell-style="cellStyle"
:row-class-name="rowClassName"
>
<el-table-column prop="time" label="预警时间" min-width="vw(140)" />
<el-table-column prop="type" label="类型" min-width="vw(80)" align="center" />
<el-table-column label="预警等级" min-width="vw(100)" align="center">
<template #default="{ row }">
<div class="warning-level">
<img
:src="
row.levelClass === 'red'
? redIcon
: row.levelClass === 'blue'
? blueIcon
: row.levelClass === 'orange'
? orangeIcon
: yellowIcon
"
alt=""
/>
<span class="ml_10">{{ row.level }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="district" label="预警区县" min-width="vw(80)" />
</el-table>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { request } from '@/utils/request';
import orangeIcon from '../../../assets/RiskWarning_img/橙色@2x.png';
import yellowIcon from '../../../assets/RiskWarning_img/黄色@2x.png';
import redIcon from '../../../assets/RiskWarning_img//红色@2x.png';
import blueIcon from '../../../assets/RiskWarning_img/蓝色@2x.png';
const emit = defineEmits(['clearFilters']);
//
const filters = ref({
red: false,
blue: false,
orange: false,
yellow: false,
});
//
const warningData = ref([]);
//
const tableRef = ref(null);
const isScrolling = ref(true);
const scrollTimer = ref(null);
const scrollSpeed = 50; //
const scrollStep = 1; //
//
const hasFilter = computed(() => {
return filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow;
});
//
const startAutoScroll = () => {
if (scrollTimer.value) {
clearInterval(scrollTimer.value);
}
if (!isScrolling.value || hasFilter.value) return;
const tableBody = document.querySelector(
'.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap'
);
if (!tableBody) return;
scrollTimer.value = setInterval(() => {
if (tableBody) {
tableBody.scrollTop += scrollStep;
// 使 >=
const maxScroll = tableBody.scrollHeight - tableBody.clientHeight;
if (tableBody.scrollTop >= maxScroll - 2) {
tableBody.scrollTop = 0;
}
}
}, scrollSpeed);
};
//
const stopAutoScroll = () => {
if (scrollTimer.value) {
clearInterval(scrollTimer.value);
scrollTimer.value = null;
}
};
//
const resetScrollToTop = () => {
const tableBody = document.querySelector(
'.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap'
);
if (tableBody) {
tableBody.scrollTop = 0;
}
};
//
const handleMouseEnter = () => {
stopAutoScroll();
};
//
const handleMouseLeave = () => {
if (!hasFilter.value) {
isScrolling.value = true;
startAutoScroll();
}
};
//
watch(hasFilter, newVal => {
if (newVal) {
//
stopAutoScroll();
resetScrollToTop();
} else {
//
isScrolling.value = true;
nextTick(() => {
startAutoScroll();
});
}
});
//
const loading = ref(false);
//
const fetchWeatherWarningData = async () => {
loading.value = true;
try {
const res = await request({
url: '/snow-ops-platform/weather-warning/affected-count/_by_weather',
method: 'GET',
params: {
offset: 0,
limit: 100000,
},
});
console.log('气象预警数据:', res);
if (res.code === '00000' && res.data) {
//
warningData.value = res.data.data.map(item => ({
time: item.startTime || '',
type: item.weatherType || '',
level: item.riskLeve || '',
levelClass: getLevelClass(item.riskLeve || ''),
district: item.countyName || '',
}));
} else {
warningData.value = [];
}
loading.value = false;
nextTick(() => {
startAutoScroll();
//
const tableContainer = document.querySelector('.weather-warning-panel .table-container');
if (tableContainer) {
tableContainer.addEventListener('mouseenter', handleMouseEnter);
tableContainer.addEventListener('mouseleave', handleMouseLeave);
}
});
} catch (error) {
console.error('获取气象预警数据失败:', error);
warningData.value = [];
loading.value = false;
}
};
// class
const getLevelClass = level => {
if (level.includes('红')) return 'red';
if (level.includes('橙')) return 'orange';
if (level.includes('黄')) return 'yellow';
if (level.includes('蓝')) return 'blue';
return '';
};
//
onMounted(() => {
//
console.log('获取气象预警数据');
fetchWeatherWarningData();
});
onUnmounted(() => {
stopAutoScroll();
const tableContainer = document.querySelector('.weather-warning-panel .table-container');
if (tableContainer) {
tableContainer.removeEventListener('mouseenter', handleMouseEnter);
tableContainer.removeEventListener('mouseleave', handleMouseLeave);
}
});
//
const filteredData = computed(() => {
const hasFilter =
filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow;
if (!hasFilter) return warningData.value;
return warningData.value.filter(item => {
if (filters.value.red && item.levelClass === 'red') return true;
if (filters.value.blue && item.levelClass === 'blue') return true;
if (filters.value.orange && item.levelClass === 'orange') return true;
if (filters.value.yellow && item.levelClass === 'yellow') return true;
return false;
});
});
// el-table
const headerCellStyle = () => ({
background: '#17466F',
color: 'rgba(255, 255, 255, 0.6)',
});
const cellStyle = () => ({
background: '#142E49',
color: 'rgba(255, 255, 255, 0.9)',
borderBottom: '1px solid rgba(64, 169, 255, 0.1)',
padding: '5px 5px',
});
const rowClassName = ({ rowIndex }) => {
return rowIndex % 2 === 0 ? 'even-row' : 'odd-row';
};
//
const clearFilters = () => {
console.log('清除筛选条件');
filters.value = {
red: false,
blue: false,
orange: false,
yellow: false,
};
//
emit('clearFilters');
};
//
const setWarningData = data => {
warningData.value = data;
};
defineExpose({
clearFilters,
setWarningData,
});
</script>
<style lang="scss" scoped>
@function vw($px) {
@return calc($px / 1920 * 100vw);
}
.weather-warning-wrapper {
position: fixed;
bottom: vw(0);
left: 52%;
transform: translateX(-50%);
z-index: 2;
}
.weather-warning-panel {
width: vw(900);
// background: url('../../../assets/RiskWarning_img/@2x.png') no-repeat center center;
// background-size: 100% 100%;
padding: vw(15);
position: relative;
.clear-icon {
position: absolute;
top: vw(-40);
right: vw(15);
width: vw(50);
height: vw(50);
cursor: pointer;
z-index: 10;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
background-image: url('../../../assets/RiskWarning_img/二级标题栏bg1@2x.png');
background-size: 100% 100%;
background-position: left top;
padding: vw(15);
.header-title {
font-size: vw(18);
font-weight: 500;
color: #fff;
}
.filter-tags {
display: flex;
gap: vw(10);
.tag {
display: flex;
align-items: center;
gap: vw(5);
cursor: pointer;
font-size: vw(14);
color: rgba(255, 255, 255, 0.8);
input[type='checkbox'] {
width: vw(14);
height: vw(14);
cursor: pointer;
}
}
}
}
.table-container {
height: vw(130);
overflow: hidden;
:deep(.el-table) {
background: transparent;
.el-table__header-wrapper {
th {
background: #17466f;
color: rgba(255, 255, 255, 0.6);
font-weight: normal;
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
}
}
.el-table__body-wrapper {
background: transparent;
tr {
background: transparent;
td {
background: #142e49;
color: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid rgba(64, 169, 255, 0.1);
}
&.even-row {
td {
background: #142e49;
}
}
&.odd-row {
td {
background: #1a3a5c;
}
}
&:hover {
td {
background: rgba(64, 169, 255, 0.2);
}
}
}
}
}
}
}
.warning-level {
display: flex;
align-items: center;
justify-content: center;
gap: vw(5);
img {
width: vw(20);
height: vw(20);
}
}
.ml_10 {
margin-left: vw(10);
}
:deep(.el-table--fit .el-table__inner-wrapper:before) {
width: 0%;
}
:deep(.el-scrollbar__wrap--hidden-default) {
background: #142e49;
}
:deep(.el-table .cell) {
text-align: center;
}
:deep(.el-table:not(.el-table--border) .el-table__cell) {
font-size: vw(14);
padding: 0;
}
:deep(.el-table .cell) {
font-size: vw(16);
}
</style>

View File

@ -1,32 +1,74 @@
// 弹窗组件统一数据配置 // 弹窗组件统一数据配置
import { ref } from 'vue';
import { request } from '@/utils/request';
// 行政区域选项 // 行政区域选项
export const regionOptions = [ export const regionOptions = ref([
{ label: "重庆市", value: "重庆市" }, // { label: "重庆市", value: "重庆市" },
{ label: "万州区", value: "万州区" }, // { label: "万州区", value: "万州区" },
{ label: "沙坪坝区", value: "沙坪坝区" }, // { label: "沙坪坝区", value: "沙坪坝区" },
{ label: "渝中区", value: "渝中区" }, // { label: "渝中区", value: "渝中区" },
{ label: "巫溪县", value: "巫溪县" }, // { label: "巫溪县", value: "巫溪县" },
{ label: "涪陵区", value: "涪陵区" }, // { label: "涪陵区", value: "涪陵区" },
{ label: "合川区", value: "合川区" }, // { label: "合川区", value: "合川区" },
{ label: "万盛区", value: "万盛区" }, // { label: "万盛区", value: "万盛区" },
{ label: "长寿区", value: "长寿区" }, // { label: "长寿区", value: "长寿区" },
{ label: "城口区", value: "城口区" }, // { label: "城口区", value: "城口区" },
{ label: "柏梓镇", value: "柏梓镇" }, // { label: "柏梓镇", value: "柏梓镇" },
{ label: "江北区", value: "江北区" }, // { label: "江北区", value: "江北区" },
]; ]);
// 类型选项 // 获取行政区域选项
export const typeOptions = [ export const fetchDistrictOptions = async () => {
{ label: "边坡坍塌", value: "边坡坍塌" }, try {
{ label: "路面塌陷", value: "路面塌陷" }, const res = await request({
{ label: "桥梁损坏", value: "桥梁损坏" }, url: '/snow-ops-platform/sm-event/dashboard/district-options',
{ label: "隧道事故", value: "隧道事故" }, method: 'GET',
{ label: "交通主管部门", value: "交通主管部门" }, });
{ label: "公路机构", value: "公路机构" }, if (res && res.code === '00000' && Array.isArray(res.data)) {
{ label: "养护站", value: "养护站" }, // 将接口返回的数据转换为选项格式
{ label: "护路员", value: "护路员" }, const options = res.data.map(item => ({
]; label: item.qxmc,
value: item.xzdm,
}));
// 保留"全部"选项,并添加接口返回的数据
regionOptions.value = [
{ label: "全部", value: "" },
...options,
];
return options;
}
} catch (error) {
console.error('获取行政区域选项失败:', error);
}
return regionOptions.value;
};
// 路况类型选项默认数据会被API数据替换
export const typeOptions = ref([
]);
// 获取路况类型选项
export const fetchRoadConditionOptions = async () => {
try {
const res = await request({
url: '/snow-ops-platform/sm-event/dashboard/road-condition-options',
method: 'GET',
});
if (res && res.code === '00000' && Array.isArray(res.data)) {
// 将接口返回的字符串数组转换为选项格式
const options = res.data.map(item => ({
label: item,
value: item,
}));
typeOptions.value = options;
return options;
}
} catch (error) {
console.error('获取路况类型选项失败:', error);
}
return typeOptions.value;
};
// 管控措施选项 // 管控措施选项
export const controlMeasureOptions = [ export const controlMeasureOptions = [
@ -84,15 +126,9 @@ export const isEndedOptions = [
]; ];
// 行政区域选项(带全部) // 行政区域选项(带全部)
export const regionOptionsWithAll = [ export const regionOptionsWithAll = ref([
{ label: "全部", value: "" }, ]);
{ label: "万州区", value: "wanzhou" },
{ label: "涪陵区", value: "fuling" },
{ label: "合川区", value: "hechuan" },
{ label: "万盛区", value: "wansheng" },
{ label: "长寿区", value: "changshou" },
{ label: "城口区", value: "chengkou" },
];
// 格式化日期时间为接口所需格式 // 格式化日期时间为接口所需格式
export const formatDateTime = (date) => { export const formatDateTime = (date) => {
@ -120,4 +156,6 @@ export default {
isEndedOptions, isEndedOptions,
regionOptionsWithAll, regionOptionsWithAll,
formatDateTime, formatDateTime,
}; fetchRoadConditionOptions,
fetchDistrictOptions,
};

View File

@ -1,17 +1,9 @@
<template> <template>
<div class="main"> <div class="main">
<div class="top_title"> <div class="top_title">
<img <img class="title_bg" src="../../assets/RiskWarning_img/一级标题栏bg@2x.png" alt="" />
class="title_bg"
src="../../assets/RiskWarning_img/一级标题栏bg@2x.png"
alt=""
/>
<div class="title_img_box"> <div class="title_img_box">
<img <img class="title_img1" src="../../assets/RiskWarning_img/位图@2x.png" alt="" />
class="title_img1"
src="../../assets/RiskWarning_img/位图@2x.png"
alt=""
/>
<img <img
class="title_img2" class="title_img2"
src="../../assets/RiskWarning_img/渝路畅行-风险预警一键响应@2x.png" src="../../assets/RiskWarning_img/渝路畅行-风险预警一键响应@2x.png"
@ -43,7 +35,7 @@
@openWarningSituation="openDialog('warningSituation')" @openWarningSituation="openDialog('warningSituation')"
@openResponseStatus="openDialog('responseStatus')" @openResponseStatus="openDialog('responseStatus')"
@openDispatchDistrict="openDialog('dispatchDistrict')" @openDispatchDistrict="openDialog('dispatchDistrict')"
@showCenterCard="(item) => handleCenterCardClick(item)" @showCenterCard="item => handleCenterCardClick(item)"
></left> ></left>
</div> </div>
<div class="right"> <div class="right">
@ -64,21 +56,33 @@
:dateRange="getdateRange" :dateRange="getdateRange"
:roadItem="roadItem" :roadItem="roadItem"
@districtClick="handleDistrictClick" @districtClick="handleDistrictClick"
@riskPointStatsChange="handleRiskPointStatsChange"
@update:roadvalArr="updateRoadvalArr"
@openHazardPointSituation="handleOpenHazardPointSituation"
/> />
</div> </div>
<!-- 地图遮罩层 --> <!-- 地图遮罩层 -->
<div class="map-mask" aria-hidden="true"></div> <div class="map-mask" aria-hidden="true"></div>
</div> </div>
<div class="bottom"> <div class="bottom">
<bottom <bottom
@roadItemClick="roadItemClick" @roadItemClick="roadItemClick"
@changeActiveIndex="changeActiveIndex" @changeActiveIndex="changeActiveIndex"
@hazardItemClick="handleHazardItemClick"
@clearMapMarkers="clearMapMarkers" @clearMapMarkers="clearMapMarkers"
@showHazardPopupfn="showHazardPopupfn"
@hideRoadStats="handleHideRoadStats"
></bottom> ></bottom>
</div> </div>
<top <top
class="top" class="top"
:roadItem="roadItem"
:showHazardPopup="showHazardPopup"
:riskPointStats="riskPointStats"
:roadvalArrtrue="roadvalArrtrue"
:showRoadStats="showRoadStats"
@openAIResult="openDialog('aiWarningResult')" @openAIResult="openDialog('aiWarningResult')"
@dateRangeChange="handleDateRangeChange" @dateRangeChange="handleDateRangeChange"
></top> ></top>
@ -164,6 +168,8 @@
<!-- 潼南基本信息对话框 --> <!-- 潼南基本信息对话框 -->
<tongnanInfoDialog <tongnanInfoDialog
v-model:visible="dialogVisible.tongnanInfo" v-model:visible="dialogVisible.tongnanInfo"
:allCountyData="allCountyData"
:tongnanInfoItemData="tongnanInfoItemData"
@close="closeDialog('tongnanInfo')" @close="closeDialog('tongnanInfo')"
@call="openDialog('confirm')" @call="openDialog('confirm')"
/> />
@ -173,7 +179,13 @@
v-model:visible="dialogVisible.tongnanResponsible" v-model:visible="dialogVisible.tongnanResponsible"
:allCountyData="allCountyData" :allCountyData="allCountyData"
@close="closeDialog('tongnanResponsible')" @close="closeDialog('tongnanResponsible')"
@detail="openDialog('tongnanInfo')" @detail="openDialog('tongnanProjectPerson')"
/>
<!-- 项目负责人对话框 -->
<tongnanProjectPersonDialog
v-model:visible="dialogVisible.tongnanProjectPerson"
:allCountyData="allCountyData"
@close="closeDialog('tongnanProjectPerson')"
/> />
<!-- 抢通情况对话框 --> <!-- 抢通情况对话框 -->
@ -208,6 +220,7 @@
:allCountyData="allCountyData" :allCountyData="allCountyData"
@close="closeDialog('tongnanTeam')" @close="closeDialog('tongnanTeam')"
@view="openDialog('tongnanInfo')" @view="openDialog('tongnanInfo')"
@itemdata="tongnanInfoItemDatafn()"
/> />
<!-- 预警情况对话框 --> <!-- 预警情况对话框 -->
@ -224,45 +237,54 @@
v-model:visible="dialogVisible.tunnelInfo" v-model:visible="dialogVisible.tunnelInfo"
@close="closeDialog('tunnelInfo')" @close="closeDialog('tunnelInfo')"
/> />
<hazardPointSituationDialog
v-model:visible="dialogVisible.hazardPointSituation"
:data="hazardPointData"
@close="closeDialog('hazardPointSituation')"
/>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, provide } from "vue"; import { ref, onMounted, provide } from 'vue';
import useMapStore from "@/map/stores/mapStore"; import useMapStore from '@/map/stores/mapStore';
import { useMapBase } from "../cockpit/composables/useMapBase"; import { useMapBase } from '../cockpit/composables/useMapBase';
import left from "./left.vue"; import left from './left.vue';
import right from "./right.vue"; import right from './right.vue';
import bottom from "./bottom.vue"; import bottom from './bottom.vue';
import top from "./top.vue"; import top from './top.vue';
import ChongqingMap from "./component/ChongqingMap.vue"; import ChongqingMap from './component/ChongqingMap.vue';
import { fetchRoadConditionOptions, fetchDistrictOptions } from './component/index.js';
// //
import responseSituationDiaLog from "./Dialog/responseSituationDiaLog.vue"; import responseSituationDiaLog from './Dialog/responseSituationDiaLog.vue';
import warningInfoDialog from "./Dialog/warningInfoDialog.vue"; import warningInfoDialog from './Dialog/warningInfoDialog.vue';
import eventDetailDialog from "./Dialog/eventDetailDialog.vue"; import eventDetailDialog from './Dialog/eventDetailDialog.vue';
import confirmDialog from "./Dialog/confirmDialog.vue"; import confirmDialog from './Dialog/confirmDialog.vue';
import riskPointDetailDialog from "./Dialog/riskPointDetailDialog.vue"; import riskPointDetailDialog from './Dialog/riskPointDetailDialog.vue';
import impactPointDialog from "./Dialog/impactPointDialog.vue"; import impactPointDialog from './Dialog/impactPointDialog.vue';
import impactPointDetailDialog from "./Dialog/impactPointDetailDialog.vue"; import impactPointDetailDialog from './Dialog/impactPointDetailDialog.vue';
import responsePointDetailDialog from "./Dialog/responsePointDetailDialog.vue"; import responsePointDetailDialog from './Dialog/responsePointDetailDialog.vue';
import responsePointInfoDialog from "./Dialog/responsePointInfoDialog.vue"; import responsePointInfoDialog from './Dialog/responsePointInfoDialog.vue';
import responseStatusDialog from "./Dialog/responseStatusDialog.vue"; import responseStatusDialog from './Dialog/responseStatusDialog.vue';
import aiWarningResultDialog from "./Dialog/aiWarningResultDialog.vue"; import aiWarningResultDialog from './Dialog/aiWarningResultDialog.vue';
import tongnanInfoDialog from "./Dialog/tongnanInfoDialog.vue"; import tongnanInfoDialog from './Dialog/tongnanInfoDialog.vue';
import tongnanResponsibleDialog from "./Dialog/tongnanResponsibleDialog.vue"; import tongnanResponsibleDialog from './Dialog/tongnanResponsibleDialog.vue';
import clearanceSituationDialog from "./Dialog/clearanceSituationDialog.vue"; import clearanceSituationDialog from './Dialog/clearanceSituationDialog.vue';
import controlSituationDialog from "./Dialog/controlSituationDialog.vue"; import controlSituationDialog from './Dialog/controlSituationDialog.vue';
import dispatchDetailDialog from "./Dialog/dispatchDetailDialog.vue"; import dispatchDetailDialog from './Dialog/dispatchDetailDialog.vue';
import dispatchDistrictDialog from "./Dialog/dispatchDistrictDialog.vue"; import dispatchDistrictDialog from './Dialog/dispatchDistrictDialog.vue';
import tongnanTeamDialog from "./Dialog/tongnanTeamDialog.vue"; import tongnanTeamDialog from './Dialog/tongnanTeamDialog.vue';
import warningSituationDialog from "./Dialog/warningSituationDialog.vue"; import warningSituationDialog from './Dialog/warningSituationDialog.vue';
import tunnelInfoDialog from "./Dialog/tunnelInfoDialog.vue"; import tunnelInfoDialog from './Dialog/tunnelInfoDialog.vue';
import centerInfoCard from "./Dialog/centerInfoCard.vue"; import centerInfoCard from './Dialog/centerInfoCard.vue';
import tongnanProjectPersonDialog from './Dialog/tongnanProjectPersonDialog.vue';
import hazardPointSituationDialog from './Dialog/hazardPointSituationDialog.vue';
import "./component/el-select.scss"; import './component/el-select.scss';
import "./component/date-picker-theme.scss"; import './component/date-picker-theme.scss';
// //
const dialogVisible = ref({ const dialogVisible = ref({
@ -286,15 +308,31 @@ const dialogVisible = ref({
tongnanTeam: false, tongnanTeam: false,
warningSituation: false, warningSituation: false,
tunnelInfo: false, tunnelInfo: false,
tongnanProjectPerson: false,
hazardPointSituation: false,
}); });
const activeitem = ref({}); const activeitem = ref({});
//
const riskPointStats = ref({
重大路外隐患点: 0,
重大路内隐患点: 0,
较大路外隐患点: 0,
较大路内隐患点: 0,
一般路内隐患点: 0,
一般路外隐患点: 0,
风险点总数: 0,
});
//
const hazardPointData = ref({});
// //
const getdateRange = ref([]); const getdateRange = ref([]);
// //
const handleDateRangeChange = (val) => { const handleDateRangeChange = val => {
console.log("日期范围变化:", val); console.log('日期范围变化:', val);
getdateRange.value = val; getdateRange.value = val;
}; };
@ -302,27 +340,67 @@ const handleDateRangeChange = (val) => {
const chongqingMapRef = ref(null); const chongqingMapRef = ref(null);
// //
const changeActiveIndex = (index) => { const changeActiveIndex = index => {
activeitem.value = index; activeitem.value = index;
}; };
const roadItem = ref({}); const roadItem = ref({});
const roadItemClick = (item) => { const showRoadStats = ref(false);
console.log("点击路段:", item); const roadItemClick = item => {
console.log('点击路段:', item);
roadItem.value = item; roadItem.value = item;
showRoadStats.value = true;
};
//
const handleHideRoadStats = () => {
console.log('隐藏路段统计');
showRoadStats.value = false;
};
//
const handleHazardItemClick = item => {
console.log('点击隐患点:', item);
//
if (chongqingMapRef.value) {
chongqingMapRef.value.handleHazardItemClick(item);
}
};
const showHazardPopup = ref(false);
const showHazardPopupfn = val => {
showHazardPopup.value = val;
};
//
const handleRiskPointStatsChange = stats => {
console.log('风险点统计数据变化:', stats);
riskPointStats.value = stats;
};
//
const roadvalArrtrue = ref([]);
const updateRoadvalArr = roadvalArr => {
roadvalArrtrue.value = roadvalArr;
// let num = 0;
// roadvalArrtrue.value.forEach(item => {
// num += item.value;
// });
// roadvalArrtrue.value.push({ label: '', value: num });
console.log('更新路段统计数据:', roadvalArr);
console.log('更新路段统计数据:', roadvalArrtrue);
}; };
// //
const openResourceDetail = (item) => { const openResourceDetail = item => {
console.log("打开资源详情:", item); console.log('打开资源详情:', item);
// //
if (item.label === "全市普通公路抢险队伍" || item.label === "人员") { if (item.label === '全市普通公路抢险队伍' || item.label === '人员') {
// //
if (chongqingMapRef.value) { if (chongqingMapRef.value) {
chongqingMapRef.value.getEmergencyForceData(); chongqingMapRef.value.getEmergencyForceData();
} }
} }
// //
const key = item.label.toLowerCase().replace(/[^a-z]/g, ""); const key = item.label.toLowerCase().replace(/[^a-z]/g, '');
if (dialogVisible.value[key] !== undefined) { if (dialogVisible.value[key] !== undefined) {
dialogVisible.value[key] = true; dialogVisible.value[key] = true;
} }
@ -330,51 +408,73 @@ const openResourceDetail = (item) => {
// //
const clearMapMarkers = () => { const clearMapMarkers = () => {
console.log("清除地图标记"); console.log('清除地图标记');
if (chongqingMapRef.value) { if (chongqingMapRef.value) {
chongqingMapRef.value.clearProjectMarkers(); chongqingMapRef.value.clearProjectMarkers();
} }
}; };
//
const handleClearFilters = () => {
console.log('index.vue 处理清除筛选事件');
//
clearMapMarkers();
//
activeitem.value = {};
roadItem.value = {};
showHazardPopup.value = false;
};
// //
const openDialog = (dialogName) => { const openDialog = dialogName => {
dialogVisible.value[dialogName] = true; dialogVisible.value[dialogName] = true;
}; };
const impactPointDetailItem = ref({}); const impactPointDetailItem = ref({});
// //
const handleImpactPointClick = (item) => { const handleImpactPointClick = item => {
console.log("影响点点击:", item); console.log('影响点点击:', item);
impactPointDetailItem.value = item; impactPointDetailItem.value = item;
}; };
const handleImpactItem = ref({}); const handleImpactItem = ref({});
const handleImpactClickItem = (item) => { const handleImpactClickItem = item => {
console.log("影响点点击详情:", item); console.log('影响点点击详情:', item);
handleImpactItem.value = item; handleImpactItem.value = item;
}; };
const tongnanInfoItemData = ref({});
const tongnanInfoItemDatafn = item => {
console.log('点击详情:', item);
tongnanInfoItemData.value = item;
};
// //
const closeDialog = (dialogName) => { const closeDialog = dialogName => {
// //
console.log("关闭弹窗", dialogName); console.log('关闭弹窗', dialogName);
dialogVisible.value[dialogName] = false; dialogVisible.value[dialogName] = false;
}; };
//
const handleOpenHazardPointSituation = item => {
console.log('打开涉灾隐患点情况弹窗:', item);
hazardPointData.value = item;
dialogVisible.value.hazardPointSituation = true;
};
// //
const warningitem = ref({}); const warningitem = ref({});
const handleWarningClick = (item) => { const handleWarningClick = item => {
console.log("气象预警点击:", item); console.log('气象预警点击:', item);
warningitem.value = item; warningitem.value = item;
}; };
// //
const confirmConfig = ref({ const confirmConfig = ref({
title: "提示", title: '提示',
message: "是否拨打电话?", message: '是否拨打电话?',
confirmText: "确定", confirmText: '确定',
cancelText: "取消", cancelText: '取消',
}); });
// //
const openConfirm = (config) => { const openConfirm = config => {
confirmConfig.value = { ...confirmConfig.value, ...config }; confirmConfig.value = { ...confirmConfig.value, ...config };
dialogVisible.value.confirm = true; dialogVisible.value.confirm = true;
}; };
@ -382,23 +482,23 @@ const openConfirm = (config) => {
const showCenterCard = ref(false); const showCenterCard = ref(false);
const allCountyData = ref({}); const allCountyData = ref({});
// //
const handleDistrictClick = (item) => { const handleDistrictClick = item => {
console.log("区县点击:", item); console.log('区县点击:', item);
allCountyData.value = item; allCountyData.value = item;
if (item.data.roadType == "national") { if (item.data.roadType == 'national') {
// //
openDialog("tongnanTeam"); openDialog('tongnanTeam');
} else if (item.data.roadType == "rural") { } else if (item.data.roadType == 'rural') {
openDialog("responseSituation"); openDialog('responseSituation');
} else if (item.data.type == "project" && item.data.roadType == "-") { } else if (item.data.type == 'project' && item.data.roadType == '-') {
// //
openDialog("tongnanResponsible"); openDialog('tongnanResponsible');
} }
}; };
// //
const handleCenterCardClick = (item) => { const handleCenterCardClick = item => {
console.log("中心卡片点击:", item); console.log('中心卡片点击:', item);
// //
if (chongqingMapRef.value && item.data) { if (chongqingMapRef.value && item.data) {
@ -409,10 +509,7 @@ const handleCenterCardClick = (item) => {
chongqingMapRef.value.openCenterCard(cardData); chongqingMapRef.value.openCenterCard(cardData);
// //
if ( if (item.data.length > 0 && (item.data[0].countyName || item.data[0].name)) {
item.data.length > 0 &&
(item.data[0].countyName || item.data[0].name)
) {
const firstCounty = item.data[0].countyName || item.data[0].name; const firstCounty = item.data[0].countyName || item.data[0].name;
chongqingMapRef.value.locateToDistrict(firstCounty); chongqingMapRef.value.locateToDistrict(firstCounty);
} }
@ -420,15 +517,15 @@ const handleCenterCardClick = (item) => {
}; };
// //
const getCardTitleByType = (type) => { const getCardTitleByType = type => {
const titleMap = { const titleMap = {
first: "国省道调度", first: '国省道调度',
second: "农村公路调度", second: '农村公路调度',
third: "建设工程调度", third: '建设工程调度',
}; };
return titleMap[type] || "调度统计"; return titleMap[type] || '调度统计';
}; };
const handleCenterCardClickType = (item) => { const handleCenterCardClickType = item => {
console.log(item.data); console.log(item.data);
showCenterCard.value = true; showCenterCard.value = true;
// if (item.type === "second") { // if (item.type === "second") {
@ -445,12 +542,12 @@ const refreshLeftData = ref(null);
const refreshRightData = ref(null); const refreshRightData = ref(null);
// //
const setRefreshLeftData = (callback) => { const setRefreshLeftData = callback => {
refreshLeftData.value = callback; refreshLeftData.value = callback;
}; };
// right.vue // right.vue
const setRefreshRightData = (callback) => { const setRefreshRightData = callback => {
refreshRightData.value = callback; refreshRightData.value = callback;
}; };
@ -466,10 +563,10 @@ const triggerRefreshLeftData = () => {
}; };
// //
provide("setRefreshLeftData", setRefreshLeftData); provide('setRefreshLeftData', setRefreshLeftData);
provide("triggerRefreshLeftData", triggerRefreshLeftData); provide('triggerRefreshLeftData', triggerRefreshLeftData);
provide("setRefreshRightData", setRefreshRightData); provide('setRefreshRightData', setRefreshRightData);
provide("getdateRange", getdateRange); provide('getdateRange', getdateRange);
// ==================== ==================== // ==================== ====================
@ -488,6 +585,8 @@ const mapBase = useMapBase(mapStore);
onMounted(() => { onMounted(() => {
// //
mapBase.loadBaseData(); mapBase.loadBaseData();
fetchRoadConditionOptions(); //
fetchDistrictOptions(); //
}); });
</script> </script>
@ -502,7 +601,7 @@ onMounted(() => {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-image: url("../../assets/RiskWarning_img/遮罩层.png"); background-image: url('../../assets/RiskWarning_img/遮罩层.png');
background-size: cover; background-size: cover;
background-position: center; background-position: center;
} }
@ -571,9 +670,17 @@ onMounted(() => {
position: absolute; position: absolute;
bottom: 5px; bottom: 5px;
left: 25%; left: 25%;
width: 50%; width: 20%;
height: 43%; height: 43%;
} }
.weather-warning-table {
position: absolute;
bottom: 5px;
left: 30%;
width: 40%;
height: 43%;
// z-index: 1;
}
.top { .top {
position: absolute; position: absolute;
@ -591,7 +698,7 @@ onMounted(() => {
// left: 25%; // left: 25%;
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: 2; // z-index: 2;
} }
/* 地图底层 - 填满整个容器 */ /* 地图底层 - 填满整个容器 */
@ -609,8 +716,7 @@ onMounted(() => {
z-index: 1; z-index: 1;
pointer-events: none; pointer-events: none;
/* 不阻挡交互 */ /* 不阻挡交互 */
background: url(../../assets/RiskWarning_img/遮罩层.png) no-repeat background: url(../../assets/RiskWarning_img/遮罩层.png) no-repeat center/cover;
center/cover;
} }
// //

View File

@ -404,8 +404,24 @@ const districtLoadLoad = async () => {
if (res.code == "00000") { if (res.code == "00000") {
const data = res.data; const data = res.data;
if (data) { if (data) {
//
const simplifyDistrictName = (name) => {
if (!name) return name;
return name
.replace("彭水苗族土家族自治县", "彭水县")
.replace("石柱土家族自治县", "石柱县")
.replace("秀山土家族苗族自治县", "秀山县")
.replace("酉阳土家族苗族自治县", "酉阳县");
};
//
const processedData = data.map((item) => ({
...item,
name: simplifyDistrictName(item.name),
}));
// //
const sortedData = data.sort((a, b) => { const sortedData = processedData.sort((a, b) => {
const totalA = const totalA =
(a.roadSectionCount || 0) + (a.roadSectionCount || 0) +
(a.bridgeCount || 0) + (a.bridgeCount || 0) +

View File

@ -19,7 +19,8 @@
<div class="resource-info"> <div class="resource-info">
<div class="resource-label">{{ item.label }}</div> <div class="resource-label">{{ item.label }}</div>
<div class="resource-value"> <div class="resource-value">
{{ item.value }}<span class="unit">{{ item.unit }}</span> {{ item.value }}
<span class="unit">{{ item.unit }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -28,8 +29,8 @@
<!-- 管控路段数 --> <!-- 管控路段数 -->
<div class="control-section"> <div class="control-section">
<div class="control-title display jc_sb ai_center"> <div class="control-title display jc_sb ai_center">
<div class="f1">管控路段数 <span class="control-num">2</span></div> <div class="f1">管控路段数</div>
<div class="f1">管控项目 <span class="control-num">2</span></div> <div class="f1">管控项目</div>
</div> </div>
<div style="display: flex; justify-content: space-between"> <div style="display: flex; justify-content: space-between">
<div class="control-grid"> <div class="control-grid">
@ -78,11 +79,7 @@
</div> </div>
</div> </div>
<div class="patrol-grid"> <div class="patrol-grid">
<div <div v-for="(item, index) in patrolData" :key="index" class="patrol-item">
v-for="(item, index) in patrolData"
:key="index"
class="patrol-item"
>
<div class="patrol-value">{{ item.value }}</div> <div class="patrol-value">{{ item.value }}</div>
<div class="patrol-label">{{ item.label }}</div> <div class="patrol-label">{{ item.label }}</div>
</div> </div>
@ -93,16 +90,13 @@
<div class="rescue-section"> <div class="rescue-section">
<div class="rescue-title">抢险投入情况</div> <div class="rescue-title">抢险投入情况</div>
<div class="rescue-grid"> <div class="rescue-grid">
<div <div v-for="(item, index) in rescueData" :key="index" class="rescue-item">
v-for="(item, index) in rescueData"
:key="index"
class="rescue-item"
>
<!-- <div class="rescue-icon" :class="item.iconClass"></div> --> <!-- <div class="rescue-icon" :class="item.iconClass"></div> -->
<img class="rescue-icon" :src="item.img" alt="" /> <img class="rescue-icon" :src="item.img" alt="" />
<div class="rescue-info"> <div class="rescue-info">
<div class="rescue-value"> <div class="rescue-value">
{{ item.value }}<span class="unit">{{ item.unit }}</span> {{ item.value }}
<span class="unit">{{ item.unit }}</span>
</div> </div>
<div class="rescue-label">{{ item.label }}</div> <div class="rescue-label">{{ item.label }}</div>
</div> </div>
@ -116,9 +110,7 @@
<SectionHeader title="受灾情况"> <SectionHeader title="受灾情况">
<template #right> <template #right>
<div class="header-filters"> <div class="header-filters">
<span class="filter-item active" @click="handleDateRangeClick()" <span class="filter-item active" @click="handleDateRangeClick()">本轮</span>
>本轮</span
>
<div class="date-range-wrapper"> <div class="date-range-wrapper">
<el-date-picker <el-date-picker
v-model="dateRange" v-model="dateRange"
@ -180,7 +172,8 @@
:class="item.class" :class="item.class"
> >
<div class="damage-value"> <div class="damage-value">
{{ item.value }}<span class="unit">{{ item.unit }}</span> {{ item.value }}
<span class="unit">{{ item.unit }}</span>
</div> </div>
<div class="damage-label">{{ item.label }}</div> <div class="damage-label">{{ item.label }}</div>
</div> </div>
@ -197,46 +190,42 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, inject, watch } from "vue"; import { ref, computed, onMounted, inject, watch } from 'vue';
import { request } from "@/utils/request"; import { request } from '@/utils/request';
import SectionHeader from "./component/sectionHeader.vue"; import SectionHeader from './component/sectionHeader.vue';
import { Calendar } from "@element-plus/icons-vue"; import { Calendar } from '@element-plus/icons-vue';
import icon1 from "../../assets/RiskWarning_img/icon1@2x.png"; import icon1 from '../../assets/RiskWarning_img/icon1@2x.png';
import icon2 from "../../assets/RiskWarning_img/icon2@2x.png"; import icon2 from '../../assets/RiskWarning_img/icon2@2x.png';
import icon3 from "../../assets/RiskWarning_img/icon3@2x.png"; import icon3 from '../../assets/RiskWarning_img/icon3@2x.png';
import icon4 from "../../assets/RiskWarning_img/icon4@2x.png"; import icon4 from '../../assets/RiskWarning_img/icon4@2x.png';
import icon11 from "../../assets/RiskWarning_img/icon-1@2x.png"; import icon11 from '../../assets/RiskWarning_img/icon-1@2x.png';
import icon12 from "../../assets/RiskWarning_img/icon-2@2x.png"; import icon12 from '../../assets/RiskWarning_img/icon-2@2x.png';
import icon13 from "../../assets/RiskWarning_img/icon-3@2x.png"; import icon13 from '../../assets/RiskWarning_img/icon-3@2x.png';
import icon51 from "../../assets/RiskWarning_img/编组5@2x.png"; import icon51 from '../../assets/RiskWarning_img/编组5@2x.png';
import icon52 from "../../assets/RiskWarning_img/编组22@2x.png"; import icon52 from '../../assets/RiskWarning_img/编组22@2x.png';
import icon55 from "../../assets/RiskWarning_img/路径55@2x.png"; import icon55 from '../../assets/RiskWarning_img/路径55@2x.png';
import icon62 from "../../assets/RiskWarning_img/路径62@2x.png"; import icon62 from '../../assets/RiskWarning_img/路径62@2x.png';
import icon621 from "../../assets/RiskWarning_img/路径62@2x (1).png"; import icon621 from '../../assets/RiskWarning_img/路径62@2x (1).png';
import icon622 from "../../assets/RiskWarning_img/路径62@2x (2).png"; import icon622 from '../../assets/RiskWarning_img/路径62@2x (2).png';
const emit = defineEmits([ const emit = defineEmits(['openClearanceSituation', 'openControlSituation', 'openResourceDetail']);
"openClearanceSituation",
"openControlSituation",
"openResourceDetail",
]);
// //
const setRefreshRightData = inject("setRefreshRightData"); const setRefreshRightData = inject('setRefreshRightData');
const getdateRange = inject("getdateRange", ref([])); const getdateRange = inject('getdateRange', ref([]));
// //
const handleDateChange = (val) => { const handleDateChange = val => {
dateRange.value = val; dateRange.value = val;
getDisasterStats(); getDisasterStats();
}; };
// //
const handleDateRangeClick = (val) => { const handleDateRangeClick = val => {
dateRange.value = []; dateRange.value = [];
getDisasterStats(); getDisasterStats();
}; };
@ -245,8 +234,8 @@ const handleDateRangeClick = (val) => {
const getYhYjllList = async () => { const getYhYjllList = async () => {
try { try {
const res = await request({ const res = await request({
url: "/snow-ops-platform/yhYjll/list", url: '/snow-ops-platform/yhYjll/list',
method: "GET", method: 'GET',
params: { params: {
// longitude: 114.305556, // longitude: 114.305556,
// latitude: 22.624722, // latitude: 22.624722,
@ -254,10 +243,10 @@ const getYhYjllList = async () => {
}, },
}); });
console.log(res); console.log(res);
if (res.code == "00000") { if (res.code == '00000') {
let gl1Rysls = 0; // let gl1Rysls = 0; //
let gl1Yjllmcs = 0; // let gl1Yjllmcs = 0; //
res.data.forEach((item) => { res.data.forEach(item => {
if (item.gl1Lx == 1 || item.gl1Lx == 2) { if (item.gl1Lx == 1 || item.gl1Lx == 2) {
gl1Yjllmcs = gl1Yjllmcs + 1; gl1Yjllmcs = gl1Yjllmcs + 1;
} }
@ -265,20 +254,20 @@ const getYhYjllList = async () => {
}); });
if (gl1Rysls > 10000) { if (gl1Rysls > 10000) {
gl1Rysls = (gl1Rysls / 10000).toFixed(2); gl1Rysls = (gl1Rysls / 10000).toFixed(2);
resourceData.value[1].unit = "万人"; resourceData.value[1].unit = '万人';
} else { } else {
resourceData.value[1].value = gl1Rysls; resourceData.value[1].value = gl1Rysls;
resourceData.value[1].unit = "人"; resourceData.value[1].unit = '人';
} }
resourceData.value[0].value = gl1Yjllmcs; resourceData.value[0].value = gl1Yjllmcs;
} }
} catch (error) { } catch (error) {
console.error("获取应急力量列表失败:", error); console.error('获取应急力量列表失败:', error);
} }
}; };
// //
const getIconByType = (type) => { const getIconByType = type => {
const iconMap = { const iconMap = {
1: icon1, // 1: icon1, //
2: icon2, // 2: icon2, //
@ -292,16 +281,16 @@ const getIconByType = (type) => {
const getYhYjllListMaterials = async () => { const getYhYjllListMaterials = async () => {
try { try {
const res = await request({ const res = await request({
url: "/snow-ops-platform/yhYjll/listMaterials", url: '/snow-ops-platform/yhYjll/listMaterials',
method: "GET", method: 'GET',
params: {}, params: {},
}); });
console.log("物资列表:", res); console.log('物资列表:', res);
if (res.code == "00000" && res.data) { if (res.code == '00000' && res.data) {
let equipment = 0; // let equipment = 0; //
let materials = 0; // let materials = 0; //
res.data.forEach((item) => { res.data.forEach(item => {
if (item.gl1Wzlx == 1) { if (item.gl1Wzlx == 1) {
equipment = equipment + extractAndSumNumbers(item.gl1Wzsl); equipment = equipment + extractAndSumNumbers(item.gl1Wzsl);
} else if (item.gl1Wzlx == 2) { } else if (item.gl1Wzlx == 2) {
@ -310,18 +299,18 @@ const getYhYjllListMaterials = async () => {
}); });
if (materials > 10000) { if (materials > 10000) {
resourceData.value[3].value = (materials / 10000).toFixed(2); resourceData.value[3].value = (materials / 10000).toFixed(2);
resourceData.value[3].unit = "万件"; resourceData.value[3].unit = '万件';
} else { } else {
resourceData.value[3].value = materials; resourceData.value[3].value = materials;
resourceData.value[3].unit = "件"; resourceData.value[3].unit = '件';
} }
console.log(equipment, materials); console.log(equipment, materials);
// //
resourceData.value[2].value = equipment || "0"; resourceData.value[2].value = equipment || '0';
} }
} catch (error) { } catch (error) {
console.error("获取物资列表失败:", error); console.error('获取物资列表失败:', error);
} }
}; };
@ -329,27 +318,27 @@ const getYhYjllListMaterials = async () => {
const getControlStats = async () => { const getControlStats = async () => {
try { try {
const res = await request({ const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/control-stats", url: '/snow-ops-platform/sm-event/dashboard/control-stats',
method: "GET", method: 'GET',
}); });
console.log("管控统计数据:", res); console.log('管控统计数据:', res);
if (res.code == "00000" && res.data) { if (res.code == '00000' && res.data) {
const data = res.data; const data = res.data;
// controlData1value // controlData1value
controlData1.value.forEach((item) => { controlData1.value.forEach(item => {
if (item.label === "封闭管控数") { if (item.label === '封闭管控数') {
item.value = data.fullClosureCount || "0"; item.value = data.fullClosureCount || '0';
} else if (item.label === "半幅通行数") { } else if (item.label === '半幅通行数') {
item.value = data.halfClosureCount || "0"; item.value = data.halfClosureCount || '0';
} else if (item.label === "限速(限车型)数") { } else if (item.label === '限速(限车型)数') {
item.value = data.speedLimitCount || "0"; item.value = data.speedLimitCount || '0';
} else if (item.label === "告警阻拦处数") { } else if (item.label === '告警阻拦处数') {
item.value = data.warningBlockCount || "0"; item.value = data.warningBlockCount || '0';
} }
}); });
} }
} catch (error) { } catch (error) {
console.error("获取管控统计数据失败:", error); console.error('获取管控统计数据失败:', error);
} }
}; };
@ -357,41 +346,41 @@ const getControlStats = async () => {
const getRescueInputStats = async () => { const getRescueInputStats = async () => {
try { try {
const res = await request({ const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/rescue-input-stats", url: '/snow-ops-platform/sm-event/dashboard/rescue-input-stats',
method: "GET", method: 'GET',
}); });
console.log("抢险投入统计数据:", res); console.log('抢险投入统计数据:', res);
if (res.code == "00000" && res.data) { if (res.code == '00000' && res.data) {
const data = res.data; const data = res.data;
// rescueDatavalue // rescueDatavalue
rescueData.value.forEach((item) => { rescueData.value.forEach(item => {
if (item.label === "本轮出动人次") { if (item.label === '本轮出动人次') {
item.value = data.investedManpower || "0"; item.value = data.investedManpower || '0';
item.unit = "人"; item.unit = '人';
if (item.value > 10000) { if (item.value > 10000) {
item.value = (item.value / 10000).toFixed(2); item.value = (item.value / 10000).toFixed(2);
item.unit = "万人"; item.unit = '万人';
} }
} else if (item.label === "本轮出动设备") { } else if (item.label === '本轮出动设备') {
item.value = data.investedMachinery || "0"; item.value = data.investedMachinery || '0';
item.unit = "台"; item.unit = '台';
if (item.value > 10000) { if (item.value > 10000) {
item.value = (item.value / 10000).toFixed(2); item.value = (item.value / 10000).toFixed(2);
item.unit = "万台"; item.unit = '万台';
} }
} else if (item.label === "清理塌方") { } else if (item.label === '清理塌方') {
// //
item.value = data.clearedLandslide.toFixed(2) || 0; item.value = data.clearedLandslide.toFixed(2) || 0;
item.unit = "立方米"; item.unit = '立方米';
if (item.value > 10000) { if (item.value > 10000) {
item.value = (item.value / 10000).toFixed(2); item.value = (item.value / 10000).toFixed(2);
item.unit = "万立方米"; item.unit = '万立方米';
} }
} }
}); });
} }
} catch (error) { } catch (error) {
console.error("获取抢险投入统计数据失败:", error); console.error('获取抢险投入统计数据失败:', error);
} }
}; };
@ -399,102 +388,98 @@ const getRescueInputStats = async () => {
const getDisasterStats = async () => { const getDisasterStats = async () => {
try { try {
const res = await request({ const res = await request({
url: "/snow-ops-platform/sm-event/dashboard/disaster-stats", url: '/snow-ops-platform/sm-event/dashboard/disaster-stats',
method: "GET", method: 'GET',
}); });
console.log("灾害统计数据:", res); console.log('灾害统计数据:', res);
if (res.code == "00000" && res.data) { if (res.code == '00000' && res.data) {
const data = res.data; const data = res.data;
// blockDatavalue // blockDatavalue
blockData.value.forEach((item) => { blockData.value.forEach(item => {
if (item.label === "今日新增阻断数") { if (item.label === '今日新增阻断数') {
item.current = data.todayNormalCount || "0"; item.current = data.todayNormalCount || '0';
item.total = data.todayTotalCount || "0"; item.total = data.todayTotalCount || '0';
} else if (item.label === "本轮累计阻断数") { } else if (item.label === '本轮累计阻断数') {
item.current = data.roundNormalCount || "0"; item.current = data.roundNormalCount || '0';
item.total = data.roundTotalCount || "0"; item.total = data.roundTotalCount || '0';
} }
}); });
// deathDatavalue // deathDatavalue
deathData.value.value = data.roundDeadCount || "0"; deathData.value.value = data.roundDeadCount || '0';
// damageDatavalue // damageDatavalue
damageData.value.forEach((item) => { damageData.value.forEach(item => {
if (item.label === "本轮塌方量") { if (item.label === '本轮塌方量') {
data.roundLandslideVolume = data.roundLandslideVolume.toFixed(2); data.roundLandslideVolume = data.roundLandslideVolume.toFixed(2);
if (data.roundLandslideVolume > 10000) { if (data.roundLandslideVolume > 10000) {
item.value = (data.roundLandslideVolume / 10000).toFixed(2) || "0"; item.value = (data.roundLandslideVolume / 10000).toFixed(2) || '0';
item.unit = "万立方米"; item.unit = '万立方米';
} else { } else {
item.value = data.roundLandslideVolume || "0"; item.value = data.roundLandslideVolume || '0';
item.unit = "立方米"; item.unit = '立方米';
} }
} else if (item.label === "汛期塌方量") { } else if (item.label === '汛期塌方量') {
data.floodSeasonLandslideVolume = data.floodSeasonLandslideVolume = data.floodSeasonLandslideVolume.toFixed(2);
data.floodSeasonLandslideVolume.toFixed(2);
if (data.floodSeasonLandslideVolume > 10000) { if (data.floodSeasonLandslideVolume > 10000) {
item.value = item.value = (data.floodSeasonLandslideVolume / 10000).toFixed(2) || '0';
(data.floodSeasonLandslideVolume / 10000).toFixed(2) || "0"; item.unit = '万立方米';
item.unit = "万立方米";
} else { } else {
item.value = data.floodSeasonLandslideVolume || "0"; item.value = data.floodSeasonLandslideVolume || '0';
item.unit = "立方米"; item.unit = '立方米';
} }
} else if (item.label === "当年塌方量") { } else if (item.label === '当年塌方量') {
data.yearLandslideVolume = data.yearLandslideVolume.toFixed(2); data.yearLandslideVolume = data.yearLandslideVolume.toFixed(2);
if (data.yearLandslideVolume > 10000) { if (data.yearLandslideVolume > 10000) {
item.value = (data.yearLandslideVolume / 10000).toFixed(2) || "0"; item.value = (data.yearLandslideVolume / 10000).toFixed(2) || '0';
item.unit = "万立方米"; item.unit = '万立方米';
} else { } else {
item.value = data.yearLandslideVolume || "0"; item.value = data.yearLandslideVolume || '0';
item.unit = "立方米"; item.unit = '立方米';
} }
} else if (item.label === "本轮已损失") { } else if (item.label === '本轮已损失') {
data.roundTotalLossAmount = data.roundTotalLossAmount.toFixed(2); data.roundTotalLossAmount = data.roundTotalLossAmount.toFixed(2);
if (data.roundTotalLossAmount > 10000) { if (data.roundTotalLossAmount > 10000) {
item.value = (data.roundTotalLossAmount / 10000).toFixed(2) || "0"; item.value = (data.roundTotalLossAmount / 10000).toFixed(2) || '0';
item.unit = "亿元"; item.unit = '亿元';
} else { } else {
item.value = data.roundTotalLossAmount || "0"; item.value = data.roundTotalLossAmount || '0';
item.unit = "万元"; item.unit = '万元';
} }
} else if (item.label === "汛期已损失") { } else if (item.label === '汛期已损失') {
data.floodSeasonTotalLossAmount = data.floodSeasonTotalLossAmount = data.floodSeasonTotalLossAmount.toFixed(2);
data.floodSeasonTotalLossAmount.toFixed(2);
if (data.floodSeasonTotalLossAmount > 10000) { if (data.floodSeasonTotalLossAmount > 10000) {
item.value = item.value = (data.floodSeasonTotalLossAmount / 10000).toFixed(2) || '0';
(data.floodSeasonTotalLossAmount / 10000).toFixed(2) || "0"; item.unit = '亿元';
item.unit = "亿元";
} else { } else {
item.value = data.floodSeasonTotalLossAmount || "0"; item.value = data.floodSeasonTotalLossAmount || '0';
item.unit = "万元"; item.unit = '万元';
} }
} else if (item.label === "当年已损失") { } else if (item.label === '当年已损失') {
data.yearTotalLossAmount = data.yearTotalLossAmount.toFixed(2); data.yearTotalLossAmount = data.yearTotalLossAmount.toFixed(2);
if (data.yearTotalLossAmount > 10000) { if (data.yearTotalLossAmount > 10000) {
item.value = (data.yearTotalLossAmount / 10000).toFixed(2) || "0"; item.value = (data.yearTotalLossAmount / 10000).toFixed(2) || '0';
item.unit = "亿元"; item.unit = '亿元';
} else { } else {
item.value = data.yearTotalLossAmount || "0"; item.value = data.yearTotalLossAmount || '0';
item.unit = "万元"; item.unit = '万元';
} }
} }
}); });
} }
} catch (error) { } catch (error) {
console.error("获取灾害统计数据失败:", error); console.error('获取灾害统计数据失败:', error);
} }
}; };
// //
const extractAndSumNumbers = (value) => { const extractAndSumNumbers = value => {
// //
if (typeof value === "number") { if (typeof value === 'number') {
return value; return value;
} }
// 0 // 0
if (!value || typeof value !== "string") return 0; if (!value || typeof value !== 'string') return 0;
// //
const numbers = value.match(/\d+\.?\d*/g); const numbers = value.match(/\d+\.?\d*/g);
if (!numbers) return 0; if (!numbers) return 0;
@ -503,17 +488,17 @@ const extractAndSumNumbers = (value) => {
}; };
// //
const handleControlClick = (item) => { const handleControlClick = item => {
if (item.label === "封闭管控数") { if (item.label === '封闭管控数') {
emit("openClearanceSituation"); emit('openClearanceSituation');
} else if (item.label === "关闭驻地数") { } else if (item.label === '关闭驻地数') {
emit("openControlSituation"); emit('openControlSituation');
} }
}; };
// //
const handleBlockClick = () => { const handleBlockClick = () => {
emit("openClearanceSituation"); emit('openClearanceSituation');
}; };
// //
@ -522,117 +507,141 @@ const dateRange = ref([]);
// //
const resourceData = ref([ const resourceData = ref([
{ {
label: "全市普通公路抢险队伍", label: '全市普通公路抢险队伍',
value: "", value: '',
unit: "支", unit: '支',
iconClass: "icon-team", iconClass: 'icon-team',
img: icon1, img: icon1,
}, },
{ {
label: "人员", label: '人员',
value: "", value: '',
unit: "人", unit: '人',
iconClass: "icon-person", iconClass: 'icon-person',
img: icon2, img: icon2,
}, },
{ {
label: "储备装备", label: '储备装备',
value: "", value: '',
unit: "台", unit: '台',
iconClass: "icon-equip", iconClass: 'icon-equip',
img: icon3, img: icon3,
}, },
{ {
label: "物资", label: '物资',
value: "", value: '',
unit: "件", unit: '件',
iconClass: "icon-material", iconClass: 'icon-material',
img: icon4, img: icon4,
}, },
]); ]);
// //
const handleResourceClick = (item) => { const handleResourceClick = item => {
emit("openResourceDetail", item); emit('openResourceDetail', item);
}; };
// //
const controlData1 = ref([ const controlData1 = ref([
{ label: "封闭管控数", value: "40" }, { label: '封闭管控数', value: '40' },
{ label: "半幅通行数", value: "40" }, { label: '半幅通行数', value: '40' },
{ label: "限速(限车型)数", value: "24" }, { label: '限速(限车型)数', value: '24' },
{ label: "告警阻拦处数", value: "32" }, { label: '告警阻拦处数', value: '32' },
]); ]);
const controlData2 = [ const controlData2 = ref([
{ label: "停工项目数", value: "30" }, { label: '停工项目数', value: '0', key: 'stoped_project_count' },
{ label: "关闭驻地数", value: "42" }, { label: '关闭驻地数', value: '0', key: 'closed_site_count' },
{ label: "转移撤离人员数", value: "58" }, { label: '转移撤离人员数', value: '0', key: 'displaced_population' },
]; ]);
//
const getAffectedCountByProject = async () => {
try {
const res = await request({
url: '/snow-ops-platform/weather-warning/affected-count/_by_project',
method: 'GET',
});
console.log('气象预警受影响统计:', res);
if (res.code === '00000' && res.data) {
const data = res.data;
// controlData2
controlData2.value.forEach(item => {
const matchedData = data.find(d => d.name === item.key);
if (matchedData) {
item.value = String(matchedData.count);
}
});
}
} catch (error) {
console.error('获取气象预警受影响统计失败:', error);
}
};
// //
const patrolData = [ const patrolData = [
{ label: "巡查路段数", value: "2" }, { label: '巡查路段数', value: '2' },
{ label: "巡查桥梁数", value: "1" }, { label: '巡查桥梁数', value: '1' },
{ label: "巡查边坡数", value: "6" }, { label: '巡查边坡数', value: '6' },
{ label: "巡查隧道数", value: "10" }, { label: '巡查隧道数', value: '10' },
{ label: "发现隐患数", value: "6" }, { label: '发现隐患数', value: '6' },
]; ];
// //
const rescueData = ref([ const rescueData = ref([
{ {
label: "本轮出动人次", label: '本轮出动人次',
value: "22341", value: '22341',
unit: "人次", unit: '人次',
iconClass: "icon-rescue-person", iconClass: 'icon-rescue-person',
img: icon11, img: icon11,
}, },
{ {
label: "本轮出动设备", label: '本轮出动设备',
value: "341", value: '341',
unit: "台次", unit: '台次',
iconClass: "icon-rescue-equip", iconClass: 'icon-rescue-equip',
img: icon12, img: icon12,
}, },
{ {
label: "清理塌方", label: '清理塌方',
value: "1367", value: '1367',
unit: "立方米", unit: '立方米',
iconClass: "icon-rescue-clear", iconClass: 'icon-rescue-clear',
img: icon13, img: icon13,
}, },
]); ]);
// - // -
const blockData = ref([ const blockData = ref([
{ label: "今日新增阻断数", current: "19", total: "23" }, { label: '今日新增阻断数', current: '19', total: '23' },
{ label: "本轮累计阻断数", current: "10", total: "23" }, { label: '本轮累计阻断数', current: '10', total: '23' },
]); ]);
// //
const deathData = ref({ label: "本轮因灾死亡人数", value: "5" }); const deathData = ref({ label: '本轮因灾死亡人数', value: '5' });
// //
const damageData = ref([ const damageData = ref([
{ label: "本轮塌方量", value: "23", unit: "万立方米", class: "blue" }, { label: '本轮塌方量', value: '23', unit: '万立方米', class: 'blue' },
{ label: "汛期塌方量", value: "23", unit: "万立方米", class: "blue" }, { 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: '80', unit: '万元', class: 'red' },
{ label: "汛期已损失", value: "18", unit: "万元", class: "red" }, { label: '汛期已损失', value: '18', unit: '万元', class: 'red' },
{ label: "当年已损失", value: "350", unit: "万元", class: "red" }, { label: '当年已损失', value: '350', unit: '万元', class: 'red' },
]); ]);
// //
const majorEvent = "0"; const majorEvent = '0';
// watch // watch
const init = () => { const init = () => {
console.log("right.vue 刷新数据"); console.log('right.vue 刷新数据');
getYhYjllList(); getYhYjllList();
getYhYjllListMaterials(); getYhYjllListMaterials();
getControlStats(); getControlStats();
getRescueInputStats(); getRescueInputStats();
getDisasterStats(); getDisasterStats();
getAffectedCountByProject();
}; };
// //
@ -646,13 +655,13 @@ onMounted(() => {
watch( watch(
() => getdateRange.value, () => getdateRange.value,
(newVal) => { newVal => {
console.log("right.vue 日期范围变化:", newVal); console.log('right.vue 日期范围变化:', newVal);
if (newVal && newVal.length === 2) { if (newVal && newVal.length === 2) {
} }
init(); init();
}, },
{ deep: true, immediate: true }, { deep: true, immediate: true }
); );
</script> </script>
@ -699,7 +708,7 @@ watch(
.section-header { .section-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
background-image: url("../../assets/RiskWarning_img/标题bg@2x.png"); background-image: url('../../assets/RiskWarning_img/标题bg@2x.png');
align-items: center; align-items: center;
margin-bottom: vw(8); margin-bottom: vw(8);
height: vw(50); height: vw(50);
@ -721,7 +730,7 @@ watch(
justify-content: center; justify-content: center;
&::before { &::before {
content: "←"; content: '←';
color: #fff; color: #fff;
font-size: vw(10); font-size: vw(10);
} }
@ -751,12 +760,7 @@ watch(
padding: vw(4) vw(8); padding: vw(4) vw(8);
background: linear-gradient(270deg, rgba(18, 52, 97, 0) 0%, #203555 100%); background: linear-gradient(270deg, rgba(18, 52, 97, 0) 0%, #203555 100%);
border: 2px solid transparent; border: 2px solid transparent;
border-image: linear-gradient( border-image: linear-gradient(270deg, rgba(80, 145, 201, 0), rgba(39, 77, 153, 1)) 2 2;
270deg,
rgba(80, 145, 201, 0),
rgba(39, 77, 153, 1)
)
2 2;
border-radius: 6px; border-radius: 6px;
border-right: 0px; border-right: 0px;
@ -771,16 +775,16 @@ watch(
font-size: vw(18); font-size: vw(18);
&.icon-team::before { &.icon-team::before {
content: "👷"; content: '👷';
} }
&.icon-person::before { &.icon-person::before {
content: "👤"; content: '👤';
} }
&.icon-equip::before { &.icon-equip::before {
content: "🚛"; content: '🚛';
} }
&.icon-material::before { &.icon-material::before {
content: "📦"; content: '📦';
} }
} }
@ -837,7 +841,7 @@ watch(
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
// background: rgba(62, 106, 172, 0.36); // background: rgba(62, 106, 172, 0.36);
// box-shadow: inset 0px 0px 8px 0px #379bff; // box-shadow: inset 0px 0px 8px 0px #379bff;
background-image: url("../../assets/RiskWarning_img/路径 62@2x.png"); background-image: url('../../assets/RiskWarning_img/路径 62@2x.png');
background-size: 100% 100%; background-size: 100% 100%;
background-position: right; background-position: right;
gap: vw(8); gap: vw(8);
@ -904,7 +908,7 @@ watch(
padding: vw(6) vw(5); padding: vw(6) vw(5);
// background: rgba(64, 169, 255, 0.1); // background: rgba(64, 169, 255, 0.1);
// border-radius: 4px; // border-radius: 4px;
background-image: url("../../assets/RiskWarning_img/路径62@2x (1).png"); background-image: url('../../assets/RiskWarning_img/路径62@2x (1).png');
background-size: 100% 100%; background-size: 100% 100%;
background-position: right; background-position: right;
@ -946,7 +950,7 @@ watch(
// background: rgba(64, 169, 255, 0.1); // background: rgba(64, 169, 255, 0.1);
// border: 1px solid rgba(64, 169, 255, 0.2); // border: 1px solid rgba(64, 169, 255, 0.2);
// border-radius: 6px; // border-radius: 6px;
background-image: url("../../assets/RiskWarning_img/路径62@2x (1).png"); background-image: url('../../assets/RiskWarning_img/路径62@2x (1).png');
background-size: 100% 100%; background-size: 100% 100%;
background-position: right; background-position: right;
@ -960,13 +964,13 @@ watch(
margin-left: vw(5); margin-left: vw(5);
&.icon-rescue-person::before { &.icon-rescue-person::before {
content: "👷"; content: '👷';
} }
&.icon-rescue-equip::before { &.icon-rescue-equip::before {
content: "🚜"; content: '🚜';
} }
&.icon-rescue-clear::before { &.icon-rescue-clear::before {
content: "🏔️"; content: '🏔️';
} }
} }
@ -1030,7 +1034,7 @@ watch(
// display: grid; // display: grid;
// grid-template-columns: repeat(5, 1fr); // grid-template-columns: repeat(5, 1fr);
// gap: 10px; // gap: 10px;
background-image: url("../../assets/RiskWarning_img/编组22@2x.png"); background-image: url('../../assets/RiskWarning_img/编组22@2x.png');
background-size: 100% 100%; background-size: 100% 100%;
background-position: center; background-position: center;
@ -1038,12 +1042,7 @@ watch(
width: 2px; width: 2px;
height: vw(40); height: vw(40);
margin: auto 0; margin: auto 0;
background: linear-gradient( background: linear-gradient(180deg, transparent 0%, #18f2f9 50%, transparent 100%);
180deg,
transparent 0%,
#18f2f9 50%,
transparent 100%
);
// margin: 0 auto; // margin: 0 auto;
} }
@ -1116,7 +1115,7 @@ watch(
padding: vw(4) 0; padding: vw(4) 0;
// background: rgba(64, 169, 255, 0.1); // background: rgba(64, 169, 255, 0.1);
// border-radius: 6px; // border-radius: 6px;
background-image: url("../../assets/RiskWarning_img/路径62@2x.png"); background-image: url('../../assets/RiskWarning_img/路径62@2x.png');
background-size: 100% 100%; background-size: 100% 100%;
background-position: left; background-position: left;
@ -1159,7 +1158,7 @@ watch(
padding: vw(12); padding: vw(12);
// background: rgba(64, 169, 255, 0.1); // background: rgba(64, 169, 255, 0.1);
// border-radius: 6px; // border-radius: 6px;
background-image: url("../../assets/RiskWarning_img/编组5@2x.png"); background-image: url('../../assets/RiskWarning_img/编组5@2x.png');
background-size: 100% 100%; background-size: 100% 100%;
background-position: left; background-position: left;

View File

@ -1,9 +1,7 @@
<template> <template>
<div class="filter-header"> <div class="filter-header">
<div class="filter-container"> <div class="filter-container">
<span class="filter-item active" @click="handleDateRangeClick()" <span class="filter-item active" @click="handleDateRangeClick()">本轮</span>
>本轮</span
>
<div class="date-range-wrapper"> <div class="date-range-wrapper">
<el-date-picker <el-date-picker
v-model="dateRange" v-model="dateRange"
@ -18,22 +16,132 @@
/> />
</div> </div>
</div> </div>
<!-- <img class="filter-icon-ai" src="../../assets/RiskWarning_img/AI1@2x.png" alt="" @click="handleAIClick" /> --> <div class="hazard-stats" v-if="showHazardPopup">
<div
v-for="(item, index) in hazardStatsShowArr"
:key="index"
class="stat-item"
:class="item.class"
>
<span class="stat-label">{{ item.label }}</span>
<span class="stat-value-container display ai_center">
<span class="stat-value">{{ item.value }}</span>
<span class="stat-unit"></span>
</span>
</div>
</div>
<div class="road-stats" v-if="showRoadStats && roadStats.length > 0">
<div v-for="(item, index) in roadStats" :key="index" class="stat-item">
<span class="stat-label">{{ item.label }}</span>
<span class="stat-value-container display ai_center">
<span class="stat-value">{{ item.value }}</span>
<span class="stat-unit"></span>
</span>
</div>
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, watch, inject } from "vue"; import { ref, watch, inject, defineProps, nextTick, provide, onMounted } from 'vue';
import { Calendar } from "@element-plus/icons-vue"; import { Calendar } from '@element-plus/icons-vue';
import { request } from '@/utils/request';
const emit = defineEmits(["openAIResult", "dateRangeChange"]); const props = defineProps({
riskPointStats: {
type: Object,
default: () => ({}),
},
showHazardPopup: {
type: Boolean,
default: false,
},
roadvalArrtrue: {
type: Array,
default: () => [],
},
roadItem: {
type: Object,
default: () => ({}),
},
showRoadStats: {
type: Boolean,
default: false,
},
});
watch(
() => props.showHazardPopup,
newShow => {
hazardStatsShowArr.value = JSON.parse(JSON.stringify([]));
hazardStats.value.forEach(item => {
item.value = 0;
item.show = false;
});
}
);
const emit = defineEmits(['openAIResult', 'dateRangeChange']);
// //
const triggerRefreshLeftData = inject("triggerRefreshLeftData"); const triggerRefreshLeftData = inject('triggerRefreshLeftData');
const dateRange = ref([]); const dateRange = ref([]);
//
const hazardStatsShowArr = ref([]);
const hazardStats = ref([
{ label: '重大路内隐患点', value: 0, show: false, type: '重大路内隐患点', isWithinRedLine: '是' },
{ label: '重大路外隐患点', value: 0, show: false, type: '重大路外隐患点', isWithinRedLine: '否' },
{ label: '较大路内隐患点', value: 0, show: false, type: '较大路内隐患点', isWithinRedLine: '是' },
{ label: '较大路外隐患点', value: 0, show: false, type: '较大路外隐患点', isWithinRedLine: '否' },
{ label: '一般路内隐患点', value: 0, show: false, type: '一般路内隐患点', isWithinRedLine: '是' },
{ label: '一般路外隐患点', value: 0, show: false, type: '一般路外隐患点', isWithinRedLine: '否' },
{ label: '风险点总数', value: 0, show: false, type: '风险点总数', isWithinRedLine: '' },
]);
//
const roadStats = ref([
{ label: '高风险路段', value: 0, type: '高风险路段' },
{ label: '较高风险路段', value: 0, type: '较高风险路段' },
{ label: '中风险路段', value: 0, type: '中风险路段' },
{ label: '低风险路段', value: 0, type: '低风险路段' },
{ label: '风险点总数', value: 0, type: '风险点总数' },
]);
watch(
() => props.riskPointStats,
newStats => {
console.log('top.vue 收到风险点统计数据:', newStats);
if (newStats) {
hazardStatsShowArr.value = [];
hazardStats.value.forEach(item => {
if (
item.label.includes(newStats.riskLevel) &&
newStats.isWithinRedLine == item.isWithinRedLine &&
newStats.value >= 0
) {
item.value = newStats.value;
item.show = true;
}
if (item.show) {
hazardStatsShowArr.value.push(item);
hazardStats.value[6].show = true;
}
});
hazardStats.value[6].value =
hazardStats.value[0].value +
hazardStats.value[1].value +
hazardStats.value[2].value +
hazardStats.value[3].value +
hazardStats.value[4].value +
hazardStats.value[5].value;
}
},
{ immediate: true, deep: true }
);
// 23:59:59 // 23:59:59
const setEndOfDay = (date) => { const setEndOfDay = date => {
if (!date) return date; if (!date) return date;
const d = new Date(date); const d = new Date(date);
d.setHours(23, 59, 59, 999); d.setHours(23, 59, 59, 999);
@ -50,9 +158,9 @@ watch(
dateRange, dateRange,
(newVal, oldVal) => { (newVal, oldVal) => {
// //
console.log("dateRange 变化:", newVal, oldVal); console.log('dateRange 变化:', newVal, oldVal);
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) { if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
console.log("dateRange 发生变化:", newVal); console.log('dateRange 发生变化:', newVal);
// 23:59:59 // 23:59:59
if (newVal && newVal.length === 2 && newVal[1]) { if (newVal && newVal.length === 2 && newVal[1]) {
newVal[1] = setEndOfDay(newVal[1]); newVal[1] = setEndOfDay(newVal[1]);
@ -62,15 +170,51 @@ watch(
// triggerRefreshLeftData(); // triggerRefreshLeftData();
// } // }
// //
emit("dateRangeChange", newVal); emit('dateRangeChange', newVal);
} }
}, },
{ deep: true }, { deep: true }
); );
const handleAIClick = () => { const handleAIClick = () => {
emit("openAIResult"); emit('openAIResult');
}; };
//
const fetchRiskLevelCount = async () => {
try {
const res = await request({
url: '/snow-ops-platform/risk-point/risk-level-count',
method: 'GET',
});
console.log('风险等级统计数据:', res);
if (res.code === '00000' && res.data) {
//
const data = res.data;
let roadTotal = 0;
roadStats.value.forEach(item => {
// 0
item.value = 0;
//
const matchedData = data.find(d => item.label.includes(d.level));
if (matchedData) {
item.value = Number(matchedData.count);
roadTotal += Number(matchedData.count);
}
});
//
roadStats.value[4].value = roadTotal;
console.log('更新后的roadStats:', roadStats.value);
}
} catch (error) {
console.error('获取风险等级统计数据失败:', error);
}
};
//
onMounted(() => {
fetchRiskLevelCount();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -82,8 +226,8 @@ const handleAIClick = () => {
.filter-header { .filter-header {
padding: vw(10); padding: vw(10);
display: flex; // display: flex;
justify-content: space-between; // justify-content: space-between;
// align-items: center; // align-items: center;
// //
@ -104,6 +248,7 @@ const handleAIClick = () => {
min-height: 18px; min-height: 18px;
gap: vw(8); gap: vw(8);
font-size: vw(13); font-size: vw(13);
margin-bottom: vw(20);
.filter-item { .filter-item {
color: #fff; color: #fff;
@ -165,4 +310,91 @@ const handleAIClick = () => {
min-height: 48px; min-height: 48px;
cursor: pointer; cursor: pointer;
} }
//
.hazard-stats {
width: min-content;
display: grid;
background: url('@/assets/RiskWarning_img/隐患点弹窗背景@2x.png') no-repeat top left;
background-size: 100% 100%;
grid-template-columns: repeat(7, 1fr);
margin-bottom: vw(20);
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
// gap: vw(4);
&:last-child {
border-right: none;
}
.stat-label {
font-size: vw(14);
padding: vw(8) vw(15);
// background: #0e365d;
color: rgba(255, 255, 255, 0.8);
white-space: nowrap;
}
.stat-value-container {
padding: vw(4) vw(10);
}
.stat-value {
font-size: vw(18);
font-weight: bold;
color: #ff4d4f;
}
.stat-unit {
font-size: vw(14);
color: #fff;
}
}
}
//
.road-stats {
padding: vw(10);
width: min-content;
display: grid;
background: url('@/assets/RiskWarning_img/隐患点弹窗背景@2x.png') no-repeat top left;
background-size: 100% 100%;
grid-template-columns: repeat(5, 1fr);
margin-bottom: vw(20);
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
gap: vw(4);
padding: 0 vw(10);
&:last-child {
border-right: none;
}
.stat-label {
font-size: vw(14);
color: rgba(255, 255, 255, 0.8);
white-space: nowrap;
}
.stat-value-container {
display: flex;
align-items: center;
gap: vw(2);
.stat-value {
font-size: vw(18);
font-weight: bold;
color: #ff4d4f;
}
.stat-unit {
font-size: vw(14);
color: rgba(255, 255, 255, 0.8);
}
}
}
}
</style> </style>

View File

@ -372,6 +372,12 @@ export default () => {
path: '/dutyManagement' path: '/dutyManagement'
}); });
}; };
// 跳转到消息推送设置
const gotoMessagePage = () => {
router.push({
path: '/messageManagement'
});
}
onMounted(() => { onMounted(() => {
getTableData(); getTableData();
@ -396,6 +402,7 @@ export default () => {
columns, columns,
gotoLedgerPage, gotoLedgerPage,
gotoDutyPage, gotoDutyPage,
gotoMessagePage,
modelVisible, modelVisible,
model, model,

View File

@ -17,6 +17,7 @@
<el-button type="primary" @click="script.gotoLedgerPage">线下帮扶台账</el-button> <el-button type="primary" @click="script.gotoLedgerPage">线下帮扶台账</el-button>
<el-button type="primary" @click="script.openScheduleDiaog">立即排班</el-button> <el-button type="primary" @click="script.openScheduleDiaog">立即排班</el-button>
<el-button type="primary" @click="script.gotoDutyPage">值班管理</el-button> <el-button type="primary" @click="script.gotoDutyPage">值班管理</el-button>
<el-button type="primary" @click="script.gotoMessagePage">消息推送设置</el-button>
<el-button type="primary" color="#952DE6" @click="">导出</el-button> <el-button type="primary" color="#952DE6" @click="">导出</el-button>
<input type="file" ref="fileInput" style="display: none" @change="handleFileSelect" accept=".*"></input> <input type="file" ref="fileInput" style="display: none" @change="handleFileSelect" accept=".*"></input>
<!-- <el-button type="primary" @click="script.gotoLedgerPage">驻地台账</el-button> --> <!-- <el-button type="primary" @click="script.gotoLedgerPage">驻地台账</el-button> -->

View File

@ -0,0 +1,267 @@
<template>
<div class="detail-container">
<el-form ref="formRef" :model="form" label-position="right" label-width="auto"
style="max-height: 60vh; overflow-y: hidden; padding-right: 50px" :rules="rules">
<el-form-item label="" prop="schedules">
<div class="user-select-container">
<!-- 左侧用户列表 -->
<div class="user-list-panel">
<div class="panel-title">用户列表</div>
<div class="user-list">
<div v-for="user in currentUsers" :key="user.userId" class="user-item"
:class="{ 'selected': isUserSelected(user) }" @click="toggleUserSelection(user)">
<span class="user-name">{{ user.realName || user.nickName || user.account }}</span>
<span class="user-position">{{ user.positionName }}</span>
</div>
</div>
</div>
<!-- 右侧已选择用户 -->
<div class="selected-panel">
<div class="panel-title">已选择用户 ({{ selectedUsers.length }})</div>
<div class="selected-user-list">
<div v-for="user in selectedUsers" :key="user.userId" class="selected-user-item">
<div class="user-info">
<span class="user-name">{{ user.realName || user.nickName || user.account }}</span>
<span class="user-position">{{ user.positionName }}</span>
</div>
<el-button type="danger" size="small" icon="Delete" circle @click.stop="removeSelectedUser(user)" />
</div>
</div>
</div>
</div>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ref, computed, onMounted, watch } from "vue";
import { request } from "@/utils/request";
import { ElMessage } from 'element-plus';
const formRef = ref(null);
//
const currentUsers = ref([]);
//
const selectedUsers = ref([]);
defineExpose({
formRef,
});
const props = defineProps({
form: {
type: Object,
default: () => ({}),
},
orgId: {
type: String,
default: ''
},
orgName: {
type: String,
default: ''
}
});
const rules = computed(() => {
return {
};
});
//
const isUserSelected = (user) => {
return selectedUsers.value.some(selected => selected.userId === user.userId);
};
//
const toggleUserSelection = (user) => {
if (isUserSelected(user)) {
removeSelectedUser(user);
} else {
// orgId
selectedUsers.value.push({
// ...user,
// orgId: user.orgId, // orgId
// timeRange: null
...user,
orgId: user.orgId,
orgName: props.orgName,
userId: user.userId,
userAccount: user.account,
userPhone: user.phone
});
}
};
//
const removeSelectedUser = (user) => {
const index = selectedUsers.value.findIndex(selected => selected.userId === user.userId);
if (index > -1) {
selectedUsers.value.splice(index, 1);
}
};
// ID
const getUsersByOrgId = async (orgId) => {
// console.log('@@@@@', orgId);
try {
const res = await request({
url: '/snow-ops-platform/user/orgUsers',
method: 'GET',
params: {
orgId
}
})
if (res.code === '00000') {
currentUsers.value = res.data || [];
// console.log('@@@@@', res.data);
} else {
throw new Error(res.message)
}
} catch (error) {
ElMessage.error('获取用户失败');
console.error('获取用户失败:', error);
}
}
onMounted(() => {
getUsersByOrgId(props.orgId);
})
watch(selectedUsers.value, (val) => {
props.form.data = val;
}, { deep: true })
</script>
<style scoped>
.form-part {
padding: 20px;
}
.text-center {
text-align: center;
}
.user-select-container {
display: flex;
gap: 20px;
width: 100%;
height: 60vh;
}
.user-list-panel {
flex: 1;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 10px;
background-color: #fff;
height: 100%;
}
.selected-panel {
flex: 1;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 10px;
background-color: #fff;
display: flex;
flex-direction: column;
height: 100%;
}
.user-list {
flex: 1;
overflow-y: auto;
}
.user-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
margin-bottom: 4px;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
border: 1px solid transparent;
}
.user-item:hover {
background-color: #f5f7fa;
}
.user-item.selected {
background-color: #409eff;
color: white;
border-color: #409eff;
}
.user-name {
font-size: 14px;
font-weight: 500;
}
.user-position {
font-size: 12px;
opacity: 0.7;
}
.selected-user-list {
flex: 1;
overflow-y: auto;
}
.selected-user-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
margin-bottom: 4px;
border-radius: 4px;
background-color: #f0f9ff;
border: 1px solid #e1f5fe;
gap: 12px;
}
.time-picker-container {
flex: 1.2;
min-width: 280px;
}
.time-picker-container :deep(.el-date-editor) {
width: 100%;
}
.user-info {
display: flex;
flex-direction: column;
min-width: 120px;
flex: 0.8;
}
.selected-user-item .user-name {
font-size: 14px;
font-weight: 500;
color: #303133;
}
.selected-user-item .user-position {
font-size: 12px;
color: #606266;
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
font-size: 14px;
padding-right: 8px;
}
</style>

View File

@ -0,0 +1,224 @@
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
import { request } from "@/utils/request";
import { useRoute, useRouter } from 'vue-router'
import AddDialog from "./addDialog.vue";
const modelVisible = ref(false); // 弹窗状态
const drawerVisible = ref(false); // 抽屉状态
// 弹窗内容
const model = reactive({
});
const form = reactive({
});
const INIT_FORM = {
};
// 抽屉内容
const drawer = reactive({
title: '',
content: null,
props: {},
onCancel: null,
onConfirm: null,
direction: 'rtl',
size: '50%'
});
const dialogRef = ref(null); // 弹窗实例
const drawerRef = ref(null); // 抽屉实例
// 消息推送组织列表固定六个增加personList存储该组织的人员数组
const messageOrgList = ref([
{ title: '中心领导', orgName: '中心领导', personList: [] },
{ title: '法规处', orgName: '法规处', personList: [] },
{ title: '养护处', orgName: '养护处', personList: [] },
{ title: '农村公路处', orgName: '农村公路处', personList: [] },
{ title: '建设处', orgName: '建设处', personList: [] },
{ title: '市公路应急中心/管理段', orgName: '公路管理段', personList: [] },
])
const messagePushPerson = ref([])
const userOrgsList = ref([])
// 查询所有消息推送人员
const getAllMessagePushPerson = async () => {
try {
const res = await request({
url: '/snow-ops-platform/messagePushPerson/listAll',
method: 'GET',
})
if (res.code === '00000') {
messagePushPerson.value = res.data
// 按orgId分组填充人员数据到对应组织
messageOrgList.value.forEach(org => {
org.personList = messagePushPerson.value.filter(person => person.orgId === org.orgId)
});
// console.log('@@@@@@', messageOrgList.value);
} else {
throw new Error(res.message)
}
} catch (error) {
ElMessage.error('获取消息推送人员失败');
console.error('获取消息推送人员失败:', error);
}
}
// 查询所有组织
const getUserOrgs = async () => {
try {
const res = await request({
url: '/snow-ops-platform/user/userOrgs',
method: 'GET',
})
if (res.code === '00000') {
userOrgsList.value = res.data.data
// 遍历后端返回的组织数据与固定组织列表匹配并赋值orgId
messageOrgList.value.forEach(fixedOrg => {
const matchedOrg = userOrgsList.value.find(org =>
org.orgName === fixedOrg.orgName
);
if (matchedOrg) {
fixedOrg.orgId = matchedOrg.orgId;
}
});
// 在获取到orgId后立即根据orgId填充对应的人员数据
messageOrgList.value.forEach(org => {
org.personList = messagePushPerson.value.filter(person => person.orgId === org.orgId)
});
// console.log('@@@@',messageOrgList.value);
} else {
throw new Error(res.message)
}
} catch (error) {
ElMessage.error('获取组织失败');
console.error('获取组织失败:', error);
}
}
// 添加消息推送人
const handelAdd = async (data) => {
try {
const loading = ElLoading.service({
lock: true,
text: '操作中',
background: 'rgba(0, 0, 0, 0.7)',
})
const res = await request({
url: '/snow-ops-platform/messagePushPerson/add',
method: 'POST',
data: data
})
loading.close();
if (res.code === '00000') {
ElMessage.success('添加成功');
modelVisible.value = false;
await getAllMessagePushPerson();
} else {
throw new Error(res.message)
}
} catch (error) {
ElMessage.error('添加失败');
console.error('添加失败:', error);
}
}
// 打开添加人员弹窗
const openAddDialog = (orgId, orgName) => {
model.title = '添加人员';
Object.assign(form, INIT_FORM);
model.props = {
orgId: orgId,
orgName: orgName,
form: form,
};
model.content = AddDialog;
model.onCancel = () => {
modelVisible.value = false;
};
model.onConfirm = async () => {
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
// console.log('@@@@@@form',form);
await handelAdd(form.data)
// await addSchedule(form)
// await publishWarning(form)
})
.catch((err) => {
ElMessage.error('请处理表单中的错误项');
});
};
model.width = "70%"
modelVisible.value = true;
}
// 删除消息推送人
const deletePushPerson = async (person) => {
try {
await ElMessageBox.confirm(
`确定要删除【${person.realName}】吗?`,
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
const loading = ElLoading.service({
lock: true,
text: '操作中',
background: 'rgba(0, 0, 0, 0.7)',
})
const res = await request({
url: '/snow-ops-platform/messagePushPerson/deleteByUserId',
method: 'POST',
data: {
userId: person.userId
}
})
loading.close();
if (res.code === '00000') {
ElMessage.success('删除成功');
await getAllMessagePushPerson();
} else {
throw new Error(res.message)
}
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('删除失败');
console.error('删除失败:', error);
}
}
}
export default () => {
const router = useRouter();
onMounted(async () => {
await getUserOrgs();
await getAllMessagePushPerson();
})
return {
modelVisible,
model,
drawerVisible,
drawer,
dialogRef,
drawerRef,
openAddDialog,
deletePushPerson,
messageOrgList,
}
}

View File

@ -0,0 +1,121 @@
<template>
<div class="root">
<div class="content-box">
<el-card shadow="never" v-for="org in script.messageOrgList.value" class="org-box">
<template #header>
<div class="card-header">
<span>{{ org.title }}</span>
<el-button type="primary" size="small" text
@click="script.openAddDialog(org.orgId, org.orgName)">添加</el-button>
</div>
</template>
<!-- 人员列表 -->
<div class="person-list">
<div v-if="org.personList.length === 0" class="empty-text">暂无人员</div>
<div v-else class="person-item" v-for="person in org.personList" :key="person.userId">
<div class="person-info">
<span class="name">{{ person.realName }}</span>
<!-- <span class="account">({{ person.userAccount }})</span> -->
<span class="phone" v-if="person.userPhone">{{ person.userPhone }}</span>
</div>
<el-button type="danger" size="small" text @click="script.deletePushPerson(person)">删除</el-button>
</div>
</div>
</el-card>
</div>
<div class="model-box">
<MyDialog v-model="script.modelVisible.value" :title="script.model?.title"
:dynamicComponent="script.model?.content" :component-props="script.model?.props"
:onConfirm="script.model?.onConfirm" :onCancel="script.model?.onCancel" ref="dialogRef"
:width="script.model?.width">
</MyDialog>
<MyDrawer v-model="script.drawerVisible.value" :title="script.drawer?.title"
:dynamicComponent="script.drawer?.content" :component-props="script.drawer?.props"
:onConfirm="script.drawer?.onConfirm" :onCancel="script.drawer?.onCancel" ref="drawerRef"
:direction="script.drawer?.direction" :size="script.drawer?.size">
</MyDrawer>
</div>
</div>
</template>
<script setup>
import DynamicTable from "@/component/DynamicTable/index.js";
import { Search, ArrowDown } from "@element-plus/icons-vue";
import MyDialog from "@/component/MyDialog/index.js";
import MyDrawer from "@/component/MyDrawer/index.js";
import scriptFn from "./index.js";
const script = scriptFn();
const { dialogRef, drawerRef } = script;
</script>
<style scoped>
.root {
height: 100%;
padding: 25px;
}
.content-box {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
gap: 20px;
}
.org-box {
flex: 1;
height: 100%;
min-width: fit-content;
}
.card-header {
display: flex;
flex-direction: row;
justify-content: space-between;
white-space: nowrap;
align-items: center;
}
.person-list {
margin-top: 10px;
}
.empty-text {
color: #999;
text-align: center;
padding: 20px 0;
}
.person-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
}
.person-item:last-child {
border-bottom: none;
}
.person-info {
display: flex;
gap: 10px;
align-items: center;
}
.name {
font-weight: bold;
}
.account {
color: #666;
font-size: 0.9em;
}
.phone {
color: #666;
font-size: 0.9em;
}
</style>