feat: 优化睡眠数据
This commit is contained in:
@@ -163,18 +163,19 @@ function calculateSleepStageStats(samples: SleepSample[]): SleepStageStats[] {
|
||||
stageMap.set(sample.value, currentDuration + duration);
|
||||
});
|
||||
|
||||
// 计算总睡眠时间(排除在床时间)
|
||||
const totalSleepTime = Array.from(stageMap.entries())
|
||||
// 计算实际睡眠时间(包括所有睡眠阶段,排除在床时间)
|
||||
const actualSleepTime = Array.from(stageMap.entries())
|
||||
.filter(([stage]) => stage !== SleepStage.InBed)
|
||||
.reduce((total, [, duration]) => total + duration, 0);
|
||||
|
||||
// 生成统计数据
|
||||
// 生成统计数据,包含所有睡眠阶段(包括清醒时间)
|
||||
const stats: SleepStageStats[] = [];
|
||||
|
||||
stageMap.forEach((duration, stage) => {
|
||||
if (stage === SleepStage.InBed || stage === SleepStage.Awake) return;
|
||||
// 只排除在床时间,保留清醒时间
|
||||
if (stage === SleepStage.InBed) return;
|
||||
|
||||
const percentage = totalSleepTime > 0 ? (duration / totalSleepTime) * 100 : 0;
|
||||
const percentage = actualSleepTime > 0 ? (duration / actualSleepTime) * 100 : 0;
|
||||
let quality: SleepQuality;
|
||||
|
||||
// 根据睡眠阶段和比例判断质量
|
||||
@@ -194,6 +195,12 @@ function calculateSleepStageStats(samples: SleepSample[]): SleepStageStats[] {
|
||||
percentage >= 35 ? SleepQuality.Good :
|
||||
percentage >= 25 ? SleepQuality.Fair : SleepQuality.Poor;
|
||||
break;
|
||||
case SleepStage.Awake:
|
||||
// 清醒时间越少越好
|
||||
quality = percentage <= 5 ? SleepQuality.Excellent :
|
||||
percentage <= 10 ? SleepQuality.Good :
|
||||
percentage <= 15 ? SleepQuality.Fair : SleepQuality.Poor;
|
||||
break;
|
||||
default:
|
||||
quality = SleepQuality.Fair;
|
||||
}
|
||||
@@ -285,12 +292,12 @@ export function getSleepStageDisplayName(stage: SleepStage): string {
|
||||
export function getSleepStageColor(stage: SleepStage): string {
|
||||
switch (stage) {
|
||||
case SleepStage.Deep:
|
||||
return '#1E40AF'; // 深蓝色
|
||||
case SleepStage.Core:
|
||||
return '#3B82F6'; // 蓝色
|
||||
case SleepStage.Core:
|
||||
return '#8B5CF6'; // 紫色
|
||||
case SleepStage.REM:
|
||||
case SleepStage.Asleep:
|
||||
return '#06B6D4'; // 青色
|
||||
return '#EC4899'; // 粉色
|
||||
case SleepStage.Awake:
|
||||
return '#F59E0B'; // 橙色
|
||||
case SleepStage.InBed:
|
||||
@@ -313,21 +320,71 @@ export async function fetchSleepDetailForDate(date: Date): Promise<SleepDetailDa
|
||||
return null;
|
||||
}
|
||||
|
||||
// 找到上床时间和起床时间
|
||||
const inBedSamples = sleepSamples.filter(sample => sample.value === SleepStage.InBed);
|
||||
const bedtime = inBedSamples.length > 0 ? inBedSamples[0].startDate : sleepSamples[0].startDate;
|
||||
const wakeupTime = inBedSamples.length > 0 ?
|
||||
inBedSamples[inBedSamples.length - 1].endDate :
|
||||
sleepSamples[sleepSamples.length - 1].endDate;
|
||||
// 找到入睡时间和起床时间
|
||||
// 过滤出实际睡眠阶段(排除在床时间和清醒时间)
|
||||
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) =>
|
||||
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) =>
|
||||
new Date(a.startDate).getTime() - new Date(b.startDate).getTime()
|
||||
);
|
||||
|
||||
bedtime = sortedAllSamples[0].startDate;
|
||||
wakeupTime = sortedAllSamples[sortedAllSamples.length - 1].endDate;
|
||||
}
|
||||
|
||||
// 计算在床时间
|
||||
const timeInBed = dayjs(wakeupTime).diff(dayjs(bedtime), 'minute');
|
||||
// 计算在床时间 - 使用 INBED 样本数据
|
||||
let timeInBed: number;
|
||||
const inBedSamples = sleepSamples.filter(sample => sample.value === SleepStage.InBed);
|
||||
|
||||
if (inBedSamples.length > 0) {
|
||||
// 使用 INBED 样本计算在床时间
|
||||
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'));
|
||||
console.log('- 在床时长:', timeInBed, '分钟');
|
||||
} else {
|
||||
// 如果没有 INBED 数据,使用睡眠时间作为在床时间
|
||||
timeInBed = dayjs(wakeupTime).diff(dayjs(bedtime), 'minute');
|
||||
console.log('没有INBED数据,使用睡眠时间作为在床时间:', timeInBed, '分钟');
|
||||
}
|
||||
|
||||
// 计算睡眠阶段统计
|
||||
const sleepStages = calculateSleepStageStats(sleepSamples);
|
||||
|
||||
// 计算总睡眠时间
|
||||
const totalSleepTime = sleepStages.reduce((total, stage) => total + stage.duration, 0);
|
||||
// 计算总睡眠时间(排除清醒时间)
|
||||
const totalSleepTime = sleepStages
|
||||
.filter(stage => stage.stage !== SleepStage.Awake)
|
||||
.reduce((total, stage) => total + stage.duration, 0);
|
||||
|
||||
// 计算睡眠效率
|
||||
const sleepEfficiency = timeInBed > 0 ? Math.round((totalSleepTime / timeInBed) * 100) : 0;
|
||||
|
||||
Reference in New Issue
Block a user