feat: 完善饮水 widget

This commit is contained in:
richarjiang
2025-09-09 14:26:16 +08:00
parent cacfde064f
commit e56ebe3636
13 changed files with 984 additions and 62 deletions

View File

@@ -101,17 +101,17 @@ async function fetchSleepSamples(date: Date): Promise<SleepSample[]> {
// 添加详细日志,了解实际获取到的数据类型
console.log('获取到睡眠样本:', results.length);
console.log('睡眠样本详情:', results.map(r => ({
value: r.value,
start: r.startDate?.substring(11, 16),
console.log('睡眠样本详情:', results.map(r => ({
value: r.value,
start: r.startDate?.substring(11, 16),
end: r.endDate?.substring(11, 16),
duration: `${Math.round((new Date(r.endDate).getTime() - new Date(r.startDate).getTime()) / 60000)}min`
})));
// 检查可用的睡眠阶段类型
const uniqueValues = [...new Set(results.map(r => r.value))];
console.log('可用的睡眠阶段类型:', uniqueValues);
resolve(results as unknown as SleepSample[]);
});
});
@@ -165,7 +165,6 @@ function calculateSleepStageStats(samples: SleepSample[]): SleepStageStats[] {
// 计算实际睡眠时间(包括所有睡眠阶段,排除在床时间)
const actualSleepTime = Array.from(stageMap.entries())
.filter(([stage]) => stage !== SleepStage.InBed)
.reduce((total, [, duration]) => total + duration, 0);
// 生成统计数据,包含所有睡眠阶段(包括清醒时间)
@@ -322,34 +321,34 @@ export async function fetchSleepDetailForDate(date: Date): Promise<SleepDetailDa
// 找到入睡时间和起床时间
// 过滤出实际睡眠阶段(排除在床时间和清醒时间)
const actualSleepSamples = sleepSamples.filter(sample =>
const actualSleepSamples = sleepSamples.filter(sample =>
sample.value !== SleepStage.InBed && sample.value !== SleepStage.Awake
);
// 入睡时间:第一个实际睡眠阶段的开始时间
// 起床时间:最后一个实际睡眠阶段的结束时间
let bedtime: string;
let wakeupTime: string;
if (actualSleepSamples.length > 0) {
// 按开始时间排序
const sortedSleepSamples = actualSleepSamples.sort((a, b) =>
const sortedSleepSamples = actualSleepSamples.sort((a, b) =>
new Date(a.startDate).getTime() - new Date(b.startDate).getTime()
);
bedtime = sortedSleepSamples[0].startDate;
wakeupTime = sortedSleepSamples[sortedSleepSamples.length - 1].endDate;
console.log('计算入睡和起床时间:');
console.log('- 入睡时间:', dayjs(bedtime).format('YYYY-MM-DD HH:mm:ss'));
console.log('- 起床时间:', dayjs(wakeupTime).format('YYYY-MM-DD HH:mm:ss'));
} else {
// 如果没有实际睡眠数据,回退到使用所有样本数据
console.warn('没有找到实际睡眠阶段数据,使用所有样本数据');
const sortedAllSamples = sleepSamples.sort((a, b) =>
const sortedAllSamples = sleepSamples.sort((a, b) =>
new Date(a.startDate).getTime() - new Date(b.startDate).getTime()
);
bedtime = sortedAllSamples[0].startDate;
wakeupTime = sortedAllSamples[sortedAllSamples.length - 1].endDate;
}
@@ -357,17 +356,17 @@ export async function fetchSleepDetailForDate(date: Date): Promise<SleepDetailDa
// 计算在床时间 - 使用 INBED 样本数据
let timeInBed: number;
const inBedSamples = sleepSamples.filter(sample => sample.value === SleepStage.InBed);
if (inBedSamples.length > 0) {
// 使用 INBED 样本计算在床时间
const sortedInBedSamples = inBedSamples.sort((a, b) =>
const sortedInBedSamples = inBedSamples.sort((a, b) =>
new Date(a.startDate).getTime() - new Date(b.startDate).getTime()
);
const inBedStart = sortedInBedSamples[0].startDate;
const inBedEnd = sortedInBedSamples[sortedInBedSamples.length - 1].endDate;
timeInBed = dayjs(inBedEnd).diff(dayjs(inBedStart), 'minute');
console.log('在床时间计算:');
console.log('- 上床时间:', dayjs(inBedStart).format('YYYY-MM-DD HH:mm:ss'));
console.log('- 离床时间:', dayjs(inBedEnd).format('YYYY-MM-DD HH:mm:ss'));
@@ -381,9 +380,8 @@ export async function fetchSleepDetailForDate(date: Date): Promise<SleepDetailDa
// 计算睡眠阶段统计
const sleepStages = calculateSleepStageStats(sleepSamples);
// 计算总睡眠时间(排除清醒时间)
// 计算总睡眠时间
const totalSleepTime = sleepStages
.filter(stage => stage.stage !== SleepStage.Awake)
.reduce((total, stage) => total + stage.duration, 0);
// 计算睡眠效率
@@ -450,14 +448,14 @@ export function formatTime(dateString: string): string {
// 将睡眠样本数据转换为15分钟间隔的睡眠阶段数据
export function convertSleepSamplesToIntervals(sleepSamples: SleepSample[], bedtime: string, wakeupTime: string): { time: string; stage: SleepStage }[] {
const data: { time: string; stage: SleepStage }[] = [];
if (sleepSamples.length === 0) {
console.log('没有睡眠样本数据可用于图表显示');
return [];
}
// 过滤掉InBed阶段只保留实际睡眠阶段
const sleepOnlySamples = sleepSamples.filter(sample =>
const sleepOnlySamples = sleepSamples.filter(sample =>
sample.value !== SleepStage.InBed
);
@@ -476,14 +474,14 @@ export function convertSleepSamplesToIntervals(sleepSamples: SleepSample[], bedt
// 创建一个映射,用于快速查找每个时间点的睡眠阶段
while (currentTime.isBefore(endTime)) {
const currentTimestamp = currentTime.toDate().getTime();
// 找到当前时间点对应的睡眠阶段
let currentStage = SleepStage.Awake; // 默认为清醒
for (const sample of sleepOnlySamples) {
const sampleStart = new Date(sample.startDate).getTime();
const sampleEnd = new Date(sample.endDate).getTime();
// 如果当前时间在这个样本的时间范围内
if (currentTimestamp >= sampleStart && currentTimestamp < sampleEnd) {
currentStage = sample.value;
@@ -493,7 +491,7 @@ export function convertSleepSamplesToIntervals(sleepSamples: SleepSample[], bedt
const timeStr = currentTime.format('HH:mm');
data.push({ time: timeStr, stage: currentStage });
// 移动到下一个15分钟间隔
currentTime = currentTime.add(15, 'minute');
}