2025-09-29 23:53:09 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="parameter-record-page">
|
|
|
|
|
|
<!-- 固定头部 -->
|
|
|
|
|
|
<view class="fixed-header">
|
|
|
|
|
|
<text class="header-title">移动式检修车间</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 内容区域 -->
|
|
|
|
|
|
<view class="tabbar-content">
|
2025-10-06 15:06:48 +08:00
|
|
|
|
<!-- 日期导航器 -->
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="date-selector">
|
2025-10-06 15:06:48 +08:00
|
|
|
|
<view class="date-navigation">
|
|
|
|
|
|
<button class="nav-button prev-button" @click="goToPreviousDay">
|
|
|
|
|
|
<!-- <text class="nav-icon">‹</text> -->
|
|
|
|
|
|
<text class="nav-text">上一天</text>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<view class="current-date">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<text class="date-text">{{ selectedDate }}</text>
|
2025-10-06 15:06:48 +08:00
|
|
|
|
<!-- <text class="date-weekday">{{ getWeekday(selectedDate) }}</text> -->
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
2025-10-06 15:06:48 +08:00
|
|
|
|
<button class="nav-button next-button" @click="goToNextDay">
|
|
|
|
|
|
<text class="nav-text">下一天</text>
|
|
|
|
|
|
<!-- <text class="nav-icon">›</text> -->
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</view>
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 温度趋势图表 -->
|
|
|
|
|
|
<view class="chart-card">
|
|
|
|
|
|
<view class="chart-header">
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<text class="chart-title">温度趋势 (WD)</text>
|
|
|
|
|
|
<!-- <view class="status-indicator">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="status-dot temperature-dot"></view>
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<text class="status-text">{{ chartData.temperature.length > 0 ? '有数据' : '无数据' }}</text>
|
|
|
|
|
|
</view> -->
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="chart-container">
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<e-chart ref="temperatureChartRef" @ready="initTemperatureChart" :height="400" />
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 湿度趋势图表 -->
|
|
|
|
|
|
<view class="chart-card">
|
|
|
|
|
|
<view class="chart-header">
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<text class="chart-title">湿度趋势 (SD)</text>
|
|
|
|
|
|
<!-- <view class="status-indicator">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="status-dot humidity-dot"></view>
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<text class="status-text">{{ chartData.humidity.length > 0 ? '有数据' : '无数据' }}</text>
|
|
|
|
|
|
</view> -->
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="chart-container">
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<e-chart ref="humidityChartRef" @ready="initHumidityChart" :height="400" />
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- PM2.5趋势图表 -->
|
|
|
|
|
|
<view class="chart-card">
|
|
|
|
|
|
<view class="chart-header">
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<text class="chart-title">PM趋势 (PM)</text>
|
|
|
|
|
|
<!-- <view class="status-indicator">
|
2025-09-29 23:53:09 +08:00
|
|
|
|
<view class="status-dot pm25-dot"></view>
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<text class="status-text">{{ chartData.pm.length > 0 ? '有数据' : '无数据' }}</text>
|
|
|
|
|
|
</view> -->
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view class="chart-container">
|
2025-10-01 02:42:22 +08:00
|
|
|
|
<e-chart ref="pm25ChartRef" @ready="initPM25Chart" :height="400" />
|
2025-09-29 23:53:09 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import mqttDataManager from '@/utils/mqttDataManager.js'
|
2025-10-01 04:07:37 +08:00
|
|
|
|
import { dataHistoryApi, eventApi } from '@/utils/api.js'
|
2025-10-01 02:42:22 +08:00
|
|
|
|
import EChart from '@/uni_modules/e-chart/components/e-chart/e-chart.vue'
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
components: {
|
|
|
|
|
|
EChart
|
|
|
|
|
|
},
|
2025-09-29 23:53:09 +08:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
selectedDate: this.getTodayDate(), // 默认选择今天
|
2025-09-29 23:53:09 +08:00
|
|
|
|
// 24小时数据 (0-23点)
|
|
|
|
|
|
temperatureData: [22, 25, 28, 32, 35, 38, 40, 38, 35, 32, 28, 25, 22, 20, 18, 20, 22, 25, 28, 30, 32, 30, 28, 25],
|
|
|
|
|
|
humidityData: [45, 50, 55, 60, 65, 70, 75, 70, 65, 60, 55, 50, 45, 40, 35, 40, 45, 50, 55, 60, 65, 60, 55, 50],
|
|
|
|
|
|
pm25Data: [15, 18, 22, 25, 28, 32, 35, 32, 28, 25, 22, 18, 15, 12, 10, 12, 15, 18, 22, 25, 28, 25, 22, 18],
|
|
|
|
|
|
connectionStatus: {
|
|
|
|
|
|
isConnected: false,
|
|
|
|
|
|
lastUpdate: null
|
2025-10-01 02:42:22 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 历史数据
|
|
|
|
|
|
historyData: [],
|
|
|
|
|
|
// 处理后的图表数据
|
|
|
|
|
|
chartData: {
|
|
|
|
|
|
temperature: [],
|
|
|
|
|
|
humidity: [],
|
|
|
|
|
|
pm: []
|
|
|
|
|
|
},
|
|
|
|
|
|
// 数据状态
|
|
|
|
|
|
dataStatus: {
|
|
|
|
|
|
isRealData: false,
|
|
|
|
|
|
lastUpdateTime: null,
|
|
|
|
|
|
dataSource: 'empty' // 'api' | 'empty' | 'error'
|
|
|
|
|
|
},
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 页面初始化状态
|
|
|
|
|
|
hasInitialized: false,
|
2025-10-06 15:06:48 +08:00
|
|
|
|
// 查询模式:'default' 表示过去24小时,'date' 表示按日期查询
|
|
|
|
|
|
queryMode: 'default',
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// ECharts配置选项
|
|
|
|
|
|
temperatureOption: {
|
|
|
|
|
|
title: {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
text: '',
|
2025-10-01 02:42:22 +08:00
|
|
|
|
left: 'center',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
|
color: '#333'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const data = params[0];
|
2025-10-06 15:06:48 +08:00
|
|
|
|
return `时间: ${data.axisValue} 温度: ${data.value}°C`;
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '3%',
|
|
|
|
|
|
right: '4%',
|
|
|
|
|
|
bottom: '3%',
|
|
|
|
|
|
containLabel: true
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
2025-10-06 15:06:48 +08:00
|
|
|
|
data: this.generateXAxisLabels(),
|
2025-10-01 02:42:22 +08:00
|
|
|
|
axisLabel: {
|
|
|
|
|
|
interval: 3, // 每4个小时显示一个标签
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '温度(°C)',
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
max: 100,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
formatter: '{value}°C',
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '温度',
|
|
|
|
|
|
type: 'line',
|
|
|
|
|
|
data: [],
|
|
|
|
|
|
smooth: true,
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#ff6b35',
|
|
|
|
|
|
width: 3
|
|
|
|
|
|
},
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: '#ff6b35'
|
|
|
|
|
|
},
|
|
|
|
|
|
areaStyle: {
|
|
|
|
|
|
color: {
|
|
|
|
|
|
type: 'linear',
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
x2: 0,
|
|
|
|
|
|
y2: 1,
|
|
|
|
|
|
colorStops: [{
|
|
|
|
|
|
offset: 0, color: 'rgba(255, 107, 53, 0.3)'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 1, color: 'rgba(255, 107, 53, 0.1)'
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}]
|
|
|
|
|
|
},
|
|
|
|
|
|
humidityOption: {
|
|
|
|
|
|
title: {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
text: '',
|
2025-10-01 02:42:22 +08:00
|
|
|
|
left: 'center',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
|
color: '#333'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const data = params[0];
|
2025-10-06 15:06:48 +08:00
|
|
|
|
return `时间: ${data.axisValue} 湿度: ${data.value}%`;
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '3%',
|
|
|
|
|
|
right: '4%',
|
|
|
|
|
|
bottom: '3%',
|
|
|
|
|
|
containLabel: true
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
2025-10-06 15:06:48 +08:00
|
|
|
|
data: this.generateXAxisLabels(),
|
2025-10-01 02:42:22 +08:00
|
|
|
|
axisLabel: {
|
|
|
|
|
|
interval: 3,
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '湿度(%)',
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
max: 100,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
formatter: '{value}%',
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: '湿度',
|
|
|
|
|
|
type: 'line',
|
|
|
|
|
|
data: [],
|
|
|
|
|
|
smooth: true,
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#4a90e2',
|
|
|
|
|
|
width: 3
|
|
|
|
|
|
},
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: '#4a90e2'
|
|
|
|
|
|
},
|
|
|
|
|
|
areaStyle: {
|
|
|
|
|
|
color: {
|
|
|
|
|
|
type: 'linear',
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
x2: 0,
|
|
|
|
|
|
y2: 1,
|
|
|
|
|
|
colorStops: [{
|
|
|
|
|
|
offset: 0, color: 'rgba(74, 144, 226, 0.3)'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 1, color: 'rgba(74, 144, 226, 0.1)'
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}]
|
|
|
|
|
|
},
|
|
|
|
|
|
pm25Option: {
|
|
|
|
|
|
title: {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
text: '',
|
2025-10-01 02:42:22 +08:00
|
|
|
|
left: 'center',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
|
color: '#333'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const data = params[0];
|
2025-10-06 15:06:48 +08:00
|
|
|
|
return `时间: ${data.axisValue} PM2.5: ${data.value}μg/m³`;
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '3%',
|
|
|
|
|
|
right: '4%',
|
|
|
|
|
|
bottom: '3%',
|
|
|
|
|
|
containLabel: true
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
2025-10-06 15:06:48 +08:00
|
|
|
|
data: this.generateXAxisLabels(),
|
2025-10-01 02:42:22 +08:00
|
|
|
|
axisLabel: {
|
|
|
|
|
|
interval: 3,
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: 'PM2.5(μg/m³)',
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
max: 100,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
formatter: '{value}μg/m³',
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
name: 'PM2.5',
|
|
|
|
|
|
type: 'line',
|
|
|
|
|
|
data: [],
|
|
|
|
|
|
smooth: true,
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: '#7ed321',
|
|
|
|
|
|
width: 3
|
|
|
|
|
|
},
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: '#7ed321'
|
|
|
|
|
|
},
|
|
|
|
|
|
areaStyle: {
|
|
|
|
|
|
color: {
|
|
|
|
|
|
type: 'linear',
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
x2: 0,
|
|
|
|
|
|
y2: 1,
|
|
|
|
|
|
colorStops: [{
|
|
|
|
|
|
offset: 0, color: 'rgba(126, 211, 33, 0.3)'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 1, color: 'rgba(126, 211, 33, 0.1)'
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}]
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
onLoad() {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
console.log('参数记录页面加载', new Date().toISOString().split('T')[0])
|
2025-09-29 23:53:09 +08:00
|
|
|
|
this.initMqttListener()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 调用历史数据接口
|
|
|
|
|
|
this.getHistoryData()
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
2025-10-01 04:07:37 +08:00
|
|
|
|
onShow() {
|
|
|
|
|
|
console.log('📱 参数记录页面显示,触发页面更新')
|
|
|
|
|
|
// 只有在非首次显示时才重新获取历史数据
|
|
|
|
|
|
// 首次显示时已经在onLoad中获取过了
|
|
|
|
|
|
if (this.hasInitialized) {
|
|
|
|
|
|
this.getHistoryData()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.hasInitialized = true
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-09-29 23:53:09 +08:00
|
|
|
|
onUnload() {
|
|
|
|
|
|
// 页面卸载时移除监听器
|
|
|
|
|
|
if (this.dataUpdateHandler) {
|
|
|
|
|
|
mqttDataManager.removeListener('dataUpdate', this.dataUpdateHandler)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.statusUpdateHandler) {
|
|
|
|
|
|
mqttDataManager.removeListener('connectionStatus', this.statusUpdateHandler)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
// 生成x轴标签
|
|
|
|
|
|
generateXAxisLabels() {
|
|
|
|
|
|
if (this.queryMode === 'date') {
|
|
|
|
|
|
// 按日期查询时,显示0-23小时
|
|
|
|
|
|
return Array.from({length: 24}, (_, i) => `${i.toString().padStart(2, '0')}:00`)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 默认查询时,显示当前时间之前24小时(整点时间)
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
const currentHour = now.getHours()
|
|
|
|
|
|
const labels = []
|
|
|
|
|
|
for (let i = 23; i >= 0; i--) {
|
|
|
|
|
|
// 计算目标小时
|
|
|
|
|
|
let targetHour = currentHour - i
|
|
|
|
|
|
if (targetHour < 0) {
|
|
|
|
|
|
targetHour += 24 // 跨天处理
|
|
|
|
|
|
}
|
|
|
|
|
|
labels.push(`${String(targetHour).padStart(2, '0')}:00`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return labels
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 获取今天的日期(本地时区)
|
|
|
|
|
|
getTodayDate() {
|
|
|
|
|
|
const today = new Date()
|
|
|
|
|
|
const year = today.getFullYear()
|
|
|
|
|
|
const month = String(today.getMonth() + 1).padStart(2, '0')
|
|
|
|
|
|
const day = String(today.getDate()).padStart(2, '0')
|
2025-10-06 15:06:48 +08:00
|
|
|
|
|
|
|
|
|
|
console.log('📅 获取今天日期:', {
|
|
|
|
|
|
'原始Date对象': today,
|
|
|
|
|
|
'ISO字符串': today.toISOString(),
|
|
|
|
|
|
'本地字符串': today.toLocaleString(),
|
|
|
|
|
|
'本地日期字符串': today.toLocaleDateString(),
|
|
|
|
|
|
'本地时间字符串': today.toLocaleTimeString(),
|
|
|
|
|
|
'时区偏移': today.getTimezoneOffset(),
|
|
|
|
|
|
'格式化结果': `${year}-${month}-${day}`
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
return `${year}-${month}-${day}`
|
|
|
|
|
|
},
|
2025-10-06 15:06:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 格式化日期为 YYYY-MM-DD 格式
|
|
|
|
|
|
formatDate(date) {
|
|
|
|
|
|
const year = date.getFullYear()
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
|
|
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
|
|
|
|
return `${year}-${month}-${day}`
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取星期几
|
|
|
|
|
|
getWeekday(dateString) {
|
|
|
|
|
|
const date = new Date(dateString)
|
|
|
|
|
|
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
|
|
|
|
|
return weekdays[date.getDay()]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取时间范围显示文本
|
|
|
|
|
|
getTimeRangeText() {
|
|
|
|
|
|
if (this.queryMode === 'date') {
|
|
|
|
|
|
return `查询日期: ${this.selectedDate}`
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
const past24Hours = new Date(now.getTime() - 24 * 60 * 60 * 1000)
|
|
|
|
|
|
const startTime = this.formatTimeDisplay(past24Hours)
|
|
|
|
|
|
const endTime = this.formatTimeDisplay(now)
|
|
|
|
|
|
return `过去24小时: ${startTime} ~ ${endTime}`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化时间显示(用于界面显示)
|
|
|
|
|
|
formatTimeDisplay(date) {
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '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')
|
|
|
|
|
|
return `${month}-${day} ${hours}:${minutes}`
|
|
|
|
|
|
},
|
2025-09-29 23:53:09 +08:00
|
|
|
|
// 初始化MQTT监听
|
|
|
|
|
|
initMqttListener() {
|
|
|
|
|
|
// 监听数据更新
|
|
|
|
|
|
this.dataUpdateHandler = (data) => {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// this.updateChartData(data)
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
mqttDataManager.addListener('dataUpdate', this.dataUpdateHandler)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听连接状态
|
|
|
|
|
|
this.statusUpdateHandler = (status) => {
|
|
|
|
|
|
this.connectionStatus = status
|
|
|
|
|
|
}
|
|
|
|
|
|
mqttDataManager.addListener('connectionStatus', this.statusUpdateHandler)
|
|
|
|
|
|
|
|
|
|
|
|
// 获取初始连接状态
|
|
|
|
|
|
this.connectionStatus = mqttDataManager.getConnectionStatus()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 更新图表数据
|
|
|
|
|
|
updateChartData(data) {
|
|
|
|
|
|
|
|
|
|
|
|
// 只处理WSD设备的数据
|
|
|
|
|
|
if (data.deviceType === 'WSD') {
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
const currentHour = now.getHours()
|
2025-10-06 15:06:48 +08:00
|
|
|
|
const currentMinute = now.getMinutes()
|
|
|
|
|
|
const currentTimeInHours = currentHour + currentMinute / 60
|
|
|
|
|
|
|
|
|
|
|
|
// 计算数据在数组中的索引位置
|
|
|
|
|
|
let dataIndex
|
|
|
|
|
|
if (this.queryMode === 'date') {
|
|
|
|
|
|
// 按日期查询时,直接使用当前小时
|
|
|
|
|
|
dataIndex = currentHour
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 默认查询时,当前时间对应索引0(最新数据)
|
|
|
|
|
|
dataIndex = 0
|
|
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
// 更新对应位置的数据
|
2025-09-29 23:53:09 +08:00
|
|
|
|
if (data.temperature !== undefined) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
Math.round(data.temperature) && (this.temperatureData[dataIndex] = Math.round(data.temperature))
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (data.humidity !== undefined) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
Math.round(data.humidity) && (this.humidityData[dataIndex] = Math.round(data.humidity))
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
2025-10-01 02:42:22 +08:00
|
|
|
|
if (data.pm !== undefined) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
Math.round(data.pm) && (this.pm25Data[dataIndex] = Math.round(data.pm))
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 重新绘制图表
|
|
|
|
|
|
this.$nextTick(() => {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.updateCharts()
|
2025-09-29 23:53:09 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ 图表数据更新完成:', {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
temperature: this.temperatureData[dataIndex],
|
|
|
|
|
|
humidity: this.humidityData[dataIndex],
|
|
|
|
|
|
dataIndex: dataIndex
|
2025-09-29 23:53:09 +08:00
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.log('⚠️ 非WSD设备数据,跳过图表更新:', data.deviceType)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 图表初始化方法
|
|
|
|
|
|
initTemperatureChart() {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.temperatureOption.xAxis.data = this.generateXAxisLabels()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.temperatureOption.series[0].data = this.temperatureData
|
|
|
|
|
|
this.$refs.temperatureChartRef.init(this.temperatureOption)
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
initHumidityChart() {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.humidityOption.xAxis.data = this.generateXAxisLabels()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.humidityOption.series[0].data = this.humidityData
|
|
|
|
|
|
this.$refs.humidityChartRef.init(this.humidityOption)
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
initPM25Chart() {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.pm25Option.xAxis.data = this.generateXAxisLabels()
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.pm25Option.series[0].data = this.pm25Data
|
|
|
|
|
|
this.$refs.pm25ChartRef.init(this.pm25Option)
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
// 上一天
|
|
|
|
|
|
goToPreviousDay() {
|
|
|
|
|
|
const currentDate = new Date(this.selectedDate)
|
|
|
|
|
|
currentDate.setDate(currentDate.getDate() - 1)
|
|
|
|
|
|
this.selectedDate = this.formatDate(currentDate)
|
|
|
|
|
|
this.queryMode = 'date' // 切换到按日期查询模式
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
|
title: '加载数据中...'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取历史数据
|
|
|
|
|
|
this.getHistoryDataByDate().finally(() => {
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 下一天
|
|
|
|
|
|
goToNextDay() {
|
|
|
|
|
|
const currentDate = new Date(this.selectedDate)
|
|
|
|
|
|
const today = new Date()
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已经是今天,如果是则不允许继续往后
|
|
|
|
|
|
if (this.selectedDate >= this.formatDate(today)) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '不能查看未来日期',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 2000
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
currentDate.setDate(currentDate.getDate() + 1)
|
|
|
|
|
|
this.selectedDate = this.formatDate(currentDate)
|
|
|
|
|
|
this.queryMode = 'date' // 切换到按日期查询模式
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
uni.showLoading({
|
|
|
|
|
|
title: '加载数据中...'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取历史数据
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.getHistoryDataByDate().finally(() => {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
uni.hideLoading()
|
2025-09-29 23:53:09 +08:00
|
|
|
|
})
|
|
|
|
|
|
},
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新图表数据
|
|
|
|
|
|
updateCharts() {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
const xAxisLabels = this.generateXAxisLabels()
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
if (this.$refs.temperatureChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.temperatureOption.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.temperatureOption.series[0].data = this.temperatureData
|
|
|
|
|
|
this.$refs.temperatureChartRef.setOption(this.temperatureOption)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.$refs.humidityChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.humidityOption.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.humidityOption.series[0].data = this.humidityData
|
|
|
|
|
|
this.$refs.humidityChartRef.setOption(this.humidityOption)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.$refs.pm25ChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.pm25Option.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.pm25Option.series[0].data = this.pm25Data
|
|
|
|
|
|
this.$refs.pm25ChartRef.setOption(this.pm25Option)
|
|
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
// 根据选择的日期获取历史数据
|
|
|
|
|
|
async getHistoryDataByDate() {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
try {
|
|
|
|
|
|
// 根据选择的日期构建时间范围
|
|
|
|
|
|
const startTime = `${this.selectedDate} 00:00:00`
|
|
|
|
|
|
const endTime = `${this.selectedDate} 23:59:59`
|
|
|
|
|
|
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
startTime: startTime,
|
|
|
|
|
|
endTime: endTime
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
const response = await dataHistoryApi.getHistory(params)
|
|
|
|
|
|
|
|
|
|
|
|
// 处理历史数据
|
|
|
|
|
|
if (response && Array.isArray(response) && response.length > 0) {
|
|
|
|
|
|
this.historyData = response
|
|
|
|
|
|
this.processHistoryData(response)
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据状态
|
|
|
|
|
|
this.dataStatus = {
|
|
|
|
|
|
isRealData: true,
|
|
|
|
|
|
lastUpdateTime: new Date().toLocaleString(),
|
|
|
|
|
|
dataSource: 'api'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存查询事件
|
|
|
|
|
|
await this.createQueryEvent('success', response.length)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.log('📊 没有历史数据,显示空状态')
|
|
|
|
|
|
// 没有数据时显示空状态
|
|
|
|
|
|
this.showEmptyState()
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据状态
|
|
|
|
|
|
this.dataStatus = {
|
|
|
|
|
|
isRealData: false,
|
|
|
|
|
|
lastUpdateTime: new Date().toLocaleString(),
|
|
|
|
|
|
dataSource: 'empty'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存查询事件(无数据)
|
|
|
|
|
|
await this.createQueryEvent('empty', 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('❌ 历史数据获取失败:', error)
|
|
|
|
|
|
// 出错时显示空状态
|
|
|
|
|
|
this.showEmptyState()
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据状态
|
|
|
|
|
|
this.dataStatus = {
|
|
|
|
|
|
isRealData: false,
|
|
|
|
|
|
lastUpdateTime: new Date().toLocaleString(),
|
|
|
|
|
|
dataSource: 'error'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存查询事件(错误)
|
|
|
|
|
|
await this.createQueryEvent('error', 0)
|
|
|
|
|
|
|
|
|
|
|
|
// 显示错误提示
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '数据加载失败',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 2000
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取历史数据(默认过去24小时)
|
|
|
|
|
|
async getHistoryData() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 构建时间范围:从当前时间开始过去24小时
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
const past24Hours = new Date(now.getTime() - 24 * 60 * 60 * 1000) // 24小时前
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化时间字符串
|
|
|
|
|
|
const startTime = this.formatDateTimeString(past24Hours)
|
|
|
|
|
|
const endTime = this.formatDateTimeString(now)
|
|
|
|
|
|
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
startTime: startTime,
|
|
|
|
|
|
endTime: endTime
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('📊 请求历史数据(过去24小时):', params)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
const response = await dataHistoryApi.getHistory(params)
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ 历史数据获取成功:', response)
|
|
|
|
|
|
|
|
|
|
|
|
// 处理历史数据
|
|
|
|
|
|
if (response && Array.isArray(response) && response.length > 0) {
|
|
|
|
|
|
this.historyData = response
|
|
|
|
|
|
this.processHistoryData(response)
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据状态
|
|
|
|
|
|
this.dataStatus = {
|
|
|
|
|
|
isRealData: true,
|
|
|
|
|
|
lastUpdateTime: new Date().toLocaleString(),
|
|
|
|
|
|
dataSource: 'api'
|
|
|
|
|
|
}
|
2025-10-01 04:07:37 +08:00
|
|
|
|
|
|
|
|
|
|
// 保存查询事件
|
|
|
|
|
|
await this.createQueryEvent('success', response.length)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
console.log('📊 没有历史数据,显示空状态')
|
|
|
|
|
|
// 没有数据时显示空状态
|
|
|
|
|
|
this.showEmptyState()
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据状态
|
|
|
|
|
|
this.dataStatus = {
|
|
|
|
|
|
isRealData: false,
|
|
|
|
|
|
lastUpdateTime: new Date().toLocaleString(),
|
|
|
|
|
|
dataSource: 'empty'
|
|
|
|
|
|
}
|
2025-10-01 04:07:37 +08:00
|
|
|
|
|
|
|
|
|
|
// 保存查询事件(无数据)
|
|
|
|
|
|
await this.createQueryEvent('empty', 0)
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('❌ 历史数据获取失败:', error)
|
|
|
|
|
|
// 出错时显示空状态
|
|
|
|
|
|
this.showEmptyState()
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据状态
|
|
|
|
|
|
this.dataStatus = {
|
|
|
|
|
|
isRealData: false,
|
|
|
|
|
|
lastUpdateTime: new Date().toLocaleString(),
|
|
|
|
|
|
dataSource: 'error'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 04:07:37 +08:00
|
|
|
|
// 保存查询事件(错误)
|
|
|
|
|
|
await this.createQueryEvent('error', 0)
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 显示错误提示
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '数据加载失败',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 2000
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
},
|
2025-10-01 02:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
// 使用默认数据
|
|
|
|
|
|
useDefaultData() {
|
|
|
|
|
|
console.log('🎨 使用默认数据展示图表')
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 使用预设的示例数据
|
|
|
|
|
|
this.temperatureData = [22, 25, 28, 32, 35, 38, 40, 38, 35, 32, 28, 25, 22, 20, 18, 20, 22, 25, 28, 30, 32, 30, 28, 25]
|
|
|
|
|
|
this.humidityData = [45, 50, 55, 60, 65, 70, 75, 70, 65, 60, 55, 50, 45, 40, 35, 40, 45, 50, 55, 60, 65, 60, 55, 50]
|
|
|
|
|
|
this.pm25Data = [15, 18, 22, 25, 28, 32, 35, 32, 28, 25, 22, 18, 15, 12, 10, 12, 15, 18, 22, 25, 28, 25, 22, 18]
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 更新数据状态
|
|
|
|
|
|
this.dataStatus = {
|
|
|
|
|
|
isRealData: false,
|
|
|
|
|
|
lastUpdateTime: new Date().toLocaleString(),
|
|
|
|
|
|
dataSource: 'default'
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 更新图表
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
this.updateCharts()
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 显示空状态
|
|
|
|
|
|
showEmptyState() {
|
|
|
|
|
|
console.log('🎨 显示空状态,默认值为0')
|
|
|
|
|
|
|
|
|
|
|
|
// 设置默认数据为0
|
|
|
|
|
|
this.temperatureData = new Array(24).fill(0)
|
|
|
|
|
|
this.humidityData = new Array(24).fill(0)
|
|
|
|
|
|
this.pm25Data = new Array(24).fill(0)
|
|
|
|
|
|
|
|
|
|
|
|
// 更新图表
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
this.updateCharts()
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
processHistoryData(data) {
|
|
|
|
|
|
console.log('🔄 开始处理历史数据:', data.length, '条记录')
|
|
|
|
|
|
console.log('📊 原始数据示例:', data[0])
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化图表数据
|
|
|
|
|
|
this.chartData = {
|
|
|
|
|
|
temperature: [],
|
|
|
|
|
|
humidity: [],
|
|
|
|
|
|
pm: []
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 按时间排序
|
|
|
|
|
|
const sortedData = data.sort((a, b) => {
|
|
|
|
|
|
const timeA = new Date(a.createTime || a.timestamp || a.time)
|
|
|
|
|
|
const timeB = new Date(b.createTime || b.timestamp || b.time)
|
|
|
|
|
|
return timeA - timeB
|
|
|
|
|
|
})
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 处理每条数据
|
|
|
|
|
|
sortedData.forEach(item => {
|
|
|
|
|
|
const time = new Date(item.createTime || item.timestamp || item.time)
|
|
|
|
|
|
const hour = time.getHours()
|
|
|
|
|
|
const minute = time.getMinutes()
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
// 计算在24小时数组中的索引位置
|
|
|
|
|
|
let dataIndex
|
|
|
|
|
|
if (this.queryMode === 'date') {
|
|
|
|
|
|
// 按日期查询时,直接使用小时作为索引
|
|
|
|
|
|
dataIndex = hour
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 默认查询时,需要计算相对于当前时间的位置(按小时计算)
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
const currentHour = now.getHours()
|
|
|
|
|
|
|
|
|
|
|
|
// 计算时间差(小时)
|
|
|
|
|
|
let timeDiff = currentHour - hour
|
|
|
|
|
|
if (timeDiff < 0) {
|
|
|
|
|
|
timeDiff += 24 // 跨天的情况
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为数组索引(23表示24小时前,0表示当前时间)
|
|
|
|
|
|
dataIndex = 23 - timeDiff
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (dataIndex < 0 || dataIndex >= 24) {
|
|
|
|
|
|
console.log(`⚠️ 数据超出范围,跳过 - 索引:${dataIndex}`)
|
|
|
|
|
|
return // 超出范围的数据跳过
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 处理温度数据 (wd是温度)
|
|
|
|
|
|
const temperature = item.wd || item.temperature || item.temp || item.T
|
|
|
|
|
|
if (temperature !== undefined && temperature !== null && temperature >= 0) {
|
|
|
|
|
|
this.chartData.temperature.push({
|
2025-10-06 15:06:48 +08:00
|
|
|
|
time: dataIndex,
|
2025-10-01 02:42:22 +08:00
|
|
|
|
value: Number(temperature),
|
|
|
|
|
|
timestamp: item.createTime || item.timestamp || item.time
|
|
|
|
|
|
})
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 处理湿度数据 (sd是湿度)
|
|
|
|
|
|
const humidity = item.sd || item.humidity || item.hum || item.H
|
|
|
|
|
|
if (humidity !== undefined && humidity !== null && humidity >= 0) {
|
|
|
|
|
|
this.chartData.humidity.push({
|
2025-10-06 15:06:48 +08:00
|
|
|
|
time: dataIndex,
|
2025-10-01 02:42:22 +08:00
|
|
|
|
value: Number(humidity),
|
|
|
|
|
|
timestamp: item.createTime || item.timestamp || item.time
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理PM数据 (支持多种字段名)
|
|
|
|
|
|
const pm = item.pm || item.pm25 || item.pm2_5 || item.PM
|
|
|
|
|
|
if (pm !== undefined && pm !== null && pm >= 0) {
|
|
|
|
|
|
this.chartData.pm.push({
|
2025-10-06 15:06:48 +08:00
|
|
|
|
time: dataIndex,
|
2025-10-01 02:42:22 +08:00
|
|
|
|
value: Number(pm),
|
|
|
|
|
|
timestamp: item.createTime || item.timestamp || item.time
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
console.log('📈 处理后的图表数据:', {
|
|
|
|
|
|
temperature: this.chartData.temperature.length,
|
|
|
|
|
|
humidity: this.chartData.humidity.length,
|
|
|
|
|
|
pm: this.chartData.pm.length
|
|
|
|
|
|
})
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 重新绘制图表
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
this.updateChartsWithHistoryData()
|
2025-09-29 23:53:09 +08:00
|
|
|
|
})
|
2025-10-01 02:42:22 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 使用历史数据更新图表
|
|
|
|
|
|
updateChartsWithHistoryData() {
|
|
|
|
|
|
console.log('🎨 使用历史数据更新图表')
|
|
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
const xAxisLabels = this.generateXAxisLabels()
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 处理温度数据
|
|
|
|
|
|
if (this.chartData.temperature.length > 0) {
|
|
|
|
|
|
const temperatureData = new Array(24).fill(0)
|
|
|
|
|
|
this.chartData.temperature.forEach(item => {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
const dataIndex = Math.floor(item.time)
|
|
|
|
|
|
if (dataIndex >= 0 && dataIndex < 24) {
|
|
|
|
|
|
temperatureData[dataIndex] = item.value || 0
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
this.temperatureData = temperatureData
|
|
|
|
|
|
if (this.$refs.temperatureChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.temperatureOption.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.temperatureOption.series[0].data = temperatureData
|
|
|
|
|
|
this.$refs.temperatureChartRef.setOption(this.temperatureOption)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 没有温度数据时,使用0填充
|
|
|
|
|
|
this.temperatureData = new Array(24).fill(0)
|
|
|
|
|
|
if (this.$refs.temperatureChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.temperatureOption.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.temperatureOption.series[0].data = this.temperatureData
|
|
|
|
|
|
this.$refs.temperatureChartRef.setOption(this.temperatureOption)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 处理湿度数据
|
|
|
|
|
|
if (this.chartData.humidity.length > 0) {
|
|
|
|
|
|
const humidityData = new Array(24).fill(0)
|
|
|
|
|
|
this.chartData.humidity.forEach(item => {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
const dataIndex = Math.floor(item.time)
|
|
|
|
|
|
if (dataIndex >= 0 && dataIndex < 24) {
|
|
|
|
|
|
humidityData[dataIndex] = item.value || 0
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
this.humidityData = humidityData
|
|
|
|
|
|
if (this.$refs.humidityChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.humidityOption.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.humidityOption.series[0].data = humidityData
|
|
|
|
|
|
this.$refs.humidityChartRef.setOption(this.humidityOption)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 没有湿度数据时,使用0填充
|
|
|
|
|
|
this.humidityData = new Array(24).fill(0)
|
|
|
|
|
|
if (this.$refs.humidityChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.humidityOption.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.humidityOption.series[0].data = this.humidityData
|
|
|
|
|
|
this.$refs.humidityChartRef.setOption(this.humidityOption)
|
|
|
|
|
|
}
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
// 处理PM数据
|
|
|
|
|
|
if (this.chartData.pm.length > 0) {
|
|
|
|
|
|
const pmData = new Array(24).fill(0)
|
|
|
|
|
|
this.chartData.pm.forEach(item => {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
const dataIndex = Math.floor(item.time)
|
|
|
|
|
|
if (dataIndex >= 0 && dataIndex < 24) {
|
|
|
|
|
|
pmData[dataIndex] = item.value || 0
|
2025-10-01 02:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
this.pm25Data = pmData
|
|
|
|
|
|
if (this.$refs.pm25ChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.pm25Option.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.pm25Option.series[0].data = pmData
|
|
|
|
|
|
this.$refs.pm25ChartRef.setOption(this.pm25Option)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 没有PM数据时,使用0填充
|
|
|
|
|
|
this.pm25Data = new Array(24).fill(0)
|
|
|
|
|
|
if (this.$refs.pm25ChartRef) {
|
2025-10-06 15:06:48 +08:00
|
|
|
|
this.pm25Option.xAxis.data = xAxisLabels
|
2025-10-01 02:42:22 +08:00
|
|
|
|
this.pm25Option.series[0].data = this.pm25Data
|
|
|
|
|
|
this.$refs.pm25ChartRef.setOption(this.pm25Option)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-01 04:07:37 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 创建查询事件
|
|
|
|
|
|
async createQueryEvent(status, dataCount) {
|
2025-10-10 10:58:43 +08:00
|
|
|
|
// try {
|
|
|
|
|
|
// const currentTime = this.formatDateTime(new Date())
|
|
|
|
|
|
// const queryEvent = {
|
|
|
|
|
|
// eventType: "参数记录查询",
|
|
|
|
|
|
// eventTime: currentTime,
|
|
|
|
|
|
// status: this.getEventStatus(status),
|
|
|
|
|
|
// description: this.getEventDescription(status, dataCount),
|
|
|
|
|
|
// deviceId: "PARAMETER_QUERY_001"
|
|
|
|
|
|
// }
|
2025-10-01 04:07:37 +08:00
|
|
|
|
|
2025-10-10 10:58:43 +08:00
|
|
|
|
// console.log('📤 提交查询事件:', queryEvent)
|
|
|
|
|
|
// const response = await eventApi.create(queryEvent)
|
|
|
|
|
|
// console.log('✅ 查询事件创建成功:', response)
|
2025-10-01 04:07:37 +08:00
|
|
|
|
|
2025-10-10 10:58:43 +08:00
|
|
|
|
// } catch (error) {
|
|
|
|
|
|
// console.error('❌ 查询事件创建失败:', error)
|
|
|
|
|
|
// }
|
2025-10-01 04:07:37 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取事件状态
|
|
|
|
|
|
getEventStatus(status) {
|
|
|
|
|
|
const statusMap = {
|
|
|
|
|
|
'success': '已完成',
|
|
|
|
|
|
'empty': '已完成',
|
|
|
|
|
|
'error': '失败'
|
|
|
|
|
|
};
|
|
|
|
|
|
return statusMap[status] || '未知';
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 获取事件描述
|
|
|
|
|
|
getEventDescription(status, dataCount) {
|
|
|
|
|
|
const descriptions = {
|
|
|
|
|
|
'success': `成功查询到${dataCount}条参数记录数据`,
|
|
|
|
|
|
'empty': '查询参数记录,但未找到数据',
|
|
|
|
|
|
'error': '查询参数记录时发生错误'
|
|
|
|
|
|
};
|
|
|
|
|
|
return descriptions[status] || '未知查询状态';
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 时间格式化函数
|
|
|
|
|
|
formatDateTime(date) {
|
|
|
|
|
|
const year = date.getFullYear()
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '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')
|
2025-10-06 15:06:48 +08:00
|
|
|
|
|
|
|
|
|
|
const result = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
|
|
|
return result
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化时间字符串(用于API请求)
|
|
|
|
|
|
formatDateTimeString(date) {
|
|
|
|
|
|
const year = date.getFullYear()
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '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')
|
2025-10-01 04:07:37 +08:00
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.parameter-record-page {
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.date-selector {
|
|
|
|
|
|
background: white;
|
2025-10-06 15:06:48 +08:00
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.time-range-info {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.time-range-text {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
font-weight: 500;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.connection-status {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
padding: 8rpx 16rpx;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.connection-status.connected {
|
|
|
|
|
|
background-color: #e8f5e8;
|
|
|
|
|
|
color: #4caf50;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-01 02:42:22 +08:00
|
|
|
|
.data-status {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
padding: 8rpx 16rpx;
|
|
|
|
|
|
border-radius: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.data-status.api {
|
|
|
|
|
|
background-color: #e8f5e8;
|
|
|
|
|
|
color: #4caf50;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.data-status.default {
|
|
|
|
|
|
background-color: #fff3e0;
|
|
|
|
|
|
color: #ff9800;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.data-status .status-text {
|
|
|
|
|
|
font-size: 24rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
.date-navigation {
|
2025-09-29 23:53:09 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-10-06 15:06:48 +08:00
|
|
|
|
gap: 15rpx;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nav-button {
|
|
|
|
|
|
// padding: 12rpx 20rpx;
|
|
|
|
|
|
// background: #007aff;
|
|
|
|
|
|
// color: white;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
// min-width: 120rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 6rpx;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nav-button:active {
|
|
|
|
|
|
// background: #0056b3;
|
|
|
|
|
|
transform: scale(0.95);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nav-button::after {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nav-icon {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.nav-text {
|
|
|
|
|
|
// color: white;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.current-date {
|
|
|
|
|
|
padding: 16rpx 24rpx;
|
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
min-width: 180rpx;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
border: 1rpx solid #e9ecef;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.date-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333;
|
2025-10-06 15:06:48 +08:00
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
margin-bottom: 4rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-06 15:06:48 +08:00
|
|
|
|
.date-weekday {
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
font-weight: 400;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-card {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border-radius: 8rpx;
|
2025-10-01 02:42:22 +08:00
|
|
|
|
padding: 30rpx;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
2025-10-06 15:06:48 +08:00
|
|
|
|
// margin-bottom: 30rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-title {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-subtitle {
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-indicator {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6rpx;
|
|
|
|
|
|
background-color: #e8f5e8;
|
|
|
|
|
|
padding: 6rpx 12rpx;
|
|
|
|
|
|
border-radius: 15rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-dot {
|
|
|
|
|
|
width: 8rpx;
|
|
|
|
|
|
height: 8rpx;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.temperature-dot {
|
|
|
|
|
|
background-color: #ff6b35;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.humidity-dot {
|
|
|
|
|
|
background-color: #4a90e2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.pm25-dot {
|
|
|
|
|
|
background-color: #7ed321;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-text {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #4caf50;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
2025-10-01 02:42:22 +08:00
|
|
|
|
width: 100%;
|
|
|
|
|
|
// padding: 0 20rpx;
|
2025-09-29 23:53:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|