fix:温湿度操作记录日志、温湿度同步后台、删除查询日志、停止视频播放

This commit is contained in:
吉浩茹
2025-10-10 10:58:43 +08:00
parent 7a88643b5d
commit 4e66592cf8
8 changed files with 716 additions and 163 deletions

View File

@ -24,7 +24,7 @@
<view class="table-cell header-cell content-column">内容</view> <view class="table-cell header-cell content-column">内容</view>
<view class="table-cell header-cell type-column">种类</view> <view class="table-cell header-cell type-column">种类</view>
<view class="table-cell header-cell time-column">时间</view> <view class="table-cell header-cell time-column">时间</view>
<view class="table-cell header-cell level-column">级别</view> <!-- <view class="table-cell header-cell level-column">级别</view> -->
<!-- <view class="table-cell header-cell action-column">处置</view> --> <!-- <view class="table-cell header-cell action-column">处置</view> -->
<!-- <view class="table-cell header-cell action-time-column">时间</view> --> <!-- <view class="table-cell header-cell action-time-column">时间</view> -->
</view> </view>
@ -56,9 +56,9 @@
<view class="table-cell type-column">{{ alarm.type }}</view> <view class="table-cell type-column">{{ alarm.type }}</view>
<view class="table-cell time-column">{{ alarm.time }}</view> <view class="table-cell time-column">{{ alarm.time }}</view>
<!-- <view class="table-cell level-column" :class="getLevelClass(alarm.level)"> --> <!-- <view class="table-cell level-column" :class="getLevelClass(alarm.level)"> -->
<view class="table-cell level-column"> <!-- <view class="table-cell level-column">
{{ alarm.level }} {{ alarm.level }}
</view> </view> -->
<!-- <view class="table-cell action-column">{{ alarm.action }}</view> --> <!-- <view class="table-cell action-column">{{ alarm.action }}</view> -->
<!-- <view class="table-cell action-time-column">{{ alarm.actionTime }}</view> --> <!-- <view class="table-cell action-time-column">{{ alarm.actionTime }}</view> -->
</view> </view>
@ -143,7 +143,6 @@ const mqttAlarmService = {
// 获取历史报警记录(分页) // 获取历史报警记录(分页)
getHistoryAlarms: async (page = 0, size = 20, isLoadMore = false) => { getHistoryAlarms: async (page = 0, size = 20, isLoadMore = false) => {
console.log(`获取历史报警记录,页码:${page}, 每页:${size}`);
try { try {
if (!isLoadMore) { if (!isLoadMore) {
isLoading.value = true; isLoading.value = true;
@ -158,8 +157,6 @@ const mqttAlarmService = {
size: size size: size
}); });
console.log('📊 获取告警数据响应:', response);
// 处理响应数据 // 处理响应数据
if (response && response.data) { if (response && response.data) {
const newAlarms = response.data.map(item => ({ const newAlarms = response.data.map(item => ({
@ -188,7 +185,6 @@ const mqttAlarmService = {
await createQueryEvent('success', newAlarms.length); await createQueryEvent('success', newAlarms.length);
} }
} else { } else {
console.warn('⚠️ 响应数据格式异常:', response);
if (!isLoadMore) { if (!isLoadMore) {
alarmList.value = []; alarmList.value = [];
} }
@ -447,23 +443,23 @@ const stopRealtimeAlarm = () => {
// 创建查询事件 // 创建查询事件
const createQueryEvent = async (status, dataCount) => { const createQueryEvent = async (status, dataCount) => {
try { // try {
const currentTime = formatDateTime(new Date().toISOString()) // const currentTime = formatDateTime(new Date().toISOString())
const queryEvent = { // const queryEvent = {
eventType: "报警记录查询", // eventType: "报警记录查询",
eventTime: currentTime, // eventTime: currentTime,
status: getEventStatus(status), // status: getEventStatus(status),
description: getEventDescription(status, dataCount), // description: getEventDescription(status, dataCount),
deviceId: "ALARM_QUERY_001" // deviceId: "ALARM_QUERY_001"
} // }
console.log('📤 提交报警查询事件:', queryEvent) // console.log('📤 提交报警查询事件:', queryEvent)
const response = await eventApi.create(queryEvent) // const response = await eventApi.create(queryEvent)
console.log('✅ 报警查询事件创建成功:', response) // console.log('✅ 报警查询事件创建成功:', response)
} catch (error) { // } catch (error) {
console.error('❌ 报警查询事件创建失败:', error) // console.error('❌ 报警查询事件创建失败:', error)
} // }
}; };
// 获取事件状态 // 获取事件状态
@ -488,7 +484,6 @@ const getEventDescription = (status, dataCount) => {
// 刷新数据方法 // 刷新数据方法
const refreshData = async () => { const refreshData = async () => {
console.log('🔄 刷新报警记录数据')
try { try {
// 重置分页状态 // 重置分页状态
currentPage.value = 0; currentPage.value = 0;

View File

@ -29,27 +29,20 @@
</view> </view>
<!-- #endif --> <!-- #endif -->
<!-- APP平台使用 cover-view --> <!-- APP平台控制按钮已集成到HTML页面中 -->
<!-- #ifdef APP-PLUS --> <!-- #ifdef APP-PLUS -->
<cover-view class="control-buttons-cover" v-if="!loading && webviewUrl"> <!-- 控制按钮现在直接在 ezviz-iframe.html 页面中 -->
<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 --> <!-- #endif -->
<!-- H5平台使用普通按钮 --> <!-- H5平台使用悬浮按钮与APP平台保持一致 -->
<!-- #ifdef H5 --> <!-- #ifdef H5 -->
<view class="control-buttons" v-if="!loading && iframeUrl"> <view class="control-buttons-unified" v-if="!loading && iframeUrl && !error">
<button class="control-btn play-btn" @click="togglePlay"> <view class="control-btn-unified play-btn-unified" @click="togglePlay">
{{ isPlaying ? ' 暂停' : ' 播放' }} <text class="btn-text-unified">{{ isPlaying ? '⏸ 暂停' : '▶ 播放' }}</text>
</button> </view>
<button class="control-btn refresh-btn" @click="refresh"> <view class="control-btn-unified refresh-btn-unified" @click="refresh">
🔄 刷新 <text class="btn-text-unified">🔄 刷新</text>
</button> </view>
</view> </view>
<!-- #endif --> <!-- #endif -->
@ -134,6 +127,7 @@ export default {
const url = encodeURIComponent(config.play_url) const url = encodeURIComponent(config.play_url)
this.webviewUrl = `/static/html/ezviz-iframe.html?accessToken=${token}&playUrl=${url}` this.webviewUrl = `/static/html/ezviz-iframe.html?accessToken=${token}&playUrl=${url}`
console.log('[简单播放器] APP平台 - 使用本地HTML文件') console.log('[简单播放器] APP平台 - 使用本地HTML文件')
console.log('[简单播放器] APP平台 - webviewUrl:', this.webviewUrl)
// #endif // #endif
// #ifdef H5 // #ifdef H5
@ -145,14 +139,21 @@ export default {
'&height=100%' + '&height=100%' +
'&autoplay=1' + '&autoplay=1' +
'&audio=1' + '&audio=1' +
'&controls=1' '&controls=1';
console.log('[简单播放器] H5平台 - 直接使用萤石云iframe') console.log('[简单播放器] H5平台 - 直接使用萤石云iframe', this.iframeUrl)
// #endif // #endif
setTimeout(() => { setTimeout(() => {
if (this.loading) { if (this.loading) {
this.loading = false this.loading = false
this.status = '播放器已加载' this.status = '播放器已加载'
console.log('[简单播放器] 加载完成,显示控制按钮')
console.log('[简单播放器] 当前状态:', {
loading: this.loading,
webviewUrl: !!this.webviewUrl,
iframeUrl: !!this.iframeUrl,
platform: this.platform
})
} }
}, 3000) }, 3000)
@ -193,55 +194,102 @@ export default {
}, },
// 切换播放/暂停 // 切换播放/暂停
// 统一的播放状态切换逻辑
togglePlay() { togglePlay() {
console.log('[简单播放器] 切换播放状态:', this.isPlaying ? '暂停' : '播放') console.log('[简单播放器] 切换播放状态:', this.isPlaying ? '暂停' : '播放')
// 通过重新加载URL来实现播放/暂停 // 防止重复点击和加载中操作
// 因为iframe播放器不支持直接控制所以采用重新加载的方式 if (this.loading) {
if (this.isPlaying) { console.log('[简单播放器] 播放器加载中,忽略操作')
// 暂停清空URL return
}
const newPlayState = !this.isPlaying
// 统一的状态更新逻辑
if (newPlayState) {
this.startPlayback()
} else {
this.pausePlayback()
}
// 返回新的播放状态
return this.isPlaying
},
// 统一的开始播放逻辑
startPlayback() {
console.log('[简单播放器] 开始播放')
if (!this.config) {
console.error('[简单播放器] 配置信息不存在,无法播放')
return
}
try {
// 设置播放URL - 两个平台使用相同的逻辑
// #ifdef APP-PLUS // #ifdef APP-PLUS
this.webviewUrl = '' const token = encodeURIComponent(this.config.accessToken)
// #endif const url = encodeURIComponent(this.config.play_url)
// #ifdef H5 this.webviewUrl = `/static/html/ezviz-iframe.html?accessToken=${token}&playUrl=${url}`
this.iframeUrl = '' console.log('[简单播放器] APP平台 - 设置webviewUrl')
// #endif // #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'
console.log('[简单播放器] H5平台 - 设置iframeUrl', this.iframeUrl)
// #endif
// 统一更新状态
this.isPlaying = true
this.status = '播放中'
this.error = false
// 触发状态变化事件
this.$emit('playStateChange', true)
console.log('[简单播放器] 播放状态已更新为:播放中')
} catch (error) {
console.error('[简单播放器] 开始播放失败:', error)
this.error = true
this.errorText = '播放失败: ' + error.message
}
},
// 统一的暂停播放逻辑
pausePlayback() {
console.log('[简单播放器] 暂停播放')
try {
// 清空播放URL - 两个平台使用相同的逻辑
// #ifdef APP-PLUS
this.webviewUrl = ''
console.log('[简单播放器] APP平台 - 清空webviewUrl')
// #endif
// #ifdef H5
this.iframeUrl = ''
console.log('[简单播放器] H5平台 - 清空iframeUrl')
// #endif
// 统一更新状态
this.isPlaying = false this.isPlaying = false
this.status = '已暂停' this.status = '已暂停'
// 触发状态变化事件 // 触发状态变化事件
this.$emit('playStateChange', false) this.$emit('playStateChange', false)
} else { console.log('[简单播放器] 播放状态已更新为:已暂停')
// 播放重新设置URL
if (this.config) { } catch (error) {
// #ifdef APP-PLUS console.error('[简单播放器] 暂停播放失败:', error)
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 = '播放中'
// 触发状态变化事件
this.$emit('playStateChange', true)
}
} }
// 返回新的播放状态
return this.isPlaying
}, },
// 获取当前播放状态 // 获取当前播放状态
@ -249,18 +297,89 @@ export default {
return this.isPlaying return this.isPlaying
}, },
// 刷新播放器 // 统一的刷新播放器逻辑
refresh() { refresh() {
console.log('[简单播放器] 刷新播放器') console.log('[简单播放器] 刷新播放器')
if (this.config) { if (!this.config) {
console.error('[简单播放器] 配置信息不存在,无法刷新')
uni.showToast({
title: '配置信息不存在',
icon: 'error',
duration: 2000
})
return
}
try {
// 显示刷新提示
uni.showToast({ uni.showToast({
title: '正在刷新...', title: '正在刷新...',
icon: 'loading', icon: 'loading',
duration: 1000 duration: 1000
}) })
// 先清空再重新加载 // 重置播放器状态
this.error = false
this.loading = true
this.loadingText = '重新加载中...'
// 先暂停播放
this.pausePlayback()
// 延迟重新开始播放,确保清空操作完成
setTimeout(() => {
try {
// 重新开始播放
this.startPlayback()
// 显示成功提示
uni.showToast({
title: '刷新成功',
icon: 'success',
duration: 1500
})
// 重置加载状态
setTimeout(() => {
this.loading = false
this.loadingText = '加载中...'
}, 1000)
} catch (error) {
console.error('[简单播放器] 重新播放失败:', error)
this.loading = false
this.error = true
this.errorText = '刷新失败: ' + error.message
uni.showToast({
title: '刷新失败',
icon: 'error',
duration: 2000
})
}
}, 500)
} catch (error) {
console.error('[简单播放器] 刷新播放器失败:', error)
this.loading = false
this.error = true
this.errorText = '刷新失败: ' + error.message
uni.showToast({
title: '刷新失败',
icon: 'error',
duration: 2000
})
}
},
// 停止播放器(页面关闭时调用)
stopPlayer() {
console.log('[简单播放器] 停止播放器')
try {
// 清空播放URL停止播放
// #ifdef APP-PLUS // #ifdef APP-PLUS
this.webviewUrl = '' this.webviewUrl = ''
// #endif // #endif
@ -268,33 +387,18 @@ export default {
this.iframeUrl = '' this.iframeUrl = ''
// #endif // #endif
setTimeout(() => { // 重置状态
// #ifdef APP-PLUS this.isPlaying = false
const token = encodeURIComponent(this.config.accessToken) this.status = '已停止'
const url = encodeURIComponent(this.config.play_url) this.loading = false
this.webviewUrl = `/static/html/ezviz-iframe.html?accessToken=${token}&playUrl=${url}` this.error = false
// #endif
// 触发状态变化事件
// #ifdef H5 this.$emit('playStateChange', false)
this.iframeUrl = 'https://open.ys7.com/ezopen/h5/iframe?' +
'url=' + encodeURIComponent(this.config.play_url) + console.log('[简单播放器] 播放器已停止')
'&accessToken=' + encodeURIComponent(this.config.accessToken) + } catch (error) {
'&width=100%' + console.error('[简单播放器] 停止播放器失败:', error)
'&height=100%' +
'&autoplay=1' +
'&audio=1' +
'&controls=1'
// #endif
this.isPlaying = true
this.status = '播放中'
uni.showToast({
title: '刷新成功',
icon: 'success',
duration: 1500
})
}, 500)
} }
} }
} }
@ -473,5 +577,107 @@ export default {
.refresh-btn:active { .refresh-btn:active {
background: rgba(25, 118, 210, 1); background: rgba(25, 118, 210, 1);
} }
/* 统一的控制按钮样式 - APP平台使用 cover-view */
.control-buttons-cover {
position: fixed;
top: 50%;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 20rpx;
z-index: 999;
}
.control-btn-cover {
background: rgba(0, 0, 0, 0.75);
border: 2rpx solid rgba(255, 255, 255, 0.6);
border-radius: 40rpx;
padding: 16rpx 32rpx;
min-width: 140rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.play-btn-cover {
background: rgba(46, 125, 50, 0.85);
border-color: rgba(76, 175, 80, 0.9);
}
.refresh-btn-cover {
background: rgba(25, 118, 210, 0.85);
border-color: rgba(33, 150, 243, 0.9);
}
.btn-text {
color: white;
font-size: 24rpx;
font-weight: 600;
text-align: center;
}
/* 统一的控制按钮样式 - H5平台使用 view */
.control-buttons-unified {
position: fixed;
top: 50%;;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 20rpx;
z-index: 999;
}
.control-btn-unified {
background: rgba(0, 0, 0, 0.75);
border: 2rpx solid rgba(255, 255, 255, 0.6);
border-radius: 40rpx;
padding: 16rpx 32rpx;
min-width: 140rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
user-select: none;
}
.control-btn-unified:hover {
transform: scale(1.05);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.3);
}
.control-btn-unified:active {
transform: scale(0.95);
}
.play-btn-unified {
background: rgba(46, 125, 50, 0.85);
border-color: rgba(76, 175, 80, 0.9);
}
.play-btn-unified:hover {
background: rgba(46, 125, 50, 0.95);
border-color: rgba(76, 175, 80, 1);
}
.refresh-btn-unified {
background: rgba(25, 118, 210, 0.85);
border-color: rgba(33, 150, 243, 0.9);
}
.refresh-btn-unified:hover {
background: rgba(25, 118, 210, 0.95);
border-color: rgba(33, 150, 243, 1);
}
.btn-text-unified {
color: white;
font-size: 24rpx;
font-weight: 600;
text-align: center;
pointer-events: none;
}
</style> </style>

View File

@ -337,12 +337,20 @@ export default {
onShow() { onShow() {
console.log('📱 环境参数页面显示,触发页面更新'); console.log('📱 环境参数页面显示,触发页面更新');
this.init(); this.init();
// 重新启动定时器
this.startDataFetching();
// // 只有在非首次显示时才重新获取最新空调温度 // // 只有在非首次显示时才重新获取最新空调温度
// if (this.hasCreatedStartupEvent) { // if (this.hasCreatedStartupEvent) {
// this.init(); // this.init();
// } // }
}, },
onHide() {
console.log('📱 环境参数页面隐藏,停止定时器');
// 页面隐藏时停止定时器
this.stopDataFetching();
},
onUnload() { onUnload() {
console.log('📱 环境参数页面卸载,清理所有资源');
// 页面卸载时移除监听器 // 页面卸载时移除监听器
if (this.dataUpdateHandler) { if (this.dataUpdateHandler) {
mqttDataManager.removeListener('dataUpdate', this.dataUpdateHandler) mqttDataManager.removeListener('dataUpdate', this.dataUpdateHandler)
@ -356,10 +364,8 @@ export default {
clearInterval(this.debugInterval) clearInterval(this.debugInterval)
} }
// 清理数据获取定时器 // 停止数据获取定时器
if (this.dataFetchInterval) { this.stopDataFetching()
clearInterval(this.dataFetchInterval)
}
}, },
methods: { methods: {
init() { init() {
@ -368,11 +374,10 @@ export default {
// 获取最新温湿度数据 // 获取最新温湿度数据
this.getLatestEnvironmentData() this.getLatestEnvironmentData()
// 首次进入系统时创建启动事件 // 首次进入系统时创建启动事件
this.createStartupEventIfNeeded() // this.createStartupEventIfNeeded()
// 获取温湿度区间设置 // 获取温湿度区间设置
this.loadWsdSettings() this.loadWsdSettings()
// 启动定时获取环境数据 // 注意:定时器在 onShow 中启动,避免重复启动
this.startDataFetching()
}, },
// 首次进入系统时创建启动事件 // 首次进入系统时创建启动事件
async createStartupEventIfNeeded() { async createStartupEventIfNeeded() {
@ -582,12 +587,18 @@ export default {
clearInterval(this.dataFetchInterval) clearInterval(this.dataFetchInterval)
} }
// 每3秒获取一次最新环境数据 // 每5秒获取一次最新环境数据
this.dataFetchInterval = setInterval(() => { this.dataFetchInterval = setInterval(() => {
this.getLatestEnvironmentData() this.getLatestEnvironmentData()
}, 5000) }, 5000)
},
console.log('🔄 已启动环境数据定时获取间隔3秒')
// 停止定时获取环境数据
stopDataFetching() {
if (this.dataFetchInterval) {
clearInterval(this.dataFetchInterval)
this.dataFetchInterval = null
}
}, },
// 初始化MQTT监听 // 初始化MQTT监听
@ -660,8 +671,6 @@ export default {
// 检查MQTT空调数据的报警条件 // 检查MQTT空调数据的报警条件
checkAlerts(mqttData) { checkAlerts(mqttData) {
const currentTime = this.formatDateTime(new Date()) const currentTime = this.formatDateTime(new Date())
console.log('====MQTT空调数据报警检查', mqttData)
// 只处理空调AC设备的数据 // 只处理空调AC设备的数据
if (mqttData.deviceType === 'AC') { if (mqttData.deviceType === 'AC') {
// 空调故障报警acFaultStatus为1 // 空调故障报警acFaultStatus为1
@ -684,8 +693,6 @@ export default {
// 检查从接口获取的数据的报警条件 // 检查从接口获取的数据的报警条件
checkAlertsFromApiData(apiData) { checkAlertsFromApiData(apiData) {
const currentTime = this.formatDateTime(new Date()) const currentTime = this.formatDateTime(new Date())
console.log('====API数据报警检查', apiData)
const { temperature, humidity, pm25 } = apiData const { temperature, humidity, pm25 } = apiData
// 1. 温度报警:使用环境控制设置的区间 // 1. 温度报警:使用环境控制设置的区间
@ -761,10 +768,7 @@ export default {
// 记录报警到控制台并调用创建告警接口 // 记录报警到控制台并调用创建告警接口
async logAlert(alert) { async logAlert(alert) {
console.log('🚨 报警触发:', JSON.stringify(alert, null, 2))
// 调用创建告警接口
try { try {
console.log('📤 正在创建告警记录...')
await alertApi.create(alert) await alertApi.create(alert)
} catch (error) { } catch (error) {
console.error('❌ 告警记录创建失败:', error) console.error('❌ 告警记录创建失败:', error)
@ -774,9 +778,12 @@ export default {
// 降低目标温度 // 降低目标温度
decreaseTemperature() { decreaseTemperature() {
if (this.targetTemperature > 16) { if (this.targetTemperature > 16) {
const oldTemp = this.targetTemperature
this.targetTemperature-- this.targetTemperature--
console.log('目标温度降低至:', this.targetTemperature + '°C') console.log('目标温度降低至:', this.targetTemperature + '°C')
this.showTemperatureChangeToast() this.showTemperatureChangeToast()
// 记录温度调节日志
this.logTemperatureAdjustment('降低', oldTemp, this.targetTemperature)
} else { } else {
uni.showToast({ uni.showToast({
title: '温度不能低于16°C', title: '温度不能低于16°C',
@ -807,8 +814,11 @@ export default {
if (this.tempValidationMessage === '') { if (this.tempValidationMessage === '') {
// 如果没有验证错误,更新目标温度 // 如果没有验证错误,更新目标温度
if (!isNaN(value)) { if (!isNaN(value)) {
const oldTemp = this.targetTemperature
this.targetTemperature = value this.targetTemperature = value
this.showTemperatureChangeToast() this.showTemperatureChangeToast()
// 记录温度调节日志
this.logTemperatureAdjustment('设置', oldTemp, this.targetTemperature)
} }
this.tempInputValue = '' this.tempInputValue = ''
} else { } else {
@ -859,9 +869,12 @@ export default {
// 提高目标温度 // 提高目标温度
increaseTemperature() { increaseTemperature() {
if (this.targetTemperature < 50) { if (this.targetTemperature < 50) {
const oldTemp = this.targetTemperature
this.targetTemperature++ this.targetTemperature++
console.log('目标温度提高至:', this.targetTemperature + '°C') console.log('目标温度提高至:', this.targetTemperature + '°C')
this.showTemperatureChangeToast() this.showTemperatureChangeToast()
// 记录温度调节日志
this.logTemperatureAdjustment('提高', oldTemp, this.targetTemperature)
} else { } else {
uni.showToast({ uni.showToast({
title: '温度不能高于50°C', title: '温度不能高于50°C',
@ -873,9 +886,12 @@ export default {
// 降低目标湿度 // 降低目标湿度
decreaseHumidity() { decreaseHumidity() {
if (this.targetHumidity > 30) { if (this.targetHumidity > 30) {
const oldHumidity = this.targetHumidity
this.targetHumidity-- this.targetHumidity--
console.log('目标湿度降低至:', this.targetHumidity + '%') console.log('目标湿度降低至:', this.targetHumidity + '%')
this.showHumidityChangeToast() this.showHumidityChangeToast()
// 记录湿度调节日志
this.logHumidityAdjustment('降低', oldHumidity, this.targetHumidity)
} else { } else {
uni.showToast({ uni.showToast({
title: '湿度不能低于30%', title: '湿度不能低于30%',
@ -887,9 +903,12 @@ export default {
// 提高目标湿度 // 提高目标湿度
increaseHumidity() { increaseHumidity() {
if (this.targetHumidity < 80) { if (this.targetHumidity < 80) {
const oldHumidity = this.targetHumidity
this.targetHumidity++ this.targetHumidity++
console.log('目标湿度提高至:', this.targetHumidity + '%') console.log('目标湿度提高至:', this.targetHumidity + '%')
this.showHumidityChangeToast() this.showHumidityChangeToast()
// 记录湿度调节日志
this.logHumidityAdjustment('提高', oldHumidity, this.targetHumidity)
} else { } else {
uni.showToast({ uni.showToast({
title: '湿度不能高于80%', title: '湿度不能高于80%',
@ -920,8 +939,11 @@ export default {
if (this.humidityValidationMessage === '') { if (this.humidityValidationMessage === '') {
// 如果没有验证错误,更新目标湿度 // 如果没有验证错误,更新目标湿度
if (!isNaN(value)) { if (!isNaN(value)) {
const oldHumidity = this.targetHumidity
this.targetHumidity = value this.targetHumidity = value
this.showHumidityChangeToast() this.showHumidityChangeToast()
// 记录湿度调节日志
this.logHumidityAdjustment('设置', oldHumidity, this.targetHumidity)
} }
this.humidityInputValue = '' this.humidityInputValue = ''
} else { } else {
@ -1002,14 +1024,14 @@ export default {
// 发送温度参数 - 使用BSQWD作为TagName与接收数据保持一致 // 发送温度参数 - 使用BSQWD作为TagName与接收数据保持一致
const temperatureData = { const temperatureData = {
"TagValue": this.targetTemperature, "TagValue": this.targetTemperature,
"TagName": "JS_COD", // 使用与接收数据一致的TagName "TagName": "SDWD", // 使用与接收数据一致的TagName
"method": "setValue" "method": "setValue"
} }
// 发送湿度参数 - 根据文档WSD设备湿度使用SD // 发送湿度参数 - 根据文档WSD设备湿度使用SD
const humidityData = { const humidityData = {
"TagValue": this.targetHumidity, "TagValue": this.targetHumidity,
"TagName": "JS_SD", // 使用与WSD设备湿度一致的TagName "TagName": "SDSD", // 使用与WSD设备湿度一致的TagName
"method": "setValue" "method": "setValue"
} }
@ -1109,16 +1131,83 @@ export default {
eventType: `空调${operation}`, eventType: `空调${operation}`,
eventTime: currentTime, eventTime: currentTime,
status: "已完成", status: "已完成",
description: `用户手动执行空调${operation}操作`, description: `用户手动执行空调${operation}操作,当前温度:${this.temperature}°C目标温度${this.targetTemperature}°C空调状态${this.acStatusList[this.acStatus]}`,
deviceId: "AC_001" deviceId: "AC_001"
} }
console.log(`📝 记录空调${operation}日志:`, logEvent) const response = await eventApi.create(logEvent)
// const response = await eventApi.create(logEvent)
console.log(`✅ 空调${operation}日志记录成功:`, response) // 显示日志记录成功提示
uni.showToast({
title: `操作日志已保存`,
icon: 'success',
duration: 1000
})
} catch (error) { } catch (error) {
console.error(`❌ 空调${operation}日志记录失败:`, error) console.error(`❌ 空调${operation}日志记录失败:`, error)
// 日志记录失败不影响主要功能,只记录错误 // 日志记录失败不影响主要功能,只记录错误
uni.showToast({
title: `日志保存失败`,
icon: 'none',
duration: 1000
})
}
},
// 记录温度调节日志
async logTemperatureAdjustment(action, oldTemp, newTemp) {
try {
const currentTime = this.formatDateTime(new Date())
const logEvent = {
eventType: `空调目标温度${action}`,
eventTime: currentTime,
status: "已完成",
description: `用户手动${action}空调目标温度,从${oldTemp}°C调整到${newTemp}°C当前环境温度${this.temperature}°C空调状态${this.acStatusList[this.acStatus]}`,
deviceId: "AC_001"
}
const response = await eventApi.create(logEvent)
} catch (error) {
console.error(`❌ 温度${action}日志记录失败:`, error)
// 日志记录失败不影响主要功能,只记录错误
}
},
// 记录湿度调节日志
async logHumidityAdjustment(action, oldHumidity, newHumidity) {
try {
const currentTime = this.formatDateTime(new Date())
const logEvent = {
eventType: `空调目标湿度${action}`,
eventTime: currentTime,
status: "已完成",
description: `用户手动${action}空调目标湿度,从${oldHumidity}%调整到${newHumidity}%,当前环境湿度:${this.humidity}%,空调状态:${this.acStatusList[this.acStatus]}`,
deviceId: "AC_001"
}
const response = await eventApi.create(logEvent)
} catch (error) {
console.error(`❌ 湿度${action}日志记录失败:`, error)
// 日志记录失败不影响主要功能,只记录错误
}
},
// 记录参数设定保存日志
async logSettingsSave() {
try {
const currentTime = this.formatDateTime(new Date())
const logEvent = {
eventType: "环境控制范围更新",
eventTime: currentTime,
status: "已完成",
description: `用户修改温湿度控制范围:温度范围${this.tempSettings.min}°C-${this.tempSettings.max}°C湿度范围${this.humiditySettings.min}%-${this.humiditySettings.max}%,当前环境温度:${this.temperature}°C当前环境湿度${this.humidity}%,空调状态:${this.acStatusList[this.acStatus]}`,
deviceId: "WSD_001"
}
const response = await eventApi.create(logEvent)
} catch (error) {
console.error(`❌ 参数设定保存日志记录失败:`, error)
// 日志记录失败不影响主要功能,只记录错误
} }
}, },
@ -1236,6 +1325,9 @@ export default {
// 关闭弹窗 // 关闭弹窗
this.closeSettingsModal() this.closeSettingsModal()
// 记录参数设定保存日志
await this.logSettingsSave()
// 显示保存成功提示 // 显示保存成功提示
uni.showToast({ uni.showToast({
title: '参数设置已保存', title: '参数设置已保存',

View File

@ -938,23 +938,23 @@ export default {
// 创建查询事件 // 创建查询事件
async createQueryEvent(status, dataCount) { async createQueryEvent(status, dataCount) {
try { // try {
const currentTime = this.formatDateTime(new Date()) // const currentTime = this.formatDateTime(new Date())
const queryEvent = { // const queryEvent = {
eventType: "参数记录查询", // eventType: "参数记录查询",
eventTime: currentTime, // eventTime: currentTime,
status: this.getEventStatus(status), // status: this.getEventStatus(status),
description: this.getEventDescription(status, dataCount), // description: this.getEventDescription(status, dataCount),
deviceId: "PARAMETER_QUERY_001" // deviceId: "PARAMETER_QUERY_001"
} // }
console.log('📤 提交查询事件:', queryEvent) // console.log('📤 提交查询事件:', queryEvent)
const response = await eventApi.create(queryEvent) // const response = await eventApi.create(queryEvent)
console.log('✅ 查询事件创建成功:', response) // console.log('✅ 查询事件创建成功:', response)
} catch (error) { // } catch (error) {
console.error('❌ 查询事件创建失败:', error) // console.error('❌ 查询事件创建失败:', error)
} // }
}, },
// 获取事件状态 // 获取事件状态

View File

@ -98,6 +98,14 @@ export default {
// 可以在这里添加重新连接摄像头等逻辑 // 可以在这里添加重新连接摄像头等逻辑
this.getVideoData() this.getVideoData()
}, },
onUnload() {
console.log('📱 视觉监控页面卸载,停止播放器')
this.stopVideoPlayer()
},
onHide() {
console.log('📱 视觉监控页面隐藏,停止播放器')
this.stopVideoPlayer()
},
methods: { methods: {
// 切换调试模式 // 切换调试模式
toggleDebug() { toggleDebug() {
@ -222,6 +230,26 @@ export default {
duration: 3000 duration: 3000
}) })
} }
},
// 停止视频播放器
stopVideoPlayer() {
try {
// 检查播放器组件是否存在
if (this.$refs.playerVideoRef) {
// 调用播放器组件的停止方法
this.$refs.playerVideoRef.stopPlayer()
} else {
console.log('⚠️ 播放器组件不存在,无需停止')
}
// 重置页面状态
this.ezstate = false
this.videoLoaded = false
this.isPlaying = false
} catch (error) {
console.error('❌ 停止视频播放器失败:', error)
}
} }
} }
} }

View File

@ -27,6 +27,69 @@
object-fit: contain; /* 保持视频比例,不变形 */ object-fit: contain; /* 保持视频比例,不变形 */
} }
/* 简化的控制按钮样式 */
.control-buttons {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 16px;
z-index: 999;
pointer-events: auto;
}
.control-btn {
background: rgba(0, 0, 0, 0.7);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 25px;
padding: 12px 20px;
min-width: 100px;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
color: white;
font-size: 14px;
font-weight: 500;
text-align: center;
}
.control-btn:active {
background: rgba(0, 0, 0, 0.8);
}
.play-btn {
background: rgba(76, 175, 80, 0.8);
border-color: rgba(76, 175, 80, 0.9);
}
.play-btn:active {
background: rgba(76, 175, 80, 0.9);
}
.refresh-btn {
background: rgba(33, 150, 243, 0.8);
border-color: rgba(33, 150, 243, 0.9);
}
.refresh-btn:active {
background: rgba(33, 150, 243, 0.9);
}
/* 按钮图标样式 */
.btn-icon {
margin-right: 6px;
font-size: 16px;
display: inline-block;
}
.btn-text {
font-weight: 500;
}
.loading { .loading {
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -56,11 +119,56 @@
@keyframes spin { @keyframes spin {
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }
/* 简化的暂停占位符样式 */
.pause-placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 50%;
background: #000000;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 5;
}
.pause-content {
text-align: center;
color: white;
}
.pause-title {
font-size: 18px;
font-weight: 400;
color: white;
}
</style> </style>
</head> </head>
<body> <body>
<div class="loading" id="loading">正在加载播放器...</div> <div class="loading" id="loading">正在加载播放器...</div>
<iframe id="player-iframe" allow="autoplay; fullscreen"></iframe> <iframe id="player-iframe" allow="autoplay; fullscreen"></iframe>
<!-- 暂停时的占位符 -->
<div class="pause-placeholder" id="pause-placeholder">
<div class="pause-content">
<div class="pause-title">监控已暂停</div>
</div>
</div>
<!-- 控制按钮 -->
<div class="control-buttons" id="control-buttons" style="display: none;">
<div class="control-btn play-btn" id="play-btn">
<span class="btn-icon" id="play-icon">▶️</span>
<span class="btn-text" id="play-text">播放</span>
</div>
<div class="control-btn refresh-btn" id="refresh-btn">
<span class="btn-icon">🔄</span>
<span class="btn-text">刷新</span>
</div>
</div>
<script> <script>
function log(message) { function log(message) {
@ -80,14 +188,20 @@
function init() { function init() {
log('初始化开始'); log('初始化开始');
const config = getConfig(); const configData = getConfig();
if (!config.accessToken || !config.playUrl) { if (!configData.accessToken || !configData.playUrl) {
log('配置参数不完整'); log('配置参数不完整');
document.getElementById('loading').textContent = '配置参数错误'; document.getElementById('loading').textContent = '配置参数错误';
return; return;
} }
// 保存配置到全局变量
config = {
accessToken: configData.accessToken,
playUrl: configData.playUrl
};
log('AccessToken: ' + config.accessToken.substring(0, 20) + '...'); log('AccessToken: ' + config.accessToken.substring(0, 20) + '...');
log('PlayUrl: ' + config.playUrl); log('PlayUrl: ' + config.playUrl);
@ -107,10 +221,16 @@
const iframe = document.getElementById('player-iframe'); const iframe = document.getElementById('player-iframe');
iframe.src = iframeUrl; iframe.src = iframeUrl;
// 隐藏loading // 设置初始播放状态
isPlaying = true;
document.getElementById('play-text').textContent = '暂停';
document.getElementById('play-icon').textContent = '⏸️';
// 隐藏loading显示控制按钮
setTimeout(() => { setTimeout(() => {
document.getElementById('loading').style.display = 'none'; document.getElementById('loading').style.display = 'none';
log('播放器加载完成'); document.getElementById('control-buttons').style.display = 'flex';
log('播放器加载完成,显示控制按钮');
}, 2000); }, 2000);
} catch (error) { } catch (error) {
@ -119,11 +239,132 @@
} }
} }
// 全局状态
let isPlaying = true;
let config = null;
// 播放/暂停控制
function togglePlay() {
log('切换播放状态: ' + (isPlaying ? '暂停' : '播放'));
const iframe = document.getElementById('player-iframe');
const playText = document.getElementById('play-text');
const playIcon = document.getElementById('play-icon');
const pausePlaceholder = document.getElementById('pause-placeholder');
if (isPlaying) {
// 暂停清空iframe显示占位符
iframe.src = 'about:blank';
pausePlaceholder.style.display = 'flex';
playText.textContent = '播放';
playIcon.textContent = '▶️';
isPlaying = false;
log('已暂停播放,显示占位符');
} else {
// 播放重新设置iframe URL隐藏占位符
if (config) {
const iframeUrl = 'https://open.ys7.com/ezopen/h5/iframe?' +
'url=' + encodeURIComponent(config.playUrl) +
'&accessToken=' + encodeURIComponent(config.accessToken) +
'&width=100%' +
'&height=100%' +
'&autoplay=1' +
'&audio=1' +
'&controls=1';
iframe.src = iframeUrl;
pausePlaceholder.style.display = 'none';
playText.textContent = '暂停';
playIcon.textContent = '⏸️';
isPlaying = true;
log('已开始播放,隐藏占位符');
}
}
}
// 刷新播放器
function refreshPlayer() {
log('刷新播放器');
const iframe = document.getElementById('player-iframe');
const playText = document.getElementById('play-text');
const playIcon = document.getElementById('play-icon');
const pausePlaceholder = document.getElementById('pause-placeholder');
// 先清空,显示加载状态
iframe.src = 'about:blank';
pausePlaceholder.style.display = 'none';
// 延迟重新加载
setTimeout(() => {
if (config) {
const iframeUrl = 'https://open.ys7.com/ezopen/h5/iframe?' +
'url=' + encodeURIComponent(config.playUrl) +
'&accessToken=' + encodeURIComponent(config.accessToken) +
'&width=100%' +
'&height=100%' +
'&autoplay=1' +
'&audio=1' +
'&controls=1';
iframe.src = iframeUrl;
playText.textContent = '暂停';
playIcon.textContent = '⏸️';
isPlaying = true;
log('刷新完成');
}
}, 500);
}
// 页面加载完成后初始化 // 页面加载完成后初始化
window.onload = function() { window.onload = function() {
log('页面加载完成'); log('页面加载完成');
// 绑定按钮事件
document.getElementById('play-btn').addEventListener('click', togglePlay);
document.getElementById('refresh-btn').addEventListener('click', refreshPlayer);
init(); init();
}; };
// 页面卸载时清理资源
window.onbeforeunload = function() {
log('页面即将卸载,清理播放器资源');
try {
const iframe = document.getElementById('player-iframe');
if (iframe) {
iframe.src = 'about:blank'; // 清空iframe源
log('播放器资源已清理');
}
} catch (error) {
log('清理播放器资源失败: ' + error.message);
}
};
// 页面隐藏时暂停播放
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
log('页面隐藏,暂停播放');
try {
const iframe = document.getElementById('player-iframe');
if (iframe) {
iframe.style.display = 'none';
}
} catch (error) {
log('暂停播放失败: ' + error.message);
}
} else {
log('页面显示,恢复播放');
try {
const iframe = document.getElementById('player-iframe');
if (iframe) {
iframe.style.display = 'block';
}
} catch (error) {
log('恢复播放失败: ' + error.message);
}
}
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -69,7 +69,6 @@ class MqttDataManager {
// 检查数据是否为数组 // 检查数据是否为数组
if (Array.isArray(data)) { if (Array.isArray(data)) {
// console.log('📋 收到数组数据,长度:', data.length) // console.log('📋 收到数组数据,长度:', data.length)
// 遍历数组中的每个设备数据 // 遍历数组中的每个设备数据
data.forEach((deviceData, index) => { data.forEach((deviceData, index) => {
// console.log(`📦 处理设备数据[${index}]:`, deviceData) // console.log(`📦 处理设备数据[${index}]:`, deviceData)
@ -97,13 +96,8 @@ class MqttDataManager {
const deviceType = deviceData.Device const deviceType = deviceData.Device
const deviceDataContent = deviceData.Data const deviceDataContent = deviceData.Data
const timestamp = deviceData.timestamp || Math.floor(Date.now() / 1000) const timestamp = deviceData.timestamp || Math.floor(Date.now() / 1000)
// console.log(`🔍 处理设备类型: ${deviceType}`)
// console.log('设备数据:', deviceDataContent)
// console.log('时间戳:', timestamp)
// 处理所有设备类型的数据 // 处理所有设备类型的数据
console.log(`✅ 处理设备类型: ${deviceType}`) // console.log(`✅ 处理设备类型: ${deviceType}`)
this.processAllDeviceData(deviceType, deviceDataContent, timestamp) this.processAllDeviceData(deviceType, deviceDataContent, timestamp)
} catch (error) { } catch (error) {
console.error('❌ 处理设备数据失败:', error) console.error('❌ 处理设备数据失败:', error)
@ -113,9 +107,6 @@ class MqttDataManager {
// 处理所有设备类型的数据 // 处理所有设备类型的数据
processAllDeviceData(deviceType, data, timestamp) { processAllDeviceData(deviceType, data, timestamp) {
try { try {
console.log(`🌡️ ${deviceType}设备数据解析:`)
console.log('设备数据:', data)
// 构建基础解析数据 // 构建基础解析数据
const parsedData = { const parsedData = {
deviceType, deviceType,

View File

@ -136,13 +136,13 @@ const initEventHandleMqtt = (topicUrl) => {
// 获取信息 // 获取信息
const mqttData = JSON.parse(message.toString()); const mqttData = JSON.parse(message.toString());
console.log('📋 解析后的数据:', mqttData); // console.log('📋 解析后的数据:', mqttData);
// 如果是数组,打印数组信息 // 如果是数组,打印数组信息
if (Array.isArray(mqttData)) { if (Array.isArray(mqttData)) {
mqttData.forEach((item, index) => { mqttData.forEach((item, index) => {
if (item.Device) { if (item.Device) {
console.log(`🔍 设备类型[${index}]: ${item.Device}`); // console.log(`🔍 设备类型[${index}]: ${item.Device}`);
} }
}); });
} }