Compare commits

..

2 Commits

6 changed files with 961 additions and 443 deletions

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.title"
:table-data="tableData" :table-data="tableData"
:table-columns="tableColumns" :table-columns="tableColumns"
:table-height="450" :table-height="450"
@ -32,17 +32,26 @@
</div> </div>
</div> </div>
<div class="info-row"> <div class="info-row">
<div class="info-item">
<span class="info-label">路线名称</span>
<span class="info-value">{{ hazardData.roadName }}</span>
</div>
<div class="info-item"> <div class="info-item">
<span class="info-label">公路编号</span> <span class="info-label">公路编号</span>
<span class="info-value">{{ hazardData.roadCode }}</span> <span class="info-value">{{ hazardData.roadCode }}</span>
</div> </div>
</div>
<div class="info-row">
<div class="info-item"> <div class="info-item">
<span class="info-label">位置</span> <span class="info-label">位置</span>
<span class="info-value">{{ hazardData.location }}</span> <span class="info-value">{{ hazardData.location }}</span>
</div> </div>
<div class="info-item">
<span class="info-label">风险类型</span>
<span class="info-value">{{ hazardData.riskType }}</span>
</div>
</div> </div>
</div> </div>
<!-- 风险描述 --> <!-- 风险描述 -->
<div class="info-block"> <div class="info-block">
<div class="block-title">风险描述</div> <div class="block-title">风险描述</div>
@ -55,8 +64,14 @@
<div class="block-content">{{ hazardData.measures }}</div> <div class="block-content">{{ hazardData.measures }}</div>
</div> </div>
<!-- 专家意见 - 仅涉灾隐患点显示 -->
<div v-if="!isRoadData && hazardData.expertOpinion" class="info-block">
<div class="block-title">专家意见</div>
<div class="block-content">{{ hazardData.expertOpinion }}</div>
</div>
<!-- 三级包保责任人 --> <!-- 三级包保责任人 -->
<div class="info-block"> <div class="info-block display jc_sb">
<div class="block-title">三级包保责任人</div> <div class="block-title">三级包保责任人</div>
<div class="responsibility-list"> <div class="responsibility-list">
<div class="responsibility-item"> <div class="responsibility-item">
@ -64,59 +79,122 @@
<span class="responsibility-name">{{ hazardData.trafficDept.name }}</span> <span class="responsibility-name">{{ hazardData.trafficDept.name }}</span>
<span class="responsibility-phone">{{ hazardData.trafficDept.phone }}</span> <span class="responsibility-phone">{{ hazardData.trafficDept.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.trafficDept.frequency }}</span> <span class="responsibility-frequency">{{ hazardData.trafficDept.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.trafficDept)" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.trafficDept)" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.trafficDept)" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
<span class="fs_12">半年巡查一次</span>
</div> </div>
<div class="responsibility-item"> <div class="responsibility-item">
<span class="responsibility-label">公路机构责任人</span> <span class="responsibility-label">公路机构责任人</span>
<span class="responsibility-name">{{ hazardData.roadOrg.name }}</span> <span class="responsibility-name">{{ hazardData.roadOrg.name }}</span>
<span class="responsibility-phone">{{ hazardData.roadOrg.phone }}</span> <span class="responsibility-phone">{{ hazardData.roadOrg.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.roadOrg.frequency }}</span> <span class="responsibility-frequency">{{ hazardData.roadOrg.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.roadOrg)" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.roadOrg)" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.roadOrg)" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
<span class="fs_12">每月巡查一次</span>
</div> </div>
<div class="responsibility-item"> <div class="responsibility-item">
<span class="responsibility-label">养护站责任人</span> <span class="responsibility-label">养护站责任人</span>
<span class="responsibility-name">{{ hazardData.maintenance.name }}</span> <span class="responsibility-name">{{ hazardData.maintenance.name }}</span>
<span class="responsibility-phone">{{ hazardData.maintenance.phone }}</span> <span class="responsibility-phone">{{ hazardData.maintenance.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.maintenance.frequency }}</span> <span class="responsibility-frequency">{{ hazardData.maintenance.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.maintenance)" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.maintenance)" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.maintenance)" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
<span class="fs_12">每周巡查一次</span>
</div> </div>
</div> </div>
</div> </div>
<!-- 护路员 --> <!-- 护路员 -->
<div class="info-row simple-row"> <div class="info-block display jc_sb">
<span class="row-label">护路员</span> <div class="block-title">护路员:</div>
<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="f1 display ai_center jc_end" style="gap: 8px">
<div class="info-row simple-row"> <span class="responsibility-name">{{ hazardData.roadKeeper.name }}</span>
<span class="responsibility-name" style="width: 100px;">{{ hazardData.roadKeeper.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.roadKeeper.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.roadKeeper)" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.roadKeeper)" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.roadKeeper)" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
<span class="fs_12">一周巡查两次</span>
</div>
</div>
<!-- 预警预报关 - 仅涉灾隐患点显示 -->
<div v-if="!isRoadData" class="info-row simple-row">
<span class="row-label">预警预报关</span> <span class="row-label">预警预报关</span>
<span class="row-value">{{ hazardData.earlyWarning }}</span> <!-- <span class="row-value">{{ hazardData.earlyWarning }}</span> -->
</div> </div>
<!-- 线下巡查关 --> <!-- 线下巡查关 - 仅涉灾隐患点显示 -->
<div class="info-row simple-row"> <div v-if="!isRoadData" class="info-row simple-row">
<span class="row-label">线下巡查关</span> <span class="row-label">线下巡查关</span>
<span class="row-value">{{ hazardData.offlinePatrol }}</span> <!-- <span class="row-value">{{ hazardData.offlinePatrol }}</span> -->
</div> </div>
<!-- 交通管控关 --> <!-- 交通管控关 - 仅涉灾隐患点显示 -->
<div class="info-row simple-row"> <div v-if="!isRoadData" class="info-row simple-row">
<span class="row-label">交通管控关</span> <span class="row-label">交通管控关</span>
<span class="row-value">{{ hazardData.trafficControl }}</span> <!-- <span class="row-value">{{ hazardData.trafficControl }}</span> -->
</div> </div>
<!-- 力量预置关 --> <!-- 力量预置关 - 仅涉灾隐患点显示 -->
<div class="info-row simple-row"> <div v-if="!isRoadData" class="info-row simple-row">
<span class="row-label">力量预置关</span> <span class="row-label">力量预置关</span>
<span class="row-value">{{ hazardData.forcePreposition }}</span> <!-- <span class="row-value">{{ hazardData.forcePreposition }}</span> -->
<el-icon class="location-icon"><Location /></el-icon> <el-icon class="location-icon"><Location /></el-icon>
</div> </div>
<!-- 告警阻拦关 --> <!-- 告警阻拦关 - 仅涉灾隐患点显示 -->
<div class="info-row simple-row"> <div v-if="!isRoadData" class="info-row simple-row">
<span class="row-label">告警阻拦关</span> <span class="row-label">告警阻拦关</span>
<span class="row-value">{{ hazardData.alarmBlocking }}</span> <!-- <span class="row-value">{{ hazardData.alarmBlocking }}</span> -->
</div>
<!-- 备注 - 仅涉灾隐患点显示 -->
<div v-if="!isRoadData && hazardData.remark" class="info-block display jc_sb">
<div class="block-title">备注</div>
<!-- <div class="block-content">{{ hazardData.remark }}</div> -->
</div>
<!-- 照片 - 路段数据展示 -->
<div v-if="isRoadData && hazardData.photos" class="info-block display jc_sb">
<div class="block-title">照片</div>
<div class="photo-list">
<img v-for="(photo, index) in hazardData.photos" :key="index" :src="photo" class="photo-item" @click="previewPhoto(photo)" />
</div>
</div> </div>
</div> </div>
</template> </template>
@ -124,9 +202,10 @@
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue'; import { ref, watch, computed } from 'vue'
import { Location } from '@element-plus/icons-vue'; import { Location, VideoCamera, Microphone, Phone } from '@element-plus/icons-vue'
import baseDialog from '../component/baseDialog.vue'; import baseDialog from '../component/baseDialog.vue'
import { openVideoConference } from '../component/index.js'
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -137,16 +216,25 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}), default: () => ({}),
}, },
}); title: {
type: String,
default: '涉灾隐患点情况',
},
})
const emit = defineEmits(['update:visible', 'close']); const emit = defineEmits(['update:visible', 'close', 'video', 'voice', 'call'])
//
const isRoadData = computed(() => {
return props.data?.dataType === 'road'
})
// 使 // 使
const tableColumns = ref([]); const tableColumns = ref([])
const tableData = ref([]); const tableData = ref([])
const total = ref(0); const total = ref(0)
const currentPage = ref(1); const currentPage = ref(1)
const pageSize = ref(10); const pageSize = ref(10)
// //
const hazardData = ref({ const hazardData = ref({
@ -204,44 +292,73 @@ const hazardData = ref({
// //
longitude: '', // GL1_LON longitude: '', // GL1_LON
latitude: '', // GL1_LAT latitude: '', // GL1_LAT
});
//
photos: [], //
})
// //
const handleClose = () => { const handleClose = () => {
emit('update:visible', false); emit('update:visible', false)
emit('close'); emit('close')
}; }
// //
const handleSizeChange = val => { const handleSizeChange = (val) => {
pageSize.value = val; pageSize.value = val
}; }
const handleCurrentChange = val => { const handleCurrentChange = (val) => {
currentPage.value = val; currentPage.value = val
}; }
//
const previewPhoto = (photo) => {
// 使 Element Plus
const { preview } = require('element-plus')
preview(photo)
}
//
const handleVideo = (item) => {
console.log('视频通话:', item)
emit('video', {
...item,
id: hazardData.value.id,
})
}
//
const handleVoice = (item) => {
console.log('语音通话:', item)
emit('voice', item)
}
//
const handleCall = (item) => {
console.log('拨打电话:', item)
emit('call', item)
}
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
newVal => { (newVal) => {
if (newVal && props.data) { if (newVal && props.data) {
// //
const data = props.data; const data = props.data
hazardData.value = { hazardData.value = {
// //
district: data.GL1_QXMC || data.district || '', district: data.GL1_QXMC || data.district || '',
riskLevel: data.GL1_FXDJ || data.riskLevel || '', riskLevel: data.GL1_FXDJ || data.riskLevel || '',
roadCode: data.GL1_GLBH || data.roadCode || '', roadCode: data.GL1_GLBH || data.roadCode || '',
roadName: data.GL1_GLMC || data.roadName || '', roadName: data.GL1_GLMC || data.roadName || '',
location: location: data.GL1_QDZH && data.GL1_ZDZH ? `${data.GL1_QDZH}${data.GL1_ZDZH}` : data.location || '',
data.GL1_QDZH && data.GL1_ZDZH
? `${data.GL1_QDZH}${data.GL1_ZDZH}`
: data.location || '',
riskDescription: data.GL1_FXMS || data.riskDescription || '', riskDescription: data.GL1_FXMS || data.riskDescription || '',
riskType: data.GL1_FXLX || data.riskType || '', riskType: data.GL1_FXLX || data.riskType || '',
measures: data.GL1_CQCS || data.measures || '', measures: data.GL1_CQCS || data.measures || '',
isWithinRedLine: data.GL1_SFHXN || data.isWithinRedLine || '', isWithinRedLine: data.GL1_SFHXN || data.isWithinRedLine || '',
id: data.GL1_ID || '',
// //
trafficDept: { trafficDept: {
@ -286,17 +403,20 @@ watch(
// //
longitude: data.GL1_LON || data.longitude || '', longitude: data.GL1_LON || data.longitude || '',
latitude: data.GL1_LAT || data.latitude || '', latitude: data.GL1_LAT || data.latitude || '',
};
//
photos: data.photos || [],
}
} }
}, },
{ immediate: true } { immediate: true },
); )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.hazard-info-panel { .hazard-info-panel {
height: 500px; height: 500px;
width: 600px; width: 650px;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
overflow-y: auto; overflow-y: auto;
// //
@ -342,7 +462,6 @@ watch(
} }
.row-value { .row-value {
flex: 1;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
font-size: 14px; font-size: 14px;
@ -399,6 +518,7 @@ watch(
padding: 12px; padding: 12px;
background: rgba(64, 169, 255, 0.05); background: rgba(64, 169, 255, 0.05);
border-radius: 4px; border-radius: 4px;
// align-items: center;
.block-title { .block-title {
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
@ -411,6 +531,41 @@ watch(
font-size: 14px; font-size: 14px;
line-height: 1.6; line-height: 1.6;
} }
.responsibility-label {
color: rgba(255, 255, 255, 0.6);
font-size: 13px;
flex-shrink: 0;
}
.responsibility-name {
color: #40a9ff;
font-size: 14px;
flex-shrink: 0;
}
//
.action-btns {
display: flex;
flex-shrink: 0;
display: flex;
align-items: center;
.action-btn {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: #40a9ff;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
border-radius: 4px;
&:hover {
color: #40a9ff;
background: rgba(64, 169, 255, 0.1);
}
}
}
} }
.responsibility-list { .responsibility-list {
@ -427,24 +582,101 @@ watch(
width: 140px; width: 140px;
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
font-size: 13px; font-size: 13px;
flex-shrink: 0;
} }
.responsibility-name { .responsibility-name {
color: #40a9ff; color: #40a9ff;
font-size: 14px; font-size: 14px;
width: 60px; flex-shrink: 0;
} }
.responsibility-phone { .responsibility-phone {
color: #40a9ff; color: #40a9ff;
font-size: 14px; font-size: 14px;
width: 120px; width: 100px;
flex-shrink: 0;
} }
.responsibility-frequency { .responsibility-frequency {
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
font-size: 13px; font-size: 13px;
flex: 1; flex: 1;
min-width: 0;
}
//
.action-btns {
display: flex;
flex-shrink: 0;
display: flex;
align-items: center;
.action-btn {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: #40a9ff;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
border-radius: 4px;
&:hover {
color: #40a9ff;
background: rgba(64, 169, 255, 0.1);
}
}
}
}
}
//
.simple-row {
.action-btns {
display: flex;
margin-left: auto;
.action-btn {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: #40a9ff;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
border-radius: 4px;
&:hover {
color: #40a9ff;
background: rgba(64, 169, 255, 0.1);
}
}
}
}
//
.photo-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
.photo-item {
width: 100px;
height: 100px;
object-fit: cover;
border-radius: 4px;
cursor: pointer;
border: 1px solid rgba(64, 169, 255, 0.3);
transition: all 0.3s ease;
&:hover {
border-color: #40a9ff;
transform: scale(1.05);
} }
} }
} }

View File

@ -68,6 +68,21 @@
<el-option v-for="option in regionOptions" :key="option.value" :label="option.label" :value="option.value" /> <el-option v-for="option in regionOptions" :key="option.value" :label="option.label" :value="option.value" />
</el-select> </el-select>
</div> </div>
<div class="filter-item">
<el-select
:teleported="false"
v-model="filterForm.roadType"
size="small"
placeholder="公路类型"
class="filter-select"
clearable
@change="handleFilterChange"
>
<el-option v-for="option in roadTypeOptions" :key="option.value" :label="option.label" :value="option.value" />
</el-select>
</div>
<div class="filter-item"> <div class="filter-item">
<el-button type="primary" class="search-btn" @click="handleSearch">查询</el-button> <el-button type="primary" class="search-btn" @click="handleSearch">查询</el-button>
</div> </div>
@ -179,7 +194,7 @@
import { ref, computed, watch, onMounted, nextTick } from 'vue' import { ref, computed, watch, onMounted, nextTick } from 'vue'
import { Close, ArrowLeft, ArrowRight } from '@element-plus/icons-vue' import { Close, ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
import { request } from '@/utils/request' import { request } from '@/utils/request'
import { pointTypeOptions, pointLevelOptions, regionOptions } from '../component/index.js' import { pointTypeOptions, pointLevelOptions, regionOptions, roadTypeOptions } from '../component/index.js'
import baseDialog from '../component/baseDialog.vue' import baseDialog from '../component/baseDialog.vue'
import respondedIcon from '../../../assets/xiangying/有回应@2x.png' import respondedIcon from '../../../assets/xiangying/有回应@2x.png'
@ -213,6 +228,7 @@ const filterForm = ref({
pointType: '', pointType: '',
pointLevel: '', pointLevel: '',
region: '', region: '',
roadType: '',
}) })
// 使 // 使
@ -481,6 +497,7 @@ const getTimeParams = () => {
offset: (currentPage.value - 1) * pageSize.value, offset: (currentPage.value - 1) * pageSize.value,
countyName: countyName || '', countyName: countyName || '',
riskLevel: filterForm.value.pointLevel || '', riskLevel: filterForm.value.pointLevel || '',
roadTypes: filterForm.value.roadType || '',
} }
} }
// //
@ -791,6 +808,7 @@ watch(
district: '', district: '',
type: '', type: '',
roadConditionType: '', roadConditionType: '',
roadType: '',
} }
} }
}, },

View File

@ -103,6 +103,7 @@ const emit = defineEmits([
'riskPointStatsChange', 'riskPointStatsChange',
'update:roadvalArr', 'update:roadvalArr',
'openHazardPointSituation', 'openHazardPointSituation',
'openRoadSectionSituation',
]); ]);
// //
@ -846,6 +847,9 @@ const addProjectMarkers = (data, iconUrl, type = 'project') => {
if (type === 'riskPoint') { if (type === 'riskPoint') {
// //
emit('openHazardPointSituation', item); emit('openHazardPointSituation', item);
} else if (type === 'road') {
//
emit('openRoadSectionSituation', item);
} else { } else {
openMapInfoDialog(type, item); openMapInfoDialog(type, item);
} }

View File

@ -1,9 +1,15 @@
// 弹窗组件统一数据配置 // 弹窗组件统一数据配置
import { ref } from 'vue'; import { ref } from 'vue'
import { request } from '@/utils/request'; import { request } from '@/utils/request'
import { ElMessage } from 'element-plus'
// 公路类型选项
export const roadTypeOptions = ref([
{ label: '全部', value: '' },
{ label: '国省道', value: 'G,S' },
{ label: '农村公路', value: ' X, Y, C' },
])
// 影响区域选项 // 影响区域选项
export const regionOptions = ref([]); export const regionOptions = ref([])
// 获取影响区域选项 // 获取影响区域选项
export const fetchDistrictOptions = async () => { export const fetchDistrictOptions = async () => {
@ -11,25 +17,25 @@ export const fetchDistrictOptions = async () => {
const res = await request({ const res = await request({
url: '/snow-ops-platform/sm-event/dashboard/district-options', url: '/snow-ops-platform/sm-event/dashboard/district-options',
method: 'GET', method: 'GET',
}); })
if (res && res.code === '00000' && Array.isArray(res.data)) { if (res && res.code === '00000' && Array.isArray(res.data)) {
// 将接口返回的数据转换为选项格式 // 将接口返回的数据转换为选项格式
const options = res.data.map(item => ({ const options = res.data.map((item) => ({
label: item.qxmc, label: item.qxmc,
value: item.xzdm, value: item.xzdm,
})); }))
// 保留"全部"选项,并添加接口返回的数据 // 保留"全部"选项,并添加接口返回的数据
regionOptions.value = [{ label: '全部', value: '' }, ...options]; regionOptions.value = [{ label: '全部', value: '' }, ...options]
return options; return options
} }
} catch (error) { } catch (error) {
console.error('获取影响区域选项失败:', error); console.error('获取影响区域选项失败:', error)
} }
return regionOptions.value; return regionOptions.value
}; }
// 路况类型选项默认数据会被API数据替换 // 路况类型选项默认数据会被API数据替换
export const typeOptions = ref([]); export const typeOptions = ref([])
// 管控措施选项默认数据会被API数据替换 // 管控措施选项默认数据会被API数据替换
export const controlMeasureOptions = ref([ export const controlMeasureOptions = ref([
@ -39,7 +45,7 @@ export const controlMeasureOptions = ref([
// { label: "限速限车", value: "限速限车" }, // { label: "限速限车", value: "限速限车" },
// { label: "限速", value: "限速" }, // { label: "限速", value: "限速" },
// { label: "告警阻拦", value: "告警阻拦" }, // { label: "告警阻拦", value: "告警阻拦" },
]); ])
// 获取路况类型选项 // 获取路况类型选项
export const fetchRoadConditionOptions = async () => { export const fetchRoadConditionOptions = async () => {
@ -47,22 +53,22 @@ export const fetchRoadConditionOptions = async () => {
const res = await request({ const res = await request({
url: '/snow-ops-platform/sm-event/dashboard/processing-measure-options', url: '/snow-ops-platform/sm-event/dashboard/processing-measure-options',
method: 'GET', method: 'GET',
}); })
if (res && res.code === '00000' && Array.isArray(res.data)) { if (res && res.code === '00000' && Array.isArray(res.data)) {
// 将接口返回的字符串数组转换为选项格式 // 将接口返回的字符串数组转换为选项格式
const options = res.data.map(item => ({ const options = res.data.map((item) => ({
label: item, label: item,
value: item, value: item,
})); }))
// 保留"全部"选项,并添加接口返回的数据 // 保留"全部"选项,并添加接口返回的数据
typeOptions.value = [{ label: '全部', value: '' }, ...options]; typeOptions.value = [{ label: '全部', value: '' }, ...options]
return options; return options
} }
} catch (error) { } catch (error) {
console.error('获取路况类型选项失败:', error); console.error('获取路况类型选项失败:', error)
} }
return typeOptions.value; return typeOptions.value
}; }
// 获取管控措施选项 // 获取管控措施选项
export const fetchControlMeasureOptions = async () => { export const fetchControlMeasureOptions = async () => {
@ -70,34 +76,34 @@ export const fetchControlMeasureOptions = async () => {
const res = await request({ const res = await request({
url: '/snow-ops-platform/sm-event/dashboard/processing-measure-options', url: '/snow-ops-platform/sm-event/dashboard/processing-measure-options',
method: 'GET', method: 'GET',
}); })
if (res && res.code === '00000' && Array.isArray(res.data)) { if (res && res.code === '00000' && Array.isArray(res.data)) {
const options = res.data const options = res.data
.map(item => { .map((item) => {
if (typeof item === 'string') { if (typeof item === 'string') {
return { label: item, value: item }; return { label: item, value: item }
} }
if (item && typeof item === 'object') { if (item && typeof item === 'object') {
const label = item.label ?? item.name ?? item.text ?? item.value ?? item.val; const label = item.label ?? item.name ?? item.text ?? item.value ?? item.val
const value = item.value ?? item.val ?? item.code ?? label; const value = item.value ?? item.val ?? item.code ?? label
if (label == null || value == null) return null; if (label == null || value == null) return null
return { label: String(label), value: String(value) }; return { label: String(label), value: String(value) }
} }
return null; return null
}) })
.filter(Boolean); .filter(Boolean)
if (options.length > 0) { if (options.length > 0) {
controlMeasureOptions.value = options; controlMeasureOptions.value = options
return options; return options
} }
} }
} catch (error) { } catch (error) {
console.error('获取管控措施选项失败:', error); console.error('获取管控措施选项失败:', error)
} }
return controlMeasureOptions.value; return controlMeasureOptions.value
}; }
// 风险等级选项 // 风险等级选项
export const riskLevelOptions = [ export const riskLevelOptions = [
@ -106,7 +112,7 @@ export const riskLevelOptions = [
{ label: '二级', value: '二级' }, { label: '二级', value: '二级' },
{ label: '三级', value: '三级' }, { label: '三级', value: '三级' },
{ label: '四级', value: '四级' }, { label: '四级', value: '四级' },
]; ]
// 影响点类型选项 // 影响点类型选项
export const pointTypeOptions = [ export const pointTypeOptions = [
@ -115,7 +121,7 @@ export const pointTypeOptions = [
{ label: '桥梁', value: 'bridge' }, { label: '桥梁', value: 'bridge' },
{ label: '隧道', value: 'tunnel' }, { label: '隧道', value: 'tunnel' },
{ label: '路面', value: 'road' }, { label: '路面', value: 'road' },
]; ]
// 影响点等级选项 // 影响点等级选项
export const pointLevelOptions = [ export const pointLevelOptions = [
@ -124,14 +130,14 @@ export const pointLevelOptions = [
{ label: '中风险', value: '中风险' }, { label: '中风险', value: '中风险' },
{ label: '较高风险', value: '较高风险' }, { label: '较高风险', value: '较高风险' },
{ label: '高风险', value: '高风险' }, { label: '高风险', value: '高风险' },
]; ]
// 是否回应选项 // 是否回应选项
export const isRespondedOptions = [ export const isRespondedOptions = [
{ label: '全部', value: '' }, { label: '全部', value: '' },
{ label: '是', value: true }, { label: '是', value: true },
{ label: '否', value: false }, { label: '否', value: false },
]; ]
// 预警等级选项 // 预警等级选项
export const warningLevelOptions = [ export const warningLevelOptions = [
@ -140,30 +146,277 @@ export const warningLevelOptions = [
{ label: '橙色预警', value: '橙色预警' }, { label: '橙色预警', value: '橙色预警' },
{ label: '黄色预警', value: '黄色预警' }, { label: '黄色预警', value: '黄色预警' },
{ label: '蓝色预警', value: '蓝色预警' }, { label: '蓝色预警', value: '蓝色预警' },
]; ]
// 是否结束选项 // 是否结束选项
export const isEndedOptions = [ export const isEndedOptions = [
{ label: '全部', value: '' }, { label: '全部', value: '' },
{ label: '是', value: true }, { label: '是', value: true },
{ label: '否', value: false }, { label: '否', value: false },
]; ]
// 影响区域选项(带全部) // 影响区域选项(带全部)
export const regionOptionsWithAll = ref([]); export const regionOptionsWithAll = ref([])
// 格式化日期时间为接口所需格式 // 格式化日期时间为接口所需格式
export const formatDateTime = date => { export 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}`
}; }
// 记录用户操作日志(使用 fetch keepalive 确保页面切换后请求仍能完成)
export const logUserOperation = (type, command) => {
try {
const data = { type, command }
// 使用 fetch 的 keepalive 选项确保页面卸载后请求仍能完成
fetch('/snow-ops-platform/weather-warning/users/logs', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
keepalive: true, // 关键:确保页面切换后请求仍能完成
})
.then((response) => {
console.log('日志请求完成:', response.status)
})
.catch((error) => {
console.error('日志请求失败:', error)
})
console.log('日志已触发发送:', data)
return true
} catch (error) {
console.error('记录操作日志失败:', error)
return false
}
}
// 监听外部应用打开并记录日志的辅助函数
const listenForAppLaunch = (type, command) => {
let hasLogged = false
let hasLostFocus = false // 是否已经失去焦点
let focusTimer = null // 用于延迟检测的定时器
const startTime = Date.now()
console.log('开始监听外部应用打开...', { type, command, initialHidden: document.hidden, startTime })
// 确认打开外部应用
const confirmLaunch = () => {
if (hasLogged) return
hasLogged = true
console.log('确认用户点击了"打开"按钮,调用日志接口')
logUserOperation(type, command)
cleanup()
}
// 检测打开状态
const checkLaunchStatus = () => {
if (hasLogged) return
const now = Date.now()
const elapsed = now - startTime
const isHidden = document.hidden
const currentHasFocus = document.hasFocus()
console.log(`检测状态 [${elapsed}ms]:`, { isHidden, hasFocus: currentHasFocus, hasLostFocus, hasLogged })
// 情况1: 页面被隐藏 → 用户点击了"打开"
if (isHidden) {
confirmLaunch()
return
}
// 情况2: 失去焦点后重新获得焦点 → 用户点击了"取消"
if (hasLostFocus && currentHasFocus) {
console.log('用户点击了"取消"按钮,不记录日志')
cleanup()
return
}
// 记录当前焦点状态
if (!currentHasFocus && !hasLostFocus) {
hasLostFocus = true
console.log('页面失去焦点,开始等待用户选择...')
// 设置延迟检测1.5秒后如果仍未获得焦点,认为用户点击了"打开"
focusTimer = setTimeout(() => {
if (!hasLogged && hasLostFocus && !document.hasFocus()) {
console.log('1.5秒未重新获得焦点,认为用户点击了"打开"')
confirmLaunch()
}
}, 1500)
}
}
// 方法1: 监听 visibilitychange 事件
const handleVisibilityChange = () => {
console.log('visibilitychange 触发, document.hidden:', document.hidden)
checkLaunchStatus()
}
// 方法2: 监听 window blur 事件
const handleWindowBlur = () => {
console.log('window blur 触发')
hasLostFocus = true
// 设置延迟检测1.5秒后如果仍未获得焦点,认为用户点击了"打开"
focusTimer = setTimeout(() => {
if (!hasLogged && hasLostFocus && !document.hasFocus()) {
console.log('1.5秒未重新获得焦点,认为用户点击了"打开"')
confirmLaunch()
}
}, 1500)
}
// 方法3: 监听 window focus 事件(判断用户是否点击取消)
const handleWindowFocus = () => {
console.log('window focus 触发')
checkLaunchStatus()
}
// 方法4: 定时轮询检测
let checkInterval = setInterval(() => {
checkLaunchStatus()
const elapsed = Date.now() - startTime
// 10秒后停止轮询
if (elapsed > 10000 || hasLogged) {
clearInterval(checkInterval)
}
}, 200)
// 清理函数
const cleanup = () => {
console.log('清理监听器')
clearInterval(checkInterval)
clearTimeout(focusTimer)
document.removeEventListener('visibilitychange', handleVisibilityChange)
window.removeEventListener('blur', handleWindowBlur)
window.removeEventListener('focus', handleWindowFocus)
}
document.addEventListener('visibilitychange', handleVisibilityChange)
window.addEventListener('blur', handleWindowBlur)
window.addEventListener('focus', handleWindowFocus)
// 10秒后自动清理
setTimeout(() => {
if (!hasLogged) {
console.log('10秒超时未检测到打开操作清理监听器')
cleanup()
}
}, 10000)
}
// 打开视频会议
export const openVideoConference = async (item) => {
console.log('打开视频会议:', item)
if (!item || !item.name || !item.phone) {
console.warn('缺少姓名或电话信息')
return
}
try {
// 调用接口获取 user-id
const res = await request({
url: '/snow-ops-platform/weather-warning/user-id',
method: 'GET',
params: {
name: item.name,
phone: item.phone,
},
})
const userId = 1279134
if (res.code === '00000') {
// const userId = res.data
const url = `taurusykz://taurusclient/action/avmeeting/conferenceCreateByIds?title=重庆渝路畅行风险预警&isVideoConference=true&calleeStaffIds=${userId}`
window.location.href = url
// 监听用户点击"打开"按钮后记录日志
let jsobj = {
name: item.name,
phone: item.phone,
id: item.id,
userId: userId,
text: '打开视频会议',
}
logUserOperation('launch-video-conference', JSON.stringify(jsobj))
} else {
console.error('获取 user-id 失败:', res)
// 非系统用户, 操作无法执行
ElMessage.warning('非系统用户, 操作无法执行')
logUserOperation('launch-video-conference', '非系统用户, 操作无法执行')
}
} catch (error) {
console.error('获取 user-id 出错:', error)
}
}
// 打开语音通话
export const openVoiceConference = async (item) => {
console.log('打开语音通话:', item)
if (!item || !item.name || !item.phone) {
console.warn('缺少姓名或电话信息')
return
}
try {
// 调用接口获取 user-id
const res = await request({
url: '/snow-ops-platform/weather-warning/user-id',
method: 'GET',
params: {
name: item.name,
phone: item.phone,
},
})
if (res.code === '00000' && res.data != null) {
const userId = res.data
const url = `taurusykz://taurusclient/action/avmeeting/conferenceCreateByIds?title=重庆渝路畅行风险预警&isVideoConference=false&calleeStaffIds=${userId}`
window.location.href = url
// 监听用户点击"打开"按钮后记录日志
let jsobj = {
name: item.name,
phone: item.phone,
id: item.id,
userId: userId,
text: '打开语音通话',
}
logUserOperation('launch-audio-conference', JSON.stringify(jsobj))
} else {
console.error('获取 user-id 失败:', res)
// 非系统用户, 操作无法执行
ElMessage.warning('非系统用户, 操作无法执行')
logUserOperation('launch-audio-conference', '非系统用户, 操作无法执行')
}
} catch (error) {
console.error('获取 user-id 出错:', error)
}
}
// 打开拨打电话
export const opencallConference = async (item) => {
console.log('打开拨打电话:', item)
if (!item || !item.name || !item.phone) {
console.warn('缺少姓名或电话信息')
return
}
// 监听用户点击"打开"按钮后记录日志
let jsobj = {
name: item.name,
phone: item.phone,
id: item.id,
userId: '',
text: '拨打电话',
}
// listenForAppLaunch('launch-audio-conference', JSON.stringify(jsobj))
logUserOperation('phone-based-confirmation', JSON.stringify(jsobj))
}
// 默认导出所有选项 // 默认导出所有选项
export default { export default {
@ -181,4 +434,7 @@ export default {
fetchRoadConditionOptions, fetchRoadConditionOptions,
fetchDistrictOptions, fetchDistrictOptions,
fetchControlMeasureOptions, fetchControlMeasureOptions,
}; openVideoConference,
openVoiceConference,
opencallConference,
}

View File

@ -4,11 +4,7 @@
<img class="title_bg" src="../../assets/RiskWarning_img/一级标题栏bg@2x.png" alt="" /> <img class="title_bg" src="../../assets/RiskWarning_img/一级标题栏bg@2x.png" alt="" />
<div class="title_img_box"> <div class="title_img_box">
<img class="title_img1" src="../../assets/RiskWarning_img/位图@2x.png" alt="" /> <img class="title_img1" src="../../assets/RiskWarning_img/位图@2x.png" alt="" />
<img <img class="title_img2" src="../../assets/RiskWarning_img/渝路畅行-风险预警一键响应@2x.png" alt="" />
class="title_img2"
src="../../assets/RiskWarning_img/渝路畅行-风险预警一键响应@2x.png"
alt=""
/>
</div> </div>
</div> </div>
@ -20,12 +16,7 @@
<div class="corner corner-bottom-left"></div> <div class="corner corner-bottom-left"></div>
<div class="corner corner-bottom-right"></div> <div class="corner corner-bottom-right"></div>
<!-- 中心数据展示卡片 --> <!-- 中心数据展示卡片 -->
<centerInfoCard <centerInfoCard :type="showCenterCard.type" :peopleCount="showCenterCard.value" roadCount="117" @click="handleCenterCardClick" />
:type="showCenterCard.type"
:peopleCount="showCenterCard.value"
roadCount="117"
@click="handleCenterCardClick"
/>
<div class="left"> <div class="left">
<left <left
@ -40,7 +31,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)"
@openOfflineHelp="openDialog('offlineHelp')" @openOfflineHelp="openDialog('offlineHelp')"
@openImageInspection="openDialog('imageInspection')" @openImageInspection="openDialog('imageInspection')"
></left> ></left>
@ -70,6 +61,7 @@
@riskPointStatsChange="handleRiskPointStatsChange" @riskPointStatsChange="handleRiskPointStatsChange"
@update:roadvalArr="updateRoadvalArr" @update:roadvalArr="updateRoadvalArr"
@openHazardPointSituation="handleOpenHazardPointSituation" @openHazardPointSituation="handleOpenHazardPointSituation"
@openRoadSectionSituation="handleOpenRoadSectionSituation"
/> />
</div> </div>
@ -127,15 +119,12 @@
:message="confirmConfig.message" :message="confirmConfig.message"
:confirm-text="confirmConfig.confirmText" :confirm-text="confirmConfig.confirmText"
:cancel-text="confirmConfig.cancelText" :cancel-text="confirmConfig.cancelText"
@confirm="closeDialog('confirm')" @confirm="confirmCall"
@cancel="closeDialog('confirm')" @cancel="closeDialog('confirm')"
/> />
<!-- 风险点详情对话框 --> <!-- 风险点详情对话框 -->
<riskPointDetailDialog <riskPointDetailDialog v-model:visible="dialogVisible.riskPointDetail" @close="closeDialog('riskPointDetail')" />
v-model:visible="dialogVisible.riskPointDetail"
@close="closeDialog('riskPointDetail')"
/>
<!-- 影响点情况对话框 --> <!-- 影响点情况对话框 -->
<impactPointDialog <impactPointDialog
@ -154,16 +143,10 @@
/> />
<!-- 响应点详情对话框 --> <!-- 响应点详情对话框 -->
<responsePointDetailDialog <responsePointDetailDialog v-model:visible="dialogVisible.responsePointDetail" @close="closeDialog('responsePointDetail')" />
v-model:visible="dialogVisible.responsePointDetail"
@close="closeDialog('responsePointDetail')"
/>
<!-- 响应点信息对话框 --> <!-- 响应点信息对话框 -->
<responsePointInfoDialog <responsePointInfoDialog v-model:visible="dialogVisible.responsePointInfo" @close="closeDialog('responsePointInfo')" />
v-model:visible="dialogVisible.responsePointInfo"
@close="closeDialog('responsePointInfo')"
/>
<!-- 响应状态对话框 --> <!-- 响应状态对话框 -->
<responseStatusDialog <responseStatusDialog
@ -174,10 +157,7 @@
/> />
<!-- AI预警处理结果对话框 --> <!-- AI预警处理结果对话框 -->
<aiWarningResultDialog <aiWarningResultDialog v-model:visible="dialogVisible.aiWarningResult" @close="closeDialog('aiWarningResult')" />
v-model:visible="dialogVisible.aiWarningResult"
@close="closeDialog('aiWarningResult')"
/>
<!-- 潼南基本信息对话框 --> <!-- 潼南基本信息对话框 -->
<tongnanInfoDialog <tongnanInfoDialog
@ -213,16 +193,10 @@
/> />
<!-- 管控情况对话框 --> <!-- 管控情况对话框 -->
<controlSituationDialog <controlSituationDialog v-model:visible="dialogVisible.controlSituation" @close="closeDialog('controlSituation')" />
v-model:visible="dialogVisible.controlSituation"
@close="closeDialog('controlSituation')"
/>
<!-- 调度详情对话框 --> <!-- 调度详情对话框 -->
<dispatchDetailDialog <dispatchDetailDialog v-model:visible="dialogVisible.dispatchDetail" @close="closeDialog('dispatchDetail')" />
v-model:visible="dialogVisible.dispatchDetail"
@close="closeDialog('dispatchDetail')"
/>
<!-- 调度区县情况对话框 --> <!-- 调度区县情况对话框 -->
<dispatchDistrictDialog <dispatchDistrictDialog
@ -250,89 +224,81 @@
/> />
<!-- 隧道信息对话框 --> <!-- 隧道信息对话框 -->
<tunnelInfoDialog <tunnelInfoDialog v-model:visible="dialogVisible.tunnelInfo" @close="closeDialog('tunnelInfo')" />
v-model:visible="dialogVisible.tunnelInfo"
@close="closeDialog('tunnelInfo')"
/>
<hazardPointSituationDialog <hazardPointSituationDialog
v-model:visible="dialogVisible.hazardPointSituation" v-model:visible="dialogVisible.hazardPointSituation"
:data="hazardPointData" :data="hazardPointData"
:title="hazardPointDialogTitle"
@close="closeDialog('hazardPointSituation')" @close="closeDialog('hazardPointSituation')"
@voice="openVoiceConference"
@video="openVideoConference"
@call="handleCallClick"
/> />
<offlineHelpDialog <offlineHelpDialog v-model:visible="dialogVisible.offlineHelp" @close="closeDialog('offlineHelp')" />
v-model:visible="dialogVisible.offlineHelp"
@close="closeDialog('offlineHelp')"
/>
<!-- 抽查人次对话框 --> <!-- 抽查人次对话框 -->
<imageInspectionDialog <imageInspectionDialog v-model:visible="dialogVisible.imageInspection" @close="closeDialog('imageInspection')" />
v-model:visible="dialogVisible.imageInspection"
@close="closeDialog('imageInspection')"
/>
<!-- 巡查里程对话框 --> <!-- 巡查里程对话框 -->
<patrolMileageDialog <patrolMileageDialog v-model:visible="dialogVisible.patrolMileage" @close="closeDialog('patrolMileage')" />
v-model:visible="dialogVisible.patrolMileage"
@close="closeDialog('patrolMileage')"
/>
<!-- 巡查情况对话框 --> <!-- 巡查情况对话框 -->
<patrolSituationDialog <patrolSituationDialog v-model:visible="dialogVisible.patrolSituation" @close="closeDialog('patrolSituation')" />
v-model:visible="dialogVisible.patrolSituation"
@close="closeDialog('patrolSituation')"
/>
</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 { import {
fetchRoadConditionOptions, fetchRoadConditionOptions,
fetchDistrictOptions, fetchDistrictOptions,
fetchControlMeasureOptions, fetchControlMeasureOptions,
} from './component/index.js'; openVideoConference,
openVoiceConference,
opencallConference,
} 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 tongnanProjectPersonDialog from './Dialog/tongnanProjectPersonDialog.vue'
import hazardPointSituationDialog from './Dialog/hazardPointSituationDialog.vue'; import hazardPointSituationDialog from './Dialog/hazardPointSituationDialog.vue'
import offlineHelpDialog from './Dialog/offlineHelpDialog.vue'; import offlineHelpDialog from './Dialog/offlineHelpDialog.vue'
import imageInspectionDialog from './Dialog/imageInspectionDialog.vue'; import imageInspectionDialog from './Dialog/imageInspectionDialog.vue'
import patrolMileageDialog from './Dialog/patrolMileageDialog.vue'; import patrolMileageDialog from './Dialog/patrolMileageDialog.vue'
import patrolSituationDialog from './Dialog/patrolSituationDialog.vue'; import patrolSituationDialog from './Dialog/patrolSituationDialog.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({
@ -362,8 +328,8 @@ const dialogVisible = ref({
imageInspection: false, imageInspection: false,
patrolMileage: false, patrolMileage: false,
patrolSituation: false, patrolSituation: false,
}); })
const activeitem = ref({}); const activeitem = ref({})
// //
const riskPointStats = ref({ const riskPointStats = ref({
@ -374,169 +340,186 @@ const riskPointStats = ref({
一般路内隐患点: 0, 一般路内隐患点: 0,
一般路外隐患点: 0, 一般路外隐患点: 0,
风险点总数: 0, 风险点总数: 0,
}); })
// //
const hazardPointData = ref({}); const hazardPointData = ref({})
//
const hazardPointDialogTitle = 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
}; }
// //
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 showRoadStats = ref(false); const showRoadStats = ref(false)
const roadItemClick = item => { const roadItemClick = (item) => {
console.log('点击路段:', item); console.log('点击路段:', item)
roadItem.value = item; roadItem.value = item
showRoadStats.value = true; showRoadStats.value = true
}; }
// //
const handleHideRoadStats = () => { const handleHideRoadStats = () => {
console.log('隐藏路段统计'); console.log('隐藏路段统计')
showRoadStats.value = false; showRoadStats.value = false
}; }
// //
const handleHazardItemClick = item => { const handleHazardItemClick = (item) => {
console.log('点击隐患点:', item); console.log('点击隐患点:', item)
// //
if (chongqingMapRef.value) { if (chongqingMapRef.value) {
chongqingMapRef.value.handleHazardItemClick(item); chongqingMapRef.value.handleHazardItemClick(item)
} }
}; }
const showHazardPopup = ref(false); const showHazardPopup = ref(false)
const showHazardPopupfn = val => { const showHazardPopupfn = (val) => {
showHazardPopup.value = val; showHazardPopup.value = val
}; }
// //
const handleRiskPointStatsChange = stats => { const handleRiskPointStatsChange = (stats) => {
console.log('风险点统计数据变化:', stats); console.log('风险点统计数据变化:', stats)
riskPointStats.value = stats; riskPointStats.value = stats
}; }
// //
const roadvalArrtrue = ref([]); const roadvalArrtrue = ref([])
const updateRoadvalArr = roadvalArr => { const updateRoadvalArr = (roadvalArr) => {
roadvalArrtrue.value = roadvalArr; roadvalArrtrue.value = roadvalArr
// let num = 0; // let num = 0;
// roadvalArrtrue.value.forEach(item => { // roadvalArrtrue.value.forEach(item => {
// num += item.value; // num += item.value;
// }); // });
// roadvalArrtrue.value.push({ label: '', value: num }); // roadvalArrtrue.value.push({ label: '', value: num });
console.log('更新路段统计数据:', roadvalArr); console.log('更新路段统计数据:', roadvalArr)
console.log('更新路段统计数据:', roadvalArrtrue); 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
} }
}; }
// //
const clearMapMarkers = () => { const clearMapMarkers = () => {
console.log('清除地图标记'); console.log('清除地图标记')
if (chongqingMapRef.value) { if (chongqingMapRef.value) {
chongqingMapRef.value.clearProjectMarkers(); chongqingMapRef.value.clearProjectMarkers()
} }
}; }
// //
const handleClearFilters = () => { const handleClearFilters = () => {
console.log('index.vue 处理清除筛选事件'); console.log('index.vue 处理清除筛选事件')
// //
clearMapMarkers(); clearMapMarkers()
// //
activeitem.value = {}; activeitem.value = {}
roadItem.value = {}; roadItem.value = {}
showHazardPopup.value = false; 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 tongnanInfoItemData = ref({})
const tongnanInfoItemDatafn = item => { const tongnanInfoItemDatafn = (item) => {
console.log('点击详情:', item); console.log('点击详情:', item)
tongnanInfoItemData.value = 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 => { const handleOpenHazardPointSituation = (item) => {
console.log('打开涉灾隐患点情况弹窗:', item); console.log('打开涉灾隐患点情况弹窗:', item)
hazardPointData.value = item; hazardPointDialogTitle.value = '涉灾隐患点情况'
dialogVisible.value.hazardPointSituation = true; hazardPointData.value = item
}; dialogVisible.value.hazardPointSituation = true
}
//
const handleOpenRoadSectionSituation = (item) => {
console.log('打开路段情况弹窗:', item)
hazardPointDialogTitle.value = '路段情况'
//
hazardPointData.value = {
...item,
dataType: 'road',
}
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 clearanceSituationDialogItemData = ref({}); const clearanceSituationDialogItemData = ref({})
const handleItemData = item => { const handleItemData = (item) => {
console.log('点击详情:', item); console.log('点击详情:', item)
clearanceSituationDialogItemData.value = item; clearanceSituationDialogItemData.value = item
}; }
const dispatchDateRange = ref([]); const dispatchDateRange = ref([])
const handleDispatchDateRange = range => { const handleDispatchDateRange = (range) => {
dispatchDateRange.value = range; dispatchDateRange.value = range
}; }
const rightDateRange = ref([]); const rightDateRange = ref([])
const updateDateRange = range => { const updateDateRange = (range) => {
console.log('更新日期范围:', range); console.log('更新日期范围:', range)
rightDateRange.value = range; rightDateRange.value = range
}; }
const filterForm = ref({}); const filterForm = ref({})
const updateFilterForm = item => { const updateFilterForm = (item) => {
console.log('更新筛选表单:', item); console.log('更新筛选表单:', item)
filterForm.value = item; filterForm.value = item
}; }
// //
const confirmConfig = ref({ const confirmConfig = ref({
@ -544,63 +527,82 @@ const confirmConfig = ref({
message: '是否拨打电话?', message: '是否拨打电话?',
confirmText: '确定', confirmText: '确定',
cancelText: '取消', cancelText: '取消',
}); })
//
const currentCallItem = ref(null)
//
const handleCallClick = (item) => {
console.log('准备拨打电话:', item)
currentCallItem.value = item
openConfirm({
title: '拨打电话',
message: `是否拨打电话: ${item.phone || item.name || ''}?`,
})
}
// //
const openConfirm = config => { const openConfirm = (config) => {
confirmConfig.value = { ...confirmConfig.value, ...config }; confirmConfig.value = { ...confirmConfig.value, ...config }
dialogVisible.value.confirm = true; dialogVisible.value.confirm = true
}; }
//
const confirmCall = () => {
if (currentCallItem.value) {
opencallConference(currentCallItem.value)
currentCallItem.value = null
}
closeDialog('confirm')
}
// //
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) {
const cardData = { const cardData = {
title: getCardTitleByType(item.type), title: getCardTitleByType(item.type),
dataList: item.data, dataList: item.data,
}; }
chongqingMapRef.value.openCenterCard(cardData); chongqingMapRef.value.openCenterCard(cardData)
// //
if (item.data.length > 0 && (item.data[0].countyName || item.data[0].name)) { if (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)
} }
} }
}; }
// //
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") {
// openDialog("tongnanTeam"); // openDialog("tongnanTeam");
// } else if (item.type === "third") { // } else if (item.type === "third") {
@ -608,47 +610,47 @@ const handleCenterCardClickType = item => {
// } else if (item.type === "first") { // } else if (item.type === "first") {
// openDialog("warningSituation"); // openDialog("warningSituation");
// } // }
}; }
// //
const refreshLeftData = ref(null); 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
}; }
// //
const triggerRefreshLeftData = () => { const triggerRefreshLeftData = () => {
if (refreshLeftData.value) { if (refreshLeftData.value) {
refreshLeftData.value(); refreshLeftData.value()
} }
// right.vue // right.vue
if (refreshRightData.value) { if (refreshRightData.value) {
refreshRightData.value(); refreshRightData.value()
} }
}; }
// //
provide('setRefreshLeftData', setRefreshLeftData); provide('setRefreshLeftData', setRefreshLeftData)
provide('triggerRefreshLeftData', triggerRefreshLeftData); provide('triggerRefreshLeftData', triggerRefreshLeftData)
provide('setRefreshRightData', setRefreshRightData); provide('setRefreshRightData', setRefreshRightData)
provide('getdateRange', getdateRange); provide('getdateRange', getdateRange)
// ==================== ==================== // ==================== ====================
const mapStore = useMapStore(); const mapStore = useMapStore()
/** /**
* 加载地图的业务底图与聚焦中心点 * 加载地图的业务底图与聚焦中心点
*/ */
const mapBase = useMapBase(mapStore); const mapBase = useMapBase(mapStore)
// ==================== ==================== // ==================== ====================
@ -657,11 +659,11 @@ const mapBase = useMapBase(mapStore);
*/ */
onMounted(() => { onMounted(() => {
// //
mapBase.loadBaseData(); mapBase.loadBaseData()
fetchRoadConditionOptions(); // fetchRoadConditionOptions() //
fetchDistrictOptions(); // fetchDistrictOptions() //
fetchControlMeasureOptions(); // fetchControlMeasureOptions() //
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,7 +1,9 @@
<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> <!-- <span class="filter-item active" @click="handleDateRangeClick()">本轮</span> -->
<span class="filter-item active" @click="handleDateRangeClick('total')">累计</span>
<span class="filter-item active" @click="handleDateRangeClick('today')">今日</span>
<div class="date-range-wrapper"> <div class="date-range-wrapper">
<el-date-picker <el-date-picker
v-model="dateRange" v-model="dateRange"
@ -17,12 +19,7 @@
</div> </div>
</div> </div>
<div class="hazard-stats" v-if="showHazardPopup"> <div class="hazard-stats" v-if="showHazardPopup">
<div <div v-for="(item, index) in hazardStatsShowArr" :key="index" class="stat-item" :class="item.class">
v-for="(item, index) in hazardStatsShowArr"
:key="index"
class="stat-item"
:class="item.class"
>
<span class="stat-label">{{ item.label }}</span> <span class="stat-label">{{ item.label }}</span>
<span class="stat-value-container display ai_center"> <span class="stat-value-container display ai_center">
<span class="stat-value">{{ item.value }}</span> <span class="stat-value">{{ item.value }}</span>
@ -43,9 +40,9 @@
</template> </template>
<script setup> <script setup>
import { ref, watch, inject, defineProps, nextTick, provide, onMounted } 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'; import { request } from '@/utils/request'
const props = defineProps({ const props = defineProps({
riskPointStats: { riskPointStats: {
@ -68,26 +65,26 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}); })
watch( watch(
() => props.showHazardPopup, () => props.showHazardPopup,
newShow => { (newShow) => {
hazardStatsShowArr.value = JSON.parse(JSON.stringify([])); hazardStatsShowArr.value = JSON.parse(JSON.stringify([]))
hazardStats.value.forEach(item => { hazardStats.value.forEach((item) => {
item.value = 0; item.value = 0
item.show = false; item.show = false
}); })
} },
); )
const emit = defineEmits(['openAIResult', 'dateRangeChange']); const emit = defineEmits(['openAIResult', 'dateRangeChange'])
// //
const triggerRefreshLeftData = inject('triggerRefreshLeftData'); const triggerRefreshLeftData = inject('triggerRefreshLeftData')
const dateRange = ref([]); const dateRange = ref([])
// //
const hazardStatsShowArr = ref([]); const hazardStatsShowArr = ref([])
const hazardStats = 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: '否' },
@ -96,7 +93,7 @@ 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: '' },
]); ])
// //
const roadStats = ref([ const roadStats = ref([
@ -105,28 +102,24 @@ const roadStats = ref([
{ label: '中风险路段', value: 0, type: '中风险路段' }, { label: '中风险路段', value: 0, type: '中风险路段' },
{ label: '低风险路段', value: 0, type: '低风险路段' }, { label: '低风险路段', value: 0, type: '低风险路段' },
{ label: '风险点总数', value: 0, type: '风险点总数' }, { label: '风险点总数', value: 0, type: '风险点总数' },
]); ])
watch( watch(
() => props.riskPointStats, () => props.riskPointStats,
newStats => { (newStats) => {
console.log('top.vue 收到风险点统计数据:', newStats); console.log('top.vue 收到风险点统计数据:', newStats)
if (newStats) { if (newStats) {
hazardStatsShowArr.value = []; hazardStatsShowArr.value = []
hazardStats.value.forEach(item => { hazardStats.value.forEach((item) => {
if ( if (item.label.includes(newStats.riskLevel) && newStats.isWithinRedLine == item.isWithinRedLine && newStats.value >= 0) {
item.label.includes(newStats.riskLevel) && item.value = newStats.value
newStats.isWithinRedLine == item.isWithinRedLine && item.show = true
newStats.value >= 0
) {
item.value = newStats.value;
item.show = true;
} }
if (item.show) { if (item.show) {
hazardStatsShowArr.value.push(item); hazardStatsShowArr.value.push(item)
hazardStats.value[6].show = true; hazardStats.value[6].show = true
} }
}); })
hazardStats.value[6].value = hazardStats.value[6].value =
hazardStats.value[0].value + hazardStats.value[0].value +
@ -134,51 +127,64 @@ watch(
hazardStats.value[2].value + hazardStats.value[2].value +
hazardStats.value[3].value + hazardStats.value[3].value +
hazardStats.value[4].value + hazardStats.value[4].value +
hazardStats.value[5].value; hazardStats.value[5].value
} }
}, },
{ immediate: true, deep: true } { 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)
return d; return d
}; }
// //
const handleDateRangeClick = () => { const handleDateRangeClick = (type) => {
dateRange.value = []; const now = new Date()
if (type === 'total') {
// 11 00:00:00 23:59:59
const startOfYear = new Date(now.getFullYear(), 0, 1, 0, 0, 0, 0)
const endOfYear = new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999)
dateRange.value = [startOfYear, endOfYear]
} else if (type === 'today') {
// 00:00:00 23:59:59
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0)
const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999)
dateRange.value = [startOfDay, endOfDay]
} else {
dateRange.value = []
}
// triggerRefreshLeftData(); // triggerRefreshLeftData();
// emitwatch dateRange emit // emitwatch dateRange emit
}; }
// dateRange // dateRange
watch( 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])
} }
// //
// if (triggerRefreshLeftData) { // if (triggerRefreshLeftData) {
// triggerRefreshLeftData(); // triggerRefreshLeftData();
// } // }
// //
emit('dateRangeChange', newVal); emit('dateRangeChange', newVal)
} }
}, },
{ deep: true } { deep: true },
); )
const handleAIClick = () => { const handleAIClick = () => {
emit('openAIResult'); emit('openAIResult')
}; }
// //
const fetchRiskLevelCount = async () => { const fetchRiskLevelCount = async () => {
@ -186,35 +192,35 @@ const fetchRiskLevelCount = async () => {
const res = await request({ const res = await request({
url: '/snow-ops-platform/risk-point/risk-level-count', url: '/snow-ops-platform/risk-point/risk-level-count',
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
let roadTotal = 0; let roadTotal = 0
roadStats.value.forEach(item => { roadStats.value.forEach((item) => {
// 0 // 0
item.value = 0; item.value = 0
// //
const matchedData = data.find(d => item.label.includes(d.level)); const matchedData = data.find((d) => item.label.includes(d.level))
if (matchedData) { if (matchedData) {
item.value = Number(matchedData.count); item.value = Number(matchedData.count)
roadTotal += Number(matchedData.count); roadTotal += Number(matchedData.count)
} }
}); })
// //
roadStats.value[4].value = roadTotal; roadStats.value[4].value = roadTotal
console.log('更新后的roadStats:', roadStats.value); console.log('更新后的roadStats:', roadStats.value)
} }
} catch (error) { } catch (error) {
console.error('获取风险等级统计数据失败:', error); console.error('获取风险等级统计数据失败:', error)
} }
}; }
// //
onMounted(() => { onMounted(() => {
fetchRiskLevelCount(); fetchRiskLevelCount()
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>