Merge branch 'main' of http://47.107.152.87:3000/dyf/APP
@ -1,671 +0,0 @@
|
|||||||
export default {
|
|
||||||
featrueValueCallback: null,//蓝牙特征变化回调
|
|
||||||
BleChangeCallback:null,//蓝牙状态变化回调
|
|
||||||
//引导用户打开蓝牙
|
|
||||||
showBluetoothGuide: function(showTip) {
|
|
||||||
let platform = process.env.UNI_PLATFORM;
|
|
||||||
|
|
||||||
|
|
||||||
var openBlueSetting = function() {
|
|
||||||
// 判断平台类型
|
|
||||||
if (platform === 'mp-weixin') {
|
|
||||||
uni.openSetting();
|
|
||||||
} else if (platform === 'app-plus' || platform === 'app') {
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
const osName = plus.os.name;
|
|
||||||
|
|
||||||
if (osName === 'iOS') {
|
|
||||||
// iOS 平台打开蓝牙设置
|
|
||||||
plus.runtime.openURL('App-Prefs:root=Bluetooth', function() {
|
|
||||||
console.log('成功打开蓝牙设置');
|
|
||||||
}, function(err) {
|
|
||||||
console.error('打开蓝牙设置失败:' + err.message);
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '无法自动打开蓝牙设置,请手动前往设置 > 蓝牙 进行操作。',
|
|
||||||
showCancel: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else if (osName === 'Android') {
|
|
||||||
// Android 平台打开蓝牙设置
|
|
||||||
try {
|
|
||||||
const Intent = plus.android.importClass('android.content.Intent');
|
|
||||||
const Settings = plus.android.importClass('android.provider.Settings');
|
|
||||||
const main = plus.android.runtimeMainActivity();
|
|
||||||
const intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
|
|
||||||
main.startActivity(intent);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('打开蓝牙设置失败:' + e.message);
|
|
||||||
// 尝试使用通用设置页面作为备选方案
|
|
||||||
plus.runtime.openURL('settings://', function() {
|
|
||||||
console.log('打开系统设置成功,请手动找到蓝牙选项');
|
|
||||||
}, function() {
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '无法自动打开蓝牙设置,请手动前往设置页面开启蓝牙。',
|
|
||||||
showCancel: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '当前系统不支持自动打开蓝牙设置,请手动操作。',
|
|
||||||
showCancel: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
} else if (platform === 'mp-alipay') {
|
|
||||||
uni.openSetting();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showTip !== undefined) {
|
|
||||||
openBlueSetting();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (platform === 'mp-weixin' || platform === 'app-plus' || platform === 'mp-alipay' || platform === 'app') {
|
|
||||||
uni.showModal({
|
|
||||||
title: '蓝牙未开启',
|
|
||||||
content: '请在系统设置中打开蓝牙以使用此功能',
|
|
||||||
success: (res) => {
|
|
||||||
if (res.confirm) {
|
|
||||||
openBlueSetting();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log("当前平台不支持打开系统设置" + platform);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
//获取蓝牙适配器状态
|
|
||||||
CheckBlue: function(callback) {
|
|
||||||
|
|
||||||
uni.getBluetoothAdapterState({
|
|
||||||
success(res1) {
|
|
||||||
|
|
||||||
console.log("当前蓝牙适配器状态:" + JSON.stringify(res1))
|
|
||||||
if (callback) {
|
|
||||||
callback(res1);
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
fail(ex1) {
|
|
||||||
console.log("检查蓝牙状态异常:" + JSON.stringify(ex1));
|
|
||||||
if (callback) {
|
|
||||||
if (ex1.code == 10000) {
|
|
||||||
console.log("未初始化蓝牙适配器");
|
|
||||||
}
|
|
||||||
let res1 = {
|
|
||||||
available: false,
|
|
||||||
discovering: false
|
|
||||||
}
|
|
||||||
callback(res1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete() {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//初始化蓝牙模块
|
|
||||||
OpenBlue: function(isCheckState, callback, availCallback) {
|
|
||||||
|
|
||||||
var these = this;
|
|
||||||
|
|
||||||
var init = function() {
|
|
||||||
uni.openBluetoothAdapter({
|
|
||||||
success: (res) => {
|
|
||||||
console.log("蓝牙初始化成功:" + JSON.stringify(res));
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
uni.onBluetoothAdapterStateChange(function(state) {
|
|
||||||
console.log('蓝牙状态发生变化:' + JSON.stringify(state));
|
|
||||||
if(this.BleChangeCallback){
|
|
||||||
this.BleChangeCallback()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
fail: function(ex2) {
|
|
||||||
console.log("蓝牙初始化失败:" + JSON.stringify(ex2))
|
|
||||||
if (ex2.code == '10001') {
|
|
||||||
console.log("手机蓝牙未打开或设备不支持蓝牙");
|
|
||||||
|
|
||||||
|
|
||||||
if (availCallback) {
|
|
||||||
availCallback();
|
|
||||||
} else {
|
|
||||||
these.showBluetoothGuide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (isCheckState) {
|
|
||||||
this.CheckBlue(function(res1) {
|
|
||||||
if (res1.available) {
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
init();
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
//关闭蓝牙模块,停止搜索、断开所有连接
|
|
||||||
CloseBlue: function(callback) {
|
|
||||||
|
|
||||||
this.StopSearch();
|
|
||||||
|
|
||||||
this.disconnectDevice();
|
|
||||||
|
|
||||||
uni.closeBluetoothAdapter({
|
|
||||||
success: () => {
|
|
||||||
console.log("蓝牙模块已关闭");
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//开始搜索新设备
|
|
||||||
StartSearch: function(callback) {
|
|
||||||
|
|
||||||
var these = this;
|
|
||||||
|
|
||||||
//发现新设备
|
|
||||||
var onDeviceFound = function() {
|
|
||||||
uni.onBluetoothDeviceFound(function(res) {
|
|
||||||
console.log("发现新设备:" + JSON.stringify(res));
|
|
||||||
if (callback) {
|
|
||||||
callback(res);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
//开始搜索
|
|
||||||
var Search = function() {
|
|
||||||
uni.startBluetoothDevicesDiscovery({
|
|
||||||
services: ["0xFFE0"],
|
|
||||||
allowDuplicatesKey: false,
|
|
||||||
success: (res) => {
|
|
||||||
console.log('开始搜索蓝牙设备成功');
|
|
||||||
onDeviceFound();
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.log(`搜索蓝牙设备失败: ${err.errMsg}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
//先检查蓝牙状态是可用
|
|
||||||
this.CheckBlue(function(res1) {
|
|
||||||
if (res1.available) {
|
|
||||||
if (!res1.discovering) {
|
|
||||||
Search();
|
|
||||||
} else {
|
|
||||||
console.log("当前蓝牙正在搜索设备")
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
these.OpenBlue(false, Search, () => {
|
|
||||||
these.showBluetoothGuide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
//停止搜索
|
|
||||||
StopSearch: function() {
|
|
||||||
uni.stopBluetoothDevicesDiscovery({
|
|
||||||
success: (res) => {
|
|
||||||
console.log("停止搜索蓝牙设备成功")
|
|
||||||
},
|
|
||||||
fail() {
|
|
||||||
console.log("无法停止蓝牙搜索")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
//获取已连接的设备
|
|
||||||
getLinkBlue: function(callback) {
|
|
||||||
uni.getConnectedBluetoothDevices({
|
|
||||||
services: ["0xFFE0"],
|
|
||||||
success: (res) => {
|
|
||||||
if (callback) {
|
|
||||||
callback(res);
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail: function(ex) {
|
|
||||||
console.log("获取已连接设备异常");
|
|
||||||
if (callback) {
|
|
||||||
callback({
|
|
||||||
devices: []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
//连接某个设备
|
|
||||||
LinkBlue: function(deviceId, callback, error) {
|
|
||||||
|
|
||||||
this.StopSearch();
|
|
||||||
var these = this;
|
|
||||||
let key = "linkedDevices";
|
|
||||||
var store = uni.getStorageInfoSync();
|
|
||||||
var f = store.keys.find(function(v) {
|
|
||||||
return v == key;
|
|
||||||
});
|
|
||||||
var linkedDevices = [];
|
|
||||||
if (f) {
|
|
||||||
var str = uni.getStorageSync(key);
|
|
||||||
if (str) {
|
|
||||||
linkedDevices = JSON.parse(str);
|
|
||||||
}else{
|
|
||||||
linkedDevices=[];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
//连接成功的回调
|
|
||||||
var lindedCallback = function () {
|
|
||||||
|
|
||||||
let c = linkedDevices.find(function (v) {
|
|
||||||
return v.deviceId == deviceId;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (c) {
|
|
||||||
console.log("连接成功开始监听特征变化")
|
|
||||||
//监听设备的特征变化
|
|
||||||
uni.notifyBLECharacteristicValueChange({
|
|
||||||
deviceId: deviceId,
|
|
||||||
serviceId: c.notifyServiceid,
|
|
||||||
characteristicId: c.notifyCharactId,
|
|
||||||
state: true,
|
|
||||||
success: function (res) {
|
|
||||||
console.log("开始监听成功。。。。")
|
|
||||||
if(res.errCode=='0'){
|
|
||||||
//订阅特征值
|
|
||||||
uni.onBLECharacteristicValueChange(function(data){
|
|
||||||
// data.characteristicId
|
|
||||||
// data.deviceId
|
|
||||||
// data.serviceId
|
|
||||||
// data.value
|
|
||||||
console.log("监听到特征值:"+JSON.stringify(data));
|
|
||||||
|
|
||||||
if(these.featrueValueCallback){
|
|
||||||
these.featrueValueCallback(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
callback(deviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var linkState = function(res) {
|
|
||||||
console.log("获取已连接的设备回调" + JSON.stringify(res))
|
|
||||||
let flag = res.devices.find(function(v) {
|
|
||||||
if (v.deviceId == deviceId) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if (flag) {
|
|
||||||
console.log("设备状态已连接");
|
|
||||||
|
|
||||||
lindedCallback(deviceId);
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
console.log("设备未连接");
|
|
||||||
linkDevice(deviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var linkDevice = function(id) {
|
|
||||||
console.log("正在连接"+id);
|
|
||||||
uni.createBLEConnection({
|
|
||||||
deviceId: id,
|
|
||||||
timeout: 30000,
|
|
||||||
success: function(info) {
|
|
||||||
|
|
||||||
console.log("连接成功");
|
|
||||||
|
|
||||||
uni.setBLEMTU({
|
|
||||||
deviceId: id,
|
|
||||||
mtu: 512,
|
|
||||||
success: () => {
|
|
||||||
console.log("mtu设置成功");
|
|
||||||
if(linkedDevices){
|
|
||||||
console.log("11111"+JSON.stringify(linkedDevices));
|
|
||||||
f = linkedDevices.find(function (v) {
|
|
||||||
return v.deviceId == id;
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
console.log("22222")
|
|
||||||
f=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!f) {
|
|
||||||
console.log("缓存中没有找到该设备")
|
|
||||||
|
|
||||||
these.getLinkBlue(function (res) {
|
|
||||||
if (res.devices && res.devices.length) {
|
|
||||||
let f = res.devices.find(function (v) {
|
|
||||||
return v.deviceId == id;
|
|
||||||
});
|
|
||||||
linkedDevices.push(f);
|
|
||||||
uni.setStorageSync(key, JSON.stringify(linkedDevices));
|
|
||||||
|
|
||||||
getService(id);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("缓存中已连接过");
|
|
||||||
if (!f.services) {
|
|
||||||
getService(id);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
lindedCallback(id);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail: function() {
|
|
||||||
console.log("mtu设置失败")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
fail: function(ex) {
|
|
||||||
if (error) {
|
|
||||||
console.log("蓝牙连接失败" + JSON.stringify(error));
|
|
||||||
error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//获取服务
|
|
||||||
var getService = function(id) {
|
|
||||||
|
|
||||||
var repeatCnt = 0;
|
|
||||||
var startgetService = function() {
|
|
||||||
uni.getBLEDeviceServices({
|
|
||||||
deviceId: id,
|
|
||||||
success: function(res) {
|
|
||||||
if (res.services && res.services.length > 0) {
|
|
||||||
console.log("获取到服务:" + JSON.stringify(res));
|
|
||||||
|
|
||||||
linkedDevices.find(function(v) {
|
|
||||||
if (v.deviceId == id) {
|
|
||||||
v.services = res.services;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
uni.setStorageSync(key, JSON.stringify(linkedDevices));
|
|
||||||
var promises = [];
|
|
||||||
for (var i = 0; i < res.services.length; i++) {
|
|
||||||
let service = res.services[i];
|
|
||||||
promises.push(getFeatrus(id, service.uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(promises)
|
|
||||||
.then(results => {
|
|
||||||
console.log('所有操作成功完成', results);
|
|
||||||
|
|
||||||
lindedCallback(id);
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('至少一个操作失败', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
repeatCnt++;
|
|
||||||
if (repeatCnt > 5) {
|
|
||||||
|
|
||||||
lindedCallback(id);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setTimeout(function() {
|
|
||||||
startgetService(id);
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
startgetService(id);
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
//获取特性
|
|
||||||
var getFeatrus = function(id, serviceId) {
|
|
||||||
var promise = new Promise((resolve, reject) => {
|
|
||||||
uni.getBLEDeviceCharacteristics({
|
|
||||||
deviceId: id,
|
|
||||||
serviceId: serviceId,
|
|
||||||
success: (res) => {
|
|
||||||
console.log("获取到特征:" + JSON.stringify(res));
|
|
||||||
|
|
||||||
//写特征
|
|
||||||
let writeChar = res.characteristics.find(char =>
|
|
||||||
char.uuid.indexOf("FFE1") > -1
|
|
||||||
);
|
|
||||||
//通知特征
|
|
||||||
let notiChar = res.characteristics.find(char =>
|
|
||||||
char.uuid.indexOf("FFE2") > -1
|
|
||||||
);
|
|
||||||
|
|
||||||
linkedDevices.find(function(v) {
|
|
||||||
if (v.deviceId == id) {
|
|
||||||
if (!v.Characteristics) {
|
|
||||||
v.Characteristics = [];
|
|
||||||
}
|
|
||||||
v.Characteristics = v.Characteristics.concat(res
|
|
||||||
.characteristics);
|
|
||||||
|
|
||||||
if (writeChar) {
|
|
||||||
v.writeServiceId = serviceId;
|
|
||||||
v.wirteCharactId = writeChar.uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notiChar) {
|
|
||||||
v.notifyServiceid = serviceId;
|
|
||||||
v.notifyCharactId = notiChar.uuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
uni.setStorageSync(key, JSON.stringify(linkedDevices));
|
|
||||||
resolve(res);
|
|
||||||
},
|
|
||||||
fail: (ex) => {
|
|
||||||
console.log("获取特征出现异常:" + JSON.stringify(ex));
|
|
||||||
resolve(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
//监测蓝牙状态变化
|
|
||||||
uni.onBLEConnectionStateChange(function(res) {
|
|
||||||
if (!res.connected) {
|
|
||||||
console.log("蓝牙断开连接" + res.deviceId + "");
|
|
||||||
// lindDevice(res.deviceId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("正在获取蓝牙适配器状态")
|
|
||||||
this.CheckBlue((res) => {
|
|
||||||
console.log("蓝牙状态:" + JSON.stringify(res));
|
|
||||||
if (res.available) {
|
|
||||||
this.getLinkBlue(linkState);
|
|
||||||
} else {
|
|
||||||
console.log("蓝牙适配器不可用,正在初始化");
|
|
||||||
this.OpenBlue(false, () => {
|
|
||||||
this.getLinkBlue(linkState);
|
|
||||||
}, () => {
|
|
||||||
console.log("请引导用户打开蓝牙");
|
|
||||||
these.showBluetoothGuide();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
//断开连接
|
|
||||||
disconnectDevice: function(deviceId) {
|
|
||||||
|
|
||||||
var disconnect = function(id) {
|
|
||||||
uni.closeBLEConnection({
|
|
||||||
deviceId: id,
|
|
||||||
success: (res) => {
|
|
||||||
console.log("蓝牙连接已断开");
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (deviceId) {
|
|
||||||
disconnect(deviceId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//断开所有已连接的设备
|
|
||||||
this.getLinkBlue(function(res) {
|
|
||||||
if (res.devices && res.devices.length > 0) {
|
|
||||||
for (var i = 0; i < res.devices.length; i++) {
|
|
||||||
let item = res.devices[i];
|
|
||||||
disconnect(item.deviceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("无连接设备");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
//发送二进制数据
|
|
||||||
sendData: function(deviceid, buffer) {
|
|
||||||
|
|
||||||
console.log("准备向设备发送数据,deviceid=" + deviceid);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!deviceid) {
|
|
||||||
reject(`deviceid为空,请输入要发送的设备`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("准备发送数据包");
|
|
||||||
let key = "linkedDevices";
|
|
||||||
var store = uni.getStorageInfoSync();
|
|
||||||
var f = store.keys.find(function(v) {
|
|
||||||
return v == key;
|
|
||||||
});
|
|
||||||
console.log("倒计时:5");
|
|
||||||
var linkedDevices = [];
|
|
||||||
if (f) {
|
|
||||||
var str = uni.getStorageSync(key);
|
|
||||||
if (str) {
|
|
||||||
linkedDevices = JSON.parse(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
console.log("倒计时:4");
|
|
||||||
if (linkedDevices && linkedDevices.length && linkedDevices.length > 0) {
|
|
||||||
console.log("倒计时:3");
|
|
||||||
f = linkedDevices.find(function(v) {
|
|
||||||
return v.deviceId == deviceid;
|
|
||||||
|
|
||||||
});
|
|
||||||
console.log("f=" + JSON.stringify(f));
|
|
||||||
// console.log("deviceid=" + deviceid);
|
|
||||||
console.log("倒计时:2");
|
|
||||||
if (f) {
|
|
||||||
console.log("倒计时:1");
|
|
||||||
uni.writeBLECharacteristicValue({
|
|
||||||
deviceId: f.deviceId,
|
|
||||||
serviceId: f.writeServiceId,
|
|
||||||
characteristicId: f.wirteCharactId,
|
|
||||||
value: buffer,
|
|
||||||
success: () => {
|
|
||||||
console.log("发送数据成功");
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.log("发送数据失败" + JSON.stringify(err));
|
|
||||||
reject(`发送数据失败: ${err.errMsg}`);
|
|
||||||
},
|
|
||||||
complete: function() {
|
|
||||||
console.log("发送数据complete");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject(`已连接设备中无法找到此设备`);
|
|
||||||
// console.log("警报:已连接设备中无法找到此设备")
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("检测到未与设备建立连接");
|
|
||||||
reject(`检测到未与设备建立连接`);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
sendDataNew: function(deviceid, serviceId, characteristicId, buffer) {
|
|
||||||
|
|
||||||
console.log("准备向设备发送数据,deviceid=" + deviceid);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
uni.writeBLECharacteristicValue({
|
|
||||||
deviceId: deviceid,
|
|
||||||
serviceId: serviceId,
|
|
||||||
characteristicId: characteristicId,
|
|
||||||
value: buffer,
|
|
||||||
success: () => {
|
|
||||||
console.log("发送数据成功");
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.log("发送数据失败" + JSON.stringify(err));
|
|
||||||
reject(`发送数据失败: ${err.errMsg}`);
|
|
||||||
},
|
|
||||||
complete: function() {
|
|
||||||
console.log("发送数据complete");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
93
api/670/HBY670.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import {request,baseURL} from '@/utils/request'
|
||||||
|
|
||||||
|
function getdata(data,url,method){
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
if(!url){
|
||||||
|
reject('url为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!method){
|
||||||
|
method='POST';
|
||||||
|
}
|
||||||
|
request({
|
||||||
|
url: url,
|
||||||
|
method: method,
|
||||||
|
data:data
|
||||||
|
}).then((res)=>{
|
||||||
|
resolve(res);
|
||||||
|
}).catch(ex=>{
|
||||||
|
reject(ex);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//人员信息设置
|
||||||
|
function sendUsr(data){
|
||||||
|
let url="/app/xinghan/device/registerPersonInfo";
|
||||||
|
return getdata(data,url,"POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
//报警信息
|
||||||
|
function warnMsg(data){
|
||||||
|
let url="/app/xinghan/device/sendAlarmMessage"
|
||||||
|
return getdata(data,url,"POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
//开机图片
|
||||||
|
function sendPic(data){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
const token = uni.getStorageSync('token');
|
||||||
|
const clientid = uni.getStorageSync('clientID');
|
||||||
|
let config = {
|
||||||
|
header: {}
|
||||||
|
};
|
||||||
|
if (token) {
|
||||||
|
config.header['Authorization'] = 'Bearer ' + token;
|
||||||
|
config.header['clientid'] = clientid;
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.uploadFile({
|
||||||
|
|
||||||
|
url: baseURL + '/app/xinghan/device/uploadLogo',
|
||||||
|
filePath: data.picPath,
|
||||||
|
name: 'file',
|
||||||
|
formData: {
|
||||||
|
deviceId: data.deviceId,
|
||||||
|
deviceImei: data.deviceImei
|
||||||
|
},
|
||||||
|
header: config.header,
|
||||||
|
timeout: 600000,
|
||||||
|
fail: (ex) => {
|
||||||
|
console.log("上传视频失败" ,ex);
|
||||||
|
reject(ex);
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
console.log("上传完成", res);
|
||||||
|
if(res.statusCode==200){
|
||||||
|
resolve(JSON.parse(res.data));
|
||||||
|
}else{
|
||||||
|
reject(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default{
|
||||||
|
sendUsr:sendUsr,
|
||||||
|
warnMsg:warnMsg,
|
||||||
|
sendPic:sendPic
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2,17 +2,14 @@
|
|||||||
<view class="message-popup" :class="{ 'show': config.show }">
|
<view class="message-popup" :class="{ 'show': config.show }">
|
||||||
|
|
||||||
<view class="mask" @click="closeMenu" :class="{ 'show': config.show }"
|
<view class="mask" @click="closeMenu" :class="{ 'show': config.show }"
|
||||||
:style="{backgroundColor:config.maskBgColor,display:(config.showMask?'':'none')}"
|
:style="{backgroundColor:config.maskBgColor,display:(config.showMask?'':'none')}">
|
||||||
>
|
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<view class="bottom-slide-menu" :style="{ backgroundColor: config.bgColor }" :class="{ 'show': config.show }"
|
<view class="bottom-slide-menu" :style="{ backgroundColor: config.bgColor }" :class="{ 'show': config.show }"
|
||||||
@touchmove.stop.prevent>
|
@touchmove.stop.prevent>
|
||||||
<view class="menu-header" :class="config.showHeader?'':'displayNone'">
|
<view class="menu-header" :class="config.showHeader?'':'displayNone'">
|
||||||
<view class="title" :style="{ color: config.textColor}">{{ config.title }}</view>
|
<view class="title" :style="{ color: config.textColor}">{{ config.title }}</view>
|
||||||
<view class="close-icon" @click="closeMenu"
|
<view class="close-icon" @click="closeMenu" :style="{display:(config.showClose?'':'none')}">
|
||||||
:style="{display:(config.showClose?'':'none')}"
|
|
||||||
>
|
|
||||||
<image src="/static/Images/public/close.png" mode="aspectFit"></image>
|
<image src="/static/Images/public/close.png" mode="aspectFit"></image>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -29,7 +26,13 @@
|
|||||||
<view class="p100" :style="{backgroundColor:config.activeIndex==index?config.itemBgColor:'',
|
<view class="p100" :style="{backgroundColor:config.activeIndex==index?config.itemBgColor:'',
|
||||||
justifyContent:config.textAlign
|
justifyContent:config.textAlign
|
||||||
}">
|
}">
|
||||||
<image v-if="item.icon" :src="item.icon" mode="aspectFit"></image>
|
<view class="imgContent" :style="{
|
||||||
|
height:config.itemHeight,
|
||||||
|
width:config.itemHeight
|
||||||
|
}">
|
||||||
|
<image v-if="item.icon" :src="item.icon" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
|
||||||
<text>{{ item.text }}</text>
|
<text>{{ item.text }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -61,34 +64,34 @@
|
|||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
show: false,//是否显示
|
show: false, //是否显示
|
||||||
showHeader: false,//是否显示标头
|
showHeader: false, //是否显示标头
|
||||||
showMask:true,//是否显示mask
|
showMask: true, //是否显示mask
|
||||||
showDivider: false,//是否在两个项之间显示分隔线
|
showDivider: false, //是否在两个项之间显示分隔线
|
||||||
showBtn: false,//是否显示底部按钮
|
showBtn: false, //是否显示底部按钮
|
||||||
showClose:false,//是否显示右上角关闭按钮
|
showClose: false, //是否显示右上角关闭按钮
|
||||||
maskBgColor:'',//mask的颜色
|
maskBgColor: '', //mask的颜色
|
||||||
menuItems: [],//菜单项 包含icon text
|
menuItems: [], //菜单项 包含icon text
|
||||||
activeIndex: -1,//当前已选中的项编号
|
activeIndex: -1, //当前已选中的项编号
|
||||||
bgColor: '#2a2a2a',//主体背景
|
bgColor: '#2a2a2a', //主体背景
|
||||||
itemBgColor: '#3a3a3a',//各项被选中后的背景
|
itemBgColor: '#3a3a3a', //各项被选中后的背景
|
||||||
textColor: '#ffffffde',//各项的文字颜色
|
textColor: '#ffffffde', //各项的文字颜色
|
||||||
textAlign: 'flex-start',//各项的文字居中方式
|
textAlign: 'flex-start', //各项的文字居中方式
|
||||||
title: '',//header的文字
|
title: '', //header的文字
|
||||||
dividerColor: '#00000000',//分隔线颜色
|
dividerColor: '#00000000', //分隔线颜色
|
||||||
dividerThickness: '0rpx',//分隔线宽度
|
dividerThickness: '0rpx', //分隔线宽度
|
||||||
dividerMargin: '10rpx',//分隔线距离两边的宽度
|
dividerMargin: '10rpx', //分隔线距离两边的宽度
|
||||||
itemHeight: '80rpx',//各项的调试
|
itemHeight: '80rpx', //各项的调试
|
||||||
btnBgColor: "#bbe600",//按钮颜色
|
btnBgColor: "#bbe600", //按钮颜色
|
||||||
btnText: "确定",//按钮文字
|
btnText: "确定", //按钮文字
|
||||||
btnTextColor: "#000000",//按钮文字颜色
|
btnTextColor: "#000000", //按钮文字颜色
|
||||||
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
closeMenu() {
|
closeMenu() {
|
||||||
|
|
||||||
@ -100,19 +103,18 @@
|
|||||||
this.$emit('itemClick', item, index);
|
this.$emit('itemClick', item, index);
|
||||||
},
|
},
|
||||||
btnClick() {
|
btnClick() {
|
||||||
|
|
||||||
let item = null;
|
let item = null;
|
||||||
let index = null;
|
let index = null;
|
||||||
if (this.config.activeIndex > -1) {
|
if (this.config.activeIndex > -1) {
|
||||||
item = this.config.menuItems[this.config.activeIndex];
|
item = this.config.menuItems[this.config.activeIndex];
|
||||||
}
|
}
|
||||||
index = this.config.activeIndex;
|
index = this.config.activeIndex;
|
||||||
this.$emit('btnClick', item, index);
|
this.$emit('btnClick', item, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -126,7 +128,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.p100 {
|
.p100 {
|
||||||
width: 100%;
|
width: calc(100% - 20rpx);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -136,7 +138,8 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 0rpx 20rpx;
|
padding: 0rpx 20rpx 0rpx 0rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.displayNone {
|
.displayNone {
|
||||||
@ -151,7 +154,7 @@
|
|||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
transition: transform 0.3s ease-out;
|
transition: transform 0.3s ease-out;
|
||||||
transform: translateY(100%);
|
transform: translateY(100%);
|
||||||
border-radius: 16rpx 16rpx 0 0;
|
border-radius: 32rpx 32rpx 0 0;
|
||||||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,11 +220,24 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item image {
|
.menu-item image {
|
||||||
width: 40rpx;
|
width: 40rpx;
|
||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.imgContent {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: #4a4a4a;
|
||||||
|
border-radius: 10rpx;
|
||||||
margin-right: 20rpx;
|
margin-right: 20rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
194
components/TextToHex/TextToHex.vue
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<canvas type="2d" canvas-id="reusableCanvas" :width="currentCanvasWidth" :height="currentCanvasHeight"
|
||||||
|
class="offscreen-canvas"></canvas>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "TextToHexV1",
|
||||||
|
props: {
|
||||||
|
txts: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
validator: (value) => value.every(item => typeof item === 'string')
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 16,
|
||||||
|
validator: (value) => value > 0 && value <= 100
|
||||||
|
},
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#ffffff"
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: "#000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 当前Canvas的宽高(动态调整)
|
||||||
|
currentCanvasWidth: 0,
|
||||||
|
currentCanvasHeight: 0,
|
||||||
|
// Canvas上下文(复用)
|
||||||
|
ctx: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
validTxts() {
|
||||||
|
return this.txts.filter(line => line.trim() !== '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 初始化Canvas上下文(只创建一次)
|
||||||
|
this.ctx = uni.createCanvasContext('reusableCanvas', this);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 估算单行文本所需的Canvas宽度
|
||||||
|
*/
|
||||||
|
calcLineWidth(textLine) {
|
||||||
|
return textLine.length * this.fontSize;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除Canvas内容
|
||||||
|
*/
|
||||||
|
clearCanvas() {
|
||||||
|
this.ctx.setFillStyle(this.bgColor);
|
||||||
|
this.ctx.fillRect(0, 0, this.currentCanvasWidth, this.currentCanvasHeight);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复用单个Canvas处理所有文本行
|
||||||
|
*/
|
||||||
|
async drawAndGetPixels() {
|
||||||
|
|
||||||
|
let convertCharToMatrix=function(imageData) {
|
||||||
|
// console.log("imgData=",imageData)
|
||||||
|
let matrix = [];
|
||||||
|
|
||||||
|
// 逐行处理
|
||||||
|
for (let y = 0; y < 16; y++) {
|
||||||
|
let byte1 = 0,
|
||||||
|
byte2 = 0;
|
||||||
|
|
||||||
|
// 每行16个像素,分为两个字节
|
||||||
|
for (let x = 0; x < 16; x++) {
|
||||||
|
// 计算像素在imageData中的索引 (RGBA格式)
|
||||||
|
let index = (y * 16 + x) * 4;
|
||||||
|
let red = imageData[index];
|
||||||
|
|
||||||
|
// 黑色像素(R值较低)视为1,白色视为0
|
||||||
|
let isBlack = red < 128;
|
||||||
|
|
||||||
|
if (x < 8) {
|
||||||
|
// 第一个字节(左8位)
|
||||||
|
if (isBlack) {
|
||||||
|
byte1 |= 0x80 >> x; // 从左到右设置位
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 第二个字节(右8位)
|
||||||
|
if (isBlack) {
|
||||||
|
byte2 |= 0x80 >> (x - 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将字节转换为两位十六进制字符串
|
||||||
|
matrix.push('0x' + byte1.toString(16).padStart(2, '0').toUpperCase());
|
||||||
|
matrix.push('0x' + byte2.toString(16).padStart(2, '0').toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
let drawTxt=async (textLine)=> {
|
||||||
|
let result = {};
|
||||||
|
let ctx = this.ctx;
|
||||||
|
|
||||||
|
// 1. 动态调整Canvas尺寸
|
||||||
|
this.currentCanvasWidth = this.calcLineWidth(textLine);
|
||||||
|
this.currentCanvasHeight = this.fontSize;
|
||||||
|
|
||||||
|
// 2. 清空Canvas(绘制背景)
|
||||||
|
this.clearCanvas();
|
||||||
|
|
||||||
|
// 3. 设置文字样式
|
||||||
|
ctx.setFillStyle(this.color);
|
||||||
|
ctx.setTextBaseline('middle');
|
||||||
|
ctx.setFontSize(this.fontSize);
|
||||||
|
ctx.font = `${this.fontSize}px "PingFang SC", PingFang SC, Arial, sans-serif`;
|
||||||
|
|
||||||
|
// 4. 绘制当前行文本
|
||||||
|
let currentX = 0;
|
||||||
|
let currentY = this.fontSize / 2;
|
||||||
|
for (let j = 0; j < textLine.length; j++) {
|
||||||
|
let char = textLine[j];
|
||||||
|
ctx.fillText(char, currentX, currentY);
|
||||||
|
// 按实际字符宽度计算间距
|
||||||
|
let charWidth = ctx.measureText(char).width;
|
||||||
|
currentX += charWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 异步绘制并获取像素数据(串行处理避免冲突)
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
ctx.draw(false, () => {
|
||||||
|
uni.canvasGetImageData({
|
||||||
|
canvasId: 'reusableCanvas',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: this.currentCanvasWidth,
|
||||||
|
height: this.currentCanvasHeight,
|
||||||
|
success: res => {
|
||||||
|
|
||||||
|
result={
|
||||||
|
line: textLine,
|
||||||
|
pixelData: res.data,
|
||||||
|
width: this.currentCanvasWidth,
|
||||||
|
height: this.currentCanvasHeight
|
||||||
|
};
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
// console.error(`处理第${i+1}行失败:`, err);
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
let arr = [];
|
||||||
|
// 循环处理每行文本
|
||||||
|
for (let i = 0; i < this.validTxts.length; i++) {
|
||||||
|
|
||||||
|
let linePixls = [];
|
||||||
|
let item = this.validTxts[i];
|
||||||
|
console.log("item=",item);
|
||||||
|
for (var j = 0; j < item.length; j++) {
|
||||||
|
let result = await drawTxt(item[j]);
|
||||||
|
linePixls.push(convertCharToMatrix(result.pixelData));
|
||||||
|
}
|
||||||
|
console.log("hexs=",linePixls.join(","));
|
||||||
|
arr.push(linePixls);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.offscreen-canvas {
|
||||||
|
position: fixed;
|
||||||
|
left: -9999px;
|
||||||
|
top: -9999px;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
194
components/TextToHex/TextToHexV1.vue
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<canvas type="2d" canvas-id="reusableCanvas" :width="currentCanvasWidth" :height="currentCanvasHeight"
|
||||||
|
class="offscreen-canvas"></canvas>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "TextToHexV1",
|
||||||
|
props: {
|
||||||
|
txts: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
validator: (value) => value.every(item => typeof item === 'string')
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 16,
|
||||||
|
validator: (value) => value > 0 && value <= 100
|
||||||
|
},
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#ffffff"
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: "#000000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 当前Canvas的宽高(动态调整)
|
||||||
|
currentCanvasWidth: 0,
|
||||||
|
currentCanvasHeight: 0,
|
||||||
|
// Canvas上下文(复用)
|
||||||
|
ctx: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
validTxts() {
|
||||||
|
return this.txts.filter(line => line.trim() !== '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 初始化Canvas上下文(只创建一次)
|
||||||
|
this.ctx = uni.createCanvasContext('reusableCanvas', this);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 估算单行文本所需的Canvas宽度
|
||||||
|
*/
|
||||||
|
calcLineWidth(textLine) {
|
||||||
|
return textLine.length * this.fontSize;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除Canvas内容
|
||||||
|
*/
|
||||||
|
clearCanvas() {
|
||||||
|
this.ctx.setFillStyle(this.bgColor);
|
||||||
|
this.ctx.fillRect(0, 0, this.currentCanvasWidth, this.currentCanvasHeight);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复用单个Canvas处理所有文本行
|
||||||
|
*/
|
||||||
|
async drawAndGetPixels() {
|
||||||
|
|
||||||
|
let convertCharToMatrix=function(imageData) {
|
||||||
|
// console.log("imgData=",imageData)
|
||||||
|
let matrix = [];
|
||||||
|
|
||||||
|
// 逐行处理
|
||||||
|
for (let y = 0; y < 16; y++) {
|
||||||
|
let byte1 = 0,
|
||||||
|
byte2 = 0;
|
||||||
|
|
||||||
|
// 每行16个像素,分为两个字节
|
||||||
|
for (let x = 0; x < 16; x++) {
|
||||||
|
// 计算像素在imageData中的索引 (RGBA格式)
|
||||||
|
let index = (y * 16 + x) * 4;
|
||||||
|
let red = imageData[index];
|
||||||
|
|
||||||
|
// 黑色像素(R值较低)视为1,白色视为0
|
||||||
|
let isBlack = red < 128;
|
||||||
|
|
||||||
|
if (x < 8) {
|
||||||
|
// 第一个字节(左8位)
|
||||||
|
if (isBlack) {
|
||||||
|
byte1 |= 0x80 >> x; // 从左到右设置位
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 第二个字节(右8位)
|
||||||
|
if (isBlack) {
|
||||||
|
byte2 |= 0x80 >> (x - 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将字节转换为两位十六进制字符串
|
||||||
|
matrix.push('0x' + byte1.toString(16).padStart(2, '0').toUpperCase());
|
||||||
|
matrix.push('0x' + byte2.toString(16).padStart(2, '0').toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
let drawTxt=async (textLine)=> {
|
||||||
|
let result = {};
|
||||||
|
let ctx = this.ctx;
|
||||||
|
|
||||||
|
// 1. 动态调整Canvas尺寸
|
||||||
|
this.currentCanvasWidth = this.calcLineWidth(textLine);
|
||||||
|
this.currentCanvasHeight = this.fontSize;
|
||||||
|
|
||||||
|
// 2. 清空Canvas(绘制背景)
|
||||||
|
this.clearCanvas();
|
||||||
|
|
||||||
|
// 3. 设置文字样式
|
||||||
|
ctx.setFillStyle(this.color);
|
||||||
|
ctx.setTextBaseline('middle');
|
||||||
|
ctx.setFontSize(this.fontSize);
|
||||||
|
ctx.font = `${this.fontSize}px "PingFang SC", PingFang SC, Arial, sans-serif`;
|
||||||
|
|
||||||
|
// 4. 绘制当前行文本
|
||||||
|
let currentX = 0;
|
||||||
|
let currentY = this.fontSize / 2;
|
||||||
|
for (let j = 0; j < textLine.length; j++) {
|
||||||
|
let char = textLine[j];
|
||||||
|
ctx.fillText(char, currentX, currentY);
|
||||||
|
// 按实际字符宽度计算间距
|
||||||
|
let charWidth = ctx.measureText(char).width;
|
||||||
|
currentX += charWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 异步绘制并获取像素数据(串行处理避免冲突)
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
ctx.draw(false, () => {
|
||||||
|
uni.canvasGetImageData({
|
||||||
|
canvasId: 'reusableCanvas',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: this.currentCanvasWidth,
|
||||||
|
height: this.currentCanvasHeight,
|
||||||
|
success: res => {
|
||||||
|
|
||||||
|
result={
|
||||||
|
line: textLine,
|
||||||
|
pixelData: res.data,
|
||||||
|
width: this.currentCanvasWidth,
|
||||||
|
height: this.currentCanvasHeight
|
||||||
|
};
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
// console.error(`处理第${i+1}行失败:`, err);
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
let arr = [];
|
||||||
|
// 循环处理每行文本
|
||||||
|
for (let i = 0; i < this.validTxts.length; i++) {
|
||||||
|
|
||||||
|
let linePixls = [];
|
||||||
|
let item = this.validTxts[i];
|
||||||
|
console.log("item=",item);
|
||||||
|
for (var j = 0; j < item.length; j++) {
|
||||||
|
let result = await drawTxt(item[j]);
|
||||||
|
linePixls.push(convertCharToMatrix(result.pixelData));
|
||||||
|
}
|
||||||
|
console.log("hexs=",linePixls.join(","));
|
||||||
|
arr.push(linePixls);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.offscreen-canvas {
|
||||||
|
position: fixed;
|
||||||
|
left: -9999px;
|
||||||
|
top: -9999px;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
199
components/global-loading/global-loading.vue
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
<template>
|
||||||
|
<view v-if="visible" class="loading-container" @touchmove.stop.prevent="handleTouchMove">
|
||||||
|
<view class="loading-content">
|
||||||
|
<!-- 刻度点容器 -->
|
||||||
|
<view class="clock-container">
|
||||||
|
<view v-for="(dot, index) in dots" :key="index" class="clock-dot" :style="{
|
||||||
|
transform: `rotate(${index * angle}deg) translateY(-${radius}px)`,
|
||||||
|
backgroundColor: getDotColor(index),
|
||||||
|
animationDuration: `${duration}ms`,
|
||||||
|
animationDelay: `${index * (duration / dotsCount)}ms`
|
||||||
|
}"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 提示文本 -->
|
||||||
|
<text class="loading-text" :class="text?'':'displayNone'" :style="{ color: textColor }">{{ text }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
dotsCount: 12,
|
||||||
|
dotColors: ['#CEF231'],
|
||||||
|
text: '请稍候...',//文本文字
|
||||||
|
textColor: '#FFFFFFde',//文本颜色
|
||||||
|
radius: 32,//圆的半径
|
||||||
|
duration: 1200,//动画的播放速度
|
||||||
|
colorIndex: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 计算每个点之间的角度
|
||||||
|
angle() {
|
||||||
|
return 360 / this.dotsCount
|
||||||
|
},
|
||||||
|
// 生成刻度点数组
|
||||||
|
dots() {
|
||||||
|
return Array.from({
|
||||||
|
length: this.dotsCount
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取刻度点颜色(实现无限循环变色)
|
||||||
|
getDotColor(index) {
|
||||||
|
// 根据当前颜色索引和刻度点位置计算颜色
|
||||||
|
const colorIndex = (index + this.colorIndex) % this.dotColors.length
|
||||||
|
return this.dotColors[colorIndex]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更新颜色索引(实现循环变色)
|
||||||
|
updateColorIndex() {
|
||||||
|
this.colorIndex = (this.colorIndex + 1) % this.dotColors.length
|
||||||
|
},
|
||||||
|
|
||||||
|
// 显示loading
|
||||||
|
show(options) {
|
||||||
|
|
||||||
|
if(!options){
|
||||||
|
options={};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update(options)
|
||||||
|
this.visible = true
|
||||||
|
|
||||||
|
// 启动颜色循环
|
||||||
|
if (!this.colorTimer) {
|
||||||
|
this.colorTimer = setInterval(() => {
|
||||||
|
this.updateColorIndex()
|
||||||
|
}, this.duration / this.dotColors.length)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 隐藏loading
|
||||||
|
hide() {
|
||||||
|
|
||||||
|
this.visible = false
|
||||||
|
// 清除颜色循环定时器
|
||||||
|
if (this.colorTimer) {
|
||||||
|
clearInterval(this.colorTimer)
|
||||||
|
this.colorTimer = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 更新loading配置
|
||||||
|
update(options) {
|
||||||
|
if(!options){
|
||||||
|
options={a:1};
|
||||||
|
}
|
||||||
|
Object.keys(options).forEach(key => {
|
||||||
|
if (this[key] !== undefined) {
|
||||||
|
this[key] = options[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 如果更新了颜色数组,重置颜色索引
|
||||||
|
if (options.dotColors) {
|
||||||
|
this.colorIndex = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 阻止触摸移动事件
|
||||||
|
handleTouchMove() {}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
// 组件销毁前清除定时器
|
||||||
|
if (this.colorTimer) {
|
||||||
|
clearInterval(this.colorTimer)
|
||||||
|
this.colorTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 全屏遮罩层 */
|
||||||
|
.loading-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #000000c2;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 99999999999;
|
||||||
|
pointer-events: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-bottom: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容居中 */
|
||||||
|
.loading-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transform: translateZ(0);
|
||||||
|
/* 启用GPU加速 */
|
||||||
|
margin-top: -150rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 刻度容器 */
|
||||||
|
.clock-container {
|
||||||
|
position: relative;
|
||||||
|
width: 200rpx;
|
||||||
|
height: 200rpx;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 单个刻度点 */
|
||||||
|
.clock-dot {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 6rpx;
|
||||||
|
height: 30rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
/* margin-top: -4rpx;
|
||||||
|
margin-left: -4rpx; */
|
||||||
|
transform-origin: 0 0;
|
||||||
|
animation: colorScale infinite ease-in-out;
|
||||||
|
box-shadow: 0 0 8rpx rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 刻度点动画 - 颜色和大小变化 */
|
||||||
|
@keyframes colorScale {
|
||||||
|
0% {
|
||||||
|
opacity: 0.05;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 提示文本 */
|
||||||
|
.loading-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 1.4rpx;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 80vw;
|
||||||
|
|
||||||
|
|
||||||
|
font-family: 'PingFang SC';
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayNone{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -2,11 +2,11 @@
|
|||||||
const config = {
|
const config = {
|
||||||
// 开发环境
|
// 开发环境
|
||||||
development: {
|
development: {
|
||||||
BASE_URL: 'http://192.168.2.34:8000',
|
BASE_URL: 'http://192.168.110.54:8000',
|
||||||
API_PREFIX: '',
|
API_PREFIX: '',
|
||||||
// MQTT 配置
|
// MQTT 配置
|
||||||
MQTT_HOST: '47.120.79.150',
|
MQTT_HOST: '47.120.79.150',
|
||||||
MQTT_PORT: 9083,
|
MQTT_PORT: 8083,
|
||||||
MQTT_USERNAME: 'admin',
|
MQTT_USERNAME: 'admin',
|
||||||
MQTT_PASSWORD: '#YtvpSfCNG'
|
MQTT_PASSWORD: '#YtvpSfCNG'
|
||||||
},
|
},
|
||||||
@ -16,7 +16,7 @@ const config = {
|
|||||||
API_PREFIX: '',
|
API_PREFIX: '',
|
||||||
// MQTT 配置
|
// MQTT 配置
|
||||||
MQTT_HOST: '47.120.79.150',
|
MQTT_HOST: '47.120.79.150',
|
||||||
MQTT_PORT: 9083,
|
MQTT_PORT: 8083,
|
||||||
MQTT_USERNAME: 'admin',
|
MQTT_USERNAME: 'admin',
|
||||||
MQTT_PASSWORD: '#YtvpSfCNG'
|
MQTT_PASSWORD: '#YtvpSfCNG'
|
||||||
}
|
}
|
||||||
|
|||||||
2
main.js
@ -1,6 +1,6 @@
|
|||||||
import App from './App'
|
import App from './App'
|
||||||
|
|
||||||
// 引入 uView UI
|
//// 引入 uView UI
|
||||||
import uView from 'vk-uview-ui';
|
import uView from 'vk-uview-ui';
|
||||||
import bleTool from '@/store/BLETools.js';
|
import bleTool from '@/store/BLETools.js';
|
||||||
|
|
||||||
|
|||||||
6
package-lock.json
generated
@ -272,7 +272,8 @@
|
|||||||
"node_modules/mescroll-uni": {
|
"node_modules/mescroll-uni": {
|
||||||
"version": "1.3.7",
|
"version": "1.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/mescroll-uni/-/mescroll-uni-1.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/mescroll-uni/-/mescroll-uni-1.3.7.tgz",
|
||||||
"integrity": "sha512-1pQMtGA+iVRKhfJZZNXdBx05NnthIk6zm3hRbumswSA54eaKOMgpUDb9AQ2+rRdXmS6kLkEYSbW/fkb7/IyoAg=="
|
"integrity": "sha512-1pQMtGA+iVRKhfJZZNXdBx05NnthIk6zm3hRbumswSA54eaKOMgpUDb9AQ2+rRdXmS6kLkEYSbW/fkb7/IyoAg==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime-db": {
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
@ -296,7 +297,8 @@
|
|||||||
"node_modules/paho-mqtt": {
|
"node_modules/paho-mqtt": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/paho-mqtt/-/paho-mqtt-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/paho-mqtt/-/paho-mqtt-1.1.0.tgz",
|
||||||
"integrity": "sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA=="
|
"integrity": "sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA==",
|
||||||
|
"license": "EPL-1.0"
|
||||||
},
|
},
|
||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
|||||||
83
pages.json
@ -190,6 +190,89 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "呼叫"
|
"navigationBarTitleText": "呼叫"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/VideoSend",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "发送视频"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/VideoSend_1",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "发送视频"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/VideoSend_670",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "发送视频"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/HBY650",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "HBY650"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/HBY650_1",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "HBY650"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/ModeSetting",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "7307-0.96TFT"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/update",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "版本更新"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/HBY6155",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "HBY6155"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/HBY6155V1",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "HBY6155_V1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/HBY670V1",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "HBY670"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"path": "pages/BlueTooth/ModeSetting/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "设备类型"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/670/HBY670",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "HBY670"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/650/HBY650",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "HBY650"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -25,18 +25,21 @@
|
|||||||
onLoad: function(option) {
|
onLoad: function(option) {
|
||||||
const eventChannel = this.getOpenerEventChannel();
|
const eventChannel = this.getOpenerEventChannel();
|
||||||
var these = this;
|
var these = this;
|
||||||
eventChannel.on('checkImg', function(data) {
|
eventChannel.on('checkImg', (data)=> {
|
||||||
console.log("我收到你的消息了,消息内容是:" + JSON.stringify(data));
|
console.log("我收到你的消息了,消息内容是:" + JSON.stringify(data));
|
||||||
these.src = data.data;
|
this.src = data.data;
|
||||||
|
console.log("我收到你的消息了,消息内容是:",data);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleCrop(e) {
|
handleCrop(e) {
|
||||||
|
|
||||||
var these = this;
|
var these = this;
|
||||||
|
|
||||||
this.Statu = true;
|
this.Statu = true;
|
||||||
console.log("裁剪完成");
|
console.log("裁剪完成");
|
||||||
console.log(e.tempFilePath);
|
console.log(e.tempFilePath);
|
||||||
|
//
|
||||||
const ctx = uni.createCanvasContext('splashCanvas', this);
|
const ctx = uni.createCanvasContext('splashCanvas', this);
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
e.tempFilePath,
|
e.tempFilePath,
|
||||||
@ -53,11 +56,12 @@
|
|||||||
height: 80,
|
height: 80,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
// 处理像素数据并发送
|
// 处理像素数据并发送
|
||||||
|
const eventChannel = these.getOpenerEventChannel();
|
||||||
console.log("res.data.length="+res.data.length);
|
console.log("res.data.length="+res.data.length);
|
||||||
// this.processAndSendImageData(res.data).then(
|
|
||||||
// resolve).catch(reject);
|
|
||||||
const eventChannel = these.getOpenerEventChannel();
|
eventChannel.emit('ImgCutOver',{piexls:res.data,picPath:e.tempFilePath});
|
||||||
eventChannel.emit('ImgCutOver',res.data);
|
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
|
|||||||
1841
pages/650/HBY650.vue
Normal file
2360
pages/670/HBY670.vue
Normal file
1947
pages/BlueTooth/ModeSetting/HBY6155.vue
Normal file
1925
pages/BlueTooth/ModeSetting/HBY6155V1.vue
Normal file
1892
pages/BlueTooth/ModeSetting/HBY650.vue
Normal file
1899
pages/BlueTooth/ModeSetting/HBY650_1.vue
Normal file
2837
pages/BlueTooth/ModeSetting/HBY670V1.vue
Normal file
1499
pages/BlueTooth/ModeSetting/ModeSetting.vue
Normal file
472
pages/BlueTooth/ModeSetting/VideoSend.vue
Normal file
@ -0,0 +1,472 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<canvas canvas-id="flashCanvas"
|
||||||
|
style="width: 160px; height: 80px; z-index: 9999;position: fixed; top:-9999px;left:-9999px;"></canvas>
|
||||||
|
|
||||||
|
<f-video ref="compARef" :src="videoPath" :direction="-90" :autoplay="true" @shotVideoClick="shotVideoClick"
|
||||||
|
:videoWidth="videoWidth" :videoHeight="videoHeight"></f-video>
|
||||||
|
|
||||||
|
|
||||||
|
<view>
|
||||||
|
<text>发送间隔</text>
|
||||||
|
<input type="text" v-model="inteval" />
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<button @click="checkVideo">选择视频</button>
|
||||||
|
<!-- <button @click="CutImg">发送</button> -->
|
||||||
|
<button @click="uploadVideo">发送</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
<view class="sending-progress" v-if="isSending">
|
||||||
|
<view class="progress-bar">
|
||||||
|
<view class="progress-fill" :style="{ width: progress + '%' }"></view>
|
||||||
|
</view>
|
||||||
|
<text>正在发送: {{ progress }}% ({{ currentPacket }}/{{ totalPackets }})</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Common from '@/utils/Common';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
videoPath: '',
|
||||||
|
inteval: 0,
|
||||||
|
progress: 0,
|
||||||
|
currentPacket: 0,
|
||||||
|
totalPackets: 100,
|
||||||
|
|
||||||
|
connectedDeviceId: '',
|
||||||
|
serviceId: '0xFFE1',
|
||||||
|
writeCharacteristicId: '0xFFE1',
|
||||||
|
notifyCharacteristicId: '0xFFE2',
|
||||||
|
isSending: "",
|
||||||
|
textProgress: "",
|
||||||
|
|
||||||
|
imgs: [],
|
||||||
|
videoWidth: 320,
|
||||||
|
videoHeight: 160,
|
||||||
|
videoDuration: 2,
|
||||||
|
|
||||||
|
hexArray: []
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
const eventChannel = this.getOpenerEventChannel();
|
||||||
|
|
||||||
|
eventChannel.on('receiveDevice', (data) => {
|
||||||
|
this.connectedDeviceId = data.connectedDeviceId;
|
||||||
|
this.serviceId = data.serviceId;
|
||||||
|
this.writeCharacteristicId = data.writeCharacteristicId;
|
||||||
|
this.notifyCharacteristicId = data.notifyCharacteristicId;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkVideo: function() {
|
||||||
|
uni.chooseVideo({
|
||||||
|
sourceType: ['album', 'camera'],
|
||||||
|
compressed: false,
|
||||||
|
maxDuration: 2,
|
||||||
|
camera: 'back',
|
||||||
|
success: (res) => {
|
||||||
|
this.videoPath = res.tempFilePath;
|
||||||
|
|
||||||
|
this.imgs = [];
|
||||||
|
this.hexArray = [];
|
||||||
|
this.$refs.compARef.base64 = [];
|
||||||
|
this.videoWidth = res.width;
|
||||||
|
this.videoHeight = res.height;
|
||||||
|
this.videoDuration = res.duration;
|
||||||
|
console.log("视频宽:" + res.width + ",视频高:" + res.height + ",视频时长:" + res.duration);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadVideo: function() {
|
||||||
|
|
||||||
|
if (this.hexArray.length > 0) {
|
||||||
|
console.log("开始处理,无需上传");
|
||||||
|
this.shotVideoClick(this.hexArray, 'rgb565');
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
if(!this.videoPath){
|
||||||
|
uni.showToast({
|
||||||
|
title: "请选择视频",
|
||||||
|
icon: 'fail'
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("正在上传视频");
|
||||||
|
uni.showLoading({
|
||||||
|
title: "上传中"
|
||||||
|
});
|
||||||
|
|
||||||
|
let p2=new Promise((resolve,reject)=>{
|
||||||
|
let start = new Date();
|
||||||
|
console.log("Common.baseURL="+Common.baseURL);
|
||||||
|
uni.uploadFile({
|
||||||
|
url:Common.baseURL+'video/upload',
|
||||||
|
filePath: this.videoPath,
|
||||||
|
name: 'file',
|
||||||
|
header: {
|
||||||
|
"Method": "POST",
|
||||||
|
"Content-Type": "multipart/form-data"
|
||||||
|
},
|
||||||
|
timeout: 600000,
|
||||||
|
fail: (ex) => {
|
||||||
|
//console.log("上传视频失败" + JSON.stringify(ex));
|
||||||
|
uni.showToast({
|
||||||
|
title: "视频文件上传失败了,请检查网络连接",
|
||||||
|
icon: 'fail'
|
||||||
|
})
|
||||||
|
uni.hideLoading();
|
||||||
|
reject(ex);
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff - s) / 60;
|
||||||
|
console.log("上传完成,耗时:" + m + "分" + s + "秒");
|
||||||
|
uni.hideLoading();
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let p1=this.HoldYouHand();
|
||||||
|
|
||||||
|
Promise.all([p2,p1]).then((arr)=>{
|
||||||
|
|
||||||
|
if(arr[1]===true){
|
||||||
|
let res=arr[0];
|
||||||
|
res = JSON.parse(res.data);
|
||||||
|
|
||||||
|
if (res.data) {
|
||||||
|
this.hexArray = res.data;
|
||||||
|
uni.showLoading({
|
||||||
|
title: "正在发送"
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.shotVideoClick(res.data, 'rgb565');
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("res")
|
||||||
|
uni.showModal({
|
||||||
|
content: "服务器未返回RGB565数据",
|
||||||
|
title: '错误'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
uni.showModal({
|
||||||
|
content:"与设备握手失败了",
|
||||||
|
title:"错误"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
shotVideoClick: function(array, type) {
|
||||||
|
//console.log("处理视频完成", array);
|
||||||
|
//console.log("type=" + type)
|
||||||
|
//console.log("array=", array);
|
||||||
|
this.imgs = array;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var sendImagePackets = (imageData) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
this.isSending = true;
|
||||||
|
this.progress = 0;
|
||||||
|
this.currentPacket = 0;
|
||||||
|
|
||||||
|
// 总数据包数
|
||||||
|
const totalPackets = 1536;
|
||||||
|
this.totalPackets = totalPackets;
|
||||||
|
let currentPacket = 1;
|
||||||
|
|
||||||
|
// 发送单个数据包
|
||||||
|
const sendNextPacket = () => {
|
||||||
|
////console.log("currentPacket="+currentPacket+",imageData.length="+imageData.length);
|
||||||
|
if (currentPacket > totalPackets) {
|
||||||
|
this.isSending = false;
|
||||||
|
resolve();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算当前包的数据
|
||||||
|
let packetSize = 250;
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
packetSize = 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建数据包
|
||||||
|
const startIndex = (currentPacket - 1) * packetSize;
|
||||||
|
const endIndex = Math.min(startIndex + packetSize, imageData.length);
|
||||||
|
if (startIndex > endIndex) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
////console.log("111111");
|
||||||
|
const packetData = imageData.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
// 构建数据包
|
||||||
|
////console.log("packetData.length"+packetData.length);
|
||||||
|
const bufferSize = 506; // 头部5字节 + 数据部分
|
||||||
|
const buffer = new ArrayBuffer(bufferSize);
|
||||||
|
const dataView = new DataView(buffer);
|
||||||
|
|
||||||
|
let sortNo = currentPacket.toString(16).padStart(4, '0');
|
||||||
|
|
||||||
|
// 填充头部
|
||||||
|
dataView.setUint8(0, 0x55); // 帧头
|
||||||
|
dataView.setUint8(1, 0x04); // 帧类型:开机画面
|
||||||
|
dataView.setUint8(2, '0x' + sortNo.substring(0, 2)); // 包序号
|
||||||
|
dataView.setUint8(3, '0x' + sortNo.substring(2, 4)); // 包序号
|
||||||
|
|
||||||
|
|
||||||
|
dataView.setUint8(4, 0x01);
|
||||||
|
dataView.setUint8(5, 0xF4);
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
for (let i = 0; i < packetData.length; i++) {
|
||||||
|
dataView.setUint8(6 + i, '0x' + packetData[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < packetData.length; i++) {
|
||||||
|
dataView.setUint16(6 + i * 2, packetData[i], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let inteval = parseInt(this.inteval ? this.inteval : 0);
|
||||||
|
this.sendData(buffer).then(() => {
|
||||||
|
// 更新进度
|
||||||
|
this.currentPacket = currentPacket;
|
||||||
|
this.progress = Math.round((currentPacket / totalPackets) *
|
||||||
|
100);
|
||||||
|
//console.log(`发送数据包完成 ${currentPacket}/${totalPackets}`);
|
||||||
|
|
||||||
|
// 发送下一个包(添加延迟避免蓝牙缓冲区溢出)
|
||||||
|
currentPacket++;
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(sendNextPacket, inteval);
|
||||||
|
}).catch(err => {
|
||||||
|
|
||||||
|
// console.log(err.errMsg + ",发送失败了,正在补偿:" + currentPacket);
|
||||||
|
setTimeout(sendNextPacket, inteval);
|
||||||
|
// uni.showToast({
|
||||||
|
// title:"发送失败"+JSON.stringify(err)
|
||||||
|
// })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sendNextPacket();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
let start = new Date();
|
||||||
|
console.log("开始发送");
|
||||||
|
sendImagePackets(array).then(() => {
|
||||||
|
console.log("发送完成");
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff-s) / 60;
|
||||||
|
console.log("发送完成,耗时:" + m + "分" + s + "秒");
|
||||||
|
uni.showToast({
|
||||||
|
title: "发送完成,耗时:" + m + "分" + s + "秒",
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
}).catch((ex1) => {
|
||||||
|
//console.log("出现了异常", ex1)
|
||||||
|
}).finally(() => {
|
||||||
|
uni.hideLoading();
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
HoldYouHand() {
|
||||||
|
|
||||||
|
var promise=new Promise((resolve,reject)=>{
|
||||||
|
try{
|
||||||
|
let start=new Date();
|
||||||
|
var str = "video transmit start"; //握手的协议字符串
|
||||||
|
console.log("开始握手:"+str)
|
||||||
|
|
||||||
|
// 1. 创建 ArrayBuffer 和 DataView
|
||||||
|
const buffer = new ArrayBuffer(str.length);
|
||||||
|
const dataView = new DataView(buffer);
|
||||||
|
|
||||||
|
// 2. 将字符串转换为 ASCII 码并写入 DataView
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
dataView.setUint8(i, str.charCodeAt(i));
|
||||||
|
}
|
||||||
|
//console.log("111111");
|
||||||
|
this.sendData(buffer).then(() => {
|
||||||
|
// 开始发送第一个包
|
||||||
|
setTimeout(()=>{
|
||||||
|
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff - s) / 60;
|
||||||
|
|
||||||
|
console.log("握手成功并完成2200ms等待,耗时"+m+"分"+s+"秒");
|
||||||
|
|
||||||
|
resolve(true);
|
||||||
|
}, 2200);
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
//console.log("握手没有成功");
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
}catch(ex){
|
||||||
|
reject(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
|
||||||
|
},
|
||||||
|
sendData(buffer) {
|
||||||
|
////console.log("deviceId=" + this.connectedDeviceId);
|
||||||
|
////console.log("serviceId=" + this.serviceId);
|
||||||
|
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
|
||||||
|
// //console.log("开始发送数据,buffer");
|
||||||
|
|
||||||
|
|
||||||
|
var promise = new Promise((succ, err) => {
|
||||||
|
uni.writeBLECharacteristicValue({
|
||||||
|
deviceId: this.connectedDeviceId,
|
||||||
|
serviceId: this.serviceId,
|
||||||
|
characteristicId: this.writeCharacteristicId,
|
||||||
|
value: buffer,
|
||||||
|
writeType: plus.os.name == 'iOS' ? 'write' : 'writeNoResponse',
|
||||||
|
success: () => {
|
||||||
|
// //console.log("发送数据成功");
|
||||||
|
succ();
|
||||||
|
},
|
||||||
|
fail: (ex) => {
|
||||||
|
//console.log("发送数据失败", ex);
|
||||||
|
err(ex);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
// //console.log("123456");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (plus.os.name == 'iOS') {
|
||||||
|
|
||||||
|
function timeout(ms) {
|
||||||
|
return new Promise((_, err) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
err({
|
||||||
|
code: -1,
|
||||||
|
errMsg: '超时了'
|
||||||
|
})
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let inteval = parseInt(this.inteval ? this.inteval : 0);
|
||||||
|
|
||||||
|
Promise.race([promise, timeout(inteval)]).then(resolve).catch((ex) => {
|
||||||
|
//console.log("ex=", ex);
|
||||||
|
if (ex.code == -1) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
}).finally(() => {
|
||||||
|
//console.log("完成了")
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
promise.then(resolve).catch(reject);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
CutImg: function() {
|
||||||
|
if (this.imgs.length == 30) {
|
||||||
|
this.shotVideoClick(this.imgs, 'img');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//console.log("开始处理视频")
|
||||||
|
uni.showLoading({
|
||||||
|
title: '开始处理'
|
||||||
|
});
|
||||||
|
this.$refs.compARef.shotVideoClick(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sending-progress {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
height: 12rpx;
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #409eff;
|
||||||
|
transition: width 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 2rpx solid #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 100rpx;
|
||||||
|
line-height: 100rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100vw;
|
||||||
|
height: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
517
pages/BlueTooth/ModeSetting/VideoSend_1.vue
Normal file
@ -0,0 +1,517 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<canvas canvas-id="flashCanvas"
|
||||||
|
style="width: 160px; height: 80px; z-index: 9999;position: fixed; top:-9999px;left:-9999px;"></canvas>
|
||||||
|
|
||||||
|
<f-video ref="compARef" :src="videoPath" :direction="-90" :autoplay="true" @shotVideoClick="shotVideoClick"
|
||||||
|
:videoWidth="videoWidth" :videoHeight="videoHeight"></f-video>
|
||||||
|
|
||||||
|
<view>
|
||||||
|
<text>并发包数量</text>
|
||||||
|
<input type="text" v-model="packgeCnt" />
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<text>发送间隔</text>
|
||||||
|
<input type="text" v-model="inteval" />
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<button @click="checkVideo">选择视频</button>
|
||||||
|
<!-- <button @click="CutImg">发送</button> -->
|
||||||
|
<button @click="uploadVideo">发送</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
<view class="sending-progress" v-if="isSending">
|
||||||
|
<view class="progress-bar">
|
||||||
|
<view class="progress-fill" :style="{ width: progress + '%' }"></view>
|
||||||
|
</view>
|
||||||
|
<text>正在发送: {{ progress }}% ({{ currentPacket }}/{{ totalPackets }})</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
videoPath: '',
|
||||||
|
packgeCnt: 20,
|
||||||
|
inteval: 0,
|
||||||
|
progress: 0,
|
||||||
|
currentPacket: 0,
|
||||||
|
totalPackets: 100,
|
||||||
|
|
||||||
|
connectedDeviceId: '',
|
||||||
|
serviceId: '0xFFE1',
|
||||||
|
writeCharacteristicId: '0xFFE1',
|
||||||
|
notifyCharacteristicId: '0xFFE2',
|
||||||
|
isSending: "",
|
||||||
|
textProgress: "",
|
||||||
|
|
||||||
|
imgs: [],
|
||||||
|
videoWidth: 320,
|
||||||
|
videoHeight: 160,
|
||||||
|
videoDuration: 2,
|
||||||
|
|
||||||
|
hexArray: []
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
const eventChannel = this.getOpenerEventChannel();
|
||||||
|
|
||||||
|
eventChannel.on('receiveDevice', (data) => {
|
||||||
|
this.connectedDeviceId = data.connectedDeviceId;
|
||||||
|
this.serviceId = data.serviceId;
|
||||||
|
this.writeCharacteristicId = data.writeCharacteristicId;
|
||||||
|
this.notifyCharacteristicId = data.notifyCharacteristicId;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkVideo: function() {
|
||||||
|
uni.chooseVideo({
|
||||||
|
sourceType: ['album', 'camera'],
|
||||||
|
compressed: false,
|
||||||
|
maxDuration: 2,
|
||||||
|
camera: 'back',
|
||||||
|
success: (res) => {
|
||||||
|
this.videoPath = res.tempFilePath;
|
||||||
|
|
||||||
|
this.imgs = [];
|
||||||
|
this.hexArray = [];
|
||||||
|
this.$refs.compARef.base64 = [];
|
||||||
|
this.videoWidth = res.width;
|
||||||
|
this.videoHeight = res.height;
|
||||||
|
this.videoDuration = res.duration;
|
||||||
|
console.log("视频宽:" + res.width + ",视频高:" + res.height + ",视频时长:" + res.duration);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadVideo: function() {
|
||||||
|
|
||||||
|
if (this.hexArray.length > 0) {
|
||||||
|
console.log("开始处理,无需上传");
|
||||||
|
this.shotVideoClick(this.hexArray, 'rgb565');
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
if(!this.videoPath){
|
||||||
|
uni.showToast({
|
||||||
|
title: "请选择视频",
|
||||||
|
icon: 'fail'
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("正在上传视频");
|
||||||
|
uni.showLoading({
|
||||||
|
title: "上传中"
|
||||||
|
});
|
||||||
|
|
||||||
|
let p2=new Promise((resolve,reject)=>{
|
||||||
|
console.log("Common.baseURL="+Common.baseURL);
|
||||||
|
let start = new Date();
|
||||||
|
uni.uploadFile({
|
||||||
|
url: Common.baseURL+'video/upload',
|
||||||
|
// url: 'http://192.168.110.169:5000/video/upload',
|
||||||
|
filePath: this.videoPath,
|
||||||
|
name: 'file',
|
||||||
|
header: {
|
||||||
|
"Method": "POST",
|
||||||
|
"Content-Type": "multipart/form-data"
|
||||||
|
},
|
||||||
|
timeout: 600000,
|
||||||
|
fail: (ex) => {
|
||||||
|
//console.log("上传视频失败" + JSON.stringify(ex));
|
||||||
|
uni.showToast({
|
||||||
|
title: "视频文件上传失败了,请检查网络连接",
|
||||||
|
icon: 'fail'
|
||||||
|
})
|
||||||
|
uni.hideLoading();
|
||||||
|
reject(ex);
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff - s) / 60;
|
||||||
|
console.log("上传完成,耗时:" + m + "分" + s + "秒");
|
||||||
|
uni.hideLoading();
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let p1=this.HoldYouHand();
|
||||||
|
|
||||||
|
Promise.all([p2,p1]).then((arr)=>{
|
||||||
|
if(arr[1]===true){
|
||||||
|
let res=arr[0];
|
||||||
|
res = JSON.parse(res.data);
|
||||||
|
|
||||||
|
if (res.data) {
|
||||||
|
this.hexArray = res.data;
|
||||||
|
uni.showLoading({
|
||||||
|
title: "正在发送"
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.shotVideoClick(res.data, 'rgb565');
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("res")
|
||||||
|
uni.showModal({
|
||||||
|
content: "服务器未返回RGB565数据",
|
||||||
|
title: '错误'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
uni.showModal({
|
||||||
|
content:"与设备握手失败了",
|
||||||
|
title:"错误"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
pause(e) {
|
||||||
|
////console.log('pause--------------------------', e);
|
||||||
|
},
|
||||||
|
shotVideoClick: function(array, type) {
|
||||||
|
//console.log("处理视频完成", array);
|
||||||
|
//console.log("type=" + type)
|
||||||
|
//console.log("array=", array);
|
||||||
|
this.imgs = array;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var sendImagePackets = (imageData) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
this.isSending = true;
|
||||||
|
this.progress = 0;
|
||||||
|
this.currentPacket = 0;
|
||||||
|
|
||||||
|
// 总数据包数
|
||||||
|
const totalPackets = 1536;
|
||||||
|
this.totalPackets = totalPackets;
|
||||||
|
let currentPacket = 1;
|
||||||
|
let promises = [];
|
||||||
|
// 发送单个数据包
|
||||||
|
const sendNextPacket = () => {
|
||||||
|
////console.log("currentPacket="+currentPacket+",imageData.length="+imageData.length);
|
||||||
|
if (currentPacket > totalPackets) {
|
||||||
|
this.isSending = false;
|
||||||
|
resolve();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算当前包的数据
|
||||||
|
let packetSize = 250;
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
packetSize = 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建数据包
|
||||||
|
const startIndex = (currentPacket - 1) * packetSize;
|
||||||
|
const endIndex = Math.min(startIndex + packetSize, imageData.length);
|
||||||
|
if (startIndex > endIndex) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
////console.log("111111");
|
||||||
|
const packetData = imageData.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
// 构建数据包
|
||||||
|
////console.log("packetData.length"+packetData.length);
|
||||||
|
const bufferSize = 506; // 头部5字节 + 数据部分
|
||||||
|
const buffer = new ArrayBuffer(bufferSize);
|
||||||
|
const dataView = new DataView(buffer);
|
||||||
|
|
||||||
|
let sortNo = currentPacket.toString(16).padStart(4, '0');
|
||||||
|
|
||||||
|
// 填充头部
|
||||||
|
dataView.setUint8(0, 0x55); // 帧头
|
||||||
|
dataView.setUint8(1, 0x04); // 帧类型:开机画面
|
||||||
|
dataView.setUint8(2, '0x' + sortNo.substring(0, 2)); // 包序号
|
||||||
|
dataView.setUint8(3, '0x' + sortNo.substring(2, 4)); // 包序号
|
||||||
|
|
||||||
|
|
||||||
|
dataView.setUint8(4, 0x01);
|
||||||
|
dataView.setUint8(5, 0xF4);
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
for (let i = 0; i < packetData.length; i++) {
|
||||||
|
dataView.setUint8(6 + i, '0x' + packetData[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < packetData.length; i++) {
|
||||||
|
dataView.setUint16(6 + i * 2, packetData[i], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let inteval = parseInt(this.inteval ? this.inteval : 0);
|
||||||
|
let promise = this.sendData(buffer);
|
||||||
|
promises.push(promise);
|
||||||
|
let packgeCnt = parseInt(this.packgeCnt || 20);
|
||||||
|
if (currentPacket % packgeCnt == 0 || (currentPacket >= totalPackets &&
|
||||||
|
promises.length > 0)) {
|
||||||
|
Promise.all(promises).then(() => {
|
||||||
|
if (currentPacket >= totalPackets) {
|
||||||
|
this.isSending = false;
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentPacket = currentPacket;
|
||||||
|
this.progress = Math.round((currentPacket / totalPackets) *
|
||||||
|
100);
|
||||||
|
currentPacket++;
|
||||||
|
setTimeout(sendNextPacket, inteval);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
currentPacket++;
|
||||||
|
sendNextPacket();
|
||||||
|
}
|
||||||
|
// .then(() => {
|
||||||
|
// // 更新进度
|
||||||
|
// this.currentPacket = currentPacket;
|
||||||
|
// this.progress = Math.round((currentPacket / totalPackets) *
|
||||||
|
// 100);
|
||||||
|
|
||||||
|
// currentPacket++;
|
||||||
|
|
||||||
|
|
||||||
|
// setTimeout(sendNextPacket, inteval);
|
||||||
|
// }).catch(err => {
|
||||||
|
|
||||||
|
// console.log(err.errMsg+",发送失败了,正在补偿:" + currentPacket);
|
||||||
|
// setTimeout(sendNextPacket, inteval);
|
||||||
|
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
sendNextPacket();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
let start = new Date();
|
||||||
|
console.log("开始发送");
|
||||||
|
sendImagePackets(array).then(() => {
|
||||||
|
|
||||||
|
let end = new Date();
|
||||||
|
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff - s) / 60;
|
||||||
|
console.log("发送完成,耗时:" + m + "分" + s + "秒");
|
||||||
|
uni.showToast({
|
||||||
|
title: "发送完成,耗时:" + m + "分" + s + "秒",
|
||||||
|
icon: 'success',
|
||||||
|
|
||||||
|
})
|
||||||
|
}).catch((ex1) => {
|
||||||
|
//console.log("出现了异常", ex1)
|
||||||
|
}).finally(() => {
|
||||||
|
uni.hideLoading();
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
HoldYouHand() {
|
||||||
|
|
||||||
|
var promise=new Promise((resolve,reject)=>{
|
||||||
|
try{
|
||||||
|
let start=new Date();
|
||||||
|
var str = "video transmit start"; //握手的协议字符串
|
||||||
|
console.log("开始握手:"+str)
|
||||||
|
|
||||||
|
// 1. 创建 ArrayBuffer 和 DataView
|
||||||
|
const buffer = new ArrayBuffer(str.length);
|
||||||
|
const dataView = new DataView(buffer);
|
||||||
|
|
||||||
|
// 2. 将字符串转换为 ASCII 码并写入 DataView
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
dataView.setUint8(i, str.charCodeAt(i));
|
||||||
|
}
|
||||||
|
//console.log("111111");
|
||||||
|
this.sendData(buffer).then(() => {
|
||||||
|
// 开始发送第一个包
|
||||||
|
setTimeout(()=>{
|
||||||
|
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff - s) / 60;
|
||||||
|
|
||||||
|
console.log("握手成功并完成2200ms等待,耗时"+m+"分"+s+"秒");
|
||||||
|
|
||||||
|
resolve(true);
|
||||||
|
}, 2200);
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
//console.log("握手没有成功");
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
}catch(ex){
|
||||||
|
reject(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
|
||||||
|
},
|
||||||
|
sendData(buffer) {
|
||||||
|
let sendBuffer = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
var promise = new Promise((succ, err) => {
|
||||||
|
uni.writeBLECharacteristicValue({
|
||||||
|
deviceId: this.connectedDeviceId,
|
||||||
|
serviceId: this.serviceId,
|
||||||
|
characteristicId: this.writeCharacteristicId,
|
||||||
|
value: buffer,
|
||||||
|
writeType: plus.os.name == 'iOS' ? 'write' : 'writeNoResponse',
|
||||||
|
success: () => {
|
||||||
|
// console.log("发送数据成功");
|
||||||
|
succ();
|
||||||
|
},
|
||||||
|
fail: (ex) => {
|
||||||
|
if (ex.code == '10007') {
|
||||||
|
// console.log("失败重试");
|
||||||
|
setTimeout(() => {
|
||||||
|
sendBuffer().then(succ).catch(err);
|
||||||
|
}, this.inteval || 0)
|
||||||
|
// succ()
|
||||||
|
|
||||||
|
} else
|
||||||
|
|
||||||
|
{
|
||||||
|
// console.log("发送数据失败",ex);
|
||||||
|
err(ex);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
//console.log("123456");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (plus.os.name == 'iOS') {
|
||||||
|
|
||||||
|
function timeout(ms) {
|
||||||
|
return new Promise((_, err) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
err({
|
||||||
|
code: -1,
|
||||||
|
errMsg: '超时了'
|
||||||
|
})
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.race([promise, timeout(this.inteval ? this.inteval : 0)]).then(() => {
|
||||||
|
// console.log("成功了");
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch((ex) => {
|
||||||
|
|
||||||
|
if (ex.code == -1) {
|
||||||
|
// console.log("超时了")
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(ex);
|
||||||
|
// console.log("异常了", ex);
|
||||||
|
//sendBuffer().then(resolve).catch(reject);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
|
||||||
|
promise.then(() => {
|
||||||
|
//console.log("then........")
|
||||||
|
resolve();
|
||||||
|
}).catch(() => {
|
||||||
|
//console.log("catch.........")
|
||||||
|
reject()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendBuffer();
|
||||||
|
},
|
||||||
|
CutImg: function() {
|
||||||
|
if (this.imgs.length == 30) {
|
||||||
|
this.shotVideoClick(this.imgs, 'img');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//console.log("开始处理视频")
|
||||||
|
uni.showLoading({
|
||||||
|
title: '开始处理'
|
||||||
|
});
|
||||||
|
this.$refs.compARef.shotVideoClick(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sending-progress {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
height: 12rpx;
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #409eff;
|
||||||
|
transition: width 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 2rpx solid #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 100rpx;
|
||||||
|
line-height: 100rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100vw;
|
||||||
|
height: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
537
pages/BlueTooth/ModeSetting/VideoSend_670.vue
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<canvas canvas-id="flashCanvas"
|
||||||
|
style="width: 160px; height: 80px; z-index: 9999;position: fixed; top:-9999px;left:-9999px;"></canvas>
|
||||||
|
|
||||||
|
<view>
|
||||||
|
<view>
|
||||||
|
选择的视频:{{videoPath}}</view>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
重发包序号:{{reSendNumber}}
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<text>发送间隔</text>
|
||||||
|
<input type="text" v-model="inteval" />
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<button @click="checkVideo">选择视频</button>
|
||||||
|
|
||||||
|
<button @click="uploadVideo">发送</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
<view class="sending-progress" v-if="isSending">
|
||||||
|
<view class="progress-bar">
|
||||||
|
<view class="progress-fill" :style="{ width: progress + '%' }"></view>
|
||||||
|
</view>
|
||||||
|
<text>正在发送: {{ progress }}% ({{ currentPacket }}/{{ totalPackets }})</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Common from '../../../utils/Common';
|
||||||
|
var mqttClient=null;
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
videoPath: '',
|
||||||
|
inteval: 0,
|
||||||
|
progress: 0,
|
||||||
|
currentPacket: 0,
|
||||||
|
totalPackets: 100,
|
||||||
|
|
||||||
|
connectedDeviceId: '',
|
||||||
|
serviceId: '0xFFE1',
|
||||||
|
writeCharacteristicId: '0xFFE1',
|
||||||
|
notifyCharacteristicId: '0xFFE2',
|
||||||
|
isSending: "",
|
||||||
|
textProgress: "",
|
||||||
|
netMode:"ble",
|
||||||
|
IMEI:"",
|
||||||
|
|
||||||
|
|
||||||
|
imgs: [],
|
||||||
|
videoWidth: 320,
|
||||||
|
videoHeight: 160,
|
||||||
|
videoDuration: 2,
|
||||||
|
|
||||||
|
hexArray: [],
|
||||||
|
reSendNumber:""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
const eventChannel = this.getOpenerEventChannel();
|
||||||
|
|
||||||
|
eventChannel.on('receiveDevice', (data) => {
|
||||||
|
this.connectedDeviceId = data.connectedDeviceId;
|
||||||
|
this.serviceId = data.serviceId;
|
||||||
|
this.writeCharacteristicId = data.writeCharacteristicId;
|
||||||
|
this.notifyCharacteristicId = data.notifyCharacteristicId;
|
||||||
|
this.netMode=data.netMode;
|
||||||
|
mqttClient=data.mqttClient;
|
||||||
|
this.IMEI=data.IMEI;
|
||||||
|
});
|
||||||
|
|
||||||
|
eventChannel.on('ReSendVideo',(data)=>{
|
||||||
|
//重新发送某一包
|
||||||
|
this.reSendNumber=data.videoNo;
|
||||||
|
setTimeout(()=>{
|
||||||
|
this.shotVideoClick(this.hexArray,'rgb565',data.videoNo);
|
||||||
|
},0);
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkVideo: function() {
|
||||||
|
uni.chooseVideo({
|
||||||
|
sourceType: ['album', 'camera'],
|
||||||
|
compressed: false,
|
||||||
|
maxDuration: 2,
|
||||||
|
camera: 'back',
|
||||||
|
success: (res) => {
|
||||||
|
this.videoPath = res.tempFilePath;
|
||||||
|
|
||||||
|
this.imgs = [];
|
||||||
|
this.hexArray = [];
|
||||||
|
|
||||||
|
this.videoWidth = res.width;
|
||||||
|
this.videoHeight = res.height;
|
||||||
|
this.videoDuration = res.duration;
|
||||||
|
console.log("视频宽:" + res.width + ",视频高:" + res.height + ",视频时长:" + res.duration);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadVideo: function() {
|
||||||
|
|
||||||
|
if (this.hexArray.length > 0) {
|
||||||
|
console.log("开始处理,无需上传");
|
||||||
|
this.shotVideoClick(this.hexArray, 'rgb565');
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
if(!this.videoPath){
|
||||||
|
uni.showToast({
|
||||||
|
title: "请选择视频",
|
||||||
|
icon: 'fail'
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("正在上传视频");
|
||||||
|
uni.showLoading({
|
||||||
|
title: "上传中"
|
||||||
|
});
|
||||||
|
|
||||||
|
let p2=new Promise((resolve,reject)=>{
|
||||||
|
let start = new Date();
|
||||||
|
console.log("Common.baseURL="+Common.baseURL);
|
||||||
|
uni.uploadFile({
|
||||||
|
url:Common.baseURL+'video/upload',
|
||||||
|
filePath: this.videoPath,
|
||||||
|
name: 'file',
|
||||||
|
header: {
|
||||||
|
"Method": "POST",
|
||||||
|
"Content-Type": "multipart/form-data"
|
||||||
|
},
|
||||||
|
timeout: 600000,
|
||||||
|
fail: (ex) => {
|
||||||
|
//console.log("上传视频失败" + JSON.stringify(ex));
|
||||||
|
uni.showToast({
|
||||||
|
title: "视频文件上传失败了,请检查网络连接",
|
||||||
|
icon: 'fail'
|
||||||
|
})
|
||||||
|
uni.hideLoading();
|
||||||
|
reject(ex);
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff - s) / 60;
|
||||||
|
console.log("上传完成,耗时:" + m + "分" + s + "秒");
|
||||||
|
uni.hideLoading();
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let p1=this.HoldYouHand();
|
||||||
|
|
||||||
|
Promise.all([p2,p1]).then((arr)=>{
|
||||||
|
|
||||||
|
if(arr[1]===true){
|
||||||
|
let res=arr[0];
|
||||||
|
res = JSON.parse(res.data);
|
||||||
|
|
||||||
|
if (res.data) {
|
||||||
|
this.hexArray = res.data;
|
||||||
|
uni.showLoading({
|
||||||
|
title: "正在发送"
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.shotVideoClick(res.data, 'rgb565');
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("res")
|
||||||
|
uni.showModal({
|
||||||
|
content: "服务器未返回RGB565数据",
|
||||||
|
title: '错误'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
uni.showModal({
|
||||||
|
content:"与设备握手失败了",
|
||||||
|
title:"错误"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
shotVideoClick: function(array, type,ReSendNo) {
|
||||||
|
//console.log("处理视频完成", array);
|
||||||
|
//console.log("type=" + type)
|
||||||
|
//console.log("array=", array);
|
||||||
|
this.imgs = array;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var sendImagePackets = (imageData) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
this.isSending = true;
|
||||||
|
this.progress = 0;
|
||||||
|
this.currentPacket = 0;
|
||||||
|
|
||||||
|
// 总数据包数
|
||||||
|
var totalPackets = 1536;
|
||||||
|
this.totalPackets = totalPackets;
|
||||||
|
let currentPacket = 1;
|
||||||
|
if(ReSendNo){
|
||||||
|
this.progress = ReSendNo-1;
|
||||||
|
this.currentPacket = ReSendNo-1;
|
||||||
|
currentPacket=ReSendNo;
|
||||||
|
totalPackets=ReSendNo;
|
||||||
|
this.totalPackets=ReSendNo;
|
||||||
|
}
|
||||||
|
// 发送单个数据包
|
||||||
|
const sendNextPacket = () => {
|
||||||
|
////console.log("currentPacket="+currentPacket+",imageData.length="+imageData.length);
|
||||||
|
if (currentPacket > totalPackets) {
|
||||||
|
this.isSending = false;
|
||||||
|
if(!ReSendNo){
|
||||||
|
this.bleSendComplete();
|
||||||
|
}else{
|
||||||
|
// this.reSendNumber="";
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算当前包的数据
|
||||||
|
let packetSize = 250;
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
packetSize = 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建数据包
|
||||||
|
const startIndex = (currentPacket - 1) * packetSize;
|
||||||
|
const endIndex = Math.min(startIndex + packetSize, imageData.length);
|
||||||
|
if (startIndex > endIndex) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
////console.log("111111");
|
||||||
|
const packetData = imageData.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
// 构建数据包
|
||||||
|
////console.log("packetData.length"+packetData.length);
|
||||||
|
const bufferSize = 506; // 头部5字节 + 数据部分
|
||||||
|
const buffer = new ArrayBuffer(bufferSize);
|
||||||
|
const dataView = new DataView(buffer);
|
||||||
|
|
||||||
|
let sortNo = currentPacket.toString(16).padStart(4, '0');
|
||||||
|
|
||||||
|
// 填充头部
|
||||||
|
dataView.setUint8(0, 0x55); // 帧头
|
||||||
|
dataView.setUint8(1, 0x04); // 帧类型:开机画面
|
||||||
|
dataView.setUint8(2, '0x' + sortNo.substring(0, 2)); // 包序号
|
||||||
|
dataView.setUint8(3, '0x' + sortNo.substring(2, 4)); // 包序号
|
||||||
|
|
||||||
|
|
||||||
|
dataView.setUint8(4, 0x01);
|
||||||
|
dataView.setUint8(5, 0xF4);
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
for (let i = 0; i < packetData.length; i++) {
|
||||||
|
dataView.setUint8(6 + i, '0x' + packetData[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < packetData.length; i++) {
|
||||||
|
dataView.setUint16(6 + i * 2, packetData[i], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let inteval = parseInt(this.inteval ? this.inteval : 0);
|
||||||
|
this.sendData(buffer).then(() => {
|
||||||
|
// 更新进度
|
||||||
|
this.currentPacket = currentPacket;
|
||||||
|
this.progress = Math.round((currentPacket / totalPackets) *
|
||||||
|
100);
|
||||||
|
console.log(`发送数据包完成 ${currentPacket}/${totalPackets}`);
|
||||||
|
|
||||||
|
// 发送下一个包(添加延迟避免蓝牙缓冲区溢出)
|
||||||
|
currentPacket++;
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(sendNextPacket, inteval);
|
||||||
|
}).catch(err => {
|
||||||
|
|
||||||
|
console.log(err.errMsg + ",发送失败了,正在补偿:" + currentPacket);
|
||||||
|
setTimeout(sendNextPacket, inteval);
|
||||||
|
// uni.showToast({
|
||||||
|
// title:"发送失败"+JSON.stringify(err)
|
||||||
|
// })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sendNextPacket();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (type == 'rgb565') {
|
||||||
|
let start = new Date();
|
||||||
|
console.log("开始发送");
|
||||||
|
sendImagePackets(array).then(() => {
|
||||||
|
console.log("发送完成");
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff-s) / 60;
|
||||||
|
console.log("发送完成,耗时:" + m + "分" + s + "秒");
|
||||||
|
uni.showModal({
|
||||||
|
content: "发送完成,耗时:" + m + "分" + s + "秒",
|
||||||
|
title: 'success'
|
||||||
|
});
|
||||||
|
|
||||||
|
}).catch((ex1) => {
|
||||||
|
console.log("出现了异常", ex1)
|
||||||
|
}).finally(() => {
|
||||||
|
uni.hideLoading();
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
HoldYouHand() {
|
||||||
|
|
||||||
|
var promise=new Promise((resolve,reject)=>{
|
||||||
|
try{
|
||||||
|
let start=new Date();
|
||||||
|
var str = "video transmit start"; //握手的协议字符串
|
||||||
|
console.log("开始握手:"+str)
|
||||||
|
|
||||||
|
// 1. 创建 ArrayBuffer 和 DataView
|
||||||
|
const buffer = new ArrayBuffer(str.length);
|
||||||
|
const dataView = new DataView(buffer);
|
||||||
|
|
||||||
|
// 2. 将字符串转换为 ASCII 码并写入 DataView
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
dataView.setUint8(i, str.charCodeAt(i));
|
||||||
|
}
|
||||||
|
//console.log("111111");
|
||||||
|
this.sendData(buffer).then(() => {
|
||||||
|
// 开始发送第一个包
|
||||||
|
setTimeout(()=>{
|
||||||
|
|
||||||
|
let end = new Date();
|
||||||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||||||
|
let s = diff % 60;
|
||||||
|
let m = (diff - s) / 60;
|
||||||
|
|
||||||
|
console.log("握手成功并完成2200ms等待,耗时"+m+"分"+s+"秒");
|
||||||
|
|
||||||
|
resolve(true);
|
||||||
|
}, 2200);
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
//console.log("握手没有成功");
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
}catch(ex){
|
||||||
|
reject(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
|
||||||
|
},
|
||||||
|
bleSendComplete() {
|
||||||
|
var str = "transmit complete"; //握手的协议字符串
|
||||||
|
let buffer = new ArrayBuffer(str.length);
|
||||||
|
let dataView = new DataView(buffer);
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
dataView.setUint8(i, str.charCodeAt(i));
|
||||||
|
}
|
||||||
|
setTimeout(()=>{
|
||||||
|
this.sendData(buffer).then(() => {
|
||||||
|
console.log("完成指令发送成功");
|
||||||
|
}).catch(err => {
|
||||||
|
console.log("完成指令发送失败");
|
||||||
|
});
|
||||||
|
},1500)
|
||||||
|
|
||||||
|
},
|
||||||
|
sendData(buffer) {
|
||||||
|
if(this.netMode=='ble'){
|
||||||
|
return this.sendBle(buffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.sendMQ(buffer);
|
||||||
|
},
|
||||||
|
sendBle(buffer){
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
|
||||||
|
// //console.log("开始发送数据,buffer");
|
||||||
|
|
||||||
|
|
||||||
|
var promise = new Promise((succ, err) => {
|
||||||
|
uni.writeBLECharacteristicValue({
|
||||||
|
deviceId: this.connectedDeviceId,
|
||||||
|
serviceId: this.serviceId,
|
||||||
|
characteristicId: this.writeCharacteristicId,
|
||||||
|
value: buffer,
|
||||||
|
writeType: plus.os.name == 'iOS' ? 'write' : 'writeNoResponse',
|
||||||
|
success: () => {
|
||||||
|
// //console.log("发送数据成功");
|
||||||
|
succ();
|
||||||
|
},
|
||||||
|
fail: (ex) => {
|
||||||
|
//console.log("发送数据失败", ex);
|
||||||
|
err(ex);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
// //console.log("123456");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (plus.os.name == 'iOS') {
|
||||||
|
|
||||||
|
function timeout(ms) {
|
||||||
|
return new Promise((_, err) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
err({
|
||||||
|
code: -1,
|
||||||
|
errMsg: '超时了'
|
||||||
|
})
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let inteval = parseInt(this.inteval ? this.inteval : 0);
|
||||||
|
|
||||||
|
Promise.race([promise, timeout(inteval)]).then(resolve).catch((ex) => {
|
||||||
|
//console.log("ex=", ex);
|
||||||
|
if (ex.code == -1) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
}).finally(() => {
|
||||||
|
//console.log("完成了")
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
promise.then(resolve).catch(reject);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
sendMQ(message) {
|
||||||
|
|
||||||
|
const topic = `B/${this.IMEI}`;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if(!mqttClient){
|
||||||
|
reject("MQTT未连接");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let flag=mqttClient.publish(topic, message, {
|
||||||
|
qos: 1
|
||||||
|
});
|
||||||
|
if(flag){
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject("MQTT未连接,无法发布消息");
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sending-progress {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
height: 12rpx;
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #409eff;
|
||||||
|
transition: width 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 2rpx solid #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 100rpx;
|
||||||
|
line-height: 100rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100vw;
|
||||||
|
height: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
115
pages/BlueTooth/ModeSetting/index.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="grid">
|
||||||
|
<view class="cell" @click="goToDetail(item.name)" v-for="item,index in options">{{item.url}}</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
options: [{
|
||||||
|
name: '/pages/BlueTooth/ModeSetting/ModeSetting',
|
||||||
|
url: '7307'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '/pages/BlueTooth/ModeSetting/HBY650',
|
||||||
|
url: 'HBY650'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '/pages/BlueTooth/ModeSetting/HBY650_1',
|
||||||
|
url: 'HBY650_V1'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: '/pages/BlueTooth/ModeSetting/HBY6155',
|
||||||
|
url: '6155'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '/pages/BlueTooth/ModeSetting/HBY6155V1',
|
||||||
|
url: '6155_V1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "/pages/BlueTooth/ModeSetting/HBY670V1",
|
||||||
|
url: 'HBY670'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: '/pages/MapTest/MapTest',
|
||||||
|
url: '地图测试'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
url: '更多'
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShow: () => {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
goToDetail: function(url) {
|
||||||
|
console.log("url=" + url)
|
||||||
|
let qd = () => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '敬请期待',
|
||||||
|
duration: 2000,
|
||||||
|
icon: "none"
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
if (url) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: url,
|
||||||
|
success: () => {
|
||||||
|
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
qd();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
qd();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: flex;
|
||||||
|
align-content: space-around;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
padding: 0rpx 20rpx;
|
||||||
|
border: 2rpx solid rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 15rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
|
margin-left: 30rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
273
pages/BlueTooth/ModeSetting/update.vue
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
<template>
|
||||||
|
<view class="update-container">
|
||||||
|
<!-- 进度条 -->
|
||||||
|
<view v-if="showProgress" class="progress-container">
|
||||||
|
<view class="progress-title">正在更新 {{ progress }}%</view>
|
||||||
|
<view class="progress-bar">
|
||||||
|
<view class="progress" :style="{ width: progress + '%' }"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 更新提示弹窗 -->
|
||||||
|
<view v-if="showUpdateDialog" class="dialog-mask">
|
||||||
|
<view class="dialog">
|
||||||
|
<view class="dialog-title">发现新版本 v{{ newVersion }}</view>
|
||||||
|
<view class="dialog-content">{{ updateInfo.desc || '有新的功能和优化,建议立即更新' }}</view>
|
||||||
|
<view class="dialog-buttons">
|
||||||
|
<button v-if="!updateInfo.force" class="cancel-btn" @click="showUpdateDialog = false">稍后更新</button>
|
||||||
|
<button class="confirm-btn" @click="startUpdate">立即更新</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 当前版本
|
||||||
|
currentVersion: '',
|
||||||
|
// 最新版本
|
||||||
|
newVersion: '',
|
||||||
|
// 更新信息
|
||||||
|
updateInfo: {},
|
||||||
|
// 是否显示更新弹窗
|
||||||
|
showUpdateDialog: false,
|
||||||
|
// 是否显示进度条
|
||||||
|
showProgress: false,
|
||||||
|
// 更新进度
|
||||||
|
progress: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad() {
|
||||||
|
// 初始化时检查版本
|
||||||
|
this.checkVersion();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 检查当前版本
|
||||||
|
*/
|
||||||
|
async checkVersion() {
|
||||||
|
try {
|
||||||
|
// 获取当前应用版本
|
||||||
|
const versionInfo = plus.runtime.version;
|
||||||
|
this.currentVersion = versionInfo;
|
||||||
|
console.log('当前版本:', this.currentVersion);
|
||||||
|
|
||||||
|
// 调用后端接口检查最新版本
|
||||||
|
// 这里替换为你的后端接口地址
|
||||||
|
const res = await this.$http.get('/api/checkVersion', {
|
||||||
|
platform: uni.getSystemInfoSync().platform,
|
||||||
|
version: this.currentVersion
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 0 && res.data.hasUpdate) {
|
||||||
|
this.newVersion = res.data.version;
|
||||||
|
this.updateInfo = res.data;
|
||||||
|
// 显示更新提示
|
||||||
|
this.showUpdateDialog = true;
|
||||||
|
} else {
|
||||||
|
console.log('当前已是最新版本');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('版本检查失败:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始更新
|
||||||
|
*/
|
||||||
|
startUpdate() {
|
||||||
|
if (!this.updateInfo.downloadUrl) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '更新地址不存在',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showUpdateDialog = false;
|
||||||
|
this.showProgress = true;
|
||||||
|
this.downloadWgt(this.updateInfo.downloadUrl);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载wgt包
|
||||||
|
*/
|
||||||
|
downloadWgt(url) {
|
||||||
|
const downloadTask = uni.downloadFile({
|
||||||
|
url: url,
|
||||||
|
success: (downloadResult) => {
|
||||||
|
if (downloadResult.statusCode === 200) {
|
||||||
|
// 下载成功,安装wgt包
|
||||||
|
this.installWgt(downloadResult.tempFilePath);
|
||||||
|
} else {
|
||||||
|
this.showProgress = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: '下载失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
this.showProgress = false;
|
||||||
|
console.error('下载失败:', err);
|
||||||
|
uni.showToast({
|
||||||
|
title: '下载失败,请稍后重试',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听下载进度
|
||||||
|
downloadTask.onProgressUpdate((res) => {
|
||||||
|
this.progress = res.progress;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安装wgt包
|
||||||
|
*/
|
||||||
|
installWgt(path) {
|
||||||
|
plus.runtime.install(
|
||||||
|
path,
|
||||||
|
{
|
||||||
|
force: false // 是否强制安装
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
console.log('安装成功');
|
||||||
|
this.showProgress = false;
|
||||||
|
|
||||||
|
// 安装成功后提示重启
|
||||||
|
uni.showModal({
|
||||||
|
title: '更新完成',
|
||||||
|
content: '应用已更新,是否立即重启?',
|
||||||
|
showCancel: !this.updateInfo.force,
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
// 重启应用
|
||||||
|
plus.runtime.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
console.error('安装失败:', err);
|
||||||
|
this.showProgress = false;
|
||||||
|
uni.showToast({
|
||||||
|
title: '更新失败: ' + err.message,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 3000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.update-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 进度条样式 */
|
||||||
|
.progress-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 10rpx 20rpx;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
height: 8rpx;
|
||||||
|
background-color: #eee;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #007aff;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 弹窗样式 */
|
||||||
|
.dialog-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
width: 600rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
padding: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #666;
|
||||||
|
padding: 40rpx 30rpx;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-buttons {
|
||||||
|
display: flex;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn, .confirm-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 100rpx;
|
||||||
|
line-height: 100rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
color: #666;
|
||||||
|
border-right: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-btn {
|
||||||
|
color: #007aff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,22 +1,296 @@
|
|||||||
<template>
|
<template>
|
||||||
<view>
|
<view class="content">
|
||||||
|
<view class="deviceDetail">
|
||||||
|
<view class="imgContent">
|
||||||
|
<image src="/static/images/BLEAdd/addBleDevice.png" class="titleIco" mode="aspectFit">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
<view class="deviceName">
|
||||||
|
蓝牙名:{{device.name}}
|
||||||
|
</view>
|
||||||
|
<view class="deviceName">
|
||||||
|
设备名:{{device.deviceName}}
|
||||||
|
</view>
|
||||||
|
<view class="deviceId">
|
||||||
|
ID:{{device.deviceId}}
|
||||||
|
</view>
|
||||||
|
<view class="bound" v-bind:class="boundStatu">
|
||||||
|
{{Statu.boundRemark}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="btnLink" @click="Link()">
|
||||||
|
连接
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<global-loading ref="loading" />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import request from '@/utils/request.js';
|
||||||
|
import bleTool from '@/utils/BleHelper.js';
|
||||||
|
import {
|
||||||
|
showLoading,
|
||||||
|
hideLoading,
|
||||||
|
updateLoading
|
||||||
|
} from '@/utils/loading.js';
|
||||||
|
|
||||||
|
const pagePath="pages/common/addBLE/LinkBle";
|
||||||
|
|
||||||
|
var these = null;
|
||||||
|
var eventChannel = null;
|
||||||
|
var ble = null;
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
Statu: {
|
||||||
|
bound: null
|
||||||
|
},
|
||||||
|
device: {
|
||||||
|
"deviceId": "",
|
||||||
|
"name": "",
|
||||||
|
"deviceName": "",
|
||||||
|
"RSSI": -37,
|
||||||
|
"localName": "",
|
||||||
|
"advertisServiceUUIDs": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"linkStatu": false,
|
||||||
|
"macAddress": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
computed: {
|
||||||
|
boundStatu: function() {
|
||||||
|
if (this.Statu.bound === null) {
|
||||||
|
return "displayNone"
|
||||||
|
}
|
||||||
|
if (this.Statu.bound) {
|
||||||
|
return "green"
|
||||||
|
} else {
|
||||||
|
return "red";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onBackPress() {
|
||||||
|
console.log("返回时断开蓝牙连接,取消订阅");
|
||||||
|
ble.disconnectDevice(these.device.deviceId);
|
||||||
|
ble.removeReceiveCallback(pagePath);
|
||||||
|
},
|
||||||
|
onUnload() {
|
||||||
|
ble.removeReceiveCallback(pagePath);
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
these = this;
|
||||||
|
ble = bleTool.getBleTool();
|
||||||
|
ble.addReceiveCallback((receive,f,path) => {
|
||||||
|
console.log("收到设备消息,", receive);
|
||||||
|
if (these.device.deviceId == receive.deviceId) {
|
||||||
|
console.log("11111");
|
||||||
|
|
||||||
|
if (receive.bytes[0] == 0xFC || receive.str.indexOf('mac address:') == 0) {
|
||||||
|
if (f && f.macAddress) {
|
||||||
|
these.device.macAddress = f.macAddress;
|
||||||
|
console.log("222222");
|
||||||
|
these.initDevice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},pagePath);
|
||||||
|
eventChannel = this.getOpenerEventChannel();
|
||||||
|
eventChannel.on('LinkItem', function(data) {
|
||||||
|
let f = ble.data.LinkedList.find((v) => {
|
||||||
|
return v.deviceId = data.deviceId;
|
||||||
|
});
|
||||||
|
if (f) {
|
||||||
|
these.device = Object.assign({}, these.device, f);
|
||||||
|
console.log("获取到设备", f);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log("未获取到设备");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
initDevice: function() {
|
||||||
|
showLoading(these, {
|
||||||
|
text: '正在获取设备信息'
|
||||||
|
});
|
||||||
|
request({
|
||||||
|
url: '/app/device/getDeviceInfoByDeviceMac',
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
deviceMac: these.device.macAddress
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
console.log("获取设备信息", res);
|
||||||
|
if (res && res.code == 200) {
|
||||||
|
let data = res.data;
|
||||||
|
if (data) {
|
||||||
|
let keys = Object.keys(data);
|
||||||
|
ble.data.LinkedList.find((v) => {
|
||||||
|
if(v.deviceId = these.device.deviceId){
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
let key = keys[i];
|
||||||
|
v[key] = data[key];
|
||||||
|
console.log("key="+key);
|
||||||
|
console.log("value="+data[key]);
|
||||||
|
|
||||||
|
|
||||||
|
these.$set(these.device, key, data[key]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ble.setBleData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("device=",these.device);
|
||||||
|
console.log("LinkedList=",ble.data.LinkedList);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((ex) => {
|
||||||
|
console.log("获取设备出现异常:", ex);
|
||||||
|
}).finally(() => {
|
||||||
|
hideLoading(these);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Link() {
|
||||||
|
// 调用绑定设备接口
|
||||||
|
|
||||||
|
let f = ble.data.LinkedList.find((v) => {
|
||||||
|
return v.deviceId = these.device.deviceId;
|
||||||
|
});
|
||||||
|
if (!f) {
|
||||||
|
these.Statu.bound = false;
|
||||||
|
these.Statu.boundRemark = "蓝牙连接不成功";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!f.macAddress) {
|
||||||
|
these.Statu.bound = false;
|
||||||
|
these.Statu.boundRemark = "设备上报Mac地址异常";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
these.Statu.bound = null;
|
||||||
|
these.Statu.boundRemark = "";
|
||||||
|
showLoading(these, {
|
||||||
|
|
||||||
|
text: "连接中..."
|
||||||
|
})
|
||||||
|
let promise = request({
|
||||||
|
url: '/app/device/bind',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
deviceImei: '',
|
||||||
|
deviceMac: these.device.macAddress,
|
||||||
|
communicationMode: '1', //0是4g,1是蓝牙
|
||||||
|
}
|
||||||
|
});
|
||||||
|
promise.then((res) => {
|
||||||
|
console.log("1111" + JSON.stringify(res));
|
||||||
|
if (res.code == 200) {
|
||||||
|
these.Statu.bound = true;
|
||||||
|
these.Statu.boundRemark = "设备绑定成功!";
|
||||||
|
|
||||||
|
|
||||||
|
uni.$emit("refreshDeviceList");
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.switchTab({
|
||||||
|
url: "/pages/common/index/index"
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
these.Statu.bound = false;
|
||||||
|
these.Statu.boundRemark = res.msg;
|
||||||
|
}
|
||||||
|
}).catch((ex) => {
|
||||||
|
these.Statu.bound = false;
|
||||||
|
these.Statu.boundRemark = '出现了未知的异常,操作失败';
|
||||||
|
}).finally(() => {
|
||||||
|
hideLoading(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.content {
|
||||||
|
background-color: #1d1d1d;
|
||||||
|
color: #ffffffde;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
height: auto;
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
.deviceDetail {
|
||||||
|
margin: 200rpx auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imgContent,
|
||||||
|
.titleIco {
|
||||||
|
width: 120rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceId {
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
font-size: 32rpx;
|
||||||
|
|
||||||
|
line-height: 44rpx;
|
||||||
|
letter-spacing: 0.14rpx;
|
||||||
|
margin-top: 5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btnLink {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 30rpx;
|
||||||
|
left: 30rpx;
|
||||||
|
right: 30rpx;
|
||||||
|
width: calc(100% - 60rpx);
|
||||||
|
border-radius: 91px;
|
||||||
|
height: 90rpx;
|
||||||
|
background: rgba(187, 230, 0, 1);
|
||||||
|
color: rgba(35, 35, 35, 1);
|
||||||
|
|
||||||
|
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 90rpx;
|
||||||
|
letter-spacing: 12rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bound,
|
||||||
|
.deviceName {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 44rpx;
|
||||||
|
letter-spacing: 0.14rpx;
|
||||||
|
margin-top: 5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayNone {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
color: rgba(187, 230, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
color: rgba(245, 80, 80, 1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -81,13 +81,22 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</BottomSlideMenuPlus>
|
</BottomSlideMenuPlus>
|
||||||
|
|
||||||
|
<global-loading ref="loading" />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ble from '../../../api/6155/BlueHelper.js';
|
import bleTool from '@/utils/BleHelper.js';
|
||||||
import request from '../../../utils/request.js';
|
import request from '@/utils/request.js';
|
||||||
|
import {
|
||||||
|
showLoading,
|
||||||
|
hideLoading,
|
||||||
|
updateLoading
|
||||||
|
} from '@/utils/loading.js'
|
||||||
|
const pagePath="pages/common/addBLE/addEquip";
|
||||||
|
var ble = null;
|
||||||
|
var these = null;
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -127,72 +136,71 @@
|
|||||||
},
|
},
|
||||||
onHide: function() {
|
onHide: function() {
|
||||||
ble.StopSearch();
|
ble.StopSearch();
|
||||||
|
ble.removeReceiveCallback(pagePath);
|
||||||
},
|
},
|
||||||
onBackPress: (e) => {
|
onBackPress: (e) => {
|
||||||
ble.StopSearch();
|
ble.StopSearch();
|
||||||
ble.disconnectDevice();
|
ble.removeDeviceFound(pagePath);
|
||||||
|
ble.removeReceiveCallback(pagePath);
|
||||||
},
|
},
|
||||||
|
onUnload(){
|
||||||
|
ble.StopSearch();
|
||||||
|
ble.removeDeviceFound(pagePath);
|
||||||
|
ble.removeReceiveCallback(pagePath);
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
these = this;
|
||||||
|
ble = bleTool.getBleTool();
|
||||||
|
ble.addDeviceFound((arr) => {
|
||||||
|
|
||||||
|
arr = arr.devices;
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
|
||||||
onShow: function() {
|
arr[i].linkStatu = false;
|
||||||
// return;
|
if(!arr[i].name){
|
||||||
var these = this;
|
continue;
|
||||||
uni.getStorage({
|
}
|
||||||
key: "linkedDevices",
|
let f = these.EquipMents.find(function(v) {
|
||||||
success: (res) => {
|
return v.deviceId == arr[i].deviceId;
|
||||||
this.PairEquip = JSON.parse(res.data);
|
});
|
||||||
},
|
|
||||||
fail: (ex) => {
|
|
||||||
this.PairEquip = [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (process.env.UNI_PLATFORM == 'mp-weixin' ||
|
|
||||||
process.env.UNI_PLATFORM == 'mp-alipay' ||
|
|
||||||
process.env.UNI_PLATFORM == 'app-plus' ||
|
|
||||||
process.env.UNI_PLATFORM == 'app'
|
|
||||||
|
|
||||||
) {
|
|
||||||
//打开蓝牙开始搜索设备
|
|
||||||
ble.OpenBlue(true, () => {
|
|
||||||
ble.StartSearch(function(arr) {
|
|
||||||
|
|
||||||
arr = arr.devices;
|
|
||||||
for (var i = 0; i < arr.length; i++) {
|
|
||||||
|
|
||||||
arr[i].linkStatu = false;
|
|
||||||
let f = these.EquipMents.find(function(v) {
|
|
||||||
return v.deviceId == arr[i].deviceId;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!f) {
|
|
||||||
these.EquipMents.push(arr[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("设备列表:" + JSON.stringify(these.EquipMents));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
these.showOpenSetting();
|
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
|
||||||
|
these.EquipMents.push(arr[i]);
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
},pagePath);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
} else {
|
onShow: function() {
|
||||||
console.log('当前环境:' + process.env.UNI_PLATFORM + '不支持蓝牙');
|
|
||||||
}
|
|
||||||
|
this.EquipMents=[];
|
||||||
|
this.PairEquip=[];
|
||||||
|
ble.StartSearch().catch((ex) => {
|
||||||
|
if (ex.code == 10001) {
|
||||||
|
these.showOpenSetting();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ble.addReceiveCallback((receivData) => {
|
||||||
|
console.log("收到数据了:", receivData);//数据格式:{bytes:[109,97],str:"",hexs:"FA 01"}
|
||||||
|
console.log("LinkedList=",ble.data.LinkedList);
|
||||||
|
let data=uni.getStorageSync(ble.StorageKey);
|
||||||
|
console.log("data=",data);
|
||||||
|
},pagePath);
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isItemLink: function(item, index) {
|
isItemLink: function(item, index) {
|
||||||
let src = '/static/images/BLEAdd/noLink.png';
|
let src = '/static/images/BLEAdd/noLink.png';
|
||||||
if (this.PairEquip && this.PairEquip instanceof Array) {
|
|
||||||
|
if (this.PairEquip && this.PairEquip.length) {
|
||||||
if (this.PairEquip.length > 0) {
|
if (this.PairEquip.length > 0) {
|
||||||
let f = this.PairEquip.find(function(v) {
|
let f = this.PairEquip.find(function(v) {
|
||||||
return v.deviceId == item.deviceId;
|
return v.deviceId == item.deviceId;
|
||||||
@ -206,114 +214,56 @@
|
|||||||
}
|
}
|
||||||
return src;
|
return src;
|
||||||
},
|
},
|
||||||
alert: function(title, content, callback) {
|
|
||||||
if (!title) {
|
|
||||||
title = '提示'
|
|
||||||
}
|
|
||||||
if (!content) {
|
|
||||||
content = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
uni.showModal({
|
|
||||||
title: title,
|
|
||||||
content: content,
|
|
||||||
success: function(res) {
|
|
||||||
if (res.confirm) {
|
|
||||||
console.log('用户点击确定');
|
|
||||||
} else if (res.cancel) {
|
|
||||||
console.log('用户点击取消');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
callback(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
showOpenSetting: function() {
|
showOpenSetting: function() {
|
||||||
this.Status.BottomMenu.show = true;
|
this.Status.BottomMenu.show = true;
|
||||||
},
|
},
|
||||||
gotoSetting: function() {
|
gotoSetting: function() {
|
||||||
this.Status.BottomMenu.show = false;
|
this.Status.BottomMenu.show = false;
|
||||||
ble.showBluetoothGuide(false);
|
ble.showBlueSetting(false);
|
||||||
},
|
},
|
||||||
Link: function(item, index) {
|
Link: function(item, index) {
|
||||||
var these = this;
|
|
||||||
if (process.env.UNI_PLATFORM == 'mp-weixin' ||
|
showLoading(this,{
|
||||||
process.env.UNI_PLATFORM == 'mp-alipay' ||
|
text: "正在连接"
|
||||||
process.env.UNI_PLATFORM == 'app-plus' ||
|
});
|
||||||
process.env.UNI_PLATFORM == 'app'
|
setTimeout(() => {
|
||||||
) {
|
let serviceid=null;
|
||||||
|
if(item.advertisServiceUUIDs.length>0){
|
||||||
uni.showLoading({
|
serviceid=item.advertisServiceUUIDs[0];
|
||||||
title: "正在连接",
|
}
|
||||||
mask: true
|
ble.LinkBlue(item.deviceId,serviceid).then((res) => {
|
||||||
});
|
let c = these.PairEquip.find(function(v) {
|
||||||
setTimeout(() => {
|
return v.deviceId == item.deviceId;
|
||||||
|
|
||||||
|
|
||||||
ble.LinkBlue(item.deviceId, function() {
|
|
||||||
let c = these.PairEquip.find(function(v) {
|
|
||||||
return v.deviceId == item.deviceId;
|
|
||||||
});
|
|
||||||
if (!c) {
|
|
||||||
these.PairEquip.push(item);
|
|
||||||
uni.setStorage({
|
|
||||||
key: 'linkedDevices',
|
|
||||||
data: JSON.stringify(these.PairEquip),
|
|
||||||
success: () => {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 调用绑定设备接口
|
|
||||||
let promise = request({
|
|
||||||
url: '/app/device/bind',
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
deviceImei: '',
|
|
||||||
deviceMac: item.deviceId,
|
|
||||||
communicationMode: '1', //0是4g,1是蓝牙
|
|
||||||
}
|
|
||||||
});
|
|
||||||
promise.then((res) => {
|
|
||||||
console.log("1111" + JSON.stringify(res));
|
|
||||||
if (res.code == 0) {
|
|
||||||
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
|
||||||
title: res.data,
|
|
||||||
icon: 'success'
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
uni.showToast({
|
|
||||||
title: res.msg,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch((ex) => {
|
|
||||||
|
|
||||||
uni.showToast({
|
|
||||||
title: '出现了未知的异常,操作失败',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}, (ex) => {
|
|
||||||
uni.hideLoading();
|
|
||||||
});
|
});
|
||||||
}, 0);
|
if (!c) {
|
||||||
|
|
||||||
|
these.PairEquip.push(item);
|
||||||
|
}
|
||||||
|
ble.removeReceiveCallback(pagePath);
|
||||||
|
uni.navigateTo({
|
||||||
|
url:"/pages/common/addBLE/LinkBle",
|
||||||
|
events:{
|
||||||
|
|
||||||
|
},
|
||||||
|
success(res) {
|
||||||
|
|
||||||
|
res.eventChannel.emit('LinkItem', item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}).catch((ex) => {
|
||||||
|
console.log("ex=",ex)
|
||||||
|
uni.showModal({
|
||||||
|
content:"连接失败:"+ex.msg
|
||||||
|
});
|
||||||
|
}).finally(()=>{
|
||||||
|
hideLoading(this);
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
these.alert("提示", "当前平台不支持蓝牙");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,7 +401,7 @@
|
|||||||
|
|
||||||
.mainContent .lblTitle {
|
.mainContent .lblTitle {
|
||||||
color: #ffffffde;
|
color: #ffffffde;
|
||||||
font-family: PingFang SC;
|
font-family: "PingFang SC";
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@ -516,7 +466,7 @@
|
|||||||
|
|
||||||
.list .item .name {
|
.list .item .name {
|
||||||
color: #ffffffde;
|
color: #ffffffde;
|
||||||
font-family: PingFang SC;
|
font-family: "PingFang SC";
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 50rpx;
|
line-height: 50rpx;
|
||||||
@ -525,7 +475,7 @@
|
|||||||
|
|
||||||
.list .item .id {
|
.list .item .id {
|
||||||
color: #ffffff99;
|
color: #ffffff99;
|
||||||
font-family: PingFang SC;
|
font-family: "PingFang SC";
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 30rpx;
|
line-height: 30rpx;
|
||||||
@ -547,7 +497,7 @@
|
|||||||
|
|
||||||
.openBlue .txt {
|
.openBlue .txt {
|
||||||
color: rgba(255, 255, 255, 0.87);
|
color: rgba(255, 255, 255, 0.87);
|
||||||
font-family: PingFang SC;
|
font-family: "PingFang SC";
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
letter-spacing: 0.14rpx;
|
letter-spacing: 0.14rpx;
|
||||||
@ -572,7 +522,7 @@
|
|||||||
width: 25%;
|
width: 25%;
|
||||||
height: 60rpx;
|
height: 60rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: PingFang SC;
|
font-family: "PingFang SC";
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
letter-spacing: 12rpx;
|
letter-spacing: 12rpx;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
@ -584,10 +534,12 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.openBlue .cancel {
|
.openBlue .cancel {
|
||||||
border: 1px solid rgba(255, 255, 255, 1);
|
border: 1px solid rgba(255, 255, 255, 1);
|
||||||
color: rgba(255, 255, 255, 1);
|
color: rgba(255, 255, 255, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.openBlue .ok {
|
.openBlue .ok {
|
||||||
background-color: #BBE600;
|
background-color: #BBE600;
|
||||||
color: #232323;
|
color: #232323;
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showView: false,
|
showView: false,
|
||||||
phone: '13800138002', //手机号码
|
phone: '17671332251', //手机号码
|
||||||
code: "123456", //验证码
|
code: "123456", //验证码
|
||||||
agreed: false,
|
agreed: false,
|
||||||
isCounting: false,
|
isCounting: false,
|
||||||
@ -69,6 +69,29 @@
|
|||||||
showAgreement: false, // 控制弹窗显示
|
showAgreement: false, // 控制弹窗显示
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onLoad(){
|
||||||
|
if(uni.getStorageSync("token") && uni.getStorageSync("clientID")){//免登陆
|
||||||
|
|
||||||
|
let time=uni.getStorageSync("tokenTime");
|
||||||
|
if(!time){
|
||||||
|
time=0;
|
||||||
|
}
|
||||||
|
let currTime=new Date().getTime();
|
||||||
|
if(currTime<time){
|
||||||
|
console.log("登陆过,并且没过期,自动进入设备页");
|
||||||
|
uni.switchTab({
|
||||||
|
url: '/pages/common/index/index'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
//token过期了
|
||||||
|
uni.removeStorageSync("token")
|
||||||
|
uni.removeStorageSync("clientID")
|
||||||
|
uni.removeStorageSync("tokenTime")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 获取验证码
|
// 获取验证码
|
||||||
async getPhoneCode() {
|
async getPhoneCode() {
|
||||||
@ -158,6 +181,7 @@
|
|||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.setStorageSync('token', res.data.access_token) // 缓存token
|
uni.setStorageSync('token', res.data.access_token) // 缓存token
|
||||||
uni.setStorageSync('clientID', res.data.client_id) // 缓存token
|
uni.setStorageSync('clientID', res.data.client_id) // 缓存token
|
||||||
|
uni.setStorageSync('tokenTime',new Date().getTime()+86400000);//过期时间
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '登录成功',
|
title: '登录成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
|
|||||||
BIN
static/fonts/PingFangSC.ttf
Normal file
BIN
static/images/6155/DeviceDetail/Hby650.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
static/images/6155/DeviceDetail/close.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
static/images/6155/DeviceDetail/uploadErr.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
static/images/6155/DeviceDetail/warnning.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
static/images/670/jieN.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
static/images/670/jieNActive.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
static/images/670/qiang.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
static/images/670/qiangActive.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
static/images/670/rb.png
Normal file
|
After Width: | Height: | Size: 754 B |
BIN
static/images/670/rbActive.png
Normal file
|
After Width: | Height: | Size: 999 B |
BIN
static/images/670/ruo.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
static/images/670/ruoActive.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
static/images/670/sg.png
Normal file
|
After Width: | Height: | Size: 968 B |
BIN
static/images/670/sgActive.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
static/images/BLEAdd/addBleDevice.png
Normal file
|
After Width: | Height: | Size: 867 B |
1274
utils/BleHelper.js
Normal file
411
utils/BleReceive.js
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
class BleReceive {
|
||||||
|
constructor() {
|
||||||
|
this.StorageKey = "linkedDevices";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentPagePath() {
|
||||||
|
|
||||||
|
const pages = getCurrentPages();
|
||||||
|
|
||||||
|
if (pages.length === 0) {
|
||||||
|
console.log("pages.length=0");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPage = pages[pages.length - 1];
|
||||||
|
console.log("currentPage=", currentPage.route);
|
||||||
|
return currentPage.route;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setBleFormData(data,f) {
|
||||||
|
if(data){
|
||||||
|
let linkedList=uni.getStorageSync(this.StorageKey);
|
||||||
|
linkedList.find((v)=>{
|
||||||
|
if(f.deviceId==v.deviceId){
|
||||||
|
let keys=Object.keys(data);
|
||||||
|
keys.forEach((key)=>{
|
||||||
|
if(!v.formData){
|
||||||
|
v.formData={};
|
||||||
|
}
|
||||||
|
if(!f.formData){
|
||||||
|
f.formData={};
|
||||||
|
}
|
||||||
|
v.formData[key]=data[key];
|
||||||
|
f.formData[key]=data[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
uni.setStorageSync(this.StorageKey,linkedList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ReceiveData(receive,f,path) {
|
||||||
|
if(f && f.macAddress && f.id){
|
||||||
|
let data={};
|
||||||
|
if(f.detailPageUrl=='/pages/6155/deviceDetail'){
|
||||||
|
console.log("该设备是6155");
|
||||||
|
data= this.Receive_6155(receive,f,path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f.detailPageUrl=='/pages/650/HBY650'){
|
||||||
|
console.log("该设备是650");
|
||||||
|
data= this.Receive_650(receive,f,path);
|
||||||
|
}
|
||||||
|
if(f.detailPageUrl=='/pages/670/HBY670'){
|
||||||
|
console.log("该设备是670");
|
||||||
|
data= this.Receive_670(receive,f,path);
|
||||||
|
}
|
||||||
|
console.log("收到数据并处理完毕,",data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
console.log("已收到该消息,但无法处理",f);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Receive_650(receive,f,path) {
|
||||||
|
console.log("通用程序正在处理650的数据",receive);
|
||||||
|
|
||||||
|
var parseData = () => {
|
||||||
|
let bytes = receive.bytes;
|
||||||
|
if (bytes[0] == 0x55) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
let staticLevelByte = bytes[1];
|
||||||
|
let staticLevelText = '未知';
|
||||||
|
let modeCurr = "";
|
||||||
|
|
||||||
|
switch (staticLevelByte) {
|
||||||
|
case 0x65:
|
||||||
|
staticLevelText = '高档';
|
||||||
|
modeCurr = "hight";
|
||||||
|
break;
|
||||||
|
case 0x66:
|
||||||
|
staticLevelText = '中档';
|
||||||
|
modeCurr = "center";
|
||||||
|
break;
|
||||||
|
case 0x67:
|
||||||
|
staticLevelText = '低档';
|
||||||
|
modeCurr = "low";
|
||||||
|
break;
|
||||||
|
case 0x68:
|
||||||
|
staticLevelText = '关闭';
|
||||||
|
modeCurr = "close";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析照明档位
|
||||||
|
let lightingLevelByte = bytes[2];
|
||||||
|
let lightingLevelText = lightingLevelByte === 0x6e ? '开启' : '关闭';
|
||||||
|
|
||||||
|
|
||||||
|
// 解析剩余照明时间(第三和第四字节,大端序)
|
||||||
|
let lightingTime = (bytes[3] << 8) | bytes[4];
|
||||||
|
let hours = Math.floor(lightingTime / 60);
|
||||||
|
let remainingMinutes = lightingTime % 60;
|
||||||
|
let xuhang = '0分';
|
||||||
|
// 处理不同情况的显示
|
||||||
|
if (hours === 0) {
|
||||||
|
xuhang = `${remainingMinutes}分`;
|
||||||
|
} else if (remainingMinutes === 0) {
|
||||||
|
xuhang = `${hours}小时`;
|
||||||
|
} else {
|
||||||
|
xuhang = `${hours}小时${remainingMinutes}分`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析剩余电量
|
||||||
|
let batteryLevelByte = bytes[5];
|
||||||
|
// 电量百分比范围检查
|
||||||
|
let batteryLevel = Math.max(0, Math.min(100, batteryLevelByte));
|
||||||
|
let iswarn = false;
|
||||||
|
let warn = bytes[6];
|
||||||
|
if (warn == 0x00) {
|
||||||
|
warn = '无预警';
|
||||||
|
} else if (warn == 0x01) {
|
||||||
|
warn = '弱预警';
|
||||||
|
} else if (warn == 0x02) {
|
||||||
|
iswarn = true;
|
||||||
|
warn = '中预警';
|
||||||
|
} else if (warn == 0x03) {
|
||||||
|
iswarn = true;
|
||||||
|
warn = '强预警';
|
||||||
|
} else if (warn == 0x04) {
|
||||||
|
iswarn = true;
|
||||||
|
warn = '非常强预警';
|
||||||
|
}
|
||||||
|
|
||||||
|
let formData={};
|
||||||
|
formData.battary = batteryLevel;
|
||||||
|
formData.xuhang = xuhang;
|
||||||
|
formData.cMode = lightingLevelByte === 0x6e;
|
||||||
|
formData.modeCurr = modeCurr;
|
||||||
|
formData.warnLevel = warn;
|
||||||
|
formData.iswarn = iswarn;
|
||||||
|
this.setBleFormData(formData,f);
|
||||||
|
|
||||||
|
let route=this.getCurrentPagePath();
|
||||||
|
console.log("f=",f);
|
||||||
|
console.log("route="+route);
|
||||||
|
if (iswarn && f.detailPageUrl.indexOf(route)==-1 ) {
|
||||||
|
uni.showModal({
|
||||||
|
content:"环境存在漏电电源",
|
||||||
|
title:"警告",
|
||||||
|
success(res){
|
||||||
|
if(res.confirm){
|
||||||
|
|
||||||
|
if(f){
|
||||||
|
uni.navigateTo({
|
||||||
|
url: f.detailPageUrl,
|
||||||
|
events: {
|
||||||
|
ack: function(data) {}
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
res.eventChannel.emit('detailData', {
|
||||||
|
data: f,
|
||||||
|
deviceType: '',
|
||||||
|
apiType: 'listA'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
console.log("当前全局不处理此消息");
|
||||||
|
}
|
||||||
|
return formData;
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receive.str) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
let str = receive.str;
|
||||||
|
|
||||||
|
if (str.indexOf('mac address:') == 0) {
|
||||||
|
let formData={};
|
||||||
|
formData.macAddress = str.split(':')[1];
|
||||||
|
this.setBleFormData(formData,f);
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
let receiveData={a:1};
|
||||||
|
try {
|
||||||
|
let json=JSON.parse(str);
|
||||||
|
|
||||||
|
if("staBlue_picture" in json){
|
||||||
|
//重发图片
|
||||||
|
console.log("收到重新发送图片的命令");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
else if("staBlue_text" in json){
|
||||||
|
//重发文本
|
||||||
|
console.log("收到重新发送文本的命令");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
else if("staBlue_vidio" in json){
|
||||||
|
//重发视频
|
||||||
|
console.log("收到重新发送视频的命令");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
else if("staBlue" in json){
|
||||||
|
if(json.staBlue=="finish"){
|
||||||
|
console.log("收到设备回复,全部传输完成");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
receiveData={};
|
||||||
|
console.log("无法解析该文本");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
receiveData={};
|
||||||
|
console.log("文本解析失败")
|
||||||
|
}
|
||||||
|
return receiveData;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let data=parseData(receive.bytes);
|
||||||
|
console.log("data=",data);
|
||||||
|
return data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Receive_670(receive,f,path){
|
||||||
|
|
||||||
|
var todo = (bytes) =>{
|
||||||
|
console.log("todo");
|
||||||
|
let receiveData = {};
|
||||||
|
if (bytes[0] == 0x55) {
|
||||||
|
try {
|
||||||
|
console.log("todo");
|
||||||
|
// 跳过帧头(第一个字节),从第二个字节开始解析
|
||||||
|
let staticLevelByte = bytes[1];
|
||||||
|
let staticLevelText = '';
|
||||||
|
switch (staticLevelByte) {
|
||||||
|
case 0x65:
|
||||||
|
staticLevelText = 'hight';
|
||||||
|
break
|
||||||
|
case 0x66:
|
||||||
|
staticLevelText = 'center';
|
||||||
|
break
|
||||||
|
case 0x67:
|
||||||
|
staticLevelText = 'low';
|
||||||
|
break
|
||||||
|
case 0x68:
|
||||||
|
staticLevelText = 'close';
|
||||||
|
break
|
||||||
|
}
|
||||||
|
console.log("todo");
|
||||||
|
// 解析照明档位
|
||||||
|
let lightingLevelByte = bytes[2];
|
||||||
|
let lightingLevelText = lightingLevelByte === 0x6d ? 'hight': lightingLevelByte === 0x6e ? 'low': 'close';
|
||||||
|
|
||||||
|
// 解析剩余照明时间(第三和第四字节,小端序)
|
||||||
|
let lightingTime = (bytes[3] << 8) | bytes[4];
|
||||||
|
|
||||||
|
// 解析剩余电量 // 电量百分比范围检查
|
||||||
|
let batteryLevelByte = bytes[5];
|
||||||
|
|
||||||
|
let batteryLevel = Math.max(0, Math.min(100, batteryLevelByte));
|
||||||
|
console.log("todo");
|
||||||
|
let warn = bytes[6];
|
||||||
|
if (warn == 0x00) {
|
||||||
|
warn = 'none';
|
||||||
|
} else if (warn == 0x01) {
|
||||||
|
warn = 'ruo';
|
||||||
|
} else if (warn == 0x02) {
|
||||||
|
warn = 'center';
|
||||||
|
} else if (warn == 0x03) {
|
||||||
|
warn = 'hight';
|
||||||
|
} else if (warn == 0x04) {
|
||||||
|
warn = 'veryhight';
|
||||||
|
}
|
||||||
|
|
||||||
|
let staticWarn = bytes[7] == 0x01;//静止报警
|
||||||
|
let fourGStrenth = bytes[8]; //4g信号强度
|
||||||
|
let sosTxt = bytes[9] == 0x00 ? 'close' : bytes[9] == 0x01 ? 'sg' : 'rb';
|
||||||
|
console.log("todo");
|
||||||
|
receiveData.modeCurr = staticLevelText;
|
||||||
|
receiveData.lightCurr = lightingLevelText;
|
||||||
|
receiveData.xuhang = lightingTime ;
|
||||||
|
receiveData.battary = batteryLevel;
|
||||||
|
receiveData.warnLevel = warn;
|
||||||
|
receiveData.staticWarn = staticWarn;
|
||||||
|
receiveData.fourGStrenth = fourGStrenth;
|
||||||
|
receiveData.SOS=sosTxt;
|
||||||
|
} catch(error) {
|
||||||
|
console.log('数据解析错误:', error);
|
||||||
|
}
|
||||||
|
console.log("todo");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
let uint8Array = new Uint8Array(receive.value);
|
||||||
|
let str = '';
|
||||||
|
for (let i = 0; i < uint8Array.length; i++) {
|
||||||
|
// 将每个字节转换为对应的字符
|
||||||
|
str += String.fromCharCode(uint8Array[i]);
|
||||||
|
}
|
||||||
|
if (str.indexOf('mac address:') == 0) {
|
||||||
|
receiveData.macAddress = str.split(':').slice(1).join(":");
|
||||||
|
console.log('收到mac地址:', +this.receiveData.macAddress);
|
||||||
|
} else if (str.indexOf('imei:') == 0) {
|
||||||
|
receiveData.imei = str.split(':')[1];
|
||||||
|
console.log('收到IEMI:', +this.receiveData.macAddress);
|
||||||
|
|
||||||
|
} else if (str.indexOf('longitude:') == 0) {
|
||||||
|
receiveData.Lon = str.split(':')[1];
|
||||||
|
console.log('收到经度:', +this.receiveData.macAddress);
|
||||||
|
} else if (str.indexOf('latitude:') == 0) {
|
||||||
|
receiveData.Lat = str.split(':')[1];
|
||||||
|
console.log('收到纬度:', +this.receiveData.macAddress);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
let json=JSON.parse(str);
|
||||||
|
if("staBlue_picture" in json){
|
||||||
|
//重发图片
|
||||||
|
console.log("收到重新发送图片的命令");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
else if("staBlue_text" in json){
|
||||||
|
//重发文本
|
||||||
|
console.log("收到重新发送文本的命令");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
else if("staBlue_vidio" in json){
|
||||||
|
//重发视频
|
||||||
|
console.log("收到重新发送视频的命令");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
else if("staBlue" in json){
|
||||||
|
if(json.staBlue=="finish"){
|
||||||
|
console.log("收到设备回复,全部传输完成");
|
||||||
|
receiveData=json;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
receiveData={};
|
||||||
|
console.log("无法解析该文本");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
receiveData={};
|
||||||
|
console.log("文本解析失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(ex) {
|
||||||
|
receiveData={};
|
||||||
|
console.log('将数据转文本失败', ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("todo",receiveData);
|
||||||
|
this.setBleFormData(receiveData,f);
|
||||||
|
return receiveData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let data=todo(receive.bytes);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
Receive_6155() {
|
||||||
|
console.log("通用程序正在处理6155的数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let receiveInstance = null;
|
||||||
|
export default {
|
||||||
|
getBleReceive: function(found, receive) {
|
||||||
|
if (!receiveInstance) {
|
||||||
|
receiveInstance = new BleReceive();
|
||||||
|
|
||||||
|
}
|
||||||
|
return receiveInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
218
utils/Common.js
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
var cfg={
|
||||||
|
Version:'Uat',//Dev:开发环境,Uat:Uat环境,Relese正式环境
|
||||||
|
DevApi:'http://192.168.110.54:8000/',//开发环境
|
||||||
|
UatApi:'http://114.55.111.217/',//UAT环境
|
||||||
|
ReleseApi:'http://relese:3169/api/'//Relese环境
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
baseURL : cfg.Version=='Dev'?cfg.DevApi:(cfg.Version=='Uat'?cfg.UatApi:cfg.ReleseApi),
|
||||||
|
guid:function generateUUID() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
const r = Math.random() * 16 | 0;
|
||||||
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
alert: function(title, content, callback) {
|
||||||
|
if(!title){
|
||||||
|
title='提示'
|
||||||
|
}
|
||||||
|
if(!content){
|
||||||
|
content=title;
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showModal({
|
||||||
|
title: title,
|
||||||
|
content: content,
|
||||||
|
success: function(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
console.log('用户点击确定');
|
||||||
|
} else if (res.cancel) {
|
||||||
|
console.log('用户点击取消');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoading:function(title,mask){
|
||||||
|
uni.showLoading({
|
||||||
|
title:title,
|
||||||
|
mask:mask,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
hideLoading:function(){
|
||||||
|
uni.hideLoading();
|
||||||
|
},
|
||||||
|
showToast:function(title,mask,duration,callback){
|
||||||
|
if(!duration){
|
||||||
|
duration=1500;
|
||||||
|
}
|
||||||
|
if(mask==undefined){
|
||||||
|
mask=false;
|
||||||
|
}
|
||||||
|
uni.showToast({
|
||||||
|
title:title,
|
||||||
|
mask:mask,
|
||||||
|
duration:duration,
|
||||||
|
callback:callback,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
GetData:function(url,data,method,contentType,succ,err,complete){
|
||||||
|
var these=this;
|
||||||
|
if(!url){
|
||||||
|
console.error("url为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(url.toLowerCase().indexOf('http://')==-1 || url.toLowerCase().indexOf('https://')==-1){
|
||||||
|
if(url.indexOf('/')==0){
|
||||||
|
url=url.substr(1,url.length-1);
|
||||||
|
}
|
||||||
|
let ServerPath=these.DevApi;
|
||||||
|
if(these.Version==='Dev'){
|
||||||
|
ServerPath=these.DevApi;
|
||||||
|
}
|
||||||
|
else if(these.Version==='Uat'){
|
||||||
|
ServerPath=these.UatApi;
|
||||||
|
}
|
||||||
|
else if(these.Version==='Relese'){
|
||||||
|
ServerPath=these.ReleseApi;
|
||||||
|
}else{
|
||||||
|
these.DevApi
|
||||||
|
}
|
||||||
|
url=ServerPath+url;
|
||||||
|
}
|
||||||
|
|
||||||
|
var these=this;
|
||||||
|
if(!method){
|
||||||
|
method='POST';
|
||||||
|
}
|
||||||
|
method=method.toUpperCase();
|
||||||
|
|
||||||
|
if(!contentType){
|
||||||
|
contentType='application/json;charset=UTF-8';
|
||||||
|
}
|
||||||
|
|
||||||
|
these.checkLAN(
|
||||||
|
|
||||||
|
function(){
|
||||||
|
these.showLoading('请稍候..',true);
|
||||||
|
setTimeout(function(){
|
||||||
|
uni.request({
|
||||||
|
url:url,
|
||||||
|
data:data,
|
||||||
|
header:{
|
||||||
|
"Content-Type":contentType
|
||||||
|
},
|
||||||
|
method:method,
|
||||||
|
timeout:60000,
|
||||||
|
dataType:'json',
|
||||||
|
success:function(json){
|
||||||
|
|
||||||
|
if(succ){
|
||||||
|
succ(json);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail:function(ex){
|
||||||
|
|
||||||
|
if(err){
|
||||||
|
err(ex);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete:function(){
|
||||||
|
|
||||||
|
if(complete){
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
,function(){
|
||||||
|
these.showToast('无网络连接');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
checkLAN:function(succ,error){
|
||||||
|
uni.getNetworkType({
|
||||||
|
success: (res) => {
|
||||||
|
const networkType = res.networkType;
|
||||||
|
|
||||||
|
|
||||||
|
// 判断网络是否连接
|
||||||
|
if (networkType === 'none') {
|
||||||
|
console.error('无网络连接')
|
||||||
|
if(error){
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(succ){
|
||||||
|
succ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('获取网络状态失败:', err);
|
||||||
|
if(error){
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
DateFormat: function(date, format) {
|
||||||
|
if(!date){
|
||||||
|
date=new Date();
|
||||||
|
}
|
||||||
|
if(!format){
|
||||||
|
format='yyyy-MM-dd HH:mm:ss';
|
||||||
|
}
|
||||||
|
// 处理参数默认值
|
||||||
|
if (typeof date === 'string' || typeof date === 'number') {
|
||||||
|
date = new Date(date);
|
||||||
|
}
|
||||||
|
date = date instanceof Date ? date : new Date();
|
||||||
|
format = format || 'yyyy-MM-dd';
|
||||||
|
|
||||||
|
// 检查日期是否有效
|
||||||
|
if (isNaN(date.getTime())) {
|
||||||
|
return 'Invalid Date';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义格式化映射
|
||||||
|
const formatMap = {
|
||||||
|
'yyyy': date.getFullYear(),
|
||||||
|
'MM': String(date.getMonth() + 1).padStart(2, '0'),
|
||||||
|
'dd': String(date.getDate()).padStart(2, '0'),
|
||||||
|
'HH': String(date.getHours()).padStart(2, '0'),
|
||||||
|
'mm': String(date.getMinutes()).padStart(2, '0'),
|
||||||
|
'ss': String(date.getSeconds()).padStart(2, '0'),
|
||||||
|
'SSS': String(date.getMilliseconds()).padStart(3, '0'),
|
||||||
|
'M': date.getMonth() + 1,
|
||||||
|
'd': date.getDate(),
|
||||||
|
'H': date.getHours(),
|
||||||
|
'm': date.getMinutes(),
|
||||||
|
's': date.getSeconds(),
|
||||||
|
'S': date.getMilliseconds()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 替换格式字符串中的占位符
|
||||||
|
return format.replace(/(yyyy|MM|dd|HH|mm|ss|SSS|M|d|H|m|s|S)/g, (match) => {
|
||||||
|
return formatMap[match];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
122
utils/gbk.js
Normal file
44
utils/loading.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// utils/loading.js
|
||||||
|
|
||||||
|
// 显示loading
|
||||||
|
export const showLoading = (ev,options) => {
|
||||||
|
if(!ev){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!options){
|
||||||
|
options={a:1};
|
||||||
|
}
|
||||||
|
if(!options.text && options.title){
|
||||||
|
options.text=options.title;
|
||||||
|
}
|
||||||
|
if(!options.text){
|
||||||
|
options.text="请稍候...";
|
||||||
|
}
|
||||||
|
ev.$refs.loading.show(options);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏loading
|
||||||
|
export const hideLoading = (ev) => {
|
||||||
|
|
||||||
|
if(!ev){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev.$refs.loading.hide();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新loading配置
|
||||||
|
export const updateLoading = (ev,options) => {
|
||||||
|
if(!ev){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!options){
|
||||||
|
options={a:1};
|
||||||
|
}
|
||||||
|
ev.$refs.loading.update(options)
|
||||||
|
|
||||||
|
}
|
||||||
@ -119,7 +119,7 @@ import Paho from 'paho-mqtt';
|
|||||||
import allConfigs from '../config/index.js';
|
import allConfigs from '../config/index.js';
|
||||||
|
|
||||||
// 根据环境选择正确的配置
|
// 根据环境选择正确的配置
|
||||||
const env = 'production'; //production //开发of线上 改这里就行
|
const env = 'development'; //production //开发of线上 改这里就行
|
||||||
const config = allConfigs[env];
|
const config = allConfigs[env];
|
||||||
|
|
||||||
class MqttClient {
|
class MqttClient {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import config from '../config/index.js';
|
import config from '../config/index.js';
|
||||||
const env = 'production'; //production development //开发of线上 改这里就行
|
const env = 'development'; //production development //开发of线上 改这里就行
|
||||||
const BASE = config[env];
|
const BASE = config[env];
|
||||||
const request = (options) => {
|
const request = (options) => {
|
||||||
console.log("options"+JSON.stringify(options),BASE.BASE_URL)
|
console.log("options"+JSON.stringify(options),BASE.BASE_URL)
|
||||||
|
|||||||
153
utils/update.js
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/**
|
||||||
|
* 检查并执行wgt热更新
|
||||||
|
* @param {String} updateUrl - 检查更新的接口地址
|
||||||
|
*/
|
||||||
|
function checkAndUpdateWgt(updateUrl) {
|
||||||
|
if(!plus){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 显示加载提示
|
||||||
|
|
||||||
|
|
||||||
|
// 1. 获取当前应用版本信息
|
||||||
|
plus.runtime.getProperty(plus.runtime.appid, (widgetInfo) => {
|
||||||
|
const currentVersion = widgetInfo.version;
|
||||||
|
console.log("当前版本:" + currentVersion);
|
||||||
|
// 2. 调用后端接口检查是否有更新
|
||||||
|
uni.request({
|
||||||
|
url: updateUrl,
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
currentVersion: currentVersion,
|
||||||
|
platform: uni.getSystemInfoSync().platform
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
uni.hideLoading();
|
||||||
|
console.log("res=", res)
|
||||||
|
if (res.statusCode === 200) {
|
||||||
|
|
||||||
|
const updateInfo = res.data.data;
|
||||||
|
if (!updateInfo.hasUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 3. 显示更新提示
|
||||||
|
uni.showModal({
|
||||||
|
title: '检测到更新',
|
||||||
|
content: updateInfo.description || '有新版本可用,是否立即更新?',
|
||||||
|
confirmText: '立即更新',
|
||||||
|
cancelText: '稍后更新',
|
||||||
|
success: (modalRes) => {
|
||||||
|
if (modalRes.confirm) {
|
||||||
|
downloadAndInstallWgt(updateInfo.downloadUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '当前已是最新版本',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: '检查更新失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
console.error('检查更新失败:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载并安装wgt更新包
|
||||||
|
* @param {String} wgtUrl - wgt包下载地址
|
||||||
|
*/
|
||||||
|
function downloadAndInstallWgt(wgtUrl) {
|
||||||
|
// 显示下载进度
|
||||||
|
var wating=plus.nativeUI.showWaiting({
|
||||||
|
title:"下载中0%"
|
||||||
|
});
|
||||||
|
// uni.showLoading({
|
||||||
|
// title: '更新下载中...',
|
||||||
|
// mask: true
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 1. 下载wgt包
|
||||||
|
const downloadTask = uni.downloadFile({
|
||||||
|
url: wgtUrl,
|
||||||
|
success: (downloadRes) => {
|
||||||
|
wating.setTitle("下载完成,正在安装");
|
||||||
|
if (downloadRes.statusCode === 200) {
|
||||||
|
// 2. 安装wgt包
|
||||||
|
plus.runtime.install(downloadRes.tempFilePath, {
|
||||||
|
force: true // 是否强制安装
|
||||||
|
}, () => {
|
||||||
|
uni.removeSavedFile({
|
||||||
|
filePath: downloadRes.tempFilePath,
|
||||||
|
success() {
|
||||||
|
console.log("临时文件已删除");
|
||||||
|
},
|
||||||
|
fail() {
|
||||||
|
console.log("无法删除临时文件");
|
||||||
|
},
|
||||||
|
complete() {
|
||||||
|
wating.close();
|
||||||
|
uni.showModal({
|
||||||
|
title: '更新完成',
|
||||||
|
content: '应用已更新,是否重启应用?',
|
||||||
|
showCancel: false,
|
||||||
|
success: () => {
|
||||||
|
// 3. 重启应用
|
||||||
|
plus.runtime.restart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}, (error) => {
|
||||||
|
|
||||||
|
wating.close();
|
||||||
|
uni.showToast({
|
||||||
|
title: '安装失败: ' + error.message,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 3000
|
||||||
|
});
|
||||||
|
console.error('wgt安装失败:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
wating.close();
|
||||||
|
uni.showToast({
|
||||||
|
title: '下载失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
uni.hideLoading();
|
||||||
|
uni.showToast({
|
||||||
|
title: '下载失败: ' + err.errMsg,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
console.error('wgt下载失败:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听下载进度
|
||||||
|
downloadTask.onProgressUpdate((progress) => {
|
||||||
|
console.log('下载进度: ' + progress.progress + '%');
|
||||||
|
wating.setTitle("下载中"+ progress.progress + '%');
|
||||||
|
// 可以在这里更新自定义进度条
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
checkAndUpdateWgt
|
||||||
|
};
|
||||||