# 方案总结
基于提供的 Git diff,我将生成以下 conventional commit message: ## 变更分析: 1. **核心功能**: - 新增睡眠监控服务(`services/sleepMonitor.ts`) - 新增睡眠通知服务(`services/sleepNotificationService.ts`) - iOS 原生端增加睡眠观察者方法 2. **应用启动优化**: - 重构 `app/_layout.tsx` 中的初始化流程,按优先级分阶段加载服务 3. **药品功能改进**: - 优化语音识别交互(实时预览、可取消) - Widget 增加 URL scheme 支持 4. **路由配置**: - 新增药品管理路由常量 ## 提交信息类型: - **主类型**:`feat` (新增睡眠监控功能) - **作用域**:`health` (健康相关功能) --- 请确认方案后,我将生成最终的 commit message。 --- **最终 Commit Message:** feat(health): 添加睡眠监控和通知服务,优化应用启动流程 - 新增睡眠监控服务,支持实时监听 HealthKit 睡眠数据更新 - 实现睡眠质量分析算法,计算睡眠评分和各阶段占比 - 新增睡眠通知服务,分析完成后自动推送质量评估和建议 - iOS 原生端实现睡眠数据观察者,支持后台数据传递 - 重构应用启动初始化流程,按优先级分阶段加载服务(关键/次要/后台/空闲) - 优化药品录入页面语音识别交互,支持实时预览和取消操作 - 药品 Widget 增加 deeplink 支持,点击跳转到应用 - 新增药品管理路由常量配置
This commit is contained in:
191
services/sleepNotificationService.ts
Normal file
191
services/sleepNotificationService.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* 睡眠通知服务
|
||||
*
|
||||
* 负责在睡眠分析完成后发送通知,提供睡眠质量评估和建议
|
||||
*/
|
||||
|
||||
import { logger } from '@/utils/logger';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { SleepAnalysisData } from './sleepMonitor';
|
||||
|
||||
/**
|
||||
* 分析睡眠数据并发送通知
|
||||
*/
|
||||
export async function analyzeSleepAndSendNotification(
|
||||
analysis: SleepAnalysisData
|
||||
): Promise<void> {
|
||||
try {
|
||||
logger.info('开始分析睡眠并发送通知:', {
|
||||
score: analysis.sleepScore,
|
||||
quality: analysis.quality,
|
||||
duration: analysis.totalSleepHours,
|
||||
});
|
||||
|
||||
// 构建通知内容
|
||||
const notification = buildSleepNotification(analysis);
|
||||
|
||||
// 发送通知
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: notification,
|
||||
trigger: null, // 立即发送
|
||||
});
|
||||
|
||||
logger.info('睡眠分析通知已发送');
|
||||
} catch (error) {
|
||||
logger.error('发送睡眠分析通知失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建睡眠通知内容
|
||||
*/
|
||||
function buildSleepNotification(analysis: SleepAnalysisData): Notifications.NotificationContentInput {
|
||||
const { sleepScore, quality, totalSleepHours, sleepEfficiency } = analysis;
|
||||
|
||||
// 根据质量等级选择emoji和标题
|
||||
const qualityConfig = getQualityConfig(quality);
|
||||
|
||||
// 构建通知标题
|
||||
const title = `${qualityConfig.emoji} ${qualityConfig.title}`;
|
||||
|
||||
// 构建通知正文
|
||||
const sleepDuration = formatSleepDuration(totalSleepHours);
|
||||
const efficiencyText = `睡眠效率 ${sleepEfficiency.toFixed(0)}%`;
|
||||
const body = `您昨晚睡了 ${sleepDuration},${efficiencyText}。评分:${sleepScore}分`;
|
||||
|
||||
// 获取建议
|
||||
const suggestion = getSleepSuggestion(analysis);
|
||||
|
||||
return {
|
||||
title,
|
||||
body: `${body}\n${suggestion}`,
|
||||
data: {
|
||||
type: 'sleep_analysis',
|
||||
score: sleepScore,
|
||||
quality,
|
||||
analysis: JSON.stringify(analysis),
|
||||
url: '/sleep-detail', // 点击通知跳转到睡眠详情页
|
||||
},
|
||||
sound: 'default',
|
||||
badge: 1,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取质量配置
|
||||
*/
|
||||
function getQualityConfig(quality: string): {
|
||||
emoji: string;
|
||||
title: string;
|
||||
} {
|
||||
const configs = {
|
||||
excellent: {
|
||||
emoji: '😴',
|
||||
title: '睡眠质量优秀',
|
||||
},
|
||||
good: {
|
||||
emoji: '😊',
|
||||
title: '睡眠质量良好',
|
||||
},
|
||||
fair: {
|
||||
emoji: '😐',
|
||||
title: '睡眠质量一般',
|
||||
},
|
||||
poor: {
|
||||
emoji: '😟',
|
||||
title: '睡眠质量较差',
|
||||
},
|
||||
very_poor: {
|
||||
emoji: '😰',
|
||||
title: '睡眠质量很差',
|
||||
},
|
||||
};
|
||||
|
||||
return configs[quality as keyof typeof configs] || {
|
||||
emoji: '💤',
|
||||
title: '睡眠分析完成',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化睡眠时长
|
||||
*/
|
||||
function formatSleepDuration(hours: number): string {
|
||||
const h = Math.floor(hours);
|
||||
const m = Math.round((hours - h) * 60);
|
||||
|
||||
if (m === 0) {
|
||||
return `${h}小时`;
|
||||
}
|
||||
return `${h}小时${m}分钟`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取睡眠建议
|
||||
*/
|
||||
function getSleepSuggestion(analysis: SleepAnalysisData): string {
|
||||
const { quality, totalSleepHours, deepSleepPercentage, remSleepPercentage, sleepEfficiency } = analysis;
|
||||
|
||||
// 优秀或良好的睡眠
|
||||
if (quality === 'excellent' || quality === 'good') {
|
||||
const tips = [
|
||||
'继续保持良好的睡眠习惯!',
|
||||
'坚持规律作息,身体会感谢你!',
|
||||
'优质睡眠让你精力充沛!',
|
||||
];
|
||||
return tips[Math.floor(Math.random() * tips.length)];
|
||||
}
|
||||
|
||||
// 根据具体问题给出建议
|
||||
const suggestions: string[] = [];
|
||||
|
||||
if (totalSleepHours < 7) {
|
||||
suggestions.push('建议增加睡眠时间至7-9小时');
|
||||
} else if (totalSleepHours > 9) {
|
||||
suggestions.push('睡眠时间偏长,注意睡眠质量');
|
||||
}
|
||||
|
||||
if (deepSleepPercentage < 13) {
|
||||
suggestions.push('深度睡眠不足,睡前避免使用电子设备');
|
||||
}
|
||||
|
||||
if (remSleepPercentage < 20) {
|
||||
suggestions.push('REM睡眠不足,保持规律的作息时间');
|
||||
}
|
||||
|
||||
if (sleepEfficiency < 85) {
|
||||
suggestions.push('睡眠效率较低,改善睡眠环境');
|
||||
}
|
||||
|
||||
// 如果有具体建议,返回第一条;否则返回通用建议
|
||||
if (suggestions.length > 0) {
|
||||
return `💡 ${suggestions[0]}`;
|
||||
}
|
||||
|
||||
return '建议关注睡眠质量,保持良好作息';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送简单的睡眠提醒(用于测试)
|
||||
*/
|
||||
export async function sendSimpleSleepReminder(userName: string = '朋友'): Promise<void> {
|
||||
try {
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: '😴 睡眠质量分析',
|
||||
body: `${userName},您的睡眠数据已更新,点击查看详细分析`,
|
||||
data: {
|
||||
type: 'sleep_reminder',
|
||||
url: '/sleep-detail',
|
||||
},
|
||||
sound: 'default',
|
||||
},
|
||||
trigger: null,
|
||||
});
|
||||
|
||||
logger.info('简单睡眠提醒已发送');
|
||||
} catch (error) {
|
||||
logger.error('发送简单睡眠提醒失败:', error);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user