diff --git a/pages/6155/deviceDetail.vue b/pages/6155/deviceDetail.vue index 9745cca..d07fd03 100644 --- a/pages/6155/deviceDetail.vue +++ b/pages/6155/deviceDetail.vue @@ -108,15 +108,15 @@ 单位: - + 部门: - + 姓名: - + @@ -919,7 +919,7 @@ fail: (ex) => { updateLoading(these, { - text: '视频文件上传失败了,请检查网络连接' + text : '视频文件上传失败了,请检查网络连接' }); reject(ex); @@ -1295,9 +1295,14 @@ case "fu": title = '辅灯模式'; items = [{ - text: '泛光', - icon: '/static/images/6155/DeviceDetail/fan.png' - }]; + text: '泛光', + icon: '/static/images/6155/DeviceDetail/fan.png' + }, + { + text: '强+泛光', + icon: '/static/images/6155/DeviceDetail/fan.png' + }, + ]; break; } @@ -1332,29 +1337,22 @@ }, setMode(mode, type) { - let dataValue = 0; - - switch (mode) { case 0: - - if (type == 'main') { - dataValue = 0x01; } else if (type == 'fu') { - dataValue = 0x04; } - break; case 1: - dataValue = 0x02; + if (type == 'main') { + dataValue = 0x02; + } else if (type == 'fu') { + dataValue = 0x0A; //强泛光 + } break; - // case 2: - // dataValue = 0x02; - // break; case 2: dataValue = 0x03; break; @@ -1363,7 +1361,7 @@ break; } - // console.log("dataValue=", dataValue) + console.log("dataValue=", dataValue) // 构建数据包 var buffer = new ArrayBuffer(6); var dataView = new DataView(buffer); @@ -1526,156 +1524,73 @@ }); this.setBleFormData(); let task = async () => { - var sendTxtPackge = (rgbdata, type, str) => { - - var promise = new Promise((resolve, reject) => { - try { - // 设备协议:FA 06/07/08 01 00 + 256字节数据 + FF - // 每个文本行只需要一个261字节的包 - const bufferSize = 261; - const dataSize = 256; // 数据部分固定256字节 - - let buffer = new ArrayBuffer(bufferSize); - let dataView = new DataView(buffer); - - // 写入头部:FA 06/07/08 01 00 - dataView.setUint8(0, 0xFA); - dataView.setUint8(1, type); - dataView.setUint8(2, 0x01); - dataView.setUint8(3, 0x00); - - // 写入数据(最多256字节),确保数据是数字格式 - let actualDataSize = Math.min(rgbdata.length, dataSize); - for (let i = 0; i < actualDataSize; i++) { - // 确保数据是数字格式,如果是字符串则转换 - let byteValue = typeof rgbdata[i] === 'string' ? these.toByteValue(rgbdata[i]) : rgbdata[i]; - dataView.setUint8(4 + i, byteValue); - } - - // 用0填充剩余数据部分(如果数据不足256字节) - for (let i = 4 + actualDataSize; i < bufferSize - 1; i++) { - dataView.setUint8(i, 0x00); - } - - // 写入尾部:FF - dataView.setUint8(bufferSize - 1, 0xFF); - - console.log(`发送文本数据包: type=0x${type.toString(16)}, 数据长度=${actualDataSize}, 总长度=${bufferSize}`); - - // 发送数据包 - ble.sendData(f.deviceId, buffer, f.writeServiceId, f - .wirteCharactId, 100).then(() => { - resolve(); - }).catch(err => { - if (err.code == '10007') { - // 重试 - setTimeout(() => { - ble.sendData(f.deviceId, buffer, f.writeServiceId, f - .wirteCharactId, 100).then(() => { - resolve(); - }).catch(reject); - }, 100); - } else { - reject(err); - } - }); - - } catch (ex) { - console.log("构建数据包异常:", ex); - reject(ex); - } - }); - - return promise; - - } - - console.log("11111"); - var result = null; try { - console.log("this.$refs.textToHex=", this.$refs.textToHex); - // 获取像素数据(组件内部会自动预热画布) - result = await this.$refs.textToHex.drawAndGetPixels(); - } catch (ex) { - console.log("获取画布数据异常:", ex); - } - if (!result) { - hideLoading(this); - return; - } - console.log("result=", result); - result = result.map(level1 => { - return level1.flat(Infinity).map(item => { - // 确保数据转换为数字格式,避免字符串格式导致的问题 - return typeof item === 'string' ? these.toByteValue(item) : item; - }); - }); - console.log("result=", result); + // 预热画布,确保画布和字体完全准备好(解决APP重新打开后第一次获取数据不完整的问题) + console.log("预热画布..."); + await this.$refs.textToHex.drawAndGetPixels(); + await new Promise(resolve => setTimeout(resolve, 200)); // 等待预热完成 - // var str1="FA 06 01 00 FF FF F7 9F EF 6F EC F7 EA 09 CF FF AF FB EF EB EF EB EC 6B EF EB EC 6B EF EB EF FB EE 63 FF FF FF FF F7 9F EF 6F EC F7 EA 09 CF FF AF FB EF EB EF EB EC 6B EF EB EC 6B EF EB EF FB EE 63 FF FF FF FF F7 FF 81 03 ED BB DD B7 CB CF F3 C7 CD 39 BE FF FE FF C0 03 FE FB FD FB F3 F7 8F 87 FF FF FF FF FE FF FE FF FE FF C0 03 FF FB FD FB FD FB FD FB FD FB FB FB FB FF F7 F7 EF F7 9F 8F FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF" - // var str2="FA 07 01 00 FF FF EE DD EE DF EF 5B AB DF AA 03 AE FF AE FF EE 03 EE FF EE FF EE 03 EE FF EE FF EE E3 FF FF FF FF EE DD EE DF EF 5B AB DF AA 03 AE FF AE FF EE 03 EE FF EE FF EE 03 EE FF EE FF EE E3 FF FF FF FF EF 77 EF 73 EF 7F 80 01 EF 7F EF 7F EF 03 E7 3B 8E BB EE D7 EE EF ED E7 ED 9B 8B 7D FF FF FF FF FF FF F7 EF F7 F7 EF F7 DF FB FF FF FF FF FE FF 80 01 FE 7F FD BF FB DF F7 E7 9F F9 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF" - // var str3="FA 08 01 00 FF FF EF DF EC 01 EF FF AB FF AA 03 AA FB AE FB EE 03 EF DF EF DF EE DB ED DF ED DD EF 1F FF FF FF FF EF BF EF 87 81 77 EE F7 EC 03 81 7F EF 7F EF 7F EF 03 81 7F EF 7F EF 7D EF 7D EF 03 FF FF FF FF F9 F1 CF BF DF FF DF FF C1 FF DD 81 DD F7 DD F7 C1 F7 DF 77 FF 77 BF 77 BF 77 FF F7 FF FF FF FF FD FF FD FF FB FF FB FF F0 07 E7 F7 EF F7 D8 07 BF F7 FF F7 F8 07 FF F7 FF F7 FF C7 FF FF FF FF FF FF FF FF FF FF FE FF FE 7F FE 7F FE FF FD BF FD FF FB DF F7 EF EF F7 DF FB BF FD FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF" - - // let arr1=('0x'+(str1.split(' ').join(",0x"))).split(','); - // let arr2=('0x'+(str2.split(' ').join(",0x"))).split(','); - // let arr3=('0x'+(str3.split(' ').join(",0x"))).split(','); - - // result=[arr1,arr2,arr3]; - - - // console.log("result=",result); - - - let h3dic = [0x06, 0x07, 0x08]; - let pros = []; - let flag = true; - // 在开始发送前添加延迟,确保数据完全准备好(解决第一次发送第一个字缺失的问题) - await new Promise(resolve => setTimeout(resolve, 500)); - - for (var i = 0; i < result.length; i++) { - - let str = this.formData.textLines[i]; - - if (str.length > 0) { - - let width = str.length * 16; - var rgb = result[i]; - - // 确保数据是数组且已转换 - if (!Array.isArray(rgb)) { - console.error(`第${i+1}行数据格式错误:`, rgb); - flag = false; - break; - } - - // 第一次发送前额外延迟,确保设备完全准备好 - if (i === 0) { - console.log("准备发送第一个文本行,等待设备准备好..."); - await new Promise(resolve => setTimeout(resolve, 500)); - } - - try { - console.log(`开始发送第${i+1}个文本行 (type=0x${h3dic[i].toString(16)})`); - await sendTxtPackge(rgb, h3dic[i], str); - console.log(`第${i+1}个文本行发送完成`); - - // 每个文本行发送完成后,添加延迟确保设备处理完成 - if (i < result.length - 1) { - await new Promise(resolve => setTimeout(resolve, 300)); - } - } catch (ex) { - flag = false; - console.error(`发送第${i+1}个文本行出现异常:`, ex); - break; - } + // 1. 获取所有文本行的像素数据 + const allPixels = await this.$refs.textToHex.drawAndGetPixels(); + if (!allPixels) { + throw new Error("无法生成像素数据"); } + // 2. 将所有像素数据合并到一个大数组中 + let combinedData = []; + for (let i = 0; i < 3; i++) { + const linePixels = (allPixels[i] || []).flat(Infinity).map(item => + typeof item === 'string' ? these.toByteValue(item) : item + ); + // 补齐到256字节 + while (linePixels.length < 256) { + linePixels.push(0x00); + } + combinedData = combinedData.concat(linePixels.slice(0, 256)); + } - } + // 3. 构建完整的逻辑大包 + const logicalPacketSize = 4 + combinedData.length + 1; // Header + Data + Footer + const logicalBuffer = new ArrayBuffer(logicalPacketSize); + const logicalDataView = new DataView(logicalBuffer); - hideLoading(these); - if (flag) { - console.log("发送成功"); + // 写入头部 + logicalDataView.setUint8(0, 0xFA); + logicalDataView.setUint8(1, 0x06); + logicalDataView.setUint8(2, 0x03); + logicalDataView.setUint8(3, 0x00); + + // 写入数据 + for (let i = 0; i < combinedData.length; i++) { + logicalDataView.setUint8(4 + i, combinedData[i]); + } + + // 写入尾部 + logicalDataView.setUint8(logicalPacketSize - 1, 0xFF); + + // 4. 将逻辑大包分包发送 + const CHUNK_SIZE = 20; // 每个物理包的大小 + const totalChunks = Math.ceil(logicalPacketSize / CHUNK_SIZE); + + updateLoading(these, { + text: `准备发送,共 ${totalChunks} 个数据包...` + }); + + for (let i = 0; i < totalChunks; i++) { + const start = i * CHUNK_SIZE; + const end = Math.min(start + CHUNK_SIZE, logicalPacketSize); + const chunk = logicalBuffer.slice(start, end); + + updateLoading(these, { + text: `正在发送 ${i + 1} / ${totalChunks}` + }); + + await ble.sendData(f.deviceId, chunk, f.writeServiceId, f.wirteCharactId, 50); + await new Promise(resolve => setTimeout(resolve, 50)); // 包之间延迟 + } + + // 5. 发送成功处理 + hideLoading(these); this.showPop({ message: "发送成功", iconUrl: "/static/images/6155/DeviceDetail/uploadSuccess.png", @@ -1683,9 +1598,6 @@ buttonBgColor: '#BBE600' }); - - - let json = { deviceId: these.device.id, name: these.formData.textLines[1], @@ -1693,17 +1605,18 @@ unitName: these.formData.textLines[2], code: "" }; - usrApi.sendUsr(json) - } else { + usrApi.sendUsr(json); + + } catch (ex) { + hideLoading(these); this.showPop({ - message: "出现异常发送失败", + message: "发送失败: " + (ex.msg || ex.message), iconUrl: "/static/images/6155/DeviceDetail/uploadErr.png", borderColor: "#e034344d", buttonBgColor: "#E03434", }); } - } - + }; setTimeout(task, 0); }, getDetail() { diff --git a/pages/common/addBLE/addEquip.vue b/pages/common/addBLE/addEquip.vue index d4fd506..d0fa275 100644 --- a/pages/common/addBLE/addEquip.vue +++ b/pages/common/addBLE/addEquip.vue @@ -165,16 +165,19 @@ }, onUnload() { - ble.StopSearch(); - ble.removeAllCallback(pagePath); - + if (ble) { + ble.StopSearch(); + ble.removeAllCallback(pagePath); + } }, onLoad(option) { let search = option.search; - ble = bleTool.getBleTool(); these = this; eventChannel = this.getOpenerEventChannel(); const systemInfo = uni.getSystemInfoSync(); + + ble = bleTool.getBleTool(); // Ensure ble is initialized + if (systemInfo.uniPlatform == 'web') { @@ -217,7 +220,9 @@ } let StartSubsrib = () => { these.EquipMents = []; - + if (!ble) { + ble = bleTool.getBleTool(); + } //蓝牙不可用的回调 ble.addStateBreakCallback(res => { if (these.Status.isPageHidden) { @@ -234,19 +239,6 @@ these.showOpenSetting(); }, pagePath); - //蓝牙再次可用的回调 - ble.addStateRecoveryCallback(res => { - if (these.Status.isPageHidden) { - return; - } - uni.showToast({ - icon: 'success', - title: '蓝牙恢复可用' - }); - these.Status.BottomMenu.show = false; - these.EquipMents = []; - these.refreshBleList(); - }, pagePath); //蓝牙断开连接的回调 ble.addDisposeCallback(res => { @@ -263,110 +255,119 @@ }, pagePath); - //蓝牙连接已恢复的回调 - ble.addRecoveryCallback(res => { + + + + //搜索到新设备的回调 (Always active) + ble.addDeviceFound((arr) => { + console.log("--- 收到原始扫描数据 ---", JSON.stringify(arr)); if (these.Status.isPageHidden) { return; } - // hideLoading(these); - these.EquipMents.find(function(v, ind) { - if (v.deviceId == res.deviceId) { - these.PairEquip.push(v); - return true; - } - return false; - }); - if (these.device) { - clearInterval(this.Status.intval); - showLoading(these, { - text: '蓝牙连接已恢复,正在验证设备' - }); - - setTimeout(() => { - these.DeviceVerdict(res.deviceId); - }, 0); - } else { - hideLoading(these); - } - - - }, pagePath); - //搜索到新设备的回调 - - ble.addDeviceFound((arr) => { - // console.log("发现设备", arr); - if (these.Status.isPageHidden) { + if (!arr || !arr.devices) { return; } arr = arr.devices; - for (var i = 0; i < arr.length; i++) { + console.log(`本次扫描批次发现 ${arr.length} 个设备`); - arr[i].linkStatu = false; - if (!arr[i].name) { - continue; - } + for (var i = 0; i < arr.length; i++) { + let device = arr[i]; + device.linkStatu = false; let f = these.EquipMents.find((v, index) => { - if (v.deviceId == arr[i].deviceId) { - - these.$set(these.EquipMents[index], 'RSSI', arr[i].RSSI); - + if (v.deviceId == device.deviceId) { + console.log(`更新设备信号: ${device.name || device.deviceId}, RSSI: ${device.RSSI}`); + these.$set(these.EquipMents[index], 'RSSI', device.RSSI); return true; } return false; }); if (!f) { - console.log("发现新设备,", arr[i]); + console.log("+++ 发现新设备,准备添加到列表:", JSON.stringify(device)); - if (these.device && these.device.bluetoothName) { - if (these.device.bluetoothName === arr[i].name || arr[i].name.indexOf(these - .device.bluetoothName) > -1 || these.device.bluetoothName.indexOf(arr[ - i].name) > -1) { - arr[i].isTarget = true; + if (these.device && these.device.bluetoothName && device.name) { + if (these.device.bluetoothName === device.name || (device.name && device.name.indexOf(these + .device.bluetoothName) > -1) || (device.name && this.device.bluetoothName.indexOf( + device.name) > -1)) { + device.isTarget = true; } } - arr[i].name = arr[i].name.replace('JQZM-', ''); - these.EquipMents.push(arr[i]); + if (device.name) { + device.name = device.name.replace('JQZM-', ''); + } + these.EquipMents.push(device); } } - // console.log("EquipMents=", these.EquipMents) }, pagePath); - //收到设备的消息回调 - ble.addReceiveCallback((receivData, f, path, arr) => { - if (these.Status.isPageHidden) { - return; - } - if (f.macAddress && these.device) { - clearInterval(this.Status.intval); - this.Status.intval = null; - this.Status.time = null; - - showLoading(these, { - text: '正在验证设备' + } + + let startValidDevice=()=>{ + if (these.device) { + console.log("进入配对模式,启用连接恢复和验证逻辑。"); + //蓝牙连接已恢复的回调 + ble.addRecoveryCallback(res => { + if (these.Status.isPageHidden) { + return; + } + // hideLoading(these); + these.EquipMents.find(function(v, ind) { + if (v.deviceId == res.deviceId) { + these.PairEquip.push(v); + return true; + } + return false; }); - - setTimeout(() => { - these.DeviceVerdict(f.deviceId); - }, 0); - } - - - }, pagePath); - + if (these.device) { + clearInterval(this.Status.intval); + showLoading(these, { + text: '蓝牙连接已恢复,正在验证设备' + }); + + setTimeout(() => { + these.DeviceVerdict(res.deviceId); + }, 0); + } else { + hideLoading(these); + } + + + }, pagePath); + + //收到设备的消息回调 + ble.addReceiveCallback((receivData, f, path, arr) => { + console.log("000000"); + if (these.Status.isPageHidden) { + return; + } + console.log("1111111"); + if (f.macAddress && these.device) { + console.log("222222"); + clearInterval(this.Status.intval); + this.Status.intval = null; + this.Status.time = null; + + showLoading(these, { + text: '正在验证设备' + }); + + setTimeout(() => { + these.DeviceVerdict(f.deviceId); + }, 0); + } + + + }, pagePath); + } } - - StartSubsrib(); - eventChannel.on('detailData', function(rec) { console.log("接收到父页面的参数:", rec); these.device = rec.data; - console.log("11111") - + startValidDevice(); these.refreshBleList(); }); @@ -377,41 +378,92 @@ this.refreshBleList(); }, methods: { - refreshBleList() { - if (!ble) { + checkAndRequestLocationPermission() { + return new Promise((resolve) => { + + if (uni.getSystemInfoSync().platform !== 'android') { + return resolve(true); + } + + plus.android.requestPermissions( + ['android.permission.ACCESS_FINE_LOCATION'], + (result) => { + if (result.granted.length > 0) { + console.log('定位权限已授予'); + resolve(true); + } else { + console.warn('定位权限被拒绝'); + uni.showModal({ + title: '权限提醒', + content: '为了正常扫描蓝牙设备,需要您开启定位权限', + showCancel: false, + success: () => { + uni.openSetting(); // 引导用户去设置页 + } + }); + resolve(false); + } + }, + (error) => { + console.error('请求定位权限失败:', error); + uni.showToast({ + title: '权限请求异常', + icon: 'none' + }); + resolve(false); + } + ); + + resolve(true); + }); + }, + async refreshBleList() { + + const hasPermission = await this.checkAndRequestLocationPermission(); + if (!hasPermission) { + console.log("缺少定位权限,已中止蓝牙扫描。"); return; } - let promis = []; - for (let index = 0; index < this.PairEquip.length; index++) { - let item = this.PairEquip[index]; - promis.push(ble.disconnectDevice(item.deviceId)); - + + + if (!ble) { + ble = bleTool.getBleTool(); + if (!ble) { + console.error("BLE helper not initialized!"); + return; + } } - - Promise.allSettled(promis).finally(() => { - ble.StopSearch().finally(res => { - console.log("停止搜索成功"); + + ble.StopSearch().finally(() => { + + let disconnectPromises = []; + if (ble.data && ble.data.LinkedList) { + ble.data.LinkedList.forEach(device => { + console.log(`Requesting disconnect for ${device.deviceId}`); + disconnectPromises.push(ble.disconnectDevice(device.deviceId)); + }); + } + + Promise.allSettled(disconnectPromises).finally(() => { + these.EquipMents = []; these.PairEquip = []; + ble.StartSearch().then(result => { - console.log("开始搜索成功"); + console.log("Fresh scan started successfully."); }).catch(err => { - console.error("开始搜索失败,err=", err); - if (err.code === 10001) { + console.error("Failed to start fresh scan:", err); + if (err.code === 10001) { these.showOpenSetting(); } else { uni.showModal({ title: '提示', - content: '出现异常:' + err.msg + content: '开始搜索失败:' + err.msg }); } }); - }).catch(ex => { - console.error("ex=", ex); }); - }); - }, isItemLink: function(item, index) { let src = '/static/images/BLEAdd/noLink.png';