Files
movecheck/src/pages/parameter/index.vue

383 lines
9.8 KiB
Vue
Raw Normal View History

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">
<!-- 日期选择器 -->
<view class="date-selector">
<picker mode="date" :value="selectedDate" @change="onDateChange">
<view class="date-picker">
<text class="date-text">{{ selectedDate }}</text>
<text class="picker-arrow"></text>
</view>
</picker>
<view class="connection-status" :class="connectionStatus.isConnected ? 'connected' : 'disconnected'">
{{ connectionStatus.isConnected ? 'MQTT已连接' : 'MQTT未连接' }}
</view>
</view>
<!-- 温度趋势图表 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">温度趋势</text>
<view class="status-indicator">
<view class="status-dot temperature-dot"></view>
<text class="status-text">正常</text>
</view>
</view>
<view class="chart-container">
<canvas canvas-id="temperatureChart" class="chart-canvas"></canvas>
</view>
</view>
<!-- 湿度趋势图表 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">湿度趋势</text>
<view class="status-indicator">
<view class="status-dot humidity-dot"></view>
<text class="status-text">正常</text>
</view>
</view>
<view class="chart-container">
<canvas canvas-id="humidityChart" class="chart-canvas"></canvas>
</view>
</view>
<!-- PM2.5趋势图表 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">PM2.5趋势</text>
<view class="status-indicator">
<view class="status-dot pm25-dot"></view>
<text class="status-text">正常</text>
</view>
</view>
<view class="chart-container">
<canvas canvas-id="pm25Chart" class="chart-canvas"></canvas>
</view>
</view>
</view>
</view>
</template>
<script>
import mqttDataManager from '@/utils/mqttDataManager.js'
export default {
data() {
return {
selectedDate: '2025-09-01',
// 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
}
}
},
onLoad() {
console.log('参数记录页面加载')
this.$nextTick(() => {
this.drawCharts()
})
this.initMqttListener()
},
onUnload() {
// 页面卸载时移除监听器
if (this.dataUpdateHandler) {
mqttDataManager.removeListener('dataUpdate', this.dataUpdateHandler)
}
if (this.statusUpdateHandler) {
mqttDataManager.removeListener('connectionStatus', this.statusUpdateHandler)
}
},
methods: {
// 初始化MQTT监听
initMqttListener() {
// 监听数据更新
this.dataUpdateHandler = (data) => {
console.log('参数记录页面收到MQTT数据:', data)
this.updateChartData(data)
}
mqttDataManager.addListener('dataUpdate', this.dataUpdateHandler)
// 监听连接状态
this.statusUpdateHandler = (status) => {
this.connectionStatus = status
console.log('参数记录页面连接状态更新:', status)
}
mqttDataManager.addListener('connectionStatus', this.statusUpdateHandler)
// 获取初始连接状态
this.connectionStatus = mqttDataManager.getConnectionStatus()
},
// 更新图表数据
updateChartData(data) {
console.log('📊 参数记录页面更新数据:', data)
// 只处理WSD设备的数据
if (data.deviceType === 'WSD') {
const now = new Date()
const currentHour = now.getHours()
// 更新对应小时的数据
if (data.temperature !== undefined) {
this.temperatureData[currentHour] = Math.round(data.temperature)
console.log(`✅ 温度数据已更新 - 小时${currentHour}:`, this.temperatureData[currentHour])
}
if (data.humidity !== undefined) {
this.humidityData[currentHour] = Math.round(data.humidity)
console.log(`✅ 湿度数据已更新 - 小时${currentHour}:`, this.humidityData[currentHour])
}
// 重新绘制图表
this.$nextTick(() => {
this.drawCharts()
})
console.log('✅ 图表数据更新完成:', {
temperature: this.temperatureData[currentHour],
humidity: this.humidityData[currentHour],
hour: currentHour
})
} else {
console.log('⚠️ 非WSD设备数据跳过图表更新:', data.deviceType)
}
},
onDateChange(e) {
this.selectedDate = e.detail.value
this.$nextTick(() => {
this.drawCharts()
})
},
drawCharts() {
this.drawTemperatureChart()
this.drawHumidityChart()
this.drawPM25Chart()
},
drawTemperatureChart() {
const ctx = uni.createCanvasContext('temperatureChart', this)
this.drawLineChart(ctx, this.temperatureData, '#ff6b35', '°C')
},
drawHumidityChart() {
const ctx = uni.createCanvasContext('humidityChart', this)
this.drawLineChart(ctx, this.humidityData, '#4a90e2', '%')
},
drawPM25Chart() {
const ctx = uni.createCanvasContext('pm25Chart', this)
this.drawLineChart(ctx, this.pm25Data, '#7ed321', 'μg/m³')
},
drawLineChart(ctx, data, color, unit) {
const canvasWidth = 300
const canvasHeight = 200
const padding = 40
const chartWidth = canvasWidth - padding * 2
const chartHeight = canvasHeight - padding * 2
// 清空画布
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
// 绘制网格
ctx.setStrokeStyle('#f0f0f0')
ctx.setLineWidth(1)
// 水平网格线
for (let i = 0; i <= 5; i++) {
const y = padding + (chartHeight / 5) * i
ctx.beginPath()
ctx.moveTo(padding, y)
ctx.lineTo(padding + chartWidth, y)
ctx.stroke()
}
// 垂直网格线
for (let i = 0; i <= 6; i++) {
const x = padding + (chartWidth / 6) * i
ctx.beginPath()
ctx.moveTo(x, padding)
ctx.lineTo(x, padding + chartHeight)
ctx.stroke()
}
// 绘制数据线
ctx.setStrokeStyle(color)
ctx.setLineWidth(3)
ctx.beginPath()
data.forEach((value, index) => {
const x = padding + (chartWidth / 23) * index
const y = padding + chartHeight - (value / 100) * chartHeight
if (index === 0) {
ctx.moveTo(x, y)
} else {
ctx.lineTo(x, y)
}
})
ctx.stroke()
// 绘制数据点
ctx.setFillStyle(color)
data.forEach((value, index) => {
const x = padding + (chartWidth / 23) * index
const y = padding + chartHeight - (value / 100) * chartHeight
ctx.beginPath()
ctx.arc(x, y, 4, 0, 2 * Math.PI)
ctx.fill()
})
// 绘制X轴标签
ctx.setFillStyle('#666')
ctx.setFontSize(12)
ctx.setTextAlign('center')
const timeLabels = ['00', '04', '08', '12', '16', '20', '23']
timeLabels.forEach((label, index) => {
const x = padding + (chartWidth / 6) * index
ctx.fillText(label, x, canvasHeight - 10)
})
// 绘制Y轴标签
ctx.setTextAlign('right')
for (let i = 0; i <= 5; i++) {
const y = padding + chartHeight - (chartHeight / 5) * i + 5
const value = (100 / 5) * i
ctx.fillText(value.toString(), padding - 10, y)
}
ctx.draw()
}
}
}
</script>
<style lang="scss" scoped>
.parameter-record-page {
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.date-selector {
background: white;
border-radius: 8rpx;
padding: 15rpx;
margin-bottom: 15rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.connection-status {
font-size: 24rpx;
font-weight: bold;
padding: 8rpx 16rpx;
border-radius: 20rpx;
}
.connection-status.connected {
background-color: #e8f5e8;
color: #4caf50;
}
.connection-status.disconnected {
background-color: #ffebee;
color: #ff4444;
}
.date-picker {
display: flex;
align-items: center;
gap: 8rpx;
padding: 15rpx 20rpx;
background-color: #f8f8f8;
border-radius: 6rpx;
}
.date-text {
font-size: 28rpx;
color: #333;
}
.picker-arrow {
color: #999;
font-size: 20rpx;
}
.chart-card {
background: white;
border-radius: 8rpx;
padding: 20rpx;
margin-bottom: 15rpx;
}
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.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 {
display: flex;
justify-content: center;
}
.chart-canvas {
width: 280px;
height: 180px;
}
</style>