对接MQTT、APP样式
This commit is contained in:
383
src/pages/parameter/index.vue
Normal file
383
src/pages/parameter/index.vue
Normal file
@ -0,0 +1,383 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user