<template>
|
<div class="water-velocity-content" v-loading="localLoading" element-loading-text="流速数据加载中..."
|
element-loading-background="rgba(11, 34, 20, 0.3)">
|
<div v-if="showSelectPrompt" style="font-weight: bold;">
|
请在地图中选取唯一测量点
|
</div>
|
<div v-else>
|
<div class="location-info">
|
<h3>位置信息</h3>
|
<p v-if="deviceName" class="coordinates">
|
{{ deviceName }}
|
</p>
|
<p v-if="!deviceName" class="coordinates">
|
经度: <strong>{{ safeCurrentInfo.longitude.toFixed(3) }} </strong>
|
纬度:<strong>{{ safeCurrentInfo.latitude.toFixed(3) }}</strong>
|
</p>
|
</div>
|
<div class="velocity-info">
|
<h3>流速信息 (m/s)</h3>
|
<p>
|
平均:<strong>{{ avgVelocity }}</strong>
|
最大:<strong>{{ maxVelocity }}</strong>
|
最小:<strong>{{ minVelocity }}</strong>
|
</p>
|
</div>
|
</div>
|
<div class="chart-placeholder">
|
<div ref="chartDom" style="width: 100%; height: 300px;"></div>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted, watch, computed, onBeforeUnmount } from 'vue';
|
import * as echarts from 'echarts';
|
import { useSimStore } from '@/store/simulation';
|
import { storeToRefs } from 'pinia';
|
import { getFlowRate } from '@/api/trApi.js'; // 假设你有真实接口
|
import { EventBus } from '@/eventBus';
|
import { ElMessage } from 'element-plus';
|
|
const simStore = useSimStore();
|
const { currentInfo } = storeToRefs(simStore);
|
const deviceName = computed(() => {
|
return currentInfo.value?.deviceName;
|
});
|
// 图表 DOM 引用
|
const chartDom = ref(null);
|
let myChart = null;
|
|
// 加载状态变量
|
const localLoading = ref(false); // <<< 新增局部 loading 变量
|
|
// 安全获取经纬度
|
const safeCurrentInfo = computed(() => {
|
const info = currentInfo.value || {};
|
return {
|
longitude: info.longitude !== undefined ? info.longitude : 0.0,
|
latitude: info.latitude !== undefined ? info.latitude : 0.0
|
};
|
});
|
|
// 是否显示选择提示
|
const showSelectPrompt = computed(() => {
|
const info = safeCurrentInfo.value;
|
return info.longitude === 0.0 && info.latitude === 0.0;
|
});
|
|
// 计算平均、最大、最小流速
|
const avgVelocity = computed(() => {
|
if (!myData.value.length) return '--';
|
const sum = myData.value.reduce((acc, cur) => acc + cur.velocity, 0);
|
return (sum / myData.value.length).toFixed(2);
|
});
|
const maxVelocity = computed(() => {
|
if (!myData.value.length) return '--';
|
return Math.max(...myData.value.map(d => d.velocity)).toFixed(2);
|
});
|
const minVelocity = computed(() => {
|
if (!myData.value.length) return '--';
|
return Math.min(...myData.value.map(d => d.velocity)).toFixed(2);
|
});
|
|
// 数据缓存
|
const myData = ref([]);
|
|
// 防抖函数
|
function debounce(func, wait) {
|
let timeout;
|
return function () {
|
const context = this;
|
const args = arguments;
|
clearTimeout(timeout);
|
timeout = setTimeout(() => {
|
func.apply(context, args);
|
}, wait);
|
};
|
}
|
|
// 时间格式化工具函数
|
function formatDateTime(date) {
|
const d = new Date(date);
|
const year = d.getFullYear();
|
const month = String(d.getMonth() + 1).padStart(2, '0'); // 月份从 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}`;
|
}
|
|
// 获取并更新图表
|
async function fetchDataAndUpdateChart(chart) {
|
const info = currentInfo.value;
|
if (!info || showSelectPrompt.value || !chartDom.value) return;
|
const { longitude, latitude, serviceInfo } = info;
|
localLoading.value = true;
|
const result = await getFlowRateInfo(longitude, latitude, serviceInfo);
|
if (result && Array.isArray(result)) {
|
myData.value = result;
|
const option = {
|
title: {
|
text: '流速变化趋势',
|
textStyle: {
|
color: '#fff',
|
fontSize: 16
|
},
|
left: '-1%'
|
},
|
tooltip: {
|
trigger: 'axis',
|
formatter: (params) => {
|
const dateStr = formatDateTime(params[0].value[0]);
|
return `${dateStr}<br/>流速:${params[0].value[1].toFixed(4)} m/s`;
|
},
|
backgroundColor: 'rgba(0,0,0,0.7)',
|
textStyle: {
|
color: '#fff',
|
fontSize: 14
|
}
|
},
|
xAxis: {
|
type: 'time',
|
name: '',
|
axisLabel: {
|
color: '#fff',
|
fontSize: 12,
|
formatter: function (value) {
|
const date = new Date(value);
|
const year = date.getFullYear();
|
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始
|
const day = String(date.getDate()).padStart(2, '0');
|
const hours = String(date.getHours()).padStart(2, '0');
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
return `${month}-${day} \n${hours}:${minutes}`;
|
},
|
interval: 'auto',
|
rotate: 45
|
},
|
nameTextStyle: {
|
color: '#fff',
|
fontSize: 14
|
}
|
},
|
yAxis: {
|
type: 'value',
|
name: '流速(m/s)',
|
min: 0,
|
max: Math.max(...result.map(i => i.velocity)) + 0.05,
|
axisLabel: {
|
color: '#fff',
|
fontSize: 12,
|
formatter: value => value.toFixed(2)
|
},
|
nameTextStyle: {
|
color: '#fff',
|
fontSize: 14
|
}
|
},
|
dataZoom: [
|
{
|
type: 'slider', // 滑块型缩放条
|
start: 0, // 初始显示从 0% 开始
|
end: 100, // 到 100%
|
height: 20, // 缩放条高度
|
bottom: 10, // 距离底部距离
|
borderColor: 'rgba(255,255,255,0.3)',
|
backgroundColor: 'rgba(50,50,50,0.3)',
|
fillerColor: 'rgba(70,130,180,0.6)',
|
textStyle: {
|
color: '#fff'
|
}
|
},
|
{
|
type: 'inside',
|
start: 0,
|
end: 100
|
}
|
],
|
series: [{
|
name: '流速',
|
type: 'line',
|
data: result.map(item => [new Date(item.time), item.velocity]),
|
showSymbol: true,
|
lineStyle: {
|
color: '#3268fe',
|
width: 2
|
},
|
itemStyle: {
|
color: '#3268fe'
|
},
|
smooth: false,
|
progressive: 0
|
}],
|
textStyle: {
|
color: '#fff',
|
fontSize: 14
|
},
|
animation: false
|
};
|
|
chart.setOption(option, true);
|
}
|
|
localLoading.value = false;
|
}
|
|
// 初始化图表
|
function initChart(chart) {
|
fetchDataAndUpdateChart(chart);
|
}
|
|
// 获取真实数据
|
function getFlowRateInfo(lon, lat, serviceInfo) {
|
const params = {
|
lon: lon,
|
lat: lat,
|
serviceName: serviceInfo
|
};
|
return getFlowRate(params).then(data => {
|
// console.log('获取到的数据:', data);
|
if (data && data.code === 200) {
|
return data.data; // 返回原始数据数组
|
} else {
|
return [];
|
}
|
}).catch(error => {
|
console.error('获取数据时发生错误:', error);
|
ElMessage.warning('数据有误,请联系管理员或重新进行模拟!');
|
return [];
|
});
|
}
|
|
// 监听 currentInfo 变化
|
watch(
|
() => currentInfo.value,
|
async (newVal) => {
|
if (!newVal || showSelectPrompt.value || !chartDom.value) return;
|
// 销毁旧图表
|
if (myChart) {
|
myChart.dispose();
|
}
|
// 创建新图表
|
myChart = echarts.init(chartDom.value);
|
await fetchDataAndUpdateChart(myChart);
|
},
|
{ deep: true }
|
);
|
|
onMounted(() => {
|
if (!showSelectPrompt.value && chartDom.value) {
|
myChart = echarts.init(chartDom.value);
|
initChart(myChart);
|
// 添加 resize 监听器
|
window.addEventListener('resize', debounce(() => {
|
if (myChart) myChart.resize();
|
}, 200));
|
}
|
// 注册事件总线监听
|
EventBus.on('clear-water-velocity', clear);
|
});
|
|
onBeforeUnmount(() => {
|
window.removeEventListener('resize', debounce(() => {
|
if (myChart) myChart.resize();
|
}, 200));
|
// 清理图表
|
if (myChart) {
|
myChart.dispose();
|
myChart = null;
|
}
|
// 移除事件监听
|
EventBus.off('clear-water-velocity', clear);
|
});
|
|
// 清空方法
|
function clear() {
|
// 清空 store 中的经纬度信息
|
currentInfo.value.longitude = 0.0;
|
currentInfo.value.latitude = 0.0;
|
|
// 清除 ECharts 图表
|
if (myChart) {
|
myChart.clear(); // 清除图表数据和图形
|
myChart.dispose(); // 销毁实例,释放资源
|
myChart = null;
|
}
|
}
|
// 暴露 resize 方法供外部调用
|
function resizeChart() {
|
if (myChart) {
|
myChart.resize();
|
}
|
}
|
defineExpose({ resizeChart });
|
</script>
|
|
<style scoped>
|
.water-velocity-content {
|
position: relative;
|
padding-left: 8px;
|
padding-top: 8px;
|
border-radius: 6px;
|
}
|
|
.chart-placeholder {
|
margin-top: 10px;
|
}
|
|
.location-info,
|
.velocity-info {
|
margin-bottom: 10px;
|
}
|
|
.coordinates {
|
font-size: 15px;
|
color: #fff;
|
user-select: all;
|
display: inline-block;
|
border-radius: 4px;
|
transition: background-color 0.2s ease;
|
}
|
|
.velocity-info p {
|
font-size: 14px;
|
color: #fff;
|
}
|
|
.velocity-info strong {
|
color: #fff;
|
margin: 0 4px;
|
}
|
</style>
|