1
0
forked from dyf/APP
Files
APP/pages/650/HBY650.vue
2025-07-29 09:34:15 +08:00

1813 lines
42 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="content contentBg">
<view class="eq">
<view class="leftImg">
<image class="img" src="/static/images/6155/DeviceDetail/Hby650.png" mode="aspectFit"></image>
</view>
<view class="rightTxt">
<view class="row">
<image class="img" src="/static/images/6155/DeviceDetail/battry.png" mode="aspectFit"></image>
<view class="txt">
<view class="bigTxt">{{formData.battary}}%</view>
<view class="smallTxt">电量</view>
</view>
</view>
<view class="row">
<image class="img" src="/static/images/6155/DeviceDetail/time.png" mode="aspectFit"></image>
<view class="txt">
<view class="bigTxt">{{formData.xuhang}}</view>
<view class="smallTxt">续航时间</view>
</view>
</view>
</view>
</view>
<view class="eqinfo">
<view class="item">
<text class="lbl">蓝牙名称</text>
<text class="value">{{formData.name}}</text>
</view>
<view class="item">
<text class="lbl">照明档位</text>
<text class="value">{{formData.RSSI}}</text>
</view>
<view class="item">
<text class="lbl">探测档位</text>
<text class="value">{{formData.statu}}</text>
</view>
</view>
<!-- <view class="lamp">
<view class="title">
<text>灯光亮度</text>
<text>{{formData.liangDu}}%</text>
</view>
<view class="slider-container">
<slider min="1" max="100" step="1" :disabled="false" :value="formData.liangDu" activeColor="#bbe600"
backgroundColor="#00000000" block-size="20" block-color="#ffffffde" @change="sliderChange"
@changing="sliderChange" class="custom-slider" />
</view>
</view> -->
<view class="modeSetting">
<view class="item" :class="Status.modeCurr=='low'?'active':''"
@click="MainModeSetting('low','staticBattery')">
<view class="p100 center">低档</view>
</view>
<view class="item " :class="Status.modeCurr=='center'?'active':''"
@click="MainModeSetting('center','staticBattery')">
<view class="p100 center">中档</view>
</view>
<view class="item " :class="Status.modeCurr=='hight'?'active':''"
@click="MainModeSetting('hight','staticBattery')">
<view class="p100 center">高档</view>
</view>
<view class="item " :class="Status.modeCurr=='close'?'active':''"
@click="MainModeSetting('close','staticBattery')">
<view class="p100 center">关闭</view>
</view>
</view>
<view class="lampMode">
<view class="mode fleft" :class="Status.cMode?'active':''" v-on:click.stop="LampToggle()">
<view class="leftImg">
<image class="img" src="/static/images/6155/DeviceDetail/mainLamp.png" mode="aspectFit"></image>
</view>
<view class="rightTxt">
<text class="bigTxt">照明模式</text>
</view>
</view>
<view class="mode marginLeft fleft" :class="Status.cMode=='mode'?'':'active'"
v-on:click.stop="UploadOpenImg()">
<view class="leftImg">
<image class="img" src="/static/images/6155/DeviceDetail/open.png" mode="aspectFit"></image>
</view>
<view class="rightTxt">
<text class="bigTxt">开机画面</text>
<text class="smallTxt">上传</text>
</view>
</view>
<view class="clear"></view>
</view>
<view class="usrinfo">
<view @click="Status.usrToggle=!Status.usrToggle">
<text class="usrtitle fleft">人员信息登记</text>
<view class="image fright" :style="{transform:Status.usrToggle?'rotate(0deg)':'rotate(180deg)' }">
<image class="img" src="/static/images/6155/DeviceDetail/slideToggle.png" mode="aspectFit"></image>
</view>
<view class="clear"></view>
</view>
<view :class="Status.usrToggle?'':'displayNone'">
<view style="margin: 20rpx 0rpx;">
<view class="btnSend fright" v-on:click.stop="sendUsr">发送</view>
<view class="clear"></view>
</view>
<view class="item">
<text class="lbl">单位</text>
<input class="value" v-model="user.company" placeholder="请输入单位" placeholder-class="usrplace" />
</view>
<view class="item">
<text class="lbl">姓名</text>
<input class="value" v-model="user.name" placeholder="请输入姓名" placeholder-class="usrplace" />
</view>
<view class="item">
<text class="lbl">职位</text>
<input class="value" v-model="user.job" placeholder="请输入职位" placeholder-class="usrplace" />
</view>
<view class="item">
<text class="lbl">ID号</text>
<input class="value" v-model="user.id" placeholder="请输入ID" placeholder-class="usrplace" />
</view>
</view>
</view>
<view class="proinfo lamp">
<text class="title">产品信息</text>
<view class="itemcontent">
<view class="item" @click="proParam()">
<image class="img" src="/static/images/6155/DeviceDetail/param.png" mode="aspectFit"></image>
<text class="txt">产品参数</text>
</view>
<view class="item" @click="handRemark()">
<image class="img" src="/static/images/6155/DeviceDetail/remark.png" mode="aspectFit"></image>
<text class="txt">操作说明</text>
</view>
<view class="item" @click="handVideo()">
<image class="img" src="/static/images/6155/DeviceDetail/video.png" mode="aspectFit"></image>
<text class="txt">操作视频</text>
</view>
</view>
</view>
<!-- 弹窗通知 -->
<MessagePopup :visible="Status.Pop.showPop" :type="Status.Pop.popType" :bgColor="Status.Pop.bgColor"
:borderColor="Status.Pop.borderColor" :textColor="Status.Pop.textColor"
:buttonBgColor="Status.Pop.buttonBgColor" :buttonTextColor="Status.Pop.buttonTextColor"
:iconUrl="Status.Pop.iconUrl" :message="Status.Pop.message" :buttonText="Status.Pop.buttonText"
@buttonClick="HidePop" :visiblePrompt="Status.Pop.visiblePrompt" :promptTitle="Status.Pop.promptTitle"
v-model="Status.Pop.modelValue" />
<!-- 下方菜单 -->
<BottomSlideMenuPlus :config="Status.BottomMenu" @close="closeMenu" @itemClick="handleItemClick"
@btnClick="btnClick">
<view class="addIco">
<view class="icoContent center" v-on:click.stop="checkImgUpload()">
<image mode="aspectFit" class="img" src="/static/images/6155/DeviceDetail/add.png"></image>
</view>
</view>
</BottomSlideMenuPlus>
<Progress :config="Status.Progress"></Progress>
</view>
</template>
<script>
import gbk from '@/utils/gbk.js'
import ble from '@/api/6155/BlueHelper';
export default {
data() {
return {
Status: {
cMode: false,
modeCurr: 'low',
usrToggle: true,
Pop: {
showPop: false, //是否显示弹窗
popType: 'custom',
bgColor: '#383934bd',
borderColor: '#BBE600',
textColor: '#ffffffde',
buttonBgColor: '#BBE600',
buttonTextColor: '#232323DE',
iconUrl: '',
message: '您确定要这样做吗?',
buttonText: '确定',
clickEvt: '',
visiblePrompt: false,
promptTitle: '设备名称',
modelValue: '',
visibleClose: false
},
BottomMenu: {
show: false,
showHeader: true,
menuItems: [{
text: '强光',
icon: '/static/images/6155/DeviceDetail/qiang.png'
},
{
text: '弱光',
icon: '/static/images/6155/DeviceDetail/ruo.png'
},
{
text: '爆闪',
icon: '/static/images/6155/DeviceDetail/shan.png'
}
],
activeIndex: -1,
bgColor: '#2a2a2a',
itemBgColor: '#3a3a3a',
textColor: '#ffffffde',
textAlign: 'flex-start',
title: '主灯模式',
showDivider: false,
dividerColor: '#00000000',
dividerThickness: '0rpx',
dividerMargin: '10rpx',
itemHeight: '80rpx',
type: '',
showBtn: true,
btnBgColor: "#bbe600",
btnText: "确定",
btnTextColor: "#232323de",
showMask: true,
maskBgColor: '#00000066',
showClose: false
},
Progress: {
show: false, //是否显示
height: '20rpx',
showMask: true, //是否显示mask
maskBgColor: '#00000000', //mask背景颜色
contentBgColor: '#121212', //总背景颜色
showText: true, //是否显示当前进度的文字
txtColor: '#ffffffde', //文字的颜色
curr: 20, //当前进度
total: 100, //总进度
proBgColor: '#2a2a2a', //进度条底色,
proBorder: '', //进度条border
currBgColor: '#bbe600', //当前进度底色
currBorder: '', //当前进度border
borderRadius: '10rpx'
}
},
formData: {
img: '/static/images/6155/DeviceDetail/equip.png',
battary: '',
xuhang: '1',
name: 'JQZM-EF4651',
RSSI: '-30',
statu: '运行中',
liangDu: '50'
},
cEdit: {
mode: ''
},
user: {
company: '黄石消防支队',
name: '菜英俊',
job: '小队长',
id: 'HSXF01061'
},
device: {
deviceId: '',
writeServiceId: '',
wirteCharactId: '',
notifyServiceid:'',
notifyCharactId:''
},
videoHexArray: []
}
},
onLoad: function() {
var these = this;
let eventChannel = this.getOpenerEventChannel();
//eventChannel.on('receivdata', function(data) {
let data = {
data: {
deviceMac: '35:06:00:EF:46:51',
bluetoothName: 'JQZM-EF4651',
deviceName: 'JQZM-EF4651',
devicePic: '',
id: '35:06:00:EF:46:51'
}
};
console.log("收到父页面的参数:" + JSON.stringify(data));
var device = data.data;
these.device.deviceId = device.deviceMac;
these.formData.name = device.bluetoothName ? device.bluetoothName : device.deviceName;
these.formData.img = device.devicePic;
these.formData.id = device.id;
//});
ble.featrueValueCallback = these.bleValueNotify;
ble.OpenBlue(true, () => {
ble.StartSearch((res) => {
let f = res.devices.find((v) => {
return v.name == 'JQZM-EF4651';
});
if (f) {
ble.StopSearch();
these.device.deviceId = f.deviceId;
these.formData.id = f.deviceId;
ble.LinkBlue(f.deviceId);
}
})
})
},
onHide: function() {
},
onBackPress(e) {
var these = this;
console.log("these.device=" + JSON.stringify(these.device));
if (these.device.deviceId) {
if (e.from === 'backbutton') {
these.getLinkBlue((res) => {
if (res.devices.length == 0) {
console.log("没有已连接的蓝牙设备")
uni.navigateBack();
return;
}
let f = res.devices.find(function(v) {
return v.deviceId == these.device.deviceId;
});
if (!f) {
console.log("该设备没有连接")
uni.navigateBack();
return;
}
uni.showModal({
title: '提示',
content: '是否断开与设备的蓝牙连接?',
success: function(res) {
if (res.confirm) {
ble.disconnectDevice(these.device.deviceId);
}
uni.navigateBack();
}
});
});
return true;
}
}
return false;
},
computed: {
RSSIRemark: function() {
let remark = '极弱';
if (this.formData.RSSI <= 0 && this.formData.RSSI >= -30) {
remark = '强';
}
if (this.formData.RSSI < -30 && this.formData.RSSI >= -60) {
remark = '一般';
}
if (this.formData.RSSI < -60 && this.formData.RSSI >= -85) {
remark = '弱';
}
if (this.formData.RSSI < -85 && this.formData.RSSI >= -100) {
remark = '微弱';
}
}
},
methods: {
bleValueNotify: function(receive) { //订阅消息
var these = this;
var bytesToHexString =
function(bytes) {
return bytes.map(
byte =>
byte
.toString(
16)
.padStart(
2, '0')
).join(' ');
}
var parseData = (
bytes) => {
if (bytes.length < 6) {
console.warn('数据包长度不足至少需要6个字节');
return;
}
try {
// 跳过帧头(第一个字节),从第二个字节开始解析
const staticLevelByte = bytes[1];
let staticLevelText = '未知';
let modeCurr = '';
switch (staticLevelByte) {
case 0x65:
staticLevelText = '高档';
modeCurr = 'hight';
break;
case 0x66:
staticLevelText = '中档';
modeCurr = 'center';
break;
case 0x67:
staticLevelText = '低档';
modeCurr = 'low';
break;
case 0x68:
staticLevelText = '关闭';
modeCurr = 'close';
break;
}
// 解析照明档位
const lightingLevelByte = bytes[2];
const lightingLevelText = lightingLevelByte === 0x6e ? '开启' : '关闭';
// 解析剩余照明时间(第三和第四字节,小端序)
const lightingTime = (bytes[4] << 8) | bytes[3];
// 解析剩余电量
const batteryLevelByte = bytes[5];
// 电量百分比范围检查
const batteryLevel = Math.max(0, Math.min(100, batteryLevelByte));
console.log('解析结果:', {
staticLevel: staticLevelText,
lightingLevel: lightingLevelText,
lightingTime: `${lightingTime} 分钟`,
batteryLevel: `${batteryLevel}%`
});
let hours = Math.floor(lightingTime / 60);
let remainingMinutes = lightingTime % 60;
let xuhang = '0分';
// 处理不同情况的显示
if (hours === 0) {
xuhang = `${remainingMinutes}`;
} else if (remainingMinutes === 0) {
xuhang = `${hours}小时`;
} else {
xuhang = `${hours}小时${remainingMinutes}`;
}
these.formData.battary = batteryLevel;
these.formData.xuhang = xuhang;
these.Status.cMode = lightingLevelByte === 0x6e;
these.Status.modeCurr = modeCurr;
console.log("curr=", {
battary: batteryLevel,
xuhang: xuhang,
cMode: these.Status.cMode,
modeCurr: modeCurr
});
} catch (error) {
console.error('数据解析错误:', error);
}
}
const dataView =
new DataView(receive
.value);
// 转换为字节数组
const bytes = [];
for (let i = 0; i <
dataView
.byteLength; i++) {
bytes.push(dataView
.getUint8(i));
}
// 保存原始数据用于调试
this.receivedData = bytes;
console.log('接收到原始数据:',
bytesToHexString(
bytes));
parseData(bytes);
},
getDevice: function() {
var these = this;
if (this.device.deviceId && this.device.writeServiceId && this.device.wirteCharactId) {
return this.device;
}
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) {
if(v.deviceId == these.device.deviceId){
these.device.writeServiceId=v.writeServiceId;
these.device.wirteCharactId=v.wirteCharactId;
these.device.notifyServiceid=v.notifyServiceid;
these.device.notifyCharactId=v.notifyCharactId;
return true;
}
return false;
});
} else {
f = null;
}
return f;
},
MainModeSetting: function(type, byteType) {
if (this.Status.modeCurr == type) {
return;
}
this.Status.modeCurr = type;
let dataValue = 0x00;
let btype = 0x00;
switch (type) {
case "low": //低档
dataValue = 0x67;
break;
case "center": //中档
dataValue = 0x66;
break;
case "hight": //高档
dataValue = 0x65;
break;
case "close": //关闭
dataValue = 0x68;
break;
case true: //开灯
dataValue = 0x6E;
break;
case false: //关灯
dataValue = 0x6F;
break;
default: //未知
dataValue = 0x00;
break;
}
switch (byteType) {
case "staticBattery":
btype = 0x00;
break;
case "lamp":
btype = 0x01;
break;
default:
break;
}
let buffer = new ArrayBuffer(6);
let dataView = new DataView(buffer);
dataView.setUint8(0, 0x55); // 帧头
dataView.setUint8(1, btype); // 帧类型
dataView.setUint8(2, 0x01); // 包序号
dataView.setUint8(3, 0x00); // 数据长度
dataView.setUint8(4, 0x01); // 数据长度
dataView.setUint8(5, dataValue); // 数据
let f = this.getDevice();
if (f) {
// 发送数据
ble.LinkBlue(f.deviceId, (id, flag) => {
setTimeout(() => {
ble.sendDataNew(f.deviceId, f.writeServiceId, f.wirteCharactId, buffer);
}, flag ? 0 : 1000);
});
}
},
LampToggle: function() {
this.Status.cMode = !this.Status.cMode;
this.MainModeSetting(this.Status.cMode, "lamp");
},
proParam: function() {
uni.navigateTo({
url: '/pages/common/productDes/index?id=' + this.device.deviceId,
success(ev) {
},
fail() {
uni.showToast({
title: '敬请期待'
})
}
});
},
handRemark: function() {
uni.navigateTo({
url: '/pages/common/operatingInstruct/index?id=' + this.device.deviceId,
success(ev) {
},
fail() {
uni.showToast({
title: '敬请期待'
})
}
});
},
handVideo: function() {
uni.navigateTo({
url: '/pages/common/operationVideo/index?id=' + this.device.deviceId,
success(ev) {
},
fail() {
uni.showToast({
title: '敬请期待'
})
}
});
},
checkImgUpload: function() {
console.log("123213213213");
var these = this;
// 处理像素数据并发送
var processAndSendImageData = function(pixels) {
return new Promise((resolve, reject) => {
// 创建RGB565格式的像素数据
const rgb565Data = convertToRGB565(pixels);
// 分包发送
sendImagePackets(rgb565Data).then(resolve).catch(reject);
});
}
// 将RGBA转换为RGB565
var convertToRGB565 = function(pixels) {
var rgbaToRgb565 = function(r, g, b, a = 255) {
// 忽略透明度(如果需要考虑透明度,请根据需求处理)
// 将8位颜色值压缩到RGB565对应的位数
const r5 = Math.round((r / 255) * 31); // 5位0-31
const g6 = Math.round((g / 255) * 63); // 6位0-63
const b5 = Math.round((b / 255) * 31); // 5位0-31
// 合并为16位整数
return (r5 << 11) | (g6 << 5) | b5;
}
const result = new Uint16Array(160 * 80);
let index = 0;
console.log("pixels.length=" + pixels.length);
for (let i = 0; i < pixels.length; i += 4) {
const r = pixels[i];
const g = pixels[i + 1];
const b = pixels[i + 2];
// 转换为RGB565 (R:5bit, G:6bit, B:5bit)
const rgb565 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
//let rgb565=rgbaToRgb565(r,g,b);
result[index++] = rgb565;
}
return result;
}
// 分包发送图片数据
var sendImagePackets = function(imageData) {
return new Promise((resolve, reject) => {
// this.isSending = true;
// this.progress = 0;
// this.currentPacket = 0;
// 总数据包数
const totalPackets = 52;
let currentPacket = 1;
let f = these.getDevice();
if (f) {
// 发送单个数据包
const sendNextPacket = () => {
if (currentPacket > totalPackets) {
uni.hideLoading();
these.Status.BottomMenu.show = false;
these.Status.Progress.show = false;
these.Status.Pop.showPop = true;
these.Status.Pop.message = "上传成功";
these.Status.Pop.iconUrl =
"/static/images/6155/DeviceDetail/uploadSuccess.png";
resolve();
return;
}
// 计算当前包的数据
let packetSize = 250;
if (currentPacket <= 51) {
packetSize = 250; // 前51个包每个500字节
} else {
packetSize = 50; // 最后一个包100字节
}
// 创建数据包
const startIndex = (currentPacket - 1) * packetSize;
const endIndex = Math.min(startIndex + packetSize, imageData
.length);
if (startIndex > endIndex) {
return;
}
const packetData = imageData.slice(startIndex,
endIndex); // imageData.subarray(startIndex, endIndex);
console.log("imageData.length=" + imageData.length +
",startIndex=" +
startIndex +
",endIndex=" + endIndex + ",数据包长度" + (endIndex -
startIndex) +
',packetData.length=' + packetData.length);
// 构建数据包
const bufferSize = 5 + packetData.length * 2; // 头部5字节 + 数据部分
const buffer = new ArrayBuffer(bufferSize);
const dataView = new DataView(buffer);
// 填充头部
dataView.setUint8(0, 0x55); // 帧头
dataView.setUint8(1, 0x02); // 帧类型:开机画面
dataView.setUint8(2, '0x' + currentPacket.toString(16).padStart(2,
'0')); // 包序号
// if(packetData.length==250)
// {
// dataView.setUint8(3, 0x01);
// dataView.setUint8(4, 0xFF);
// }
if (packetData.length == 250) {
dataView.setUint8(3, 0x01);
dataView.setUint8(4, 0xF4);
} else {
dataView.setUint8(3, 0x00);
dataView.setUint8(4, 0x64);
}
// 填充数据每个RGB565值占2字节
for (let i = 0; i < packetData.length; i++) {
dataView.setUint16(5 + i * 2, packetData[i], false); // 大端字节序
}
console.log(
`发送数据包${currentPacket}/${totalPackets},${dataView.getUint8(0)} ${dataView.getUint8(1)} ${dataView.getUint8(2)}`
)
//发送数据包
ble.sendDataNew(f.deviceId, f.writeServiceId, f.wirteCharactId,
buffer).then(() => {
these.Status.Progress.curr = currentPacket;
currentPacket++;
setTimeout(sendNextPacket, 40);
}).catch(err => {
console.log("发送数据包失败了" + JSON.stringify(err));
if(err.code=='10007'){
setTimeout(sendNextPacket, 40);
return;
}
these.Status.BottomMenu.show = false;
these.Status.Progress.show = false;
these.alert("发送数据包失败了");
uni.hideLoading();
reject(err);
});
}
// 开始牵手
these.HoldYouHand("picture transmit start", 120, f.deviceId, f.writeServiceId,f.wirteCharactId).then(() => {
sendNextPacket();
}).catch((err) => {
console.log("握手没有成功");
reject(err);
});
}
});
}
//去图片裁剪
var gotoCutImg = (imgPath) => {
uni.navigateTo({
url: "/pages/6155/ImgCrop",
events: {
ImgCutOver: function(data) {
console.log("我收到裁剪后的图片了,感谢老铁," + data)
uni.showLoading({
title: "正在发送..."
});
these.Status.Progress.show = true;
these.Status.Progress.curr = 0;
these.Status.Progress.total = 52;
these.Status.BottomMenu.show = false;
setTimeout(function() {
processAndSendImageData(data).catch(() => {
});
}, 0)
}
},
success(ev) {
ev.eventChannel.emit('checkImg', {
data: imgPath
});
}
});
}
var sendVideo = (videoPath) => {
let uploadVideo = () => {
if (these.videoHexArray.length > 0) {
console.log("开始处理,无需上传");
shotVideoClick(these.videoHexArray);
return;
}
console.log("开始处理,正在上传");
let f = this.getDevice();
uni.showLoading({
title: "上传中"
});
let p1 = these.HoldYouHand("video transmit start", 2200, f.deviceId, f.writeServiceId,f.wirteCharactId);
let p2 = new Promise((succ, err) => {
uni.uploadFile({
url: 'http://114.55.111.217/video/upload',
filePath: 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();
err(ex);
},
success: (res) => {
uni.hideLoading();
console.log("上传完成,向蓝牙设备发送");
succ(res);
}
});
});
Promise.all([p1, p2]).then((arr) => {
let res = arr[1];
res = JSON.parse(res.data);
if (res.data) {
these.videoHexArray = res.data;
these.Status.Progress.show = true;
these.Status.Progress.curr = 0;
these.Status.Progress.total = 1536;
these.Status.BottomMenu.show = false;
setTimeout(() => {
shotVideoClick(res.data);
}, 0)
} else {
console.log("服务器未返回正确的数据");
uni.showToast({
title: "与服务器连接出现异常",
icon: 'fail'
})
}
}).catch((ex) => {
uni.showModal({
title: "提示",
content: "出现异常"
});
})
}
let f = these.getDevice();
console.log("f=", f);
let sendVideoPackets = (imageData) => {
console.log("开始发送分片数据");
return new Promise((resolve, reject) => {
if (f) {
// 总数据包数
const totalPackets = 1536;
this.totalPackets = totalPackets;
let currentPacket = 1;
console.log("发送数据准备中,总共" + totalPackets);
// 发送单个数据包
const sendNextVideoPacket = () => {
////console.log("currentPacket="+currentPacket+",imageData.length="+imageData.length);
if (currentPacket > totalPackets) {
these.Status.BottomMenu.show = false;
these.Status.Progress.show = false;
these.Status.Pop.showPop = true;
these.Status.Pop.message = "上传成功";
these.videoHexArray = [];
these.Status.Pop.iconUrl =
"/static/images/6155/DeviceDetail/uploadSuccess.png";
resolve();
return;
}
// 计算当前包的数据
let 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);
for (let i = 0; i < packetData.length; i++) {
dataView.setUint8(6 + i, '0x' + packetData[i]);
}
let inteval = 50;
ble.sendDataNew(f.deviceId, f.writeServiceId, f.wirteCharactId,
buffer).then(() => {
these.Status.Progress.curr = currentPacket;
currentPacket++;
setTimeout(sendNextVideoPacket, inteval);
}).catch(err => {
console.log(err.errMsg + ",发送失败了,正在补偿:" +
currentPacket);
setTimeout(sendNextVideoPacket, inteval);
});
};
sendNextVideoPacket();
} else {
console.log("Fail.......")
}
});
}
let shotVideoClick = (array) => {
console.log("正在开始发送");
sendVideoPackets(array).then(() => {
console.log("发送完成");
}).catch((ex1) => {
//console.log("出现了异常", ex1)
}).finally(() => {
uni.hideLoading();
});
}
uploadVideo();
}
uni.chooseMedia({
count: 1,
mediaType: ['image', 'video'],
sourceType: ['album'],
maxDuration: 3,
sizeType: ['original'],
success: (res) => {
let file = res.tempFiles[0];
if (file.fileType == 'image') {
gotoCutImg(file.tempFilePath);
return;
}
if (file.fileType == 'video') {
if (file.duration < 2) {
this.alert('提示', "请选择2S及以上的视频");
return;
}
these.videoHexArray = [];
sendVideo(file.tempFilePath);
return;
}
}
});
// uni.chooseImage({
// count: 1,
// sizeType: ['original', 'compressed'],
// sourceType: ['album'],
// success: function(res) {
// gotoCutImg(res.tempFiles[0].path);
// }
// });
},
UploadOpenImg: function() {
//上传开机画面
this.Status.BottomMenu.menuItems = [];
this.Status.BottomMenu.title = "上传开机画面";
this.Status.BottomMenu.type = "checkImg";
this.Status.BottomMenu.show = true;
this.Status.cMode = "img";
},
showMenu(flag) {
this.Status.BottomMenu.show = true;
},
closeMenu() {
this.Status.BottomMenu.show = false;
},
btnClick(item, index) {
},
setMode(mode) {
},
handleItemClick(item, index) {
switch (this.Status.BottomMenu.type) {
case "main":
break;
case "fu":
break;
}
this.Status.BottomMenu.activeIndex = index;
},
HidePop: function() {
if (this.Status.Pop.clickEvt == 'SendUsr') {
}
this.Status.Pop.showPop = false;
},
sendUsr: function() {
var these = this;
var textLines = [
this.user.company,
this.user.name,
this.user.job,
this.user.id
];
let f = this.getDevice();
var sendText = function() {
// 总数据包数
const totalPackets = textLines.length;
let currentPacket = 1;
// 发送单个数据包
const sendNextPacket = () => {
if (currentPacket > totalPackets) {
these.Status.Pop = {
showPop: true, //是否显示弹窗
popType: 'custom',
bgColor: '#383934bd',
borderColor: '#BBE600',
textColor: '#ffffffde',
buttonBgColor: '#BBE600',
buttonTextColor: '#232323DE',
iconUrl: '/static/images/6155/DeviceDetail/sendSucc.png',
message: '人员信息发送成功',
buttonText: '确定',
clickEvt: 'SendUsr',
visiblePrompt: false,
promptTitle: '',
modelValue: '',
visibleClose: true
}
return;
}
// 获取当前行文字
const text = textLines[currentPacket - 1] || '';
let arr = gbk.encode(text)
let gbkData = gbk.arr2hex(arr);
console.log(JSON.stringify(gbkData));
// 构建数据包
const bufferSize = 5 + text.length * 2; // 头部4字节 + 数据部分
const buffer = new ArrayBuffer(bufferSize);
const dataView = new DataView(buffer);
// 填充头部
dataView.setUint8(0, 0x55); // 帧头
dataView.setUint8(1, 0x03); // 帧类型:文字
dataView.setUint8(2, currentPacket.toString(16)); // 包序号
dataView.setUint16(3, (text.length * 2).toString(16)); // 数据长度
console.log("gbkData.length=" + gbkData.length)
// 填充数据
for (let i = 1; i <= text.length * 2; i++) {
const highNibble = gbkData[i * 2 - 2]; // 高4位
const lowNibble = gbkData[i * 2 - 1]; // 低4位如果是奇数长度补0
//console.log("i=" + i + "," + highNibble + lowNibble)
// 组合高低位并转换为字节值
const byteValue = parseInt(highNibble + lowNibble, 16);
dataView.setUint8(5 + i - 1, byteValue);
}
console.log("dataView.length=" + dataView.byteLength)
// 发送数据包
ble.sendDataNew(f.deviceId, f.writeServiceId, f.wirteCharactId, buffer).then(() => {
// 更新进度
console.log(
`发送文字数据包 ${currentPacket}/${totalPackets}: ${text}`
);
// 发送下一个包
currentPacket++;
setTimeout(sendNextPacket, 100);
}).catch(err => {
// this.isSendingText = false;
uni.showToast({
title: '文字发送失败',
icon: 'none'
});
});
};
// 开始发送第一个包
sendNextPacket();
}
these.HoldYouHand("word transmit start", 120, f.deviceId, f.writeServiceId, f.wirteCharactId).then(
() => {
setTimeout(sendText, 200);
}).catch((ex) => {
console.log("握手没有成功", ex);
uni.showToast({
title: '握手没有成功',
icon: 'none'
});
});
},
HoldYouHand(str, pauseTime, deviceid, serviceid, characid) {
if (!pauseTime) {
pauseTime = 0;
}
var promise = new Promise((resolve, reject) => {
// 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("开始握手");
ble.LinkBlue(deviceid, () => {
ble.sendDataNew(deviceid, serviceid, characid, buffer).then(
() => {
setTimeout(() => {
console.log("握手成功并完成了等待");
resolve(true);
}, pauseTime);
}).catch(err => {
reject(err);
});
});
});
return promise;
},
ack: function() {
var these = this;
let eventChannel = this.getOpenerEventChannel();
eventChannel.emit('ack', {
data: '我已收到了您的消息,谢谢。'
});
}
}
}
</script>
<style>
.content {
padding: 30rpx;
box-sizing: border-box;
}
.eq {
width: 100%;
height: 250rpx;
border-radius: 8px;
background: rgba(26, 26, 26, 1);
box-sizing: border-box;
padding: 24rpx 28rpx;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
margin-bottom: 24rpx;
}
.eq .leftImg {
box-sizing: border-box;
padding: 36rpx;
border-radius: 16rpx;
background: rgba(42, 42, 42, 0.5);
}
.eq .leftImg,
.eq .rightTxt {
width: 50%;
height: 100%;
}
.eq .rightTxt {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: space-evenly;
align-items: flex-start;
}
.eq .leftImg .img {
width: 100%;
height: 100%;
}
.eq .rightTxt .img {
width: 52rpx;
height: 52rpx;
}
.eq .rightTxt .row {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
padding-left: 50rpx;
}
.eq .rightTxt .row .txt {
padding-left: 20rpx;
}
.eq .bigTxt {
color: rgba(255, 255, 255, 0.87);
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
}
.eq .smallTxt {
color: rgba(255, 255, 255, 0.6);
font-family: PingFang SC;
font-size: 24rpx;
font-weight: 400;
}
.eqinfo {
border-radius: 16rpx;
background: rgba(26, 26, 26, 1);
box-sizing: border-box;
padding: 14rpx 0rpx;
}
.eqinfo .item {
width: 100%;
height: 60rpx;
line-height: 60rpx;
padding: 0rpx 28rpx;
box-sizing: border-box;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
align-items: center;
}
.eqinfo .lbl {
color: rgba(255, 255, 255, 0.87);
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
letter-spacing: 0.07px;
text-align: left;
}
.eqinfo .value {
color: rgba(255, 255, 255, 0.6);
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
letter-spacing: 0.07px;
text-align: left;
}
.lamp {
margin-top: 24rpx;
}
.lamp .title {
width: 100%;
height: 60rpx;
line-height: 60rpx;
padding: 0rpx 28rpx;
box-sizing: border-box;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
}
.lampMode {
padding: 30rpx 0rpx;
width: 100%;
box-sizing: border-box;
}
.lampMode .mode {
width: calc(calc(100% - 34rpx) / 2);
border-radius: 8px;
margin-top: 20rpx;
background: rgba(26, 26, 26, 1);
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
align-items: center;
justify-content: flex-start;
padding: 30rpx;
box-sizing: border-box;
}
.lampMode .mode.active {
border: 1px solid rgba(174, 214, 0, 1);
}
.lampMode .mode.active .bigTxt {
color: rgba(174, 214, 0, 1) !important;
}
.mode.marginLeft {
margin-left: 34rpx !important;
}
.mode .leftImg .img {
width: 70rpx;
height: 70rpx;
}
.mode .rightTxt {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: center;
align-items: flex-start;
padding-left: 20rpx;
}
.mode .bigTxt {
color: rgba(255, 255, 255, 0.87);
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
letter-spacing: 0.07px;
}
.mode .smallTxt {
color: rgba(255, 255, 255, 0.6);
font-family: PingFang SC;
font-size: 24rpx;
font-weight: 400;
letter-spacing: 0.07px;
}
.usrinfo {
border-radius: 8px;
width: 100%;
box-sizing: border-box;
padding: 24rpx 28rpx;
background: rgba(26, 26, 26, 1);
}
.usrtitle {
color: rgba(255, 255, 255, 0.87);
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
height: 40rpx;
line-height: 40rpx;
letter-spacing: 0.07px;
}
.usrinfo .btnSend {
line-height: 44rpx;
border-radius: 8px;
width: 82rpx;
height: 44rpx;
color: rgba(35, 35, 35, 0.87);
font-family: PingFang SC;
font-size: 24rpx;
font-weight: 400;
letter-spacing: 0.07px;
text-align: center;
background-color: #BBE600;
}
.usrinfo .item {
border-radius: 8px;
width: 100%;
box-sizing: border-box;
line-height: 90rpx;
height: 90rpx;
background: rgba(42, 42, 42, 1);
margin-top: 24rpx;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-start;
align-items: center;
}
.usrinfo .lbl {
width: 120rpx;
height: 100%;
padding-left: 24rpx;
box-sizing: border-box;
text-align: right;
color: rgba(255, 255, 255, 0.87);
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
letter-spacing: 0.07px;
}
.usrinfo .value {
width: calc(100% - 120rpx);
height: 100%;
font-size: 28rpx;
font-weight: 400;
letter-spacing: 0.07px;
text-align: left;
}
.usrinfo .value .uni-input-input {
color: rgba(255, 255, 255, 0.87);
font-family: PingFang SC;
}
.usrplace {
color: rgba(255, 255, 255, 0.4);
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
letter-spacing: 0.07px;
text-align: left;
}
.proinfo .itemcontent {
display: flex;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-evenly;
}
.proinfo .item {
width: 180rpx;
height: 180rpx;
box-sizing: border-box;
padding: 40rpx;
border-radius: 16rpx;
background: rgba(26, 26, 26, 1);
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
}
.proinfo .item .img {
width: 50rpx;
height: 50rpx;
}
.proinfo .item .txt {
color: rgba(255, 255, 255, 0.6);
font-family: PingFang SC;
font-size: 24rpx;
font-weight: 400;
margin-top: 20rpx;
letter-spacing: 0.07px;
text-align: left;
}
.slider-container {
padding: 0px;
}
/* .custom-slider .uni-slider-handle-wrapper {
height: 60rpx !important;
border-radius: 3px;
}
.custom-slider .uni-slider-active {
background-color: #FF6B6B !important;
}
.custom-slider .uni-slider-handle {
width: 60rpx !important;
height: 60rpx !important;
border-radius: 16rpx !important;
background-color: #FFFFFFde !important;
margin-top: -15px !important;
border: none !important;
}
.custom-slider .uni-slider-thumb {
width: 60rpx !important;
height: 60rpx !important;
border-radius: 16rpx !important;
background-color: #00000000 !important;
border: none !important;
} */
.addIco {
width: 100%;
height: 360rpx;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
align-content: center;
justify-content: center;
align-items: center;
}
.icoContent {
width: 240rpx;
height: 240rpx;
border-radius: 8rpx;
background: rgba(58, 58, 58, 1);
}
.icoContent .img {
width: 70rpx;
height: 70rpx;
}
.modeSetting {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: space-around;
align-items: center;
}
.modeSetting .item {
width: 150rpx;
height: 150rpx;
background: rgba(26, 26, 26, 1);
border-radius: 50%;
color: rgba(255, 255, 255, 0.87);
margin-top: 40rpx;
font-family: PingFang SC;
font-size: 28rpx;
font-weight: 400;
line-height: 0px;
box-sizing: border-box;
}
.modeSetting .item.active {
border: 4rpx solid rgba(174, 214, 0, 1);
background: rgba(26, 26, 26, 1);
padding: 6rpx;
color: rgba(26, 26, 26, 0.87);
}
.modeSetting .item.active .p100 {
background: rgba(174, 214, 0, 1);
border-radius: 50%;
}
.usrinfo .image {
width: 30rpx;
height: 40rpx;
}
.usrinfo .img {
width: 30rpx;
height: 40rpx;
}
.content {
box-sizing: border-box;
width: 100%;
min-height: 100vh;
height: auto;
}
.contentBg {
background-color: #121212;
color: #ffffffde;
}
.fleft {
float: left;
}
.fright {
float: right;
}
.clear {
clear: both;
}
.displayNone {
display: none !important;
}
.p100 {
width: 100%;
height: 100%;
}
.center {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
}
.centerLeft {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-start;
align-items: center;
}
</style>