From 0ffa67da6557a0a24e892da71c2fa70fa6e691bb Mon Sep 17 00:00:00 2001 From: Guoguo Date: Wed, 10 Jun 2026 08:16:17 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20implement=20MVP=20Phase=201=20=E2=80=94?= =?UTF-8?q?=20full-area=20scan=20with=20ADC=20data=20collection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Send scan command: all 5 regions LED on, brightness 128 - Listen for ADC notify (17 bytes) instead of broken queryStatus - Parse and display PD1-PD7 values with visual bars - Show VBAT/battery info - Store scan PD data in globalData for Phase 3 smart adjustment - 8s timeout fallback, stop LED on page unload --- miniprogram/pages/auto-scan/auto-scan.js | 111 ++++++++++------- miniprogram/pages/auto-scan/auto-scan.wxml | 37 +++--- miniprogram/pages/auto-scan/auto-scan.wxss | 138 ++++++++++++++------- 3 files changed, 185 insertions(+), 101 deletions(-) diff --git a/miniprogram/pages/auto-scan/auto-scan.js b/miniprogram/pages/auto-scan/auto-scan.js index b81dd8d..ea824c4 100644 --- a/miniprogram/pages/auto-scan/auto-scan.js +++ b/miniprogram/pages/auto-scan/auto-scan.js @@ -1,12 +1,17 @@ var ble = require('../../services/ble') +var SCAN_BRIGHTNESS = 128 +var SCAN_TIMEOUT = 8000 + Page({ data: { statusBarHeight: 44, scanning: true, scanProgress: 0, - regions: 0x7F, - regionData: [], - timeout: false, + regions: 0x1F, + pdValues: [], + pdRaw: [], + vbat: 0, + battery: 0, error: '' }, @@ -22,72 +27,88 @@ Page({ var app = getApp() this.setData({ statusBarHeight: app.globalData.statusBarHeight, - regions: parseInt(options.regions) || 0x7F + regions: parseInt(options.regions) || 0x1F }) this.startScan() }, startScan: function () { var self = this - self.setData({ scanning: true, scanProgress: 0, timeout: false }) + self.setData({ scanning: true, scanProgress: 0, error: '', pdValues: [] }) this._progressTimer = setInterval(function () { - var p = self.data.scanProgress + 2 - if (p > 98) p = 98 + var p = self.data.scanProgress + 1 + if (p > 90) p = 90 self.setData({ scanProgress: p }) - }, 100) + }, 80) - this._onStatus = function (status) { - if (status.mode_state === 0x01) { - self.setData({ scanProgress: 50 }) - } else if (status.mode_state === 0x04 || status.mode_state === 0x00) { - clearInterval(self._progressTimer) - self.setData({ scanning: false, scanProgress: 100 }) - var names = ble.getRegionName(status.region_mask || 0x7F) - self.setData({ regionData: self.parseScanResults(names) }) - } + this._onAdc = function (data) { + console.log('[SCAN] 收到ADC数据:', JSON.stringify(data)) + clearInterval(self._progressTimer) + clearTimeout(self._timeoutTimer) + self.setData({ scanning: false, scanProgress: 100 }) + self._handleAdcData(data) } - ble.on('status', this._onStatus) + ble.on('adc', this._onAdc) - ble.queryStatus().catch(function () {}) + console.log('[SCAN] 下发扫描指令: 全域亮度', SCAN_BRIGHTNESS) + ble.setParams({ + region_mask: 0x1F, + wavelength: 2, + brightness: SCAN_BRIGHTNESS, + hold_time: 10 + }).then(function () { + console.log('[SCAN] 扫描指令发送成功,等待ADC回传...') + }).catch(function (err) { + console.error('[SCAN] 扫描指令发送失败:', err) + self.setData({ error: '扫描指令发送失败' }) + }) - setTimeout(function () { + this._timeoutTimer = setTimeout(function () { clearInterval(self._progressTimer) if (!self.data.scanning) return + console.log('[SCAN] 等待ADC超时,使用默认值') self.setData({ scanning: false, scanProgress: 100 }) - var names = ble.getRegionName(self.data.regions || 0x7F) - self.setData({ regionData: self.parseScanResults(names) }) - }, 5000) + self._handleAdcData(null) + }, SCAN_TIMEOUT) }, - parseScanResults: function (regions) { - return regions.map(function (name) { - return { region: name, pd: '待检测' } - }) + _handleAdcData: function (data) { + var regionNames = ['右区(IO1)', '左区(IO2)', '上区(IO3)', '中区(IO4)', '下区(IO5)'] + var pdValues = [] + + if (data && data.pd && data.pd.length >= 7) { + this.setData({ pdRaw: data.pd, vbat: data.vbat || 0, battery: data.battery || 0 }) + for (var i = 0; i < 5; i++) { + pdValues.push({ region: regionNames[i], pd: data.pd[i], pdText: String(data.pd[i]) }) + } + pdValues.push({ region: 'PD6', pd: data.pd[5], pdText: String(data.pd[5]) }) + pdValues.push({ region: 'PD7', pd: data.pd[6], pdText: String(data.pd[6]) }) + + getApp().globalData.lastScanPd = data.pd + getApp().globalData.lastScanVbat = data.vbat + } else { + for (var j = 0; j < 5; j++) { + pdValues.push({ region: regionNames[j], pd: 0, pdText: '未采集' }) + } + } + + this.setData({ pdValues: pdValues }) }, onUnload: function () { if (this._progressTimer) clearInterval(this._progressTimer) - if (this._onStatus) ble.off('status', this._onStatus) + if (this._timeoutTimer) clearTimeout(this._timeoutTimer) + if (this._onAdc) ble.off('adc', this._onAdc) + ble.stopTreatment().catch(function () {}) }, onNext: function () { - var mask = this.data.regions || 0x7F - ble.setParams({ - region_mask: mask, - wavelength: 2, - brightness: 200, - duration_ms: 600000, - mode: 1 - }).then(function () { - return ble.startTreatment(mask) - }).then(function () { - wx.redirectTo({ - url: '/pages/treating/treating?regions=' + mask + '&wavelength=2&duration=600000&mode=1' - }) - }).catch(function (err) { - wx.showToast({ title: err.error_msg || '启动失败', icon: 'none' }) + var mask = this.data.regions || 0x1F + var pdRaw = this.data.pdRaw + var pdParam = pdRaw.length > 0 ? '&pd=' + encodeURIComponent(JSON.stringify(pdRaw)) : '' + wx.redirectTo({ + url: '/pages/treatment-setup/treatment-setup?regions=' + mask + pdParam }) - }, - + } }) diff --git a/miniprogram/pages/auto-scan/auto-scan.wxml b/miniprogram/pages/auto-scan/auto-scan.wxml index 09584e7..0b3bbfc 100644 --- a/miniprogram/pages/auto-scan/auto-scan.wxml +++ b/miniprogram/pages/auto-scan/auto-scan.wxml @@ -1,30 +1,39 @@ ‹ 返回 - 自动扫描 - 正在识别区域... + 区域扫描 + {{scanning ? '正在采集数据...' : '扫描完成'}} - 自动扫描区域 - - + + + + + 全域LED已开启,亮度 128,等待PD数据回传... - 请正确佩戴设备 - 连接设备后可获取检测数据 - - - 正在扫描... {{regionData.length || 3}} 个区域 + + PD 采集结果 + + + {{item.region}} + {{item.pdText}} + + + + + + + 电池电压: {{vbat}}mV ({{battery}}%) + - - {{item.region}} - + {{error}} - + diff --git a/miniprogram/pages/auto-scan/auto-scan.wxss b/miniprogram/pages/auto-scan/auto-scan.wxss index 6bf4134..9ec41f5 100644 --- a/miniprogram/pages/auto-scan/auto-scan.wxss +++ b/miniprogram/pages/auto-scan/auto-scan.wxss @@ -1,13 +1,13 @@ .scan-container { - position: relative; - width: 320rpx; - height: 400rpx; - margin: 40rpx auto; + display: flex; + flex-direction: column; + align-items: center; + padding: 20rpx 0; } .face-outline { - width: 100%; - height: 100%; + width: 320rpx; + height: 400rpx; border: 6rpx solid #e5e5e5; border-radius: 50% 50% 45% 45%; position: relative; @@ -29,49 +29,103 @@ 100% { top: calc(100% - 6rpx); opacity: 0.5; } } -.scan-hint { - text-align: center; - font-size: 26rpx; - color: #666666; - margin-bottom: 24rpx; +.scan-progress-bar { + width: 80%; + height: 8rpx; + background: #f0f0f0; + border-radius: 4rpx; + margin-top: 30rpx; + overflow: hidden; } -.scan-progress { - text-align: center; - background: #f0f9ff; - padding: 16rpx 28rpx; - border-radius: 24rpx; - font-size: 26rpx; - color: #006699; - width: fit-content; - margin: 0 auto; +.scan-progress-fill { + height: 100%; + background: linear-gradient(90deg, #E6508C, #DCB982); + border-radius: 4rpx; + transition: width 0.3s; } -.highlight { - color: #E6508C; - font-weight: 600; -} - -.detected-tags { - text-align: center; - margin-top: 24rpx; -} - -.detected-tag { - background: #fdf2f8; - border: 2rpx solid #E6508C; - color: #E6508C; - padding: 10rpx 24rpx; - border-radius: 24rpx; +.scan-status { font-size: 24rpx; - display: inline-block; - margin: 6rpx; - animation: tagPulse 1s ease-in-out; + color: #999; + margin-top: 16rpx; + text-align: center; } -@keyframes tagPulse { - 0%, 100% { transform: scale(1); } - 50% { transform: scale(1.05); } +.scan-result { + background: #fff; + border-radius: 20rpx; + padding: 24rpx; + margin-top: 20rpx; +} + +.result-title { + font-size: 28rpx; + font-weight: 600; + color: #333; + margin-bottom: 20rpx; +} + +.pd-list { + display: flex; + flex-direction: column; + gap: 16rpx; +} + +.pd-item { + display: flex; + align-items: center; + gap: 16rpx; +} + +.pd-region { + font-size: 26rpx; + color: #666; + width: 160rpx; + flex-shrink: 0; +} + +.pd-value { + font-size: 28rpx; + font-weight: 600; + color: #E6508C; + width: 100rpx; + flex-shrink: 0; + text-align: right; +} + +.pd-empty { + color: #ccc; + font-weight: normal; +} + +.pd-bar-bg { + flex: 1; + height: 16rpx; + background: #f5f5f5; + border-radius: 8rpx; + overflow: hidden; +} + +.pd-bar-fill { + height: 100%; + background: linear-gradient(90deg, #E6508C, #DCB982); + border-radius: 8rpx; + min-width: 4rpx; +} + +.vbat-info { + margin-top: 20rpx; + font-size: 24rpx; + color: #999; + text-align: center; +} + +.scan-error { + text-align: center; + color: #ff4d4f; + font-size: 26rpx; + margin-top: 20rpx; } .btn-primary::after {