diff --git a/pages/basics/BluetoothDebugging/B13page/B13page.js b/pages/basics/BluetoothDebugging/B13page/B13page.js index 0f9eb8d..5ecd4ad 100644 --- a/pages/basics/BluetoothDebugging/B13page/B13page.js +++ b/pages/basics/BluetoothDebugging/B13page/B13page.js @@ -38,6 +38,8 @@ Page({ // 条件“有无人标记”选项,参考截图:无人至有人/短暂离开/长时间离开/有人至无人 tagOptions: ['无人至有人', '短暂离开', '长时间离开', '有人至无人'], stateOptions: ['不判断', '触发', '释放', '关至开', '开至关'], + // 门磁专用选项(与其他端口不同):0=不判断,1=关门,2=开门,3=关至开,4=开至关 + doorMagOptions: ['不判断', '关门', '开门', '关至开', '开至关'], // 默认条件:由用户指定的条件组与条件 conditions: [ // 组1: timeout 2秒,包含1个条件 @@ -49,11 +51,11 @@ Page({ // 组3: timeout 2秒,包含1个条件 { group: 3, seq: 1, tag: 1, cardPower: 0, doorMag: 4, irHall: 0, bathRadar: 0, bathroomRadar: 0, judgeTime: 0, judgeUnit: 0, timeout: 2, timeoutUnit: 0 }, // 组4: timeout 10分,包含1个条件 - { group: 4, seq: 1, tag: 1, cardPower: 0, doorMag: 3, irHall: 2, bathRadar: 2, bathroomRadar: 2, judgeTime: 2, judgeUnit: 1, timeout: 10, timeoutUnit: 1 }, + { group: 4, seq: 1, tag: 1, cardPower: 0, doorMag: 1, irHall: 2, bathRadar: 2, bathroomRadar: 2, judgeTime: 2, judgeUnit: 1, timeout: 10, timeoutUnit: 1 }, // 组5: timeout 10分,包含1个条件 - { group: 5, seq: 1, tag: 2, cardPower: 0, doorMag: 3, irHall: 2, bathRadar: 2, bathroomRadar: 2, judgeTime: 2, judgeUnit: 1, timeout: 10, timeoutUnit: 1 }, + { group: 5, seq: 1, tag: 2, cardPower: 0, doorMag: 1, irHall: 2, bathRadar: 2, bathroomRadar: 2, judgeTime: 2, judgeUnit: 1, timeout: 10, timeoutUnit: 1 }, // 组6: timeout 10分,包含1个条件 - { group: 6, seq: 1, tag: 3, cardPower: 0, doorMag: 3, irHall: 2, bathRadar: 2, bathroomRadar: 2, judgeTime: 2, judgeUnit: 1, timeout: 10, timeoutUnit: 1 } + { group: 6, seq: 1, tag: 3, cardPower: 0, doorMag: 1, irHall: 2, bathRadar: 2, bathroomRadar: 2, judgeTime: 2, judgeUnit: 1, timeout: 10, timeoutUnit: 1 } ], // 二级菜单:按组折叠 condGroups: [], @@ -78,7 +80,7 @@ Page({ // 门磁/卫浴事件控件数据(仅保留 秒 / 分) eventUnits: ['秒', '分'], // 雷达读取状态:false=未读取, true=正在读取 - radarReading: false, + radarReading: true, // 门磁 doorTriggerDelay: 0, doorTriggerUnitIndex: 0, @@ -249,6 +251,13 @@ Page({ if (id === 2) { this.onSendReadVersion() } + // 切换到设备升级标签(data-id === 3)时,默认发送一包 OTA 升级命令 + if (id === 3) { + // 给用户一点缓冲时间再发送(确保 UI 切换完成) + // setTimeout(() => { + // this.onStartOta() + // }, 200) + } }, onOpenDelayChange(e) { @@ -294,9 +303,10 @@ Page({ // 通过 picker index 推导真实数值(index + 1) const opts = { door: { - triggerDelay: Number((d.doorTriggerIndex || 0) + 1), + // use the actual delay value (can be 0) instead of index+1 + triggerDelay: Number(d.doorTriggerDelay || 0), triggerUnit: mapUnit(d.doorTriggerUnitIndex), - releaseDelay: Number((d.doorReleaseIndex || 0) + 1), + releaseDelay: Number(d.doorReleaseDelay || 0), releaseUnit: mapUnit(d.doorReleaseUnitIndex) }, bath: null @@ -344,9 +354,9 @@ Page({ const opts = { door: null, bath: { - triggerDelay: Number((d.bathTriggerIndex || 0) + 1), + triggerDelay: Number(d.bathTriggerDelay || 0), triggerUnit: mapUnit(d.bathTriggerUnitIndex), - releaseDelay: Number((d.bathReleaseIndex || 0) + 1), + releaseDelay: Number(d.bathReleaseDelay || 0), releaseUnit: mapUnit(d.bathReleaseUnitIndex) } } @@ -851,7 +861,7 @@ Page({ // 开启订阅(若已传入rx特征),保证能接收数据 this.enableNotify() this.setupBleListener() - // this.sendRadarStatusCommand(true) + this.sendRadarStatusCommand(true) }, enableNotify() { @@ -1033,6 +1043,7 @@ Page({ */ setupBleListener() { // 移除旧监听,防止重复触发(页面重复进入或多次初始化的场景) + this.teardownBleListener() // 运行环境不支持通知回调则直接返回(避免报错) if (typeof wx.onBLECharacteristicValueChange !== 'function') return @@ -1073,7 +1084,23 @@ Page({ // 注册系统 BLE 通知回调 wx.onBLECharacteristicValueChange(this._onBleChange) }, - + onDownloadOtaTool() { + const url = 'https://www.baidu.com/'; + if (wx && wx.setClipboardData) { + wx.setClipboardData({ + data: url, + success() { + wx.showToast({ title: '下载链接已复制到剪贴板', icon: 'none' }); + }, + fail() { + wx.showModal({ title: '提示', content: '无法复制链接,请手动访问:' + url, showCancel: false }); + } + }); + } else { + // fallback + wx.showModal({ title: '提示', content: '下载链接:' + url, showCancel: false }); + } + }, teardownBleListener() { if (this._onBleChange && typeof wx.offBLECharacteristicValueChange === 'function') { wx.offBLECharacteristicValueChange(this._onBleChange) @@ -1145,39 +1172,61 @@ Page({ }, updateRadarLights(bits) { - // 更新雷达指示灯数组(保持原有展示) - const next = (this.data.radarLights || []).map((it, idx) => { - const triggered = ((bits >> idx) & 0x01) === 1 - return { - ...it, - triggered, - colorClass: triggered ? 'red' : 'green' + // 节流更新:合并高频上报,避免频繁 setData 导致 UI 卡顿 + try { + const now = Date.now() + const throttleMs = 200 + if (!this._lastRadarUpdateTime || (now - this._lastRadarUpdateTime) >= throttleMs) { + // 直接更新 + this._lastRadarUpdateTime = now + const next = (this.data.radarLights || []).map((it, idx) => { + const triggered = ((bits >> idx) & 0x01) === 1 + return Object.assign({}, it, { triggered, colorClass: triggered ? 'red' : 'green' }) + }) + const doorTriggered = ((bits >> 0) & 0x01) === 1 + const bathTriggered = ((bits >> 1) & 0x01) === 1 + const bedTriggered = ((bits >> 2) & 0x01) === 1 + const hallTriggered = ((bits >> 3) & 0x01) === 1 + const cardClasses = { + roomHasPeople: (bedTriggered || hallTriggered) ? 'orange' : 'gray', + roomNoPeople: (!bedTriggered && !hallTriggered) ? 'green' : 'gray', + doorOpen: (!doorTriggered) ? 'red' : 'gray', + doorClose: (doorTriggered) ? 'green' : 'gray', + bathHasPeople: (bathTriggered) ? 'blue' : 'gray', + bathNoPeople: (!bathTriggered) ? 'green' : 'gray' + } + this.setData({ radarLights: next, cardClasses }) + } else { + // 延迟更新到节流窗口结束,使用最新 bits + this._pendingRadarBits = bits + if (this._radarUpdateTimer) clearTimeout(this._radarUpdateTimer) + this._radarUpdateTimer = setTimeout(() => { + try { + const b = this._pendingRadarBits || 0 + this._lastRadarUpdateTime = Date.now() + const next = (this.data.radarLights || []).map((it, idx) => { + const triggered = ((b >> idx) & 0x01) === 1 + return Object.assign({}, it, { triggered, colorClass: triggered ? 'red' : 'green' }) + }) + const doorTriggered = ((b >> 0) & 0x01) === 1 + const bathTriggered = ((b >> 1) & 0x01) === 1 + const bedTriggered = ((b >> 2) & 0x01) === 1 + const hallTriggered = ((b >> 3) & 0x01) === 1 + const cardClasses = { + roomHasPeople: (bedTriggered || hallTriggered) ? 'orange' : 'gray', + roomNoPeople: (!bedTriggered && !hallTriggered) ? 'green' : 'gray', + doorOpen: (!doorTriggered) ? 'red' : 'gray', + doorClose: (doorTriggered) ? 'green' : 'gray', + bathHasPeople: (bathTriggered) ? 'blue' : 'gray', + bathNoPeople: (!bathTriggered) ? 'green' : 'gray' + } + this.setData({ radarLights: next, cardClasses }) + } catch (e) { /* ignore */ } + }, throttleMs) } - }) - - // 解析位值(约定:bit0=门磁, bit1=卫浴, bit2=卧室, bit3=走廊) - const doorTriggered = ((bits >> 0) & 0x01) === 1 - const bathTriggered = ((bits >> 1) & 0x01) === 1 - const bedTriggered = ((bits >> 2) & 0x01) === 1 - const hallTriggered = ((bits >> 3) & 0x01) === 1 - - // 计算卡片显示规则:默认灰色,按需求将对应卡片设色 - const cardClasses = { - // 房间有人:卧室或走廊任一触发 -> 橙色,否则灰色 - roomHasPeople: (bedTriggered || hallTriggered) ? 'orange' : 'gray', - // 房间无人:卧室和走廊均处于释放 -> 绿色,否则灰色 - roomNoPeople: (!bedTriggered && !hallTriggered) ? 'green' : 'gray', - // 门开:门磁释放 -> 红色,否则灰色 - doorOpen: (!doorTriggered) ? 'red' : 'gray', - // 门关:门磁触发 -> 绿色,否则灰色 - doorClose: (doorTriggered) ? 'green' : 'gray', - // 卫浴有人:卫浴触发 -> 蓝色,否则灰色 - bathHasPeople: (bathTriggered) ? 'blue' : 'gray', - // 卫浴无人:卫浴释放 -> 绿色,否则灰色 - bathNoPeople: (!bathTriggered) ? 'green' : 'gray' + } catch (e) { + try { console.warn('updateRadarLights error', e) } catch (xx) { /* ignore */ } } - - this.setData({ radarLights: next, cardClasses }) }, // 数值约束 @@ -1400,6 +1449,94 @@ Page({ wx.showToast({ title: '端口配置已发送', icon: 'success' }) }, + // 仅下发端口配置(参考一键下发,但只发送 0x09 端口包) + onSendPorts() { + const sendPorts = async () => { + try { + this.appendLog('UI', '操作: 端口下发(开始)') + // 标准化 ports:缺失 deviceType/deviceAddr 时写入默认值 + try { + const rawPorts = Array.isArray(this.data.ports) ? this.data.ports : [] + let changed = false + const normalized = rawPorts.map((p) => { + const np = { ...p } + if (np.deviceType == null || np.deviceType === 0) { + if (np.deviceType !== 2) { np.deviceType = 2; changed = true } + } + if (np.deviceAddr == null || np.deviceAddr === 0) { + if (np.deviceAddr !== 1) { np.deviceAddr = 1; changed = true } + } + return np + }) + if (changed) { + try { this.setData({ ports: normalized }) } catch (e) { /* ignore */ } + } + } catch (e) { /* ignore normalization error */ } + + const ports = Array.isArray(this.data.ports) ? this.data.ports : [] + const portPkts = [] + for (let i = 0; i < ports.length; i++) { + const p = ports[i] + const P0 = (p && p.deviceType) ? (p.deviceType & 0xFF) : 0 + const P1 = (p && p.deviceAddr) ? (p.deviceAddr & 0xFF) : 0 + const loopLE = [((p && p.loop) || 0) & 0xFF, (((p && p.loop) || 0) >>> 8) & 0xFF] + const P4 = ((p && p.thresholdDown) || 0) & 0xFF + const P5 = this.getVirtualPort(p, i) + const P6 = (p && p.enabled) ? 0x01 : 0x00 + const dtLE = [((p && p.detectTime) || 0) & 0xFF, ((((p && p.detectTime) || 0) >>> 8) & 0xFF)] + const P9 = (this.normalizeUnitForPacket ? this.normalizeUnitForPacket((p && p.detectUnit) || 0) : this.unitIndexToProtocolValue((p && p.detectUnit) || 0)) & 0xFF + const P10 = ((p && p.thresholdUp) || 0) & 0xFF + const payload = [P0, P1, ...loopLE, P4, P5, P6, ...dtLE, P9, P10] + const pkt = buildCommand(COMMANDS.SET_CONDITION_2, payload, { frame: i + 1, framNum: ports.length }) + portPkts.push({ pkt, label: `端口 ${p && p.name || (i+1)}` }) + this.appendLog('TX', `端口配置[${p && p.name || (i+1)}]: ${this.toHex(pkt)}`) + } + + try { this.enableNotify() } catch (e) { /* ignore */ } + + const sendWithRetry = async (pktObj, cmdType) => { + const maxRetries = 3 + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + const waitPromise = this.waitForResponse(cmdType, 3000) + try { await this.writeRawBytes(pktObj.pkt, pktObj.label) } catch (writeErr) { + if (this._pendingResponse && typeof this._pendingResponse.reject === 'function') { + try { this._pendingResponse.reject(new Error('写入失败')) } catch (e) { /* ignore */ } + this._pendingResponse = null + } + throw writeErr + } + const params = await waitPromise + if (params && params.length > 0 && (params[0] & 0xFF) === 0x01) { + this.appendLog('UI', `${pktObj.label} 下发成功 (attempt ${attempt})`) + await new Promise(r => setTimeout(r, 100)) + return true + } else { + throw new Error('设备返回失败或参数不正确') + } + } catch (err) { + this.appendLog('WARN', `${pktObj.label} 发送 attempt ${attempt} 失败: ${err && (err.message || err)}`) + if (attempt < maxRetries) { await new Promise(r => setTimeout(r, 200)); continue } + throw new Error(`${pktObj.label} 下发失败`) + } + } + } + + for (let i = 0; i < portPkts.length; i++) { + const obj = portPkts[i] + await sendWithRetry(obj, COMMANDS.SET_CONDITION_2 & 0xFF) + } + + wx.showToast({ title: '端口下发完成', icon: 'success' }) + this.appendLog('UI', '端口下发完成') + } catch (err) { + wx.showToast({ title: '端口下发失败', icon: 'none' }) + this.appendLog('WARN', `端口下发失败: ${err && (err.message || err)}`) + } + } + sendPorts() + }, + // 读取端口配置(占位示例,后续可接入真实读取命令) onReadPorts() { this.appendLog('UI', '请求读取端口配置') @@ -1473,6 +1610,89 @@ Page({ wx.showToast({ title: '条件配置已发送', icon: 'success' }) }, + // 仅下发条件配置(参考一键下发,但只发送 0x08 条件包) + onSendConditions() { + const sendConds = async () => { + try { + this.appendLog('UI', '操作: 条件下发(开始)') + // 扁平化 condGroups 并兼容旧字段名 + const flat = [] + ;(this.data.condGroups || []).forEach(grp => { + (grp.items || []).forEach(it => { + const item = { ...it, group: grp.group, timeout: grp.timeout, timeoutUnit: grp.timeoutUnit } + if (item.tag == null && (item.cardPower != null)) item.tag = item.cardPower + if (item.judgeUnit == null) item.judgeUnit = (item.judgeUnit === 0 ? 0 : 2) + if (item.timeoutUnit == null) item.timeoutUnit = (item.timeoutUnit === 0 ? 0 : 2) + flat.push(item) + }) + }) + + const condPkts = [] + for (let i = 0; i < flat.length; i++) { + const c = flat[i] + const P0 = (typeof this.tagIndexToProtocolValue === 'function' ? this.tagIndexToProtocolValue((c && c.tag) || 0) : (((c && c.tag) || 0) + 1)) & 0xFF + const P1 = ((c && c.group) || 0) & 0xFF + const P2 = ((c && c.seq) || 0) & 0xFF + const jtLE = [((c && c.judgeTime) || 0) & 0xFF, (((c && c.judgeTime) || 0) >>> 8) & 0xFF] + const P5 = (typeof this.normalizeUnitForPacket === 'function') ? (this.normalizeUnitForPacket((c && c.judgeUnit) || 0) & 0xFF) : (((c && c.judgeUnit) || 0) & 0xFF) + const P6 = ((c && c.cardPower) || 0) & 0xFF + const P7 = ((c && c.doorMag) || 0) & 0xFF + const P8 = ((c && c.bathRadar) || 0) & 0xFF + const P9 = ((c && c.bathroomRadar) || 0) & 0xFF + const P10 = ((c && c.irHall) || 0) & 0xFF + const toLE = [((c && c.timeout) || 0) & 0xFF, ((((c && c.timeout) || 0) >>> 8) & 0xFF)] + const P13 = (typeof this.normalizeUnitForPacket === 'function') ? (this.normalizeUnitForPacket((c && c.timeoutUnit) || 0) & 0xFF) : (((c && c.timeoutUnit) || 0) & 0xFF) + const payload = [P0, P1, P2, ...jtLE, P5, P6, P7, P8, P9, P10, ...toLE, P13] + const pkt = buildCommand(COMMANDS.SET_CONDITION_1, payload, { frame: i + 1, framNum: flat.length }) + condPkts.push({ pkt, label: `条件 ${c && c.group || ''}-${c && c.seq || i+1}` }) + this.appendLog('TX', `条件配置[组${c.group}/序${c.seq}]: ${this.toHex(pkt)}`) + } + + try { this.enableNotify() } catch (e) { /* ignore */ } + + const sendWithRetry = async (pktObj, cmdType) => { + const maxRetries = 3 + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + const waitPromise = this.waitForResponse(cmdType, 3000) + try { await this.writeRawBytes(pktObj.pkt, pktObj.label) } catch (writeErr) { + if (this._pendingResponse && typeof this._pendingResponse.reject === 'function') { + try { this._pendingResponse.reject(new Error('写入失败')) } catch (e) { /* ignore */ } + this._pendingResponse = null + } + throw writeErr + } + const params = await waitPromise + if (params && params.length > 0 && (params[0] & 0xFF) === 0x01) { + this.appendLog('UI', `${pktObj.label} 下发成功 (attempt ${attempt})`) + await new Promise(r => setTimeout(r, 100)) + return true + } else { + throw new Error('设备返回失败或参数不正确') + } + } catch (err) { + this.appendLog('WARN', `${pktObj.label} 发送 attempt ${attempt} 失败: ${err && (err.message || err)}`) + if (attempt < maxRetries) { await new Promise(r => setTimeout(r, 200)); continue } + throw new Error(`${pktObj.label} 下发失败`) + } + } + } + + for (let i = 0; i < condPkts.length; i++) { + const obj = condPkts[i] + await sendWithRetry(obj, COMMANDS.SET_CONDITION_1 & 0xFF) + } + + wx.showToast({ title: '条件下发完成', icon: 'success' }) + this.appendLog('UI', '条件下发完成') + } catch (err) { + wx.showToast({ title: '条件下发失败', icon: 'none' }) + this.appendLog('WARN', `条件下发失败: ${err && (err.message || err)}`) + } + } + sendConds() + }, + // 功能栏:删除条件组 onDeleteCondGroup() { const groups = (this.data.condGroups || []).map(g => String(g.group)) @@ -2280,8 +2500,16 @@ Page({ } catch (e) { /* ignore console errors */ } const id = `${Date.now()}-${Math.random().toString(16).slice(2)}` - const next = [{ id, time: timeStr, text: finalText }, ...this.data.logList] - - this.setData({ logList: next }) + // 限制日志长度,避免无限增长导致 setData 负担和内存问题(保留最新200条) + try { + const maxLogs = 200 + const cur = Array.isArray(this.data.logList) ? this.data.logList : [] + const next = [{ id, time: timeStr, text: finalText }, ...cur] + if (next.length > maxLogs) next.length = maxLogs + this.setData({ logList: next }) + } catch (e) { + // 若 setData 出现异常,仍保证不抛到外层 + try { console.warn('appendLog setData failed', e) } catch (xx) { /* ignore */ } + } } }) diff --git a/pages/basics/BluetoothDebugging/B13page/B13page.wxml b/pages/basics/BluetoothDebugging/B13page/B13page.wxml index d904555..9ab67ea 100644 --- a/pages/basics/BluetoothDebugging/B13page/B13page.wxml +++ b/pages/basics/BluetoothDebugging/B13page/B13page.wxml @@ -9,23 +9,21 @@ - 蓝牙调试 - 蓝牙升级 + 设备测试 + 设备配置 + 设备升级 - + - + @@ -79,11 +77,14 @@ - 门磁开廊灯事件设置 + 门磁开廊灯事件设置 + + + - 触发延迟 + 开门延时 {{doorTriggerOptions[doorTriggerIndex]}} @@ -91,7 +92,7 @@ {{eventUnits[doorTriggerUnitIndex]}} - 释放延迟 + 关门延时 {{doorReleaseOptions[doorReleaseIndex]}} @@ -105,7 +106,10 @@ - 卫浴雷达开卫浴灯事件设置 + 卫浴雷达开卫浴灯事件设置 + + + @@ -133,7 +137,10 @@ 通讯日志 - 清空 + + + + @@ -168,8 +175,9 @@ - + + @@ -205,6 +213,7 @@ 端口配置 + @@ -252,6 +261,7 @@ 条件配置 + @@ -275,7 +285,7 @@ - + @@ -322,8 +332,8 @@ - - {{stateOptions[it.doorMag]}} + + {{doorMagOptions[it.doorMag]}} @@ -397,5 +407,29 @@ - + + + + + + OTA 升级工具 + + + + + + 1. 升级工具下载: + + + 2. 安装软件 + 3. 点击 OTA 按钮,发送 OTA 升级命令 + 4. 打开下载的 【OTA 升级工具】 + 5. 蓝牙连接名称:OTAOTA_OTAOTA_OTA + 6. 连接后点击 GETINFO,再点击 IMAGEA + 7. 选择升级固件后,点击最下面的 START 按钮,再选择芯片 “CH573” 开始升级 + 下载链接: https://www.baidu.com/ (点击“下载工具”将复制链接) + + + + \ No newline at end of file diff --git a/pages/basics/BluetoothDebugging/B13page/B13page.wxss b/pages/basics/BluetoothDebugging/B13page/B13page.wxss index 388629d..bd724fa 100644 --- a/pages/basics/BluetoothDebugging/B13page/B13page.wxss +++ b/pages/basics/BluetoothDebugging/B13page/B13page.wxss @@ -26,7 +26,7 @@ .icon.gray { background: #9aa0a6; } .icon { overflow: hidden; display:flex; align-items:center; justify-content:center; } .icon-img { width: 100%; height: 100%; display: block; } -.card-title { font-size: 24rpx; color: #555; } +.card-title { font-size: 22rpx; color: #555; } /* 按下效果 */ .card.pressed { transform: translateY(4rpx) scale(0.985); filter: brightness(0.94); box-shadow: none; } @@ -41,6 +41,28 @@ .log-head .title { font-size: 26rpx; color: #333; } .log-head .action { font-size: 24rpx; color: #2bab99; } +/* 日志头按钮组:读雷达 与 清空 按钮并列样式 */ +.log-head .log-actions { display:flex; align-items:center; gap: 8rpx; } +.log-head .log-actions .radar-btn { + padding: 0 16rpx; + height: 48rpx; + line-height: 48rpx; + border-radius: 12rpx; + font-size: 22rpx; +} +.log-head .log-actions .clear-btn { + padding: 0 16rpx; + min-width: 130rpx; + height: 48rpx; + line-height: 48rpx; + border-radius: 12rpx; + font-size: 22rpx; + background: #ffffff !important; + color: #2bab99 !important; + border: 1rpx solid rgba(43,171,153,0.18) !important; +} +.log-head .log-actions .clear-btn:active { opacity: 0.9 } + .log-options { display: flex; flex-wrap: nowrap; gap: 14rpx; } .log-options .option { display: flex; align-items: center; font-size: 24rpx; color: #555; white-space: nowrap; } .log-options checkbox { margin-right: 10rpx; transform: scale(0.9); } @@ -62,6 +84,13 @@ .dr-btn-view:active { opacity: 0.85; } /* 顶部操作按钮:紧凑内间距,适配工具栏顶部的多个小按钮 */ +.top-actions { + display: flex; + justify-content: flex-end; + gap: 6rpx; + padding: 4rpx 6rpx; +} + .top-actions button { padding: 0 10rpx; height: 58rpx; @@ -192,6 +221,23 @@ .log-text { display: block; font-size: 24rpx; color: #333; word-break: break-all; } .log-empty { font-size: 24rpx; color: #9aa0a6; text-align: center; padding: 20rpx 0; } +/* group toggle button (triangle) styling */ +.group-toggle { + padding: 0 8rpx !important; + width: 52rpx !important; + height: 40rpx !important; + line-height: 40rpx !important; + font-size: 26rpx !important; + border-radius: 8rpx !important; + background: transparent !important; + color: #0ea5e9 !important; + border: 1rpx solid rgba(14,165,233,0.14) !important; +} +.group-toggle:active { background: rgba(14,165,233,0.06) !important; } + +/* 收窄条件组超时输入宽度 */ +.cond-card .group-time input.picker-text { width: 80rpx; padding: 0 6rpx; box-sizing: border-box; } + /* Inline form for trigger/release delay - keep controls on one row on mobile */ .form-row { display:block; } .form-inline { display:flex; align-items:center; gap: 10rpx; flex-wrap: nowrap; } diff --git a/pages/basics/BluetoothDebugging/BluetoothDebugging.js b/pages/basics/BluetoothDebugging/BluetoothDebugging.js index 803f689..5945e98 100644 --- a/pages/basics/BluetoothDebugging/BluetoothDebugging.js +++ b/pages/basics/BluetoothDebugging/BluetoothDebugging.js @@ -261,9 +261,8 @@ Page({ const withParams = (svc && tx && rx) ? `${base}&serviceId=${encodeURIComponent(svc)}&txCharId=${encodeURIComponent(tx)}&rxCharId=${encodeURIComponent(rx)}` : base - console.log(url) - console.log(withParams) - wx.navigateTo({ url: withParams }) + console.log('navigateTo:', withParams) + wx.navigateTo({ url: withParams })