import * as Notifications from 'expo-notifications'; import { NotificationData, notificationService } from '../services/notifications'; /** * 构建 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 } ); } } /** * 目标相关的通知辅助函数 */ export class GoalNotificationHelpers { /** * 发送目标达成通知 */ static async sendGoalAchievementNotification(userName: string, goalName: string) { return notificationService.sendImmediateNotification({ title: '目标达成', body: `${userName},恭喜您达成了目标:${goalName}!`, data: { type: 'goal_achievement', goalName }, sound: true, priority: 'high', }); } /** * 发送目标进度更新通知 */ static async sendGoalProgressNotification(userName: string, goalName: string, progress: number) { return notificationService.sendImmediateNotification({ title: '目标进度', body: `${userName},您的目标"${goalName}"已完成${progress}%!`, data: { type: 'goal_progress', goalName, progress }, sound: true, priority: 'normal', }); } /** * 安排目标提醒 */ static async scheduleGoalReminder(userName: string, goalName: string, deadline: Date) { // 在截止日期前一天发送提醒 const reminderDate = new Date(deadline); reminderDate.setDate(reminderDate.getDate() - 1); return notificationService.scheduleNotificationAtDate( { title: '目标截止提醒', body: `${userName},您的目标"${goalName}"明天就要截止了,加油!`, data: { type: 'goal_deadline_reminder', goalName }, sound: true, priority: 'high', }, reminderDate ); } /** * 根据目标设置创建定时推送 * @param goalData 目标数据 * @param userName 用户名 * @returns 通知ID数组 */ static async scheduleGoalNotifications( goalData: { title: string; repeatType: 'daily' | 'weekly' | 'monthly'; frequency: number; hasReminder: boolean; reminderTime?: string; customRepeatRule?: { weekdays?: number[]; dayOfMonth?: number[]; }; startTime?: number; }, userName: string ): Promise { const notificationIds: string[] = []; // 如果没有开启提醒,直接返回 if (!goalData.hasReminder || !goalData.reminderTime) { console.log('目标未开启提醒或未设置提醒时间'); return notificationIds; } try { // 解析提醒时间 const [hours, minutes] = goalData.reminderTime.split(':').map(Number); // 创建通知内容 const notification: NotificationData = { title: '目标提醒', body: `${userName},该完成您的目标"${goalData.title}"了!`, data: { type: 'goal_reminder', goalTitle: goalData.title, repeatType: goalData.repeatType, frequency: goalData.frequency }, sound: true, priority: 'high', }; // 根据重复类型创建不同的通知 switch (goalData.repeatType) { case 'daily': // 每日重复 - 使用日历重复通知 const dailyId = await notificationService.scheduleCalendarRepeatingNotification( notification, { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour: hours, minute: minutes, } ); notificationIds.push(dailyId); console.log(`已安排每日目标提醒,通知ID:${dailyId}`); break; case 'weekly': // 每周重复 - 为每个选中的星期几创建单独的通知 if (goalData.customRepeatRule?.weekdays && goalData.customRepeatRule.weekdays.length > 0) { for (const weekday of goalData.customRepeatRule.weekdays) { const weeklyId = await notificationService.scheduleCalendarRepeatingNotification( notification, { type: Notifications.SchedulableTriggerInputTypes.WEEKLY, hour: hours, minute: minutes, weekdays: [weekday], } ); notificationIds.push(weeklyId); console.log(`已安排每周目标提醒,星期${weekday},通知ID:${weeklyId}`); } } else { // 默认每周重复 const weeklyId = await notificationService.scheduleCalendarRepeatingNotification( notification, { type: Notifications.SchedulableTriggerInputTypes.WEEKLY, hour: hours, minute: minutes, } ); notificationIds.push(weeklyId); console.log(`已安排每周目标提醒,通知ID:${weeklyId}`); } break; case 'monthly': // 每月重复 - 为每个选中的日期创建单独的通知 if (goalData.customRepeatRule?.dayOfMonth && goalData.customRepeatRule.dayOfMonth.length > 0) { for (const dayOfMonth of goalData.customRepeatRule.dayOfMonth) { const monthlyId = await notificationService.scheduleCalendarRepeatingNotification( notification, { type: Notifications.SchedulableTriggerInputTypes.MONTHLY, hour: hours, minute: minutes, dayOfMonth: dayOfMonth, } ); notificationIds.push(monthlyId); console.log(`已安排每月目标提醒,${dayOfMonth}号,通知ID:${monthlyId}`); } } else { // 默认每月重复 const monthlyId = await notificationService.scheduleCalendarRepeatingNotification( notification, { type: Notifications.SchedulableTriggerInputTypes.MONTHLY, hour: hours, minute: minutes, dayOfMonth: 1, } ); notificationIds.push(monthlyId); console.log(`已安排每月目标提醒,通知ID:${monthlyId}`); } break; } console.log(`目标"${goalData.title}"的定时推送已创建完成,共${notificationIds.length}个通知`); return notificationIds; } catch (error) { console.error('创建目标定时推送失败:', error); throw error; } } /** * 取消特定目标的所有通知 */ static async cancelGoalNotifications(goalTitle: string): Promise { try { const notifications = await notificationService.getAllScheduledNotifications(); for (const notification of notifications) { if (notification.content.data?.type === 'goal_reminder' && notification.content.data?.goalTitle === goalTitle) { await notificationService.cancelNotification(notification.identifier); console.log(`已取消目标"${goalTitle}"的通知:${notification.identifier}`); } } } catch (error) { console.error('取消目标通知失败:', error); throw error; } } } /** * 心情相关的通知辅助函数 */ export class MoodNotificationHelpers { /** * 发送心情打卡提醒 */ static async sendMoodCheckinReminder(userName: string) { return notificationService.sendImmediateNotification({ title: '心情打卡', body: `${userName},记得记录今天的心情状态哦`, data: { type: 'mood_checkin_reminder' }, sound: true, priority: 'normal', }); } /** * 安排每日心情打卡提醒 */ static async scheduleDailyMoodReminder(userName: string, hour: number = 20, 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_mood_reminder' }, sound: true, priority: 'normal', }, { days: 1 } ); } } /** * 营养相关的通知辅助函数 */ 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(); console.log('existingNotifications', existingNotifications); 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; } } /** * 发送午餐记录提醒 */ static async sendLunchReminder(userName: string) { const coachUrl = buildCoachDeepLink({ action: 'diet', subAction: 'card', meal: 'lunch' }); return notificationService.sendImmediateNotification({ title: '午餐记录提醒', body: `${userName},记得记录今天的午餐情况哦!`, data: { type: 'lunch_reminder', meal: '午餐', url: coachUrl }, sound: true, priority: 'normal', }); } /** * 取消午餐提醒 */ static async cancelLunchReminder(): Promise { try { const notifications = await notificationService.getAllScheduledNotifications(); for (const notification of notifications) { if (notification.content.data?.type === 'lunch_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 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 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, }; }, }, };