441 lines
11 KiB
Vue
441 lines
11 KiB
Vue
<template>
|
||
<view>
|
||
<tm-nav-bar left-icon="arrow-left" title="睡眠" @clickLeft="back" />
|
||
<view class="flx jcsb ac" style="height: 40rpx;background-color: #fff;padding: 20rpx;">
|
||
<view class="" style="font-size: 40rpx;font-weight: bold;">
|
||
|
||
</view>
|
||
<view class="" style="color: #b8b8b8;font-size: 24rpx;">
|
||
{{time}}
|
||
</view>
|
||
</view>
|
||
<view class="canvas_box">
|
||
<canvas canvas-id="circleCanvas" style="width: 250px; height: 250px;margin: 0 auto;"></canvas>
|
||
<view class="" style="height: 40rpx;">
|
||
|
||
</view>
|
||
<view class="flx flx_sb">
|
||
<view class="flx flx_ac">
|
||
<!-- color:'#e933dd',
|
||
bigColor:'#6452da', -->
|
||
<view class="circle" style="background-color:#6452da ;" >
|
||
</view>
|
||
<view class="sleep_info">
|
||
<view class="info_title">
|
||
睡眠时长
|
||
</view>
|
||
<view class="info_val">
|
||
{{sleep.shen}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="flx flx_ac">
|
||
<view class="sleep_info">
|
||
<view class="info_title" style="text-align: right;">
|
||
深度睡眠
|
||
</view>
|
||
<view class="info_val">
|
||
{{sleep.qian}}
|
||
</view>
|
||
</view>
|
||
<view class="circle" style="background-color:#e933dd ;">
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
<view class="radius_box" style="margin: 20rpx;margin-top: 40rpx ;">
|
||
<view class="flx flx_sb title_box">
|
||
<view class="title">
|
||
{{sleep.shen}}
|
||
</view>
|
||
</view>
|
||
<sleep-list-data :canvas-id="'sleep-canvas-id'" :dataList="sleepList"></sleep-list-data>
|
||
<view class="flx flx_sb flx_ac" style="margin-top: 20rpx;">
|
||
<view class="flx flx_ac">
|
||
<view class="flx flx_ac">
|
||
<image src="../../static/icon/sleep.png" style="width: 30rpx;margin-right: 5rpx;" mode="widthFix"></image>
|
||
</view>
|
||
<view class="small-title" v-if="fallAsleepTime.length > 0">
|
||
{{ fallAsleepTime[2] }}:{{ fallAsleepTime[3] }} , {{ fallAsleepTime[0] }}/{{ fallAsleepTime[1] }}
|
||
</view>
|
||
<view class="small-title" v-else>
|
||
|
||
</view>
|
||
</view>
|
||
<view class="flx flx_ac">
|
||
<view class="small-title" v-if="exitSleepTime.length > 0">
|
||
{{ exitSleepTime[2] }}:{{ exitSleepTime[3] }} , {{ exitSleepTime[0] }}/{{ exitSleepTime[1] }}
|
||
</view>
|
||
<view class="small-title" v-else>
|
||
|
||
</view>
|
||
<view class="flx flx_ac">
|
||
<image src="../../static/image/richu.png" style="width: 50rpx;" mode="widthFix"></image>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="radius_box" style="margin: 20rpx;padding-bottom: 20rpx;margin-top: 40rpx;" v-if="option.series[0].data.length > 0">
|
||
<view class="" style="font-size: 26rpx;margin-bottom: 30rpx;">
|
||
睡眠阶段
|
||
</view>
|
||
<view class="flx flx_sb">
|
||
<view class="">
|
||
<view style="width: 200rpx; height:200rpx;background-color: #fff;"><l-echart ref="chartRef" @finished="init"></l-echart></view>
|
||
</view>
|
||
<view class="flx flx_sb" style="width: 100%;margin-left: 40rpx;flex-direction: column;padding: 20rpx 0;padding-right: 40rpx;">
|
||
<view class="flx flx_sb line">
|
||
<view class="flx small-title flx_ac">
|
||
<view class="dian0 yuan" style="margin-right: 10rpx;">
|
||
</view>
|
||
<view class="">
|
||
深睡
|
||
</view>
|
||
</view>
|
||
<view class="">
|
||
<view class="c0">
|
||
{{ sleepData.shen }}%
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="flx flx_sb line">
|
||
<view class="flx small-title flx_ac">
|
||
<view class="dian1 yuan" style="margin-right: 10rpx;">
|
||
</view>
|
||
<view class="">
|
||
浅睡
|
||
</view>
|
||
</view>
|
||
<view class="">
|
||
<view class="c1">
|
||
{{ sleepData.qian }}%
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="flx flx_sb line">
|
||
<view class="flx small-title flx_ac">
|
||
<view class="dian2 yuan" style="margin-right: 10rpx;">
|
||
</view>
|
||
<view class="">
|
||
快速动眼
|
||
</view>
|
||
</view>
|
||
<view class="">
|
||
<view class="c2">
|
||
{{ sleepData.kuai }}%
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="radius_box" style="margin: 20rpx;padding-bottom: 20rpx;margin-top: 40rpx;">
|
||
<view class="flx flx_sb title_box flx_ac">
|
||
<view class="title" >
|
||
目标
|
||
</view>
|
||
<view class="more" style="font-size: 24rpx;">
|
||
8 小时
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="" style="height: 40rpx;">
|
||
|
||
</view>
|
||
</view>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
import { mapGetters } from "vuex";
|
||
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
|
||
export default {
|
||
data() {
|
||
return {
|
||
sleepData:{
|
||
shen:0,
|
||
qian:0,
|
||
kuai:0
|
||
},
|
||
isOption:false,
|
||
isInit:false,
|
||
exitSleepTime:[],
|
||
fallAsleepTime:[],
|
||
option:{
|
||
tooltip: {
|
||
show:false
|
||
},
|
||
legend: {
|
||
top: '5%',
|
||
left: 'center'
|
||
},
|
||
series: [
|
||
{
|
||
data:[],
|
||
type: 'pie',
|
||
radius: ['70%', '90%'],
|
||
avoidLabelOverlap: false,
|
||
labelLine: {
|
||
show: false
|
||
},
|
||
}
|
||
]
|
||
},
|
||
cavasConfig:{
|
||
canvasWidth: 250,
|
||
canvasHeight: 250,
|
||
lineWidth:20,
|
||
radius: 68, // 内圆的半径
|
||
startAngle: -90, // 起始角度,-90度,即垂直方向的3点钟位置
|
||
bigRadius:90,// 外圆的半径
|
||
cxt:null,
|
||
colorBg:'#f7c1f5',
|
||
bigColorBg:'#d1ccf4',
|
||
color:'#e933dd',
|
||
bigColor:'#6452da',
|
||
bigAngle:0,
|
||
angle:0,
|
||
startSmallAngle:0,
|
||
bigStartAngle:0,
|
||
stop:0,
|
||
bigStop:0,
|
||
maxTime:480
|
||
},
|
||
sleepList:[],
|
||
time: new Date().toISOString().substring(0, 10),
|
||
sleep:{
|
||
shen:'0 分',
|
||
qian:'0 分'
|
||
}
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.getDataList()
|
||
},
|
||
watch:{
|
||
isInit(newVal,oldVal){
|
||
if(this.isOption == true){
|
||
this.doDrawPie()
|
||
}
|
||
},
|
||
isOption(newVal,oldVal){
|
||
if(this.isInit == true){
|
||
this.doDrawPie()
|
||
}
|
||
}
|
||
},
|
||
onReady() {
|
||
this.cavasConfig.ctx = uni.createCanvasContext('circleCanvas', this);
|
||
this.drawCircle('bottom',360,this.cavasConfig.bigRadius,this.cavasConfig.bigColorBg);
|
||
this.drawCircle('bottom',360,this.cavasConfig.radius,this.cavasConfig.colorBg);
|
||
|
||
},
|
||
computed: {
|
||
...mapGetters({
|
||
getActiceDevice: "api/getActiceDevice"
|
||
})
|
||
},
|
||
methods: {
|
||
async init() {
|
||
this.isInit = true
|
||
|
||
|
||
},
|
||
async doDrawPie(){
|
||
const chart = await this.$refs.chartRef.init(echarts);
|
||
chart.setOption(this.option)
|
||
},
|
||
countOccurrences(array, value) {
|
||
return array.reduce((count, current) => {
|
||
return current === value ? count + 1 : count;
|
||
}, 0);
|
||
},
|
||
back() {
|
||
uni.navigateBack({
|
||
delta: 1
|
||
})
|
||
},
|
||
|
||
getDataList(){
|
||
let type = 'SleepDatas'
|
||
let res = this.$store.dispatch('api/getDeviceListDays', {
|
||
type: type,
|
||
// type: (this.type),
|
||
device_real_time: this.time,
|
||
device_id:this.getActiceDevice.device_id
|
||
}).then(res => {
|
||
|
||
if(res.data.length > 0){
|
||
this.sleep.shen = this.min2Hour(res.data[0].data_msg[0].sleepTotalTime)
|
||
this.sleep.qian = this.min2Hour(res.data[0].data_msg[0].deepSleepTime)
|
||
this.cavasConfig.angle = this.getAngle(res.data[0].data_msg[0].deepSleepTime)
|
||
this.cavasConfig.bigAngle = this.getAngle(res.data[0].data_msg[0].sleepTotalTime)
|
||
this.sleepList = res.data[0].data_msg[0].sleepCurve
|
||
this.option.series[0].data = [
|
||
{
|
||
value:this.countOccurrences(this.sleepList,0),
|
||
itemStyle:{
|
||
color:'#e933dd'
|
||
}
|
||
},
|
||
{
|
||
value:this.countOccurrences(this.sleepList,1),
|
||
itemStyle:{
|
||
color:'#6452da'
|
||
}
|
||
},
|
||
{
|
||
value:this.countOccurrences(this.sleepList,2),
|
||
itemStyle:{
|
||
color:'#4faffc'
|
||
}
|
||
},
|
||
];
|
||
let len = this.sleepList.length
|
||
this.sleepData.shen = this.getPercent(this.sleepList,0)
|
||
this.sleepData.qian = this.getPercent(this.sleepList,1)
|
||
this.sleepData.kuai = this.getPercent(this.sleepList,2)
|
||
this.exitSleepTime = res.data[0].data_msg[0].exitSleepTime.split('-')
|
||
this.fallAsleepTime = res.data[0].data_msg[0].fallAsleepTime.split('-')
|
||
this.isOption = true
|
||
}
|
||
this.doAnimation(0)
|
||
this.doAnimation(1)
|
||
})
|
||
|
||
|
||
},
|
||
getPercent(data,find){
|
||
let len = data.length
|
||
return (this.countOccurrences(data,find) / len * 100).toFixed(1)
|
||
},
|
||
getAngle(min){
|
||
return min/this.cavasConfig.maxTime * 360
|
||
},
|
||
min2Hour(min){
|
||
let hour = (Math.floor(min / 60))
|
||
let minute = (min % 60)
|
||
return (hour?hour + ' 小时 ' + minute+ ' 分':minute+ ' 分')
|
||
},
|
||
doAnimation(type){
|
||
if(type == 0){
|
||
if(this.cavasConfig.bigStop === 1){
|
||
return
|
||
}
|
||
if(this.cavasConfig.bigStartAngle >= this.cavasConfig.bigAngle){
|
||
this.cavasConfig.bigStartAngle = this.cavasConfig.bigAngle
|
||
this.cavasConfig.bigStop = 1;
|
||
}else{
|
||
this.cavasConfig.bigStartAngle += this.cavasConfig.bigAngle/50
|
||
}
|
||
this.drawCircle('round',this.cavasConfig.bigStartAngle,this.cavasConfig.bigRadius,this.cavasConfig.bigColor);
|
||
}else{
|
||
if(this.cavasConfig.stop == 1){
|
||
return
|
||
}
|
||
if(this.cavasConfig.startSmallAngle >= this.cavasConfig.angle){
|
||
this.cavasConfig.startSmallAngle = this.cavasConfig.angle
|
||
this.cavasConfig.stop = 1;
|
||
}else{
|
||
this.cavasConfig.startSmallAngle += this.cavasConfig.angle/50
|
||
}
|
||
this.drawCircle('round',this.cavasConfig.startSmallAngle,this.cavasConfig.radius,this.cavasConfig.color);
|
||
}
|
||
// window.requestAnimationFrame(() => {
|
||
setTimeout(() => {
|
||
this.doAnimation(type)
|
||
},(17))
|
||
|
||
// })
|
||
},
|
||
// lineCap线条类型 edangle绘制角度 radius 直径 color 线条颜色
|
||
drawCircle(lineCap,edangle,radius,color) {
|
||
this.cavasConfig.ctx.save()
|
||
const cx = this.cavasConfig.canvasWidth / 2
|
||
const cy = this.cavasConfig.canvasHeight / 2
|
||
this.cavasConfig.ctx.translate(cx,cy)
|
||
this.cavasConfig.ctx.scale(1, 1);
|
||
this.cavasConfig.ctx.lineCap = lineCap
|
||
let start = this.cavasConfig.startAngle*Math.PI/180
|
||
let end = (edangle+this.cavasConfig.startAngle)*Math.PI/180
|
||
this.cavasConfig.ctx.beginPath()
|
||
this.cavasConfig.ctx.arc(0,0, radius , start, end);
|
||
this.cavasConfig.ctx.lineWidth = this.cavasConfig.lineWidth; // 设置线宽
|
||
this.cavasConfig.ctx.strokeStyle = color; // 设置绘制样式为蓝色
|
||
this.cavasConfig.ctx.stroke(); // 绘制路径
|
||
this.cavasConfig.ctx.closePath()
|
||
this.cavasConfig.ctx.restore()
|
||
this.cavasConfig.ctx.draw(true)
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.dian0{
|
||
background-color: #e933dd;
|
||
}
|
||
.dian1{
|
||
background-color: #6452da;
|
||
}
|
||
.dian2{
|
||
background-color: #4faffc;
|
||
}
|
||
.c0{
|
||
color: #e933dd;
|
||
font-size: 26rpx;
|
||
}
|
||
.c1{
|
||
color: #6452da;
|
||
font-size: 26rpx;
|
||
}
|
||
.c2{
|
||
color: #4faffc;
|
||
font-size: 26rpx;
|
||
}
|
||
.yuan{
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-radius: 50%;
|
||
}
|
||
.small-title{
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
.canvas_box{
|
||
background-color: #fff;
|
||
padding: 20rpx;
|
||
.circle {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
|
||
margin: 0 auto;
|
||
border-radius: 50%;
|
||
margin: 0 10rpx;
|
||
}
|
||
.sleep_info{
|
||
|
||
.info_title{
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
.info_val{
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
.title_box{
|
||
margin-bottom: 20rpx;
|
||
.title{
|
||
font-size: 28rpx;
|
||
}
|
||
.more{
|
||
color: #999;
|
||
}
|
||
}
|
||
</style>
|