Compare commits

..

No commits in common. "0d0f2d39370d968475aa155d1323d92e948da720" and "f304d444ab8318f4cf92736ffada752bfc80ce33" have entirely different histories.

20 changed files with 1888 additions and 2245 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,14 +116,7 @@ watch(
(newVal) => { (newVal) => {
console.log('newVal', newVal) console.log('newVal', newVal)
if (newVal.label) { if (newVal.label) {
// label filterForm.value.roadConditionType = newVal.label.substring(0, newVal.label.length - 1) || ''
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,51 +1,39 @@
<template> <template>
<div> <div v-if="visible" class="confirm-dialog-overlay" @click="handleOverlayClick">
<!-- 确认弹窗 --> <div class="confirm-dialog" @click.stop>
<div v-if="visible" class="confirm-dialog-overlay" @click="handleOverlayClick"> <!-- 四个角的装饰 -->
<div class="confirm-dialog" @click.stop> <div class="corner corner-top-left"></div>
<!-- 四个角的装饰 --> <div class="corner corner-top-right"></div>
<div class="corner corner-top-left"></div> <div class="corner corner-bottom-left"></div>
<div class="corner corner-top-right"></div> <div class="corner corner-bottom-right"></div>
<div class="corner corner-bottom-left"></div> <!-- 标题栏 -->
<div class="corner corner-bottom-right"></div> <div class="dialog-header">
<!-- 标题栏 --> <div class="header-title">{{ title }}</div>
<div class="dialog-header"> <div class="close-btn" @click="handleCancel">
<div class="header-title">{{ title }}</div> <el-icon><Close /></el-icon>
<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>
<!-- 软电话配置弹窗 --> <!-- 提示内容 -->
<SoftPhoneConfigDialog <div class="dialog-content">
v-model:visible="softPhoneVisible" <p class="confirm-message">{{ message }}</p>
@confirm="handleSoftPhoneConfirm" </div>
@cancel="handleSoftPhoneCancel"
/> <!-- 按钮区域 -->
<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>
</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: {
@ -72,28 +60,12 @@ 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 = () => {
softPhoneVisible.value = true; emit('confirm');
};
//
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,21 +54,13 @@
</div> </div>
<!-- 照片 - 路段数据展示 --> <!-- 照片 - 路段数据展示 -->
<div v-if="hazardData.photos" class="info-block display"> <div v-if="isRoadData && 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(index)" /> <img v-for="(photo, index) in hazardData.photos" :key="index" :src="photo" class="photo-item" @click="previewPhoto(photo)" />
</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>
@ -321,14 +313,11 @@ const handleCurrentChange = (val) => {
currentPage.value = val currentPage.value = val
} }
//
const previewVisible = ref(false)
const previewIndex = ref(0)
// //
const previewPhoto = (index) => { const previewPhoto = (photo) => {
previewIndex.value = index // 使 Element Plus
previewVisible.value = true const { preview } = require('element-plus')
preview(photo)
} }
// //

View File

@ -219,10 +219,6 @@ 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'])
@ -232,7 +228,7 @@ const filterForm = ref({
pointType: '', pointType: '',
pointLevel: '', pointLevel: '',
region: '', region: '',
roadType: 'G,S', roadType: '',
}) })
// 使 // 使
@ -332,20 +328,14 @@ 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') {
@ -357,12 +347,12 @@ const loadBarChartData = async () => {
bridge: '桥梁', bridge: '桥梁',
tunnel: '隧道', tunnel: '隧道',
slope: '边坡', slope: '边坡',
project: '驻地', project: '项目',
Road: '路段', Road: '路段',
Bridge: '桥梁', Bridge: '桥梁',
Tunnel: '隧道', Tunnel: '隧道',
Slope: '边坡', Slope: '边坡',
Project: '驻地', Project: '项目',
} }
// name // name
@ -394,13 +384,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
} }
@ -410,7 +400,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'
@ -491,22 +481,21 @@ const handleFilterChange = () => {
const getTimeParams = () => { const getTimeParams = () => {
console.log('原始时间范围:', props.handleImpactItem) console.log('原始时间范围:', props.handleImpactItem)
let countyId = '' let countyName = ''
console.log('区域:', filterForm.value)
regionOptions.value.forEach((item) => { regionOptions.value.forEach((item) => {
if (item.label === filterForm.value.region || item.value === filterForm.value.region) { if (item.label === filterForm.value.region) {
countyId = item.value || '' countyName = item.label || ''
} }
}) })
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.getdateRange[0] ? props.getdateRange[0] : props.handleImpactItem.dateRange?.[0] || ''), start: formatDateTime(props.handleImpactItem.dateRange?.[0] || ''),
end: formatDateTime(props.getdateRange[1] ? props.getdateRange[1] : props.handleImpactItem.dateRange?.[1] || ''), end: formatDateTime(props.handleImpactItem.dateRange?.[1] || ''),
limit: pageSize.value, limit: pageSize.value,
offset: (currentPage.value - 1) * pageSize.value, offset: (currentPage.value - 1) * pageSize.value,
countyId: countyId || '', countyName: countyName || '',
riskLevel: filterForm.value.pointLevel || '', riskLevel: filterForm.value.pointLevel || '',
roadTypes: filterForm.value.roadType || '', roadTypes: filterForm.value.roadType || '',
} }
@ -703,7 +692,7 @@ const processUnifiedData = (item, type) => {
} }
// SQL // SQL
if (cardTypeVal.value === '驻地') { if (cardTypeVal.value === '项目') {
return { return {
...baseData, ...baseData,
// - 使COUNTY // - 使COUNTY
@ -776,14 +765,6 @@ 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) {
// //
@ -844,7 +825,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
:visible="props.visible" v-model:visible="props.visible"
title="巡查里程" title="巡查里程"
:table-data="tableData" :table-data="tableData"
:table-columns="tableColumns" :table-columns="tableColumns"
@ -11,7 +11,6 @@
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
@close="handleClose" @close="handleClose"
@update:visible="handleClose"
> >
<!-- 统计卡片区域 --> <!-- 统计卡片区域 -->
<template #header> <template #header>
@ -40,7 +39,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"
@ -49,7 +48,12 @@
clearable clearable
@change="handleFilterChange" @change="handleFilterChange"
> >
<el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option
v-for="item in districtOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> </el-select>
</div> </div>
</div> </div>
@ -58,143 +62,184 @@
</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/yhWgxc/county-mileage', url: '/snow-ops-platform/patrol/mileage-list',
method: 'GET', method: 'GET',
params: { params: {
pageNum: currentPage.value, pageNum: currentPage.value,
pageSize: pageSize.value, pageSize: pageSize.value,
startTime: formatDateTime(props.getdateRange?.[0] || ''), districtCode: filterForm.value.district,
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.qxmc || '-', district: item.districtName || '-',
mileage: item.mileage ? `${item.mileage}公里` : '0', mileage: item.mileage ? `${item.mileage}公里` : '-',
} };
}) });
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 => {
tableData.value = [] if (newVal) {
total.value = 0 currentPage.value = 1;
currentPage.value = 1 fetchStatsData();
// fetchStatsData() fetchData();
fetchData() }
}, }
) );
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -206,6 +251,7 @@ 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,21 +41,52 @@
<!-- 筛选区域 --> <!-- 筛选区域 -->
<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 :teleported="false" v-model="filterForm.pointLevel" placeholder="影响点等级" class="filter-select"> <el-select
<el-option v-for="option in pointLevelOptions" :key="option.value" :label="option.label" :value="option.value" /> :teleported="false"
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 :teleported="false" v-model="filterForm.isResponded" placeholder="是否回应" class="filter-select"> <el-select
<el-option v-for="option in isRespondedOptions" :key="option.value" :label="option.label" :value="option.value" /> :teleported="false"
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>
@ -69,7 +100,11 @@
<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 class="response-icon" :src="row.trafficDept.isResponded ? row.trafficDept.img : row.trafficDept.img" alt /> <img
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>
@ -109,9 +144,9 @@
</template> </template>
<!-- 回应状态列插槽 --> <!-- 回应状态列插槽 -->
<!-- <template #responseStatusData="{ row }"> <!-- <template #responseStatus="{ row }">
<span class="response-status" :class="row.responseClass">{{ <span class="response-status" :class="row.responseClass">{{
row.responseStatusData row.responseStatus
}}</span> }}</span>
</template> --> </template> -->
@ -131,22 +166,27 @@
</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 { pointTypeOptions, pointLevelOptions, isRespondedOptions, formatDateTime } from '../component/index.js' import {
import baseDialog from '../component/baseDialog.vue' pointTypeOptions,
import { request } from '@/utils/request.js' pointLevelOptions,
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: {
@ -157,22 +197,18 @@ 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([
@ -180,8 +216,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([
@ -198,40 +234,37 @@ 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 = {
@ -239,44 +272,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 () => {
@ -284,32 +317,29 @@ 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,
@ -342,26 +372,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: '路段',
@ -369,52 +399,46 @@ 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

@ -1,370 +0,0 @@
<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,7 +26,12 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option v-for="option in warningLevelOptions" :key="option.value" :label="option.label" :value="option.value" /> <el-option
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">
@ -38,7 +43,12 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option v-for="option in regionOptions" :key="option.value" :label="option.label" :value="option.value" /> <el-option
v-for="option in regionOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
</div> </div>
<div class="filter-item"> <div class="filter-item">
@ -50,7 +60,12 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option v-for="option in isEndedOptions" :key="option.value" :label="option.label" :value="option.value" /> <el-option
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">
@ -62,7 +77,12 @@
@change="handleWarningLevelChange" @change="handleWarningLevelChange"
clearable clearable
> >
<el-option v-for="option in isRespondedOptions" :key="option.value" :label="option.label" :value="option.value" /> <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"> <div class="filter-item">
@ -87,12 +107,17 @@
</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 { warningLevelOptions, regionOptions, isEndedOptions, isRespondedOptions } from '../component/index.js' import {
warningLevelOptions,
regionOptions,
isEndedOptions,
isRespondedOptions,
} from '../component/index.js';
const props = defineProps({ const props = defineProps({
visible: { visible: {
@ -103,9 +128,9 @@ const props = defineProps({
type: Array, type: Array,
default: () => [], default: () => [],
}, },
}) });
const emit = defineEmits(['update:visible', 'close', 'openImpactPoint', 'getResponseStatusrowFn']) const emit = defineEmits(['update:visible', 'close', 'openImpactPoint']);
// //
const filterForm = ref({ const filterForm = ref({
@ -113,7 +138,7 @@ const filterForm = ref({
region: '', region: '',
isEnded: '', isEnded: '',
isResponded: '', isResponded: '',
}) });
// //
const tableColumns = ref([ const tableColumns = ref([
@ -128,56 +153,82 @@ 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 = (row) => { const handleCalledClick = () => {
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: '',
@ -188,28 +239,30 @@ 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((option) => option.value === filterForm.value.region) const selectedRegion = regionOptions.value.find(
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) => ({
@ -225,47 +278,46 @@ 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,20 +17,56 @@
<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 v-model="filterForm.riskLeve" placeholder="请选择" class="filter-select el-select" clearable size="small" :teleported="false"> <el-select
<el-option v-for="item in warningLevelOptions" :key="item.value" :label="item.label" :value="item.value" /> v-model="filterForm.riskLeve"
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 v-model="filterForm.countyName" placeholder="请选择" class="filter-select" clearable size="small" :teleported="false"> <el-select
<el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" /> v-model="filterForm.countyName"
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 v-model="filterForm.isEnded" placeholder="请选择" class="filter-select" clearable size="small" :teleported="false"> <el-select
<el-option v-for="item in isEndedOptions" :key="item.value" :label="item.label" :value="item.value" /> v-model="filterForm.isEnded"
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>
@ -65,14 +101,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: {
@ -83,44 +119,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({
@ -128,12 +164,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
@ -145,7 +181,7 @@ const handleDateChange = (val) => {
// index.js // index.js
// //
const tableHeight = ref(300) const tableHeight = ref(300);
// //
const tableColumns = ref([ const tableColumns = ref([
@ -157,22 +193,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,
@ -183,36 +219,38 @@ 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((option) => option.value === filterForm.value.countyName) const selectedRegion = regionOptions.value.find(
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,
@ -223,80 +261,79 @@ 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
@ -306,83 +343,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 && props.visible) { if (oldVal && Object.keys(oldVal).length > 0) {
currentPage.value = 1 currentPage.value = 1;
fetchWarningData() fetchWarningData();
} }
}, },
{ deep: true }, { deep: true }
) );
// dateRange filterForm.dateRange // dateRange filterForm.dateRange
watch( watch(
() => dateRange.value, () => dateRange.value,
(newVal) => { newVal => {
filterForm.value.dateRange = newVal filterForm.value.dateRange = newVal;
}, },
{ deep: true }, { deep: true }
) );
watch( watch(
() => filterForm.value.dateRange, () => filterForm.value.dateRange,
(newVal) => { newVal => {
dateRange.value = newVal dateRange.value = newVal;
}, },
{ deep: true }, { deep: true }
) );
</script> </script>
<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,11 +16,16 @@
</div> </div>
</div> </div>
<!-- 气象预警监测表格组件 --> <!-- 气象预警监测表格组件 -->
<WeatherWarningTable ref="weatherWarningTableRef" :getdateRange="getdateRange" @clearFilters="handleClearFilters" /> <WeatherWarningTable ref="weatherWarningTableRef" @clearFilters="handleClearFilters" />
<!-- 涉灾隐患点图片弹窗 --> <!-- 涉灾隐患点图片弹窗 -->
<div v-if="showHazardPopup" class="hazard-popup" :style="popupStyle"> <div v-if="showHazardPopup" class="hazard-popup" :style="popupStyle">
<div class="hazard-popup-content"> <div class="hazard-popup-content">
<div v-for="(item, index) in hazardItems" :key="index" class="hazard-item" @click="handleHazardItemClick(item)"> <div
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>
@ -29,7 +34,12 @@
<!-- 路段图片弹窗 --> <!-- 路段图片弹窗 -->
<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 v-for="(item, index) in roadItems" :key="index" class="hazard-item" @click="handleRoadItemClick(item)"> <div
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>
@ -39,43 +49,48 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, nextTick, inject } from 'vue' import { ref, computed, nextTick } 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 getdateRange = inject('getdateRange', ref([])) const emit = defineEmits([
const emit = defineEmits(['changeActiveIndex', 'clearMapMarkers', 'hazardItemClick', 'roadItemClick', 'showHazardPopupfn']) 'changeActiveIndex',
'clearMapMarkers',
'hazardItemClick',
'roadItemClick',
'showHazardPopupfn',
]);
const activeIndex = ref(-1) const activeIndex = ref(-1);
const menuItems = [ const menuItems = [
{ {
@ -93,7 +108,7 @@ const menuItems = [
icon1: roadIconIcon1, icon1: roadIconIcon1,
}, },
{ {
label: '驻地', label: '项目',
icon: 'icon-warning', icon: 'icon-warning',
iconClass: 'warning', iconClass: 'warning',
icon: warningIconIcon, icon: warningIconIcon,
@ -134,12 +149,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([
@ -149,11 +164,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([
@ -161,108 +176,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,7 +2,12 @@
<!-- 气象预警监测表格 --> <!-- 气象预警监测表格 -->
<div class="weather-warning-wrapper"> <div class="weather-warning-wrapper">
<div class="weather-warning-panel"> <div class="weather-warning-panel">
<img class="clear-icon" src="../../../assets/RiskWarning_img/清除icon@2x.png" alt="" @click="clearFilters" /> <img
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">
@ -43,7 +48,13 @@
<div class="warning-level"> <div class="warning-level">
<img <img
:src=" :src="
row.levelClass === 'red' ? redIcon : row.levelClass === 'blue' ? blueIcon : row.levelClass === 'orange' ? orangeIcon : yellowIcon row.levelClass === 'red'
? redIcon
: row.levelClass === 'blue'
? blueIcon
: row.levelClass === 'orange'
? orangeIcon
: yellowIcon
" "
alt="" alt=""
/> />
@ -59,28 +70,14 @@
</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({
@ -88,94 +85,98 @@ 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('.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap') const tableBody = document.querySelector(
if (!tableBody) return '.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap'
);
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('.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap') const tableBody = document.querySelector(
'.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',
@ -183,118 +184,117 @@ 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 = filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow const hasFilter =
if (!hasFilter) return warningData.value filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow;
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: 'POST', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
@ -201,6 +201,121 @@ 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) => {
@ -304,21 +419,14 @@ 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
@ -334,8 +442,6 @@ 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') {
@ -344,10 +450,7 @@ export const getImageUrlList = (fileIdStr) => {
} }
// 按逗号分割字符串 // 按逗号分割字符串
const fileIdList = fileIdStr const fileIdList = fileIdStr.split(',').map(id => id.trim()).filter(id => id)
.split(',')
.map((id) => id.trim())
.filter((id) => id)
if (fileIdList.length === 0) { if (fileIdList.length === 0) {
console.warn('fileIdStr 分割后为空') console.warn('fileIdStr 分割后为空')
@ -358,7 +461,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

@ -0,0 +1,113 @@
<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,7 +103,6 @@
v-model:visible="dialogVisible.warningInfo" v-model:visible="dialogVisible.warningInfo"
@close="closeDialog('warningInfo')" @close="closeDialog('warningInfo')"
@responseStatus="openDialog('responseStatus')" @responseStatus="openDialog('responseStatus')"
@getResponseStatusrowFn="getResponseStatusfn"
/> />
<!-- 事件详情对话框 --> <!-- 事件详情对话框 -->
@ -130,7 +129,6 @@
<!-- 影响点情况对话框 --> <!-- 影响点情况对话框 -->
<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')"
@ -153,7 +151,6 @@
<!-- 响应状态对话框 --> <!-- 响应状态对话框 -->
<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')"
@ -243,7 +240,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" :getdateRange="getdateRange" @close="closeDialog('patrolMileage')" /> <patrolMileageDialog v-model:visible="dialogVisible.patrolMileage" @close="closeDialog('patrolMileage')" />
<!-- 巡查情况对话框 --> <!-- 巡查情况对话框 -->
<patrolSituationDialog v-model:visible="dialogVisible.patrolSituation" @close="closeDialog('patrolSituation')" /> <patrolSituationDialog v-model:visible="dialogVisible.patrolSituation" @close="closeDialog('patrolSituation')" />
@ -376,7 +373,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
} }
@ -390,9 +387,8 @@ 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(items, false) chongqingMapRef.value.handleHazardItemClick(item)
} }
} }
const showHazardPopup = ref(false) const showHazardPopup = ref(false)
@ -463,17 +459,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) => {
@ -486,7 +482,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
} }
@ -506,33 +502,28 @@ 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
} }
// //
@ -580,7 +571,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,7 +153,6 @@ 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 },
@ -259,7 +258,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([])
@ -594,12 +593,12 @@ const loadBarChartData = async () => {
bridge: '桥梁', bridge: '桥梁',
tunnel: '隧道', tunnel: '隧道',
slope: '边坡', slope: '边坡',
project: '驻地', project: '项目',
Road: '路段', Road: '路段',
Bridge: '桥梁', Bridge: '桥梁',
Tunnel: '隧道', Tunnel: '隧道',
Slope: '边坡', Slope: '边坡',
Project: '驻地', Project: '项目',
} }
// name // name
@ -616,7 +615,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
} }
}) })
@ -629,7 +628,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,7 +205,6 @@ 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',
@ -219,6 +218,7 @@ 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', key: '全幅封闭' }, { label: '封闭管控数', value: '40' },
{ label: '半幅通行数', value: '40', key: '半幅封闭' }, { label: '半幅通行数', value: '40' },
{ label: '限速(限车型)数', value: '24', key: '限速' }, { label: '限速(限车型)数', value: '24' },
{ label: '告警阻拦处数', value: '32', key: '告警阻拦' }, { label: '告警阻拦处数', value: '32' },
]) ])
const controlData2 = ref([ const controlData2 = ref([
{ label: '停工项目数', value: '0', key: 'stoped_project_count' }, { label: '停工项目数', value: '0', key: 'stoped_project_count' },
@ -756,7 +756,6 @@ 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,16 +81,7 @@ 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([])
@ -228,10 +219,6 @@ 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",