|
|
@@ -17,7 +17,7 @@
|
|
|
</div>
|
|
|
<div class="md">
|
|
|
<div class="headContainer">
|
|
|
- <img src="../static/images/main/testhead.png"/>
|
|
|
+ <img :src="userHead"/>
|
|
|
</div>
|
|
|
<span class="username">
|
|
|
<em>{{username}}</em>
|
|
|
@@ -62,21 +62,21 @@
|
|
|
<ul>
|
|
|
<li>
|
|
|
<div class="center">
|
|
|
- <em>{{cal}}</em>
|
|
|
+ <em>{{cal |parseToInt}}</em>
|
|
|
<img src="../static/images/main/normal.png"/>
|
|
|
<span>卡路里</span>
|
|
|
</div>
|
|
|
</li>
|
|
|
<li>
|
|
|
<div class="center">
|
|
|
- <em>{{sportCal}}</em>
|
|
|
+ <em>{{sportCal |parseToInt}}</em>
|
|
|
<img src="../static/images/main/redfire.png"/>
|
|
|
<span>运动卡路里</span>
|
|
|
</div>
|
|
|
</li>
|
|
|
<li>
|
|
|
<div class="center">
|
|
|
- <em>{{ck}}</em>
|
|
|
+ <em>{{ck |parseToFix2}}</em>
|
|
|
<img src="../static/images/main/ck.png" class="ck"/>
|
|
|
<span>CK</span>
|
|
|
</div>
|
|
|
@@ -84,7 +84,7 @@
|
|
|
</ul>
|
|
|
</div>
|
|
|
<div class="bottom">
|
|
|
- <h5>5分钟心率趋势图</h5>
|
|
|
+ <h5>心率趋势图</h5>
|
|
|
<span>最大心率 : {{heartMax}} 平均心率 : {{heartAverage}}</span>
|
|
|
<Line-example
|
|
|
:width="screenWidth"
|
|
|
@@ -127,6 +127,7 @@
|
|
|
dataLabels: [],
|
|
|
dataDatasets: [],
|
|
|
watchText: '',
|
|
|
+ userHead: 'http://xhead.beswell.com/flyhead.png',
|
|
|
watchState: false,//false
|
|
|
bgColor: '#028FE1',
|
|
|
activeLevel: 0,
|
|
|
@@ -136,24 +137,43 @@
|
|
|
openAlert: false,//false
|
|
|
alertState: false,//false
|
|
|
watchListState: false,//false
|
|
|
- username: '王胜寒',
|
|
|
+ username: 'XXX',
|
|
|
sex: 1,
|
|
|
height: 148,
|
|
|
age: 8,
|
|
|
weight: 38,
|
|
|
- peaceHeart: 100,
|
|
|
+ peaceHeart: 70,
|
|
|
heartMax: 0,
|
|
|
heartAverage: 0,
|
|
|
cal: 0,
|
|
|
sportCal: 0,
|
|
|
ck: 0,
|
|
|
- screenWidth: document.body.clientWidth,
|
|
|
- screenHeight: parseInt(document.documentElement.clientHeight / 5),
|
|
|
+ screenWidth: parseInt(document.body.clientWidth - 10),
|
|
|
+ screenHeight: parseInt(document.documentElement.clientHeight / 3),
|
|
|
watchs: [],
|
|
|
+ begin: null,
|
|
|
+ heartLine: [],
|
|
|
+ dataLabels: [],
|
|
|
}
|
|
|
},
|
|
|
mounted() {
|
|
|
this.getBodyInfo();
|
|
|
+ // test
|
|
|
+ // this.begin = new Date('2021-02-04 16:13:01');
|
|
|
+ // this.dataLabels = ['', '', '', '', '', '', '', '', ''];
|
|
|
+ // this.heartLine = [65];
|
|
|
+ // let heartRate = 0;
|
|
|
+ // this.timer = setInterval(() => {
|
|
|
+ // heartRate = parseInt(Math.random()*100+70);
|
|
|
+ // this.heartRate = heartRate;
|
|
|
+ // this.activeState = true;
|
|
|
+ // this.watchState = true;
|
|
|
+ // this.dataLabels.push('');
|
|
|
+ // this.heartLine.push(heartRate);
|
|
|
+ // this.calcCalorie(heartRate);
|
|
|
+ // this.calcActLevel(heartRate);
|
|
|
+ // this.DrawHeartLine(this.heartLine, this.dataLabels)
|
|
|
+ // },1000);
|
|
|
},
|
|
|
watch: {
|
|
|
activeLevel(val) {
|
|
|
@@ -183,7 +203,6 @@
|
|
|
that.bgColor = '#D11122';
|
|
|
that.activeLevelText = '峰值锻炼';
|
|
|
break;
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
@@ -193,13 +212,13 @@
|
|
|
let that = this;
|
|
|
plus.bluetooth.openBluetoothAdapter({
|
|
|
success: function (e) {
|
|
|
- that.Toast('蓝牙适配器打开成功!');
|
|
|
+ that.Toast('蓝牙适配器打开成功!','success');
|
|
|
that.openAlert = true;
|
|
|
that.searchWatch();
|
|
|
return e
|
|
|
},
|
|
|
fail: function (e) {
|
|
|
- that.Toast('打开失败! 请确认蓝牙开关已开启');
|
|
|
+ that.Toast('打开失败! 请确认蓝牙开关已开启','error');
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
@@ -213,7 +232,7 @@
|
|
|
plus.bluetooth.startBluetoothDevicesDiscovery({
|
|
|
// services: ['heart_rate'],//ios不支持
|
|
|
success: function (e) {
|
|
|
- that.Toast('开始搜索成功!');
|
|
|
+ that.Toast('开始搜索成功!','success');
|
|
|
plus.bluetooth.onBluetoothDeviceFound(function (e) {
|
|
|
let devices = e.devices;
|
|
|
for (let i in devices) {
|
|
|
@@ -234,19 +253,19 @@
|
|
|
},
|
|
|
choiceWatch(w) {
|
|
|
let that = this;
|
|
|
- that.Toast('连接心率带' + w.localName + '中...');
|
|
|
+ that.Toast('连接心率带' + w.localName + '中...','success');
|
|
|
// 建立连接
|
|
|
plus.bluetooth.createBLEConnection({
|
|
|
deviceId: w.deviceId,
|
|
|
success: function (e) {
|
|
|
- that.Toast('连接成功!');
|
|
|
+ that.Toast('连接成功!','success');
|
|
|
// 渲染完毕再执行这个,所以才能没有延时的更改
|
|
|
// 需要一个回调等待5S
|
|
|
clearTimeout(that.timer); //清除延迟执行
|
|
|
that.timer = setTimeout(() => { //设置延迟执行
|
|
|
// 获取服务
|
|
|
that.getServices(w);
|
|
|
- }, 5000);
|
|
|
+ }, 2000);
|
|
|
},
|
|
|
fail: function (e) {
|
|
|
that.Toast('连接失败! ' + JSON.stringify(e));
|
|
|
@@ -260,11 +279,18 @@
|
|
|
plus.bluetooth.getBLEDeviceServices({
|
|
|
deviceId: w.deviceId,
|
|
|
success: function (e) {
|
|
|
- that.Toast('获取服务成功!');
|
|
|
+ that.Toast('获取服务成功!','success');
|
|
|
// 获取服务的特征值
|
|
|
// console.log('服务的特征值' + w.advertisServiceUUIDs[0]);
|
|
|
- var uuid = "0000180D-0000-1000-8000-00805F9B34FB";//HEART RATE
|
|
|
- that.getCharacteristics(w.deviceId, uuid);
|
|
|
+ var HEARTuuid = "0000180D-0000-1000-8000-00805F9B34FB";//HEART RATE
|
|
|
+ var Batteryuuid = "0000180F-0000-1000-8000-00805F9B34FB";//Battery
|
|
|
+ that.getBatteryCharacteristics(w.deviceId, Batteryuuid);
|
|
|
+ clearTimeout(that.timer); //清除延迟执行
|
|
|
+ that.timer = setTimeout(() => { //设置延迟执行
|
|
|
+ // 获取服务
|
|
|
+ that.getCharacteristics(w.deviceId, HEARTuuid);
|
|
|
+ }, 5000);
|
|
|
+
|
|
|
},
|
|
|
fail: function (e) {
|
|
|
console.log('获取服务失败! ' + JSON.stringify(e));
|
|
|
@@ -277,19 +303,19 @@
|
|
|
let that = this;
|
|
|
let chaaracterUuid = '00002A37-0000-1000-8000-00805F9B34FB';
|
|
|
let characteristicId = null;
|
|
|
+ that.begin = new Date();
|
|
|
plus.bluetooth.getBLEDeviceCharacteristics({
|
|
|
deviceId: deviceId,
|
|
|
serviceId: serviceId,
|
|
|
success: function (e) {
|
|
|
let characteristics = e.characteristics;
|
|
|
- that.Toast('获取特征值成功! ' + characteristics.length);
|
|
|
+ that.Toast('获取特征值成功! ' + characteristics.length,'success');
|
|
|
plus.bluetooth.notifyBLECharacteristicValueChange({ //监听数据变化
|
|
|
deviceId: deviceId,
|
|
|
serviceId: serviceId,
|
|
|
characteristicId: chaaracterUuid,
|
|
|
success: function (e) {
|
|
|
- that.Toast('notifyBLECharacteristicValueChange success.');
|
|
|
- that.readValue(deviceId, serviceId, chaaracterUuid)
|
|
|
+ that.onValuesChange();
|
|
|
},
|
|
|
fail: function (e) {
|
|
|
that.Toast('notifyBLECharacteristicValueChange failed! ' + JSON.stringify(e));
|
|
|
@@ -302,26 +328,184 @@
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
- readValue(deviceId, serviceId, characteristicId) {
|
|
|
+ // 获取服务的特征值
|
|
|
+ getBatteryCharacteristics(deviceId, serviceId) {
|
|
|
let that = this;
|
|
|
- plus.bluetooth.readBLECharacteristicValue({
|
|
|
+ let chaaracterUuid = '00002A19-0000-1000-8000-00805F9B34FB';
|
|
|
+ let characteristicId = null;
|
|
|
+ that.begin = new Date();
|
|
|
+ plus.bluetooth.getBLEDeviceCharacteristics({
|
|
|
deviceId: deviceId,
|
|
|
serviceId: serviceId,
|
|
|
- characteristicId: characteristicId,
|
|
|
success: function (e) {
|
|
|
- that.Toast('读取数据成功!');
|
|
|
- that.Toast(e)
|
|
|
- console.log("读取数据成功" + e);
|
|
|
+ let characteristics = e.characteristics;
|
|
|
+ that.Toast('获取特征值成功! ' + characteristics.length,'success');
|
|
|
+ plus.bluetooth.notifyBLECharacteristicValueChange({ //监听数据变化
|
|
|
+ deviceId: deviceId,
|
|
|
+ serviceId: serviceId,
|
|
|
+ characteristicId: chaaracterUuid,
|
|
|
+ success: function (e) {
|
|
|
+ that.onBatteryValuesChange();
|
|
|
+ },
|
|
|
+ fail: function (e) {
|
|
|
+ that.Toast('notifyBLECharacteristicValueChange failed! ' + JSON.stringify(e));
|
|
|
+ }
|
|
|
+ });
|
|
|
},
|
|
|
fail: function (e) {
|
|
|
- that.Toast('读取数据失败! ' + JSON.stringify(e));
|
|
|
+ console.log('获取特征值失败! ' + JSON.stringify(e));
|
|
|
+ that.Toast('获取特征值失败! ' + JSON.stringify(e));
|
|
|
}
|
|
|
- });
|
|
|
+ })
|
|
|
},
|
|
|
+ // readValue(deviceId, serviceId, characteristicId) {
|
|
|
+ // let that = this;
|
|
|
+ // plus.bluetooth.readBLECharacteristicValue({
|
|
|
+ // deviceId: deviceId,
|
|
|
+ // serviceId: serviceId,
|
|
|
+ // characteristicId: characteristicId,
|
|
|
+ // success: function (e) {
|
|
|
+ // that.Toast('读取数据成功!');
|
|
|
+ // that.Toast(e);
|
|
|
+ // console.log("读取数据成功" + e);
|
|
|
+ // },
|
|
|
+ // fail: function (e) {
|
|
|
+ // that.Toast('读取数据失败! ' + JSON.stringify(e));
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ // },
|
|
|
// 获取基础身体数据
|
|
|
getBodyInfo() {
|
|
|
+ // todo
|
|
|
+ },
|
|
|
+ onValuesChange() {
|
|
|
+ let that = this;
|
|
|
+ // todo 提出来,放在init里 有值就监听
|
|
|
+ // 监听低功耗蓝牙设备的特征值变化
|
|
|
+ plus.bluetooth.onBLECharacteristicValueChange(function (e) {
|
|
|
+ console.log('onBLECharacteristicValueChange: ' + JSON.stringify(e));
|
|
|
+ console.log('e.value: ' + JSON.stringify(e.value));
|
|
|
+ console.log('---> parseHeartRate() = ' + that.parseHeartRate(e.value).heartRate);
|
|
|
+ // 成功获取心跳
|
|
|
+ that.heartRate = parseInt(that.parseHeartRate(e.value).heartRate);
|
|
|
+ that.watchText = '心率带已连接';
|
|
|
+ that.activeState = true;
|
|
|
+ // 运动强度计算
|
|
|
+ that.calcActLevel(that.heartRate);
|
|
|
+ that.openAlert = false;//关闭弹窗
|
|
|
+ that.watchState = true;//关闭连接按钮
|
|
|
+ // 卡路里计算
|
|
|
+ that.calcCalorie(that.heartRate);
|
|
|
+ if (that.heartLine.length > 30) {
|
|
|
+ that.heartLine.unshift();
|
|
|
+ that.dataLabels.unshift();
|
|
|
+ } else {
|
|
|
+ that.heartLine.push(that.heartRate);
|
|
|
+ that.dataLabels.push('');
|
|
|
+ }
|
|
|
+ that.DrawHeartLine(that.heartLine,that.dataLabels);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onBatteryValuesChange() {
|
|
|
+ let that = this;
|
|
|
+ // 监听低功耗蓝牙设备的特征值变化
|
|
|
+ plus.bluetooth.onBLECharacteristicValueChange(function (e) {
|
|
|
+ console.log('onBLECharacteristicValueChange: ' + JSON.stringify(e));
|
|
|
+ console.log('Battery: ' + e.value);
|
|
|
+ // console.log('---> Battery () = ' + that.parseHeartRate(e.value).heartRate);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ parseHeartRate(data) {
|
|
|
+ var data = new DataView(data);
|
|
|
+ const flags = data.getUint8(0);
|
|
|
+ const rate16Bits = flags & 0x1;
|
|
|
+ const result = {};
|
|
|
+ let index = 1;
|
|
|
+ if (rate16Bits) {
|
|
|
+ result.heartRate = data.getUint16(index, /*littleEndian=*/ true);
|
|
|
+ index += 2;
|
|
|
+ } else {
|
|
|
+ result.heartRate = data.getUint8(index);
|
|
|
+ index += 1;
|
|
|
+ }
|
|
|
+ const contactDetected = flags & 0x2;
|
|
|
+ const contactSensorPresent = flags & 0x4;
|
|
|
+ if (contactSensorPresent) {
|
|
|
+ result.contactDetected = !!contactDetected;
|
|
|
+ }
|
|
|
+ const energyPresent = flags & 0x8;
|
|
|
+ if (energyPresent) {
|
|
|
+ result.energyExpended = data.getUint16(index, /*littleEndian=*/ true);
|
|
|
+ index += 2;
|
|
|
+ }
|
|
|
+ const rrIntervalPresent = flags & 0x10;
|
|
|
+ if (rrIntervalPresent) {
|
|
|
+ const rrIntervals = [];
|
|
|
+ for (; index + 1 < data.byteLength; index += 2) {
|
|
|
+ rrIntervals.push(data.getUint16(index, /*littleEndian=*/ true));
|
|
|
+ }
|
|
|
+ result.rrIntervals = rrIntervals;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+ // 活动强度计算公式
|
|
|
+ calcActLevel(heartRate) {
|
|
|
+ let sum = 170 - this.age;
|
|
|
+ this.activeLevel = parseInt((heartRate / sum) * 100);
|
|
|
+ },
|
|
|
+ // 持续时间
|
|
|
+ calcHoldTime(curTime) {
|
|
|
+ let res = parseInt(curTime.getTime() - this.begin.getTime()) / 1000;
|
|
|
+ return parseInt(res)
|
|
|
+ },
|
|
|
+ // 计算卡路里
|
|
|
+ calcCalorie(heartRate) {
|
|
|
+ let that = this;
|
|
|
+ let calorieNoVo2 = 0;
|
|
|
+ let curTime = that.calcHoldTime(new Date());
|
|
|
+ console.log(curTime);
|
|
|
+ // 男
|
|
|
+ if (that.sex == 1) {
|
|
|
+ calorieNoVo2 = ((-55.0969 + (0.6309 * heartRate) + (0.1988 * that.weight) + (0.2017 * that.age)) / 4.184) / 60 * 1;
|
|
|
+ } else {
|
|
|
+ calorieNoVo2 = ((-20.4022 + (0.4472 * heartRate) + (0.1263 * that.weight) + (0.074 * that.age)) / 4.184) / 60 * 1;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ that.cal = that.cal + calorieNoVo2;
|
|
|
+ // 计算CK
|
|
|
+ that.calcCk(that.cal);
|
|
|
+ that.calcSportCal(calorieNoVo2, curTime)
|
|
|
+ },
|
|
|
+ // 计算CK
|
|
|
+ calcCk(cal) {
|
|
|
+ this.ck = parseFloat(cal / this.weight).toFixed(2);
|
|
|
+ },
|
|
|
+ // 计算运动卡路里
|
|
|
+ calcSportCal(calorieNoVo2) {
|
|
|
+ let bmrMSjDaily = (10.00 * this.weight) + (6.25 * this.height) - (5.00 * this.age) + 5.00;
|
|
|
+ let BmrMSjRmrcb = parseFloat((bmrMSjDaily * 1.1) / 24);
|
|
|
+ let calorieNoVo2Pure = (calorieNoVo2 - BmrMSjRmrcb / 3600 * 1);
|
|
|
+ this.sportCal = this.sportCal + calorieNoVo2Pure;
|
|
|
+ },
|
|
|
+ // 绘制心电图
|
|
|
+ DrawHeartLine(heartLine, dataLabels) {
|
|
|
+ this.dataLabels = dataLabels;
|
|
|
+ this.dataDatasets = heartLine;
|
|
|
+ this.calcMaxHr(heartLine);
|
|
|
+ this.calcAveHr(heartLine);
|
|
|
+ },
|
|
|
+ // 最大心率
|
|
|
+ calcMaxHr(heartLine) {
|
|
|
+ this.heartMax = Math.max(...heartLine);
|
|
|
+ },
|
|
|
+ // 平均心率
|
|
|
+ calcAveHr(heartLine) {
|
|
|
+ var sum = 0;
|
|
|
+ for (var i = 0; i < heartLine.length; i++) {
|
|
|
+ sum += heartLine[i];
|
|
|
+ }
|
|
|
+ this.heartAverage = parseInt(sum / heartLine.length);
|
|
|
+ },
|
|
|
},
|
|
|
filters: {
|
|
|
parseLevel: function (value) {
|
|
|
@@ -334,6 +518,12 @@
|
|
|
return '弱'
|
|
|
}
|
|
|
}
|
|
|
+ },
|
|
|
+ parseToInt:function (val) {
|
|
|
+ return parseInt(val)
|
|
|
+ },
|
|
|
+ parseToFix2:function (val) {
|
|
|
+ return parseFloat(val).toFixed(2)
|
|
|
}
|
|
|
},
|
|
|
components: {
|
|
|
@@ -348,6 +538,8 @@
|
|
|
overflow: hidden;
|
|
|
display: block;
|
|
|
margin: 0 auto;
|
|
|
+ padding-top: 10px;
|
|
|
+ padding-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
.top .watchState {
|
|
|
@@ -531,7 +723,9 @@
|
|
|
width: 80px;
|
|
|
height: 20px;
|
|
|
overflow: hidden;
|
|
|
- float: left;
|
|
|
+ display: block;
|
|
|
+ margin: 0 auto;
|
|
|
+ /*float: left;*/
|
|
|
color: #fff;
|
|
|
border: 1px solid #fff;
|
|
|
border-radius: 250px;
|
|
|
@@ -599,8 +793,8 @@
|
|
|
display: block;
|
|
|
margin: 0 auto;
|
|
|
background: #EFEFEF;
|
|
|
- padding-top: 10px;
|
|
|
- padding-bottom: 10px;
|
|
|
+ padding-top: 5px;
|
|
|
+ padding-bottom: 5px;
|
|
|
}
|
|
|
|
|
|
.row .rowCenter {
|