From 4c674e5c239605c67d1737881da35afb1fc9f81c Mon Sep 17 00:00:00 2001 From: Guoguo Date: Mon, 22 Jun 2026 06:28:25 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20address=20audit=20findings=20=E2=80=94?= =?UTF-8?q?=20fitting=20trigger,=20race=20guards,=20state=20conflicts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wear-check: - Send weak pulse light (brightness=26) to trigger FFE4 fitting report - Timeout degrades to pass (backward compat with 17-byte firmware) - Sync _resolved flag prevents double-resolve treating: - Only treat run_state=0x00 as completion after seeing run_state=0x02 (prevents false completion on startup) - Sync _finishing flag replaces async data.completed for race prevention - onStatus preserves paused state during fitting loss (|| fittingLost) - Remove dead _fittingTimer reference from onUnload auto-scan: - Sync _completed flag in _scanComplete prevents double-build --- miniprogram/pages/auto-scan/auto-scan.js | 3 +++ miniprogram/pages/treating/treating.js | 17 +++++++++++------ miniprogram/pages/wear-check/wear-check.js | 19 +++++++++++++++++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/miniprogram/pages/auto-scan/auto-scan.js b/miniprogram/pages/auto-scan/auto-scan.js index 761d506..61d6f92 100644 --- a/miniprogram/pages/auto-scan/auto-scan.js +++ b/miniprogram/pages/auto-scan/auto-scan.js @@ -43,6 +43,7 @@ Page({ startScan: function () { var self = this self._scanResults = [] + self._completed = false if (!ble.isConnected()) { self.setData({ scanning: false, error: '设备未连接,请先连接设备' }) @@ -110,6 +111,8 @@ Page({ }, _scanComplete: function () { + if (this._completed) return + this._completed = true this._cleanup() this.setData({ scanning: false, scanProgress: 100 }) this._buildDisplay() diff --git a/miniprogram/pages/treating/treating.js b/miniprogram/pages/treating/treating.js index 54ff11a..073a1f4 100644 --- a/miniprogram/pages/treating/treating.js +++ b/miniprogram/pages/treating/treating.js @@ -84,7 +84,6 @@ Page({ 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) { @@ -99,10 +98,15 @@ Page({ }, onRunState: function (data) { - if (this.data.completed) return + if (this._finishing) return console.log('[TREAT] run_state:', data.run_state) - if (data.run_state === 0xFF) { + if (data.run_state === 0x02) { + this._seenTreating = true + } + + if (data.run_state === 0xFF && !this._finishing) { + this._finishing = true this.setData({ deviceFault: true }) var self = this wx.showModal({ @@ -114,7 +118,7 @@ Page({ return } - if (data.run_state === 0x00 && !this.data.paused && !this.data.fittingLost) { + if (data.run_state === 0x00 && this._seenTreating && !this.data.fittingLost) { this.finishAsComplete() } }, @@ -170,7 +174,7 @@ Page({ this.setData({ battery: status.battery || this.data.battery, temperature: status.temperature || this.data.temperature, - paused: status.mode_state === 0x03 + paused: status.mode_state === 0x03 || this.data.fittingLost }) this.syncCommands() }, @@ -239,7 +243,8 @@ Page({ }, finishAsComplete: function () { - if (this.data.completed) return + if (this._finishing) return + this._finishing = true var elapsed = Math.min(this.data.duration, Date.now() - this.data.startedAt) this.syncTreatmentEnd(elapsed) this.onComplete({ diff --git a/miniprogram/pages/wear-check/wear-check.js b/miniprogram/pages/wear-check/wear-check.js index d077149..d74bf50 100644 --- a/miniprogram/pages/wear-check/wear-check.js +++ b/miniprogram/pages/wear-check/wear-check.js @@ -42,6 +42,7 @@ Page({ checkWearing: function () { var self = this self._cleanup() + self._resolved = false self.setData({ checking: true, result: null, error: '' }) if (!ble.isConnected()) { @@ -57,18 +58,32 @@ Page({ ble.on('battery', self._onBattery) self._onFitting = function (data) { + if (self._resolved) return console.log('[WEAR] 贴合状态:', data.fitting) if (data.fitting === 1) { + self._resolved = true self._cleanup() self.setData({ checking: false, result: 'ok' }) } } ble.on('fitting', self._onFitting) + ble.setParams({ + region_mask: 0x1F, + wavelength: 2, + brightness: 26, + hold_time: 0, + control: 0x01 + }).then(function () { + console.log('[WEAR] 微弱光贴合检测指令已发送') + }).catch(function () {}) + self._fittingTimer = setTimeout(function () { - if (self.data.result) return + if (self._resolved) return + self._resolved = true self._cleanup() - self.setData({ checking: false, result: 'fail', error: '未检测到贴合,请确认设备已正确佩戴' }) + console.log('[WEAR] 超时未收到 fitting 事件,降级为通过(兼容旧固件)') + self.setData({ checking: false, result: 'ok' }) }, FITTING_TIMEOUT) },