130 lines
4.5 KiB
Vue
130 lines
4.5 KiB
Vue
<template>
|
|
<div class="bill-chart common-chart"
|
|
v-loading="healthStore.isLoading"
|
|
element-loading-text="正在加载中...">
|
|
<div class="chart-container card-item">
|
|
<div class="content">
|
|
<span class="title">📊体重趋势</span>
|
|
</div>
|
|
<div class="chart" ref="weightDailyChartRef"/>
|
|
</div>
|
|
|
|
<div class="chart-container card-item">
|
|
<div class="content">
|
|
<span class="title">📊睡眠时长统计图</span>
|
|
</div>
|
|
<div class="chart" ref="sleepDailyChartRef"/>
|
|
</div>
|
|
|
|
<div class="chart-container card-item">
|
|
<div class="content">
|
|
<span class="title">📊运动时长统计</span>
|
|
</div>
|
|
<div class="chart" ref="healthDurationChartRef"/>
|
|
</div>
|
|
|
|
<div class="chart-container card-item">
|
|
<div class="content">
|
|
<span class="title">📊运动类别统计</span>
|
|
</div>
|
|
<div class="chart" ref="healthCategoryChartRef"/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onMounted, ref, watch } from 'vue'
|
|
import * as echarts from 'echarts'
|
|
import { lineChartOptions, barChartOptions, pieChartOptions } from 'vue3-common/utils/eChartsUtil'
|
|
import { useHealthStore } from '@/store/health'
|
|
import { useAppStore } from '@/store/app.ts'
|
|
import { formatDate } from 'vue3-common/utils/dateUtil'
|
|
|
|
const healthStore = useHealthStore()
|
|
const appStore = useAppStore()
|
|
|
|
const weightDailyChartRef = ref<HTMLElement>()
|
|
const sleepDailyChartRef = ref<HTMLElement>()
|
|
const healthDurationChartRef = ref<HTMLElement>()
|
|
const healthCategoryChartRef = ref<HTMLElement>()
|
|
|
|
let weightDailyChart: echarts.ECharts
|
|
let sleepDailyChart: echarts.ECharts
|
|
let healthDurationChart: echarts.ECharts
|
|
let healthCategoryChart: echarts.ECharts
|
|
|
|
watch(() => healthStore.isRefresh, () => {
|
|
updateChart()
|
|
})
|
|
|
|
onMounted(() => {
|
|
weightDailyChart = echarts.init(weightDailyChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
|
sleepDailyChart = echarts.init(sleepDailyChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
|
healthDurationChart = echarts.init(healthDurationChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
|
healthCategoryChart = echarts.init(healthCategoryChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
|
|
})
|
|
|
|
const updateChart = () => {
|
|
const MAX_CATEGORY_COUNT = 5
|
|
|
|
// 体重趋势统计图
|
|
const weightRecordList = healthStore.healthRecordList
|
|
.filter((item) => item.weight !== 0)
|
|
|
|
const weightXAxis = weightRecordList.map((item) => {
|
|
return formatDate(item.date, 'MM-DD')
|
|
}).reverse()
|
|
const weightYAxis = weightRecordList.map((item) => item.weight).reverse()
|
|
const sortedRecordList = weightRecordList.sort((a, b) => a.weight - b.weight)
|
|
|
|
weightDailyChart.setOption(lineChartOptions('日期', weightXAxis, '体重(千克)', weightYAxis))
|
|
|
|
if (sortedRecordList.length > 0) {
|
|
weightDailyChart.setOption({
|
|
yAxis: {
|
|
min: Math.floor(sortedRecordList[0].weight),
|
|
max: Math.ceil(sortedRecordList[sortedRecordList.length - 1].weight)
|
|
}
|
|
})
|
|
}
|
|
|
|
// 睡眠时长统计图
|
|
const sleepRecordList = healthStore.healthRecordList
|
|
.filter((item) => item.sleepDuration !== null)
|
|
.sort((a, b) => (a.date > b.date ? -1 : 1))
|
|
|
|
const sleepXAxis = sleepRecordList.map((item) => {
|
|
return formatDate(item.date, 'MM-DD')
|
|
}).reverse()
|
|
const sleepYAxis = sleepRecordList.map((item) => item.sleepDuration).reverse() as number[]
|
|
|
|
sleepDailyChart.setOption(barChartOptions('日期', sleepXAxis, '时间(小时)', sleepYAxis))
|
|
|
|
// 运动量统计图
|
|
const sportRecordList = healthStore.healthRecordList
|
|
.filter((item) => item.sportProject !== '')
|
|
.sort((a, b) => (a.date > b.date ? -1 : 1))
|
|
|
|
const durationXAxis = sportRecordList.map((item) => {
|
|
return formatDate(item.date, 'MM-DD')
|
|
}).reverse()
|
|
const durationYAxis = sportRecordList.map((item) => item.sportDuration).reverse()
|
|
|
|
healthDurationChart.setOption(barChartOptions('日期', durationXAxis, '时间(分钟)', durationYAxis))
|
|
|
|
// 类别统计图
|
|
const healthCategoryList = healthStore.healthRecordList.reduce((acc, item) => {
|
|
if (item.sportProject && item.sportDuration > 0) {
|
|
const existing = acc.find((project) => project.name === item.sportProject)
|
|
if (existing) {
|
|
existing.value += item.sportDuration
|
|
} else {
|
|
acc.push({ name: item.sportProject, value: item.sportDuration })
|
|
}
|
|
}
|
|
return acc
|
|
}, [])
|
|
healthCategoryChart.setOption(pieChartOptions('名称', '分钟', healthCategoryList.slice(0, MAX_CATEGORY_COUNT)))
|
|
}
|
|
</script>
|