1
0
forked from dyf/APP

Compare commits

..

5 Commits

2 changed files with 245 additions and 281 deletions

View File

@ -108,15 +108,15 @@
<view class="item"> <view class="item">
<text class="lbl">单位</text> <text class="lbl">单位</text>
<input class="value" v-model="formData.textLines[0]" placeholder="请输入单位" placeholder-class="usrplace" /> <input class="value" v-model.trim="formData.textLines[0]" placeholder="请输入单位" placeholder-class="usrplace" />
</view> </view>
<view class="item"> <view class="item">
<text class="lbl">部门</text> <text class="lbl">部门</text>
<input class="value" v-model="formData.textLines[1]" placeholder="请输入姓名" placeholder-class="usrplace" /> <input class="value" v-model.trim="formData.textLines[1]" placeholder="请输入姓名" placeholder-class="usrplace" />
</view> </view>
<view class="item"> <view class="item">
<text class="lbl">姓名</text> <text class="lbl">姓名</text>
<input class="value" v-model="formData.textLines[2]" placeholder="请输入职位" placeholder-class="usrplace" /> <input class="value" v-model.trim="formData.textLines[2]" placeholder="请输入职位" placeholder-class="usrplace" />
</view> </view>
</view> </view>
@ -1295,7 +1295,12 @@
items = [{ items = [{
text: '泛光', text: '泛光',
icon: '/static/images/6155/DeviceDetail/fan.png' icon: '/static/images/6155/DeviceDetail/fan.png'
}]; },
{
text: '强+泛光',
icon: '/static/images/6155/DeviceDetail/fan.png'
},
];
break; break;
} }
@ -1330,29 +1335,22 @@
}, },
setMode(mode, type) { setMode(mode, type) {
let dataValue = 0; let dataValue = 0;
switch (mode) { switch (mode) {
case 0: case 0:
if (type == 'main') { if (type == 'main') {
dataValue = 0x01; dataValue = 0x01;
} else if (type == 'fu') { } else if (type == 'fu') {
dataValue = 0x04; dataValue = 0x04;
} }
break; break;
case 1: case 1:
if (type == 'main') {
dataValue = 0x02; dataValue = 0x02;
} else if (type == 'fu') {
dataValue = 0x0A; //强泛光
}
break; break;
// case 2:
// dataValue = 0x02;
// break;
case 2: case 2:
dataValue = 0x03; dataValue = 0x03;
break; break;
@ -1361,7 +1359,7 @@
break; break;
} }
// console.log("dataValue=", dataValue) console.log("dataValue=", dataValue)
// 构建数据包 // 构建数据包
var buffer = new ArrayBuffer(6); var buffer = new ArrayBuffer(6);
var dataView = new DataView(buffer); var dataView = new DataView(buffer);
@ -1524,156 +1522,73 @@
}); });
this.setBleFormData(); this.setBleFormData();
let task = async () => { let task = async () => {
var sendTxtPackge = (rgbdata, type, str) => {
var promise = new Promise((resolve, reject) => {
try { try {
// 设备协议FA 06/07/08 01 00 + 256字节数据 + FF // 预热画布确保画布和字体完全准备好解决APP重新打开后第一次获取数据不完整的问题
// 每个文本行只需要一个261字节的包 console.log("预热画布...");
const bufferSize = 261; await this.$refs.textToHex.drawAndGetPixels();
const dataSize = 256; // 数据部分固定256字节 await new Promise(resolve => setTimeout(resolve, 200)); // 等待预热完成
let buffer = new ArrayBuffer(bufferSize); // 1. 获取所有文本行的像素数据
let dataView = new DataView(buffer); const allPixels = await this.$refs.textToHex.drawAndGetPixels();
if (!allPixels) {
// 写入头部FA 06/07/08 01 00 throw new Error("无法生成像素数据");
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字节 // 2. 将所有像素数据合并到一个大数组中
for (let i = 4 + actualDataSize; i < bufferSize - 1; i++) { let combinedData = [];
dataView.setUint8(i, 0x00); 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));
} }
// 写入尾部FF // 3. 构建完整的逻辑大包
dataView.setUint8(bufferSize - 1, 0xFF); const logicalPacketSize = 4 + combinedData.length + 1; // Header + Data + Footer
const logicalBuffer = new ArrayBuffer(logicalPacketSize);
const logicalDataView = new DataView(logicalBuffer);
console.log(`发送文本数据包: type=0x${type.toString(16)}, 数据长度=${actualDataSize}, 总长度=${bufferSize}`); // 写入头部
logicalDataView.setUint8(0, 0xFA);
logicalDataView.setUint8(1, 0x06);
logicalDataView.setUint8(2, 0x03);
logicalDataView.setUint8(3, 0x00);
// 发送数据 // 写入数据
ble.sendData(f.deviceId, buffer, f.writeServiceId, f for (let i = 0; i < combinedData.length; i++) {
.wirteCharactId, 100).then(() => { logicalDataView.setUint8(4 + i, combinedData[i]);
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);
} }
// 写入尾部
logicalDataView.setUint8(logicalPacketSize - 1, 0xFF);
// 4. 将逻辑大包分包发送
const CHUNK_SIZE = 20; // 每个物理包的大小
const totalChunks = Math.ceil(logicalPacketSize / CHUNK_SIZE);
updateLoading(these, {
text: `准备发送,共 ${totalChunks} 个数据包...`
}); });
} catch (ex) { for (let i = 0; i < totalChunks; i++) {
console.log("构建数据包异常:", ex); const start = i * CHUNK_SIZE;
reject(ex); const end = Math.min(start + CHUNK_SIZE, logicalPacketSize);
} const chunk = logicalBuffer.slice(start, end);
updateLoading(these, {
text: `正在发送 ${i + 1} / ${totalChunks}`
}); });
return promise; await ble.sendData(f.deviceId, chunk, f.writeServiceId, f.wirteCharactId, 50);
await new Promise(resolve => setTimeout(resolve, 50)); // 包之间延迟
}
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);
// 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;
}
}
} }
// 5. 发送成功处理
hideLoading(these); hideLoading(these);
if (flag) {
console.log("发送成功");
this.showPop({ this.showPop({
message: "发送成功", message: "发送成功",
iconUrl: "/static/images/6155/DeviceDetail/uploadSuccess.png", iconUrl: "/static/images/6155/DeviceDetail/uploadSuccess.png",
@ -1681,9 +1596,6 @@
buttonBgColor: '#BBE600' buttonBgColor: '#BBE600'
}); });
let json = { let json = {
deviceId: these.device.id, deviceId: these.device.id,
name: these.formData.textLines[1], name: these.formData.textLines[1],
@ -1691,17 +1603,18 @@
unitName: these.formData.textLines[2], unitName: these.formData.textLines[2],
code: "" code: ""
}; };
usrApi.sendUsr(json) usrApi.sendUsr(json);
} else {
} catch (ex) {
hideLoading(these);
this.showPop({ this.showPop({
message: "出现异常发送失败", message: "发送失败: " + (ex.msg || ex.message),
iconUrl: "/static/images/6155/DeviceDetail/uploadErr.png", iconUrl: "/static/images/6155/DeviceDetail/uploadErr.png",
borderColor: "#e034344d", borderColor: "#e034344d",
buttonBgColor: "#E03434", buttonBgColor: "#E03434",
}); });
} }
} };
setTimeout(task, 0); setTimeout(task, 0);
}, },
getDetail() { getDetail() {

View File

@ -165,15 +165,19 @@
}, },
onUnload() { onUnload() {
if (ble) {
ble.StopSearch(); ble.StopSearch();
ble.removeAllCallback(pagePath); ble.removeAllCallback(pagePath);
}
}, },
onLoad(option) { onLoad(option) {
let search = option.search; let search = option.search;
these = this; these = this;
eventChannel = this.getOpenerEventChannel(); eventChannel = this.getOpenerEventChannel();
const systemInfo = uni.getSystemInfoSync(); const systemInfo = uni.getSystemInfoSync();
ble = bleTool.getBleTool(); // Ensure ble is initialized
if (systemInfo.uniPlatform == 'web') { if (systemInfo.uniPlatform == 'web') {
@ -216,7 +220,9 @@
} }
let StartSubsrib = () => { let StartSubsrib = () => {
these.EquipMents = []; these.EquipMents = [];
if (!ble) {
ble = bleTool.getBleTool(); ble = bleTool.getBleTool();
}
//蓝牙不可用的回调 //蓝牙不可用的回调
ble.addStateBreakCallback(res => { ble.addStateBreakCallback(res => {
if (these.Status.isPageHidden) { if (these.Status.isPageHidden) {
@ -233,19 +239,6 @@
these.showOpenSetting(); these.showOpenSetting();
}, pagePath); }, 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 => { ble.addDisposeCallback(res => {
@ -262,6 +255,10 @@
}, pagePath); }, pagePath);
// --- Start: Logic for Pairing Mode Only ---
if (these.device) {
console.log("进入配对模式,启用连接恢复和验证逻辑。");
//蓝牙连接已恢复的回调 //蓝牙连接已恢复的回调
ble.addRecoveryCallback(res => { ble.addRecoveryCallback(res => {
if (these.Status.isPageHidden) { if (these.Status.isPageHidden) {
@ -290,46 +287,7 @@
}, pagePath); }, pagePath);
//搜索到新设备的回调
ble.addDeviceFound((arr) => {
if (these.Status.isPageHidden) {
return;
}
arr = arr.devices;
for (var i = 0; i < arr.length; i++) {
arr[i].linkStatu = false;
if (!arr[i].name) {
continue;
}
let f = these.EquipMents.find((v, index) => {
if (v.deviceId == arr[i].deviceId) {
these.$set(these.EquipMents[index], 'RSSI', arr[i].RSSI);
return true;
}
return false;
});
if (!f) {
console.log("发现新设备,", arr[i]);
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;
}
}
arr[i].name = arr[i].name.replace('JQZM-', '');
these.EquipMents.push(arr[i]);
}
}
// console.log("EquipMents=", these.EquipMents)
}, pagePath);
//收到设备的消息回调 //收到设备的消息回调
ble.addReceiveCallback((receivData, f, path, arr) => { ble.addReceiveCallback((receivData, f, path, arr) => {
if (these.Status.isPageHidden) { if (these.Status.isPageHidden) {
@ -351,18 +309,60 @@
}, pagePath); }, pagePath);
}
// --- End: Logic for Pairing Mode Only ---
//搜索到新设备的回调 (Always active)
ble.addDeviceFound((arr) => {
console.log("--- 收到原始扫描数据 ---", JSON.stringify(arr));
if (these.Status.isPageHidden) {
return;
}
if (!arr || !arr.devices) {
return;
}
arr = arr.devices;
console.log(`本次扫描批次发现 ${arr.length} 个设备`);
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 == 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("+++ 发现新设备,准备添加到列表:", JSON.stringify(device));
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;
}
}
if (device.name) {
device.name = device.name.replace('JQZM-', '');
}
these.EquipMents.push(device);
}
}
}, pagePath);
} }
if (search) {
StartSubsrib(); StartSubsrib();
}
eventChannel.on('detailData', function(rec) { eventChannel.on('detailData', function(rec) {
console.log("接收到父页面的参数:", rec); console.log("接收到父页面的参数:", rec);
these.device = rec.data; these.device = rec.data;
StartSubsrib();
these.refreshBleList(); these.refreshBleList();
}); });
@ -373,41 +373,92 @@
this.refreshBleList(); this.refreshBleList();
}, },
methods: { methods: {
refreshBleList() { checkAndRequestLocationPermission() {
if (!ble) { 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; 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(() => {
ble.StopSearch().finally(res => {
console.log("停止搜索成功"); 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.EquipMents = [];
these.PairEquip = []; these.PairEquip = [];
ble.StartSearch().then(result => { ble.StartSearch().then(result => {
console.log("开始搜索成功"); console.log("Fresh scan started successfully.");
}).catch(err => { }).catch(err => {
console.error("开始搜索失败,err=", err); console.error("Failed to start fresh scan:", err);
if (err.code === 10001) { if (err.code === 10001) {
these.showOpenSetting(); these.showOpenSetting();
} else { } else {
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '出现异常:' + err.msg content: '开始搜索失败:' + err.msg
}); });
} }
}); });
}).catch(ex => {
console.error("ex=", ex);
}); });
}); });
}, },
isItemLink: function(item, index) { isItemLink: function(item, index) {
let src = '/static/images/BLEAdd/noLink.png'; let src = '/static/images/BLEAdd/noLink.png';