From e7b40dbed662bc20f0f40b5a8cf013358a3d8ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=AE=E5=BE=AE=E4=B8=80=E7=AC=91?= <709648985@qq.com> Date: Thu, 26 Mar 2026 15:39:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D100J?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/100J/HBY100-J.js | 14 +++++- pages/100J/HBY100-J.vue | 62 ++++++++++++++++++++++----- pages/100J/audioManager/AudioList.vue | 30 +++++++++++-- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/api/100J/HBY100-J.js b/api/100J/HBY100-J.js index de32841..06dec71 100644 --- a/api/100J/HBY100-J.js +++ b/api/100J/HBY100-J.js @@ -684,10 +684,20 @@ export function deviceUpdateVolume(data) { ); } -// 语音播放 +/** 蓝牙侧语音播报:自定义音(mode=7)部分固件需先 0x0C 带模式再 0x06,否则无声音 */ +function bleVoiceBroadcastChain(data) { + const on = Number(data.voiceBroadcast) === 1; + const mode = data.mode != null ? String(data.mode) : ''; + if (on && mode === '7') { + return protocolInstance.setForceAlarm(0, 7).then(() => protocolInstance.setVoiceBroadcast(1)); + } + return protocolInstance.setVoiceBroadcast(on ? 1 : 0); +} + +// 语音播放(HTTP 透传 data,便于后端识别 mode) export function deviceVoiceBroadcast(data) { return execWithBleFirst( - () => protocolInstance.setVoiceBroadcast(data.voiceBroadcast).then(() => ({ code: 200, msg: '操作成功(蓝牙)' })), + () => bleVoiceBroadcastChain(data).then(() => ({ code: 200, msg: '操作成功(蓝牙)' })), () => request({ url: `/app/hby100j/device/voiceBroadcast`, method: 'post', data }), '语音播报' ); diff --git a/pages/100J/HBY100-J.vue b/pages/100J/HBY100-J.vue index 97bac15..dc2514b 100644 --- a/pages/100J/HBY100-J.vue +++ b/pages/100J/HBY100-J.vue @@ -469,23 +469,41 @@ const eventChannel = this.getOpenerEventChannel(); var these = this; - // 低电量提示:同一百分比不重复弹(MQTT/蓝牙反复上报时避免刷屏);恢复高于 20% 后再次降低可再提示 + // 低电量:语音上传/蓝牙分包时电量字段易抖动,防抖 + 上传中不弹,避免「发送中频繁低电量」误报 this._lastBatteryLowToastPct = null; - this.$watch("deviceInfo.batteryPercentage", (newVal) => { - const n = Number(newVal); + this._batteryLowDebounceTimer = null; + this.$watch("deviceInfo.batteryPercentage", () => { + if (bleTool.isVoiceUploading && bleTool.isVoiceUploading()) { + if (this._batteryLowDebounceTimer) { + clearTimeout(this._batteryLowDebounceTimer); + this._batteryLowDebounceTimer = null; + } + return; + } + const n = Math.round(Number(this.deviceInfo.batteryPercentage)); if (!Number.isFinite(n)) return; if (n > 20) { this._lastBatteryLowToastPct = null; + if (this._batteryLowDebounceTimer) { + clearTimeout(this._batteryLowDebounceTimer); + this._batteryLowDebounceTimer = null; + } return; } - if (n <= 20 && this._lastBatteryLowToastPct !== n) { - this._lastBatteryLowToastPct = n; + if (this._batteryLowDebounceTimer) clearTimeout(this._batteryLowDebounceTimer); + this._batteryLowDebounceTimer = setTimeout(() => { + this._batteryLowDebounceTimer = null; + if (bleTool.isVoiceUploading && bleTool.isVoiceUploading()) return; + const cur = Math.round(Number(this.deviceInfo.batteryPercentage)); + if (!Number.isFinite(cur) || cur > 20) return; + if (this._lastBatteryLowToastPct === cur) return; + this._lastBatteryLowToastPct = cur; uni.showToast({ title: '设备电量低', icon: 'none', duration: 2000 }); - } + }, 800); }); eventChannel.on('detailData', function(data) { var device = data.data; @@ -656,6 +674,10 @@ this.Status.pageHide = true; }, onUnload() { + if (this._batteryLowDebounceTimer) { + clearTimeout(this._batteryLowDebounceTimer); + this._batteryLowDebounceTimer = null; + } if (this._hby100jBleAdapterHandler && typeof uni.offBluetoothAdapterStateChange === 'function') { uni.offBluetoothAdapterStateChange(this._hby100jBleAdapterHandler); this._hby100jBleAdapterHandler = null; @@ -1035,11 +1057,11 @@ } }) } else if (isVoiceOperate) { - console.log('我是谁'); - let data = { + const data = { deviceId: this.deviceInfo.deviceId, - voiceBroadcast: Number(this.formData.sta_VoiceType) === -1 ? 0 : 1 - } + voiceBroadcast: Number(this.formData.sta_VoiceType) === -1 ? 0 : 1, + mode: this.formData.sta_VoiceType + }; deviceVoiceBroadcast(data).then((res) => { if (res.code == 200) { uni.showToast({ @@ -1052,7 +1074,25 @@ icon: 'none' }); } - }) + }).catch(() => { + uni.showToast({ title: '下发失败,请检查蓝牙或网络', icon: 'none' }); + }); + } else { + // 非强制报警态下选择内置音色:原先仅改 UI 未下发,设备无播报 + const data = { + deviceIds: [this.deviceInfo.deviceId], + voiceStrobeAlarm: 0, + mode: val + }; + deviceForceAlarmActivation(data).then((res) => { + if (res.code === 200) { + uni.showToast({ title: res.msg || '已切换', icon: 'none' }); + } else { + uni.showToast({ title: res.msg || '操作失败', icon: 'none' }); + } + }).catch(() => { + uni.showToast({ title: '下发失败,请检查蓝牙或网络', icon: 'none' }); + }); } }, // 报警模式 diff --git a/pages/100J/audioManager/AudioList.vue b/pages/100J/audioManager/AudioList.vue index 3136d07..4a5dd4e 100644 --- a/pages/100J/audioManager/AudioList.vue +++ b/pages/100J/audioManager/AudioList.vue @@ -29,8 +29,8 @@ - {{ item.useStatus == 1 ? '使用中' : '使用' }} + :class="{ 'active': isVoiceInUse(item), 'btn-default': !isVoiceInUse(item) }"> + {{ isVoiceInUse(item) ? '使用中' : '使用' }} @@ -266,7 +266,8 @@ this.total = res.total; const list = (res.data || []).map(item => ({ ...item, - createTime: item.createTime || Common.DateFormat(new Date(), "yyyy年MM月dd日") + createTime: item.createTime || Common.DateFormat(new Date(), "yyyy年MM月dd日"), + useStatus: Number(item.useStatus) === 1 ? 1 : 0 })); this.dataListA = mergeLocal(list); if (this.mescroll) this.mescroll.endBySize(this.dataListA.length, this.total + (this.dataListA.length - list.length)); @@ -496,6 +497,27 @@ this.checkList.push(item.Id); } }, + /** 与后端约定:仅 1 为使用中(避免字符串 "0" 在 class 里仍为 truthy) */ + isVoiceInUse(item) { + return Number(item && item.useStatus) === 1; + }, + /** 切换「使用」后同步整表:仅当前项为 1,其余为 0(避免第一项永远显示使用中) */ + syncVoiceListUseStatus(activeItem) { + const pickId = (o) => { + if (!o) return ''; + const v = o.id ?? o.fileId ?? o.Id; + return v != null && v !== '' ? String(v) : ''; + }; + const aid = pickId(activeItem); + if (!aid) return; + this.dataListA.forEach((row, i) => { + const rid = pickId(row); + const use = rid === aid ? 1 : 0; + if (Number(row.useStatus) !== use) { + this.$set(this.dataListA, i, { ...row, useStatus: use }); + } + }); + }, Apply(item, index) { this.updateProgress = 0; this.isUpdating = true; @@ -530,6 +552,7 @@ if (RES.code == 200) { // 蓝牙上传:进度已由 onProgress 更新,直接完成 if (RES._channel === 'ble') { + this.syncVoiceListUseStatus(item); uni.showToast({ title: '音频上传成功', icon: 'success', duration: 2000 }); this.isUpdating = false; setTimeout(() => { uni.navigateBack(); }, 1500); @@ -554,6 +577,7 @@ this.updateProgress = progress; if (progress === 100) { clearTimeout(this.upgradeTimer); + this.syncVoiceListUseStatus(item); uni.showToast({ title: '音频上传成功', icon: 'success', duration: 2000 }); this.isUpdating = false; setTimeout(() => { uni.navigateBack(); }, 1500);