feat: 增加个人信息模块
This commit is contained in:
2
env/.env
vendored
2
env/.env
vendored
@@ -1,4 +1,4 @@
|
|||||||
VITE_APP_TITLE = 'unibest'
|
VITE_APP_TITLE = '健康记'
|
||||||
VITE_APP_PORT = 9000
|
VITE_APP_PORT = 9000
|
||||||
|
|
||||||
VITE_UNI_APPID = '__UNI__D1E5001'
|
VITE_UNI_APPID = '__UNI__D1E5001'
|
||||||
|
|||||||
BIN
favicon.ico
BIN
favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
10
package.json
10
package.json
@@ -19,11 +19,11 @@
|
|||||||
"description": "unibest - 最好的 uniapp 开发模板",
|
"description": "unibest - 最好的 uniapp 开发模板",
|
||||||
"generate-time": "用户创建项目时生成",
|
"generate-time": "用户创建项目时生成",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "feige996",
|
"name": "Cxx0822",
|
||||||
"zhName": "菲鸽",
|
"zhName": "Cxx",
|
||||||
"email": "1020103647@qq.com",
|
"email": "",
|
||||||
"github": "https://github.com/feige996",
|
"github": "",
|
||||||
"gitee": "https://gitee.com/feige996"
|
"gitee": ""
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://unibest.tech",
|
"homepage": "https://unibest.tech",
|
||||||
|
|||||||
65
src/components/Profile/ProfilePopup.vue
Normal file
65
src/components/Profile/ProfilePopup.vue
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<wd-popup
|
||||||
|
v-model="profileStore.showProfilePopup"
|
||||||
|
position="bottom"
|
||||||
|
:safe-area-inset-bottom="true"
|
||||||
|
custom-style="border-radius: 32rpx 32rpx 0 0; padding: 40rpx 32rpx 150rpx;"
|
||||||
|
>
|
||||||
|
<view class="mb-4 text-center text-base text-gray-700 font-semibold">
|
||||||
|
编辑个人信息
|
||||||
|
</view>
|
||||||
|
<wd-form :model="profileStore.profileForm" layout="horizontal" title-width="80" size="large" border>
|
||||||
|
<wd-form-item title="昵称" prop="name">
|
||||||
|
<wd-input v-model="profileStore.profileForm.name" placeholder="请输入昵称" />
|
||||||
|
</wd-form-item>
|
||||||
|
<wd-form-item title="性别" prop="gender">
|
||||||
|
<wd-radio-group v-model="profileStore.profileForm.gender" type="button">
|
||||||
|
<wd-radio value="male">
|
||||||
|
男
|
||||||
|
</wd-radio>
|
||||||
|
<wd-radio value="female">
|
||||||
|
女
|
||||||
|
</wd-radio>
|
||||||
|
</wd-radio-group>
|
||||||
|
</wd-form-item>
|
||||||
|
<wd-form-item title="身高" prop="height">
|
||||||
|
<view class="flex items-center gap-2">
|
||||||
|
<wd-input v-model.number="profileStore.profileForm.height" type="number" placeholder="请输入身高" />
|
||||||
|
<text class="shrink-0 text-sm text-gray-400">cm</text>
|
||||||
|
</view>
|
||||||
|
</wd-form-item>
|
||||||
|
<wd-form-item title="体重" prop="weight">
|
||||||
|
<view class="flex items-center gap-2">
|
||||||
|
<wd-input v-model.number="profileStore.profileForm.weight" type="number" placeholder="请输入体重" />
|
||||||
|
<text class="shrink-0 text-sm text-gray-400">Kg</text>
|
||||||
|
</view>
|
||||||
|
</wd-form-item>
|
||||||
|
</wd-form>
|
||||||
|
|
||||||
|
<wd-button type="primary" class="mt-10 w-full" @click="saveProfileClick">
|
||||||
|
保存
|
||||||
|
</wd-button>
|
||||||
|
</wd-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { saveProfile } from '@/utils/profile'
|
||||||
|
|
||||||
|
import { useProfileStore } from '@/store/profile'
|
||||||
|
|
||||||
|
const profileStore = useProfileStore()
|
||||||
|
|
||||||
|
function saveProfileClick() {
|
||||||
|
const { name } = profileStore.profileForm
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
uni.showToast({ title: '请输入昵称', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
saveProfile(profileStore.profileForm)
|
||||||
|
profileStore.showProfilePopup = false
|
||||||
|
profileStore.isRefresh = !profileStore.isRefresh
|
||||||
|
uni.showToast({ title: '保存信息成功', icon: 'success' })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -10,11 +10,8 @@
|
|||||||
{{ today }}
|
{{ today }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="h-9 w-9 flex items-center justify-center rounded-full bg-[#07c160]">
|
|
||||||
<text class="text-lg">
|
<wd-img :width="40" :height="40" :src="imgURL" />
|
||||||
🩺
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -53,12 +50,13 @@
|
|||||||
<text class="text-lg">{{ plan.icon }}</text>
|
<text class="text-lg">{{ plan.icon }}</text>
|
||||||
<text class="text-sm">{{ plan.label }}</text>
|
<text class="text-sm">{{ plan.label }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view
|
|
||||||
class="h-5 w-5 flex items-center justify-center border-2 rounded-full"
|
<wd-tag v-if="plan.done" type="success" round>
|
||||||
:class="plan.done ? 'bg-[#07c160] border-[#07c160]' : 'border-gray-300'"
|
已完成
|
||||||
>
|
</wd-tag>
|
||||||
<text v-if="plan.done" class="text-xs text-white">✓</text>
|
<wd-tag v-else type="danger" round>
|
||||||
</view>
|
未完成
|
||||||
|
</wd-tag>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="idx < plans.length - 1" class="h-1px w-full bg-[#f2f4f3]" />
|
<view v-if="idx < plans.length - 1" class="h-1px w-full bg-[#f2f4f3]" />
|
||||||
</view>
|
</view>
|
||||||
@@ -79,8 +77,9 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useRecordStore } from '@/store/record'
|
import { useRecordStore } from '@/store/record'
|
||||||
|
import type { IHealthRecord } from '@/utils/record'
|
||||||
import { getDateStr, getDayRecords } from '@/utils/record'
|
import { getDateStr, getDayRecords } from '@/utils/record'
|
||||||
import type { IHealthRecord } from '@/types/record'
|
import appImage from '@/static/images/app.png'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
@@ -93,6 +92,8 @@ definePage({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const imgURL = appImage
|
||||||
|
|
||||||
const recordStore = useRecordStore()
|
const recordStore = useRecordStore()
|
||||||
|
|
||||||
const todayRecords = ref<IHealthRecord[]>([])
|
const todayRecords = ref<IHealthRecord[]>([])
|
||||||
|
|||||||
@@ -1,13 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="mt-10 text-center text-green-500">
|
<view class="min-h-screen bg-[#f2f4f3] pb-10">
|
||||||
我的页面
|
<wd-card title="个人信息" type="rectangle">
|
||||||
|
<view class="flex items-center gap-4">
|
||||||
|
<wd-avatar :text="profile.name ? profile.name.charAt(0).toUpperCase() : '我'" bg-color="#8b5cf6" />
|
||||||
|
|
||||||
|
<view class="flex flex-col">
|
||||||
|
<text class="text-lg text-gray-800 font-semibold">
|
||||||
|
{{ profile.name || '未设置姓名' }}
|
||||||
|
</text>
|
||||||
|
<text class="mt-0.5 text-xs text-gray-400">
|
||||||
|
{{ genderText }} · {{ profile.height ? `${profile.height} cm` : '身高未填' }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="ml-auto">
|
||||||
|
<wd-button size="small" plain type="primary" @click="openProfile">
|
||||||
|
编辑
|
||||||
|
</wd-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</wd-card>
|
||||||
|
|
||||||
|
<profile-popup />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import type { IProfile } from '@/utils/profile'
|
||||||
|
import { getProfile } from '@/utils/profile'
|
||||||
|
import { useProfileStore } from '@/store/profile'
|
||||||
|
import ProfilePopup from '@/components/Profile/ProfilePopup.vue'
|
||||||
|
|
||||||
definePage({
|
definePage({
|
||||||
style: {
|
style: { navigationBarTitleText: '我的' },
|
||||||
navigationBarTitleText: '我的',
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const profileStore = useProfileStore()
|
||||||
|
|
||||||
|
const profile = ref<IProfile>(getProfile())
|
||||||
|
|
||||||
|
const genderText = computed(() => {
|
||||||
|
if (profile.value.gender === 'male')
|
||||||
|
return '男'
|
||||||
|
if (profile.value.gender === 'female')
|
||||||
|
return '女'
|
||||||
|
|
||||||
|
return '性别未填'
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => profileStore.isRefresh, () => {
|
||||||
|
profile.value = getProfile()
|
||||||
|
})
|
||||||
|
|
||||||
|
function openProfile() {
|
||||||
|
Object.assign(profileStore.profileForm, profile.value)
|
||||||
|
|
||||||
|
profileStore.showProfilePopup = true
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -18,10 +18,7 @@
|
|||||||
|
|
||||||
<!-- 时间轴区域 -->
|
<!-- 时间轴区域 -->
|
||||||
<view class="px-5 py-2">
|
<view class="px-5 py-2">
|
||||||
<view v-if="grouped.length === 0" class="py-16 text-center">
|
<wd-empty v-if="grouped.length === 0" icon="no-content" tip="暂无内容" />
|
||||||
<text class="text-4xl">📭</text>
|
|
||||||
<text class="mt-3 block text-sm text-gray-400">暂无记录</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 外层:每个日期分组 -->
|
<!-- 外层:每个日期分组 -->
|
||||||
<view v-for="group in grouped" :key="group.date" class="mb-6">
|
<view v-for="group in grouped" :key="group.date" class="mb-6">
|
||||||
@@ -54,8 +51,8 @@
|
|||||||
<view class="rounded-xl bg-white p-3.5 shadow-sm">
|
<view class="rounded-xl bg-white p-3.5 shadow-sm">
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
<text class="text-xs text-gray-400 font-mono">{{ item.time }}</text>
|
<text class="text-xs text-gray-400 font-mono">{{ item.time }}</text>
|
||||||
<wd-tag type="primary" round>
|
<wd-tag :type="getRecordStatus(item).type" round>
|
||||||
{{ getRecordStatus(item) }}
|
{{ getRecordStatus(item).label }}
|
||||||
</wd-tag>
|
</wd-tag>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -80,36 +77,6 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- AI 分析模块(最底部) -->
|
|
||||||
<view class="px-4 pb-8">
|
|
||||||
<view class="rounded-2xl from-[#07c160] to-[#2baa5e] bg-gradient-to-br p-4 shadow-sm">
|
|
||||||
<!-- 标题行 -->
|
|
||||||
<view class="flex items-center justify-between">
|
|
||||||
<view class="flex items-center gap-2">
|
|
||||||
<text class="text-base">🤖</text>
|
|
||||||
<text class="text-sm text-white font-semibold">AI 健康分析</text>
|
|
||||||
</view>
|
|
||||||
<text class="text-[10px] text-white/70">{{ aiSummary.dateRange }}</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 摘要 -->
|
|
||||||
<text class="mt-2.5 block text-sm text-white/95 leading-relaxed">
|
|
||||||
{{ aiSummary.text }}
|
|
||||||
</text>
|
|
||||||
|
|
||||||
<!-- 标签 -->
|
|
||||||
<view class="mt-3 flex flex-wrap gap-1.5">
|
|
||||||
<text
|
|
||||||
v-for="(tag, tIdx) in aiSummary.tags"
|
|
||||||
:key="tIdx"
|
|
||||||
class="rounded-full bg-white/20 px-2.5 py-1 text-[10px] text-white"
|
|
||||||
>
|
|
||||||
{{ tag }}
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 日期选择器 -->
|
<!-- 日期选择器 -->
|
||||||
<wd-datetime-picker
|
<wd-datetime-picker
|
||||||
v-model="currentDate"
|
v-model="currentDate"
|
||||||
@@ -122,9 +89,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { getMonthRecords, getMonthStr, getRecordMeta, getRecordStatus, getRecordValue, groupByDate } from '@/utils/record'
|
import type { IHealthRecord } from '@/utils/record'
|
||||||
import type { IHealthRecord } from '@/types/record'
|
import {
|
||||||
|
getMonthRecords,
|
||||||
|
getMonthStr,
|
||||||
|
getRecordMeta,
|
||||||
|
getRecordStatus,
|
||||||
|
getRecordValue,
|
||||||
|
groupByDate,
|
||||||
|
} from '@/utils/record'
|
||||||
|
|
||||||
definePage({
|
definePage({
|
||||||
style: {
|
style: {
|
||||||
@@ -151,7 +125,7 @@ function loadRecords() {
|
|||||||
grouped.value = groupByDate(all)
|
grouped.value = groupByDate(all)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onShow(() => {
|
||||||
loadRecords()
|
loadRecords()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -175,12 +149,6 @@ function openDatePicker() {
|
|||||||
function onDateConfirm({ value }) {
|
function onDateConfirm({ value }) {
|
||||||
loadRecords()
|
loadRecords()
|
||||||
}
|
}
|
||||||
|
|
||||||
const aiSummary = ref({
|
|
||||||
dateRange: '基于今日数据',
|
|
||||||
text: '今日整体健康状态良好。体重平稳,血压正常,建议增加有氧运动频率,保持当前作息规律。',
|
|
||||||
tags: ['🟢 体重稳定', '❤️ 血压正常', '🏃 建议多运动', '😴 睡眠良好'],
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
BIN
src/static/images/app.png
Normal file
BIN
src/static/images/app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
@@ -1,33 +1 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1787537238233" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7270" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M779.84 64c71.936 0 133.568 53.888 133.568 125.824V855.04c0 71.936-61.632 133.568-133.568 133.568H243.008c-71.936 0-125.824-61.632-125.824-133.568v-72.448h73.6c42.496 0 76.992-34.56 76.992-77.056v-50.24c0-42.56-34.496-77.056-76.992-77.056H117.12V474.752h73.6c42.496 0 76.992-34.496 76.992-76.992v-50.304c0-42.496-34.496-76.992-76.992-76.992H117.12v-80.64C117.12 117.888 171.072 64 243.008 64z m-71.872 669.12H399.68a25.728 25.728 0 0 0 0 51.456h308.16a25.664 25.664 0 0 0 0.128-51.456z m-539.52-104.128c28.288 0 51.456 23.104 51.456 51.392a51.52 51.52 0 0 1-51.456 51.392H117.12a51.52 51.52 0 0 1-51.392-51.392c0-28.288 23.104-51.392 51.392-51.392z m539.52-49.92H399.68a25.728 25.728 0 1 0 0 51.328h308.16a25.728 25.728 0 0 0 0.128-51.392zM621.376 238.592c-31.744 0-57.344 16.704-69.632 27.648-13.312-11.968-38.912-27.648-69.44-27.648-46.72 0-98.048 77.568-12.16 150.08 22.464 19.136 36.096 25.408 48.384 36.032 20.16 17.6 28.032 24.768 31.232 27.904l1.536 1.536c0.384 0.448 19.648-11.84 39.808-29.44 12.608-11.008 21.696-13.44 48.384-36.032 85.952-72.512 28.608-150.08-18.112-150.08zM166.784 320.768c28.288 0 51.456 23.104 51.456 51.392a51.52 51.52 0 0 1-51.456 51.392h-51.392A51.648 51.648 0 0 1 64 372.16c0-28.288 23.104-51.392 51.392-51.392z" fill="#8b5cf6" p-id="7271"></path></svg>
|
||||||
<svg id="_图层_2" data-name="图层 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 113.39 113.39">
|
|
||||||
<defs>
|
|
||||||
<style>
|
|
||||||
.cls-1 {
|
|
||||||
fill: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cls-2 {
|
|
||||||
fill: #d14328;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cls-3 {
|
|
||||||
fill: #2c8d3a;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</defs>
|
|
||||||
<g id="_图层_1-2" data-name="图层 1">
|
|
||||||
<g>
|
|
||||||
<rect class="cls-1" width="113.39" height="113.39" />
|
|
||||||
<g>
|
|
||||||
<path class="cls-3"
|
|
||||||
d="M86.31,11.34H25.08c-8.14,0-14.74,6.6-14.74,14.74v61.23c0,8.14,6.6,14.74,14.74,14.74h61.23c.12,0,.24-.02,.37-.02-9.76-.2-17.64-8.18-17.64-17.99,0-.56,.03-1.12,.08-1.67H34.1c-1.57,0-2.83-1.27-2.83-2.83V32.43c0-.78,.63-1.42,1.42-1.42h9.17c.78,0,1.42,.63,1.42,1.42v36.52c0,.78,.63,1.42,1.42,1.42h22.02c.78,0,1.42-.63,1.42-1.42V32.43c0-.78,.63-1.42,1.42-1.42h9.17c.78,0,1.42,.63,1.42,1.42v34.99c2.13-.89,4.47-1.39,6.92-1.39,5.66,0,10.7,2.63,14.01,6.72V26.08c0-8.14-6.6-14.74-14.74-14.74Z" />
|
|
||||||
<g>
|
|
||||||
<path class="cls-2"
|
|
||||||
d="M87.04,68.03c-8.83,0-16.01,7.18-16.01,16.01s7.18,16.01,16.01,16.01,16.01-7.18,16.01-16.01-7.18-16.01-16.01-16.01Zm-.27,24.84h-7.2v-3h1.18v-10.48h4.58v2.81h1.42c.84,0,1.46-.16,1.88-.48s.62-.87,.62-1.64c0-.69-.25-1.17-.74-1.45s-1.19-.42-2.09-.42h-6.84v-3h7.2c2.38,0,4.15,.38,5.31,1.15,1.16,.77,1.74,1.93,1.74,3.48,0,1.71-.83,2.93-2.5,3.64,1.07,.4,1.87,.95,2.39,1.65s.79,1.56,.79,2.58c0,3.44-2.58,5.16-7.73,5.16Z" />
|
|
||||||
<path class="cls-2"
|
|
||||||
d="M86.49,85.17h-1.16v4.7h1.8c.81,0,1.46-.18,1.94-.55s.72-.95,.72-1.73c0-.86-.25-1.48-.74-1.85s-1.35-.56-2.56-.56Z" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
18
src/store/profile.ts
Normal file
18
src/store/profile.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import type { IProfile } from '@/utils/profile'
|
||||||
|
|
||||||
|
export const useProfileStore = defineStore('profile', {
|
||||||
|
state: () => ({
|
||||||
|
showProfilePopup: false,
|
||||||
|
profileForm: {
|
||||||
|
gender: '',
|
||||||
|
height: 0,
|
||||||
|
name: '',
|
||||||
|
weight: 0,
|
||||||
|
} as IProfile,
|
||||||
|
isRefresh: false,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
||||||
25
src/utils/profile.ts
Normal file
25
src/utils/profile.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export interface IProfile {
|
||||||
|
name: string
|
||||||
|
gender: 'male' | 'female' | ''
|
||||||
|
height: number | null
|
||||||
|
weight: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const PROFILE_KEY = 'user_profile'
|
||||||
|
|
||||||
|
function getEmptyProfile(): IProfile {
|
||||||
|
return {
|
||||||
|
gender: '',
|
||||||
|
height: null,
|
||||||
|
name: '',
|
||||||
|
weight: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getProfile(): IProfile {
|
||||||
|
return wx.getStorageSync(PROFILE_KEY) || getEmptyProfile()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveProfile(data: IProfile) {
|
||||||
|
wx.setStorageSync(PROFILE_KEY, data)
|
||||||
|
}
|
||||||
@@ -1,4 +1,23 @@
|
|||||||
import type { IHealthRecord, IRecordMeta } from '@/types/record'
|
import { getProfile } from '@/utils/profile'
|
||||||
|
|
||||||
|
export interface IHealthRecord {
|
||||||
|
id: string
|
||||||
|
type: string
|
||||||
|
time: string
|
||||||
|
date?: string
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRecordMeta {
|
||||||
|
icon: string
|
||||||
|
label: string
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRecordStats {
|
||||||
|
label: string
|
||||||
|
type: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'volcano' | 'lightblue' | 'cyan' | 'pink' | 'purple'
|
||||||
|
}
|
||||||
|
|
||||||
const MONTH_KEEP = 12
|
const MONTH_KEEP = 12
|
||||||
|
|
||||||
@@ -161,48 +180,78 @@ export function getRecordValue(record: IHealthRecord): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRecordStatus(record: IHealthRecord): string {
|
export function getRecordStatus(record: IHealthRecord): IRecordStats {
|
||||||
|
const profile = getProfile()
|
||||||
|
|
||||||
switch (record.type) {
|
switch (record.type) {
|
||||||
case 'bloodPressure':
|
case 'bloodPressure':
|
||||||
if (record.systolic >= 140 || record.diastolic >= 90)
|
if (record.systolic >= 140 || record.diastolic >= 90) {
|
||||||
return '偏高'
|
return { label: '偏高', type: 'danger' }
|
||||||
if (record.systolic < 90 || record.diastolic < 60)
|
|
||||||
return '偏低'
|
|
||||||
return '正常'
|
|
||||||
|
|
||||||
case 'bloodSugar':
|
|
||||||
if (record.period.includes('空腹')) {
|
|
||||||
return record.value >= 6.1 ? '偏高' : '正常'
|
|
||||||
}
|
}
|
||||||
// 餐后
|
if (record.systolic < 90 || record.diastolic < 60) {
|
||||||
return record.value >= 7.8 ? '偏高' : '正常'
|
return { label: '偏低', type: 'danger' }
|
||||||
|
}
|
||||||
|
return { label: '正常', type: 'primary' }
|
||||||
|
|
||||||
|
case 'weight': {
|
||||||
|
if (!profile.height) {
|
||||||
|
return { label: '身高未知', type: 'default' }
|
||||||
|
}
|
||||||
|
const bmi = (record.value * 10000) / (profile.height * profile.height)
|
||||||
|
if (bmi < 18.5)
|
||||||
|
return { label: '偏瘦', type: 'warning' }
|
||||||
|
if (bmi < 24)
|
||||||
|
return { label: '正常', type: 'primary' }
|
||||||
|
if (bmi < 28)
|
||||||
|
return { label: '偏重', type: 'danger' }
|
||||||
|
return { label: '肥胖', type: 'danger' }
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'bloodSugar': {
|
||||||
|
const period = record.period || ''
|
||||||
|
let limit = 11.1
|
||||||
|
if (period.includes('空腹') || period.includes('睡前'))
|
||||||
|
limit = 6.1
|
||||||
|
else if (period.includes('餐后1h'))
|
||||||
|
limit = 11.1
|
||||||
|
else if (period.includes('餐后2h'))
|
||||||
|
limit = 7.8
|
||||||
|
|
||||||
|
if (record.value < 3.9)
|
||||||
|
return { label: '偏低', type: 'danger' }
|
||||||
|
if (record.value >= limit)
|
||||||
|
return { label: '偏高', type: 'danger' }
|
||||||
|
return { label: '正常', type: 'primary' }
|
||||||
|
}
|
||||||
|
|
||||||
case 'heartRate':
|
case 'heartRate':
|
||||||
if (record.value < 60)
|
if (record.value < 60)
|
||||||
return '偏慢'
|
return { label: '偏慢', type: 'warning' }
|
||||||
if (record.value <= 100)
|
if (record.value <= 100)
|
||||||
return '正常'
|
return { label: '正常', type: 'primary' }
|
||||||
return '偏快'
|
return { label: '偏快', type: 'warning' }
|
||||||
|
|
||||||
case 'temperature':
|
case 'temperature':
|
||||||
if (record.value < 36.1)
|
if (record.value < 36.1)
|
||||||
return '偏低'
|
return { label: '偏低', type: 'warning' }
|
||||||
if (record.value <= 37.2)
|
if (record.value <= 37.2)
|
||||||
return '正常'
|
return { label: '正常', type: 'primary' }
|
||||||
return '偏高'
|
return { label: '偏高', type: 'danger' }
|
||||||
|
|
||||||
case 'sport':
|
case 'sport':
|
||||||
return record.duration >= 30 ? '达标' : '偏少'
|
return record.duration >= 30
|
||||||
|
? { label: '达标', type: 'success' }
|
||||||
|
: { label: '偏少', type: 'warning' }
|
||||||
|
|
||||||
case 'sleep':
|
case 'sleep':
|
||||||
if (record.duration >= 7)
|
if (record.duration >= 7)
|
||||||
return '充足'
|
return { label: '充足', type: 'success' }
|
||||||
if (record.duration >= 6)
|
if (record.duration >= 6)
|
||||||
return '良好'
|
return { label: '良好', type: 'primary' }
|
||||||
return '不足'
|
return { label: '不足', type: 'warning' }
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return '未知'
|
return { label: '未知', type: 'default' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user