160 lines
4.8 KiB
Vue
160 lines
4.8 KiB
Vue
<template>
|
||
<view class="min-h-screen bg-[#f2f4f3]">
|
||
<view class="sticky top-0 z-10 flex flex-col gap-2 bg-white p-2">
|
||
<view class="flex items-center justify-evenly">
|
||
<wd-button icon="caret-left" type="primary" :round="true" size="small" @click="changeMonth(-1)" />
|
||
<view class="flex flex-col items-center" @click="openDatePicker">
|
||
<text class="text-base text-gray-800 font-semibold">{{ displayDate }}</text>
|
||
</view>
|
||
<wd-button icon="caret-right" type="primary" :round="true" size="small" @click="changeMonth(1)" />
|
||
|
||
<wd-button type="primary" size="small" @click="goToday">
|
||
回到今天
|
||
</wd-button>
|
||
</view>
|
||
|
||
<wd-segmented v-model:value="current" :options="list"/>
|
||
</view>
|
||
|
||
<!-- 时间轴区域 -->
|
||
<view class="px-5 py-2">
|
||
<wd-empty v-if="grouped.length === 0" icon="no-content" tip="暂无记录" />
|
||
|
||
<!-- 外层:每个日期分组 -->
|
||
<view v-for="group in grouped" :key="group.date" class="mb-6">
|
||
<!-- 日期分类标题 -->
|
||
<view class="mb-2 flex items-center gap-2 pl-1">
|
||
<text class="text-sm text-gray-500 font-medium">{{ group.date }}</text>
|
||
<text class="text-xs text-gray-400">周{{ group.weekday }}</text>
|
||
<view class="ml-2 h-[1px] flex-1 bg-gray-200" />
|
||
</view>
|
||
|
||
<!-- 该日期下的时间轴 -->
|
||
<view class="relative pl-6">
|
||
<view
|
||
class="absolute bottom-1 top-1 w-[2px] from-[#07c160] via-[#2E5B8C] to-[#dde3e0] bg-gradient-to-b"
|
||
style="left: 0;"
|
||
/>
|
||
|
||
<view
|
||
v-for="(item, idx) in group.items"
|
||
:key="item.id || idx"
|
||
class="relative mb-5 last:mb-0"
|
||
>
|
||
<view
|
||
class="absolute border-[2.5px] border-white rounded-full shadow-sm"
|
||
style="width: 14px; height: 14px; left: -30px; top: 0; z-index: 2;"
|
||
:class="getRecordMeta(item.type).color"
|
||
/>
|
||
|
||
<!-- 卡片 -->
|
||
<view class="rounded-xl bg-white p-3.5 shadow-sm">
|
||
<view class="flex items-center justify-between">
|
||
<text class="text-xs text-gray-400 font-mono">{{ item.time }}</text>
|
||
<wd-tag :type="getRecordStatus(item).type" round>
|
||
{{ getRecordStatus(item).label }}
|
||
</wd-tag>
|
||
</view>
|
||
|
||
<view class="mt-1.5 flex items-center gap-2">
|
||
<view
|
||
class="h-7 w-7 flex items-center justify-center rounded-lg text-sm"
|
||
:class="getRecordMeta(item.type).color"
|
||
>
|
||
<text>{{ getRecordMeta(item.type).icon }}</text>
|
||
</view>
|
||
<text class="text-sm text-gray-700 font-medium">{{ getRecordMeta(item.type).label }}</text>
|
||
</view>
|
||
|
||
<text class="mt-1.5 block text-xl text-gray-800 font-bold">{{ getRecordValue(item) }}</text>
|
||
|
||
<text v-if="item.note" class="mt-0.5 block text-xs text-gray-400 leading-relaxed">
|
||
{{ item.note }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 日期选择器 -->
|
||
<wd-datetime-picker
|
||
v-model="currentDate"
|
||
v-model:visible="showDatePicker"
|
||
type="year-month"
|
||
:max-date="Date.now()"
|
||
@confirm="onDateConfirm"
|
||
/>
|
||
</view>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { computed, ref } from 'vue'
|
||
import {
|
||
getMonthRecords,
|
||
getMonthStr,
|
||
getRecordMeta,
|
||
getRecordStatus,
|
||
getRecordValue,
|
||
groupByDate,
|
||
} from '@/utils/record'
|
||
import { onShow } from "@dcloudio/uni-app";
|
||
import type { IHealthRecord } from "@/type/record";
|
||
|
||
const currentDate = ref(Date.now())
|
||
const showDatePicker = ref(false)
|
||
const list = ref<string[]>(['所有', '体重', '睡眠', '运动', '血压', '血糖', '心率'])
|
||
const current = ref('所有')
|
||
|
||
const displayDate = computed(() => {
|
||
const d = new Date(currentDate.value)
|
||
return `${d.getFullYear()}年${d.getMonth() + 1}月`
|
||
})
|
||
|
||
const records = ref<IHealthRecord[]>([])
|
||
const grouped = ref<ReturnType<typeof groupByDate>>([])
|
||
|
||
function loadRecords() {
|
||
const all = getMonthRecords(getMonthStr(currentDate.value))
|
||
records.value = all
|
||
grouped.value = groupByDate(all)
|
||
}
|
||
|
||
onShow(() => {
|
||
loadRecords()
|
||
})
|
||
|
||
function changeMonth(offset: number) {
|
||
const d = new Date(currentDate.value)
|
||
d.setMonth(d.getMonth() + offset)
|
||
currentDate.value = d.getTime()
|
||
|
||
loadRecords()
|
||
}
|
||
|
||
function goToday() {
|
||
currentDate.value = Date.now()
|
||
loadRecords()
|
||
}
|
||
|
||
function openDatePicker() {
|
||
showDatePicker.value = true
|
||
}
|
||
|
||
function onDateConfirm() {
|
||
loadRecords()
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
:deep(.wd-segmented) {
|
||
overflow: auto;
|
||
}
|
||
|
||
:deep(.wd-segmented__item) {
|
||
min-width: 60px;
|
||
flex-shrink: 0;
|
||
justify-content: center;
|
||
}
|
||
</style>
|