feat: treating page monitors fitting/run_state and handles safety events

- Listen for 'fitting' event: detect skin detachment, pause on loss,
  resume on re-attach
- Listen for 'run_state' event: detect device fault (0xFF) and IDLE
  completion (0x00)
- Low battery warnings: toast at <=10%, force stop at <=5%
- Guard finishAsComplete against double-completion
- Proper cleanup of all new event listeners on unload
这个提交包含在:
Guoguo
2026-06-22 06:21:59 -07:00
父节点 f4e74e9460
当前提交 c5a9e89bd9
+64 -4
查看文件
@@ -17,6 +17,8 @@ Page({
completed: false,
startedAt: 0,
regionText: '全区域',
fittingLost: false,
deviceFault: false
},
_getRegionText: function (regionMask) {
@@ -44,15 +46,18 @@ Page({
regionText: this._getRegionText(regions)
})
this._sessionId = 'SESS_' + Date.now()
this._onStatus = this.onStatus.bind(this)
this._onBattery = this.onBattery.bind(this)
this._onComplete = this.onComplete.bind(this)
this._onException = this.onException.bind(this)
this._onDisconnect = this.onDisconnect.bind(this)
this._onReconnect = this.onReconnect.bind(this)
this._onReconnectFailed = this.onReconnectFailed.bind(this)
this._sessionId = 'SESS_' + Date.now()
this._onFitting = this.onFitting.bind(this)
this._onRunState = this.onRunState.bind(this)
this._onBattery = this.onBattery.bind(this)
ble.on('status', this._onStatus)
ble.on('battery', this._onBattery)
ble.on('treatment_complete', this._onComplete)
@@ -60,6 +65,9 @@ Page({
ble.on('disconnected', this._onDisconnect)
ble.on('reconnected', this._onReconnect)
ble.on('reconnect_failed', this._onReconnectFailed)
ble.on('fitting', this._onFitting)
ble.on('run_state', this._onRunState)
this.startLocalTimer()
this.syncCommands()
this.syncTreatmentStart()
@@ -73,7 +81,42 @@ Page({
if (this._onDisconnect) ble.off('disconnected', this._onDisconnect)
if (this._onReconnect) ble.off('reconnected', this._onReconnect)
if (this._onReconnectFailed) ble.off('reconnect_failed', this._onReconnectFailed)
if (this._onFitting) ble.off('fitting', this._onFitting)
if (this._onRunState) ble.off('run_state', this._onRunState)
if (this._localTimer) clearInterval(this._localTimer)
if (this._fittingTimer) clearTimeout(this._fittingTimer)
},
onFitting: function (data) {
if (this.data.completed) return
if (data.fitting === 0 && !this.data.fittingLost) {
this.setData({ fittingLost: true, paused: true })
wx.showToast({ title: '检测到离肤,请重新佩戴设备', icon: 'none', duration: 3000 })
} else if (data.fitting === 1 && this.data.fittingLost) {
this.setData({ fittingLost: false, paused: false })
wx.showToast({ title: '已重新贴合,继续使用', icon: 'success', duration: 2000 })
}
},
onRunState: function (data) {
if (this.data.completed) return
console.log('[TREAT] run_state:', data.run_state)
if (data.run_state === 0xFF) {
this.setData({ deviceFault: true })
var self = this
wx.showModal({
title: '设备故障',
content: '设备上报故障,已自动停止。',
showCancel: false,
complete: function () { self.finishAsComplete() }
})
return
}
if (data.run_state === 0x00 && !this.data.paused && !this.data.fittingLost) {
this.finishAsComplete()
}
},
startLocalTimer: function () {
@@ -83,6 +126,23 @@ Page({
var elapsed = Date.now() - self.data.startedAt
var remaining = Math.max(0, self.data.duration - elapsed)
self.updateProgress(remaining)
if (self.data.battery > 0 && self.data.battery <= 5) {
clearInterval(timer)
wx.showModal({
title: '电量过低',
content: '设备电量不足5%,已自动停止。请及时充电。',
showCancel: false,
complete: function () { self.finishAsComplete() }
})
return
}
if (self.data.battery > 0 && self.data.battery <= 10 && !self._lowBatteryWarned) {
self._lowBatteryWarned = true
wx.showToast({ title: '电量低,请及时充电', icon: 'none', duration: 3000 })
}
if (remaining <= 0) {
clearInterval(timer)
self.finishAsComplete()
@@ -179,6 +239,7 @@ Page({
},
finishAsComplete: function () {
if (this.data.completed) return
var elapsed = Math.min(this.data.duration, Date.now() - this.data.startedAt)
this.syncTreatmentEnd(elapsed)
this.onComplete({
@@ -254,6 +315,5 @@ Page({
}
}
})
},
}
})