Prechádzať zdrojové kódy

Merge branch 'master' of git.beswell.com:duanchangpeng/flyLong

# Conflicts:
#	online/src/page/mainpage.vue
Changpeng Duan 5 rokov pred
rodič
commit
3199ee0c49

+ 10 - 10
online/src/components/BaseCharts.js

@@ -68,7 +68,7 @@ export function generateChart (chartId, chartType) {
                 }
             },
             renderChart (data, options) {
-                if (this.$data._chart) this.$data._chart.destroy()
+                if (this.$data._chart) this.$data._chart.destroy();
                 this.$data._chart = new Chart(
                     this.$refs.canvas.getContext('2d'), {
                         type: chartType,
@@ -87,15 +87,15 @@ export function generateChart (chartId, chartType) {
     }
 }
 
-export const Bar = generateChart('bar-chart', 'bar')
-export const HorizontalBar = generateChart('horizontalbar-chart', 'horizontalBar')
-export const Doughnut = generateChart('doughnut-chart', 'doughnut')
-export const Line = generateChart('line-chart', 'line')
-export const Pie = generateChart('pie-chart', 'pie')
-export const PolarArea = generateChart('polar-chart', 'polarArea')
-export const Radar = generateChart('radar-chart', 'radar')
-export const Bubble = generateChart('bubble-chart', 'bubble')
-export const Scatter = generateChart('scatter-chart', 'scatter')
+export const Bar = generateChart('bar-chart', 'bar');
+export const HorizontalBar = generateChart('horizontalbar-chart', 'horizontalBar');
+export const Doughnut = generateChart('doughnut-chart', 'doughnut');
+export const Line = generateChart('line-chart', 'line');
+export const Pie = generateChart('pie-chart', 'pie');
+export const PolarArea = generateChart('polar-chart', 'polarArea');
+export const Radar = generateChart('radar-chart', 'radar');
+export const Bubble = generateChart('bubble-chart', 'bubble');
+export const Scatter = generateChart('scatter-chart', 'scatter');
 
 export default {
     Bar,

+ 9 - 3
online/src/components/LineExample.js

@@ -32,10 +32,9 @@ export default {
                             display: false,
                             text: 'Custom Chart Title'
                         },
-                        Legend: {
-                            display: false,
-                        },
+
                         label: '',
+                        barShowStroke : true, // 是否显示线
                         color: '#E75296',
                         borderColor: '#E75296',
                         backgroundColor: 'rgba(255,255,255,0)',
@@ -43,6 +42,13 @@ export default {
                     }
                 ]
             }, {
+                animation:{
+                    duration:0,
+                    // easing:'easeInQuad'
+                },
+                legend:{
+                    display:false
+                },
                 responsive: false,
                 maintainAspectRatio: false,
                 scales: {

+ 228 - 34
online/src/page/mainpage.vue

@@ -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 {