From 74b0c5fa86375dc3e594a5c852f9876114c5f56a Mon Sep 17 00:00:00 2001 From: Guoguo Date: Tue, 28 Jul 2026 06:58:03 -0700 Subject: [PATCH] feat(debug): temporary BLE debug page for on-device verification - entry in profile menu, visible only while a device is connected - live FFE4 readout: 7x PD, VBAT, fitting, scan wave marker, run state - tap a face-map region to fire a 2s single-region treat command (verifies region-to-IO mapping on the physical mask) - wavelength selector (red/ir/uv/yellow) to verify color byte order - scan command / full-face 2s / stop buttons, hex log of every write - intentionally not i18n'd; remove page before release --- miniprogram/app.json | 5 +- miniprogram/pages/ble-debug/ble-debug.js | 130 +++++++++++++++++++++ miniprogram/pages/ble-debug/ble-debug.json | 4 + miniprogram/pages/ble-debug/ble-debug.wxml | 65 +++++++++++ miniprogram/pages/ble-debug/ble-debug.wxss | 39 +++++++ miniprogram/pages/profile/profile.js | 7 ++ miniprogram/pages/profile/profile.wxml | 6 + 7 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 miniprogram/pages/ble-debug/ble-debug.js create mode 100644 miniprogram/pages/ble-debug/ble-debug.json create mode 100644 miniprogram/pages/ble-debug/ble-debug.wxml create mode 100644 miniprogram/pages/ble-debug/ble-debug.wxss diff --git a/miniprogram/app.json b/miniprogram/app.json index d82bdef..872039a 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -20,7 +20,8 @@ "pages/contact/contact", "pages/light-info/light-info", "pages/manual-treatment/manual-treatment", - "pages/scan-report/scan-report" + "pages/scan-report/scan-report", + "pages/ble-debug/ble-debug" ], "window": { "navigationBarBackgroundColor": "#ffffff", @@ -65,4 +66,4 @@ ], "style": "v2", "sitemapLocation": "sitemap.json" -} +} \ No newline at end of file diff --git a/miniprogram/pages/ble-debug/ble-debug.js b/miniprogram/pages/ble-debug/ble-debug.js new file mode 100644 index 0000000..fd2c768 --- /dev/null +++ b/miniprogram/pages/ble-debug/ble-debug.js @@ -0,0 +1,130 @@ +// TEMPORARY debug page for on-device verification (region↔IO mapping, color byte +// order, scan wave bucketing, PD polarity). Guoguo-only tooling — intentionally +// NOT i18n'd; remove this page before any release build. +var ble = require('../../services/ble') +var protocol = require('../../services/ble/protocol') + +var WAVES = [ + { key: 'red', code: 2, label: '红光' }, + { key: 'ir', code: 1, label: '红外' }, + { key: 'uv', code: 3, label: '紫外' }, + { key: 'yellow', code: 4, label: '暖黄' } +] +var REGION_LABELS = { 1: '左区/IO1', 2: '中上/IO2', 4: '中区/IO3', 8: '中下/IO4', 16: '右区/IO5' } +var RUN_STATES = { 0: 'IDLE', 1: '检测', 2: '治疗', 255: '故障(0xFF)' } + +function hex(bytes) { + return bytes.map(function (b) { return ('0' + b.toString(16)).slice(-2).toUpperCase() }).join(' ') +} + +Page({ + data: { + statusBarHeight: 44, + connected: false, + waves: WAVES, + selectedWave: 'red', + // live FFE4 status + pd: [], vbat: 0, battery: 0, fitting: -1, scanWave: '-', runState: '-', frames: 0, + logs: [] + }, + + onLoad: function () { + this.setData({ statusBarHeight: getApp().globalData.statusBarHeight }) + }, + + onShow: function () { + var self = this + self.setData({ connected: ble.isConnected() }) + self._onAdc = function (d) { + self.setData({ + pd: d.pd || [], + vbat: d.vbat || 0, + battery: d.battery || 0, + fitting: d.fitting, + scanWave: d.scan_wave || '-', + runState: RUN_STATES[d.run_state] !== undefined ? RUN_STATES[d.run_state] : String(d.run_state), + frames: self.data.frames + 1 + }) + } + ble.on('adc', self._onAdc) + }, + + onHide: function () { this._cleanup() }, + onUnload: function () { this._cleanup() }, + _cleanup: function () { + if (this._onAdc) { ble.off('adc', this._onAdc); this._onAdc = null } + }, + + onBack: function () { + wx.navigateBack({ fail: function () { wx.switchTab({ url: '/pages/profile/profile' }) } }) + }, + + _log: function (msg) { + var logs = this.data.logs + logs.unshift(new Date().toTimeString().slice(0, 8) + ' ' + msg) + if (logs.length > 20) logs.pop() + this.setData({ logs: logs }) + }, + + _send: function (label, options) { + var self = this + if (!ble.isConnected()) { + self.setData({ connected: false }) + wx.showToast({ title: '设备未连接', icon: 'none' }) + return + } + var bytes = protocol.buildVendorCommand(options) + self._log(label) + self._log('→ ' + hex(bytes)) + ble.setParams(options).then(function () { + self._log('✓ 写入成功') + }).catch(function (err) { + self._log('✗ 写入失败: ' + ((err && err.msg) || JSON.stringify(err))) + }) + }, + + onSelectWave: function (e) { + this.setData({ selectedWave: e.currentTarget.dataset.key }) + }, + + _waveCode: function () { + var key = this.data.selectedWave + for (var i = 0; i < WAVES.length; i++) if (WAVES[i].key === key) return WAVES[i].code + return 2 + }, + + // 点脸型图分区:该区 2 秒治疗(验证物理位置对不对) + onTapRegion: function (e) { + var mask = parseInt(e.currentTarget.dataset.mask) + this._send('治疗 2s ' + REGION_LABELS[mask] + ' ' + this.data.selectedWave, { + region_mask: mask, wavelength: this._waveCode(), brightness: 204, + hold_time: 2, control: 0x02 + }) + }, + + // 检测指令(与 auto-scan 同参:红光 128 全脸,设备自跑序贯扫描) + onScanCmd: function () { + this._send('检测指令 control=0x01', { + region_mask: 0x1F, wavelength: 2, brightness: 128, + hold_time: 0, control: 0x01 + }) + }, + + // 全脸当前波长 2 秒 + onTreatAll: function () { + this._send('治疗 2s 全脸 ' + this.data.selectedWave, { + region_mask: 0x1F, wavelength: this._waveCode(), brightness: 204, + hold_time: 2, control: 0x02 + }) + }, + + // 停止 / IDLE + onStop: function () { + var self = this + self._log('停止 → IDLE 全零帧') + ble.stopTreatment().then(function () { self._log('✓ 已停止') }) + .catch(function (err) { self._log('✗ 停止失败: ' + ((err && err.msg) || '')) }) + }, + + onClearLog: function () { this.setData({ logs: [], frames: 0 }) } +}) diff --git a/miniprogram/pages/ble-debug/ble-debug.json b/miniprogram/pages/ble-debug/ble-debug.json new file mode 100644 index 0000000..65aeba3 --- /dev/null +++ b/miniprogram/pages/ble-debug/ble-debug.json @@ -0,0 +1,4 @@ +{ + "navigationStyle": "custom", + "navigationBarTitleText": "调试工具" +} diff --git a/miniprogram/pages/ble-debug/ble-debug.wxml b/miniprogram/pages/ble-debug/ble-debug.wxml new file mode 100644 index 0000000..6a36630 --- /dev/null +++ b/miniprogram/pages/ble-debug/ble-debug.wxml @@ -0,0 +1,65 @@ + + + + ‹ 返回 + 调试工具(临时) + {{connected ? '设备已连接' : '设备未连接'}} + + + + + + FFE4 实时状态 ({{frames}} 帧) + + + PD{{index + 1}} + {{item}} + + + + VBAT {{vbat}}mV ({{battery}}%) + 贴合 {{fitting}} + 光色 {{scanWave}} + 状态 {{runState}} + + + + + + 波长(点分区/全脸时使用) + + {{item.label}} + + + + + + 点分区 → 该区 2 秒治疗(对物理位置) + + 中上\nIO2 + 左\nIO1 + 右\nIO5 + 中\nIO3 + 中下\nIO4 + + + + + + 指令 + + + + + + + + + + 发送日志 清空 + {{item}} + 暂无 + + + diff --git a/miniprogram/pages/ble-debug/ble-debug.wxss b/miniprogram/pages/ble-debug/ble-debug.wxss new file mode 100644 index 0000000..ba8bc0f --- /dev/null +++ b/miniprogram/pages/ble-debug/ble-debug.wxss @@ -0,0 +1,39 @@ +/* 临时调试页样式(上线前随页面一并移除) */ +.page { min-height: 100vh; background: #f5f6f8; } +.page-content { padding: 24rpx; } + +.card { background: #fff; border-radius: 24rpx; padding: 24rpx; margin-bottom: 20rpx; } +.card-title { font-size: 28rpx; font-weight: 600; color: #333; margin-bottom: 16rpx; } +.frames { font-size: 22rpx; color: #999; font-weight: 400; } + +.pd-row { display: flex; flex-wrap: wrap; gap: 12rpx; } +.pd-cell { flex: 0 0 calc((100% - 72rpx) / 7); text-align: center; background: #FAFAFA; border-radius: 12rpx; padding: 10rpx 0; } +.pd-idx { font-size: 20rpx; color: #999; } +.pd-val { font-size: 24rpx; color: #333; font-weight: 600; } +.status-row { display: flex; flex-wrap: wrap; gap: 20rpx; margin-top: 16rpx; font-size: 24rpx; color: #666; } + +.wave-row { display: flex; gap: 16rpx; } +.wave-chip { flex: 1; text-align: center; padding: 18rpx 0; border: 4rpx solid #e5e5e5; border-radius: 20rpx; font-size: 26rpx; color: #999; } +.wave-chip.active { border-color: #E6508C; background: rgba(230, 80, 140, 0.12); color: #E6508C; } + +.face-map { width: 280rpx; height: 340rpx; margin: 0 auto; position: relative; } +.face-region { + position: absolute; border: 4rpx solid #d5d5d5; border-radius: 50%; + display: flex; align-items: center; justify-content: center; text-align: center; + font-size: 22rpx; color: #666; background: #FAFAFA; white-space: pre-line; line-height: 1.3; +} +.face-region:active { background: rgba(230, 80, 140, 0.25); border-color: #E6508C; color: #E6508C; } +.face-region.forehead { top: 5%; left: 25%; width: 50%; height: 15%; border-radius: 40rpx 40rpx 50% 50%; } +.face-region.left-cheek { top: 25%; left: 5%; width: 30%; height: 25%; } +.face-region.right-cheek { top: 25%; right: 5%; width: 30%; height: 25%; } +.face-region.nose { top: 45%; left: 35%; width: 30%; height: 18%; border-radius: 40%; } +.face-region.chin { top: 68%; left: 25%; width: 50%; height: 20%; border-radius: 0 0 50% 50%; } + +.btn-row { display: flex; gap: 16rpx; } +.dbg-btn { flex: 1; font-size: 26rpx; padding: 0; line-height: 76rpx; border-radius: 20rpx; background: #4A90D9; color: #fff; } +.dbg-btn::after { border: none; } +.dbg-btn-stop { background: #E8503A; } + +.log-clear { float: right; font-size: 22rpx; color: #4A90D9; font-weight: 400; } +.log-line { font-family: monospace; font-size: 20rpx; color: #555; padding: 4rpx 0; border-bottom: 1rpx solid #f2f2f2; word-break: break-all; } +.log-empty { font-size: 22rpx; color: #bbb; } diff --git a/miniprogram/pages/profile/profile.js b/miniprogram/pages/profile/profile.js index 24d8619..ba2d113 100644 --- a/miniprogram/pages/profile/profile.js +++ b/miniprogram/pages/profile/profile.js @@ -19,6 +19,13 @@ Page({ onShow: function () { i18n.bind(this) this.loadProfile() + // 临时调试入口:仅设备已连接时显示(上线前随 ble-debug 页一并移除) + var ble = require('../../services/ble') + this.setData({ debugVisible: ble.isConnected() }) + }, + + onOpenDebug: function () { + wx.navigateTo({ url: '/pages/ble-debug/ble-debug' }) }, onLightInfo: function () { diff --git a/miniprogram/pages/profile/profile.wxml b/miniprogram/pages/profile/profile.wxml index a15ec08..cc746e9 100644 --- a/miniprogram/pages/profile/profile.wxml +++ b/miniprogram/pages/profile/profile.wxml @@ -50,6 +50,12 @@ {{i18n.profile.menuHistory}} + + + 🔧 + 调试工具(临时) + + 💳 {{i18n.profile.menuSubscription}}