import * as Notifications from 'expo-notifications'; import { NotificationData, NotificationTypes, notificationService } from '../services/notifications'; import { getNotificationEnabled, getWaterReminderEnabled } from './userPreferences'; /** * 构建 coach 页面的深度链接 */ export function buildCoachDeepLink(params: { action?: 'diet' | 'weight' | 'mood' | 'workout'; subAction?: 'record' | 'photo' | 'text' | 'card'; meal?: 'breakfast' | 'lunch' | 'dinner' | 'snack'; message?: string; }): string { const baseUrl = '/coach'; const searchParams = new URLSearchParams(); if (params.action) searchParams.set('action', params.action); if (params.subAction) searchParams.set('subAction', params.subAction); if (params.meal) searchParams.set('meal', params.meal); if (params.message) searchParams.set('message', encodeURIComponent(params.message)); const queryString = searchParams.toString(); return queryString ? `${baseUrl}?${queryString}` : baseUrl; } /** * 运动相关的通知辅助函数 */ export class WorkoutNotificationHelpers { /** * 发送运动开始提醒 */ static async sendWorkoutStartReminder(userName: string) { return notificationService.sendImmediateNotification({ title: '运动时间到', body: `${userName},该开始今天的普拉提训练了!`, data: { type: 'workout_start' }, sound: true, priority: 'high', }); } /** * 发送运动完成通知 */ static async sendWorkoutCompleteNotification(userName: string, duration: number) { return notificationService.sendImmediateNotification({ title: '运动完成', body: `${userName},恭喜您完成了${duration}分钟的训练!`, data: { type: 'workout_complete' }, sound: true, priority: 'normal', }); } /** * 安排每日运动提醒 */ static async scheduleDailyWorkoutReminder(userName: string, hour: number = 9, minute: number = 0) { const reminderTime = new Date(); reminderTime.setHours(hour, minute, 0, 0); // 如果今天的时间已经过了,设置为明天 if (reminderTime.getTime() <= Date.now()) { reminderTime.setDate(reminderTime.getDate() + 1); } return notificationService.scheduleRepeatingNotification( { title: '每日运动提醒', body: `${userName},该开始今天的普拉提训练了!`, data: { type: 'daily_workout_reminder' }, sound: true, priority: 'high', }, { days: 1 } ); } } // GoalNotificationHelpers 类已删除,因为目标功能已移除 export class ChallengeNotificationHelpers { static buildChallengesTabUrl(): string { return '/(tabs)/challenges'; } static async sendEncouragementNotification(params: { userName: string; challengeTitle: string; challengeId: string; }): Promise { const { userName, challengeTitle, challengeId } = params; const notification: NotificationData = { title: '挑战提醒', body: `${userName},今天还没有完成「${challengeTitle}」挑战,快来打卡吧!`, data: { type: NotificationTypes.CHALLENGE_ENCOURAGEMENT, challengeId, url: ChallengeNotificationHelpers.buildChallengesTabUrl(), }, sound: true, priority: 'high', }; return notificationService.sendImmediateNotification(notification); } } /** * 营养相关的通知辅助函数 */ export class NutritionNotificationHelpers { /** * 发送营养记录提醒 */ static async sendNutritionRecordReminder(userName: string) { return notificationService.sendImmediateNotification({ title: '营养记录', body: `${userName},记得记录今天的饮食情况`, data: { type: 'nutrition_record_reminder' }, sound: true, priority: 'normal', }); } /** * 安排每日午餐提醒 * @param userName 用户名 * @param hour 小时 (默认12点) * @param minute 分钟 (默认0分) * @returns 通知ID */ static async scheduleDailyLunchReminder( userName: string, hour: number = 12, minute: number = 0 ): Promise { try { // 检查是否已经存在午餐提醒 const existingNotifications = await notificationService.getAllScheduledNotifications(); const existingLunchReminder = existingNotifications.find( notification => notification.content.data?.type === 'lunch_reminder' && notification.content.data?.isDailyReminder === true ); if (existingLunchReminder) { console.log('午餐提醒已存在,跳过重复注册:', existingLunchReminder.identifier); return existingLunchReminder.identifier; } // 构建跳转到 coach 页面的深度链接 const coachUrl = buildCoachDeepLink({ action: 'diet', subAction: 'card', meal: 'lunch' }); // 创建午餐提醒通知 const notificationId = await notificationService.scheduleCalendarRepeatingNotification( { title: '午餐记录提醒', body: `${userName},记得记录今天的午餐情况哦!`, data: { type: 'lunch_reminder', isDailyReminder: true, meal: '午餐', url: coachUrl // 添加深度链接 }, sound: true, priority: 'normal', }, { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour: hour, minute: minute, } ); console.log('每日午餐提醒已安排,ID:', notificationId); return notificationId; } catch (error) { console.error('安排每日午餐提醒失败:', error); throw error; } } /** * 安排每日晚餐提醒 * @param userName 用户名 * @param hour 小时 (默认18点) * @param minute 分钟 (默认0分) * @returns 通知ID */ static async scheduleDailyDinnerReminder( userName: string, hour: number = 18, minute: number = 0 ): Promise { try { // 检查是否已经存在晚餐提醒 const existingNotifications = await notificationService.getAllScheduledNotifications(); const existingDinnerReminder = existingNotifications.find( notification => notification.content.data?.type === 'dinner_reminder' && notification.content.data?.isDailyReminder === true ); if (existingDinnerReminder) { console.log('晚餐提醒已存在,跳过重复注册:', existingDinnerReminder.identifier); return existingDinnerReminder.identifier; } // 创建晚餐提醒通知 const notificationId = await notificationService.scheduleCalendarRepeatingNotification( { title: '🍽️ 晚餐时光到啦!', body: `${userName},美好的晚餐时光开始了~记得记录今天的晚餐哦!营养均衡很重要呢 💪`, data: { type: 'dinner_reminder', isDailyReminder: true, meal: '晚餐', url: '/nutrition/records' // 直接跳转到营养记录页面 }, sound: true, priority: 'normal', }, { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour: hour, minute: minute, } ); console.log('每日晚餐提醒已安排,ID:', notificationId); return notificationId; } catch (error) { console.error('安排每日晚餐提醒失败:', error); throw error; } } /** * 取消晚餐提醒 */ static async cancelDinnerReminder(): Promise { try { const notifications = await notificationService.getAllScheduledNotifications(); for (const notification of notifications) { if (notification.content.data?.type === 'dinner_reminder' && notification.content.data?.isDailyReminder === true) { await notificationService.cancelNotification(notification.identifier); console.log('已取消晚餐提醒:', notification.identifier); } } } catch (error) { console.error('取消晚餐提醒失败:', error); throw error; } } /** * 安排营养记录提醒 */ static async scheduleNutritionReminders(userName: string) { // 安排三餐提醒 const mealTimes = [ { hour: 8, minute: 0, meal: '早餐' }, { hour: 12, minute: 0, meal: '午餐' }, { hour: 18, minute: 0, meal: '晚餐' }, ]; const notifications = []; for (const mealTime of mealTimes) { const reminderTime = new Date(); reminderTime.setHours(mealTime.hour, mealTime.minute, 0, 0); // 如果今天的时间已经过了,设置为明天 if (reminderTime.getTime() <= Date.now()) { reminderTime.setDate(reminderTime.getDate() + 1); } // 构建深度链接 const mealTypeMap: Record = { '早餐': 'breakfast', '午餐': 'lunch', '晚餐': 'dinner' }; const coachUrl = buildCoachDeepLink({ action: 'diet', subAction: 'card', meal: mealTypeMap[mealTime.meal] as 'breakfast' | 'lunch' | 'dinner' }); const notificationId = await notificationService.scheduleRepeatingNotification( { title: `${mealTime.meal}提醒`, body: `${userName},记得记录您的${mealTime.meal}情况`, data: { type: 'meal_reminder', meal: mealTime.meal, url: coachUrl }, sound: true, priority: 'normal', }, { days: 1 } ); notifications.push(notificationId); } return notifications; } } /** * 心情相关的通知辅助函数 */ export class MoodNotificationHelpers { /** * 安排每日心情提醒 * @param userName 用户名 * @param hour 小时 (默认21点) * @param minute 分钟 (默认0分) * @returns 通知ID */ static async scheduleDailyMoodReminder( userName: string, hour: number = 21, minute: number = 0 ): Promise { try { // 检查是否已经存在心情提醒 const existingNotifications = await notificationService.getAllScheduledNotifications(); const existingMoodReminder = existingNotifications.find( notification => notification.content.data?.type === 'mood_reminder' && notification.content.data?.isDailyReminder === true ); if (existingMoodReminder) { console.log('心情提醒已存在,跳过重复注册:', existingMoodReminder.identifier); return existingMoodReminder.identifier; } // 创建心情提醒通知 const notificationId = await notificationService.scheduleCalendarRepeatingNotification( { title: '🌙 今天过得怎么样呀?', body: `${userName},夜深了~来记录一下今天的心情吧!每一份情感都值得被珍藏 ✨💕`, data: { type: 'mood_reminder', isDailyReminder: true, url: '/mood/edit' // 跳转到心情记录页面 }, sound: true, priority: 'normal', }, { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour: hour, minute: minute, } ); console.log('每日心情提醒已安排,ID:', notificationId); return notificationId; } catch (error) { console.error('安排每日心情提醒失败:', error); throw error; } } /** * 发送心情记录提醒 */ static async sendMoodReminder(userName: string) { return notificationService.sendImmediateNotification({ title: '🌙 今天过得怎么样呀?', body: `${userName},夜深了~来记录一下今天的心情吧!每一份情感都值得被珍藏 ✨💕`, data: { type: 'mood_reminder', url: '/mood/edit' }, sound: true, priority: 'normal', }); } /** * 取消心情提醒 */ static async cancelMoodReminder(): Promise { try { const notifications = await notificationService.getAllScheduledNotifications(); for (const notification of notifications) { if (notification.content.data?.type === 'mood_reminder' && notification.content.data?.isDailyReminder === true) { await notificationService.cancelNotification(notification.identifier); console.log('已取消心情提醒:', notification.identifier); } } } catch (error) { console.error('取消心情提醒失败:', error); throw error; } } } /** * 喝水相关的通知辅助函数 */ export class WaterNotificationHelpers { /** * 检查喝水目标完成情况并发送提醒 * @param userName 用户名 * @param todayStats 今日喝水统计数据 * @param currentHour 当前小时(用于时间限制检查) * @returns 是否发送了通知 */ static async checkWaterGoalAndNotify( userName: string, todayStats: { totalAmount: number; dailyGoal: number; completionRate: number }, currentHour: number = new Date().getHours() ): Promise { try { // 首先检查用户是否启用了喝水提醒 const isWaterReminderEnabled = await getWaterReminderEnabled(); if (!isWaterReminderEnabled) { console.log('用户未启用喝水提醒,跳过通知检查'); return false; } // 检查时间限制:早上9点以前和晚上9点以后不通知 if (currentHour < 9 || currentHour >= 23) { console.log(`当前时间${currentHour}点,不在通知时间范围内(9:00-21:00),跳过喝水提醒`); return false; } // 检查喝水目标是否已达成 if (todayStats.completionRate >= 100) { console.log('喝水目标已达成,无需发送提醒'); return false; } // 检查是否在过去2小时内已经发送过喝水提醒,避免重复打扰 const lastNotificationKey = '@last_water_notification'; const AsyncStorage = (await import('@/utils/kvStore')).default; const lastNotificationTime = await AsyncStorage.getItem(lastNotificationKey); const now = new Date().getTime(); const twoHoursAgo = now - (2 * 60 * 60 * 1000); // 2小时前 if (lastNotificationTime && parseInt(lastNotificationTime) > twoHoursAgo) { console.log('2小时内已发送过喝水提醒,跳过本次通知'); return false; } // 计算还需要喝多少水 const remainingAmount = todayStats.dailyGoal - todayStats.totalAmount; const completionPercentage = Math.round(todayStats.completionRate); // 根据完成度生成不同的提醒消息 let title = '💧 该喝水啦!'; let body = ''; if (completionPercentage < 30) { // 完成度低于30% const encouragingMessages = [ `${userName},今天才喝了${completionPercentage}%的水哦!还需要${Math.round(remainingAmount)}ml,记得多补水~身体会感谢您的!💙`, `${userName},水分补充进度${completionPercentage}%,再喝${Math.round(remainingAmount)}ml就更健康啦!来一大杯清水吧~🚰`, `${userName},喝水进度才${completionPercentage}%呢~身体需要更多水分,还差${Math.round(remainingAmount)}ml,一起加油!✨`, ]; body = encouragingMessages[Math.floor(Math.random() * encouragingMessages.length)]; } else if (completionPercentage < 60) { // 完成度30-60% const moderateMessages = [ `${userName},喝水进度${completionPercentage}%,还需要${Math.round(remainingAmount)}ml哦!保持这个节奏,您做得很棒!👍`, `${userName},水分补充已完成${completionPercentage}%,再来${Math.round(remainingAmount)}ml就达标了!继续保持~💪`, `${userName},今日饮水${completionPercentage}%完成!距离目标还有${Math.round(remainingAmount)}ml,加把劲!🌊`, ]; body = moderateMessages[Math.floor(Math.random() * moderateMessages.length)]; } else { // 完成度60-99% const almostDoneMessages = [ `${userName},喝水进度${completionPercentage}%,太棒了!最后${Math.round(remainingAmount)}ml就达成目标啦!🎉`, `${userName},已经完成${completionPercentage}%了!还有${Math.round(remainingAmount)}ml就成功了,您很快就能达成今天的目标!🏆`, `${userName},水分补充进度${completionPercentage}%,就差最后一点点!再喝${Math.round(remainingAmount)}ml就胜利了!🥳`, ]; body = almostDoneMessages[Math.floor(Math.random() * almostDoneMessages.length)]; } // 发送通知 const notificationId = await notificationService.sendImmediateNotification({ title, body, data: { type: 'water_reminder', completionRate: completionPercentage, remainingAmount: Math.round(remainingAmount), dailyGoal: todayStats.dailyGoal, currentAmount: todayStats.totalAmount, url: '/statistics' // 跳转到统计页面查看详情 }, sound: true, priority: 'normal', }); // 记录通知发送时间 await AsyncStorage.setItem(lastNotificationKey, now.toString()); console.log(`喝水提醒通知已发送,ID: ${notificationId},完成度: ${completionPercentage}%`); return true; } catch (error) { console.error('检查喝水目标并发送通知失败:', error); return false; } } /** * 发送立即喝水提醒 * @param userName 用户名 * @param message 自定义消息(可选) */ static async sendWaterReminder(userName: string, message?: string) { const defaultMessage = `${userName},记得要多喝水哦!保持身体水分充足很重要~💧`; return notificationService.sendImmediateNotification({ title: '💧 喝水提醒', body: message || defaultMessage, data: { type: 'water_reminder', url: '/statistics' }, sound: true, priority: 'normal', }); } /** * 安排定期喝水提醒(每2小时一次,在9:00-21:00之间) * @param userName 用户名 * @returns 通知ID数组 */ static async scheduleRegularWaterReminders(userName: string): Promise { try { // 首先检查用户是否启用了喝水提醒 const isWaterReminderEnabled = await getWaterReminderEnabled(); if (!isWaterReminderEnabled) { console.log('用户未启用喝水提醒,不安排定期提醒'); // 确保取消任何可能存在的旧提醒 await this.cancelAllWaterReminders(); return []; } const notificationIds: string[] = []; // 检查是否已经存在定期喝水提醒 const existingNotifications = await notificationService.getAllScheduledNotifications(); const existingWaterReminders = existingNotifications.filter( notification => notification.content.data?.type === 'regular_water_reminder' && notification.content.data?.isRegularReminder === true ); if (existingWaterReminders.length > 0) { console.log('定期喝水提醒已存在,跳过重复注册'); return existingWaterReminders.map(n => n.identifier); } // 创建多个时间点的喝水提醒(9:00-21:00,每2小时一次) const reminderHours = [9, 11, 13, 15, 17, 19, 21]; for (const hour of reminderHours) { const notificationId = await notificationService.scheduleCalendarRepeatingNotification( { title: '💧 定时喝水提醒', body: `${userName},该喝水啦!记得补充水分,保持身体健康~`, data: { type: 'regular_water_reminder', isRegularReminder: true, reminderHour: hour, url: '/statistics' }, sound: true, priority: 'normal', }, { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour: hour, minute: 0, } ); notificationIds.push(notificationId); console.log(`已安排${hour}:00的定期喝水提醒,通知ID: ${notificationId}`); } console.log(`定期喝水提醒设置完成,共${notificationIds.length}个通知`); return notificationIds; } catch (error) { console.error('设置定期喝水提醒失败:', error); throw error; } } /** * 根据用户设置安排喝水提醒通知 * @param userName 用户名 * @param settings 喝水提醒设置 * @returns 通知ID数组 */ static async scheduleCustomWaterReminders( userName: string, settings: { enabled: boolean; startTime: string; // 格式: "HH:mm" endTime: string; // 格式: "HH:mm" interval: number; // 分钟 } ): Promise { try { const notificationIds: string[] = []; // 如果不启用提醒,先取消所有提醒 if (!settings.enabled) { await this.cancelAllWaterReminders(); return notificationIds; } // 先取消现有的喝水提醒 await this.cancelAllWaterReminders(); // 解析开始和结束时间 const [startHour, startMinute] = settings.startTime.split(':').map(Number); const [endHour, endMinute] = settings.endTime.split(':').map(Number); // 计算一天内所有的提醒时间点 const reminderTimes: { hour: number; minute: number }[] = []; // 创建开始时间的 Date 对象 let currentTime = new Date(); currentTime.setHours(startHour, startMinute, 0, 0); // 创建结束时间的 Date 对象 let endTime = new Date(); endTime.setHours(endHour, endMinute, 0, 0); // 如果结束时间小于开始时间,说明跨天了,结束时间设为第二天 if (endTime <= currentTime) { endTime.setDate(endTime.getDate() + 1); } // 生成所有的提醒时间点 while (currentTime < endTime) { reminderTimes.push({ hour: currentTime.getHours(), minute: currentTime.getMinutes(), }); // 增加间隔时间 currentTime.setTime(currentTime.getTime() + settings.interval * 60 * 1000); } console.log(`计算出${reminderTimes.length}个喝水提醒时间点:`, reminderTimes); // 为每个时间点创建重复通知 for (const time of reminderTimes) { const notificationId = await notificationService.scheduleCalendarRepeatingNotification( { title: '💧 喝水时间到啦!', body: `${userName},记得补充水分哦~保持身体健康!`, data: { type: 'custom_water_reminder', isCustomReminder: true, reminderHour: time.hour, reminderMinute: time.minute, url: '/statistics' }, sound: true, priority: 'normal', }, { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour: time.hour, minute: time.minute, } ); notificationIds.push(notificationId); console.log(`已安排${time.hour}:${String(time.minute).padStart(2, '0')}的喝水提醒,通知ID: ${notificationId}`); } console.log(`自定义喝水提醒设置完成,共${notificationIds.length}个通知`); return notificationIds; } catch (error) { console.error('设置自定义喝水提醒失败:', error); throw error; } } /** * 取消所有喝水提醒 */ static async cancelAllWaterReminders(): Promise { try { const notifications = await notificationService.getAllScheduledNotifications(); for (const notification of notifications) { if (notification.content.data?.type === 'water_reminder' || notification.content.data?.type === 'regular_water_reminder' || notification.content.data?.type === 'custom_water_reminder') { await notificationService.cancelNotification(notification.identifier); console.log('已取消喝水提醒:', notification.identifier); } } } catch (error) { console.error('取消喝水提醒失败:', error); throw error; } } } /** * 通用通知辅助函数 */ export class GeneralNotificationHelpers { /** * 发送欢迎通知 */ static async sendWelcomeNotification(userName: string) { return notificationService.sendImmediateNotification({ title: '欢迎使用', body: `${userName},欢迎来到普拉提世界!开始您的健康之旅吧`, data: { type: 'welcome' }, sound: true, priority: 'normal', }); } /** * 发送成就通知 */ static async sendAchievementNotification(userName: string, achievement: string) { return notificationService.sendImmediateNotification({ title: '新成就', body: `${userName},恭喜您获得了新成就:${achievement}!`, data: { type: 'achievement', achievement }, sound: true, priority: 'high', }); } /** * 发送系统维护通知 */ static async sendMaintenanceNotification(message: string) { return notificationService.sendImmediateNotification({ title: '系统通知', body: message, data: { type: 'maintenance' }, sound: true, priority: 'high', }); } /** * 取消特定类型的通知 */ static async cancelNotificationsByType(type: string) { const notifications = await notificationService.getAllScheduledNotifications(); for (const notification of notifications) { if (notification.content.data?.type === type) { await notificationService.cancelNotification(notification.identifier); } } } /** * 批量发送通知 */ static async sendBatchNotifications(notifications: NotificationData[]) { const results = []; for (const notification of notifications) { try { const id = await notificationService.sendImmediateNotification(notification); results.push({ success: true, id, notification }); } catch (error) { results.push({ success: false, error, notification }); } } return results; } } /** * 站立提醒通知助手 */ export class StandReminderHelpers { /** * 检查站立状态并发送提醒通知 */ static async checkStandStatusAndNotify(userName: string): Promise { try { console.log('检查站立状态并发送提醒通知...'); // 动态导入健康工具,避免循环依赖 const { getCurrentHourStandStatus } = await import('@/utils/health'); // 获取当前小时站立状态 const standStatus = await getCurrentHourStandStatus(); console.log('当前站立状态:', standStatus); // 如果已经站立过,不需要提醒 if (standStatus.hasStood) { console.log('用户当前小时已经站立,无需提醒'); return false; } // 检查时间范围(工作时间内提醒,避免深夜或清晨打扰) const currentHour = new Date().getHours(); if (currentHour < 9 || currentHour >= 22) { console.log(`当前时间${currentHour}点,不在站立提醒时间范围内`); return false; } // 检查是否启用了通知 if (!(await getNotificationEnabled())) { console.log('用户未启用通知功能,跳过站立提醒'); return false; } // 生成提醒消息 const reminderMessage = this.generateStandReminderMessage(userName, standStatus.standHours, standStatus.standHoursGoal); // 发送站立提醒通知 await notificationService.sendImmediateNotification({ title: '站立提醒', body: reminderMessage, data: { type: 'stand_reminder', currentStandHours: standStatus.standHours, standHoursGoal: standStatus.standHoursGoal, timestamp: Date.now() }, sound: true, priority: 'normal', }); console.log('站立提醒通知发送成功'); return true; } catch (error) { console.error('检查站立状态并发送提醒失败:', error); return false; } } /** * 生成站立提醒消息 */ private static generateStandReminderMessage(userName: string, currentStandHours: number, goalHours: number): string { const currentHour = new Date().getHours(); const progress = Math.round((currentStandHours / goalHours) * 100); const messages = [ `${userName},该站起来活动一下了!当前已完成${progress}%的站立目标`, `${userName},久坐伤身,起来走走吧~已站立${currentStandHours}/${goalHours}小时`, `${userName},站立一会儿对健康有益,目前进度${currentStandHours}/${goalHours}小时`, `${userName},记得起身活动哦!今日站立进度${progress}%` ]; // 根据时间选择不同的消息 const messageIndex = currentHour % messages.length; return messages[messageIndex]; } /** * 取消所有站立提醒通知 */ static async cancelStandReminders(): Promise { try { await GeneralNotificationHelpers.cancelNotificationsByType('stand_reminder'); console.log('已取消所有站立提醒通知'); } catch (error) { console.error('取消站立提醒通知失败:', error); } } } /** * 通知模板 */ export const NotificationTemplates = { workout: { start: (userName: string) => ({ title: '运动时间到', body: `${userName},该开始今天的普拉提训练了!`, data: { type: 'workout_start' }, sound: true, priority: 'high' as const, }), complete: (userName: string, duration: number) => ({ title: '运动完成', body: `${userName},恭喜您完成了${duration}分钟的训练!`, data: { type: 'workout_complete' }, sound: true, priority: 'normal' as const, }), }, goal: { achievement: (userName: string, goalName: string) => ({ title: '目标达成', body: `${userName},恭喜您达成了目标:${goalName}!`, data: { type: 'goal_achievement', goalName }, sound: true, priority: 'high' as const, }), progress: (userName: string, goalName: string, progress: number) => ({ title: '目标进度', body: `${userName},您的目标"${goalName}"已完成${progress}%!`, data: { type: 'goal_progress', goalName, progress }, sound: true, priority: 'normal' as const, }), }, mood: { reminder: (userName: string) => ({ title: '心情打卡', body: `${userName},记得记录今天的心情状态哦`, data: { type: 'mood_checkin_reminder' }, sound: true, priority: 'normal' as const, }), }, nutrition: { reminder: (userName: string, meal: string) => { const mealTypeMap: Record = { '早餐': 'breakfast', '午餐': 'lunch', '晚餐': 'dinner', '加餐': 'snack' }; const coachUrl = buildCoachDeepLink({ action: 'diet', subAction: 'card', meal: mealTypeMap[meal] as 'breakfast' | 'lunch' | 'dinner' | 'snack' }); return { title: `${meal}提醒`, body: `${userName},记得记录您的${meal}情况`, data: { type: 'meal_reminder', meal, url: coachUrl }, sound: true, priority: 'normal' as const, }; }, lunch: (userName: string) => { const coachUrl = buildCoachDeepLink({ action: 'diet', subAction: 'card', meal: 'lunch' }); return { title: '午餐记录提醒', body: `${userName},记得记录今天的午餐情况哦!`, data: { type: 'lunch_reminder', meal: '午餐', url: coachUrl }, sound: true, priority: 'normal' as const, }; }, }, water: { reminder: (userName: string, completionRate: number, remainingAmount: number) => ({ title: '💧 该喝水啦!', body: `${userName},今日喝水进度${completionRate}%,还需要${Math.round(remainingAmount)}ml,记得补充水分~`, data: { type: 'water_reminder', completionRate, remainingAmount: Math.round(remainingAmount), url: '/statistics' }, sound: true, priority: 'normal' as const, }), regular: (userName: string) => ({ title: '💧 定时喝水提醒', body: `${userName},该喝水啦!记得补充水分,保持身体健康~`, data: { type: 'regular_water_reminder', url: '/statistics' }, sound: true, priority: 'normal' as const, }), achievement: (userName: string) => ({ title: '🎉 喝水目标达成!', body: `${userName},恭喜您完成了今天的喝水目标!继续保持健康的饮水习惯~`, data: { type: 'water_achievement', url: '/statistics' }, sound: true, priority: 'high' as const, }), }, dailySummary: { reminder: (userName: string) => ({ title: '今日健康总结', body: `${userName},来看看今天的健康生活总结吧~每一份记录都是成长的足迹!✨`, data: { type: 'daily_summary_reminder', url: '/statistics' }, sound: true, priority: 'normal' as const, }), highCompletion: (userName: string, completedItems: string[]) => ({ title: '今天表现棒极了!', body: `${userName},今天您${completedItems.join('、')},真的很棒!继续保持这样的好习惯!🌟`, data: { type: 'daily_summary', completedItems, url: '/statistics' }, sound: true, priority: 'normal' as const, }), mediumCompletion: (userName: string, completedItems: string[], encouragementItems: string[]) => ({ title: '今日健康小结', body: `${userName},今天您${completedItems.join('、')},已经很不错了!明天记得关注一下${encouragementItems.join('、')},让健康生活更完整~`, data: { type: 'daily_summary', completedItems, encouragementItems, url: '/statistics' }, sound: true, priority: 'normal' as const, }), lowCompletion: (userName: string, encouragementItems: string[]) => ({ title: '明天是新的开始', body: `${userName},今天可能比较忙碌。明天记得关注${encouragementItems.slice(0, 2).join('和')},每一个小改变都是向健康生活迈进的一步~💪`, data: { type: 'daily_summary', encouragementItems, url: '/statistics' }, sound: true, priority: 'normal' as const, }), }, };