feat: 更新每日记录模块

This commit is contained in:
2026-08-23 21:56:15 +08:00
parent af0f396ed8
commit 0d587ac241
5 changed files with 292 additions and 161 deletions

View File

@@ -39,7 +39,7 @@
<wd-form-item title="时长"> <wd-form-item title="时长">
<view class="py-1 text-gray-800"> <view class="py-1 text-gray-800">
{{ sleepDuration }} {{ sleepDuration }} 小时
</view> </view>
</wd-form-item> </wd-form-item>
@@ -106,22 +106,14 @@ const sleepDuration = computed(() => {
const end = recordStore.sleepForm.endTime const end = recordStore.sleepForm.endTime
if (!start || !end) if (!start || !end)
return '请选择开始和结束时间' return 0
const diffMs = new Date(end).getTime() - new Date(start).getTime() const diffMs = new Date(end).getTime() - new Date(start).getTime()
if (diffMs <= 0) if (diffMs <= 0)
return '结束时间需晚于开始时间' return 0
const totalMinutes = Math.floor(diffMs / 60000) return Math.round((diffMs / 3600000) * 10) / 10
const hours = Math.floor(totalMinutes / 60)
const minutes = totalMinutes % 60
if (hours > 0 && minutes > 0)
return `${hours}小时${minutes}分钟`
if (hours > 0)
return `${hours}小时`
return `${minutes}分钟`
}) })
function handeClosePopup() { function handeClosePopup() {
@@ -131,7 +123,7 @@ function handeClosePopup() {
} }
function saveSleep() { function saveSleep() {
const { startTime, endTime, time, note } = recordStore.sleepForm const { startTime, endTime, time } = recordStore.sleepForm
if (!startTime) { if (!startTime) {
uni.showToast({ title: '请选择开始时间', icon: 'none' }) uni.showToast({ title: '请选择开始时间', icon: 'none' })
@@ -150,6 +142,7 @@ function saveSleep() {
return return
} }
recordStore.sleepForm.duration = sleepDuration.value
recordStore.submitSleep() recordStore.submitSleep()
uni.showToast({ title: '睡眠记录成功', icon: 'success' }) uni.showToast({ title: '睡眠记录成功', icon: 'success' })

View File

@@ -79,7 +79,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useRecordStore } from '@/store/record' import { useRecordStore } from '@/store/record'
import { getDateStr, getDayRecords, getMonthRecords } from '@/utils/record' import { getDateStr, getDayRecords } from '@/utils/record'
import type { IHealthRecord } from '@/types/record'
defineOptions({ defineOptions({
name: 'Home', name: 'Home',
@@ -94,28 +95,103 @@ definePage({
const recordStore = useRecordStore() const recordStore = useRecordStore()
const greeting = '下午好,小明 👋' const todayRecords = ref<IHealthRecord[]>([])
const today = '8月19日 周三'
// 今日概览数据 const now = new Date()
const overviewItems = [ const hour = now.getHours()
{ icon: '⚖️', label: '体重', value: '68.5kg', sub: '较昨日 -0.3kg', color: 'text-[#1F2D28]', bg: 'bg-[#E89E3A]' },
{ icon: '😴', label: '睡眠', value: '7.5h', sub: '深睡 2.1h', color: 'text-[#1F2D28]', bg: 'bg-[#2E5B8C]' },
{ icon: '🏃', label: '运动', value: '30min', sub: '目标 30min', color: 'text-[#1F2D28]', bg: 'bg-[#3A7C5B]' },
{ icon: '❤️ ', label: '血压', value: '120/80', sub: '正常', color: 'text-[#1F2D28]', bg: 'bg-[#C04A3C]' },
]
// 今日计划 const greeting = computed(() => {
const plans = [ if (hour < 6)
{ icon: '🏃', label: '运动30分钟', done: true }, return '夜深了 🌙'
{ icon: '🛏️', label: '23:00 前入睡', done: false }, if (hour < 12)
] return '早上好 ☀️'
if (hour < 18)
return '下午好 👋'
return '晚上好 🌆'
})
const today = computed(() => {
const m = now.getMonth() + 1
const d = now.getDate()
const w = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()]
return `${m}${d}日 周${w}`
})
onMounted(() => { onMounted(() => {
const result = getDayRecords(getDateStr(Date.now())) todayRecords.value = getDayRecords(getDateStr(Date.now()))
console.log(result) })
console.log(getMonthRecords('2026-08')) watch(() => recordStore.isRecord, () => {
todayRecords.value = getDayRecords(getDateStr(Date.now()))
})
// 今日概览
const overviewItems = computed(() => {
const list = todayRecords.value
// 体重:取最新一条
const weight = list.filter(r => r.type === 'weight').pop()
// 血压:取最新一条
const bp = list.filter(r => r.type === 'bloodPressure').pop()
// 睡眠:取最新一条
const sleep = list.filter(r => r.type === 'sleep').pop()
// 运动:全部累加
const sports = list.filter(r => r.type === 'sport')
const sportTotal = sports.reduce((sum, r) => sum + (r.duration || 0), 0)
return [
{
icon: '⚖️',
label: '体重',
value: weight ? `${weight.value} kg` : '未记录',
sub: '',
bg: 'bg-[#E89E3A]',
},
{
icon: '😴',
label: '睡眠',
value: sleep ? `${sleep.duration}h` : '未记录',
sub: '',
bg: 'bg-[#2E5B8C]',
},
{
icon: '🏃',
label: '运动',
value: sportTotal > 0 ? `${sportTotal}min` : '0min',
sub: sportTotal >= 30 ? '已达标' : '目标 30min',
bg: 'bg-[#3A7C5B]',
},
{
icon: '❤️',
label: '血压',
value: bp ? `${bp.systolic}/${bp.diastolic}` : '未记录',
sub: '',
bg: 'bg-[#C04A3C]',
},
]
})
// 今日计划
const plans = computed(() => {
const list = todayRecords.value
const hasWeight = list.some(r => r.type === 'weight')
const sportTotal = list
.filter(r => r.type === 'sport')
.reduce((sum, r) => sum + (r.duration || 0), 0)
const sleepOnTime = list
.filter(r => r.type === 'sleep')
.some((r) => {
const hour = new Date(r.startTime).getHours()
return hour <= 23
})
const hasBp = list.some(r => r.type === 'bloodPressure')
return [
{ icon: '⚖️', label: '记录体重', done: hasWeight },
{ icon: '❤️', label: '测量血压', done: hasBp },
{ icon: '🏃', label: '运动30分钟', done: sportTotal >= 30 },
{ icon: '🛏️', label: '23:00 前入睡', done: sleepOnTime },
]
}) })
function handelFabClick() { function handelFabClick() {

View File

@@ -18,57 +18,64 @@
<!-- 时间轴区域 --> <!-- 时间轴区域 -->
<view class="px-5 py-2"> <view class="px-5 py-2">
<!-- 时间轴容器 --> <view v-if="grouped.length === 0" class="py-16 text-center">
<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 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="relative pl-6">
<view <view
class="absolute bottom-1 top-1 w-[2px] from-[#07c160] via-[#2E5B8C] to-[#dde3e0] bg-gradient-to-b" class="absolute bottom-1 top-1 w-[2px] from-[#07c160] via-[#2E5B8C] to-[#dde3e0] bg-gradient-to-b"
style="left: 0;" style="left: 0;"
/> />
<!-- 每条记录 -->
<view <view
v-for="(item, idx) in records" v-for="(item, idx) in group.items"
:key="idx" :key="item.id || idx"
class="relative mb-5 last:mb-0" class="relative mb-5 last:mb-0"
> >
<view <view
class="absolute border-[2.5px] border-white rounded-full shadow-sm" class="absolute border-[2.5px] border-white rounded-full shadow-sm"
style="width: 14px; height: 14px; left: -30px; top: 0; z-index: 2;" style="width: 14px; height: 14px; left: -30px; top: 0; z-index: 2;"
:class="item.color" :class="getRecordMeta(item.type).color"
/> />
<!-- 卡片 --> <!-- 卡片 -->
<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="primary" round>
{{ item.status }} {{ getRecordStatus(item) }}
</wd-tag> </wd-tag>
</view> </view>
<!-- 第二行图标 + 指标名 -->
<view class="mt-1.5 flex items-center gap-2"> <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="item.color"> <view
<text>{{ item.icon }}</text> 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> </view>
<text class="text-sm text-gray-700 font-medium">{{ item.type }}</text> <text class="text-sm text-gray-700 font-medium">{{ getRecordMeta(item.type).label }}</text>
</view> </view>
<!-- 第三行数值 --> <text class="mt-1.5 block text-xl text-gray-800 font-bold">{{ getRecordValue(item) }}</text>
<text class="mt-1.5 block text-xl text-gray-800 font-bold">{{ item.value }}</text>
<!-- 第四行备注 -->
<text v-if="item.note" class="mt-0.5 block text-xs text-gray-400 leading-relaxed"> <text v-if="item.note" class="mt-0.5 block text-xs text-gray-400 leading-relaxed">
{{ item.note }} {{ item.note }}
</text> </text>
</view> </view>
</view> </view>
<!-- 无数据 -->
<view v-if="records.length === 0" class="py-16 text-center">
<text class="text-4xl">📭</text>
<text class="mt-3 block text-sm text-gray-400">这一天还没有记录</text>
</view> </view>
</view> </view>
</view> </view>
@@ -116,7 +123,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, ref } from 'vue' import { computed, onMounted, ref } from 'vue'
import { getMonthRecords, getMonthStr } from '@/utils/record' import { getMonthRecords, getMonthStr, getRecordMeta, getRecordStatus, getRecordValue, groupByDate } from '@/utils/record'
import type { IHealthRecord } from '@/types/record'
definePage({ definePage({
style: { style: {
@@ -134,10 +142,17 @@ const displayDate = computed(() => {
return `${d.getFullYear()}${d.getMonth() + 1}` return `${d.getFullYear()}${d.getMonth() + 1}`
}) })
const records = ref([]) 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)
}
onMounted(() => { onMounted(() => {
records.value = getMonthRecords(getMonthStr(currentDate.value)) loadRecords()
}) })
function changeMonth(offset: number) { function changeMonth(offset: number) {
@@ -145,12 +160,12 @@ function changeMonth(offset: number) {
d.setMonth(d.getMonth() + offset) d.setMonth(d.getMonth() + offset)
currentDate.value = d.getTime() currentDate.value = d.getTime()
records.value = getMonthRecords(getMonthStr(currentDate.value)) loadRecords()
} }
function goToday() { function goToday() {
currentDate.value = Date.now() currentDate.value = Date.now()
records.value = getMonthRecords(getMonthStr(currentDate.value)) loadRecords()
} }
function openDatePicker() { function openDatePicker() {
@@ -158,67 +173,9 @@ function openDatePicker() {
} }
function onDateConfirm({ value }) { function onDateConfirm({ value }) {
records.value = getMonthRecords(getMonthStr(currentDate.value)) loadRecords()
} }
// ===== 时间轴数据 =====
// const records = ref([
// {
// icon: '😴',
// label: '睡眠',
// value: '7.5 h',
// datetime: '2026-08-20 07:30',
// note: '质量良好深睡2.1h',
// color: 'bg-[#2E5B8C]',
// status: '良好',
// },
// {
// icon: '⚖️',
// label: '体重',
// value: '68.5 kg',
// datetime: '2026-08-20 08:30',
// note: '早起空腹,较昨日 -0.3kg',
// color: 'bg-[#E89E3A]',
// status: '正常',
// },
// {
// icon: '❤️',
// label: '血压',
// value: '118/76 mmHg',
// datetime: '2026-08-20 09:00',
// note: '服药后测量静坐5分钟',
// color: 'bg-[#C04A3C]',
// status: '正常',
// },
// {
// icon: '📈',
// label: '血糖',
// value: '5.2 mmol/L',
// datetime: '2026-08-20 10:30',
// note: '早餐后2小时',
// color: 'bg-[#9C27B0]',
// status: '正常',
// },
// {
// icon: '🏃',
// label: '运动',
// value: '30 min',
// datetime: '2026-08-20 14:00',
// note: '快走,公园环道',
// color: 'bg-[#3A7C5B]',
// status: '达标',
// },
// {
// icon: '💓',
// label: '心率',
// value: '68 bpm',
// datetime: '2026-08-20 16:00',
// note: '静息心率',
// color: 'bg-[#D32F2F]',
// status: '正常',
// },
// ])
const aiSummary = ref({ const aiSummary = ref({
dateRange: '基于今日数据', dateRange: '基于今日数据',
text: '今日整体健康状态良好。体重平稳,血压正常,建议增加有氧运动频率,保持当前作息规律。', text: '今日整体健康状态良好。体重平稳,血压正常,建议增加有氧运动频率,保持当前作息规律。',

View File

@@ -11,7 +11,6 @@ export const useRecordStore = defineStore('record', {
showBpPopup: false, showBpPopup: false,
showGlucosePopup: false, showGlucosePopup: false,
showTempPopup: false, showTempPopup: false,
weightForm: { weightForm: {
value: 0, value: 0,
note: '', note: '',
@@ -20,14 +19,13 @@ export const useRecordStore = defineStore('record', {
sleepForm: { sleepForm: {
startTime: Date.now(), startTime: Date.now(),
endTime: Date.now(), endTime: Date.now(),
duration: 0,
note: '', note: '',
time: Date.now(), time: Date.now(),
}, },
sportForm: { sportForm: {
category: '', category: '',
duration: 0, duration: 0,
calories: 0,
distance: 0,
note: '', note: '',
time: Date.now(), time: Date.now(),
}, },
@@ -50,6 +48,7 @@ export const useRecordStore = defineStore('record', {
note: '', note: '',
time: Date.now(), time: Date.now(),
}, },
isRecord: false,
}), }),
actions: { actions: {
openWeight() { openWeight() {
@@ -79,17 +78,18 @@ export const useRecordStore = defineStore('record', {
submitWeight() { submitWeight() {
addWeight(this.weightForm.value, this.weightForm.note, this.weightForm.time) addWeight(this.weightForm.value, this.weightForm.note, this.weightForm.time)
this.showWeightPopup = false this.showWeightPopup = false
this.resetWeight() this.isRecord = !this.isRecord
}, },
submitSleep() { submitSleep() {
addSleep( addSleep(
this.sleepForm.startTime, this.sleepForm.startTime,
this.sleepForm.endTime, this.sleepForm.endTime,
this.sleepForm.duration,
this.sleepForm.note, this.sleepForm.note,
this.sleepForm.time, this.sleepForm.time,
) )
this.showSleepPopup = false this.showSleepPopup = false
this.resetSleep() this.isRecord = !this.isRecord
}, },
submitSport() { submitSport() {
addSport( addSport(
@@ -99,7 +99,7 @@ export const useRecordStore = defineStore('record', {
this.sportForm.time, this.sportForm.time,
) )
this.showSportPopup = false this.showSportPopup = false
this.resetSport() this.isRecord = !this.isRecord
}, },
submitBp() { submitBp() {
addBloodPressure( addBloodPressure(
@@ -110,7 +110,7 @@ export const useRecordStore = defineStore('record', {
this.bpForm.time, this.bpForm.time,
) )
this.showBpPopup = false this.showBpPopup = false
this.resetBp() this.isRecord = !this.isRecord
}, },
submitGlucose() { submitGlucose() {
addBloodSugar( addBloodSugar(
@@ -120,7 +120,7 @@ export const useRecordStore = defineStore('record', {
this.glucoseForm.time, this.glucoseForm.time,
) )
this.showGlucosePopup = false this.showGlucosePopup = false
this.resetGlucose() this.isRecord = !this.isRecord
}, },
submitTemp() { submitTemp() {
addTemperature( addTemperature(
@@ -130,16 +130,16 @@ export const useRecordStore = defineStore('record', {
this.tempForm.time, this.tempForm.time,
) )
this.showTempPopup = false this.showTempPopup = false
this.resetTemp() this.isRecord = !this.isRecord
}, },
resetWeight() { resetWeight() {
this.weightForm = { value: 70, note: '', time: Date.now() } this.weightForm = { value: 70, note: '', time: Date.now() }
}, },
resetSleep() { resetSleep() {
this.sleepForm = { startTime: Date.now() - 8 * 60 * 60 * 1000, endTime: Date.now(), note: '', time: Date.now() } this.sleepForm = { startTime: Date.now() - 8 * 60 * 60 * 1000, endTime: Date.now(), duration: 8, note: '', time: Date.now() }
}, },
resetSport() { resetSport() {
this.sportForm = { category: '跑步', duration: 30, calories: 0, distance: 0, note: '', time: Date.now() } this.sportForm = { category: '跑步', duration: 30, note: '', time: Date.now() }
}, },
resetBp() { resetBp() {
this.bpForm = { systolic: 120, diastolic: 70, heartRate: 80, note: '', time: Date.now() } this.bpForm = { systolic: 120, diastolic: 70, heartRate: 80, note: '', time: Date.now() }

View File

@@ -1,3 +1,5 @@
import type { IHealthRecord, IRecordMeta } from '@/types/record'
const MONTH_KEEP = 12 const MONTH_KEEP = 12
function getMonthKey(timestamp: number) { function getMonthKey(timestamp: number) {
@@ -56,8 +58,8 @@ export function addWeight(value: number, note: string, timestamp: number) {
addRecord('weight', { value, note }, timestamp) addRecord('weight', { value, note }, timestamp)
} }
export function addSleep(startTime: number, endTime: number, note: string, timestamp: number) { export function addSleep(startTime: number, endTime: number, duration: number, note: string, timestamp: number) {
addRecord('sleep', { startTime, endTime, note }, timestamp) addRecord('sleep', { startTime, endTime, duration, note }, timestamp)
} }
export function addSport(category: string, duration: number, note: string, timestamp: number) { export function addSport(category: string, duration: number, note: string, timestamp: number) {
@@ -92,20 +94,20 @@ function getMonthKeyForDate(dateStr: string): string {
return `health_${y}-${m}` return `health_${y}-${m}`
} }
export function getDayRecords(date: string): Record<string, any>[] { export function getDayRecords(date: string): IHealthRecord[] {
const key = getMonthKeyForDate(date) const key = getMonthKeyForDate(date)
const all = wx.getStorageSync(key) || {} const all = wx.getStorageSync(key) || {}
const dayRecords = all[date] || [] const dayRecords = all[date] || []
return [...dayRecords].sort((a, b) => a.time.localeCompare(b.time)) return [...dayRecords].sort((a, b) => a.time.localeCompare(b.time))
} }
export function getMonthRecords(yearMonth: string, type?: string): Record<string, any>[] { export function getMonthRecords(yearMonth: string, type?: string): IHealthRecord[] {
const key = `health_${yearMonth}` const key = `health_${yearMonth}`
const all = wx.getStorageSync(key) || {} const all = wx.getStorageSync(key) || {}
const result: Record<string, any>[] = [] const result: IHealthRecord[] = []
Object.keys(all).forEach((date) => { Object.keys(all).forEach((date) => {
all[date].forEach((r: Record<string, any>) => { all[date].forEach((r: IHealthRecord) => {
if (!type || r.type === type) { if (!type || r.type === type) {
result.push({ date, ...r }) result.push({ date, ...r })
} }
@@ -116,7 +118,7 @@ export function getMonthRecords(yearMonth: string, type?: string): Record<string
} }
// 排序:先按 date 正序,再按 time 正序 // 排序:先按 date 正序,再按 time 正序
function sortRecords(records: Record<string, any>[]): Record<string, any>[] { function sortRecords(records: IHealthRecord[]): IHealthRecord[] {
return records.sort((a, b) => { return records.sort((a, b) => {
const dateCmp = a.date.localeCompare(b.date) const dateCmp = a.date.localeCompare(b.date)
if (dateCmp !== 0) if (dateCmp !== 0)
@@ -124,3 +126,106 @@ function sortRecords(records: Record<string, any>[]): Record<string, any>[] {
return a.time.localeCompare(b.time) return a.time.localeCompare(b.time)
}) })
} }
const META_MAP: Record<string, IRecordMeta> = {
weight: { icon: '⚖️', label: '体重', color: 'bg-[#E89E3A]' },
sleep: { icon: '😴', label: '睡眠', color: 'bg-[#2E5B8C]' },
bloodPressure: { icon: '❤️', label: '血压', color: 'bg-[#C04A3C]' },
bloodSugar: { icon: '📈', label: '血糖', color: 'bg-[#9C27B0]' },
sport: { icon: '🏃', label: '运动', color: 'bg-[#3A7C5B]' },
temperature: { icon: '🌡️', label: '体温', color: 'bg-[#D32F2F]' },
}
export function getRecordMeta(type: string): IRecordMeta {
return META_MAP[type] || { icon: '📋', label: '其他', color: 'bg-gray-400' }
}
export function getRecordValue(record: IHealthRecord): string {
switch (record.type) {
case 'weight':
return `${record.value} kg`
case 'bloodPressure':
return `${record.systolic}/${record.diastolic} mmHg${record.heartRate ? ` · 心率 ${record.heartRate}` : ''}`
case 'bloodSugar':
return `${record.value} mmol/L · ${record.period}`
case 'heartRate':
return `${record.value} bpm`
case 'temperature':
return `${record.value}${record.location ? ` · ${record.location}` : ''}`
case 'sport':
return `${record.category} · ${record.duration}min`
case 'sleep':
return `${new Date(record.startTime).toTimeString().slice(0, 5)} ~ ${new Date(record.endTime).toTimeString().slice(0, 5)}${record.duration}h`
default:
return ''
}
}
export function getRecordStatus(record: IHealthRecord): string {
switch (record.type) {
case 'bloodPressure':
if (record.systolic >= 140 || record.diastolic >= 90)
return '偏高'
if (record.systolic < 90 || record.diastolic < 60)
return '偏低'
return '正常'
case 'bloodSugar':
if (record.period.includes('空腹')) {
return record.value >= 6.1 ? '偏高' : '正常'
}
// 餐后
return record.value >= 7.8 ? '偏高' : '正常'
case 'heartRate':
if (record.value < 60)
return '偏慢'
if (record.value <= 100)
return '正常'
return '偏快'
case 'temperature':
if (record.value < 36.1)
return '偏低'
if (record.value <= 37.2)
return '正常'
return '偏高'
case 'sport':
return record.duration >= 30 ? '达标' : '偏少'
case 'sleep':
if (record.duration >= 7)
return '充足'
if (record.duration >= 6)
return '良好'
return '不足'
default:
return '未知'
}
}
const WEEKDAY = ['日', '一', '二', '三', '四', '五', '六']
export function groupByDate(records: IHealthRecord[]): Array<{
date: string
weekday: string
items: IHealthRecord[]
}> {
const map: Record<string, IHealthRecord[]> = {}
records.forEach((r) => {
if (!r.date)
return
if (!map[r.date])
map[r.date] = []
map[r.date].push(r)
})
return Object.keys(map)
.sort((a, b) => b.localeCompare(a)) // 日期倒序,最新的在上
.map(date => ({
date,
weekday: WEEKDAY[new Date(date).getDay()],
items: map[date].sort((a, b) => a.time.localeCompare(b.time)), // 当天按时间正序
}))
}