feat:空调开关、状态
This commit is contained in:
@ -17,13 +17,33 @@
|
||||
></web-view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- H5平台提示 -->
|
||||
<!-- H5平台直接使用iframe -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="h5-tip">H5平台暂不支持</view>
|
||||
<view v-if="iframeUrl" class="h5-iframe-container">
|
||||
<iframe
|
||||
:src="iframeUrl"
|
||||
class="h5-iframe"
|
||||
allow="autoplay; fullscreen"
|
||||
allowfullscreen
|
||||
></iframe>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 控制按钮 -->
|
||||
<view class="control-buttons" v-if="!loading && !error">
|
||||
<!-- APP平台:使用 cover-view -->
|
||||
<!-- #ifdef APP-PLUS -->
|
||||
<cover-view class="control-buttons-cover" v-if="!loading && webviewUrl">
|
||||
<cover-view class="control-btn-cover play-btn-cover" @click="togglePlay">
|
||||
<cover-view class="btn-text">{{ isPlaying ? '⏸ 暂停' : '▶ 播放' }}</cover-view>
|
||||
</cover-view>
|
||||
<cover-view class="control-btn-cover refresh-btn-cover" @click="refresh">
|
||||
<cover-view class="btn-text">🔄 刷新</cover-view>
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- H5平台:使用普通按钮 -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="control-buttons" v-if="!loading && iframeUrl">
|
||||
<button class="control-btn play-btn" @click="togglePlay">
|
||||
{{ isPlaying ? '⏸ 暂停' : '▶ 播放' }}
|
||||
</button>
|
||||
@ -31,6 +51,7 @@
|
||||
🔄 刷新
|
||||
</button>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<view v-if="loading" class="loading">
|
||||
<text>{{ loadingText }}</text>
|
||||
@ -39,6 +60,16 @@
|
||||
<view v-if="error" class="error">
|
||||
<text>{{ errorText }}</text>
|
||||
<button @click="retry">重试</button>
|
||||
|
||||
<!-- 即使有错误也显示控制按钮 -->
|
||||
<view class="error-controls">
|
||||
<button class="control-btn play-btn" @click="togglePlay">
|
||||
{{ isPlaying ? '⏸ 暂停' : '▶ 播放' }}
|
||||
</button>
|
||||
<button class="control-btn refresh-btn" @click="refresh">
|
||||
🔄 刷新
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@ -56,7 +87,8 @@ export default {
|
||||
return {
|
||||
platform: '',
|
||||
status: '未初始化',
|
||||
webviewUrl: '',
|
||||
webviewUrl: '', // APP平台使用
|
||||
iframeUrl: '', // H5平台使用
|
||||
loading: false,
|
||||
loadingText: '',
|
||||
error: false,
|
||||
@ -96,12 +128,26 @@ export default {
|
||||
this.status = '加载中'
|
||||
|
||||
try {
|
||||
// #ifdef APP-PLUS
|
||||
// APP平台:使用本地HTML文件
|
||||
const token = encodeURIComponent(config.accessToken)
|
||||
const url = encodeURIComponent(config.play_url)
|
||||
// 使用iframe版本(内存占用更小)
|
||||
this.webviewUrl = `/static/html/ezviz-iframe.html?accessToken=${token}&playUrl=${url}`
|
||||
console.log('[简单播放器] APP平台 - 使用本地HTML文件')
|
||||
// #endif
|
||||
|
||||
console.log('[简单播放器] 使用iframe版本,URL已设置')
|
||||
// #ifdef H5
|
||||
// H5平台:直接构建萤石云iframe URL
|
||||
this.iframeUrl = 'https://open.ys7.com/ezopen/h5/iframe?' +
|
||||
'url=' + encodeURIComponent(config.play_url) +
|
||||
'&accessToken=' + encodeURIComponent(config.accessToken) +
|
||||
'&width=100%' +
|
||||
'&height=100%' +
|
||||
'&autoplay=1' +
|
||||
'&audio=1' +
|
||||
'&controls=1'
|
||||
console.log('[简单播放器] H5平台 - 直接使用萤石云iframe')
|
||||
// #endif
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.loading) {
|
||||
@ -154,7 +200,13 @@ export default {
|
||||
// 因为iframe播放器不支持直接控制,所以采用重新加载的方式
|
||||
if (this.isPlaying) {
|
||||
// 暂停:清空URL
|
||||
// #ifdef APP-PLUS
|
||||
this.webviewUrl = ''
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
this.iframeUrl = ''
|
||||
// #endif
|
||||
|
||||
this.isPlaying = false
|
||||
this.status = '已暂停'
|
||||
|
||||
@ -163,9 +215,23 @@ export default {
|
||||
} else {
|
||||
// 播放:重新设置URL
|
||||
if (this.config) {
|
||||
// #ifdef APP-PLUS
|
||||
const token = encodeURIComponent(this.config.accessToken)
|
||||
const url = encodeURIComponent(this.config.play_url)
|
||||
this.webviewUrl = `/static/html/ezviz-iframe.html?accessToken=${token}&playUrl=${url}`
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
this.iframeUrl = 'https://open.ys7.com/ezopen/h5/iframe?' +
|
||||
'url=' + encodeURIComponent(this.config.play_url) +
|
||||
'&accessToken=' + encodeURIComponent(this.config.accessToken) +
|
||||
'&width=100%' +
|
||||
'&height=100%' +
|
||||
'&autoplay=1' +
|
||||
'&audio=1' +
|
||||
'&controls=1'
|
||||
// #endif
|
||||
|
||||
this.isPlaying = true
|
||||
this.status = '播放中'
|
||||
|
||||
@ -195,12 +261,31 @@ export default {
|
||||
})
|
||||
|
||||
// 先清空再重新加载
|
||||
// #ifdef APP-PLUS
|
||||
this.webviewUrl = ''
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
this.iframeUrl = ''
|
||||
// #endif
|
||||
|
||||
setTimeout(() => {
|
||||
// #ifdef APP-PLUS
|
||||
const token = encodeURIComponent(this.config.accessToken)
|
||||
const url = encodeURIComponent(this.config.play_url)
|
||||
this.webviewUrl = `/static/html/ezviz-iframe.html?accessToken=${token}&playUrl=${url}`
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
this.iframeUrl = 'https://open.ys7.com/ezopen/h5/iframe?' +
|
||||
'url=' + encodeURIComponent(this.config.play_url) +
|
||||
'&accessToken=' + encodeURIComponent(this.config.accessToken) +
|
||||
'&width=100%' +
|
||||
'&height=100%' +
|
||||
'&autoplay=1' +
|
||||
'&audio=1' +
|
||||
'&controls=1'
|
||||
// #endif
|
||||
|
||||
this.isPlaying = true
|
||||
this.status = '播放中'
|
||||
|
||||
@ -244,16 +329,27 @@ export default {
|
||||
|
||||
.video-webview {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.h5-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
/* H5平台iframe容器 */
|
||||
.h5-iframe-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: white;
|
||||
font-size: 28rpx;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.h5-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loading {
|
||||
@ -300,6 +396,36 @@ export default {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
/* 错误状态下的控制按钮 */
|
||||
.error-controls {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 30rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.error-controls .control-btn {
|
||||
flex: 1;
|
||||
max-width: 200rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 8rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.error-controls .play-btn {
|
||||
background: linear-gradient(135deg, #46a049 0%, #4caf50 100%);
|
||||
}
|
||||
|
||||
.error-controls .refresh-btn {
|
||||
background: linear-gradient(135deg, #2196f3 0%, #21cbf3 100%);
|
||||
}
|
||||
|
||||
/* 控制按钮 */
|
||||
.control-buttons {
|
||||
position: absolute;
|
||||
|
||||
@ -24,9 +24,9 @@
|
||||
<view class="detail-progress-bar">
|
||||
<view class="detail-progress-fill temperature-progress" :style="{ width: temperatureProgress + '%' }"></view>
|
||||
</view>
|
||||
<view class="detail-range">
|
||||
<!-- <view class="detail-range">
|
||||
<text class="detail-range-text">{{ 0 }}°C - {{ 100 }}°C</text>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<!-- 湿度卡片 -->
|
||||
@ -44,9 +44,9 @@
|
||||
<view class="detail-progress-bar">
|
||||
<view class="detail-progress-fill humidity-progress" :style="{ width: humidityProgress + '%' }"></view>
|
||||
</view>
|
||||
<view class="detail-range">
|
||||
<!-- <view class="detail-range">
|
||||
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<!-- 洁净度卡片 -->
|
||||
@ -64,22 +64,39 @@
|
||||
<view class="detail-progress-bar">
|
||||
<view class="detail-progress-fill cleanliness-progress" :style="{ width: cleanlinessProgress + '%' }"></view>
|
||||
</view>
|
||||
<view class="detail-range">
|
||||
<!-- <view class="detail-range">
|
||||
<text class="detail-range-text">{{ 0 }}% - {{ 100 }}%</text>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空调目标参数设置 -->
|
||||
<!-- 空调设置 -->
|
||||
<view class="air-conditioner-settings">
|
||||
<view class="ac-header">
|
||||
<view class="ac-title-container">
|
||||
<view class="ac-icon">❄️</view>
|
||||
<text class="ac-title">空调目标参数设置</text>
|
||||
<text class="ac-title">空调设置</text>
|
||||
</view>
|
||||
<view class="ac-status-indicator">
|
||||
<view class="status-dot active"></view>
|
||||
<text class="status-label">运行中</text>
|
||||
<text class="status-label">{{ acStatusList[acStatus] }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空调开关控制卡片 -->
|
||||
<view class="ac-control-card power-card">
|
||||
<view class="control-header">
|
||||
<view class="control-icon-container">
|
||||
<text class="control-label">设备控制</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ac-power-controls">
|
||||
<button class="ac-power-btn power-on" @click="turnOnAirConditioner" :disabled="acControlLoading">
|
||||
开机
|
||||
</button>
|
||||
<button class="ac-power-btn power-off" @click="turnOffAirConditioner" :disabled="acControlLoading">
|
||||
关机
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -259,27 +276,27 @@ export default {
|
||||
cleanlinessProgress: 0,
|
||||
lastUpdate: '暂无数据',
|
||||
temperatureRange: {
|
||||
min: 25,
|
||||
max: 35
|
||||
min: 0,
|
||||
max: 0
|
||||
},
|
||||
humidityRange: {
|
||||
min: 40,
|
||||
max: 70
|
||||
min: 0,
|
||||
max: 0
|
||||
},
|
||||
tempSettings: {
|
||||
min: 25,
|
||||
max: 35
|
||||
min: 0,
|
||||
max: 0
|
||||
},
|
||||
humiditySettings: {
|
||||
min: 40,
|
||||
max: 70
|
||||
min: 0,
|
||||
max: 0
|
||||
},
|
||||
connectionStatus: {
|
||||
isConnected: false,
|
||||
lastUpdate: null
|
||||
},
|
||||
targetTemperature: 30,
|
||||
targetHumidity: 50, // 空调设定湿度
|
||||
targetTemperature: 0,
|
||||
targetHumidity: 0, // 空调设定湿度
|
||||
// 温度输入相关
|
||||
tempInputValue: '',
|
||||
tempValidationMessage: '',
|
||||
@ -295,36 +312,32 @@ export default {
|
||||
alertHistory: [], // 报警历史记录
|
||||
// 系统启动事件相关
|
||||
hasCreatedStartupEvent: false, // 是否已创建启动事件
|
||||
acStatus: 4,
|
||||
// 0待机1启动中2运行中3关机中, 没有就默认连接中
|
||||
acStatusList: ['待机', '启动中', '运行中', '关机中', '连接中'],
|
||||
// 空调控制相关
|
||||
acControlLoading: false, // 空调控制按钮加载状态
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
console.log('环境参数页面加载')
|
||||
|
||||
// 从本地存储读取是否已创建启动事件的状态
|
||||
const hasCreatedStartupEvent = uni.getStorageSync('hasCreatedStartupEvent')
|
||||
if (hasCreatedStartupEvent) {
|
||||
this.hasCreatedStartupEvent = true
|
||||
console.log('📱 从本地存储读取到启动事件状态: 已创建')
|
||||
}
|
||||
// // 从本地存储读取是否已创建启动事件的状态
|
||||
// const hasCreatedStartupEvent = uni.getStorageSync('hasCreatedStartupEvent')
|
||||
// if (hasCreatedStartupEvent) {
|
||||
// this.hasCreatedStartupEvent = true
|
||||
// console.log('📱 从本地存储读取到启动事件状态: 已创建')
|
||||
// }
|
||||
|
||||
this.initMqttListener();
|
||||
this.init();
|
||||
// // 获取最新空调温度
|
||||
// this.getLatestAirConditionerTemperature()
|
||||
// // 获取最新温湿度数据
|
||||
// this.getLatestWsdData()
|
||||
// // 首次进入系统时创建启动事件
|
||||
// this.createStartupEventIfNeeded()
|
||||
|
||||
// // 获取温湿度区间设置
|
||||
// this.loadWsdSettings()
|
||||
},
|
||||
onShow() {
|
||||
console.log('📱 环境参数页面显示,触发页面更新')
|
||||
// 只有在非首次显示时才重新获取最新空调温度
|
||||
if (this.hasCreatedStartupEvent) {
|
||||
this.init();
|
||||
}
|
||||
console.log('📱 环境参数页面显示,触发页面更新');
|
||||
this.init();
|
||||
// // 只有在非首次显示时才重新获取最新空调温度
|
||||
// if (this.hasCreatedStartupEvent) {
|
||||
// this.init();
|
||||
// }
|
||||
},
|
||||
onUnload() {
|
||||
// 页面卸载时移除监听器
|
||||
@ -413,12 +426,12 @@ export default {
|
||||
if (response && response.id) {
|
||||
// 更新温度和湿度控制范围
|
||||
this.temperatureRange = {
|
||||
min: response.minTemperature || 25,
|
||||
max: response.maxTemperature || 35
|
||||
min: response.minTemperature || 0,
|
||||
max: response.maxTemperature || 0
|
||||
}
|
||||
this.humidityRange = {
|
||||
min: response.minHumidity || 40,
|
||||
max: response.maxHumidity || 70
|
||||
min: response.minHumidity || 0,
|
||||
max: response.maxHumidity || 0
|
||||
}
|
||||
|
||||
// 同时更新设置弹窗中的临时变量
|
||||
@ -433,8 +446,8 @@ export default {
|
||||
} catch (error) {
|
||||
console.error('❌ 温湿度区间设置加载失败:', error)
|
||||
// 使用默认值
|
||||
this.temperatureRange = { min: 25, max: 35 }
|
||||
this.humidityRange = { min: 40, max: 70 }
|
||||
this.temperatureRange = { min: 0, max: 0 }
|
||||
this.humidityRange = { min: 0, max: 0 }
|
||||
this.tempSettings = { ...this.temperatureRange }
|
||||
this.humiditySettings = { ...this.humidityRange }
|
||||
console.log('🔄 使用默认温湿度区间设置')
|
||||
@ -444,20 +457,18 @@ export default {
|
||||
// 获取最新空调温湿度参数
|
||||
async getLatestAirConditionerTemperature() {
|
||||
try {
|
||||
console.log('🌡️ 开始获取最新空调温湿度参数...')
|
||||
const res = await thDataApi.getLatest();
|
||||
if (res.status === 'success') {
|
||||
// 从接口获取温度和湿度设定值
|
||||
this.targetTemperature = res.temperature || 30;
|
||||
this.targetHumidity = res.humidity || 50;
|
||||
this.targetTemperature = res.temperature || 0;
|
||||
this.targetHumidity = res.humidity || 0;
|
||||
}
|
||||
console.log('✅ 最新空调温湿度参数:', res)
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 获取最新空调温湿度参数失败:', error)
|
||||
// 接口失败时使用默认值
|
||||
this.targetTemperature = 30;
|
||||
this.targetHumidity = 50;
|
||||
this.targetTemperature = 0;
|
||||
this.targetHumidity = 0;
|
||||
}
|
||||
},
|
||||
// 获取最新温湿度数据
|
||||
@ -465,13 +476,10 @@ export default {
|
||||
try {
|
||||
const res = await wsdApi.getLatest();
|
||||
if (res.status === 'success') {
|
||||
// this.temperature = res.wd || 30;
|
||||
// this.humidity = res.sd || 50
|
||||
// this.cleanliness = res.pm || 0;
|
||||
this.updateEnvironmentData({
|
||||
deviceType: 'WSD',
|
||||
temperature: res.wd || 30,
|
||||
humidity: res.sd || 50,
|
||||
temperature: res.wd || 0,
|
||||
humidity: res.sd || 0,
|
||||
cleanliness: res.pm || 0,
|
||||
})
|
||||
}
|
||||
@ -515,12 +523,8 @@ export default {
|
||||
|
||||
// 更新环境数据
|
||||
updateEnvironmentData(data) {
|
||||
// 处理空调故障状态
|
||||
if (data.deviceType === 'AC' && data.faultStatus !== undefined) {
|
||||
this.acFaultStatus = data.faultStatus
|
||||
}
|
||||
|
||||
// 只处理WSD设备的数据
|
||||
console.log('============data', data)
|
||||
// 处理WSD设备的数据
|
||||
if (data.deviceType === 'WSD') {
|
||||
if (data.temperature !== undefined) {
|
||||
this.temperature = parseFloat(data.temperature.toFixed(1))
|
||||
@ -531,18 +535,31 @@ export default {
|
||||
this.humidity = parseFloat(data.humidity.toFixed(1))
|
||||
this.humidityProgress = Math.min(Math.max(this.humidity, 0), 100)
|
||||
}
|
||||
|
||||
if (data.cleanliness !== undefined) {
|
||||
this.cleanliness = parseFloat(data.cleanliness.toFixed(1))
|
||||
this.cleanlinessProgress = Math.min(Math.max(this.cleanliness, 0), 100)
|
||||
}
|
||||
|
||||
this.lastUpdate = data.time || new Date().toLocaleString('zh-CN')
|
||||
|
||||
// 检查报警条件,传入MQTT原始数据
|
||||
this.checkAlerts(data)
|
||||
} else if (data.deviceType === 'AC') {
|
||||
// 处理空调AC数据
|
||||
if (data.faultStatus !== undefined) {
|
||||
this.acFaultStatus = data.faultStatus // 空调故障
|
||||
}
|
||||
if (data.rawData.status !== undefined) {
|
||||
this.acStatus = data.rawData.status
|
||||
}
|
||||
if (data.rawData.ctrlword !== undefined) {
|
||||
this.acCtrlword = data.rawData.ctrlword
|
||||
}
|
||||
} else if (data.deviceType === 'PM25') {
|
||||
// 处理PM25数据
|
||||
if (data.rawData.PM25 !== undefined) {
|
||||
this.cleanliness = data.rawData.PM25;
|
||||
this.cleanlinessProgress = Math.min(Math.max(this.cleanliness, 0), 100)
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ 非WSD设备数据,跳过更新:', data.deviceType)
|
||||
console.log('⚠️ 非WSD、AC、PM25设备数据,跳过更新:', data.deviceType)
|
||||
// 处理其他设备数据
|
||||
}
|
||||
},
|
||||
|
||||
@ -566,13 +583,20 @@ export default {
|
||||
if (mqttData.deviceType !== 'WSD') {
|
||||
return
|
||||
}
|
||||
console.log('====mqttData', mqttData)
|
||||
// {
|
||||
// "deviceType": "WSD",
|
||||
// "temperature": 0,
|
||||
// "humidity": 0,
|
||||
// "cleanliness": 0
|
||||
// }
|
||||
|
||||
// 获取MQTT原始数据
|
||||
const mqttTemperature = mqttData.temperature
|
||||
const mqttHumidity = mqttData.humidity
|
||||
|
||||
// 1. 温度报警:使用环境控制设置的区间(使用MQTT原始数据)
|
||||
if (mqttTemperature !== undefined && (mqttTemperature < this.temperatureRange.min || mqttTemperature > this.temperatureRange.max)) {
|
||||
if (mqttTemperature !== undefined && mqttTemperature !== 0 && (mqttTemperature < this.temperatureRange.min || mqttTemperature > this.temperatureRange.max)) {
|
||||
const alert = {
|
||||
// content: `温度传感器异常,读数${mqttTemperature}°C超出控制范围${this.temperatureRange.min}°C-${this.temperatureRange.max}°C`,
|
||||
content: `温度超出控制范围`,
|
||||
@ -660,21 +684,21 @@ export default {
|
||||
// 记录报警到控制台并调用创建告警接口
|
||||
async logAlert(alert) {
|
||||
console.log('🚨 报警触发:', JSON.stringify(alert, null, 2))
|
||||
this.alertHistory.push(alert)
|
||||
// this.alertHistory.push(alert)
|
||||
|
||||
// 调用创建告警接口
|
||||
try {
|
||||
console.log('📤 正在创建告警记录...')
|
||||
const response = await alertApi.create(alert)
|
||||
console.log('✅ 告警记录创建成功:', response)
|
||||
} catch (error) {
|
||||
console.error('❌ 告警记录创建失败:', error)
|
||||
}
|
||||
// // 调用创建告警接口
|
||||
// try {
|
||||
// console.log('📤 正在创建告警记录...')
|
||||
// const response = await alertApi.create(alert)
|
||||
// console.log('✅ 告警记录创建成功:', response)
|
||||
// } catch (error) {
|
||||
// console.error('❌ 告警记录创建失败:', error)
|
||||
// }
|
||||
|
||||
// 限制报警历史记录数量,避免内存溢出
|
||||
if (this.alertHistory.length > 100) {
|
||||
this.alertHistory = this.alertHistory.slice(-50)
|
||||
}
|
||||
// // 限制报警历史记录数量,避免内存溢出
|
||||
// if (this.alertHistory.length > 100) {
|
||||
// this.alertHistory = this.alertHistory.slice(-50)
|
||||
// }
|
||||
},
|
||||
|
||||
// 降低目标温度
|
||||
@ -875,7 +899,7 @@ export default {
|
||||
this.humidityValidationClass = ''
|
||||
},
|
||||
|
||||
// 显示湿度变化提示
|
||||
// 空调湿度更新
|
||||
showHumidityChangeToast() {
|
||||
// 发送空调参数到MQTT
|
||||
this.sendAirConditionerParams()
|
||||
@ -889,110 +913,156 @@ export default {
|
||||
this.checkAlerts(mockMqttData)
|
||||
},
|
||||
|
||||
// 显示温度变化提示
|
||||
showTemperatureChangeToast() {
|
||||
// uni.showToast({
|
||||
// title: `目标温度: ${this.targetTemperature}°C`,
|
||||
// icon: 'success',
|
||||
// duration: 1500
|
||||
// })
|
||||
|
||||
// 发送空调参数到MQTT
|
||||
this.sendAirConditionerParams()
|
||||
|
||||
// 温度变化后检查报警(使用当前页面数据模拟MQTT数据)
|
||||
const mockMqttData = {
|
||||
deviceType: 'WSD',
|
||||
temperature: this.temperature,
|
||||
humidity: this.humidity
|
||||
// 空调温度更新
|
||||
showTemperatureChangeToast() {
|
||||
// 发送空调参数到MQTT
|
||||
this.sendAirConditionerParams()
|
||||
|
||||
// 温度变化后检查报警(使用当前页面数据模拟MQTT数据)
|
||||
const mockMqttData = {
|
||||
deviceType: 'WSD',
|
||||
temperature: this.temperature,
|
||||
humidity: this.humidity
|
||||
}
|
||||
this.checkAlerts(mockMqttData)
|
||||
},
|
||||
|
||||
// 发送空调参数
|
||||
async sendAirConditionerParams() {
|
||||
try {
|
||||
// 根据MQTT文档,空调温度使用BSQWD,但控制指令可能使用不同的TagName
|
||||
// 发送温度参数 - 使用BSQWD作为TagName(与接收数据保持一致)
|
||||
const temperatureData = {
|
||||
"TagValue": this.targetTemperature,
|
||||
"TagName": "JS_COD", // 使用与接收数据一致的TagName
|
||||
"method": "setValue"
|
||||
}
|
||||
this.checkAlerts(mockMqttData)
|
||||
},
|
||||
|
||||
// 发送空调参数
|
||||
async sendAirConditionerParams() {
|
||||
// 发送湿度参数 - 根据文档WSD设备湿度使用SD
|
||||
const humidityData = {
|
||||
"TagValue": this.targetHumidity,
|
||||
"TagName": "JS_SD", // 使用与WSD设备湿度一致的TagName
|
||||
"method": "setValue"
|
||||
}
|
||||
|
||||
console.log('🌡️ 发送空调温度参数:', temperatureData)
|
||||
console.log('💧 发送空调湿度参数:', humidityData)
|
||||
|
||||
// 调用发送MQTT数据的方法
|
||||
const tempSuccess = sendMqttData(temperatureData)
|
||||
const humiditySuccess = sendMqttData(humidityData)
|
||||
|
||||
if (tempSuccess && humiditySuccess) {
|
||||
console.log('✅ 空调温湿度参数MQTT发送请求已提交')
|
||||
|
||||
// 发送成功后调用提交温湿度数据API
|
||||
try {
|
||||
// 根据MQTT文档,空调温度使用BSQWD,但控制指令可能使用不同的TagName
|
||||
// 发送温度参数 - 使用BSQWD作为TagName(与接收数据保持一致)
|
||||
const temperatureData = {
|
||||
"TagValue": this.targetTemperature,
|
||||
"TagName": "JS_COD", // 使用与接收数据一致的TagName
|
||||
"method": "setValue"
|
||||
}
|
||||
|
||||
// 发送湿度参数 - 根据文档WSD设备湿度使用SD
|
||||
const humidityData = {
|
||||
"TagValue": this.targetHumidity,
|
||||
"TagName": "JS_SD", // 使用与WSD设备湿度一致的TagName
|
||||
"method": "setValue"
|
||||
}
|
||||
|
||||
console.log('🌡️ 发送空调温度参数:', temperatureData)
|
||||
console.log('💧 发送空调湿度参数:', humidityData)
|
||||
|
||||
// 调用发送MQTT数据的方法
|
||||
const tempSuccess = sendMqttData(temperatureData)
|
||||
const humiditySuccess = sendMqttData(humidityData)
|
||||
|
||||
if (tempSuccess && humiditySuccess) {
|
||||
console.log('✅ 空调温湿度参数MQTT发送请求已提交')
|
||||
|
||||
// 发送成功后调用提交温湿度数据API
|
||||
try {
|
||||
await this.submitTemperatureData()
|
||||
// 显示成功提示
|
||||
uni.showToast({
|
||||
title: '参数设置成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
} catch (apiError) {
|
||||
// MQTT发送成功,但接口保存失败
|
||||
console.warn('⚠️ MQTT发送成功,但接口保存失败:', apiError)
|
||||
uni.showToast({
|
||||
title: 'MQTT已发送,接口保存失败',
|
||||
icon: 'none',
|
||||
duration: 2500
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
console.error('❌ 空调参数MQTT发送失败')
|
||||
uni.showToast({
|
||||
title: 'MQTT发送失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 发送空调参数异常:', error)
|
||||
await this.submitTemperatureData()
|
||||
// 显示成功提示
|
||||
uni.showToast({
|
||||
title: '参数设置失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
title: '参数设置成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
} catch (apiError) {
|
||||
// MQTT发送成功,但接口保存失败
|
||||
console.warn('⚠️ MQTT发送成功,但接口保存失败:', apiError)
|
||||
uni.showToast({
|
||||
title: 'MQTT已发送,接口保存失败',
|
||||
icon: 'none',
|
||||
duration: 2500
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
} else {
|
||||
console.error('❌ 空调参数MQTT发送失败')
|
||||
uni.showToast({
|
||||
title: 'MQTT发送失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 发送空调参数异常:', error)
|
||||
uni.showToast({
|
||||
title: '参数设置失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 空调开机控制
|
||||
async turnOnAirConditioner() {
|
||||
await this.sendAirConditionerControl(1, '开机')
|
||||
},
|
||||
|
||||
// 空调关机控制
|
||||
async turnOffAirConditioner() {
|
||||
await this.sendAirConditionerControl(2, '关机')
|
||||
},
|
||||
|
||||
// 发送空调控制指令
|
||||
async sendAirConditionerControl(ctrlValue, actionName) {
|
||||
this.acControlLoading = true;
|
||||
try {
|
||||
// 构建控制指令数据
|
||||
const controlData = {
|
||||
"TagValue": ctrlValue,
|
||||
"TagName": "ctrlword",
|
||||
"method": "setValue"
|
||||
}
|
||||
|
||||
// 提交温湿度数据
|
||||
async submitTemperatureData() {
|
||||
try {
|
||||
const temperatureHumidityData = {
|
||||
temperature: this.targetTemperature,
|
||||
humidity: this.targetHumidity,
|
||||
deviceId: "TH_SENSOR_001",
|
||||
timestamp: new Date().toISOString(),
|
||||
source: "manual_setting" // 标识为手动设置
|
||||
}
|
||||
console.log('📤 提交温湿度数据到接口:', temperatureHumidityData)
|
||||
const response = await thDataApi.submit(temperatureHumidityData)
|
||||
console.log('✅ 温湿度数据接口提交成功:', response)
|
||||
} catch (error) {
|
||||
console.error('❌ 温湿度数据接口提交失败:', error)
|
||||
// 接口失败不影响MQTT发送,只记录日志
|
||||
throw error // 重新抛出错误,让调用方知道接口失败了
|
||||
}
|
||||
},
|
||||
console.log(`🔧 发送空调${actionName}指令:`, controlData)
|
||||
|
||||
// 调用发送MQTT数据的方法
|
||||
const success = sendMqttData(controlData)
|
||||
this.acControlLoading = false;
|
||||
if (success) {
|
||||
// 显示成功提示
|
||||
uni.showToast({
|
||||
title: `${actionName}指令已发送`,
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: `${actionName}失败`,
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: `${actionName}异常`,
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
} finally {
|
||||
// 清除加载状态
|
||||
this.acControlLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 提交温湿度数据
|
||||
async submitTemperatureData() {
|
||||
try {
|
||||
const temperatureHumidityData = {
|
||||
temperature: this.targetTemperature,
|
||||
humidity: this.targetHumidity,
|
||||
deviceId: "TH_SENSOR_001",
|
||||
timestamp: new Date().toISOString(),
|
||||
source: "manual_setting" // 标识为手动设置
|
||||
}
|
||||
console.log('📤 提交温湿度数据到接口:', temperatureHumidityData)
|
||||
const response = await thDataApi.submit(temperatureHumidityData)
|
||||
console.log('✅ 温湿度数据接口提交成功:', response)
|
||||
} catch (error) {
|
||||
console.error('❌ 温湿度数据接口提交失败:', error)
|
||||
// 接口失败不影响MQTT发送,只记录日志
|
||||
throw error // 重新抛出错误,让调用方知道接口失败了
|
||||
}
|
||||
},
|
||||
|
||||
// 手动重连MQTT
|
||||
manualReconnect() {
|
||||
@ -1449,6 +1519,58 @@ export default {
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 空调开关控制按钮样式 */
|
||||
.ac-power-controls {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx;
|
||||
border: 1rpx solid #e1e5e9;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.ac-power-btn {
|
||||
flex: 1;
|
||||
max-width: 120rpx;
|
||||
// height: 60rpx;
|
||||
border-radius: 6rpx;
|
||||
border: 1rpx solid;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.power-on {
|
||||
background: #27ae60;
|
||||
color: white;
|
||||
border-color: #27ae60;
|
||||
}
|
||||
|
||||
.power-on:active {
|
||||
background: #229954;
|
||||
border-color: #229954;
|
||||
}
|
||||
|
||||
.power-off {
|
||||
background: #e74c3c;
|
||||
color: white;
|
||||
border-color: #e74c3c;
|
||||
}
|
||||
|
||||
.power-off:active {
|
||||
background: #c0392b;
|
||||
border-color: #c0392b;
|
||||
}
|
||||
|
||||
.ac-power-btn:disabled {
|
||||
background: #bdc3c7;
|
||||
color: #7f8c8d;
|
||||
border-color: #bdc3c7;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.ac-temp-display {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
@ -25,31 +25,6 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 视频信息区域 -->
|
||||
<view v-if="ezstate" class="video-info">
|
||||
<view class="info-item">
|
||||
<text class="info-label">📡 设备状态</text>
|
||||
<text class="info-value online">在线</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">🎥 分辨率</text>
|
||||
<text class="info-value">高清</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">🔊 音频</text>
|
||||
<text class="info-value">开启</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 视频控制按钮 -->
|
||||
<view v-if="ezstate" class="control-section">
|
||||
<button @click="handleInitPlayer" class="control-btn init-btn">
|
||||
🔄 初始化
|
||||
</button>
|
||||
<button @click="handleTogglePlay" class="control-btn pause-btn">
|
||||
{{ isPlaying ? '⏸ 暂停播放' : '▶ 开始播放' }}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- API测试按钮 -->
|
||||
<view class="test-section" v-if="!ezstate">
|
||||
@ -136,55 +111,6 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
// 初始化播放器
|
||||
async handleInitPlayer() {
|
||||
console.log('🔄 重新初始化播放器...')
|
||||
|
||||
uni.showLoading({
|
||||
title: '正在初始化...'
|
||||
})
|
||||
|
||||
try {
|
||||
// 重新获取视频数据并初始化
|
||||
await this.getVideoData()
|
||||
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '初始化成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
// 重置播放状态
|
||||
this.isPlaying = true
|
||||
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
console.error('初始化失败:', error)
|
||||
uni.showToast({
|
||||
title: '初始化失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 切换播放/暂停
|
||||
handleTogglePlay() {
|
||||
console.log('🎬 切换播放状态:', this.isPlaying ? '暂停' : '播放')
|
||||
|
||||
if (this.$refs.playerVideoRef) {
|
||||
// 调用播放器组件的切换播放方法(状态会通过事件同步)
|
||||
this.$refs.playerVideoRef.togglePlay()
|
||||
} else {
|
||||
console.error('❌ 播放器组件未找到')
|
||||
uni.showToast({
|
||||
title: '播放器未就绪',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 处理播放状态变化(由播放器组件触发)
|
||||
handlePlayStateChange(isPlaying) {
|
||||
|
||||
@ -9,7 +9,14 @@ class MqttDataManager {
|
||||
temperature: null,
|
||||
humidity: null,
|
||||
pm25: null,
|
||||
timestamp: null
|
||||
timestamp: null,
|
||||
// 扩展数据结构支持更多设备类型
|
||||
deviceType: null,
|
||||
rawData: null,
|
||||
// 空调设备数据
|
||||
acTemperature: null,
|
||||
// 其他设备数据可在此扩展
|
||||
otherDeviceData: {}
|
||||
}
|
||||
this.init()
|
||||
}
|
||||
@ -95,41 +102,65 @@ class MqttDataManager {
|
||||
// console.log('设备数据:', deviceDataContent)
|
||||
// console.log('时间戳:', timestamp)
|
||||
|
||||
// 根据设备类型处理数据
|
||||
if (deviceType === 'WSD') {
|
||||
// console.log('✅ 处理WSD设备数据 - 更新环境参数')
|
||||
this.processWSDData(deviceDataContent, timestamp)
|
||||
} else {
|
||||
// console.log(`⚠️ 设备类型 ${deviceType} 暂不处理,仅打印到控制台`)
|
||||
// console.log('设备详情:', {
|
||||
// deviceType,
|
||||
// data: deviceDataContent,
|
||||
// timestamp: new Date(timestamp * 1000).toLocaleString('zh-CN')
|
||||
// })
|
||||
}
|
||||
// 处理所有设备类型的数据
|
||||
console.log(`✅ 处理设备类型: ${deviceType}`)
|
||||
this.processAllDeviceData(deviceType, deviceDataContent, timestamp)
|
||||
} catch (error) {
|
||||
console.error('❌ 处理设备数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理WSD设备数据
|
||||
processWSDData(data, timestamp) {
|
||||
// 处理所有设备类型的数据
|
||||
processAllDeviceData(deviceType, data, timestamp) {
|
||||
try {
|
||||
// 解析WSD数据 - 根据您提供的数据结构,WD是温度,SD是湿度
|
||||
const temperature = data.WD && parseFloat(data.WD);
|
||||
const humidity = data.SD && parseFloat(data.SD);
|
||||
console.log(`🌡️ ${deviceType}设备数据解析:`)
|
||||
console.log('设备数据:', data)
|
||||
|
||||
// console.log('🌡️ WSD数据解析:')
|
||||
// console.log('温度(WD):', temperature)
|
||||
// console.log('湿度(SD):', humidity)
|
||||
|
||||
// 构建解析后的数据
|
||||
// 构建基础解析数据
|
||||
const parsedData = {
|
||||
deviceType: 'WSD',
|
||||
deviceType,
|
||||
timestamp,
|
||||
time: new Date(timestamp * 1000).toLocaleString('zh-CN'),
|
||||
temperature,
|
||||
humidity
|
||||
rawData: data // 保存原始数据供页面特殊处理
|
||||
}
|
||||
|
||||
// 根据设备类型解析特定数据
|
||||
switch (deviceType) {
|
||||
case 'WSD': // 温湿度传感器
|
||||
if (data.WD !== undefined) {
|
||||
parsedData.temperature = parseFloat(data.WD)
|
||||
}
|
||||
if (data.SD !== undefined) {
|
||||
parsedData.humidity = parseFloat(data.SD)
|
||||
}
|
||||
break
|
||||
|
||||
case 'AC': // 空调设备
|
||||
if (data.BSQWD !== undefined) {
|
||||
parsedData.acTemperature = parseFloat(data.BSQWD)
|
||||
}
|
||||
|
||||
if (data.SD !== undefined) {
|
||||
parsedData.acHumidity = parseFloat(data.SD)
|
||||
}
|
||||
|
||||
if (data.status !== undefined) {
|
||||
parsedData.acStatus = data.status
|
||||
}
|
||||
// 可以添加其他空调参数
|
||||
break
|
||||
|
||||
case 'PM': // PM2.5传感器
|
||||
if (data.PM25 !== undefined) {
|
||||
parsedData.pm25 = parseFloat(data.PM25)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
// 其他设备类型,保存到otherDeviceData中
|
||||
console.log(`📦 处理未知设备类型 ${deviceType},保存原始数据`)
|
||||
// parsedData.otherDeviceData = data
|
||||
break
|
||||
}
|
||||
|
||||
// 更新最新数据
|
||||
@ -138,9 +169,9 @@ class MqttDataManager {
|
||||
// 通知所有监听器
|
||||
this.notifyListeners('dataUpdate', parsedData)
|
||||
|
||||
// console.log('✅ WSD数据处理完成:', parsedData)
|
||||
console.log(`✅ ${deviceType}数据处理完成:`, parsedData)
|
||||
} catch (error) {
|
||||
console.error('❌ 处理WSD数据失败:', error)
|
||||
console.error(`❌ 处理${deviceType}数据失败:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,16 +229,18 @@ class MqttDataManager {
|
||||
|
||||
// 更新最新数据
|
||||
updateLastData(parsedData) {
|
||||
if (parsedData.temperature !== undefined) {
|
||||
this.lastData.temperature = parsedData.temperature
|
||||
}
|
||||
if (parsedData.humidity !== undefined) {
|
||||
this.lastData.humidity = parsedData.humidity
|
||||
}
|
||||
if (parsedData.pm25 !== undefined) {
|
||||
this.lastData.pm25 = parsedData.pm25
|
||||
}
|
||||
this.lastData.timestamp = parsedData.timestamp
|
||||
// 直接合并数据,只更新有值的字段
|
||||
Object.keys(parsedData).forEach(key => {
|
||||
if (parsedData[key] !== undefined) {
|
||||
if (key === 'otherDeviceData' && this.lastData.otherDeviceData) {
|
||||
// 对于 otherDeviceData,进行深度合并
|
||||
this.lastData.otherDeviceData = { ...this.lastData.otherDeviceData, ...parsedData.otherDeviceData }
|
||||
} else {
|
||||
// 其他字段直接赋值
|
||||
this.lastData[key] = parsedData[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 添加数据监听器
|
||||
|
||||
Reference in New Issue
Block a user