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 })