修改大屏的地图,使用天地图。进入页面加载涉灾隐患点数据,修改所有大屏项目文字改为驻地,大屏驻地图标加载优化,去除本轮字段,增加网络电话弹窗。

This commit is contained in:
fanjia 2026-05-07 09:32:05 +08:00
parent 3b23b530d9
commit de2d0184a9
20 changed files with 2245 additions and 1888 deletions

View File

@ -399,7 +399,7 @@ const currentWarningInfo = computed(() => {
// //
const impactTabs = ref([ const impactTabs = ref([
{ key: 'point', label: '影响点' }, { key: 'point', label: '影响点' },
{ key: 'project', label: '影响项目' }, { key: 'project', label: '影响驻地' },
]); ]);
const activeImpactTab = ref('project'); const activeImpactTab = ref('project');
@ -413,7 +413,7 @@ const aiiTypeArr = ref([
{ number: '21', label: '风险路段' }, { number: '21', label: '风险路段' },
{ number: '21', label: '桥梁' }, { number: '21', label: '桥梁' },
{ number: '21', label: '隧道' }, { number: '21', label: '隧道' },
{ number: '21', label: '项目' }, { number: '21', label: '驻地' },
]); ]);
// //
const impactProjectDataTable = ref([ const impactProjectDataTable = ref([

View File

@ -116,7 +116,14 @@ watch(
(newVal) => { (newVal) => {
console.log('newVal', newVal) console.log('newVal', newVal)
if (newVal.label) { if (newVal.label) {
filterForm.value.roadConditionType = newVal.label.substring(0, newVal.label.length - 1) || '' // label
const labelMap = {
封闭管控数: '全幅封闭',
告警阻拦处数: '告警阻拦',
'限速(限车型)数': '限速',
半幅通行数: '半幅封闭',
}
filterForm.value.roadConditionType = labelMap[newVal.label] || newVal.label.substring(0, newVal.label.length - 1) || ''
currentPage.value = 1 currentPage.value = 1
fetchData() fetchData()
} else { } else {

View File

@ -1,39 +1,51 @@
<template> <template>
<div v-if="visible" class="confirm-dialog-overlay" @click="handleOverlayClick"> <div>
<div class="confirm-dialog" @click.stop> <!-- 确认弹窗 -->
<!-- 四个角的装饰 --> <div v-if="visible" class="confirm-dialog-overlay" @click="handleOverlayClick">
<div class="corner corner-top-left"></div> <div class="confirm-dialog" @click.stop>
<div class="corner corner-top-right"></div> <!-- 四个角的装饰 -->
<div class="corner corner-bottom-left"></div> <div class="corner corner-top-left"></div>
<div class="corner corner-bottom-right"></div> <div class="corner corner-top-right"></div>
<!-- 标题栏 --> <div class="corner corner-bottom-left"></div>
<div class="dialog-header"> <div class="corner corner-bottom-right"></div>
<div class="header-title">{{ title }}</div> <!-- 标题栏 -->
<div class="close-btn" @click="handleCancel"> <div class="dialog-header">
<el-icon><Close /></el-icon> <div class="header-title">{{ title }}</div>
<div class="close-btn" @click="handleCancel">
<el-icon><Close /></el-icon>
</div>
</div>
<!-- 提示内容 -->
<div class="dialog-content">
<p class="confirm-message">{{ message }}</p>
</div>
<!-- 按钮区域 -->
<div class="dialog-footer">
<el-button type="primary" class="btn-confirm" @click="handleCancel">
{{ cancelText }}
</el-button>
<el-button type="primary" class="btn-confirm" @click="handleConfirm">
{{ confirmText }}
</el-button>
</div> </div>
</div> </div>
<!-- 提示内容 -->
<div class="dialog-content">
<p class="confirm-message">{{ message }}</p>
</div>
<!-- 按钮区域 -->
<div class="dialog-footer">
<el-button type="primary" class="btn-confirm" @click="handleCancel">
{{ cancelText }}
</el-button>
<el-button type="primary" class="btn-confirm" @click="handleConfirm">
{{ confirmText }}
</el-button>
</div>
</div> </div>
<!-- 软电话配置弹窗 -->
<SoftPhoneConfigDialog
v-model:visible="softPhoneVisible"
@confirm="handleSoftPhoneConfirm"
@cancel="handleSoftPhoneCancel"
/>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue';
import { Close } from '@element-plus/icons-vue'; import { Close } from '@element-plus/icons-vue';
import SoftPhoneConfigDialog from './softPhoneConfigDialog.vue';
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -60,12 +72,28 @@ const props = defineProps({
const emit = defineEmits(['update:visible', 'confirm', 'cancel']); const emit = defineEmits(['update:visible', 'confirm', 'cancel']);
// //
const softPhoneVisible = ref(false);
// -
const handleConfirm = () => { const handleConfirm = () => {
emit('confirm'); softPhoneVisible.value = true;
};
//
const handleSoftPhoneConfirm = (configData) => {
console.log('软电话配置数据:', configData);
// confirm
emit('confirm', configData);
emit('update:visible', false); emit('update:visible', false);
}; };
//
const handleSoftPhoneCancel = () => {
//
console.log('软电话配置已取消');
};
// //
const handleCancel = () => { const handleCancel = () => {
emit('cancel'); emit('cancel');

View File

@ -54,13 +54,21 @@
</div> </div>
<!-- 照片 - 路段数据展示 --> <!-- 照片 - 路段数据展示 -->
<div v-if="isRoadData && hazardData.photos" class="info-block display"> <div v-if="hazardData.photos" class="info-block display">
<div class="block-title mr_10">照片</div> <div class="block-title mr_10">照片</div>
<div class="photo-list"> <div class="photo-list">
<img v-for="(photo, index) in hazardData.photos" :key="index" :src="photo" class="photo-item" @click="previewPhoto(photo)" /> <img v-for="(photo, index) in hazardData.photos" :key="index" :src="photo" class="photo-item" @click="previewPhoto(index)" />
</div> </div>
</div> </div>
<!-- 图片预览组件 -->
<el-image-viewer
v-if="previewVisible"
:url-list="hazardData.photos"
:initial-index="previewIndex"
@close="previewVisible = false"
/>
<!-- 风险描述 --> <!-- 风险描述 -->
<div class="info-block"> <div class="info-block">
<div class="block-title">风险描述</div> <div class="block-title">风险描述</div>
@ -313,11 +321,14 @@ const handleCurrentChange = (val) => {
currentPage.value = val currentPage.value = val
} }
//
const previewVisible = ref(false)
const previewIndex = ref(0)
// //
const previewPhoto = (photo) => { const previewPhoto = (index) => {
// 使 Element Plus previewIndex.value = index
const { preview } = require('element-plus') previewVisible.value = true
preview(photo)
} }
// //

View File

@ -219,6 +219,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
getdateRange: {
type: Array,
default: () => [],
},
}) })
const emit = defineEmits(['update:visible', 'close', 'detail', 'itemClick']) const emit = defineEmits(['update:visible', 'close', 'detail', 'itemClick'])
@ -228,7 +232,7 @@ const filterForm = ref({
pointType: '', pointType: '',
pointLevel: '', pointLevel: '',
region: '', region: '',
roadType: '', roadType: 'G,S',
}) })
// 使 // 使
@ -328,14 +332,20 @@ const impactData = ref([
{ name: '影响桥梁', count: 0, icon: Icon0, type: '桥梁' }, { name: '影响桥梁', count: 0, icon: Icon0, type: '桥梁' },
{ name: '影响隧道', count: 0, icon: Icon2, type: '隧道' }, { name: '影响隧道', count: 0, icon: Icon2, type: '隧道' },
{ name: '影响边坡', count: 0, icon: Icon1, type: '边坡' }, { name: '影响边坡', count: 0, icon: Icon1, type: '边坡' },
{ name: '影响项目', count: 0, icon: Icon3, type: '项目' }, { name: '影响项目', count: 0, icon: Icon3, type: '驻地' },
]) ])
// //
const loadBarChartData = async () => { const loadBarChartData = async () => {
console.log('原始时间范围:', props.handleImpactItem)
try { try {
const res = await request({ const res = await request({
url: '/snow-ops-platform/weather-warning/affected-count', url: '/snow-ops-platform/weather-warning/affected-count',
method: 'GET', method: 'GET',
params: {
start: formatDateTime(props.getdateRange[0]),
end: formatDateTime(props.getdateRange[1]),
warningId: props.handleImpactItem.warningId,
},
}) })
if (res.code == '00000') { if (res.code == '00000') {
@ -347,12 +357,12 @@ const loadBarChartData = async () => {
bridge: '桥梁', bridge: '桥梁',
tunnel: '隧道', tunnel: '隧道',
slope: '边坡', slope: '边坡',
project: '项目', project: '驻地',
Road: '路段', Road: '路段',
Bridge: '桥梁', Bridge: '桥梁',
Tunnel: '隧道', Tunnel: '隧道',
Slope: '边坡', Slope: '边坡',
Project: '项目', Project: '驻地',
} }
// name // name
@ -384,13 +394,13 @@ const getColumnsByType = (type) => {
桥梁: slopeColumns, 桥梁: slopeColumns,
隧道: tunnelColumns, 隧道: tunnelColumns,
边坡: roadColumns, 边坡: roadColumns,
项目: projectColumns, 驻地: projectColumns,
} }
// { name: '', count: 0, icon: Icon4, type: '' }, // { name: '', count: 0, icon: Icon4, type: '' },
// { name: '', count: 0, icon: Icon0, type: '' }, // { name: '', count: 0, icon: Icon0, type: '' },
// { name: '', count: 0, icon: Icon2, type: '' }, // { name: '', count: 0, icon: Icon2, type: '' },
// { name: '', count: 0, icon: Icon1, type: '' }, // { name: '', count: 0, icon: Icon1, type: '' },
// { name: '', count: 0, icon: Icon3, type: '' }, // { name: '', count: 0, icon: Icon3, type: '' },
return typeMap[type] || bridgeColumns return typeMap[type] || bridgeColumns
} }
@ -400,7 +410,7 @@ const getApiUrlByType = (type) => {
桥梁: '/snow-ops-platform/weather-warning/affected-object/bridge', 桥梁: '/snow-ops-platform/weather-warning/affected-object/bridge',
边坡: '/snow-ops-platform/weather-warning/affected-object/slope', 边坡: '/snow-ops-platform/weather-warning/affected-object/slope',
隧道: '/snow-ops-platform/weather-warning/affected-object/tunnel', 隧道: '/snow-ops-platform/weather-warning/affected-object/tunnel',
项目: '/snow-ops-platform/weather-warning/affected-object/project', 驻地: '/snow-ops-platform/weather-warning/affected-object/project',
路段: '/snow-ops-platform/weather-warning/affected-object/road-section', 路段: '/snow-ops-platform/weather-warning/affected-object/road-section',
} }
return urlMap[type] || '/snow-ops-platform/weather-warning/affected-object/bridge' return urlMap[type] || '/snow-ops-platform/weather-warning/affected-object/bridge'
@ -481,21 +491,22 @@ const handleFilterChange = () => {
const getTimeParams = () => { const getTimeParams = () => {
console.log('原始时间范围:', props.handleImpactItem) console.log('原始时间范围:', props.handleImpactItem)
let countyName = '' let countyId = ''
console.log('区域:', filterForm.value)
regionOptions.value.forEach((item) => { regionOptions.value.forEach((item) => {
if (item.label === filterForm.value.region) { if (item.label === filterForm.value.region || item.value === filterForm.value.region) {
countyName = item.label || '' countyId = item.value || ''
} }
}) })
return { return {
// start: `${year}-${month}-01 00:00:00`, // start: `${year}-${month}-01 00:00:00`,
// end: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`, // end: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`,
start: formatDateTime(props.handleImpactItem.dateRange?.[0] || ''), start: formatDateTime(props.getdateRange[0] ? props.getdateRange[0] : props.handleImpactItem.dateRange?.[0] || ''),
end: formatDateTime(props.handleImpactItem.dateRange?.[1] || ''), end: formatDateTime(props.getdateRange[1] ? props.getdateRange[1] : props.handleImpactItem.dateRange?.[1] || ''),
limit: pageSize.value, limit: pageSize.value,
offset: (currentPage.value - 1) * pageSize.value, offset: (currentPage.value - 1) * pageSize.value,
countyName: countyName || '', countyId: countyId || '',
riskLevel: filterForm.value.pointLevel || '', riskLevel: filterForm.value.pointLevel || '',
roadTypes: filterForm.value.roadType || '', roadTypes: filterForm.value.roadType || '',
} }
@ -692,7 +703,7 @@ const processUnifiedData = (item, type) => {
} }
// SQL // SQL
if (cardTypeVal.value === '项目') { if (cardTypeVal.value === '驻地') {
return { return {
...baseData, ...baseData,
// - 使COUNTY // - 使COUNTY
@ -765,6 +776,14 @@ const fetchData = async () => {
})) }))
total.value = res.total || 0 total.value = res.total || 0
} }
} else if (cardTypeVal.value == '驻地') {
if (res.data) {
tableData.value = res.data.map((item, index) => ({
...processDataByType(item, cardType.value),
id: index + 1,
}))
total.value = res.total || 0
}
} else { } else {
if (res.code === '00000' && res.data) { if (res.code === '00000' && res.data) {
// //
@ -825,7 +844,7 @@ watch(
// } // }
// tableData.value = [] // tableData.value = []
// cardType.value = '0' // cardType.value = '0'
// loadBarChartData() loadBarChartData()
// currentPage.value = 1 // currentPage.value = 1
// fetchData() // fetchData()
// } // }

View File

@ -1,6 +1,6 @@
<template> <template>
<base-dialog <base-dialog
v-model:visible="props.visible" :visible="props.visible"
title="巡查里程" title="巡查里程"
:table-data="tableData" :table-data="tableData"
:table-columns="tableColumns" :table-columns="tableColumns"
@ -11,6 +11,7 @@
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
@close="handleClose" @close="handleClose"
@update:visible="handleClose"
> >
<!-- 统计卡片区域 --> <!-- 统计卡片区域 -->
<template #header> <template #header>
@ -39,7 +40,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"
@ -48,12 +49,7 @@
clearable clearable
@change="handleFilterChange" @change="handleFilterChange"
> >
<el-option <el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" />
v-for="item in districtOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</div> </div>
</div> </div>
@ -62,184 +58,143 @@
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue'; import { ref, watch } from 'vue'
import BaseDialog from '../component/baseDialog.vue'; import BaseDialog from '../component/baseDialog.vue'
import { request } from '@/utils/request'; import { request } from '@/utils/request'
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 IconNational from '../../../assets/xiangying/国省道icon.png'; import IconNational from '../../../assets/xiangying/国省道icon.png'
import IconRuralRoad from '../../../assets/xiangying/农村公路icon.png'; import IconRuralRoad from '../../../assets/xiangying/农村公路icon.png'
import { formatDateTime, regionOptions } from '../component/index.js'
const props = defineProps({ const props = defineProps({
visible: { visible: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}); getdateRange: {
type: Array,
default: () => [],
},
})
const emit = defineEmits(['update:visible', 'close']); const emit = defineEmits(['update:visible', 'close'])
// //
const nationalRoadMileage = ref(345); const nationalRoadMileage = ref(345)
const ruralRoadMileage = ref(4333); const ruralRoadMileage = ref(4333)
// //
const mileageData = ref([ const mileageData = ref([
{ name: '国省道', value: 345, icon: IconNational, type: 'national' }, { name: '国省道', value: 345, icon: IconNational, type: 'national' },
{ name: '农村公路', value: 4333, icon: IconRuralRoad, type: 'rural' }, { name: '农村公路', value: 4333, icon: IconRuralRoad, type: 'rural' },
]); ])
// //
const cardType = ref('0'); const cardType = ref('0')
// //
const handleClick = (index, item) => { const handleClick = (index, item) => {
cardType.value = index + ''; cardType.value = index + ''
// //
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
}; }
// //
const filterForm = ref({ const filterForm = ref({
district: '', district: '',
}); })
//
const districtOptions = ref([
{ label: '万州区', value: 'wanzhou' },
{ label: '黔江区', value: 'qianjiang' },
{ label: '涪陵区', value: 'fuling' },
{ label: '渝中区', value: 'yuzhong' },
{ label: '大渡口区', value: 'dadukou' },
{ label: '江北区', value: 'jiangbei' },
{ label: '沙坪坝区', value: 'shapingba' },
{ label: '九龙坡区', value: 'jiulongpo' },
{ label: '南岸区', value: 'nanan' },
{ label: '北碚区', value: 'beibei' },
{ label: '渝北区', value: 'yubei' },
{ label: '巴南区', value: 'banan' },
{ label: '长寿区', value: 'changshou' },
{ label: '江津区', value: 'jiangjin' },
{ label: '合川区', value: 'hechuan' },
{ label: '永川区', value: 'yongchuan' },
{ label: '南川区', value: 'nanchuan' },
{ label: '綦江区', value: 'qijiang' },
{ label: '大足区', value: 'dazu' },
{ label: '璧山区', value: 'bishan' },
{ label: '铜梁区', value: 'tongliang' },
{ label: '潼南区', value: 'tongnan' },
{ label: '荣昌区', value: 'rongchang' },
{ label: '开州区', value: 'kaizhou' },
{ label: '梁平区', value: 'liangping' },
{ label: '武隆区', value: 'wulong' },
]);
// //
const tableHeight = ref(300); const tableHeight = ref(300)
// - // -
const tableColumns = ref([ const tableColumns = ref([
{ prop: 'id', label: '序号' }, { prop: 'id', label: '序号' },
{ prop: 'district', label: '所属区县' }, { prop: 'district', label: '所属区县' },
{ prop: 'mileage', label: '巡查里程' }, { prop: 'mileage', label: '巡查里程' },
]); ])
// //
const tableData = ref([]); const tableData = ref([])
// //
const currentPage = ref(1); const currentPage = ref(1)
const pageSize = ref(10); const pageSize = ref(10)
const total = ref(0); const total = ref(0)
// //
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
fetchData(); fetchData()
}; }
const handleCurrentChange = val => { const handleCurrentChange = (val) => {
currentPage.value = val; currentPage.value = val
fetchData(); fetchData()
}; }
// //
const handleFilterChange = () => { const handleFilterChange = () => {
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
}; }
//
const fetchStatsData = async () => {
try {
const res = await request({
url: '/snow-ops-platform/patrol/mileage-stats',
method: 'GET',
});
if (res.code === '00000' && res.data) {
const nationalVal = res.data.nationalRoadMileage || 345;
const ruralVal = res.data.ruralRoadMileage || 4333;
nationalRoadMileage.value = nationalVal;
ruralRoadMileage.value = ruralVal;
// mileageData
mileageData.value[0].value = nationalVal;
mileageData.value[1].value = ruralVal;
}
} catch (error) {
console.error('获取巡查里程统计数据失败:', error);
}
};
// //
const fetchData = async () => { const fetchData = async () => {
try { try {
const res = await request({ const res = await request({
url: '/snow-ops-platform/patrol/mileage-list', url: '/snow-ops-platform/yhWgxc/county-mileage',
method: 'GET', method: 'GET',
params: { params: {
pageNum: currentPage.value, pageNum: currentPage.value,
pageSize: pageSize.value, pageSize: pageSize.value,
districtCode: filterForm.value.district, startTime: formatDateTime(props.getdateRange?.[0] || ''),
endTime: formatDateTime(props.getdateRange?.[1] || ''),
qxbm: filterForm.value.district || '',
}, },
}); })
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, index) => { tableData.value = data.records.map((item, index) => {
return { return {
id: currentPage.value * pageSize.value - (pageSize.value - index - 1), id: currentPage.value * pageSize.value - (pageSize.value - index - 1),
district: item.districtName || '-', district: item.qxmc || '-',
mileage: item.mileage ? `${item.mileage}公里` : '-', mileage: item.mileage ? `${item.mileage}公里` : '0',
}; }
}); })
total.value = data.total; total.value = data.total
} else {
tableData.value = []
total.value = 0
} }
} catch (error) { } catch (error) {
console.error('获取巡查里程列表数据失败:', error); console.error('获取巡查里程列表数据失败:', error)
} }
}; }
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
newVal => { (newVal) => {
if (newVal) { tableData.value = []
currentPage.value = 1; total.value = 0
fetchStatsData(); currentPage.value = 1
fetchData(); // fetchStatsData()
} fetchData()
} },
); )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -251,7 +206,6 @@ watch(
margin-bottom: 16px; margin-bottom: 16px;
padding: 0 4px; padding: 0 4px;
.stat-card { .stat-card {
display: flex; display: flex;
flex: 1; flex: 1;

View File

@ -41,52 +41,21 @@
<!-- 筛选区域 --> <!-- 筛选区域 -->
<template #filter> <template #filter>
<div class="filter-row"> <div class="filter-row">
<!-- <div class="filter-item">
<el-select :teleported="false"
v-model="filterForm.pointType"
placeholder="影响点类型"
class="filter-select"
>
<el-option
v-for="option in pointTypeOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</div> -->
<div class="filter-item"> <div class="filter-item">
<span class="filter-label">影响点等级</span> <span class="filter-label">影响点等级</span>
<el-select <el-select :teleported="false" v-model="filterForm.pointLevel" placeholder="影响点等级" class="filter-select">
:teleported="false" <el-option v-for="option in pointLevelOptions" :key="option.value" :label="option.label" :value="option.value" />
v-model="filterForm.pointLevel"
placeholder="影响点等级"
class="filter-select"
>
<el-option
v-for="option in pointLevelOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</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 :teleported="false" v-model="filterForm.isResponded" placeholder="是否回应" class="filter-select">
:teleported="false" <el-option v-for="option in isRespondedOptions" :key="option.value" :label="option.label" :value="option.value" />
v-model="filterForm.isResponded"
placeholder="是否回应"
class="filter-select"
>
<el-option
v-for="option in isRespondedOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
</div> </div>
<div class="filter-item">
<el-button type="primary" @click="handleSearch">查询</el-button>
</div>
</div> </div>
</template> </template>
@ -100,11 +69,7 @@
<div class="person-info"> <div class="person-info">
<div class="person-name center"> <div class="person-name center">
<span style="margin-right: 5px">{{ row.trafficDept.name }}</span> <span style="margin-right: 5px">{{ row.trafficDept.name }}</span>
<img <img class="response-icon" :src="row.trafficDept.isResponded ? row.trafficDept.img : row.trafficDept.img" alt />
class="response-icon"
:src="row.trafficDept.isResponded ? row.trafficDept.img : row.trafficDept.img"
alt
/>
</div> </div>
<span class="person-phone">{{ row.trafficDept.phone }}</span> <span class="person-phone">{{ row.trafficDept.phone }}</span>
</div> </div>
@ -144,9 +109,9 @@
</template> </template>
<!-- 回应状态列插槽 --> <!-- 回应状态列插槽 -->
<!-- <template #responseStatus="{ row }"> <!-- <template #responseStatusData="{ row }">
<span class="response-status" :class="row.responseClass">{{ <span class="response-status" :class="row.responseClass">{{
row.responseStatus row.responseStatusData
}}</span> }}</span>
</template> --> </template> -->
@ -166,27 +131,22 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, watch, onMounted } 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, formatDateTime } from '../component/index.js'
pointTypeOptions, import baseDialog from '../component/baseDialog.vue'
pointLevelOptions, import { request } from '@/utils/request.js'
isRespondedOptions,
formatDateTime,
} from '../component/index.js';
import baseDialog from '../component/baseDialog.vue';
import { request } from '@/utils/request.js';
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: {
@ -197,18 +157,22 @@ const props = defineProps({
type: Array, type: Array,
default: () => [], default: () => [],
}, },
}); responseStatusData: {
type: Object,
default: () => {},
},
})
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('路段'); const cardType = ref('路段')
// //
const statsCardsData = ref([ const statsCardsData = ref([
@ -216,8 +180,8 @@ const statsCardsData = ref([
{ type: '桥梁', label: '影响桥梁', value: 0, icon: Icon0 }, { type: '桥梁', label: '影响桥梁', value: 0, icon: Icon0 },
{ type: '隧道', label: '影响隧道', value: 0, icon: Icon2 }, { type: '隧道', label: '影响隧道', value: 0, icon: Icon2 },
{ type: '边坡', label: '影响边坡', value: 0, icon: Icon1 }, { type: '边坡', label: '影响边坡', value: 0, icon: Icon1 },
{ type: '项目', label: '影响项目', value: 0, icon: Icon3 }, { type: '驻地', label: '影响驻地', value: 0, icon: Icon3 },
]); ])
// //
const tableColumns = ref([ const tableColumns = ref([
@ -234,37 +198,40 @@ const tableColumns = ref([
{ prop: 'generalStaff', label: '一般人员(路长履职)', width: '100px', slot: 'generalStaff' }, { prop: 'generalStaff', label: '一般人员(路长履职)', width: '100px', slot: 'generalStaff' },
{ prop: 'urgeTime', label: '最新催告时间', width: '', slot: 'urgeTime' }, { prop: 'urgeTime', label: '最新催告时间', width: '', slot: 'urgeTime' },
{ prop: 'operation', label: '操作', width: '', slot: 'operation' }, { prop: 'operation', label: '操作', width: '', slot: 'operation' },
]); ])
// //
const tableData = ref([]); const tableData = ref([])
// //
const currentPage = ref(1); const currentPage = ref(1)
const pageSize = ref(10); const pageSize = ref(10)
const total = ref(36); 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
fetchData(); fetchData()
}; }
// //
const loadBarChartData = async () => { const loadBarChartData = async () => {
try { try {
const res = await request({ const res = await request({
url: '/snow-ops-platform/weather-warning/affected-count', url: '/snow-ops-platform/weather-warning/affected-count',
method: 'GET', method: 'GET',
}); params: {
warningId: props.responseStatusData.warningId,
},
})
if (res.code == '00000') { if (res.code == '00000') {
const data = res.data; const data = res.data
if (data && Array.isArray(data)) { if (data && Array.isArray(data)) {
// //
const nameMap = { const nameMap = {
@ -272,44 +239,44 @@ const loadBarChartData = async () => {
bridge: '桥梁', bridge: '桥梁',
tunnel: '隧道', tunnel: '隧道',
slope: '边坡', slope: '边坡',
project: '项目', project: '驻地',
Road: '路段', Road: '路段',
Bridge: '桥梁', Bridge: '桥梁',
Tunnel: '隧道', Tunnel: '隧道',
Slope: '边坡', Slope: '边坡',
Project: '项目', Project: '驻地',
}; }
statsCardsData.value.forEach(item => { statsCardsData.value.forEach((item) => {
data.forEach(stat => { data.forEach((stat) => {
if (stat.extension == item.type) { if (stat.extension == item.type) {
item.value = stat.count || 0; item.value = stat.count || 0
} }
}); })
}); })
} }
} }
} catch (error) { } catch (error) {
console.error('加载柱状图数据失败:', 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 = async () => { const fetchData = async () => {
@ -317,29 +284,32 @@ const fetchData = async () => {
const params = { const params = {
start: '', start: '',
end: '', end: '',
}; offset: (currentPage.value - 1) * pageSize.value,
limit: pageSize.value,
warningId: props.responseStatusData.warningId,
}
if (props.dispatchDateRange && props.dispatchDateRange.length > 0) { if (props.dispatchDateRange && props.dispatchDateRange.length > 0) {
params.start = formatDateTime(props.dispatchDateRange[0]) || ''; params.start = formatDateTime(props.dispatchDateRange[0]) || ''
params.end = formatDateTime(props.dispatchDateRange[1]) || ''; params.end = formatDateTime(props.dispatchDateRange[1]) || ''
} }
const res = await request({ const res = await request({
url: '/snow-ops-platform/weather-warning/notice-entity', url: '/snow-ops-platform/weather-warning/notice-entity',
method: 'GET', method: 'GET',
params, params,
}); })
if (res && res.data) { if (res && res.data) {
tableData.value = res.data.map((item, index) => { tableData.value = res.data.map((item, index) => {
// events // events
const trafficDeptEvent = item.events?.find(e => e.noticeRoles?.includes('交通主管')) || {}; const trafficDeptEvent = item.events?.find((e) => e.noticeRoles?.includes('交通主管')) || {}
const roadKeeperEvent = item.events?.find(e => e.noticeRoles?.includes('护路员')) || {}; const roadKeeperEvent = item.events?.find((e) => e.noticeRoles?.includes('护路员')) || {}
const roadOrgEvent = item.events?.find(e => e.noticeRoles?.includes('公路机构')) || {}; const roadOrgEvent = item.events?.find((e) => e.noticeRoles?.includes('公路机构')) || {}
const maintenanceEvent = item.events?.find(e => e.noticeRoles?.includes('养护站')) || {}; const maintenanceEvent = item.events?.find((e) => e.noticeRoles?.includes('养护站')) || {}
// //
const lastNoticeTime = item.events?.[0]?.lastNoticeTime || ''; const lastNoticeTime = item.events?.[0]?.lastNoticeTime || ''
const urgeTimeParts = lastNoticeTime ? lastNoticeTime.split('T') : ['', '']; const urgeTimeParts = lastNoticeTime ? lastNoticeTime.split('T') : ['', '']
return { return {
id: index + 1, id: index + 1,
@ -372,26 +342,26 @@ const fetchData = async () => {
img: roadKeeperEvent.replyState === 'read' ? respondedIcon : notRespondedIcon, img: roadKeeperEvent.replyState === 'read' ? respondedIcon : notRespondedIcon,
isResponded: roadKeeperEvent.replyState === 'read', isResponded: roadKeeperEvent.replyState === 'read',
}, },
generalStaff:{ generalStaff: {
name: item.GL1_QLGCS || "-", name: item.GL1_QLGCS || '-',
phone: item.GL1_QLGCSDH || "-", phone: item.GL1_QLGCSDH || '-',
}, },
urgeTime: { urgeTime: {
date: urgeTimeParts[0] || '-', date: urgeTimeParts[0] || '-',
time: urgeTimeParts[1] ? urgeTimeParts[1].substring(0, 8) : '-', time: urgeTimeParts[1] ? urgeTimeParts[1].substring(0, 8) : '-',
}, },
}; }
}); })
total.value = res.data.length; total.value = res.data.length
} }
} catch (error) { } catch (error) {
console.error('获取通知实体数据失败:', error); console.error('获取通知实体数据失败:', error)
} }
}; }
// //
const getTypeLabel = type => { const getTypeLabel = (type) => {
const typeMap = { const typeMap = {
'road-section': '路段', 'road-section': '路段',
road_section: '路段', road_section: '路段',
@ -399,46 +369,52 @@ const getTypeLabel = type => {
bridge: '桥梁', bridge: '桥梁',
tunnel: '隧道', tunnel: '隧道',
slope: '边坡', slope: '边坡',
project: '项目', project: '驻地',
}; }
return typeMap[type] || type || '-'; return typeMap[type] || type || '-'
}; }
// //
const getLevelClass = riskLevel => { const getLevelClass = (riskLevel) => {
if (!riskLevel) return ''; if (!riskLevel) return ''
if (riskLevel.includes('高')) return 'level-serious'; if (riskLevel.includes('高')) return 'level-serious'
if (riskLevel.includes('一般')) return 'level-normal'; if (riskLevel.includes('一般')) return 'level-normal'
return ''; return ''
}; }
//
const handleSearch = () => {
fetchData()
loadBarChartData()
}
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
newVal => { (newVal) => {
if (newVal) { if (newVal) {
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
loadBarChartData()
} }
} },
); )
// //
watch( watch(
() => props.dispatchDateRange, () => props.dispatchDateRange,
() => { () => {
if (props.visible) { if (props.visible) {
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
} }
}, },
{ deep: true } { deep: true },
); )
onMounted(() => { onMounted(() => {
// //
loadBarChartData(); loadBarChartData()
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -0,0 +1,370 @@
<template>
<div v-if="visible" class="softphone-dialog-overlay" @click="handleOverlayClick">
<div class="softphone-dialog" @click.stop>
<!-- 四个角的装饰 -->
<div class="corner corner-top-left"></div>
<div class="corner corner-top-right"></div>
<div class="corner corner-bottom-left"></div>
<div class="corner corner-bottom-right"></div>
<!-- 标题栏 -->
<div class="dialog-header">
<div class="header-title">软电话配置</div>
<div class="close-btn" @click="handleCancel">
<el-icon><Close /></el-icon>
</div>
</div>
<!-- 内容区域 -->
<div class="dialog-content">
<!-- 状态按钮组 -->
<div class="status-buttons">
<button
v-for="status in statusList"
:key="status.value"
:class="['status-btn', { active: currentStatus === status.value }]"
@click="currentStatus = status.value"
>
{{ status.label }}
</button>
</div>
<!-- 表单区域 -->
<div class="form-area">
<div class="form-item">
<span class="form-label">服务器环境</span>
<input v-model="formData.serverEnv" type="text" class="form-input" placeholder="请输入服务器环境" />
</div>
<div class="form-item">
<span class="form-label">工号</span>
<input v-model="formData.workId" type="text" class="form-input" placeholder="请输入工号" />
</div>
<div class="form-item">
<span class="form-label">坐席密码</span>
<input v-model="formData.seatPassword" type="password" class="form-input" placeholder="请输入坐席密码" />
</div>
</div>
</div>
<!-- 按钮区域 -->
<div class="dialog-footer">
<button class="btn-cancel" @click="handleCancel">取消</button>
<button class="btn-confirm" @click="handleConfirm">确定</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, watch } from 'vue'
import { Close } from '@element-plus/icons-vue'
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['update:visible', 'confirm', 'cancel'])
//
const statusList = [
{ label: '未登录', value: 'notLogin' },
{ label: '示忙', value: 'busy' },
{ label: '示闲', value: 'idle' },
{ label: '呼出', value: 'callOut' },
{ label: '保持', value: 'hold' },
{ label: '接回', value: 'retrieve' },
{ label: '挂断', value: 'hangUp' },
{ label: '会议', value: 'conference' },
{ label: '应答', value: 'answer' },
{ label: '转出', value: 'transfer' },
{ label: '咨询', value: 'consult' },
]
//
const currentStatus = ref('notLogin')
//
const formData = reactive({
serverEnv: '',
workId: '',
seatPassword: '',
})
//
const handleConfirm = () => {
emit('confirm', {
status: currentStatus.value,
...formData,
})
emit('update:visible', false)
}
//
const handleCancel = () => {
emit('cancel')
emit('update:visible', false)
}
//
const handleOverlayClick = () => {
handleCancel()
}
// visible
watch(
() => props.visible,
(newVal) => {
if (newVal) {
currentStatus.value = 'notLogin'
formData.serverEnv = ''
formData.workId = ''
formData.seatPassword = ''
}
},
)
</script>
<style lang="scss" scoped>
.softphone-dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 2200;
}
.softphone-dialog {
width: 500px;
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
border: 1px solid rgba(64, 169, 255, 0.3);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
overflow: hidden;
animation: dialogSlideIn 0.3s ease-out;
position: relative;
@media (max-width: 768px) {
width: 90vw;
max-width: 90vw;
}
//
.corner {
position: absolute;
width: 20px;
height: 20px;
border: 1px solid #40a9ff;
z-index: 100;
pointer-events: none;
&.corner-top-left {
top: 0;
left: 0;
border-right: none;
border-bottom: none;
}
&.corner-top-right {
top: 0;
right: 0;
border-left: none;
border-bottom: none;
}
&.corner-bottom-left {
bottom: 0;
left: 0;
border-right: none;
border-top: none;
}
&.corner-bottom-right {
bottom: 0;
right: 0;
border-left: none;
border-top: none;
}
}
}
@keyframes dialogSlideIn {
from {
opacity: 0;
transform: scale(0.8) translateY(-50px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
//
.dialog-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background: linear-gradient(90deg, rgba(64, 169, 255, 0.15) 0%, rgba(64, 169, 255, 0.05) 100%);
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
.header-title {
font-size: 16px;
font-weight: 600;
color: #fff;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.close-btn {
width: 19px;
height: 19px;
display: flex;
align-items: center;
justify-content: center;
color: rgba(255, 255, 255, 0.6);
cursor: pointer;
font-size: 13px;
transition: color 0.3s;
flex-shrink: 0;
&:hover {
color: #fff;
}
}
}
//
.dialog-content {
padding: 20px;
max-height: 60vh;
overflow-y: auto;
}
//
.status-buttons {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
.status-btn {
padding: 6px 12px;
background: transparent;
border: 1px solid rgba(64, 169, 255, 0.4);
border-radius: 4px;
color: rgba(255, 255, 255, 0.7);
font-size: 12px;
cursor: pointer;
transition: all 0.3s;
&:hover {
border-color: rgba(64, 169, 255, 0.6);
color: rgba(255, 255, 255, 0.9);
}
&.active {
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
border-color: #40a9ff;
color: #fff;
}
}
}
//
.form-area {
display: flex;
flex-direction: column;
gap: 16px;
}
.form-item {
display: flex;
align-items: center;
gap: 16px;
.form-label {
width: 80px;
font-size: 14px;
color: rgba(255, 255, 255, 0.8);
flex-shrink: 0;
}
.form-input {
flex: 1;
height: 36px;
padding: 0 12px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(64, 169, 255, 0.3);
border-radius: 4px;
color: #fff;
font-size: 14px;
transition: all 0.3s;
&::placeholder {
color: rgba(255, 255, 255, 0.4);
}
&:focus {
outline: none;
border-color: rgba(64, 169, 255, 0.6);
background: rgba(255, 255, 255, 0.08);
}
}
}
//
.dialog-footer {
display: flex;
justify-content: center;
gap: 16px;
padding: 0 20px 20px;
flex-wrap: wrap;
.btn-cancel {
min-width: 80px;
height: 32px;
padding: 0 24px;
background-color: transparent;
border: 1px solid rgba(64, 169, 255, 0.4);
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background-color: rgba(64, 169, 255, 0.1);
border-color: rgba(64, 169, 255, 0.6);
color: #fff;
}
}
.btn-confirm {
min-width: 80px;
height: 32px;
padding: 0 24px;
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
border: none;
color: #fff;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
}
}
}
</style>

View File

@ -26,12 +26,7 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option <el-option v-for="option in warningLevelOptions" :key="option.value" :label="option.label" :value="option.value" />
v-for="option in warningLevelOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
</div> </div>
<div class="filter-item"> <div class="filter-item">
@ -43,12 +38,7 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option <el-option v-for="option in regionOptions" :key="option.value" :label="option.label" :value="option.value" />
v-for="option in regionOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
</div> </div>
<div class="filter-item"> <div class="filter-item">
@ -60,12 +50,7 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option <el-option v-for="option in isEndedOptions" :key="option.value" :label="option.label" :value="option.value" />
v-for="option in isEndedOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
</div> </div>
<div class="filter-item"> <div class="filter-item">
@ -77,12 +62,7 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option <el-option v-for="option in isRespondedOptions" :key="option.value" :label="option.label" :value="option.value" />
v-for="option in isRespondedOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
</div> </div>
<div class="filter-item"> <div class="filter-item">
@ -107,17 +87,12 @@
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue'; import { ref, watch } from 'vue'
import { Search } from '@element-plus/icons-vue'; import { Search } from '@element-plus/icons-vue'
import baseDialog from '../component/baseDialog.vue'; import baseDialog from '../component/baseDialog.vue'
import { formatDateTime } from '../component/index.js'; import { formatDateTime } from '../component/index.js'
import { request } from '@/utils/request'; import { request } from '@/utils/request'
import { import { warningLevelOptions, regionOptions, isEndedOptions, isRespondedOptions } from '../component/index.js'
warningLevelOptions,
regionOptions,
isEndedOptions,
isRespondedOptions,
} from '../component/index.js';
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -128,9 +103,9 @@ const props = defineProps({
type: Array, type: Array,
default: () => [], default: () => [],
}, },
}); })
const emit = defineEmits(['update:visible', 'close', 'openImpactPoint']); const emit = defineEmits(['update:visible', 'close', 'openImpactPoint', 'getResponseStatusrowFn'])
// //
const filterForm = ref({ const filterForm = ref({
@ -138,7 +113,7 @@ const filterForm = ref({
region: '', region: '',
isEnded: '', isEnded: '',
isResponded: '', isResponded: '',
}); })
// //
const tableColumns = ref([ const tableColumns = ref([
@ -153,82 +128,56 @@ const tableColumns = ref([
{ prop: 'responded', label: '已回应', width: '' }, { prop: 'responded', label: '已回应', width: '' },
{ prop: 'notResponded', label: '未回应', width: '' }, { prop: 'notResponded', label: '未回应', width: '' },
{ prop: 'urged', label: '已催告', width: '' }, { prop: 'urged', label: '已催告', width: '' },
]); ])
// //
const tableData = ref([]); const tableData = ref([])
// //
const currentPage = ref(1); const currentPage = ref(1)
const pageSize = ref(10); const pageSize = ref(10)
const total = ref(36); const total = ref(36)
//
const tableHeight = ref(300);
//
const headerCellStyle = () => {
return {
backgroundColor: '#1C4979',
color: '#fff',
fontSize: '14px',
fontWeight: '500',
textAlign: 'center',
padding: '12px 16px',
border: 'none',
};
};
const cellStyle = () => {
return {
backgroundColor: 'transparent',
color: 'rgba(255, 255, 255, 0.85)',
fontSize: '13px',
textAlign: 'center',
padding: '12px 16px',
border: 'none',
};
};
// //
const handleClose = () => { const handleClose = () => {
emit('update:visible', false); emit('update:visible', false)
emit('close'); emit('close')
}; }
// base-dialog // base-dialog
// //
const handleCalledClick = () => { const handleCalledClick = (row) => {
emit('responseStatus'); emit('responseStatus')
}; emit('getResponseStatusrowFn', row)
}
// //
const handleSearch = () => { const handleSearch = () => {
console.log('查询条件:', filterForm.value); console.log('查询条件:', filterForm.value)
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
}; }
// //
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 handleWarningLevelChange = () => { const handleWarningLevelChange = () => {
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
}; }
// //
const fetchData = async () => { const fetchData = async () => {
try { try {
console.log(props.dispatchDateRange); console.log(props.dispatchDateRange)
const params = { const params = {
start: '', start: '',
end: '', end: '',
@ -239,30 +188,28 @@ const fetchData = async () => {
countyName: '', countyName: '',
isExpire: filterForm.value.isEnded, isExpire: filterForm.value.isEnded,
isReply: filterForm.value.isResponded, isReply: filterForm.value.isResponded,
}; }
if (regionOptions.value.length > 0) { if (regionOptions.value.length > 0) {
// //
const selectedRegion = regionOptions.value.find( const selectedRegion = regionOptions.value.find((option) => option.value === filterForm.value.region)
option => option.value === filterForm.value.region
);
if (selectedRegion) { if (selectedRegion) {
params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || ''; params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || ''
} }
} }
if (props.dispatchDateRange.length > 0) { if (props.dispatchDateRange.length > 0) {
params.start = formatDateTime(props.dispatchDateRange[0]) || ''; params.start = formatDateTime(props.dispatchDateRange[0]) || ''
params.end = formatDateTime(props.dispatchDateRange[1]) || ''; params.end = formatDateTime(props.dispatchDateRange[1]) || ''
} }
const res = await request({ const res = await request({
url: '/snow-ops-platform/weather-warning/notice-count', url: '/snow-ops-platform/weather-warning/notice-count',
method: 'GET', method: 'GET',
params, params,
}); })
console.log(res); console.log(res)
if (res) { if (res) {
// //
tableData.value = res.data.map((item, index) => ({ tableData.value = res.data.map((item, index) => ({
@ -278,46 +225,47 @@ const fetchData = async () => {
responded: item.replyCount || 0, responded: item.replyCount || 0,
notResponded: (item.notifyCount || 0) - (item.replyCount || 0), notResponded: (item.notifyCount || 0) - (item.replyCount || 0),
urged: item.retryCount || 0, urged: item.retryCount || 0,
})); warningId: item.warningId || '-',
total.value = res.total || res.data.length; }))
total.value = res.total || res.data.length
} }
} catch (error) { } catch (error) {
console.error('获取预警通知统计失败:', error); console.error('获取预警通知统计失败:', error)
} }
}; }
// //
const getLevelClass = riskLevel => { const getLevelClass = (riskLevel) => {
if (!riskLevel) return ''; if (!riskLevel) return ''
if (riskLevel.includes('红')) return 'level-red'; if (riskLevel.includes('红')) return 'level-red'
if (riskLevel.includes('橙')) return 'level-orange'; if (riskLevel.includes('橙')) return 'level-orange'
if (riskLevel.includes('黄')) return 'level-yellow'; if (riskLevel.includes('黄')) return 'level-yellow'
if (riskLevel.includes('蓝')) return 'level-blue'; if (riskLevel.includes('蓝')) return 'level-blue'
return ''; return ''
}; }
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
newVal => { (newVal) => {
if (newVal) { if (newVal) {
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
} }
} },
); )
// //
watch( watch(
() => props.dispatchDateRange, () => props.dispatchDateRange,
() => { () => {
if (props.visible) { if (props.visible) {
currentPage.value = 1; currentPage.value = 1
fetchData(); fetchData()
} }
}, },
{ deep: true } { deep: true },
); )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -17,56 +17,20 @@
<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 v-model="filterForm.riskLeve" placeholder="请选择" class="filter-select el-select" clearable size="small" :teleported="false">
v-model="filterForm.riskLeve" <el-option v-for="item in warningLevelOptions" :key="item.value" :label="item.label" :value="item.value" />
placeholder="请选择"
class="filter-select el-select"
clearable
size="small"
:teleported="false"
>
<el-option
v-for="item in warningLevelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</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" placeholder="请选择" class="filter-select" clearable size="small" :teleported="false">
v-model="filterForm.countyName" <el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" />
placeholder="请选择"
class="filter-select"
clearable
size="small"
:teleported="false"
>
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</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.isEnded" placeholder="请选择" class="filter-select" clearable size="small" :teleported="false">
v-model="filterForm.isEnded" <el-option v-for="item in isEndedOptions" :key="item.value" :label="item.label" :value="item.value" />
placeholder="请选择"
class="filter-select"
clearable
size="small"
:teleported="false"
>
<el-option
v-for="item in isEndedOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</div> </div>
@ -101,14 +65,14 @@
</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 { warningLevelOptions, regionOptions, isEndedOptions } from '../component/index.js'; import { warningLevelOptions, regionOptions, isEndedOptions } from '../component/index.js'
import baseDialog from '../component/baseDialog.vue'; import baseDialog from '../component/baseDialog.vue'
import { request } from '@/utils/request'; import { request } from '@/utils/request'
// //
const getdateRange = inject('getdateRange', ref([])); const getdateRange = inject('getdateRange', ref([]))
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -119,44 +83,44 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}), default: () => ({}),
}, },
}); })
const emit = defineEmits(['update:visible', 'close', 'impactClick']); const emit = defineEmits(['update:visible', 'close', 'impactClick'])
// //
const dateRange = ref([]); const dateRange = ref([])
onMounted(() => { onMounted(() => {
// //
if (props.visible) { if (props.visible) {
initDialogData(); initDialogData()
} }
}); })
// 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({
@ -164,12 +128,12 @@ const filterForm = ref({
countyName: '', countyName: '',
isEnded: '', isEnded: '',
dateRange: dateRange.value, dateRange: dateRange.value,
}); })
// //
const handleDateChange = val => { const handleDateChange = (val) => {
filterForm.value.dateRange = val; filterForm.value.dateRange = val
}; }
// //
// index.js // index.js
@ -181,7 +145,7 @@ const handleDateChange = val => {
// index.js // index.js
// //
const tableHeight = ref(300); const tableHeight = ref(300)
// //
const tableColumns = ref([ const tableColumns = ref([
@ -193,22 +157,22 @@ const tableColumns = ref([
{ prop: 'warningTime', label: '生效时间', width: '' }, { prop: 'warningTime', label: '生效时间', width: '' },
{ prop: 'endTime', label: '失效时间', width: '' }, { prop: 'endTime', label: '失效时间', width: '' },
{ prop: 'impactCount', label: '影响点数量', width: '', slot: 'impactCount' }, { prop: 'impactCount', label: '影响点数量', width: '', slot: 'impactCount' },
]); ])
// //
const tableData = ref([]); const tableData = ref([])
// //
const currentPage = ref(1); const currentPage = ref(1)
const pageSize = ref(10); const pageSize = ref(10)
const total = ref(0); const total = ref(0)
// //
const loading = ref(false); const loading = ref(false)
// //
const fetchWarningData = async () => { const fetchWarningData = async () => {
loading.value = true; loading.value = true
try { try {
const params = { const params = {
offset: (currentPage.value - 1) * pageSize.value, offset: (currentPage.value - 1) * pageSize.value,
@ -219,38 +183,36 @@ const fetchWarningData = async () => {
weatherType: '', weatherType: '',
isExpire: '', isExpire: '',
countyName: '', countyName: '',
}; }
// //
if (filterForm.value.riskLeve) { if (filterForm.value.riskLeve) {
params.riskLevel = filterForm.value.riskLeve; params.riskLevel = filterForm.value.riskLeve
} }
if (filterForm.value.countyName) { if (filterForm.value.countyName) {
const selectedRegion = regionOptions.value.find( const selectedRegion = regionOptions.value.find((option) => option.value === filterForm.value.countyName)
option => option.value === filterForm.value.countyName
);
if (selectedRegion) { if (selectedRegion) {
params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || ''; params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || ''
} }
} }
if (filterForm.value.isEnded !== undefined && filterForm.value.isEnded !== '') { if (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) {
params.start = formatDateTime(filterForm.value.dateRange[0]); params.start = formatDateTime(filterForm.value.dateRange[0])
params.end = formatDateTime(filterForm.value.dateRange[1]); params.end = formatDateTime(filterForm.value.dateRange[1])
} }
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,
@ -261,79 +223,80 @@ const fetchWarningData = async () => {
warningTime: item.startTime || '-', warningTime: item.startTime || '-',
endTime: item.endTime || '-', endTime: item.endTime || '-',
impactCount: item.affectedCount || 0, impactCount: item.affectedCount || 0,
})); warningId: item.warningId || '',
}))
} else { } else {
tableData.value = []; tableData.value = []
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 {
loading.value = false; loading.value = false
} }
}; }
// //
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()
}; }
// //
const initDialogData = () => { const initDialogData = () => {
// //
if (getdateRange.value && getdateRange.value.length === 2) { if (getdateRange.value && getdateRange.value.length === 2) {
dateRange.value = getdateRange.value; dateRange.value = getdateRange.value
} }
// warningitem // warningitem
@ -343,83 +306,83 @@ const initDialogData = () => {
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()
}; }
// //
const resetData = () => { const resetData = () => {
// //
tableData.value = []; tableData.value = []
total.value = 0; total.value = 0
currentPage.value = 1; currentPage.value = 1
// //
filterForm.value = { filterForm.value = {
riskLeve: '', riskLeve: '',
countyName: '', countyName: '',
isEnded: '', isEnded: '',
dateRange: [], dateRange: [],
}; }
// //
dateRange.value = []; dateRange.value = []
}; }
// visible // visible
watch( watch(
() => props.visible, () => props.visible,
newVal => { (newVal) => {
if (newVal) { if (newVal) {
// //
initDialogData(); initDialogData()
} else { } else {
// //
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 && props.visible) {
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>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -8,7 +8,7 @@
: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>
@ -16,16 +16,11 @@
</div> </div>
</div> </div>
<!-- 气象预警监测表格组件 --> <!-- 气象预警监测表格组件 -->
<WeatherWarningTable ref="weatherWarningTableRef" @clearFilters="handleClearFilters" /> <WeatherWarningTable ref="weatherWarningTableRef" :getdateRange="getdateRange" @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">
<div <div v-for="(item, index) in hazardItems" :key="index" class="hazard-item" @click="handleHazardItemClick(item)">
v-for="(item, index) in hazardItems"
:key="index"
class="hazard-item"
@click="handleHazardItemClick(item)"
>
<img :src="item.icon" :alt="item.label" /> <img :src="item.icon" :alt="item.label" />
<span>{{ item.label }}</span> <span>{{ item.label }}</span>
</div> </div>
@ -34,12 +29,7 @@
<!-- 路段图片弹窗 --> <!-- 路段图片弹窗 -->
<div v-if="showRoadPopup" class="hazard-popup road-popup" :style="roadPopupStyle"> <div 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" :key="index" class="hazard-item" @click="handleRoadItemClick(item)">
v-for="(item, index) in roadItems"
:key="index"
class="hazard-item"
@click="handleRoadItemClick(item)"
>
<img :src="item.icon" :alt="item.label" /> <img :src="item.icon" :alt="item.label" />
<span>{{ item.label }}</span> <span>{{ item.label }}</span>
</div> </div>
@ -49,48 +39,43 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, nextTick } from 'vue'; import { ref, computed, nextTick, inject } from 'vue'
import WeatherWarningTable from './component/WeatherWarningTable.vue'; import WeatherWarningTable from './component/WeatherWarningTable.vue'
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 engineeringIconIconIcon from '../../assets/RiskWarning_img/危大工程icon@2x.png'; import engineeringIconIconIcon 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 engineeringIconIcon from '../../assets/RiskWarning_img/危大工程icon1@2x.png'; import engineeringIconIcon 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([ const getdateRange = inject('getdateRange', ref([]))
'changeActiveIndex', const emit = defineEmits(['changeActiveIndex', 'clearMapMarkers', 'hazardItemClick', 'roadItemClick', 'showHazardPopupfn'])
'clearMapMarkers',
'hazardItemClick',
'roadItemClick',
'showHazardPopupfn',
]);
const activeIndex = ref(-1); const activeIndex = ref(-1)
const menuItems = [ const menuItems = [
{ {
@ -108,7 +93,7 @@ const menuItems = [
icon1: roadIconIcon1, icon1: roadIconIcon1,
}, },
{ {
label: '项目', label: '驻地',
icon: 'icon-warning', icon: 'icon-warning',
iconClass: 'warning', iconClass: 'warning',
icon: warningIconIcon, icon: warningIconIcon,
@ -149,12 +134,12 @@ const menuItems = [
icon: engineeringIconIconIcon, icon: engineeringIconIconIcon,
icon1: engineeringIconIcon, icon1: engineeringIconIcon,
}, },
]; ]
// //
const showHazardPopup = ref(false); const showHazardPopup = ref(false)
const popupStyle = ref({}); const popupStyle = ref({})
const navIconRefs = ref([]); const navIconRefs = ref([])
// //
const hazardItems = ref([ const hazardItems = ref([
@ -164,11 +149,11 @@ const hazardItems = ref([
{ icon: hazardIconIcon4, label: '较大路外隐患点', isWithinRedLine: '否' }, { icon: hazardIconIcon4, label: '较大路外隐患点', isWithinRedLine: '否' },
{ icon: hazardIconIcon1, label: '一般路内隐患点', isWithinRedLine: '是' }, { icon: hazardIconIcon1, label: '一般路内隐患点', isWithinRedLine: '是' },
{ icon: hazardIconIcon2, label: '一般路外隐患点', isWithinRedLine: '否' }, { icon: hazardIconIcon2, label: '一般路外隐患点', isWithinRedLine: '否' },
]); ])
// //
const showRoadPopup = ref(false); const showRoadPopup = ref(false)
const roadPopupStyle = ref({}); const roadPopupStyle = ref({})
// //
const roadItems = ref([ const roadItems = ref([
@ -176,108 +161,108 @@ const roadItems = ref([
{ icon: tunnelLineIcon2, label: '较高风险路段' }, { icon: tunnelLineIcon2, label: '较高风险路段' },
{ icon: tunnelLineIcon1, label: '中风险路段' }, { icon: tunnelLineIcon1, label: '中风险路段' },
{ icon: tunnelLineIcon, label: '低风险路段' }, { icon: tunnelLineIcon, label: '低风险路段' },
]); ])
// nav-icon-boxref // nav-icon-boxref
const setNavIconRef = (el, index) => { const setNavIconRef = (el, index) => {
if (el) { if (el) {
navIconRefs.value[index] = el; navIconRefs.value[index] = el
} }
}; }
const weatherWarningTableRef = ref(null); const weatherWarningTableRef = ref(null)
// //
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) {
showRoadPopup.value = false; showRoadPopup.value = false
} }
if (showHazardPopup.value) { if (showHazardPopup.value) {
// //
const navIconBox = navIconRefs.value[index]; const navIconBox = navIconRefs.value[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 === '路段') {
// //
// //
showRoadPopup.value = !showRoadPopup.value; showRoadPopup.value = !showRoadPopup.value
if (showRoadPopup.value) { if (showRoadPopup.value) {
showHazardPopup.value = false; showHazardPopup.value = false
} }
if (showRoadPopup.value) { if (showRoadPopup.value) {
// //
const navIconBox = navIconRefs.value[index]; const navIconBox = navIconRefs.value[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: 2, zIndex: 2,
}; }
} }
} }
emit('showHazardPopupfn', false); emit('showHazardPopupfn', false)
} else { } else {
showHazardPopup.value = false; showHazardPopup.value = false
showRoadPopup.value = false; showRoadPopup.value = false
emit('showHazardPopupfn', false); emit('showHazardPopupfn', false)
// //
emit('hideRoadStats'); emit('hideRoadStats')
} }
activeIndex.value = index; activeIndex.value = index
if (item.label !== '路段') { if (item.label !== '路段') {
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); 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 handleClearFilters = () => { const handleClearFilters = () => {
console.log('清除筛选条件'); console.log('清除筛选条件')
// //
activeIndex.value = -1; activeIndex.value = -1
// //
showHazardPopup.value = false; showHazardPopup.value = false
showRoadPopup.value = false; showRoadPopup.value = false
// //
emit('clearMapMarkers'); emit('clearMapMarkers')
emit('showHazardPopupfn', false); emit('showHazardPopupfn', false)
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -2,12 +2,7 @@
<!-- 气象预警监测表格 --> <!-- 气象预警监测表格 -->
<div class="weather-warning-wrapper"> <div class="weather-warning-wrapper">
<div class="weather-warning-panel"> <div class="weather-warning-panel">
<img <img class="clear-icon" src="../../../assets/RiskWarning_img/清除icon@2x.png" alt="" @click="clearFilters" />
class="clear-icon"
src="../../../assets/RiskWarning_img/清除icon@2x.png"
alt=""
@click="clearFilters"
/>
<div class="panel-header"> <div class="panel-header">
<div class="header-title">气象预警监测</div> <div class="header-title">气象预警监测</div>
<div class="filter-tags"> <div class="filter-tags">
@ -48,13 +43,7 @@
<div class="warning-level"> <div class="warning-level">
<img <img
:src=" :src="
row.levelClass === 'red' row.levelClass === 'red' ? redIcon : row.levelClass === 'blue' ? blueIcon : row.levelClass === 'orange' ? orangeIcon : yellowIcon
? redIcon
: row.levelClass === 'blue'
? blueIcon
: row.levelClass === 'orange'
? orangeIcon
: yellowIcon
" "
alt="" alt=""
/> />
@ -70,14 +59,28 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'; import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { request } from '@/utils/request'; import { request } from '@/utils/request'
import orangeIcon from '../../../assets/RiskWarning_img/橙色@2x.png'; import orangeIcon from '../../../assets/RiskWarning_img/橙色@2x.png'
import yellowIcon from '../../../assets/RiskWarning_img/黄色@2x.png'; import yellowIcon from '../../../assets/RiskWarning_img/黄色@2x.png'
import redIcon from '../../../assets/RiskWarning_img//红色@2x.png'; import redIcon from '../../../assets/RiskWarning_img//红色@2x.png'
import blueIcon from '../../../assets/RiskWarning_img/蓝色@2x.png'; import blueIcon from '../../../assets/RiskWarning_img/蓝色@2x.png'
import { formatDateTime } from './index'
const emit = defineEmits(['clearFilters']); const emit = defineEmits(['clearFilters'])
const props = defineProps({
getdateRange: {
type: Array,
default: () => [],
},
})
watch(
() => props.getdateRange,
(newVal) => {
console.log('日期范围变化:===========', newVal)
fetchWeatherWarningData()
},
)
// //
const filters = ref({ const filters = ref({
@ -85,98 +88,94 @@ const filters = ref({
blue: false, blue: false,
orange: false, orange: false,
yellow: false, yellow: false,
}); })
// //
const warningData = ref([]); const warningData = ref([])
// //
const tableRef = ref(null); const tableRef = ref(null)
const isScrolling = ref(true); const isScrolling = ref(true)
const scrollTimer = ref(null); const scrollTimer = ref(null)
const scrollSpeed = 50; // const scrollSpeed = 50 //
const scrollStep = 1; // const scrollStep = 1 //
// //
const hasFilter = computed(() => { const hasFilter = computed(() => {
return filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow; return filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow
}); })
// //
const startAutoScroll = () => { const startAutoScroll = () => {
if (scrollTimer.value) { if (scrollTimer.value) {
clearInterval(scrollTimer.value); clearInterval(scrollTimer.value)
} }
if (!isScrolling.value || hasFilter.value) return; if (!isScrolling.value || hasFilter.value) return
const tableBody = document.querySelector( const tableBody = document.querySelector('.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap')
'.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap' if (!tableBody) return
);
if (!tableBody) return;
scrollTimer.value = setInterval(() => { scrollTimer.value = setInterval(() => {
if (tableBody) { if (tableBody) {
tableBody.scrollTop += scrollStep; tableBody.scrollTop += scrollStep
// 使 >= // 使 >=
const maxScroll = tableBody.scrollHeight - tableBody.clientHeight; const maxScroll = tableBody.scrollHeight - tableBody.clientHeight
if (tableBody.scrollTop >= maxScroll - 2) { if (tableBody.scrollTop >= maxScroll - 2) {
tableBody.scrollTop = 0; tableBody.scrollTop = 0
} }
} }
}, scrollSpeed); }, scrollSpeed)
}; }
// //
const stopAutoScroll = () => { const stopAutoScroll = () => {
if (scrollTimer.value) { if (scrollTimer.value) {
clearInterval(scrollTimer.value); clearInterval(scrollTimer.value)
scrollTimer.value = null; scrollTimer.value = null
} }
}; }
// //
const resetScrollToTop = () => { const resetScrollToTop = () => {
const tableBody = document.querySelector( const tableBody = document.querySelector('.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap')
'.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap'
);
if (tableBody) { if (tableBody) {
tableBody.scrollTop = 0; tableBody.scrollTop = 0
} }
}; }
// //
const handleMouseEnter = () => { const handleMouseEnter = () => {
stopAutoScroll(); stopAutoScroll()
}; }
// //
const handleMouseLeave = () => { const handleMouseLeave = () => {
if (!hasFilter.value) { if (!hasFilter.value) {
isScrolling.value = true; isScrolling.value = true
startAutoScroll(); startAutoScroll()
} }
}; }
// //
watch(hasFilter, newVal => { watch(hasFilter, (newVal) => {
if (newVal) { if (newVal) {
// //
stopAutoScroll(); stopAutoScroll()
resetScrollToTop(); resetScrollToTop()
} else { } else {
// //
isScrolling.value = true; isScrolling.value = true
nextTick(() => { nextTick(() => {
startAutoScroll(); startAutoScroll()
}); })
} }
}); })
// //
const loading = ref(false); const loading = ref(false)
// //
const fetchWeatherWarningData = async () => { const fetchWeatherWarningData = async () => {
loading.value = true; loading.value = true
try { try {
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',
@ -184,117 +183,118 @@ const fetchWeatherWarningData = async () => {
params: { params: {
offset: 0, offset: 0,
limit: 100000, limit: 100000,
start: props.getdateRange?.[0] ? formatDateTime(props.getdateRange[0] || '') : '',
end: props.getdateRange?.[1] ? formatDateTime(props.getdateRange[1] || '') : '',
}, },
}); })
console.log('气象预警数据:', res); console.log('气象预警数据:', res)
if (res.code === '00000' && res.data) { if (res.code === '00000' && res.data) {
// //
warningData.value = res.data.data.map(item => ({ warningData.value = res.data.data.map((item) => ({
time: item.startTime || '', time: item.startTime || '',
type: item.weatherType || '', type: item.weatherType || '',
level: item.riskLeve || '', level: item.riskLeve || '',
levelClass: getLevelClass(item.riskLeve || ''), levelClass: getLevelClass(item.riskLeve || ''),
district: item.countyName || '', district: item.countyName || '',
})); }))
} else { } else {
warningData.value = []; warningData.value = []
} }
loading.value = false; loading.value = false
nextTick(() => { nextTick(() => {
startAutoScroll(); startAutoScroll()
// //
const tableContainer = document.querySelector('.weather-warning-panel .table-container'); const tableContainer = document.querySelector('.weather-warning-panel .table-container')
if (tableContainer) { if (tableContainer) {
tableContainer.addEventListener('mouseenter', handleMouseEnter); tableContainer.addEventListener('mouseenter', handleMouseEnter)
tableContainer.addEventListener('mouseleave', handleMouseLeave); tableContainer.addEventListener('mouseleave', handleMouseLeave)
} }
}); })
} catch (error) { } catch (error) {
console.error('获取气象预警数据失败:', error); console.error('获取气象预警数据失败:', error)
warningData.value = []; warningData.value = []
loading.value = false; loading.value = false
} }
}; }
// class // class
const getLevelClass = level => { const getLevelClass = (level) => {
if (level.includes('红')) return 'red'; if (level.includes('红')) return 'red'
if (level.includes('橙')) return 'orange'; if (level.includes('橙')) return 'orange'
if (level.includes('黄')) return 'yellow'; if (level.includes('黄')) return 'yellow'
if (level.includes('蓝')) return 'blue'; if (level.includes('蓝')) return 'blue'
return ''; return ''
}; }
// //
onMounted(() => { onMounted(() => {
// //
console.log('获取气象预警数据'); console.log('获取气象预警数据')
fetchWeatherWarningData(); fetchWeatherWarningData()
}); })
onUnmounted(() => { onUnmounted(() => {
stopAutoScroll(); stopAutoScroll()
const tableContainer = document.querySelector('.weather-warning-panel .table-container'); const tableContainer = document.querySelector('.weather-warning-panel .table-container')
if (tableContainer) { if (tableContainer) {
tableContainer.removeEventListener('mouseenter', handleMouseEnter); tableContainer.removeEventListener('mouseenter', handleMouseEnter)
tableContainer.removeEventListener('mouseleave', handleMouseLeave); tableContainer.removeEventListener('mouseleave', handleMouseLeave)
} }
}); })
// //
const filteredData = computed(() => { const filteredData = computed(() => {
const hasFilter = const hasFilter = filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow
filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow; if (!hasFilter) return warningData.value
if (!hasFilter) return warningData.value;
return warningData.value.filter(item => { return warningData.value.filter((item) => {
if (filters.value.red && item.levelClass === 'red') return true; if (filters.value.red && item.levelClass === 'red') return true
if (filters.value.blue && item.levelClass === 'blue') return true; if (filters.value.blue && item.levelClass === 'blue') return true
if (filters.value.orange && item.levelClass === 'orange') return true; if (filters.value.orange && item.levelClass === 'orange') return true
if (filters.value.yellow && item.levelClass === 'yellow') return true; if (filters.value.yellow && item.levelClass === 'yellow') return true
return false; return false
}); })
}); })
// el-table // el-table
const headerCellStyle = () => ({ const headerCellStyle = () => ({
background: '#17466F', background: '#17466F',
color: 'rgba(255, 255, 255, 0.6)', color: 'rgba(255, 255, 255, 0.6)',
}); })
const cellStyle = () => ({ const cellStyle = () => ({
background: '#142E49', background: '#142E49',
color: 'rgba(255, 255, 255, 0.9)', color: 'rgba(255, 255, 255, 0.9)',
borderBottom: '1px solid rgba(64, 169, 255, 0.1)', borderBottom: '1px solid rgba(64, 169, 255, 0.1)',
padding: '5px 5px', padding: '5px 5px',
}); })
const rowClassName = ({ rowIndex }) => { const rowClassName = ({ rowIndex }) => {
return rowIndex % 2 === 0 ? 'even-row' : 'odd-row'; return rowIndex % 2 === 0 ? 'even-row' : 'odd-row'
}; }
// //
const clearFilters = () => { const clearFilters = () => {
console.log('清除筛选条件'); console.log('清除筛选条件')
filters.value = { filters.value = {
red: false, red: false,
blue: false, blue: false,
orange: false, orange: false,
yellow: false, yellow: false,
}; }
// //
emit('clearFilters'); emit('clearFilters')
}; }
// //
const setWarningData = data => { const setWarningData = (data) => {
warningData.value = data; warningData.value = data
}; }
defineExpose({ defineExpose({
clearFilters, clearFilters,
setWarningData, setWarningData,
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -179,7 +179,7 @@ export const logUserOperation = (type, command) => {
// 使用 fetch 的 keepalive 选项确保页面卸载后请求仍能完成 // 使用 fetch 的 keepalive 选项确保页面卸载后请求仍能完成
fetch('/snow-ops-platform/weather-warning/users/logs', { fetch('/snow-ops-platform/weather-warning/users/logs', {
method: 'PUT', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
@ -201,121 +201,6 @@ export const logUserOperation = (type, command) => {
} }
} }
// 监听外部应用打开并记录日志的辅助函数
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) => { export const openVideoConference = async (item) => {
@ -419,14 +304,21 @@ export const opencallConference = async (item) => {
logUserOperation('phone-based-confirmation', JSON.stringify(jsobj)) logUserOperation('phone-based-confirmation', JSON.stringify(jsobj))
} }
// 基础 API 地址配置根据当前网址动态判断存在bxztpc时外网地址否则内网地址
const BASE_API_URL = window.location.href.includes('bxztpc')
? 'http://58.144.223.132:30008/'
: PROXY_TARGET
// 从本地存储获取 token // 从本地存储获取 token
const getTokenFromStorage = () => { const getTokenFromStorage = () => {
try { try {
// 首先尝试从 URL 获取 token
const urlParams = new URLSearchParams(window.location.search)
const urlToken = urlParams.get('token')
console.log('从 URL 获取的 token:', urlToken)
if (urlToken) {
// 更新本地存储
localStorage.setItem('token', urlToken)
sessionStorage.setItem('token', urlToken)
console.log('从 URL 获取并更新 token 成功')
return urlToken
}
// 尝试从 localStorage 获取 // 尝试从 localStorage 获取
const token = localStorage.getItem('token') const token = localStorage.getItem('token')
if (token) return token if (token) return token
@ -442,6 +334,8 @@ const getTokenFromStorage = () => {
} }
} }
// 基础 API 地址配置根据当前网址动态判断存在bxztpc时外网地址否则内网地址
const BASE_API_URL = 'http://58.144.223.132:30008/'
// 获取图片地址数组 // 获取图片地址数组
export const getImageUrlList = (fileIdStr) => { export const getImageUrlList = (fileIdStr) => {
if (!fileIdStr || typeof fileIdStr !== 'string') { if (!fileIdStr || typeof fileIdStr !== 'string') {
@ -450,7 +344,10 @@ export const getImageUrlList = (fileIdStr) => {
} }
// 按逗号分割字符串 // 按逗号分割字符串
const fileIdList = fileIdStr.split(',').map(id => id.trim()).filter(id => id) const fileIdList = fileIdStr
.split(',')
.map((id) => id.trim())
.filter((id) => id)
if (fileIdList.length === 0) { if (fileIdList.length === 0) {
console.warn('fileIdStr 分割后为空') console.warn('fileIdStr 分割后为空')
@ -461,7 +358,7 @@ export const getImageUrlList = (fileIdStr) => {
const token = getTokenFromStorage() const token = getTokenFromStorage()
// 构建图片地址数组 // 构建图片地址数组
const imageUrlList = fileIdList.map(fileId => { const imageUrlList = fileIdList.map((fileId) => {
return `${BASE_API_URL}apis/file-api/private/preview?fileId=${fileId}&token=${token}` return `${BASE_API_URL}apis/file-api/private/preview?fileId=${fileId}&token=${token}`
}) })

View File

@ -1,113 +0,0 @@
<template>
<div class="risk-table">
<table>
<thead>
<tr>
<th class="col-type">
<div>项目</div>
<div>类型</div>
</th>
<th class="col-red">红色预警</th>
<th class="col-orange">橙色预警</th>
<th class="col-yellow">黄色预警</th>
<th class="col-blue">蓝色预警</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in tableData" :key="index">
<td class="col-type">{{ item.type }}</td>
<td class="col-red">{{ item.red }}</td>
<td class="col-orange">{{ item.orange }}</td>
<td class="col-yellow">{{ item.yellow }}</td>
<td class="col-blue">{{ item.blue }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script setup>
defineProps({
tableData: {
type: Array,
default: () => [
{ type: '桥梁', red: 0, orange: 1, yellow: 8, blue: 11 },
{ type: '隧道', red: 0, orange: 0, yellow: 6, blue: 12 },
{ type: '边坡', red: 0, orange: 1, yellow: 9, blue: 9 },
{ type: '路段', red: 0, orange: 2, yellow: 11, blue: 7 },
{ type: '项目', red: 0, orange: 2, yellow: 11, blue: 7 },
],
},
});
</script>
<style lang="scss" scoped>
.risk-table {
width: 100%;
height: 100%;
padding: 10px;
box-sizing: border-box;
table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
color: #fff;
th,
td {
padding: 4px 4px;
text-align: center;
border: none;
}
thead {
th {
font-weight: normal;
font-size: 12px;
color: rgba(255, 255, 255, 0.8);
&.col-type {
color: rgba(255, 255, 255, 0.6);
}
}
}
tbody {
tr {
&:nth-child(odd) {
background-color: rgba(255, 255, 255, 0.05);
}
td {
font-size: 14px;
&.col-type {
color: rgba(255, 255, 255, 0.9);
}
}
}
}
.col-red {
color: #ff4d4f;
}
.col-orange {
color: #ff7a45;
}
.col-yellow {
color: #ffc53d;
}
.col-blue {
color: #40a9ff;
}
.col-type {
width: 20%;
}
}
}
</style>

View File

@ -103,6 +103,7 @@
v-model:visible="dialogVisible.warningInfo" v-model:visible="dialogVisible.warningInfo"
@close="closeDialog('warningInfo')" @close="closeDialog('warningInfo')"
@responseStatus="openDialog('responseStatus')" @responseStatus="openDialog('responseStatus')"
@getResponseStatusrowFn="getResponseStatusfn"
/> />
<!-- 事件详情对话框 --> <!-- 事件详情对话框 -->
@ -129,6 +130,7 @@
<!-- 影响点情况对话框 --> <!-- 影响点情况对话框 -->
<impactPointDialog <impactPointDialog
:handleImpactItem="handleImpactItem" :handleImpactItem="handleImpactItem"
:getdateRange="getdateRange"
v-model:visible="dialogVisible.impactPoint" v-model:visible="dialogVisible.impactPoint"
@close="closeDialog('impactPoint')" @close="closeDialog('impactPoint')"
@detail="openDialog('impactPointDetail')" @detail="openDialog('impactPointDetail')"
@ -151,6 +153,7 @@
<!-- 响应状态对话框 --> <!-- 响应状态对话框 -->
<responseStatusDialog <responseStatusDialog
:dispatchDateRange="dispatchDateRange" :dispatchDateRange="dispatchDateRange"
:responseStatusData="responseStatusRow"
v-model:visible="dialogVisible.responseStatus" v-model:visible="dialogVisible.responseStatus"
@close="closeDialog('responseStatus')" @close="closeDialog('responseStatus')"
@detail="openDialog('responsePointDetail')" @detail="openDialog('responsePointDetail')"
@ -240,7 +243,7 @@
<imageInspectionDialog v-model:visible="dialogVisible.imageInspection" @close="closeDialog('imageInspection')" /> <imageInspectionDialog v-model:visible="dialogVisible.imageInspection" @close="closeDialog('imageInspection')" />
<!-- 巡查里程对话框 --> <!-- 巡查里程对话框 -->
<patrolMileageDialog v-model:visible="dialogVisible.patrolMileage" @close="closeDialog('patrolMileage')" /> <patrolMileageDialog v-model:visible="dialogVisible.patrolMileage" :getdateRange="getdateRange" @close="closeDialog('patrolMileage')" />
<!-- 巡查情况对话框 --> <!-- 巡查情况对话框 -->
<patrolSituationDialog v-model:visible="dialogVisible.patrolSituation" @close="closeDialog('patrolSituation')" /> <patrolSituationDialog v-model:visible="dialogVisible.patrolSituation" @close="closeDialog('patrolSituation')" />
@ -373,7 +376,7 @@ 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
} }
@ -387,8 +390,9 @@ const handleHideRoadStats = () => {
const handleHazardItemClick = (item) => { const handleHazardItemClick = (item) => {
console.log('点击隐患点:', item) console.log('点击隐患点:', item)
// //
let items = { ...item }
if (chongqingMapRef.value) { if (chongqingMapRef.value) {
chongqingMapRef.value.handleHazardItemClick(item) chongqingMapRef.value.handleHazardItemClick(items, false)
} }
} }
const showHazardPopup = ref(false) const showHazardPopup = ref(false)
@ -459,17 +463,17 @@ 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) => {
@ -482,7 +486,7 @@ const closeDialog = (dialogName) => {
const handleOpenHazardPointSituation = (item) => { const handleOpenHazardPointSituation = (item) => {
console.log('打开涉灾隐患点情况弹窗:', item) console.log('打开涉灾隐患点情况弹窗:', item)
hazardPointDialogTitle.value = '涉灾隐患点情况' hazardPointDialogTitle.value = '涉灾隐患点情况'
hazardPointData.value = item hazardPointData.value = { ...item }
dialogVisible.value.hazardPointSituation = true dialogVisible.value.hazardPointSituation = true
} }
@ -502,28 +506,33 @@ const handleOpenRoadSectionSituation = (item) => {
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 responseStatusRow = ref({})
const getResponseStatusfn = (row) => {
console.log('已叫应详情:', row)
responseStatusRow.value = row
} }
// //
@ -571,7 +580,7 @@ const handleDistrictClick = (item) => {
} 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')
} }
} }

View File

@ -70,7 +70,7 @@
<el-table-column prop="bridgeCount" label="桥梁" :min-width="vw(50)" /> <el-table-column prop="bridgeCount" label="桥梁" :min-width="vw(50)" />
<el-table-column prop="tunnelCount" label="隧道" :min-width="vw(50)" /> <el-table-column prop="tunnelCount" label="隧道" :min-width="vw(50)" />
<el-table-column prop="slopeCount" label="边坡" :min-width="vw(50)" /> <el-table-column prop="slopeCount" label="边坡" :min-width="vw(50)" />
<el-table-column prop="projectCount" label="项目" :min-width="vw(50)" /> <el-table-column prop="projectCount" label="驻地" :min-width="vw(50)" />
</el-table> </el-table>
</div> </div>
@ -79,7 +79,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> <!-- <span class="filter-item active" @click="handleDateRangeClick()">本轮</span> -->
<div class="date-range-wrapper"> <div class="date-range-wrapper">
<el-date-picker <el-date-picker
v-model="dateRange" v-model="dateRange"
@ -153,6 +153,7 @@ watch(
() => getdateRange.value, () => getdateRange.value,
(newVal) => { (newVal) => {
console.log('left.vue 日期范围变化:', newVal) console.log('left.vue 日期范围变化:', newVal)
dateRange.value = JSON.parse(JSON.stringify(newVal))
init() init()
}, },
{ deep: true }, { deep: true },
@ -258,7 +259,7 @@ const impactData = ref([
{ name: '桥梁', count: 0 }, { name: '桥梁', count: 0 },
{ name: '隧道', count: 0 }, { name: '隧道', count: 0 },
{ name: '边坡', count: 0 }, { name: '边坡', count: 0 },
{ name: '项目', count: 0 }, { name: '驻地', count: 0 },
]) ])
const dateRange = ref([]) const dateRange = ref([])
@ -593,12 +594,12 @@ const loadBarChartData = async () => {
bridge: '桥梁', bridge: '桥梁',
tunnel: '隧道', tunnel: '隧道',
slope: '边坡', slope: '边坡',
project: '项目', project: '驻地',
Road: '路段', Road: '路段',
Bridge: '桥梁', Bridge: '桥梁',
Tunnel: '隧道', Tunnel: '隧道',
Slope: '边坡', Slope: '边坡',
Project: '项目', Project: '驻地',
} }
// name // name
@ -615,7 +616,7 @@ const loadBarChartData = async () => {
impactData.value[2].count = item.count || 0 impactData.value[2].count = item.count || 0
} else if (item.name == '边坡') { } else if (item.name == '边坡') {
impactData.value[3].count = item.count || 0 impactData.value[3].count = item.count || 0
} else if (item.name == '项目') { } else if (item.name == '驻地') {
impactData.value[4].count = item.count || 0 impactData.value[4].count = item.count || 0
} }
}) })
@ -628,7 +629,7 @@ const loadBarChartData = async () => {
{ name: '桥梁', count: 0 }, { name: '桥梁', count: 0 },
{ name: '隧道', count: 0 }, { name: '隧道', count: 0 },
{ name: '边坡', count: 0 }, { name: '边坡', count: 0 },
{ name: '项目', count: 0 }, { name: '驻地', count: 0 },
]), ]),
) )
} }

View File

@ -107,7 +107,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> <!-- <span class="filter-item active" @click="handleDateRangeClick()">本轮</span> -->
<div class="date-range-wrapper"> <div class="date-range-wrapper">
<el-date-picker <el-date-picker
v-model="dateRange" v-model="dateRange"
@ -205,6 +205,7 @@ 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'
import { formatDateTime } from './component/index.js' import { formatDateTime } from './component/index.js'
const getdateRange = inject('getdateRange', ref([]))
const emit = defineEmits([ const emit = defineEmits([
'openClearanceSituation', 'openClearanceSituation',
@ -218,7 +219,6 @@ const emit = defineEmits([
// //
const setRefreshRightData = inject('setRefreshRightData') const setRefreshRightData = inject('setRefreshRightData')
const getdateRange = inject('getdateRange', ref([]))
const props = defineProps({}) const props = defineProps({})
@ -586,10 +586,10 @@ const handleResourceClick = (item) => {
// //
const controlData1 = ref([ const controlData1 = ref([
{ label: '封闭管控数', value: '40' }, { label: '封闭管控数', value: '40', key: '全幅封闭' },
{ label: '半幅通行数', value: '40' }, { label: '半幅通行数', value: '40', key: '半幅封闭' },
{ label: '限速(限车型)数', value: '24' }, { label: '限速(限车型)数', value: '24', key: '限速' },
{ label: '告警阻拦处数', value: '32' }, { label: '告警阻拦处数', value: '32', key: '告警阻拦' },
]) ])
const controlData2 = ref([ const controlData2 = ref([
{ label: '停工项目数', value: '0', key: 'stoped_project_count' }, { label: '停工项目数', value: '0', key: 'stoped_project_count' },
@ -756,6 +756,7 @@ watch(
() => getdateRange.value, () => getdateRange.value,
(newVal) => { (newVal) => {
console.log('right.vue 日期范围变化:', newVal) console.log('right.vue 日期范围变化:', newVal)
dateRange.value = newVal
init() init()
}, },
{ deep: true, immediate: true }, { deep: true, immediate: true },

View File

@ -81,7 +81,16 @@ const emit = defineEmits(['openAIResult', 'dateRangeChange'])
// //
const triggerRefreshLeftData = inject('triggerRefreshLeftData') const triggerRefreshLeftData = inject('triggerRefreshLeftData')
const dateRange = ref([])
// 00:00:00 - 23:59:59
const getTodayDateRange = () => {
const today = new Date()
const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0)
const endOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59)
return [startOfDay, endOfDay]
}
const dateRange = ref(getTodayDateRange())
// //
const hazardStatsShowArr = ref([]) const hazardStatsShowArr = ref([])
@ -219,6 +228,10 @@ const fetchRiskLevelCount = async () => {
// //
onMounted(() => { onMounted(() => {
//
const todayRange = getTodayDateRange()
dateRange.value = todayRange
emit('dateRangeChange', todayRange)
fetchRiskLevelCount() fetchRiskLevelCount()
}) })
</script> </script>

View File

@ -98,7 +98,7 @@ const columns = [
}, },
{ {
prop: "affectedProjectCount", prop: "affectedProjectCount",
label: "影响项目", label: "影响驻地",
}, },
{ {
prop: "responseStatus", prop: "responseStatus",