移植6155、650、670
@ -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="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 class="bottom-slide-menu" :style="{ backgroundColor: config.bgColor }" :class="{ 'show': config.show }"
|
||||
@touchmove.stop.prevent>
|
||||
<view class="menu-header" :class="config.showHeader?'':'displayNone'">
|
||||
<view class="title" :style="{ color: config.textColor}">{{ config.title }}</view>
|
||||
<view class="close-icon" @click="closeMenu"
|
||||
:style="{display:(config.showClose?'':'none')}"
|
||||
>
|
||||
<view class="close-icon" @click="closeMenu" :style="{display:(config.showClose?'':'none')}">
|
||||
<image src="/static/Images/public/close.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
@ -29,7 +26,13 @@
|
||||
<view class="p100" :style="{backgroundColor:config.activeIndex==index?config.itemBgColor:'',
|
||||
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>
|
||||
</view>
|
||||
|
||||
@ -61,34 +64,34 @@
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
show: false,//是否显示
|
||||
showHeader: false,//是否显示标头
|
||||
showMask:true,//是否显示mask
|
||||
showDivider: false,//是否在两个项之间显示分隔线
|
||||
showBtn: false,//是否显示底部按钮
|
||||
showClose:false,//是否显示右上角关闭按钮
|
||||
maskBgColor:'',//mask的颜色
|
||||
menuItems: [],//菜单项 包含icon text
|
||||
activeIndex: -1,//当前已选中的项编号
|
||||
bgColor: '#2a2a2a',//主体背景
|
||||
itemBgColor: '#3a3a3a',//各项被选中后的背景
|
||||
textColor: '#ffffffde',//各项的文字颜色
|
||||
textAlign: 'flex-start',//各项的文字居中方式
|
||||
title: '',//header的文字
|
||||
dividerColor: '#00000000',//分隔线颜色
|
||||
dividerThickness: '0rpx',//分隔线宽度
|
||||
dividerMargin: '10rpx',//分隔线距离两边的宽度
|
||||
itemHeight: '80rpx',//各项的调试
|
||||
btnBgColor: "#bbe600",//按钮颜色
|
||||
btnText: "确定",//按钮文字
|
||||
btnTextColor: "#000000",//按钮文字颜色
|
||||
|
||||
show: false, //是否显示
|
||||
showHeader: false, //是否显示标头
|
||||
showMask: true, //是否显示mask
|
||||
showDivider: false, //是否在两个项之间显示分隔线
|
||||
showBtn: false, //是否显示底部按钮
|
||||
showClose: false, //是否显示右上角关闭按钮
|
||||
maskBgColor: '', //mask的颜色
|
||||
menuItems: [], //菜单项 包含icon text
|
||||
activeIndex: -1, //当前已选中的项编号
|
||||
bgColor: '#2a2a2a', //主体背景
|
||||
itemBgColor: '#3a3a3a', //各项被选中后的背景
|
||||
textColor: '#ffffffde', //各项的文字颜色
|
||||
textAlign: 'flex-start', //各项的文字居中方式
|
||||
title: '', //header的文字
|
||||
dividerColor: '#00000000', //分隔线颜色
|
||||
dividerThickness: '0rpx', //分隔线宽度
|
||||
dividerMargin: '10rpx', //分隔线距离两边的宽度
|
||||
itemHeight: '80rpx', //各项的调试
|
||||
btnBgColor: "#bbe600", //按钮颜色
|
||||
btnText: "确定", //按钮文字
|
||||
btnTextColor: "#000000", //按钮文字颜色
|
||||
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
closeMenu() {
|
||||
|
||||
@ -100,19 +103,18 @@
|
||||
this.$emit('itemClick', item, index);
|
||||
},
|
||||
btnClick() {
|
||||
|
||||
|
||||
let item = null;
|
||||
let index = null;
|
||||
if (this.config.activeIndex > -1) {
|
||||
item = this.config.menuItems[this.config.activeIndex];
|
||||
}
|
||||
index = this.config.activeIndex;
|
||||
this.$emit('btnClick', item, index);
|
||||
this.$emit('btnClick', item, index);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@ -126,7 +128,7 @@
|
||||
}
|
||||
|
||||
.p100 {
|
||||
width: 100%;
|
||||
width: calc(100% - 20rpx);
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
@ -136,7 +138,8 @@
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0rpx 20rpx;
|
||||
padding: 0rpx 20rpx 0rpx 0rpx;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.displayNone {
|
||||
@ -151,7 +154,7 @@
|
||||
z-index: 9999;
|
||||
transition: transform 0.3s ease-out;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -217,11 +220,24 @@
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.menu-item image {
|
||||
width: 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;
|
||||
}
|
||||
|
||||
|
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 = {
|
||||
// 开发环境
|
||||
development: {
|
||||
BASE_URL: 'http://192.168.2.34:8000',
|
||||
BASE_URL: 'http://192.168.110.54:8000',
|
||||
API_PREFIX: '',
|
||||
// MQTT 配置
|
||||
MQTT_HOST: '47.120.79.150',
|
||||
MQTT_PORT: 9083,
|
||||
MQTT_PORT: 8083,
|
||||
MQTT_USERNAME: 'admin',
|
||||
MQTT_PASSWORD: '#YtvpSfCNG'
|
||||
},
|
||||
@ -16,7 +16,7 @@ const config = {
|
||||
API_PREFIX: '',
|
||||
// MQTT 配置
|
||||
MQTT_HOST: '47.120.79.150',
|
||||
MQTT_PORT: 9083,
|
||||
MQTT_PORT: 8083,
|
||||
MQTT_USERNAME: 'admin',
|
||||
MQTT_PASSWORD: '#YtvpSfCNG'
|
||||
}
|
||||
|
6
package-lock.json
generated
@ -272,7 +272,8 @@
|
||||
"node_modules/mescroll-uni": {
|
||||
"version": "1.3.7",
|
||||
"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": {
|
||||
"version": "1.52.0",
|
||||
@ -296,7 +297,8 @@
|
||||
"node_modules/paho-mqtt": {
|
||||
"version": "1.1.0",
|
||||
"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": {
|
||||
"version": "1.1.0",
|
||||
|
83
pages.json
@ -190,6 +190,89 @@
|
||||
"style": {
|
||||
"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) {
|
||||
const eventChannel = this.getOpenerEventChannel();
|
||||
var these = this;
|
||||
eventChannel.on('checkImg', function(data) {
|
||||
eventChannel.on('checkImg', (data)=> {
|
||||
console.log("我收到你的消息了,消息内容是:" + JSON.stringify(data));
|
||||
these.src = data.data;
|
||||
this.src = data.data;
|
||||
console.log("我收到你的消息了,消息内容是:",data);
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleCrop(e) {
|
||||
|
||||
var these = this;
|
||||
|
||||
this.Statu = true;
|
||||
console.log("裁剪完成");
|
||||
console.log(e.tempFilePath);
|
||||
|
||||
//
|
||||
const ctx = uni.createCanvasContext('splashCanvas', this);
|
||||
ctx.drawImage(
|
||||
e.tempFilePath,
|
||||
@ -53,11 +56,12 @@
|
||||
height: 80,
|
||||
success: (res) => {
|
||||
// 处理像素数据并发送
|
||||
const eventChannel = these.getOpenerEventChannel();
|
||||
console.log("res.data.length="+res.data.length);
|
||||
// this.processAndSendImageData(res.data).then(
|
||||
// resolve).catch(reject);
|
||||
const eventChannel = these.getOpenerEventChannel();
|
||||
eventChannel.emit('ImgCutOver',res.data);
|
||||
|
||||
|
||||
eventChannel.emit('ImgCutOver',{piexls:res.data,picPath:e.tempFilePath});
|
||||
|
||||
uni.navigateBack();
|
||||
},
|
||||
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>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<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 {
|
||||
data() {
|
||||
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>
|
||||
|
||||
<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>
|
||||
</BottomSlideMenuPlus>
|
||||
|
||||
<global-loading ref="loading" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ble from '../../../api/6155/BlueHelper.js';
|
||||
import request from '../../../utils/request.js';
|
||||
|
||||
import bleTool from '@/utils/BleHelper.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 {
|
||||
data() {
|
||||
return {
|
||||
@ -127,72 +136,71 @@
|
||||
},
|
||||
onHide: function() {
|
||||
ble.StopSearch();
|
||||
ble.removeReceiveCallback(pagePath);
|
||||
},
|
||||
onBackPress: (e) => {
|
||||
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() {
|
||||
// return;
|
||||
var these = this;
|
||||
uni.getStorage({
|
||||
key: "linkedDevices",
|
||||
success: (res) => {
|
||||
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();
|
||||
arr[i].linkStatu = false;
|
||||
if(!arr[i].name){
|
||||
continue;
|
||||
}
|
||||
let f = these.EquipMents.find(function(v) {
|
||||
return v.deviceId == arr[i].deviceId;
|
||||
});
|
||||
|
||||
if (!f) {
|
||||
|
||||
these.EquipMents.push(arr[i]);
|
||||
} else {
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
},pagePath);
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
console.log('当前环境:' + process.env.UNI_PLATFORM + '不支持蓝牙');
|
||||
}
|
||||
},
|
||||
|
||||
onShow: function() {
|
||||
|
||||
|
||||
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: {
|
||||
isItemLink: function(item, index) {
|
||||
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) {
|
||||
let f = this.PairEquip.find(function(v) {
|
||||
return v.deviceId == item.deviceId;
|
||||
@ -206,114 +214,56 @@
|
||||
}
|
||||
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() {
|
||||
this.Status.BottomMenu.show = true;
|
||||
},
|
||||
gotoSetting: function() {
|
||||
this.Status.BottomMenu.show = false;
|
||||
ble.showBluetoothGuide(false);
|
||||
ble.showBlueSetting(false);
|
||||
},
|
||||
Link: function(item, index) {
|
||||
var these = this;
|
||||
if (process.env.UNI_PLATFORM == 'mp-weixin' ||
|
||||
process.env.UNI_PLATFORM == 'mp-alipay' ||
|
||||
process.env.UNI_PLATFORM == 'app-plus' ||
|
||||
process.env.UNI_PLATFORM == 'app'
|
||||
) {
|
||||
|
||||
uni.showLoading({
|
||||
title: "正在连接",
|
||||
mask: true
|
||||
});
|
||||
setTimeout(() => {
|
||||
|
||||
|
||||
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();
|
||||
|
||||
showLoading(this,{
|
||||
text: "正在连接"
|
||||
});
|
||||
setTimeout(() => {
|
||||
let serviceid=null;
|
||||
if(item.advertisServiceUUIDs.length>0){
|
||||
serviceid=item.advertisServiceUUIDs[0];
|
||||
}
|
||||
ble.LinkBlue(item.deviceId,serviceid).then((res) => {
|
||||
let c = these.PairEquip.find(function(v) {
|
||||
return v.deviceId == item.deviceId;
|
||||
});
|
||||
}, 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 {
|
||||
color: #ffffffde;
|
||||
font-family: PingFang SC;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
@ -516,7 +466,7 @@
|
||||
|
||||
.list .item .name {
|
||||
color: #ffffffde;
|
||||
font-family: PingFang SC;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 26rpx;
|
||||
font-weight: 400;
|
||||
line-height: 50rpx;
|
||||
@ -525,7 +475,7 @@
|
||||
|
||||
.list .item .id {
|
||||
color: #ffffff99;
|
||||
font-family: PingFang SC;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
line-height: 30rpx;
|
||||
@ -547,7 +497,7 @@
|
||||
|
||||
.openBlue .txt {
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
font-family: PingFang SC;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.14rpx;
|
||||
@ -572,7 +522,7 @@
|
||||
width: 25%;
|
||||
height: 60rpx;
|
||||
text-align: center;
|
||||
font-family: PingFang SC;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 28rpx;
|
||||
letter-spacing: 12rpx;
|
||||
display: flex !important;
|
||||
@ -584,10 +534,12 @@
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.openBlue .cancel {
|
||||
border: 1px solid rgba(255, 255, 255, 1);
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
.openBlue .ok {
|
||||
background-color: #BBE600;
|
||||
color: #232323;
|
||||
|
@ -60,7 +60,7 @@
|
||||
data() {
|
||||
return {
|
||||
showView: false,
|
||||
phone: '13800138002', //手机号码
|
||||
phone: '17671332251', //手机号码
|
||||
code: "123456", //验证码
|
||||
agreed: false,
|
||||
isCounting: false,
|
||||
@ -69,6 +69,29 @@
|
||||
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: {
|
||||
// 获取验证码
|
||||
async getPhoneCode() {
|
||||
@ -158,6 +181,7 @@
|
||||
uni.hideLoading()
|
||||
uni.setStorageSync('token', res.data.access_token) // 缓存token
|
||||
uni.setStorageSync('clientID', res.data.client_id) // 缓存token
|
||||
uni.setStorageSync('tokenTime',new Date().getTime()+86400000);//过期时间
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
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 |
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];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -119,7 +119,7 @@ import Paho from 'paho-mqtt';
|
||||
import allConfigs from '../config/index.js';
|
||||
|
||||
// 根据环境选择正确的配置
|
||||
const env = 'production'; //production //开发of线上 改这里就行
|
||||
const env = 'development'; //production //开发of线上 改这里就行
|
||||
const config = allConfigs[env];
|
||||
|
||||
class MqttClient {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import config from '../config/index.js';
|
||||
const env = 'production'; //production development //开发of线上 改这里就行
|
||||
const env = 'development'; //production development //开发of线上 改这里就行
|
||||
const BASE = config[env];
|
||||
const request = (options) => {
|
||||
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
|
||||
};
|