718 lines
17 KiB
Vue
718 lines
17 KiB
Vue
<template>
|
||
<view class="content" style="width: 60%;">
|
||
<uni-popup ref="popup" type="bottom" border-radius="10px 10px 0 0">
|
||
<view class="pop-main" v-if="typeIndex == 1">
|
||
<view>
|
||
<view class="pop-close" @click="close()">
|
||
×
|
||
</view>
|
||
<view class="dxxl">
|
||
<scroll-view class="myScoll" scroll-x :show-scrollbar="true">
|
||
<view class="box1">
|
||
<canvas canvas-id="ecg" style="width: 3000px; height: 300px;"></canvas>
|
||
</view>
|
||
<view class="box2" :style="{'left': pLeft + 'px'}">
|
||
<canvas canvas-id="myCanvas" style="width: 3000px; height: 300px;"></canvas>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<view class="list">
|
||
<view class="flx flx_ac ">
|
||
<view class="" style="margin-top: 10rpx;margin-right: 10rpx;">
|
||
<image src="../../static/icon/xinlv-small.png" style="width: 40rpx;" mode="widthFix">
|
||
</image>
|
||
</view>
|
||
<view class="" style="color: red;">
|
||
心率
|
||
</view>
|
||
</view>
|
||
<view class="flx flx_sb sl_box flx_wp">
|
||
<view class="all" v-for="(item,index) in xinlv.jisuan">
|
||
<view class="">
|
||
<span class="sl_box_wz">{{item.times?item.times:0}}</span>
|
||
<span class="sl_box_unit">{{item.unit}}</span>
|
||
</view>
|
||
<view class="sl_box_desc">
|
||
{{item.desc}}
|
||
</view>
|
||
<view class="sl_box_cankao" v-if="item.cankao">
|
||
{{item.cankao}}
|
||
</view>
|
||
</view>
|
||
<view class="all" v-for="(item,index) in xinlv.cankao">
|
||
<view class="">
|
||
<span class="sl_box_wz">{{item.times.toFixed(2)}}</span>
|
||
<span class="sl_box_unit">{{item.unit}}</span>
|
||
</view>
|
||
<view class="sl_box_desc">
|
||
{{item.desc}}
|
||
</view>
|
||
<view class="sl_box_cankao" v-if="item.cankao">
|
||
{{item.cankao}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="list">
|
||
<view class="flx flx_ac ">
|
||
<view class="" style="margin-top: 10rpx;margin-right: 10rpx;">
|
||
<image src="../../static/icon/xinlv-small.png" style="width: 40rpx;" mode="widthFix">
|
||
</image>
|
||
</view>
|
||
<view class="" style="color: red;">
|
||
心率变异性
|
||
</view>
|
||
</view>
|
||
<view class="">
|
||
<xdt :datas="ybx.hrv"></xdt>
|
||
<xdt :datas="ybx.sdnn"></xdt>
|
||
<xdt :datas="ybx.rmssd"></xdt>
|
||
</view>
|
||
</view>
|
||
<view class="list">
|
||
<view class="flx flx_ac ">
|
||
<view class="" style="margin-top: 10rpx;margin-right: 10rpx;">
|
||
<image src="../../static/icon/xinlv-small.png" style="width: 40rpx;" mode="widthFix">
|
||
</image>
|
||
</view>
|
||
<view class="" style="color: red;">
|
||
心电图
|
||
</view>
|
||
</view>
|
||
<view class="">
|
||
<xdt :datas="xdt.pwv"></xdt>
|
||
<xdt :datas="xdt.qtc"></xdt>
|
||
<xdt :datas="xdt.qsrf"></xdt>
|
||
<xdt :datas="xdt.qsrx"></xdt>
|
||
<xdt :datas="xdt.qsrfx"></xdt>
|
||
<xdt :datas="xdt.st"></xdt>
|
||
</view>
|
||
</view>
|
||
<view class="" style="height: 20rpx;"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="pop-main" v-if="typeIndex == 2">
|
||
<view>
|
||
<view class="pop-close" @click="close()">
|
||
×
|
||
</view>
|
||
<view>
|
||
<view class="flx flx_ac" style="background-color: #fff;padding: 30rpx 0 0 30rpx;">
|
||
<view class="">
|
||
<text class="iconfont icon-wode"
|
||
:style="'font-size: 50rpx;margin-right:10rpx;color:' + bodyDesc.color "></text>
|
||
</view>
|
||
<view class="">
|
||
<text>{{bodyDesc.name}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="" style="position: relative;">
|
||
<image src="../../static/image/body.png" style="width: 100%;" mode="widthFix"></image>
|
||
<view class="left_position postion ">
|
||
<view class="desc_box">
|
||
<view class="flx flx_ac">
|
||
<view class="tt">
|
||
{{ dataInfo.data_msg.basalMetabolicRate }}
|
||
</view>
|
||
<view class="unit">
|
||
千卡
|
||
</view>
|
||
</view>
|
||
<view class="name">
|
||
基础代谢
|
||
</view>
|
||
</view>
|
||
<view class="desc_box">
|
||
<view class="flx flx_ac">
|
||
<view class="tt">
|
||
{{ dataInfo.data_msg.boneMass }}
|
||
</view>
|
||
<view class="unit">
|
||
千克
|
||
</view>
|
||
</view>
|
||
<view class="name">
|
||
骨重
|
||
</view>
|
||
</view>
|
||
<view class="desc_box">
|
||
<view class="flx flx_ac">
|
||
<view class="tt">
|
||
{{ dataInfo.data_msg.waterContent }}
|
||
</view>
|
||
<view class="unit">
|
||
千克
|
||
</view>
|
||
</view>
|
||
<view class="name">
|
||
水分
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
<view class="right_position postion">
|
||
<view class="desc_box">
|
||
<view class="flx flx_ac">
|
||
<view class="tt">
|
||
{{ dataInfo.data_msg.fatMass }}
|
||
</view>
|
||
<view class="unit">
|
||
千克
|
||
</view>
|
||
</view>
|
||
<view class="name">
|
||
脂肪
|
||
</view>
|
||
</view>
|
||
<view class="desc_box" style="margin-bottom: 0;margin-top: 174rpx;">
|
||
<view class="flx flx_ac">
|
||
<view class="tt">
|
||
{{ dataInfo.data_msg.proteinAmount }}
|
||
</view>
|
||
<view class="unit">
|
||
千克
|
||
</view>
|
||
</view>
|
||
<view class="name">
|
||
蛋白质
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="postion center_posion">
|
||
{{ dataInfo.data_msg.userInfo.gender == '2'?'女':'男' }}性,{{ dataInfo.data_msg.userInfo.weight }}千克
|
||
</view>
|
||
<view class="postion right_center">
|
||
{{ dataInfo.data_msg.userInfo.height }}厘米
|
||
</view>
|
||
</view>
|
||
<view class="radius_box" style="padding: 0;margin: 30rpx;">
|
||
<view class="" v-for="(v,i) in arr" :key="i">
|
||
<body_info_components :key_name="v" :value="parseFloat(dataInfo.data_msg[v])">
|
||
</body_info_components>
|
||
</view>
|
||
</view>
|
||
<view class="" style="height: 40rpx;">
|
||
|
||
</view>
|
||
</view>
|
||
|
||
<view class="" style="height: 20rpx;"></view>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "pop-info",
|
||
data() {
|
||
return {
|
||
typeIndex: 1,
|
||
dataInfo: {},
|
||
bodyDesc: {},
|
||
arr: [
|
||
'BMI',
|
||
'bodyFatPercentage',
|
||
'leanBodyMass',
|
||
'muscleRate',
|
||
'muscleMass',
|
||
'subcutaneousFat',
|
||
'bodyMoisture',
|
||
'skeletalMuscleRate',
|
||
'boneMass',
|
||
'proteinAmount',
|
||
'basalMetabolicRate',
|
||
],
|
||
|
||
|
||
title: '',
|
||
list: [],
|
||
|
||
height: 300,
|
||
width: 3000,
|
||
centerY: 200,
|
||
pLeft: '0',
|
||
dataInfo: {},
|
||
xinlv: {
|
||
jisuan: [{
|
||
times: 0,
|
||
unit: '次/分',
|
||
desc: '平均心率',
|
||
cankao: ''
|
||
},
|
||
{
|
||
times: 0,
|
||
unit: '次/分',
|
||
desc: '最高心率',
|
||
cankao: ''
|
||
},
|
||
{
|
||
times: 0,
|
||
unit: '次/分',
|
||
desc: '最低心率',
|
||
cankao: ''
|
||
}
|
||
],
|
||
cankao: [{
|
||
times: 0,
|
||
unit: '%',
|
||
desc: '正常',
|
||
cankao: '(60~100次/分)'
|
||
},
|
||
{
|
||
times: 0,
|
||
unit: '%',
|
||
desc: '心率偏快',
|
||
cankao: '>100次/分)'
|
||
},
|
||
{
|
||
times: 0,
|
||
unit: '%',
|
||
desc: '心率偏慢',
|
||
cankao: '(<60次/分)'
|
||
},
|
||
|
||
],
|
||
},
|
||
// 心率异变性
|
||
ybx: {
|
||
hrv: {
|
||
name: 'HRV',
|
||
max: 210,
|
||
unit: '毫秒',
|
||
min: 0,
|
||
val: 0
|
||
},
|
||
sdnn: {
|
||
name: 'SDNN',
|
||
max: 180,
|
||
unit: '毫秒',
|
||
min: 102,
|
||
val: 0
|
||
},
|
||
rmssd: {
|
||
name: 'RMSSD',
|
||
max: 39,
|
||
unit: '毫秒',
|
||
min: 15,
|
||
val: 0
|
||
}
|
||
},
|
||
xdt: {
|
||
pwv: {
|
||
name: 'PWV',
|
||
max: 15,
|
||
unit: 'm/s',
|
||
min: 6,
|
||
val: 0
|
||
},
|
||
qtc: {
|
||
name: 'QTc',
|
||
max: 400,
|
||
unit: '毫秒',
|
||
min: 260,
|
||
val: 0
|
||
},
|
||
qsrf: {
|
||
name: 'QRS 波振幅',
|
||
max: 1.5,
|
||
unit: 'mV',
|
||
min: 0.05,
|
||
val: 0
|
||
},
|
||
qsrx: {
|
||
name: 'QRS 波时限',
|
||
max: 120,
|
||
unit: '毫秒',
|
||
min: 80,
|
||
val: 0
|
||
},
|
||
qsrfx: {
|
||
name: 'QRS 主波方向',
|
||
max: 0,
|
||
unit: '向上,向下',
|
||
min: 0,
|
||
val: 0
|
||
},
|
||
st: {
|
||
name: 'ST 段振幅',
|
||
max: 0.1,
|
||
unit: 'mV',
|
||
min: -0.05,
|
||
val: 0
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
close() {
|
||
this.$refs.popup.close()
|
||
},
|
||
open(val) {
|
||
val == 1 ? this.typeIndex = 1 : this.typeIndex = 2;
|
||
// 通过组件定义的ref调用uni-popup方法 ,如果传入参数 ,type 属性将失效 ,仅支持 ['top','left','bottom','right','center']
|
||
this.$refs.popup.open('bottom')
|
||
|
||
if (val == 1) {
|
||
const dataKey = 'infoData'; // 同上面设置的key
|
||
let get = uni.getStorageSync(dataKey)
|
||
|
||
if (!get) {
|
||
uni.showToast({
|
||
title: "读取数据失败"
|
||
})
|
||
setTimeout(() => {
|
||
uni.navigateBack({
|
||
delta: -1
|
||
})
|
||
}, 2000)
|
||
return
|
||
}
|
||
const data = JSON.parse(get);
|
||
console.log(data)
|
||
this.dataInfo = data;
|
||
this.changeData(this.dataInfo)
|
||
this.list = this.dataInfo.data_msg.list;
|
||
|
||
// 绘制
|
||
setTimeout(() => {
|
||
this.list = this.list.filter(val => val !== 0)
|
||
const ctx = uni.createCanvasContext('ecg', this);
|
||
ctx.setStrokeStyle('#d5d5d5') //
|
||
ctx.setLineWidth(1) // 线条宽度
|
||
for (var x = 0.5; x < 3000; x += 15) {
|
||
ctx.moveTo(x, 0)
|
||
// 结束点
|
||
ctx.lineTo(x, 3000)
|
||
// 描边,不调用stroke则看不到画的内容
|
||
ctx.stroke()
|
||
}
|
||
for (var y = 0.5; y < 3000; y += 15) {
|
||
ctx.moveTo(0, y)
|
||
// 结束点
|
||
ctx.lineTo(3000, y)
|
||
// 描边,不调用stroke则看不到画的内容
|
||
ctx.stroke()
|
||
}
|
||
// ctx.fill();
|
||
ctx.draw()
|
||
this.drawCurve()
|
||
}, 1000)
|
||
} else {
|
||
const dataKey = 'bodyData'; // 同上面设置的key
|
||
let get = uni.getStorageSync(dataKey)
|
||
|
||
if (!get) {
|
||
uni.showToast({
|
||
title: "读取数据失败"
|
||
})
|
||
setTimeout(() => {
|
||
uni.navigateBack({
|
||
delta: -1
|
||
})
|
||
}, 2000)
|
||
return
|
||
}
|
||
const data = JSON.parse(get);
|
||
this.dataInfo = data;
|
||
console.log(this.dataInfo)
|
||
// this.getUserInfo()
|
||
this.bodyDesc = this.$utils.getBodyKeyInfo(this.dataInfo.data_msg.BMI, 'BMI')
|
||
// uni.removeStorageSync(dataKey);
|
||
}
|
||
},
|
||
|
||
drawCurve() {
|
||
let ctx = uni.createCanvasContext('myCanvas', this)
|
||
let list = this.list;
|
||
let centerY = this.centerY;
|
||
let width = this.width;
|
||
let xScale = width / (list.length - 1); // 计算每个数据点占据的宽度
|
||
let yScale = centerY / (Math.max(...list) - Math.min(...list))
|
||
// yScale *= 3
|
||
let x = 0;
|
||
let y = centerY / 2 - (list[0] * yScale)
|
||
ctx.beginPath(); // 开始绘制
|
||
ctx.moveTo(x, y);
|
||
ctx.setStrokeStyle('#c96d79'); // 设置线条颜色
|
||
ctx.setLineWidth(2); // 设置线条宽度
|
||
for (let i = 1; i < list.length; i++) {
|
||
let x = i * xScale;
|
||
let y = centerY / 2 - ((list[i] / 2) * yScale); // 负数在中心下方,正数在中心上方
|
||
ctx.lineTo(x, y);
|
||
|
||
}
|
||
ctx.stroke() // 绘制线条
|
||
// ctx.fill();
|
||
ctx.draw(false);
|
||
|
||
// 绘制到canvas上,不需要等待上一步绘制完成
|
||
},
|
||
|
||
changeData(data) {
|
||
let HRV = []
|
||
let QT = []
|
||
let heart = []
|
||
let pwv = []
|
||
let resRate = []
|
||
this.xinlv.jisuan[0].times = data.data_msg.meanHeartRate == undefined ? data.data_msg.heartRate : data
|
||
.data_msg.meanHeartRate
|
||
if (data.data_msg.wavefrom == undefined) {
|
||
return
|
||
}
|
||
data.data_msg.wavefrom.map((v, i) => {
|
||
|
||
if (!(v instanceof Array)) {
|
||
if (v.HRV != 0) {
|
||
HRV.push(v.HRV)
|
||
}
|
||
if (v.QT != 0) {
|
||
QT.push(v.QT)
|
||
}
|
||
if (v.heart != 0 && v.heart != null) {
|
||
heart.push(v.heart)
|
||
}
|
||
if (v.pwv != 0) {
|
||
pwv.push(v.pwv)
|
||
}
|
||
if (v.resRate != 0) {
|
||
resRate.push(v.resRate)
|
||
}
|
||
}
|
||
|
||
})
|
||
this.xinlv.jisuan[1].times = Math.max(...heart)
|
||
this.xinlv.jisuan[2].times = Math.min(...heart)
|
||
// 获取心率每个区间的数据数量
|
||
let heart_zc = heart.filter(value => (value >= 60 && value <= 100)).length;
|
||
let heart_fast = heart.filter(value => value > 100).length;
|
||
let heart_slow = heart.filter(value => value < 60).length;
|
||
let heart_length = heart.length
|
||
this.xinlv.cankao[0].times = (heart_zc / heart_length).toFixed(2) * 100
|
||
this.xinlv.cankao[1].times = (heart_fast / heart_length).toFixed(2) * 100
|
||
this.xinlv.cankao[2].times = (heart_slow / heart_length).toFixed(2) * 100
|
||
if (this.xinlv.cankao[0].times > 50) {
|
||
this.title = '窦性心率';
|
||
} else if (this.xinlv.cankao[1].times >= 50) {
|
||
this.title = '心率偏快';
|
||
} else if (this.xinlv.cankao[2].times >= 50) {
|
||
this.title = '心率偏慢';
|
||
} else {
|
||
this.title = '窦性心率不齐';
|
||
}
|
||
if (data.diseaseRisk != undefined && data.diseaseRisk >= 30 && this.xinlv.cankao[0].times > 50) {
|
||
this.title = '窦性心率不齐';
|
||
}
|
||
if (data.data_msg.hrv != undefined) {
|
||
this.ybx.hrv.val = data.data_msg.hrv
|
||
this.ybx.sdnn.val = data.data_msg.diseaseSdnn
|
||
this.ybx.rmssd.val = data.data_msg.diseaseRmssd
|
||
this.xdt.pwv.val = (data.data_msg.pwvMeanVal / 10).toFixed(2)
|
||
this.xdt.qtc.val = data.data_msg.QTC
|
||
this.xdt.qsrf.val = (data.data_msg.qrsAmp / 100).toFixed(2)
|
||
this.xdt.qsrx.val = data.data_msg.qrsTime
|
||
this.xdt.qsrfx.val = data.data_msg.leadOffType == 0 ? '向上' : '向下'
|
||
this.xdt.st.val = (data.data_msg.stMeanVal / 100).toFixed(2)
|
||
} else {
|
||
console.log('is undefined')
|
||
this.ybx.hrv.val = data.data_msg.averageHRV
|
||
this.xdt.qtc.val = data.data_msg.averageTimeInterval
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.pop-close {
|
||
display: flex;
|
||
flex-direction: row-reverse;
|
||
font-size: 100rpx;
|
||
padding-right: 50rpx;
|
||
}
|
||
|
||
.pop-main {
|
||
width: 100%;
|
||
height: 100vh;
|
||
background-color: #fff;
|
||
overflow-y: scroll;
|
||
}
|
||
|
||
.box1 {
|
||
position: absolute;
|
||
left: 0px;
|
||
width: 3000rpx;
|
||
}
|
||
|
||
.box2 {
|
||
position: absolute;
|
||
left: 0px;
|
||
width: 3000rpx;
|
||
}
|
||
|
||
.myScoll {
|
||
width: 100%;
|
||
height: 396rpx;
|
||
white-space: nowrap;
|
||
position: relative;
|
||
}
|
||
|
||
.list {
|
||
background-color: #fff;
|
||
overflow: hidden;
|
||
padding: 30rpx;
|
||
margin: 30rpx 30rpx;
|
||
border-radius: 30rpx;
|
||
}
|
||
|
||
.dxxl {
|
||
background-color: #fff;
|
||
padding: 20rpx;
|
||
padding-top: 40rpx;
|
||
}
|
||
|
||
.sl_box {
|
||
text-align: center;
|
||
|
||
.all {
|
||
width: calc(100% / 3);
|
||
margin-top: 40rpx;
|
||
}
|
||
|
||
.sl_box_cankao,
|
||
.sl_box_desc {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.sl_box_unit {
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.sl_box_wz {
|
||
margin-right: 10rpx;
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
|
||
<style lang="scss" scoped>
|
||
.pop-close {
|
||
display: flex;
|
||
flex-direction: row-reverse;
|
||
font-size: 100rpx;
|
||
padding-right: 50rpx;
|
||
}
|
||
|
||
.pop-main {
|
||
width: 60%;
|
||
height: 100vh;
|
||
background-color: #fff;
|
||
overflow-y: scroll;
|
||
}
|
||
|
||
.box1 {
|
||
position: absolute;
|
||
left: 0px;
|
||
width: 3000rpx;
|
||
}
|
||
|
||
.box2 {
|
||
position: absolute;
|
||
left: 0px;
|
||
width: 3000rpx;
|
||
}
|
||
|
||
.myScoll {
|
||
width: 100%;
|
||
height: 396rpx;
|
||
white-space: nowrap;
|
||
position: relative;
|
||
}
|
||
|
||
.list {
|
||
background-color: #fff;
|
||
overflow: hidden;
|
||
padding: 30rpx;
|
||
margin: 30rpx 30rpx;
|
||
border-radius: 30rpx;
|
||
}
|
||
|
||
.dxxl {
|
||
background-color: #fff;
|
||
padding: 20rpx;
|
||
padding-top: 40rpx;
|
||
}
|
||
|
||
.sl_box {
|
||
text-align: center;
|
||
|
||
.all {
|
||
width: calc(100% / 3);
|
||
margin-top: 40rpx;
|
||
}
|
||
|
||
.sl_box_cankao,
|
||
.sl_box_desc {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.sl_box_unit {
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.sl_box_wz {
|
||
margin-right: 10rpx;
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
|
||
<style lang="scss" scoped>
|
||
.postion{
|
||
position: absolute;
|
||
}
|
||
.left_position{
|
||
left: 40rpx;
|
||
top:12%
|
||
}
|
||
.right_position{
|
||
right: 40rpx;
|
||
top:15%
|
||
}
|
||
.right_center{
|
||
right: 160rpx;
|
||
top:42%;
|
||
font-size: 26rpx;
|
||
}
|
||
.center_posion{
|
||
width: 100%;
|
||
text-align: center;
|
||
bottom: 20rpx;
|
||
}
|
||
.desc_box{
|
||
margin-bottom: 64rpx;
|
||
.tt{
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
margin-right: 10rpx;
|
||
}
|
||
.unit{
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
.name{
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
</style>
|