ReedawFoodApp/components/foodIndex/bluetooth.vue

512 lines
12 KiB
Vue

<template>
<view class="weightPages">
<view class="table">
<view class="texttip">
<image src="/static/zhong.png"></image>
<text @click="openBluetoothAdapter">{{bleTipsText}}</text>
</view>
<view class="duan" @click="handleBack" v-if="isShow&&isConnection == 2">
断开连接
</view>
</view>
<view class="name">{{name}}</view>
<!-- 蓝牙称重 -->
<view class="weight-wrap">
<view class="weight" @click="inputDialogToggle">
<text class="val">{{weight == '' ? '0.0':weight}}</text>
<text class="unit">{{unit}}</text>
</view>
<view class="weight">
<text class="val">{{kcal?kcal:0}}</text>
<text class="unit">kcal</text>
</view>
</view>
<view class="groupbtn">
<view class="btn danwei">
<view class="lan border-bottom">
<view class="right">
<picker mode="selector" :range="unitA" @change="changleUnits" :value="unitListIndex">
<view class="uni-input">
单位
</view>
</picker>
</view>
</view>
</view>
<view class="btn" @click="handleDetailSub" :style="{'width':!stopblue?'20%':'45%'}">保存</view>
<view class="btn" @click="handleDetailNext" v-if="!stopblue">下一味</view>
<view class="btn qingling" @click="handleqingling">清零</view>
</view>
<view>
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog mode="input" title="重量" placeholder="请输入食物重量" @close="close"
@confirm="confirm"></uni-popup-dialog>
</uni-popup>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
kcal: "",
unit: 'g',
deviceId: "",
serviceId: "",
notify: "",
write: "",
unitA: [],
stopblue: false,
unitListIndex: 0,
}
},
props: {
weightKcal: {
type: Number,
default: 0 //当前测量食物每g含的kcal
},
isLast: {
type: Boolean,
default: false
},
name: {
type: String,
default: ''
}
},
computed: {
...mapState(["user", "bleValue", "countFoodInfo"]),
weight() {
let weightNew = this.$ble.convertToGrams(this.bleValue.foodWeight, this.bleValue.foodUnit)
this.kcal = (Number(this.weightKcal) * weightNew).toFixed(1)
this.unit = this.bleValue.foodUnit
return this.bleValue.foodWeight
},
isConnection() {
return this.bleValue.isConnectStatus
},
isShow() {
return this.bleValue.serviceId != '' ? true : false
},
bleTipsText() {
return this.bleValue.bleTipsText
},
// unitA() {
// let that = this
// that.unitListIndex = that.bleValue.unitList.findIndex(ite => ite.unit == that.bleValue.foodUnit)
// return that.bleValue.unitList
// }
},
watch: {
bleValue: {
handler(newVal, oldVal) {
let that = this
if (!newVal.isBluetoothTyle) {
that.handleBack()
}
if (newVal.serviceId) {
that.deviceId = newVal.deviceId
that.serviceId = newVal.serviceId
that.getBLEDeviceCharacteristics()
}
that.unitA = newVal.unitList
that.unitListIndex = newVal.unitList.findIndex(ite => ite.unit == newVal.foodUnit)
},
deep: true,
immediate: true
},
isLast: {
handler(newVal, oldVal) {
this.stopblue = newVal
},
immediate: true
},
},
methods: {
// 初始化蓝牙
openBluetoothAdapter() {
let that = this
if (that.isConnection != 1) return
that.kcal = ""
that.$store.commit('changeBluetoothValue', {
bleTipsText: "蓝牙搜索中",
isConnectStatus: 0,
isBleLink: false,
deviceId: "",
serviceId: "",
foodNotify: "",
foodType: 1,
foodWrite: "",
foodWeight: 0,
})
that.$ble.openBluetoothAdapter()
},
/**
* 获取指定服务的特征值
*/
getBLEDeviceCharacteristics() {
let that = this
uni.getBLEDeviceCharacteristics({
deviceId: that.deviceId,
serviceId: that.serviceId,
success: res => {
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
if (item.uuid.indexOf('0000FFF2') != -1) {
that.write = item.uuid
} else if (item.uuid.indexOf('0000FFF1') != -1) {
that.notify = item.uuid
}
}
that.getBLECharacteristicValueChange()
},
fail: res => {
that.$store.commit("changeBluetoothValue", {
foodType: 1,
isConnectStatus: 1,
bleTipsText: "连接超时,点击重新连接",
})
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
getBLECharacteristicValueChange() {
let that = this
uni.notifyBLECharacteristicValueChange({
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.notify,
state: true,
success: () => {
that.$store.commit('changeBluetoothValue', {
deviceId: that.deviceId,
serviceId: that.serviceId,
foodNotify: that.notify,
foodWrite: that.write,
bleTipsText: "测量中,请将食物放到秤上",
isConnectStatus: 2
})
uni.onBLECharacteristicValueChange(function(res) {
const value = res.value
const dataView = new DataView(value)
const header = dataView.getUint8(0)
// MCU主动上报数据
if (header === 0xC7) {
const cmd = dataView.getUint8(2)
switch (cmd) {
case 0x02:
const statusByte = dataView.getUint8(4)
const isNegative = !!(statusByte & 0x80) // 最高位表示正负
const statusType = statusByte & 0x0F // 状态类型
// 组合24位重量值 (大端序)
const weightValue =
(dataView.getUint8(5) << 16) |
(dataView.getUint8(6) << 8) |
dataView.getUint8(7)
// 精度和单位
const unitByte = dataView.getUint8(8)
const precision = (unitByte & 0xF0) >> 4 // 高4位精度
const unitIndex = unitByte & 0x0F // 低4位单位
// 计算实际重量
let finalWeight = weightValue / Math.pow(10, precision)
if (isNegative) finalWeight = -finalWeight
that.$store.commit("changeBluetoothValue", {
foodWeight: finalWeight,
foodUnit: that.$json.units[unitIndex],
foodType: statusType
})
console.log('重量:' + finalWeight, "状态:" + statusType)
console.log('单位:' + that.$json.units[unitIndex])
break
case 0x03:
break
case 0x08:
const start0 = []
const value2 = that.$tools.ab2hex(value, "");
const start = that.$tools.parseUnitMask(value2.substring(8,
10), that.$json.units.slice(0, 7))
const start1 = that.$tools.parseUnitMask(value2.substring(10,
12), that.$json.units.slice(8, 10))
start.push.apply(start, start1)
if (start.length) {
that.$json.unitMinus.forEach(item => {
start.forEach(item2 => {
if (item == item2) {
start0.push(item)
}
})
})
}
that.$store.commit("changeBluetoothValue", {
unitList: start0.length ? start0 : that.$json
.unitMinus
})
console.log("22222222222222", start, start0)
break
}
}
})
},
fail: res => {
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
// 备料完成
handleDetailSub() {
let that = this
if (Number(that.weight) > 0) {
that.$emit("handleDetailSub", that.weight, that.unit, that.kcal)
} else {
that.$tools.msg("数据异常,请清零后重新测量!")
}
},
//备料下一个
handleDetailNext() {
let that = this
if (Number(that.weight) > 0) {
that.$emit("handleDetailNext", that.weight, that.unit, that.kcal)
} else {
that.$tools.msg("数据异常,请清零后重新测量!")
}
},
changleUnits(e) {
let that = this
let unit = that.unitA[e.detail.value]
console.log("danwei", that.unit, unit)
if (that.isShow && that.unit != unit) {
that.handletoggleUnit(that.$ble.unitInstruction(unit))
}
if (that.bleValue.serviceId == '') {
that.unitListIndex = [e.detail.value]
that.$store.commit('changeBluetoothValue', {
foodUnit: that.unitA[e.detail.value],
})
}
},
// 下发单位
handletoggleUnit(unit) {
let that = this
let checksum = 0;
const bytes = [0xC5, 0x03, 0x05, 0x11]
bytes[4] = unit
for (let i = 0; i < bytes.length; i++) {
checksum ^= bytes[i];
}
bytes[5] = checksum
that.sendData(new Uint8Array(bytes).buffer)
},
handleqingling() {
let that = this
let str = "C503071100D0"
let buf = new Uint8Array(str.match(/[\da-f]{2}/gi).map(function(h) {
return parseInt(h, 16)
}))
that.sendData(buf.buffer)
},
sendData(buffer) {
let that = this
uni.writeBLECharacteristicValue({
deviceId: that.bleValue.deviceId,
serviceId: that.bleValue.serviceId,
characteristicId: that.bleValue.foodWrite,
value: buffer,
success: res => {
console.log('下发指令成功', res.errMsg)
},
fail: res => {
console.log("下发指令失败", res);
},
})
},
handleBack() {
let that = this
that.unitA = that.$json.unitMinus
that.$store.commit("changeBluetoothValue", {
bleTipsText: "连接失败,点击重新连接",
unitList: that.$json.unitMinus,
isConnectStatus: 1,
foodType: 1
})
that.$ble.stopBluetoothDevicesDiscovery() //取消蓝牙搜索
that.$ble.closeBLEConnection(that.deviceId)
that.$ble.closeBluetoothAdapter()
},
confirm(value) {
console.log(value)
let that = this
that.$store.commit("changeBluetoothValue", {
foodWeight: value,
foodUnit: that.$json.unitMinus[that.unitListIndex]
})
that.$refs.popup.close()
},
close() {
this.$refs.popup.close()
},
inputDialogToggle() {
this.$refs.popup.open()
},
},
}
</script>
<style scoped lang="scss">
.table {
width: 100%;
font-size: 14px;
align-items: center;
padding: 5px 0;
border-radius: 5px;
display: flex;
justify-content: space-between;
.texttip {
color: #8284f0;
display: flex;
image {
width: 22px;
height: 22px;
margin-right: 5px;
}
}
}
.weightPages {
position: absolute;
left: 15px;
right: 15px;
bottom: 30rpx;
top: 15px;
display: flex;
flex-direction: column;
justify-content: space-between;
.weight {
background: #fff;
color: #666;
font-size: 16px;
flex-wrap: wrap;
text-align: center;
view {
width: 60%;
height: 100rpx;
display: flex;
margin-left: 25%;
align-items: flex-end;
margin-bottom: 30rpx;
text {
width: 80px;
display: inline-block;
border-bottom: 1px solid #dfdfdf;
margin: 0 20rpx;
font-size: 18px;
font-weight: bold;
color: #f0ae43;
}
}
}
.tips {
font-size: 24rpx;
text-align: center;
}
.groupbtn {
margin-top: 0;
display: flex;
align-items: center;
justify-content: space-between;
.btn {
width: 20%;
color: $maincolor;
text-align: center;
height: 40px;
line-height: 40px;
border-radius: 10px;
border: 1px solid $maincolor;
background: #fff;
margin: 0;
view {
border: none !important;
width: auto !important;
height: 40px !important;
line-height: 40px !important;
}
}
}
.weight-wrap {
display: flex;
justify-content: space-around;
align-items: center;
color: #666;
font-size: 16px;
text-align: center;
height: 60px;
border-radius: 10px;
.weight {
display: flex;
justify-content: center;
align-items: center;
width: 48%;
padding: 30rpx 0;
border-radius: 20rpx;
background-color: #F8F8F8;
.val {
font-size: 54rpx;
color: #F0AE43;
margin: 0 !important;
}
.unit {
padding: 10rpx;
margin-left: 20rpx;
font-size: 28rpx;
color: #fff;
border-radius: 8rpx;
background-color: #F0AE43;
}
}
}
.duan {
width: fit-content;
background: linear-gradient(-90deg, #d4f5c4, #a7d5e4 80%, );
border-radius: 5px;
text-align: center;
padding: 3px 10px;
font-size: 12px;
}
.name {
width: 100%;
text-align: center;
font-size: 16px;
font-weight: bold;
}
}
</style>