Compare commits
2 Commits
f304d444ab
...
0d0f2d3937
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d0f2d3937 | |||
| de2d0184a9 |
@ -399,7 +399,7 @@ const currentWarningInfo = computed(() => {
|
||||
// 影响范围标签页
|
||||
const impactTabs = ref([
|
||||
{ key: 'point', label: '影响点' },
|
||||
{ key: 'project', label: '影响项目' },
|
||||
{ key: 'project', label: '影响驻地' },
|
||||
]);
|
||||
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: '驻地' },
|
||||
]);
|
||||
// 影响项目
|
||||
const impactProjectDataTable = ref([
|
||||
|
||||
@ -116,7 +116,14 @@ watch(
|
||||
(newVal) => {
|
||||
console.log('newVal', newVal)
|
||||
if (newVal.label) {
|
||||
filterForm.value.roadConditionType = newVal.label.substring(0, newVal.label.length - 1) || ''
|
||||
// 根据 label 映射对应的管控措施类型
|
||||
const labelMap = {
|
||||
封闭管控数: '全幅封闭',
|
||||
告警阻拦处数: '告警阻拦',
|
||||
'限速(限车型)数': '限速',
|
||||
半幅通行数: '半幅封闭',
|
||||
}
|
||||
filterForm.value.roadConditionType = labelMap[newVal.label] || newVal.label.substring(0, newVal.label.length - 1) || ''
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
} else {
|
||||
|
||||
@ -1,39 +1,51 @@
|
||||
<template>
|
||||
<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-bottom-left"></div>
|
||||
<div class="corner corner-bottom-right"></div>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">{{ title }}</div>
|
||||
<div class="close-btn" @click="handleCancel">
|
||||
<el-icon><Close /></el-icon>
|
||||
<div>
|
||||
<!-- 确认弹窗 -->
|
||||
<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-bottom-left"></div>
|
||||
<div class="corner corner-bottom-right"></div>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">{{ title }}</div>
|
||||
<div class="close-btn" @click="handleCancel">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提示内容 -->
|
||||
<div class="dialog-content">
|
||||
<p class="confirm-message">{{ message }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 按钮区域 -->
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" class="btn-confirm" @click="handleCancel">
|
||||
{{ cancelText }}
|
||||
</el-button>
|
||||
<el-button type="primary" class="btn-confirm" @click="handleConfirm">
|
||||
{{ confirmText }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提示内容 -->
|
||||
<div 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>
|
||||
|
||||
<!-- 软电话配置弹窗 -->
|
||||
<SoftPhoneConfigDialog
|
||||
v-model:visible="softPhoneVisible"
|
||||
@confirm="handleSoftPhoneConfirm"
|
||||
@cancel="handleSoftPhoneCancel"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Close } from '@element-plus/icons-vue';
|
||||
import SoftPhoneConfigDialog from './softPhoneConfigDialog.vue';
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -60,12 +72,28 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(['update:visible', 'confirm', 'cancel']);
|
||||
|
||||
// 确认
|
||||
// 软电话配置弹窗显示状态
|
||||
const softPhoneVisible = ref(false);
|
||||
|
||||
// 确认 - 显示软电话配置弹窗
|
||||
const handleConfirm = () => {
|
||||
emit('confirm');
|
||||
softPhoneVisible.value = true;
|
||||
};
|
||||
|
||||
// 软电话配置确认
|
||||
const handleSoftPhoneConfirm = (configData) => {
|
||||
console.log('软电话配置数据:', configData);
|
||||
// 触发原始的 confirm 事件,并传递配置数据
|
||||
emit('confirm', configData);
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
// 软电话配置取消
|
||||
const handleSoftPhoneCancel = () => {
|
||||
// 软电话配置弹窗关闭时,保持确认弹窗打开
|
||||
console.log('软电话配置已取消');
|
||||
};
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
emit('cancel');
|
||||
|
||||
@ -54,13 +54,21 @@
|
||||
</div>
|
||||
|
||||
<!-- 照片 - 路段数据展示 -->
|
||||
<div v-if="isRoadData && hazardData.photos" class="info-block display">
|
||||
<div v-if="hazardData.photos" class="info-block display">
|
||||
<div class="block-title mr_10">照片</div>
|
||||
<div class="photo-list">
|
||||
<img v-for="(photo, index) in hazardData.photos" :key="index" :src="photo" class="photo-item" @click="previewPhoto(photo)" />
|
||||
<img v-for="(photo, index) in hazardData.photos" :key="index" :src="photo" class="photo-item" @click="previewPhoto(index)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图片预览组件 -->
|
||||
<el-image-viewer
|
||||
v-if="previewVisible"
|
||||
:url-list="hazardData.photos"
|
||||
:initial-index="previewIndex"
|
||||
@close="previewVisible = false"
|
||||
/>
|
||||
|
||||
<!-- 风险描述 -->
|
||||
<div class="info-block">
|
||||
<div class="block-title">风险描述</div>
|
||||
@ -313,11 +321,14 @@ const handleCurrentChange = (val) => {
|
||||
currentPage.value = val
|
||||
}
|
||||
|
||||
// 图片预览状态
|
||||
const previewVisible = ref(false)
|
||||
const previewIndex = ref(0)
|
||||
|
||||
// 预览照片
|
||||
const previewPhoto = (photo) => {
|
||||
// 使用 Element Plus 的图片预览功能
|
||||
const { preview } = require('element-plus')
|
||||
preview(photo)
|
||||
const previewPhoto = (index) => {
|
||||
previewIndex.value = index
|
||||
previewVisible.value = true
|
||||
}
|
||||
|
||||
// 视频通话
|
||||
|
||||
@ -219,6 +219,10 @@ const props = defineProps({
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
getdateRange: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'close', 'detail', 'itemClick'])
|
||||
@ -228,7 +232,7 @@ const filterForm = ref({
|
||||
pointType: '',
|
||||
pointLevel: '',
|
||||
region: '',
|
||||
roadType: '',
|
||||
roadType: 'G,S',
|
||||
})
|
||||
|
||||
// 统一的表格列配置(桥梁、边坡、隧道、路段使用)
|
||||
@ -328,14 +332,20 @@ const impactData = ref([
|
||||
{ name: '影响桥梁', count: 0, icon: Icon0, type: '桥梁' },
|
||||
{ name: '影响隧道', count: 0, icon: Icon2, type: '隧道' },
|
||||
{ name: '影响边坡', count: 0, icon: Icon1, type: '边坡' },
|
||||
{ name: '影响项目', count: 0, icon: Icon3, type: '项目' },
|
||||
{ name: '影响项目', count: 0, icon: Icon3, type: '驻地' },
|
||||
])
|
||||
// 顶部卡片数据
|
||||
const loadBarChartData = async () => {
|
||||
console.log('原始时间范围:', props.handleImpactItem)
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weather-warning/affected-count',
|
||||
method: 'GET',
|
||||
params: {
|
||||
start: formatDateTime(props.getdateRange[0]),
|
||||
end: formatDateTime(props.getdateRange[1]),
|
||||
warningId: props.handleImpactItem.warningId,
|
||||
},
|
||||
})
|
||||
|
||||
if (res.code == '00000') {
|
||||
@ -347,12 +357,12 @@ const loadBarChartData = async () => {
|
||||
bridge: '桥梁',
|
||||
tunnel: '隧道',
|
||||
slope: '边坡',
|
||||
project: '项目',
|
||||
project: '驻地',
|
||||
Road: '路段',
|
||||
Bridge: '桥梁',
|
||||
Tunnel: '隧道',
|
||||
Slope: '边坡',
|
||||
Project: '项目',
|
||||
Project: '驻地',
|
||||
}
|
||||
|
||||
// 转换英文name为中文
|
||||
@ -384,13 +394,13 @@ const getColumnsByType = (type) => {
|
||||
桥梁: slopeColumns,
|
||||
隧道: tunnelColumns,
|
||||
边坡: roadColumns,
|
||||
项目: projectColumns,
|
||||
驻地: projectColumns,
|
||||
}
|
||||
// { name: '影响路段', count: 0, icon: Icon4, type: '路段' },
|
||||
// { name: '影响桥梁', count: 0, icon: Icon0, type: '桥梁' },
|
||||
// { name: '影响隧道', count: 0, icon: Icon2, type: '隧道' },
|
||||
// { name: '影响边坡', count: 0, icon: Icon1, type: '边坡' },
|
||||
// { name: '影响项目', count: 0, icon: Icon3, type: '项目' },
|
||||
// { name: '影响项目', count: 0, icon: Icon3, type: '驻地' },
|
||||
return typeMap[type] || bridgeColumns
|
||||
}
|
||||
|
||||
@ -400,7 +410,7 @@ const getApiUrlByType = (type) => {
|
||||
桥梁: '/snow-ops-platform/weather-warning/affected-object/bridge',
|
||||
边坡: '/snow-ops-platform/weather-warning/affected-object/slope',
|
||||
隧道: '/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',
|
||||
}
|
||||
return urlMap[type] || '/snow-ops-platform/weather-warning/affected-object/bridge'
|
||||
@ -481,21 +491,22 @@ const handleFilterChange = () => {
|
||||
|
||||
const getTimeParams = () => {
|
||||
console.log('原始时间范围:', props.handleImpactItem)
|
||||
let countyName = ''
|
||||
let countyId = ''
|
||||
console.log('区域:', filterForm.value)
|
||||
regionOptions.value.forEach((item) => {
|
||||
if (item.label === filterForm.value.region) {
|
||||
countyName = item.label || ''
|
||||
if (item.label === filterForm.value.region || item.value === filterForm.value.region) {
|
||||
countyId = item.value || ''
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
// start: `${year}-${month}-01 00:00:00`,
|
||||
// end: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`,
|
||||
start: formatDateTime(props.handleImpactItem.dateRange?.[0] || ''),
|
||||
end: formatDateTime(props.handleImpactItem.dateRange?.[1] || ''),
|
||||
start: formatDateTime(props.getdateRange[0] ? props.getdateRange[0] : props.handleImpactItem.dateRange?.[0] || ''),
|
||||
end: formatDateTime(props.getdateRange[1] ? props.getdateRange[1] : props.handleImpactItem.dateRange?.[1] || ''),
|
||||
limit: pageSize.value,
|
||||
offset: (currentPage.value - 1) * pageSize.value,
|
||||
countyName: countyName || '',
|
||||
countyId: countyId || '',
|
||||
riskLevel: filterForm.value.pointLevel || '',
|
||||
roadTypes: filterForm.value.roadType || '',
|
||||
}
|
||||
@ -692,7 +703,7 @@ const processUnifiedData = (item, type) => {
|
||||
}
|
||||
|
||||
// 项目类型特殊处理(根据SQL字段映射)
|
||||
if (cardTypeVal.value === '项目') {
|
||||
if (cardTypeVal.value === '驻地') {
|
||||
return {
|
||||
...baseData,
|
||||
// 影响区域 - 使用COUNTY字段
|
||||
@ -765,6 +776,14 @@ const fetchData = async () => {
|
||||
}))
|
||||
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 {
|
||||
if (res.code === '00000' && res.data) {
|
||||
// 处理返回数据
|
||||
@ -825,7 +844,7 @@ watch(
|
||||
// }
|
||||
// tableData.value = []
|
||||
// cardType.value = '0'
|
||||
// loadBarChartData()
|
||||
loadBarChartData()
|
||||
// currentPage.value = 1
|
||||
// fetchData()
|
||||
// }
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
:visible="props.visible"
|
||||
title="巡查里程"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
@ -11,6 +11,7 @@
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
@update:visible="handleClose"
|
||||
>
|
||||
<!-- 统计卡片区域 -->
|
||||
<template #header>
|
||||
@ -39,7 +40,7 @@
|
||||
<template #filter>
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">帮扶区县</span>
|
||||
<span class="filter-label">巡查区县</span>
|
||||
<el-select
|
||||
:teleported="false"
|
||||
v-model="filterForm.district"
|
||||
@ -48,12 +49,7 @@
|
||||
clearable
|
||||
@change="handleFilterChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in districtOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
<el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
@ -62,184 +58,143 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import BaseDialog from '../component/baseDialog.vue';
|
||||
import { request } from '@/utils/request';
|
||||
import selectedIcon from '../../../assets/xiangying/选中bg@2x.png';
|
||||
import unselectedIcon from '../../../assets/xiangying/未选中bg@2x.png';
|
||||
import { ref, watch } from 'vue'
|
||||
import BaseDialog from '../component/baseDialog.vue'
|
||||
import { request } from '@/utils/request'
|
||||
import selectedIcon from '../../../assets/xiangying/选中bg@2x.png'
|
||||
import unselectedIcon from '../../../assets/xiangying/未选中bg@2x.png'
|
||||
|
||||
// 引入图标
|
||||
import IconNational from '../../../assets/xiangying/国省道icon.png';
|
||||
import IconRuralRoad from '../../../assets/xiangying/农村公路icon.png';
|
||||
import IconNational from '../../../assets/xiangying/国省道icon.png'
|
||||
import IconRuralRoad from '../../../assets/xiangying/农村公路icon.png'
|
||||
|
||||
import { formatDateTime, regionOptions } from '../component/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
getdateRange: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'close']);
|
||||
const emit = defineEmits(['update:visible', 'close'])
|
||||
|
||||
// 统计数值
|
||||
const nationalRoadMileage = ref(345);
|
||||
const ruralRoadMileage = ref(4333);
|
||||
const nationalRoadMileage = ref(345)
|
||||
const ruralRoadMileage = ref(4333)
|
||||
|
||||
// 里程数据
|
||||
const mileageData = ref([
|
||||
{ name: '国省道', value: 345, icon: IconNational, type: 'national' },
|
||||
{ name: '农村公路', value: 4333, icon: IconRuralRoad, type: 'rural' },
|
||||
]);
|
||||
])
|
||||
|
||||
// 当前选中卡片类型
|
||||
const cardType = ref('0');
|
||||
const cardType = ref('0')
|
||||
|
||||
// 点击卡片
|
||||
const handleClick = (index, item) => {
|
||||
cardType.value = index + '';
|
||||
cardType.value = index + ''
|
||||
// 可以在这里添加筛选逻辑
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
};
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
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([
|
||||
{ prop: 'id', label: '序号' },
|
||||
{ prop: 'district', label: '所属区县' },
|
||||
{ prop: 'mileage', label: '巡查里程' },
|
||||
]);
|
||||
])
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
const tableData = ref([])
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(0);
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit('update:visible', false);
|
||||
emit('close');
|
||||
};
|
||||
emit('update:visible', false)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = val => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
fetchData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = val => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 筛选条件改变时触发
|
||||
const handleFilterChange = () => {
|
||||
currentPage.value = 1;
|
||||
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);
|
||||
}
|
||||
};
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 获取列表数据
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/patrol/mileage-list',
|
||||
url: '/snow-ops-platform/yhWgxc/county-mileage',
|
||||
method: 'GET',
|
||||
params: {
|
||||
pageNum: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
districtCode: filterForm.value.district,
|
||||
startTime: formatDateTime(props.getdateRange?.[0] || ''),
|
||||
endTime: formatDateTime(props.getdateRange?.[1] || ''),
|
||||
qxbm: filterForm.value.district || '',
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
if (res.code === '00000' && res.data) {
|
||||
const data = res.data;
|
||||
const data = res.data
|
||||
tableData.value = data.records.map((item, index) => {
|
||||
return {
|
||||
id: currentPage.value * pageSize.value - (pageSize.value - index - 1),
|
||||
district: item.districtName || '-',
|
||||
mileage: item.mileage ? `${item.mileage}公里` : '-',
|
||||
};
|
||||
});
|
||||
total.value = data.total;
|
||||
district: item.qxmc || '-',
|
||||
mileage: item.mileage ? `${item.mileage}公里` : '0',
|
||||
}
|
||||
})
|
||||
total.value = data.total
|
||||
} else {
|
||||
tableData.value = []
|
||||
total.value = 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取巡查里程列表数据失败:', error);
|
||||
console.error('获取巡查里程列表数据失败:', error)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVal => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchStatsData();
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
);
|
||||
(newVal) => {
|
||||
tableData.value = []
|
||||
total.value = 0
|
||||
currentPage.value = 1
|
||||
// fetchStatsData()
|
||||
fetchData()
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -251,7 +206,6 @@ watch(
|
||||
margin-bottom: 16px;
|
||||
padding: 0 4px;
|
||||
|
||||
|
||||
.stat-card {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
@ -41,52 +41,21 @@
|
||||
<!-- 筛选区域 -->
|
||||
<template #filter>
|
||||
<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">
|
||||
<span class="filter-label">影响点等级</span>
|
||||
<el-select
|
||||
: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 :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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">是否回应</span>
|
||||
<el-select
|
||||
: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 :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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -100,11 +69,7 @@
|
||||
<div class="person-info">
|
||||
<div class="person-name center">
|
||||
<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>
|
||||
<span class="person-phone">{{ row.trafficDept.phone }}</span>
|
||||
</div>
|
||||
@ -144,9 +109,9 @@
|
||||
</template>
|
||||
|
||||
<!-- 回应状态列插槽 -->
|
||||
<!-- <template #responseStatus="{ row }">
|
||||
<!-- <template #responseStatusData="{ row }">
|
||||
<span class="response-status" :class="row.responseClass">{{
|
||||
row.responseStatus
|
||||
row.responseStatusData
|
||||
}}</span>
|
||||
</template> -->
|
||||
|
||||
@ -166,27 +131,22 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted } from 'vue';
|
||||
import { Close, ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
|
||||
import {
|
||||
pointTypeOptions,
|
||||
pointLevelOptions,
|
||||
isRespondedOptions,
|
||||
formatDateTime,
|
||||
} from '../component/index.js';
|
||||
import baseDialog from '../component/baseDialog.vue';
|
||||
import { request } from '@/utils/request.js';
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { Close, ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
|
||||
import { pointTypeOptions, 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 notRespondedIcon from '../../../assets/xiangying/无回应@2x.png';
|
||||
import selectedIcon from '../../../assets/xiangying/选中bg@2x.png';
|
||||
import unselectedIcon from '../../../assets/xiangying/未选中bg@2x.png';
|
||||
import respondedIcon from '../../../assets/xiangying/有回应@2x.png'
|
||||
import notRespondedIcon from '../../../assets/xiangying/无回应@2x.png'
|
||||
import selectedIcon from '../../../assets/xiangying/选中bg@2x.png'
|
||||
import unselectedIcon from '../../../assets/xiangying/未选中bg@2x.png'
|
||||
|
||||
import Icon0 from '../../../assets/xiangying/选中@2x.png';
|
||||
import Icon1 from '../../../assets/xiangying/未选中1@2x.png';
|
||||
import Icon2 from '../../../assets/xiangying/未选中2@2x.png';
|
||||
import Icon3 from '../../../assets/xiangying/未选中3@2x.png';
|
||||
import Icon4 from '../../../assets/xiangying/未选中4@2x.png';
|
||||
import Icon0 from '../../../assets/xiangying/选中@2x.png'
|
||||
import Icon1 from '../../../assets/xiangying/未选中1@2x.png'
|
||||
import Icon2 from '../../../assets/xiangying/未选中2@2x.png'
|
||||
import Icon3 from '../../../assets/xiangying/未选中3@2x.png'
|
||||
import Icon4 from '../../../assets/xiangying/未选中4@2x.png'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -197,18 +157,22 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
responseStatusData: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'close', 'detail']);
|
||||
const emit = defineEmits(['update:visible', 'close', 'detail'])
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
pointType: '',
|
||||
pointLevel: '',
|
||||
isResponded: '',
|
||||
});
|
||||
})
|
||||
|
||||
const cardType = ref('路段');
|
||||
const cardType = ref('路段')
|
||||
|
||||
// 统计卡片数据
|
||||
const statsCardsData = ref([
|
||||
@ -216,8 +180,8 @@ const statsCardsData = ref([
|
||||
{ type: '桥梁', label: '影响桥梁', value: 0, icon: Icon0 },
|
||||
{ type: '隧道', label: '影响隧道', value: 0, icon: Icon2 },
|
||||
{ type: '边坡', label: '影响边坡', value: 0, icon: Icon1 },
|
||||
{ type: '项目', label: '影响项目', value: 0, icon: Icon3 },
|
||||
]);
|
||||
{ type: '驻地', label: '影响驻地', value: 0, icon: Icon3 },
|
||||
])
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
@ -234,37 +198,40 @@ const tableColumns = ref([
|
||||
{ prop: 'generalStaff', label: '一般人员(路长履职)', width: '100px', slot: 'generalStaff' },
|
||||
{ prop: 'urgeTime', label: '最新催告时间', width: '', slot: 'urgeTime' },
|
||||
{ prop: 'operation', label: '操作', width: '', slot: 'operation' },
|
||||
]);
|
||||
])
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
const tableData = ref([])
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(36);
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(36)
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit('update:visible', false);
|
||||
emit('close');
|
||||
};
|
||||
emit('update:visible', false)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 点击卡片切换
|
||||
const handleClick = type => {
|
||||
cardType.value = type;
|
||||
fetchData();
|
||||
};
|
||||
const handleClick = (type) => {
|
||||
cardType.value = type
|
||||
fetchData()
|
||||
}
|
||||
// 顶部卡片数据
|
||||
const loadBarChartData = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weather-warning/affected-count',
|
||||
method: 'GET',
|
||||
});
|
||||
params: {
|
||||
warningId: props.responseStatusData.warningId,
|
||||
},
|
||||
})
|
||||
|
||||
if (res.code == '00000') {
|
||||
const data = res.data;
|
||||
const data = res.data
|
||||
if (data && Array.isArray(data)) {
|
||||
// 英文转中文映射
|
||||
const nameMap = {
|
||||
@ -272,44 +239,44 @@ const loadBarChartData = async () => {
|
||||
bridge: '桥梁',
|
||||
tunnel: '隧道',
|
||||
slope: '边坡',
|
||||
project: '项目',
|
||||
project: '驻地',
|
||||
Road: '路段',
|
||||
Bridge: '桥梁',
|
||||
Tunnel: '隧道',
|
||||
Slope: '边坡',
|
||||
Project: '项目',
|
||||
};
|
||||
Project: '驻地',
|
||||
}
|
||||
|
||||
statsCardsData.value.forEach(item => {
|
||||
data.forEach(stat => {
|
||||
statsCardsData.value.forEach((item) => {
|
||||
data.forEach((stat) => {
|
||||
if (stat.extension == item.type) {
|
||||
item.value = stat.count || 0;
|
||||
item.value = stat.count || 0
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载柱状图数据失败:', error);
|
||||
console.error('加载柱状图数据失败:', error)
|
||||
}
|
||||
};
|
||||
}
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = item => {
|
||||
emit('detail', item);
|
||||
};
|
||||
const handleDetail = (item) => {
|
||||
emit('detail', item)
|
||||
}
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = val => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
fetchData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = val => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 获取通知实体数据
|
||||
const fetchData = async () => {
|
||||
@ -317,29 +284,32 @@ const fetchData = async () => {
|
||||
const params = {
|
||||
start: '',
|
||||
end: '',
|
||||
};
|
||||
offset: (currentPage.value - 1) * pageSize.value,
|
||||
limit: pageSize.value,
|
||||
warningId: props.responseStatusData.warningId,
|
||||
}
|
||||
if (props.dispatchDateRange && props.dispatchDateRange.length > 0) {
|
||||
params.start = formatDateTime(props.dispatchDateRange[0]) || '';
|
||||
params.end = formatDateTime(props.dispatchDateRange[1]) || '';
|
||||
params.start = formatDateTime(props.dispatchDateRange[0]) || ''
|
||||
params.end = formatDateTime(props.dispatchDateRange[1]) || ''
|
||||
}
|
||||
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weather-warning/notice-entity',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
})
|
||||
|
||||
if (res && res.data) {
|
||||
tableData.value = res.data.map((item, index) => {
|
||||
// 从 events 中提取不同角色的人员信息
|
||||
const trafficDeptEvent = 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 maintenanceEvent = 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 roadOrgEvent = item.events?.find((e) => e.noticeRoles?.includes('公路机构')) || {}
|
||||
const maintenanceEvent = item.events?.find((e) => e.noticeRoles?.includes('养护站')) || {}
|
||||
|
||||
// 获取最新的催告时间
|
||||
const lastNoticeTime = item.events?.[0]?.lastNoticeTime || '';
|
||||
const urgeTimeParts = lastNoticeTime ? lastNoticeTime.split('T') : ['', ''];
|
||||
const lastNoticeTime = item.events?.[0]?.lastNoticeTime || ''
|
||||
const urgeTimeParts = lastNoticeTime ? lastNoticeTime.split('T') : ['', '']
|
||||
|
||||
return {
|
||||
id: index + 1,
|
||||
@ -372,26 +342,26 @@ const fetchData = async () => {
|
||||
img: roadKeeperEvent.replyState === 'read' ? respondedIcon : notRespondedIcon,
|
||||
isResponded: roadKeeperEvent.replyState === 'read',
|
||||
},
|
||||
generalStaff:{
|
||||
name: item.GL1_QLGCS || "-",
|
||||
phone: item.GL1_QLGCSDH || "-",
|
||||
generalStaff: {
|
||||
name: item.GL1_QLGCS || '-',
|
||||
phone: item.GL1_QLGCSDH || '-',
|
||||
},
|
||||
|
||||
|
||||
urgeTime: {
|
||||
date: urgeTimeParts[0] || '-',
|
||||
time: urgeTimeParts[1] ? urgeTimeParts[1].substring(0, 8) : '-',
|
||||
},
|
||||
};
|
||||
});
|
||||
total.value = res.data.length;
|
||||
}
|
||||
})
|
||||
total.value = res.data.length
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取通知实体数据失败:', error);
|
||||
console.error('获取通知实体数据失败:', error)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 类型映射
|
||||
const getTypeLabel = type => {
|
||||
const getTypeLabel = (type) => {
|
||||
const typeMap = {
|
||||
'road-section': '路段',
|
||||
road_section: '路段',
|
||||
@ -399,46 +369,52 @@ const getTypeLabel = type => {
|
||||
bridge: '桥梁',
|
||||
tunnel: '隧道',
|
||||
slope: '边坡',
|
||||
project: '项目',
|
||||
};
|
||||
return typeMap[type] || type || '-';
|
||||
};
|
||||
project: '驻地',
|
||||
}
|
||||
return typeMap[type] || type || '-'
|
||||
}
|
||||
|
||||
// 根据风险等级获取样式类
|
||||
const getLevelClass = riskLevel => {
|
||||
if (!riskLevel) return '';
|
||||
if (riskLevel.includes('高')) return 'level-serious';
|
||||
if (riskLevel.includes('一般')) return 'level-normal';
|
||||
return '';
|
||||
};
|
||||
const getLevelClass = (riskLevel) => {
|
||||
if (!riskLevel) return ''
|
||||
if (riskLevel.includes('高')) return 'level-serious'
|
||||
if (riskLevel.includes('一般')) return 'level-normal'
|
||||
return ''
|
||||
}
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
fetchData()
|
||||
loadBarChartData()
|
||||
}
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVal => {
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
loadBarChartData()
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
)
|
||||
|
||||
// 监听日期范围变化
|
||||
watch(
|
||||
() => props.dispatchDateRange,
|
||||
() => {
|
||||
if (props.visible) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化加载顶部卡片数据
|
||||
loadBarChartData();
|
||||
});
|
||||
loadBarChartData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -0,0 +1,370 @@
|
||||
<template>
|
||||
<div v-if="visible" class="softphone-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="softphone-dialog" @click.stop>
|
||||
<!-- 四个角的装饰 -->
|
||||
<div class="corner corner-top-left"></div>
|
||||
<div class="corner corner-top-right"></div>
|
||||
<div class="corner corner-bottom-left"></div>
|
||||
<div class="corner corner-bottom-right"></div>
|
||||
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">软电话配置</div>
|
||||
<div class="close-btn" @click="handleCancel">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="dialog-content">
|
||||
<!-- 状态按钮组 -->
|
||||
<div class="status-buttons">
|
||||
<button
|
||||
v-for="status in statusList"
|
||||
:key="status.value"
|
||||
:class="['status-btn', { active: currentStatus === status.value }]"
|
||||
@click="currentStatus = status.value"
|
||||
>
|
||||
{{ status.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<div class="form-area">
|
||||
<div class="form-item">
|
||||
<span class="form-label">服务器环境</span>
|
||||
<input v-model="formData.serverEnv" type="text" class="form-input" placeholder="请输入服务器环境" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">工号</span>
|
||||
<input v-model="formData.workId" type="text" class="form-input" placeholder="请输入工号" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">坐席密码</span>
|
||||
<input v-model="formData.seatPassword" type="password" class="form-input" placeholder="请输入坐席密码" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 按钮区域 -->
|
||||
<div class="dialog-footer">
|
||||
<button class="btn-cancel" @click="handleCancel">取消</button>
|
||||
<button class="btn-confirm" @click="handleConfirm">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import { Close } from '@element-plus/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'confirm', 'cancel'])
|
||||
|
||||
// 状态列表
|
||||
const statusList = [
|
||||
{ label: '未登录', value: 'notLogin' },
|
||||
{ label: '示忙', value: 'busy' },
|
||||
{ label: '示闲', value: 'idle' },
|
||||
{ label: '呼出', value: 'callOut' },
|
||||
{ label: '保持', value: 'hold' },
|
||||
{ label: '接回', value: 'retrieve' },
|
||||
{ label: '挂断', value: 'hangUp' },
|
||||
{ label: '会议', value: 'conference' },
|
||||
{ label: '应答', value: 'answer' },
|
||||
{ label: '转出', value: 'transfer' },
|
||||
{ label: '咨询', value: 'consult' },
|
||||
]
|
||||
|
||||
// 当前状态
|
||||
const currentStatus = ref('notLogin')
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
serverEnv: '',
|
||||
workId: '',
|
||||
seatPassword: '',
|
||||
})
|
||||
|
||||
// 确认
|
||||
const handleConfirm = () => {
|
||||
emit('confirm', {
|
||||
status: currentStatus.value,
|
||||
...formData,
|
||||
})
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
emit('cancel')
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleCancel()
|
||||
}
|
||||
|
||||
// 监听 visible 变化,打开时重置表单
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentStatus.value = 'notLogin'
|
||||
formData.serverEnv = ''
|
||||
formData.workId = ''
|
||||
formData.seatPassword = ''
|
||||
}
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.softphone-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2200;
|
||||
}
|
||||
|
||||
.softphone-dialog {
|
||||
width: 500px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
overflow: hidden;
|
||||
animation: dialogSlideIn 0.3s ease-out;
|
||||
position: relative;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 90vw;
|
||||
max-width: 90vw;
|
||||
}
|
||||
|
||||
// 四个角的装饰
|
||||
.corner {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #40a9ff;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
|
||||
&.corner-top-left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dialogSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.8) translateY(-50px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px;
|
||||
background: linear-gradient(90deg, rgba(64, 169, 255, 0.15) 0%, rgba(64, 169, 255, 0.05) 100%);
|
||||
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: color 0.3s;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
.dialog-content {
|
||||
padding: 20px;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
// 状态按钮组
|
||||
.status-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
|
||||
|
||||
.status-btn {
|
||||
padding: 6px 12px;
|
||||
background: transparent;
|
||||
border: 1px solid rgba(64, 169, 255, 0.4);
|
||||
border-radius: 4px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(64, 169, 255, 0.6);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表单区域
|
||||
.form-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
|
||||
.form-label {
|
||||
width: 80px;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
height: 36px;
|
||||
padding: 0 12px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: rgba(64, 169, 255, 0.6);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮区域
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding: 0 20px 20px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.btn-cancel {
|
||||
min-width: 80px;
|
||||
height: 32px;
|
||||
padding: 0 24px;
|
||||
background-color: transparent;
|
||||
border: 1px solid rgba(64, 169, 255, 0.4);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border-color: rgba(64, 169, 255, 0.6);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
min-width: 80px;
|
||||
height: 32px;
|
||||
padding: 0 24px;
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -26,12 +26,7 @@
|
||||
@change="handleWarningLevelChange"
|
||||
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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
@ -43,12 +38,7 @@
|
||||
@change="handleWarningLevelChange"
|
||||
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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
@ -60,12 +50,7 @@
|
||||
@change="handleWarningLevelChange"
|
||||
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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
@ -77,12 +62,7 @@
|
||||
@change="handleWarningLevelChange"
|
||||
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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
@ -107,17 +87,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
import baseDialog from '../component/baseDialog.vue';
|
||||
import { formatDateTime } from '../component/index.js';
|
||||
import { request } from '@/utils/request';
|
||||
import {
|
||||
warningLevelOptions,
|
||||
regionOptions,
|
||||
isEndedOptions,
|
||||
isRespondedOptions,
|
||||
} from '../component/index.js';
|
||||
import { ref, watch } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import baseDialog from '../component/baseDialog.vue'
|
||||
import { formatDateTime } from '../component/index.js'
|
||||
import { request } from '@/utils/request'
|
||||
import { warningLevelOptions, regionOptions, isEndedOptions, isRespondedOptions } from '../component/index.js'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -128,9 +103,9 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'close', 'openImpactPoint']);
|
||||
const emit = defineEmits(['update:visible', 'close', 'openImpactPoint', 'getResponseStatusrowFn'])
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
@ -138,7 +113,7 @@ const filterForm = ref({
|
||||
region: '',
|
||||
isEnded: '',
|
||||
isResponded: '',
|
||||
});
|
||||
})
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
@ -153,82 +128,56 @@ const tableColumns = ref([
|
||||
{ prop: 'responded', label: '已回应', width: '' },
|
||||
{ prop: 'notResponded', label: '未回应', width: '' },
|
||||
{ prop: 'urged', label: '已催告', width: '' },
|
||||
]);
|
||||
])
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
const tableData = ref([])
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
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 currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(36)
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit('update:visible', false);
|
||||
emit('close');
|
||||
};
|
||||
emit('update:visible', false)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 点击已叫应
|
||||
const handleCalledClick = () => {
|
||||
emit('responseStatus');
|
||||
};
|
||||
const handleCalledClick = (row) => {
|
||||
emit('responseStatus')
|
||||
emit('getResponseStatusrowFn', row)
|
||||
}
|
||||
|
||||
// 查询
|
||||
const handleSearch = () => {
|
||||
console.log('查询条件:', filterForm.value);
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
};
|
||||
console.log('查询条件:', filterForm.value)
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = val => {
|
||||
pageSize.value = val;
|
||||
fetchData();
|
||||
};
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
fetchData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = val => {
|
||||
currentPage.value = val;
|
||||
fetchData();
|
||||
};
|
||||
const handleCurrentChange = (val) => {
|
||||
currentPage.value = val
|
||||
fetchData()
|
||||
}
|
||||
// 处理预警等级变化
|
||||
const handleWarningLevelChange = () => {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
};
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
}
|
||||
// 获取预警通知统计
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
console.log(props.dispatchDateRange);
|
||||
console.log(props.dispatchDateRange)
|
||||
const params = {
|
||||
start: '',
|
||||
end: '',
|
||||
@ -239,30 +188,28 @@ const fetchData = async () => {
|
||||
countyName: '',
|
||||
isExpire: filterForm.value.isEnded,
|
||||
isReply: filterForm.value.isResponded,
|
||||
};
|
||||
}
|
||||
|
||||
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) {
|
||||
params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || '';
|
||||
params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || ''
|
||||
}
|
||||
}
|
||||
|
||||
if (props.dispatchDateRange.length > 0) {
|
||||
params.start = formatDateTime(props.dispatchDateRange[0]) || '';
|
||||
params.end = formatDateTime(props.dispatchDateRange[1]) || '';
|
||||
params.start = formatDateTime(props.dispatchDateRange[0]) || ''
|
||||
params.end = formatDateTime(props.dispatchDateRange[1]) || ''
|
||||
}
|
||||
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weather-warning/notice-count',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
})
|
||||
|
||||
console.log(res);
|
||||
console.log(res)
|
||||
if (res) {
|
||||
// 映射数据到表格格式
|
||||
tableData.value = res.data.map((item, index) => ({
|
||||
@ -278,46 +225,47 @@ const fetchData = async () => {
|
||||
responded: item.replyCount || 0,
|
||||
notResponded: (item.notifyCount || 0) - (item.replyCount || 0),
|
||||
urged: item.retryCount || 0,
|
||||
}));
|
||||
total.value = res.total || res.data.length;
|
||||
warningId: item.warningId || '-',
|
||||
}))
|
||||
total.value = res.total || res.data.length
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取预警通知统计失败:', error);
|
||||
console.error('获取预警通知统计失败:', error)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 根据预警等级获取样式类
|
||||
const getLevelClass = riskLevel => {
|
||||
if (!riskLevel) return '';
|
||||
if (riskLevel.includes('红')) return 'level-red';
|
||||
if (riskLevel.includes('橙')) return 'level-orange';
|
||||
if (riskLevel.includes('黄')) return 'level-yellow';
|
||||
if (riskLevel.includes('蓝')) return 'level-blue';
|
||||
return '';
|
||||
};
|
||||
const getLevelClass = (riskLevel) => {
|
||||
if (!riskLevel) return ''
|
||||
if (riskLevel.includes('红')) return 'level-red'
|
||||
if (riskLevel.includes('橙')) return 'level-orange'
|
||||
if (riskLevel.includes('黄')) return 'level-yellow'
|
||||
if (riskLevel.includes('蓝')) return 'level-blue'
|
||||
return ''
|
||||
}
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVal => {
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
)
|
||||
|
||||
// 监听日期范围变化
|
||||
watch(
|
||||
() => props.dispatchDateRange,
|
||||
() => {
|
||||
if (props.visible) {
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
currentPage.value = 1
|
||||
fetchData()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true },
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -17,56 +17,20 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">预警等级</span>
|
||||
<el-select
|
||||
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 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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">影响区域</span>
|
||||
<el-select
|
||||
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 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>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">是否失效</span>
|
||||
<el-select
|
||||
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 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>
|
||||
</div>
|
||||
|
||||
@ -101,14 +65,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted, inject } from 'vue';
|
||||
import { Close, Calendar } from '@element-plus/icons-vue';
|
||||
import { warningLevelOptions, regionOptions, isEndedOptions } from '../component/index.js';
|
||||
import baseDialog from '../component/baseDialog.vue';
|
||||
import { request } from '@/utils/request';
|
||||
import { ref, computed, watch, onMounted, inject } from 'vue'
|
||||
import { Close, Calendar } from '@element-plus/icons-vue'
|
||||
import { warningLevelOptions, regionOptions, isEndedOptions } from '../component/index.js'
|
||||
import baseDialog from '../component/baseDialog.vue'
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
// 注入日期范围
|
||||
const getdateRange = inject('getdateRange', ref([]));
|
||||
const getdateRange = inject('getdateRange', ref([]))
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -119,44 +83,44 @@ const props = defineProps({
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'close', 'impactClick']);
|
||||
const emit = defineEmits(['update:visible', 'close', 'impactClick'])
|
||||
|
||||
// 日期范围器
|
||||
const dateRange = ref([]);
|
||||
const dateRange = ref([])
|
||||
onMounted(() => {
|
||||
// 如果弹窗初始就是打开状态,则初始化数据
|
||||
if (props.visible) {
|
||||
initDialogData();
|
||||
initDialogData()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// 监听 warningitem 变化,当弹窗重新打开时更新筛选条件
|
||||
watch(
|
||||
() => props.warningitem,
|
||||
newVal => {
|
||||
console.log('warningitem 变化:', newVal);
|
||||
(newVal) => {
|
||||
console.log('warningitem 变化:', newVal)
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
filterForm.value.riskLeve = newVal.label || '';
|
||||
currentPage.value = 1;
|
||||
filterForm.value.riskLeve = newVal.label || ''
|
||||
currentPage.value = 1
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
// 监听注入的日期范围变化
|
||||
watch(
|
||||
() => getdateRange.value,
|
||||
newVal => {
|
||||
console.log('warningSituationDialog.vue 日期范围变化:', newVal);
|
||||
(newVal) => {
|
||||
console.log('warningSituationDialog.vue 日期范围变化:', newVal)
|
||||
if (newVal && newVal.length === 2) {
|
||||
dateRange.value = newVal;
|
||||
filterForm.value.dateRange = newVal;
|
||||
dateRange.value = newVal
|
||||
filterForm.value.dateRange = newVal
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = ref({
|
||||
@ -164,12 +128,12 @@ const filterForm = ref({
|
||||
countyName: '',
|
||||
isEnded: '',
|
||||
dateRange: dateRange.value,
|
||||
});
|
||||
})
|
||||
|
||||
// 处理日期范围变化
|
||||
const handleDateChange = val => {
|
||||
filterForm.value.dateRange = val;
|
||||
};
|
||||
const handleDateChange = (val) => {
|
||||
filterForm.value.dateRange = val
|
||||
}
|
||||
|
||||
// 预警等级选项
|
||||
// 已从 index.js 导入
|
||||
@ -181,7 +145,7 @@ const handleDateChange = val => {
|
||||
// 已从 index.js 导入
|
||||
|
||||
// 表格高度
|
||||
const tableHeight = ref(300);
|
||||
const tableHeight = ref(300)
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
@ -193,22 +157,22 @@ const tableColumns = ref([
|
||||
{ prop: 'warningTime', label: '生效时间', width: '' },
|
||||
{ prop: 'endTime', label: '失效时间', width: '' },
|
||||
{ prop: 'impactCount', label: '影响点数量', width: '', slot: 'impactCount' },
|
||||
]);
|
||||
])
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
const tableData = ref([])
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const total = ref(0);
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false);
|
||||
const loading = ref(false)
|
||||
|
||||
// 获取预警数据
|
||||
const fetchWarningData = async () => {
|
||||
loading.value = true;
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
offset: (currentPage.value - 1) * pageSize.value,
|
||||
@ -219,38 +183,36 @@ const fetchWarningData = async () => {
|
||||
weatherType: '',
|
||||
isExpire: '',
|
||||
countyName: '',
|
||||
};
|
||||
}
|
||||
|
||||
// 添加筛选条件
|
||||
if (filterForm.value.riskLeve) {
|
||||
params.riskLevel = filterForm.value.riskLeve;
|
||||
params.riskLevel = filterForm.value.riskLeve
|
||||
}
|
||||
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) {
|
||||
params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || '';
|
||||
params.countyName = selectedRegion.label == '全部' ? '' : selectedRegion.label || ''
|
||||
}
|
||||
}
|
||||
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) {
|
||||
params.start = formatDateTime(filterForm.value.dateRange[0]);
|
||||
params.end = formatDateTime(filterForm.value.dateRange[1]);
|
||||
params.start = formatDateTime(filterForm.value.dateRange[0])
|
||||
params.end = formatDateTime(filterForm.value.dateRange[1])
|
||||
}
|
||||
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weather-warning/affected-count/_by_weather',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
})
|
||||
|
||||
if (res.code === '00000' && res.data) {
|
||||
// 处理返回数据
|
||||
const list = res.data.data || res.data.records || [];
|
||||
total.value = res.data.total || 0;
|
||||
const list = res.data.data || res.data.records || []
|
||||
total.value = res.data.total || 0
|
||||
|
||||
tableData.value = list.map((item, index) => ({
|
||||
index: index + 1,
|
||||
@ -261,79 +223,80 @@ const fetchWarningData = async () => {
|
||||
warningTime: item.startTime || '-',
|
||||
endTime: item.endTime || '-',
|
||||
impactCount: item.affectedCount || 0,
|
||||
}));
|
||||
warningId: item.warningId || '',
|
||||
}))
|
||||
} else {
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
tableData.value = []
|
||||
total.value = 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取预警数据失败:', error);
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
console.error('获取预警数据失败:', error)
|
||||
tableData.value = []
|
||||
total.value = 0
|
||||
} finally {
|
||||
loading.value = false;
|
||||
loading.value = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 格式化日期时间
|
||||
const formatDateTime = date => {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
const hours = String(d.getHours()).padStart(2, '0');
|
||||
const minutes = String(d.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(d.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
const formatDateTime = (date) => {
|
||||
if (!date) return ''
|
||||
const d = new Date(date)
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
const hours = String(d.getHours()).padStart(2, '0')
|
||||
const minutes = String(d.getMinutes()).padStart(2, '0')
|
||||
const seconds = String(d.getSeconds()).padStart(2, '0')
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
|
||||
// 获取预警等级样式类
|
||||
const getWarningClass = level => {
|
||||
const getWarningClass = (level) => {
|
||||
const classMap = {
|
||||
红色预警: 'warning-red',
|
||||
橙色预警: 'warning-orange',
|
||||
黄色预警: 'warning-yellow',
|
||||
蓝色预警: 'warning-blue',
|
||||
};
|
||||
return classMap[level] || '';
|
||||
};
|
||||
}
|
||||
return classMap[level] || ''
|
||||
}
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit('update:visible', false);
|
||||
emit('close');
|
||||
};
|
||||
emit('update:visible', false)
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 点击影响点数量
|
||||
const handleImpactClick = item => {
|
||||
emit('impactClick', item);
|
||||
const handleImpactClick = (item) => {
|
||||
emit('impactClick', item)
|
||||
emit('impactClickItem', {
|
||||
...item,
|
||||
dateRange: filterForm.value.dateRange || [],
|
||||
riskLeve: filterForm.value.riskLeve || '',
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
// 分页操作
|
||||
const handleSizeChange = val => {
|
||||
pageSize.value = val;
|
||||
console.log('分页大小变化:', val);
|
||||
currentPage.value = 1;
|
||||
fetchWarningData();
|
||||
};
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val
|
||||
console.log('分页大小变化:', val)
|
||||
currentPage.value = 1
|
||||
fetchWarningData()
|
||||
}
|
||||
|
||||
const handleCurrentChange = val => {
|
||||
console.log('当前页码变化:', val);
|
||||
currentPage.value = val;
|
||||
fetchWarningData();
|
||||
};
|
||||
const handleCurrentChange = (val) => {
|
||||
console.log('当前页码变化:', val)
|
||||
currentPage.value = val
|
||||
fetchWarningData()
|
||||
}
|
||||
|
||||
// 初始化弹窗数据
|
||||
const initDialogData = () => {
|
||||
// 设置日期范围
|
||||
if (getdateRange.value && getdateRange.value.length === 2) {
|
||||
dateRange.value = getdateRange.value;
|
||||
dateRange.value = getdateRange.value
|
||||
}
|
||||
|
||||
// 如果有 warningitem 则设置筛选条件
|
||||
@ -343,83 +306,83 @@ const initDialogData = () => {
|
||||
countyName: props.warningitem.countyName || '',
|
||||
isEnded: '',
|
||||
dateRange: dateRange.value,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
filterForm.value = {
|
||||
riskLeve: '',
|
||||
countyName: '',
|
||||
isEnded: '',
|
||||
dateRange: dateRange.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 重置页码并获取数据
|
||||
currentPage.value = 1;
|
||||
console.log('初始化筛选条件:', filterForm.value);
|
||||
fetchWarningData();
|
||||
};
|
||||
currentPage.value = 1
|
||||
console.log('初始化筛选条件:', filterForm.value)
|
||||
fetchWarningData()
|
||||
}
|
||||
|
||||
// 重置数据
|
||||
const resetData = () => {
|
||||
// 清空表格数据
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
currentPage.value = 1;
|
||||
tableData.value = []
|
||||
total.value = 0
|
||||
currentPage.value = 1
|
||||
// 清空筛选条件
|
||||
filterForm.value = {
|
||||
riskLeve: '',
|
||||
countyName: '',
|
||||
isEnded: '',
|
||||
dateRange: [],
|
||||
};
|
||||
}
|
||||
// 清空日期范围
|
||||
dateRange.value = [];
|
||||
};
|
||||
dateRange.value = []
|
||||
}
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
newVal => {
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
// 弹窗打开时,初始化数据
|
||||
initDialogData();
|
||||
initDialogData()
|
||||
} else {
|
||||
// 弹窗关闭时,清空页面数据
|
||||
resetData();
|
||||
resetData()
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
)
|
||||
|
||||
// 监听筛选条件变化(手动修改时触发,初始化时不触发)
|
||||
watch(
|
||||
() => filterForm.value,
|
||||
(newVal, oldVal) => {
|
||||
console.log('筛选条件变化:===========', newVal, oldVal);
|
||||
console.log('筛选条件变化:===========', newVal, oldVal)
|
||||
// 只在旧值存在且不为空对象时触发(排除初始化情况)
|
||||
if (oldVal && Object.keys(oldVal).length > 0) {
|
||||
currentPage.value = 1;
|
||||
fetchWarningData();
|
||||
if (oldVal && Object.keys(oldVal).length > 0 && props.visible) {
|
||||
currentPage.value = 1
|
||||
fetchWarningData()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
// 同步 dateRange 和 filterForm.dateRange
|
||||
watch(
|
||||
() => dateRange.value,
|
||||
newVal => {
|
||||
filterForm.value.dateRange = newVal;
|
||||
(newVal) => {
|
||||
filterForm.value.dateRange = newVal
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
watch(
|
||||
() => filterForm.value.dateRange,
|
||||
newVal => {
|
||||
dateRange.value = newVal;
|
||||
(newVal) => {
|
||||
dateRange.value = newVal
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
{ deep: true },
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
:class="{ active: activeIndex === 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> -->
|
||||
<img :src="activeIndex === index ? item.icon1 : item.icon" alt="" />
|
||||
</div>
|
||||
@ -16,16 +16,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 气象预警监测表格组件 -->
|
||||
<WeatherWarningTable ref="weatherWarningTableRef" @clearFilters="handleClearFilters" />
|
||||
<WeatherWarningTable ref="weatherWarningTableRef" :getdateRange="getdateRange" @clearFilters="handleClearFilters" />
|
||||
<!-- 涉灾隐患点图片弹窗 -->
|
||||
<div v-if="showHazardPopup" class="hazard-popup" :style="popupStyle">
|
||||
<div class="hazard-popup-content">
|
||||
<div
|
||||
v-for="(item, index) in hazardItems"
|
||||
:key="index"
|
||||
class="hazard-item"
|
||||
@click="handleHazardItemClick(item)"
|
||||
>
|
||||
<div v-for="(item, index) in hazardItems" :key="index" class="hazard-item" @click="handleHazardItemClick(item)">
|
||||
<img :src="item.icon" :alt="item.label" />
|
||||
<span>{{ item.label }}</span>
|
||||
</div>
|
||||
@ -34,12 +29,7 @@
|
||||
<!-- 路段图片弹窗 -->
|
||||
<div v-if="showRoadPopup" class="hazard-popup road-popup" :style="roadPopupStyle">
|
||||
<div class="hazard-popup-content">
|
||||
<div
|
||||
v-for="(item, index) in roadItems"
|
||||
:key="index"
|
||||
class="hazard-item"
|
||||
@click="handleRoadItemClick(item)"
|
||||
>
|
||||
<div v-for="(item, index) in roadItems" :key="index" class="hazard-item" @click="handleRoadItemClick(item)">
|
||||
<img :src="item.icon" :alt="item.label" />
|
||||
<span>{{ item.label }}</span>
|
||||
</div>
|
||||
@ -49,48 +39,43 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, nextTick } from 'vue';
|
||||
import WeatherWarningTable from './component/WeatherWarningTable.vue';
|
||||
import { ref, computed, nextTick, inject } from 'vue'
|
||||
import WeatherWarningTable from './component/WeatherWarningTable.vue'
|
||||
|
||||
import warningIconIcon 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 bridgeIconIcon from '../../assets/RiskWarning_img/桥梁icon@2x.png';
|
||||
import roadIconIcon from '../../assets/RiskWarning_img/线路路段icon@2x.png';
|
||||
import teamIconIcon from '../../assets/RiskWarning_img/队伍icon@2x.png';
|
||||
import hazardIconIconIcon from '../../assets/RiskWarning_img/隐患点icon@2x.png';
|
||||
import engineeringIconIconIcon 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 slopeIconIcon from '../../assets/RiskWarning_img/边坡icon@2x.png'
|
||||
import bridgeIconIcon from '../../assets/RiskWarning_img/桥梁icon@2x.png'
|
||||
import roadIconIcon from '../../assets/RiskWarning_img/线路路段icon@2x.png'
|
||||
import teamIconIcon from '../../assets/RiskWarning_img/队伍icon@2x.png'
|
||||
import hazardIconIconIcon from '../../assets/RiskWarning_img/隐患点icon@2x.png'
|
||||
import engineeringIconIconIcon from '../../assets/RiskWarning_img/危大工程icon@2x.png'
|
||||
|
||||
import warningIconIcon1 from '../../assets/RiskWarning_img/风险预警icon1@2x.png';
|
||||
import tunnelIconIcon1 from '../../assets/RiskWarning_img/隧道icon1@2x.png';
|
||||
import slopeIconIcon1 from '../../assets/RiskWarning_img/边坡icon1@2x.png';
|
||||
import bridgeIconIcon1 from '../../assets/RiskWarning_img/桥梁icon1@2x.png';
|
||||
import roadIconIcon1 from '../../assets/RiskWarning_img/线路路段icon1@2x.png';
|
||||
import teamIconIcon1 from '../../assets/RiskWarning_img/队伍icon1@2x.png';
|
||||
import hazardIconIcon from '../../assets/RiskWarning_img/隐患点icon1@2x.png';
|
||||
import engineeringIconIcon 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 slopeIconIcon1 from '../../assets/RiskWarning_img/边坡icon1@2x.png'
|
||||
import bridgeIconIcon1 from '../../assets/RiskWarning_img/桥梁icon1@2x.png'
|
||||
import roadIconIcon1 from '../../assets/RiskWarning_img/线路路段icon1@2x.png'
|
||||
import teamIconIcon1 from '../../assets/RiskWarning_img/队伍icon1@2x.png'
|
||||
import hazardIconIcon from '../../assets/RiskWarning_img/隐患点icon1@2x.png'
|
||||
import engineeringIconIcon from '../../assets/RiskWarning_img/危大工程icon1@2x.png'
|
||||
|
||||
import hazardIconIcon1 from '../../assets/MaMap_img/一般路内隐患点@2x.png';
|
||||
import hazardIconIcon2 from '../../assets/MaMap_img/一般路外隐患点@2x.png';
|
||||
import hazardIconIcon3 from '../../assets/MaMap_img/较大路内隐患点@2x.png';
|
||||
import hazardIconIcon4 from '../../assets/MaMap_img/较大路外隐患点@2x.png';
|
||||
import hazardIconIcon5 from '../../assets/MaMap_img/重大路内隐患点@2x.png';
|
||||
import hazardIconIcon6 from '../../assets/MaMap_img/重大路外隐患点@2x.png';
|
||||
import hazardIconIcon1 from '../../assets/MaMap_img/一般路内隐患点@2x.png'
|
||||
import hazardIconIcon2 from '../../assets/MaMap_img/一般路外隐患点@2x.png'
|
||||
import hazardIconIcon3 from '../../assets/MaMap_img/较大路内隐患点@2x.png'
|
||||
import hazardIconIcon4 from '../../assets/MaMap_img/较大路外隐患点@2x.png'
|
||||
import hazardIconIcon5 from '../../assets/MaMap_img/重大路内隐患点@2x.png'
|
||||
import hazardIconIcon6 from '../../assets/MaMap_img/重大路外隐患点@2x.png'
|
||||
|
||||
import tunnelLineIcon3 from '../../assets/MaMap_img/高风险路段@2x.png';
|
||||
import tunnelLineIcon2 from '../../assets/MaMap_img/较高风险路段@2x.png';
|
||||
import tunnelLineIcon1 from '../../assets/MaMap_img/中风险路段@2x.png';
|
||||
import tunnelLineIcon from '../../assets/MaMap_img/线路icon定位@2x.png';
|
||||
import tunnelLineIcon3 from '../../assets/MaMap_img/高风险路段@2x.png'
|
||||
import tunnelLineIcon2 from '../../assets/MaMap_img/较高风险路段@2x.png'
|
||||
import tunnelLineIcon1 from '../../assets/MaMap_img/中风险路段@2x.png'
|
||||
import tunnelLineIcon from '../../assets/MaMap_img/线路icon定位@2x.png'
|
||||
|
||||
const emit = defineEmits([
|
||||
'changeActiveIndex',
|
||||
'clearMapMarkers',
|
||||
'hazardItemClick',
|
||||
'roadItemClick',
|
||||
'showHazardPopupfn',
|
||||
]);
|
||||
const getdateRange = inject('getdateRange', ref([]))
|
||||
const emit = defineEmits(['changeActiveIndex', 'clearMapMarkers', 'hazardItemClick', 'roadItemClick', 'showHazardPopupfn'])
|
||||
|
||||
const activeIndex = ref(-1);
|
||||
const activeIndex = ref(-1)
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
@ -108,7 +93,7 @@ const menuItems = [
|
||||
icon1: roadIconIcon1,
|
||||
},
|
||||
{
|
||||
label: '项目',
|
||||
label: '驻地',
|
||||
icon: 'icon-warning',
|
||||
iconClass: 'warning',
|
||||
icon: warningIconIcon,
|
||||
@ -149,12 +134,12 @@ const menuItems = [
|
||||
icon: engineeringIconIconIcon,
|
||||
icon1: engineeringIconIcon,
|
||||
},
|
||||
];
|
||||
]
|
||||
|
||||
// 涉灾隐患点弹窗相关
|
||||
const showHazardPopup = ref(false);
|
||||
const popupStyle = ref({});
|
||||
const navIconRefs = ref([]);
|
||||
const showHazardPopup = ref(false)
|
||||
const popupStyle = ref({})
|
||||
const navIconRefs = ref([])
|
||||
|
||||
// 隐患点数据
|
||||
const hazardItems = ref([
|
||||
@ -164,11 +149,11 @@ const hazardItems = ref([
|
||||
{ icon: hazardIconIcon4, label: '较大路外隐患点', isWithinRedLine: '否' },
|
||||
{ icon: hazardIconIcon1, label: '一般路内隐患点', isWithinRedLine: '是' },
|
||||
{ icon: hazardIconIcon2, label: '一般路外隐患点', isWithinRedLine: '否' },
|
||||
]);
|
||||
])
|
||||
|
||||
// 路段弹窗相关
|
||||
const showRoadPopup = ref(false);
|
||||
const roadPopupStyle = ref({});
|
||||
const showRoadPopup = ref(false)
|
||||
const roadPopupStyle = ref({})
|
||||
|
||||
// 路段数据
|
||||
const roadItems = ref([
|
||||
@ -176,108 +161,108 @@ const roadItems = ref([
|
||||
{ icon: tunnelLineIcon2, label: '较高风险路段' },
|
||||
{ icon: tunnelLineIcon1, label: '中风险路段' },
|
||||
{ icon: tunnelLineIcon, label: '低风险路段' },
|
||||
]);
|
||||
])
|
||||
|
||||
// 设置nav-icon-box的ref
|
||||
const setNavIconRef = (el, index) => {
|
||||
if (el) {
|
||||
navIconRefs.value[index] = el;
|
||||
navIconRefs.value[index] = el
|
||||
}
|
||||
};
|
||||
const weatherWarningTableRef = ref(null);
|
||||
}
|
||||
const weatherWarningTableRef = ref(null)
|
||||
|
||||
// 点击切换导航项
|
||||
const handleClick = (item, index) => {
|
||||
// 如果点击的是涉灾隐患点
|
||||
if (item.label === '涉灾隐患点') {
|
||||
// 切换弹窗显示状态
|
||||
showHazardPopup.value = !showHazardPopup.value;
|
||||
showHazardPopup.value = !showHazardPopup.value
|
||||
if (showHazardPopup.value) {
|
||||
showRoadPopup.value = false;
|
||||
showRoadPopup.value = false
|
||||
}
|
||||
if (showHazardPopup.value) {
|
||||
// 计算弹窗位置
|
||||
const navIconBox = navIconRefs.value[index];
|
||||
const navIconBox = navIconRefs.value[index]
|
||||
if (navIconBox) {
|
||||
const rect = navIconBox.getBoundingClientRect();
|
||||
const rect = navIconBox.getBoundingClientRect()
|
||||
popupStyle.value = {
|
||||
position: 'fixed',
|
||||
left: rect.right + 10 + 'px',
|
||||
top: rect.top + 'px',
|
||||
zIndex: 2,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (item.label === '路段') {
|
||||
// 如果点击的是路段
|
||||
|
||||
// 切换弹窗显示状态
|
||||
showRoadPopup.value = !showRoadPopup.value;
|
||||
showRoadPopup.value = !showRoadPopup.value
|
||||
if (showRoadPopup.value) {
|
||||
showHazardPopup.value = false;
|
||||
showHazardPopup.value = false
|
||||
}
|
||||
|
||||
if (showRoadPopup.value) {
|
||||
// 计算弹窗位置
|
||||
const navIconBox = navIconRefs.value[index];
|
||||
const navIconBox = navIconRefs.value[index]
|
||||
if (navIconBox) {
|
||||
const rect = navIconBox.getBoundingClientRect();
|
||||
const rect = navIconBox.getBoundingClientRect()
|
||||
roadPopupStyle.value = {
|
||||
position: 'fixed',
|
||||
left: rect.right + 10 + 'px',
|
||||
top: rect.top + 'px',
|
||||
zIndex: 2,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
emit('showHazardPopupfn', false);
|
||||
emit('showHazardPopupfn', false)
|
||||
} else {
|
||||
showHazardPopup.value = false;
|
||||
showRoadPopup.value = false;
|
||||
emit('showHazardPopupfn', false);
|
||||
showHazardPopup.value = false
|
||||
showRoadPopup.value = false
|
||||
emit('showHazardPopupfn', false)
|
||||
// 点击非路段,隐藏路段统计
|
||||
emit('hideRoadStats');
|
||||
emit('hideRoadStats')
|
||||
}
|
||||
|
||||
activeIndex.value = index;
|
||||
activeIndex.value = index
|
||||
if (item.label !== '路段') {
|
||||
emit('changeActiveIndex', {
|
||||
...item,
|
||||
});
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 点击隐患点项
|
||||
const handleHazardItemClick = item => {
|
||||
console.log('点击隐患点:', item);
|
||||
emit('hazardItemClick', item);
|
||||
const handleHazardItemClick = (item) => {
|
||||
console.log('点击隐患点:', item)
|
||||
emit('hazardItemClick', item)
|
||||
// 可以在这里添加其他逻辑,比如关闭弹窗
|
||||
// showHazardPopup.value = false;
|
||||
emit('showHazardPopupfn', true);
|
||||
};
|
||||
emit('showHazardPopupfn', true)
|
||||
}
|
||||
|
||||
const roadItem = ref({});
|
||||
const roadItem = ref({})
|
||||
// 点击路段项
|
||||
const handleRoadItemClick = item => {
|
||||
console.log('点击路段:', item);
|
||||
roadItem.value = item;
|
||||
emit('roadItemClick', item);
|
||||
const handleRoadItemClick = (item) => {
|
||||
console.log('点击路段:', item)
|
||||
roadItem.value = item
|
||||
emit('roadItemClick', item)
|
||||
// 可以在这里添加其他逻辑,比如关闭弹窗
|
||||
// showRoadPopup.value = false;
|
||||
};
|
||||
}
|
||||
|
||||
// 处理清除筛选事件
|
||||
const handleClearFilters = () => {
|
||||
console.log('清除筛选条件');
|
||||
console.log('清除筛选条件')
|
||||
// 重置活动索引
|
||||
activeIndex.value = -1;
|
||||
activeIndex.value = -1
|
||||
// 关闭弹窗
|
||||
showHazardPopup.value = false;
|
||||
showRoadPopup.value = false;
|
||||
showHazardPopup.value = false
|
||||
showRoadPopup.value = false
|
||||
// 触发清除地图标记事件
|
||||
emit('clearMapMarkers');
|
||||
emit('showHazardPopupfn', false);
|
||||
};
|
||||
emit('clearMapMarkers')
|
||||
emit('showHazardPopupfn', false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,7 @@
|
||||
<!-- 气象预警监测表格 -->
|
||||
<div class="weather-warning-wrapper">
|
||||
<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="header-title">气象预警监测</div>
|
||||
<div class="filter-tags">
|
||||
@ -48,13 +43,7 @@
|
||||
<div class="warning-level">
|
||||
<img
|
||||
: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=""
|
||||
/>
|
||||
@ -70,14 +59,28 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||
import { request } from '@/utils/request';
|
||||
import orangeIcon from '../../../assets/RiskWarning_img/橙色@2x.png';
|
||||
import yellowIcon from '../../../assets/RiskWarning_img/黄色@2x.png';
|
||||
import redIcon from '../../../assets/RiskWarning_img//红色@2x.png';
|
||||
import blueIcon from '../../../assets/RiskWarning_img/蓝色@2x.png';
|
||||
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
||||
import { request } from '@/utils/request'
|
||||
import orangeIcon from '../../../assets/RiskWarning_img/橙色@2x.png'
|
||||
import yellowIcon from '../../../assets/RiskWarning_img/黄色@2x.png'
|
||||
import redIcon from '../../../assets/RiskWarning_img//红色@2x.png'
|
||||
import blueIcon from '../../../assets/RiskWarning_img/蓝色@2x.png'
|
||||
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({
|
||||
@ -85,98 +88,94 @@ const filters = ref({
|
||||
blue: false,
|
||||
orange: false,
|
||||
yellow: false,
|
||||
});
|
||||
})
|
||||
|
||||
// 预警数据
|
||||
const warningData = ref([]);
|
||||
const warningData = ref([])
|
||||
|
||||
// 表格自动滚动相关
|
||||
const tableRef = ref(null);
|
||||
const isScrolling = ref(true);
|
||||
const scrollTimer = ref(null);
|
||||
const scrollSpeed = 50; // 滚动间隔(毫秒)
|
||||
const scrollStep = 1; // 每次滚动像素
|
||||
const tableRef = ref(null)
|
||||
const isScrolling = ref(true)
|
||||
const scrollTimer = ref(null)
|
||||
const scrollSpeed = 50 // 滚动间隔(毫秒)
|
||||
const scrollStep = 1 // 每次滚动像素
|
||||
|
||||
// 检查是否有筛选条件
|
||||
const hasFilter = computed(() => {
|
||||
return filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow;
|
||||
});
|
||||
return filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow
|
||||
})
|
||||
|
||||
// 开始自动滚动
|
||||
const startAutoScroll = () => {
|
||||
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'
|
||||
);
|
||||
if (!tableBody) return;
|
||||
const tableBody = document.querySelector('.weather-warning-panel .el-table__body-wrapper .el-scrollbar__wrap')
|
||||
if (!tableBody) return
|
||||
|
||||
scrollTimer.value = setInterval(() => {
|
||||
if (tableBody) {
|
||||
tableBody.scrollTop += scrollStep;
|
||||
tableBody.scrollTop += scrollStep
|
||||
// 滚动到底部后回到顶部(使用 >= 判断,并留出一点余量确保准确触发)
|
||||
const maxScroll = tableBody.scrollHeight - tableBody.clientHeight;
|
||||
const maxScroll = tableBody.scrollHeight - tableBody.clientHeight
|
||||
if (tableBody.scrollTop >= maxScroll - 2) {
|
||||
tableBody.scrollTop = 0;
|
||||
tableBody.scrollTop = 0
|
||||
}
|
||||
}
|
||||
}, scrollSpeed);
|
||||
};
|
||||
}, scrollSpeed)
|
||||
}
|
||||
|
||||
// 停止自动滚动
|
||||
const stopAutoScroll = () => {
|
||||
if (scrollTimer.value) {
|
||||
clearInterval(scrollTimer.value);
|
||||
scrollTimer.value = null;
|
||||
clearInterval(scrollTimer.value)
|
||||
scrollTimer.value = null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 重置滚动到顶部
|
||||
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) {
|
||||
tableBody.scrollTop = 0;
|
||||
tableBody.scrollTop = 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 鼠标移入停止滚动
|
||||
const handleMouseEnter = () => {
|
||||
stopAutoScroll();
|
||||
};
|
||||
stopAutoScroll()
|
||||
}
|
||||
|
||||
// 鼠标移出开始滚动
|
||||
const handleMouseLeave = () => {
|
||||
if (!hasFilter.value) {
|
||||
isScrolling.value = true;
|
||||
startAutoScroll();
|
||||
isScrolling.value = true
|
||||
startAutoScroll()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 监听筛选条件变化
|
||||
watch(hasFilter, newVal => {
|
||||
watch(hasFilter, (newVal) => {
|
||||
if (newVal) {
|
||||
// 有筛选条件时停止滚动并回到顶部
|
||||
stopAutoScroll();
|
||||
resetScrollToTop();
|
||||
stopAutoScroll()
|
||||
resetScrollToTop()
|
||||
} else {
|
||||
// 取消筛选后开始滚动
|
||||
isScrolling.value = true;
|
||||
isScrolling.value = true
|
||||
nextTick(() => {
|
||||
startAutoScroll();
|
||||
});
|
||||
startAutoScroll()
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false);
|
||||
const loading = ref(false)
|
||||
// 获取气象预警数据
|
||||
const fetchWeatherWarningData = async () => {
|
||||
loading.value = true;
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weather-warning/affected-count/_by_weather',
|
||||
@ -184,117 +183,118 @@ const fetchWeatherWarningData = async () => {
|
||||
params: {
|
||||
offset: 0,
|
||||
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) {
|
||||
// 映射数据格式
|
||||
warningData.value = res.data.data.map(item => ({
|
||||
warningData.value = res.data.data.map((item) => ({
|
||||
time: item.startTime || '',
|
||||
type: item.weatherType || '',
|
||||
level: item.riskLeve || '',
|
||||
levelClass: getLevelClass(item.riskLeve || ''),
|
||||
district: item.countyName || '',
|
||||
}));
|
||||
}))
|
||||
} else {
|
||||
warningData.value = [];
|
||||
warningData.value = []
|
||||
}
|
||||
loading.value = false;
|
||||
loading.value = false
|
||||
nextTick(() => {
|
||||
startAutoScroll();
|
||||
startAutoScroll()
|
||||
// 添加鼠标事件监听
|
||||
const tableContainer = document.querySelector('.weather-warning-panel .table-container');
|
||||
const tableContainer = document.querySelector('.weather-warning-panel .table-container')
|
||||
if (tableContainer) {
|
||||
tableContainer.addEventListener('mouseenter', handleMouseEnter);
|
||||
tableContainer.addEventListener('mouseleave', handleMouseLeave);
|
||||
tableContainer.addEventListener('mouseenter', handleMouseEnter)
|
||||
tableContainer.addEventListener('mouseleave', handleMouseLeave)
|
||||
}
|
||||
});
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('获取气象预警数据失败:', error);
|
||||
warningData.value = [];
|
||||
loading.value = false;
|
||||
console.error('获取气象预警数据失败:', error)
|
||||
warningData.value = []
|
||||
loading.value = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 根据预警等级获取对应的class
|
||||
const getLevelClass = level => {
|
||||
if (level.includes('红')) return 'red';
|
||||
if (level.includes('橙')) return 'orange';
|
||||
if (level.includes('黄')) return 'yellow';
|
||||
if (level.includes('蓝')) return 'blue';
|
||||
return '';
|
||||
};
|
||||
const getLevelClass = (level) => {
|
||||
if (level.includes('红')) return 'red'
|
||||
if (level.includes('橙')) return 'orange'
|
||||
if (level.includes('黄')) return 'yellow'
|
||||
if (level.includes('蓝')) return 'blue'
|
||||
return ''
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
// 获取气象预警数据
|
||||
console.log('获取气象预警数据');
|
||||
fetchWeatherWarningData();
|
||||
});
|
||||
console.log('获取气象预警数据')
|
||||
fetchWeatherWarningData()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
stopAutoScroll();
|
||||
const tableContainer = document.querySelector('.weather-warning-panel .table-container');
|
||||
stopAutoScroll()
|
||||
const tableContainer = document.querySelector('.weather-warning-panel .table-container')
|
||||
if (tableContainer) {
|
||||
tableContainer.removeEventListener('mouseenter', handleMouseEnter);
|
||||
tableContainer.removeEventListener('mouseleave', handleMouseLeave);
|
||||
tableContainer.removeEventListener('mouseenter', handleMouseEnter)
|
||||
tableContainer.removeEventListener('mouseleave', handleMouseLeave)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// 过滤后的数据
|
||||
const filteredData = computed(() => {
|
||||
const hasFilter =
|
||||
filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow;
|
||||
if (!hasFilter) return warningData.value;
|
||||
const hasFilter = filters.value.red || filters.value.blue || filters.value.orange || filters.value.yellow
|
||||
if (!hasFilter) return warningData.value
|
||||
|
||||
return warningData.value.filter(item => {
|
||||
if (filters.value.red && item.levelClass === 'red') return true;
|
||||
if (filters.value.blue && item.levelClass === 'blue') return true;
|
||||
if (filters.value.orange && item.levelClass === 'orange') return true;
|
||||
if (filters.value.yellow && item.levelClass === 'yellow') return true;
|
||||
return false;
|
||||
});
|
||||
});
|
||||
return warningData.value.filter((item) => {
|
||||
if (filters.value.red && item.levelClass === 'red') return true
|
||||
if (filters.value.blue && item.levelClass === 'blue') return true
|
||||
if (filters.value.orange && item.levelClass === 'orange') return true
|
||||
if (filters.value.yellow && item.levelClass === 'yellow') return true
|
||||
return false
|
||||
})
|
||||
})
|
||||
|
||||
// el-table 样式
|
||||
const headerCellStyle = () => ({
|
||||
background: '#17466F',
|
||||
color: 'rgba(255, 255, 255, 0.6)',
|
||||
});
|
||||
})
|
||||
|
||||
const cellStyle = () => ({
|
||||
background: '#142E49',
|
||||
color: 'rgba(255, 255, 255, 0.9)',
|
||||
borderBottom: '1px solid rgba(64, 169, 255, 0.1)',
|
||||
padding: '5px 5px',
|
||||
});
|
||||
})
|
||||
|
||||
const rowClassName = ({ rowIndex }) => {
|
||||
return rowIndex % 2 === 0 ? 'even-row' : 'odd-row';
|
||||
};
|
||||
return rowIndex % 2 === 0 ? 'even-row' : 'odd-row'
|
||||
}
|
||||
|
||||
// 清除筛选条件
|
||||
const clearFilters = () => {
|
||||
console.log('清除筛选条件');
|
||||
console.log('清除筛选条件')
|
||||
filters.value = {
|
||||
red: false,
|
||||
blue: false,
|
||||
orange: false,
|
||||
yellow: false,
|
||||
};
|
||||
}
|
||||
// 触发事件通知父组件
|
||||
emit('clearFilters');
|
||||
};
|
||||
emit('clearFilters')
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
const setWarningData = data => {
|
||||
warningData.value = data;
|
||||
};
|
||||
const setWarningData = (data) => {
|
||||
warningData.value = data
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
clearFilters,
|
||||
setWarningData,
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -179,7 +179,7 @@ export const logUserOperation = (type, command) => {
|
||||
|
||||
// 使用 fetch 的 keepalive 选项确保页面卸载后请求仍能完成
|
||||
fetch('/snow-ops-platform/weather-warning/users/logs', {
|
||||
method: 'PUT',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
@ -201,121 +201,6 @@ export const logUserOperation = (type, command) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 监听外部应用打开并记录日志的辅助函数
|
||||
const listenForAppLaunch = (type, command) => {
|
||||
let hasLogged = false
|
||||
let hasLostFocus = false // 是否已经失去焦点
|
||||
let focusTimer = null // 用于延迟检测的定时器
|
||||
const startTime = Date.now()
|
||||
console.log('开始监听外部应用打开...', { type, command, initialHidden: document.hidden, startTime })
|
||||
|
||||
// 确认打开外部应用
|
||||
const confirmLaunch = () => {
|
||||
if (hasLogged) return
|
||||
hasLogged = true
|
||||
console.log('确认用户点击了"打开"按钮,调用日志接口')
|
||||
logUserOperation(type, command)
|
||||
cleanup()
|
||||
}
|
||||
|
||||
// 检测打开状态
|
||||
const checkLaunchStatus = () => {
|
||||
if (hasLogged) return
|
||||
|
||||
const now = Date.now()
|
||||
const elapsed = now - startTime
|
||||
|
||||
const isHidden = document.hidden
|
||||
const currentHasFocus = document.hasFocus()
|
||||
|
||||
console.log(`检测状态 [${elapsed}ms]:`, { isHidden, hasFocus: currentHasFocus, hasLostFocus, hasLogged })
|
||||
|
||||
// 情况1: 页面被隐藏 → 用户点击了"打开"
|
||||
if (isHidden) {
|
||||
confirmLaunch()
|
||||
return
|
||||
}
|
||||
|
||||
// 情况2: 失去焦点后重新获得焦点 → 用户点击了"取消"
|
||||
if (hasLostFocus && currentHasFocus) {
|
||||
console.log('用户点击了"取消"按钮,不记录日志')
|
||||
cleanup()
|
||||
return
|
||||
}
|
||||
|
||||
// 记录当前焦点状态
|
||||
if (!currentHasFocus && !hasLostFocus) {
|
||||
hasLostFocus = true
|
||||
console.log('页面失去焦点,开始等待用户选择...')
|
||||
|
||||
// 设置延迟检测:1.5秒后如果仍未获得焦点,认为用户点击了"打开"
|
||||
focusTimer = setTimeout(() => {
|
||||
if (!hasLogged && hasLostFocus && !document.hasFocus()) {
|
||||
console.log('1.5秒未重新获得焦点,认为用户点击了"打开"')
|
||||
confirmLaunch()
|
||||
}
|
||||
}, 1500)
|
||||
}
|
||||
}
|
||||
|
||||
// 方法1: 监听 visibilitychange 事件
|
||||
const handleVisibilityChange = () => {
|
||||
console.log('visibilitychange 触发, document.hidden:', document.hidden)
|
||||
checkLaunchStatus()
|
||||
}
|
||||
|
||||
// 方法2: 监听 window blur 事件
|
||||
const handleWindowBlur = () => {
|
||||
console.log('window blur 触发')
|
||||
hasLostFocus = true
|
||||
// 设置延迟检测:1.5秒后如果仍未获得焦点,认为用户点击了"打开"
|
||||
focusTimer = setTimeout(() => {
|
||||
if (!hasLogged && hasLostFocus && !document.hasFocus()) {
|
||||
console.log('1.5秒未重新获得焦点,认为用户点击了"打开"')
|
||||
confirmLaunch()
|
||||
}
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
// 方法3: 监听 window focus 事件(判断用户是否点击取消)
|
||||
const handleWindowFocus = () => {
|
||||
console.log('window focus 触发')
|
||||
checkLaunchStatus()
|
||||
}
|
||||
|
||||
// 方法4: 定时轮询检测
|
||||
let checkInterval = setInterval(() => {
|
||||
checkLaunchStatus()
|
||||
const elapsed = Date.now() - startTime
|
||||
|
||||
// 10秒后停止轮询
|
||||
if (elapsed > 10000 || hasLogged) {
|
||||
clearInterval(checkInterval)
|
||||
}
|
||||
}, 200)
|
||||
|
||||
// 清理函数
|
||||
const cleanup = () => {
|
||||
console.log('清理监听器')
|
||||
clearInterval(checkInterval)
|
||||
clearTimeout(focusTimer)
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||||
window.removeEventListener('blur', handleWindowBlur)
|
||||
window.removeEventListener('focus', handleWindowFocus)
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||||
window.addEventListener('blur', handleWindowBlur)
|
||||
window.addEventListener('focus', handleWindowFocus)
|
||||
|
||||
// 10秒后自动清理
|
||||
setTimeout(() => {
|
||||
if (!hasLogged) {
|
||||
console.log('10秒超时,未检测到打开操作,清理监听器')
|
||||
cleanup()
|
||||
}
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
// 打开视频会议
|
||||
export const openVideoConference = async (item) => {
|
||||
@ -419,14 +304,21 @@ export const opencallConference = async (item) => {
|
||||
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
|
||||
const getTokenFromStorage = () => {
|
||||
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 获取
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) return token
|
||||
@ -442,6 +334,8 @@ const getTokenFromStorage = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 基础 API 地址配置(根据当前网址动态判断)存在bxztpc时,外网地址,否则内网地址
|
||||
const BASE_API_URL = 'http://58.144.223.132:30008/'
|
||||
// 获取图片地址数组
|
||||
export const getImageUrlList = (fileIdStr) => {
|
||||
if (!fileIdStr || typeof fileIdStr !== 'string') {
|
||||
@ -450,7 +344,10 @@ export const getImageUrlList = (fileIdStr) => {
|
||||
}
|
||||
|
||||
// 按逗号分割字符串
|
||||
const fileIdList = fileIdStr.split(',').map(id => id.trim()).filter(id => id)
|
||||
const fileIdList = fileIdStr
|
||||
.split(',')
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id)
|
||||
|
||||
if (fileIdList.length === 0) {
|
||||
console.warn('fileIdStr 分割后为空')
|
||||
@ -461,7 +358,7 @@ export const getImageUrlList = (fileIdStr) => {
|
||||
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}`
|
||||
})
|
||||
|
||||
|
||||
@ -1,113 +0,0 @@
|
||||
<template>
|
||||
<div class="risk-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-type">
|
||||
<div>项目</div>
|
||||
<div>类型</div>
|
||||
</th>
|
||||
<th class="col-red">红色预警</th>
|
||||
<th class="col-orange">橙色预警</th>
|
||||
<th class="col-yellow">黄色预警</th>
|
||||
<th class="col-blue">蓝色预警</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in tableData" :key="index">
|
||||
<td class="col-type">{{ item.type }}</td>
|
||||
<td class="col-red">{{ item.red }}</td>
|
||||
<td class="col-orange">{{ item.orange }}</td>
|
||||
<td class="col-yellow">{{ item.yellow }}</td>
|
||||
<td class="col-blue">{{ item.blue }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
tableData: {
|
||||
type: Array,
|
||||
default: () => [
|
||||
{ type: '桥梁', red: 0, orange: 1, yellow: 8, blue: 11 },
|
||||
{ type: '隧道', red: 0, orange: 0, yellow: 6, blue: 12 },
|
||||
{ type: '边坡', red: 0, orange: 1, yellow: 9, blue: 9 },
|
||||
{ type: '路段', red: 0, orange: 2, yellow: 11, blue: 7 },
|
||||
{ type: '项目', red: 0, orange: 2, yellow: 11, blue: 7 },
|
||||
],
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.risk-table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 4px 4px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
}
|
||||
|
||||
thead {
|
||||
th {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&.col-type {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
&:nth-child(odd) {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 14px;
|
||||
|
||||
&.col-type {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.col-red {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.col-orange {
|
||||
color: #ff7a45;
|
||||
}
|
||||
|
||||
.col-yellow {
|
||||
color: #ffc53d;
|
||||
}
|
||||
|
||||
.col-blue {
|
||||
color: #40a9ff;
|
||||
}
|
||||
|
||||
.col-type {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -103,6 +103,7 @@
|
||||
v-model:visible="dialogVisible.warningInfo"
|
||||
@close="closeDialog('warningInfo')"
|
||||
@responseStatus="openDialog('responseStatus')"
|
||||
@getResponseStatusrowFn="getResponseStatusfn"
|
||||
/>
|
||||
|
||||
<!-- 事件详情对话框 -->
|
||||
@ -129,6 +130,7 @@
|
||||
<!-- 影响点情况对话框 -->
|
||||
<impactPointDialog
|
||||
:handleImpactItem="handleImpactItem"
|
||||
:getdateRange="getdateRange"
|
||||
v-model:visible="dialogVisible.impactPoint"
|
||||
@close="closeDialog('impactPoint')"
|
||||
@detail="openDialog('impactPointDetail')"
|
||||
@ -151,6 +153,7 @@
|
||||
<!-- 响应状态对话框 -->
|
||||
<responseStatusDialog
|
||||
:dispatchDateRange="dispatchDateRange"
|
||||
:responseStatusData="responseStatusRow"
|
||||
v-model:visible="dialogVisible.responseStatus"
|
||||
@close="closeDialog('responseStatus')"
|
||||
@detail="openDialog('responsePointDetail')"
|
||||
@ -240,7 +243,7 @@
|
||||
<imageInspectionDialog v-model:visible="dialogVisible.imageInspection" @close="closeDialog('imageInspection')" />
|
||||
|
||||
<!-- 巡查里程对话框 -->
|
||||
<patrolMileageDialog v-model:visible="dialogVisible.patrolMileage" @close="closeDialog('patrolMileage')" />
|
||||
<patrolMileageDialog v-model:visible="dialogVisible.patrolMileage" :getdateRange="getdateRange" @close="closeDialog('patrolMileage')" />
|
||||
|
||||
<!-- 巡查情况对话框 -->
|
||||
<patrolSituationDialog v-model:visible="dialogVisible.patrolSituation" @close="closeDialog('patrolSituation')" />
|
||||
@ -373,7 +376,7 @@ const roadItem = ref({})
|
||||
const showRoadStats = ref(false)
|
||||
const roadItemClick = (item) => {
|
||||
console.log('点击路段:', item)
|
||||
roadItem.value = {...item}
|
||||
roadItem.value = { ...item }
|
||||
showRoadStats.value = true
|
||||
}
|
||||
|
||||
@ -387,8 +390,9 @@ const handleHideRoadStats = () => {
|
||||
const handleHazardItemClick = (item) => {
|
||||
console.log('点击隐患点:', item)
|
||||
// 调用地图组件的方法获取风险点数据
|
||||
let items = { ...item }
|
||||
if (chongqingMapRef.value) {
|
||||
chongqingMapRef.value.handleHazardItemClick(item)
|
||||
chongqingMapRef.value.handleHazardItemClick(items, false)
|
||||
}
|
||||
}
|
||||
const showHazardPopup = ref(false)
|
||||
@ -459,17 +463,17 @@ const impactPointDetailItem = ref({})
|
||||
// 处理影响点点击
|
||||
const handleImpactPointClick = (item) => {
|
||||
console.log('影响点点击:', item)
|
||||
impactPointDetailItem.value = item
|
||||
impactPointDetailItem.value = { ...item }
|
||||
}
|
||||
const handleImpactItem = ref({})
|
||||
const handleImpactClickItem = (item) => {
|
||||
console.log('影响点点击详情:', item)
|
||||
handleImpactItem.value = item
|
||||
handleImpactItem.value = { ...item }
|
||||
}
|
||||
const tongnanInfoItemData = ref({})
|
||||
const tongnanInfoItemDatafn = (item) => {
|
||||
console.log('点击详情:', item)
|
||||
tongnanInfoItemData.value = item
|
||||
tongnanInfoItemData.value = { ...item }
|
||||
}
|
||||
// 关闭弹窗
|
||||
const closeDialog = (dialogName) => {
|
||||
@ -482,7 +486,7 @@ const closeDialog = (dialogName) => {
|
||||
const handleOpenHazardPointSituation = (item) => {
|
||||
console.log('打开涉灾隐患点情况弹窗:', item)
|
||||
hazardPointDialogTitle.value = '涉灾隐患点情况'
|
||||
hazardPointData.value = item
|
||||
hazardPointData.value = { ...item }
|
||||
dialogVisible.value.hazardPointSituation = true
|
||||
}
|
||||
|
||||
@ -502,28 +506,33 @@ const handleOpenRoadSectionSituation = (item) => {
|
||||
const warningitem = ref({})
|
||||
const handleWarningClick = (item) => {
|
||||
console.log('气象预警点击:', item)
|
||||
warningitem.value = item
|
||||
warningitem.value = { ...item }
|
||||
}
|
||||
|
||||
const clearanceSituationDialogItemData = ref({})
|
||||
const handleItemData = (item) => {
|
||||
console.log('点击详情:', item)
|
||||
clearanceSituationDialogItemData.value = item
|
||||
clearanceSituationDialogItemData.value = { ...item }
|
||||
}
|
||||
|
||||
const dispatchDateRange = ref([])
|
||||
const handleDispatchDateRange = (range) => {
|
||||
dispatchDateRange.value = range
|
||||
dispatchDateRange.value = [...range]
|
||||
}
|
||||
const rightDateRange = ref([])
|
||||
const updateDateRange = (range) => {
|
||||
console.log('更新日期范围:', range)
|
||||
rightDateRange.value = range
|
||||
rightDateRange.value = [...range]
|
||||
}
|
||||
const filterForm = ref({})
|
||||
const updateFilterForm = (item) => {
|
||||
console.log('更新筛选表单:', item)
|
||||
filterForm.value = item
|
||||
filterForm.value = { ...item }
|
||||
}
|
||||
const responseStatusRow = ref({})
|
||||
const getResponseStatusfn = (row) => {
|
||||
console.log('已叫应详情:', row)
|
||||
responseStatusRow.value = row
|
||||
}
|
||||
|
||||
// 确认对话框配置
|
||||
@ -571,7 +580,7 @@ const handleDistrictClick = (item) => {
|
||||
} else if (item.data.roadType == 'rural') {
|
||||
openDialog('responseSituation')
|
||||
} else if (item.data.type == 'project' && item.data.roadType == '-') {
|
||||
// 项目
|
||||
// 驻地
|
||||
openDialog('tongnanResponsible')
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@
|
||||
<el-table-column prop="bridgeCount" 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="projectCount" label="项目" :min-width="vw(50)" />
|
||||
<el-table-column prop="projectCount" label="驻地" :min-width="vw(50)" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
@ -79,7 +79,7 @@
|
||||
<SectionHeader title="响应调度">
|
||||
<template #right>
|
||||
<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">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
@ -153,6 +153,7 @@ watch(
|
||||
() => getdateRange.value,
|
||||
(newVal) => {
|
||||
console.log('left.vue 日期范围变化:', newVal)
|
||||
dateRange.value = JSON.parse(JSON.stringify(newVal))
|
||||
init()
|
||||
},
|
||||
{ deep: true },
|
||||
@ -258,7 +259,7 @@ const impactData = ref([
|
||||
{ name: '桥梁', count: 0 },
|
||||
{ name: '隧道', count: 0 },
|
||||
{ name: '边坡', count: 0 },
|
||||
{ name: '项目', count: 0 },
|
||||
{ name: '驻地', count: 0 },
|
||||
])
|
||||
|
||||
const dateRange = ref([])
|
||||
@ -593,12 +594,12 @@ const loadBarChartData = async () => {
|
||||
bridge: '桥梁',
|
||||
tunnel: '隧道',
|
||||
slope: '边坡',
|
||||
project: '项目',
|
||||
project: '驻地',
|
||||
Road: '路段',
|
||||
Bridge: '桥梁',
|
||||
Tunnel: '隧道',
|
||||
Slope: '边坡',
|
||||
Project: '项目',
|
||||
Project: '驻地',
|
||||
}
|
||||
|
||||
// 转换英文name为中文
|
||||
@ -615,7 +616,7 @@ const loadBarChartData = async () => {
|
||||
impactData.value[2].count = item.count || 0
|
||||
} else if (item.name == '边坡') {
|
||||
impactData.value[3].count = item.count || 0
|
||||
} else if (item.name == '项目') {
|
||||
} else if (item.name == '驻地') {
|
||||
impactData.value[4].count = item.count || 0
|
||||
}
|
||||
})
|
||||
@ -628,7 +629,7 @@ const loadBarChartData = async () => {
|
||||
{ name: '桥梁', count: 0 },
|
||||
{ name: '隧道', count: 0 },
|
||||
{ name: '边坡', count: 0 },
|
||||
{ name: '项目', count: 0 },
|
||||
{ name: '驻地', count: 0 },
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@
|
||||
<SectionHeader title="受灾情况">
|
||||
<template #right>
|
||||
<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">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
@ -205,6 +205,7 @@ import icon62 from '../../assets/RiskWarning_img/路径62@2x.png'
|
||||
import icon621 from '../../assets/RiskWarning_img/路径62@2x (1).png'
|
||||
import icon622 from '../../assets/RiskWarning_img/路径62@2x (2).png'
|
||||
import { formatDateTime } from './component/index.js'
|
||||
const getdateRange = inject('getdateRange', ref([]))
|
||||
|
||||
const emit = defineEmits([
|
||||
'openClearanceSituation',
|
||||
@ -218,7 +219,6 @@ const emit = defineEmits([
|
||||
|
||||
// 注入兄弟组件通信机制
|
||||
const setRefreshRightData = inject('setRefreshRightData')
|
||||
const getdateRange = inject('getdateRange', ref([]))
|
||||
|
||||
const props = defineProps({})
|
||||
|
||||
@ -586,10 +586,10 @@ const handleResourceClick = (item) => {
|
||||
|
||||
// 管控路段数据
|
||||
const controlData1 = ref([
|
||||
{ label: '封闭管控数', value: '40' },
|
||||
{ label: '半幅通行数', value: '40' },
|
||||
{ label: '限速(限车型)数', value: '24' },
|
||||
{ label: '告警阻拦处数', value: '32' },
|
||||
{ label: '封闭管控数', value: '40', key: '全幅封闭' },
|
||||
{ label: '半幅通行数', value: '40', key: '半幅封闭' },
|
||||
{ label: '限速(限车型)数', value: '24', key: '限速' },
|
||||
{ label: '告警阻拦处数', value: '32', key: '告警阻拦' },
|
||||
])
|
||||
const controlData2 = ref([
|
||||
{ label: '停工项目数', value: '0', key: 'stoped_project_count' },
|
||||
@ -756,6 +756,7 @@ watch(
|
||||
() => getdateRange.value,
|
||||
(newVal) => {
|
||||
console.log('right.vue 日期范围变化:', newVal)
|
||||
dateRange.value = newVal
|
||||
init()
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
|
||||
@ -81,7 +81,16 @@ const emit = defineEmits(['openAIResult', 'dateRangeChange'])
|
||||
|
||||
// 注入兄弟组件通信机制
|
||||
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([])
|
||||
@ -219,6 +228,10 @@ const fetchRiskLevelCount = async () => {
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
// 页面进入时最先执行,设置默认时间范围为今天,并触发事件通知父组件
|
||||
const todayRange = getTodayDateRange()
|
||||
dateRange.value = todayRange
|
||||
emit('dateRangeChange', todayRange)
|
||||
fetchRiskLevelCount()
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -98,7 +98,7 @@ const columns = [
|
||||
},
|
||||
{
|
||||
prop: "affectedProjectCount",
|
||||
label: "影响项目",
|
||||
label: "影响驻地",
|
||||
},
|
||||
{
|
||||
prop: "responseStatus",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user