import type { Medication } from '@/types/medication'; import { getMedicationReminderEnabled, getNotificationEnabled } from '@/utils/userPreferences'; import * as Notifications from 'expo-notifications'; import { notificationService, NotificationTypes } from './notifications'; /** * 药品通知服务 * 负责管理药品提醒通知的调度和取消 */ export class MedicationNotificationService { private static instance: MedicationNotificationService; private notificationPrefix = 'medication_'; private constructor() {} public static getInstance(): MedicationNotificationService { if (!MedicationNotificationService.instance) { MedicationNotificationService.instance = new MedicationNotificationService(); } return MedicationNotificationService.instance; } /** * 检查是否可以发送药品通知 */ private async canSendMedicationNotifications(): Promise { try { // 检查总通知开关 const notificationEnabled = await getNotificationEnabled(); if (!notificationEnabled) { console.log('总通知开关已关闭,跳过药品通知'); return false; } // 检查药品通知开关 const medicationReminderEnabled = await getMedicationReminderEnabled(); if (!medicationReminderEnabled) { console.log('药品通知开关已关闭,跳过药品通知'); return false; } // 检查系统权限 const permissionStatus = await notificationService.getPermissionStatus(); if (permissionStatus !== 'granted') { console.log('系统通知权限未授予,跳过药品通知'); return false; } return true; } catch (error) { console.error('检查药品通知权限失败:', error); return false; } } /** * 为药品安排通知 */ async scheduleMedicationNotifications(medication: Medication): Promise { try { const canSend = await this.canSendMedicationNotifications(); if (!canSend) { console.log('药品通知权限不足,跳过安排通知'); return; } // 先取消该药品的现有通知 await this.cancelMedicationNotifications(medication.id); // 为每个用药时间安排通知 for (const time of medication.medicationTimes) { const [hour, minute] = time.split(':').map(Number); // 创建通知内容 const notificationContent = { title: '用药提醒', body: `该服用 ${medication.name} 了 (${medication.dosageValue}${medication.dosageUnit})`, data: { type: NotificationTypes.MEDICATION_REMINDER, medicationId: medication.id, medicationName: medication.name, dosage: `${medication.dosageValue}${medication.dosageUnit}`, }, sound: true, priority: 'high' as const, }; // 安排每日重复通知 const notificationId = await notificationService.scheduleCalendarRepeatingNotification( notificationContent, { type: Notifications.SchedulableTriggerInputTypes.DAILY, hour, minute, } ); console.log(`已为药品 ${medication.name} 安排通知,时间: ${time},通知ID: ${notificationId}`); } } catch (error) { console.error('安排药品通知失败:', error); } } /** * 取消药品的所有通知 */ async cancelMedicationNotifications(medicationId: string): Promise { try { // 获取所有已安排的通知 const allNotifications = await notificationService.getAllScheduledNotifications(); // 过滤出该药品的通知并取消 for (const notification of allNotifications) { const data = notification.content.data as any; if (data?.type === NotificationTypes.MEDICATION_REMINDER && data?.medicationId === medicationId) { await notificationService.cancelNotification(notification.identifier); console.log(`已取消药品通知,ID: ${notification.identifier}`); } } } catch (error) { console.error('取消药品通知失败:', error); } } /** * 重新安排所有激活药品的通知 */ async rescheduleAllMedicationNotifications(medications: Medication[]): Promise { try { // 先取消所有药品通知 for (const medication of medications) { await this.cancelMedicationNotifications(medication.id); } // 重新安排激活药品的通知 const activeMedications = medications.filter(m => m.isActive); for (const medication of activeMedications) { await this.scheduleMedicationNotifications(medication); } console.log(`已重新安排 ${activeMedications.length} 个激活药品的通知`); } catch (error) { console.error('重新安排药品通知失败:', error); } } /** * 发送立即的药品通知(用于测试) */ async sendTestMedicationNotification(medication: Medication): Promise { try { const canSend = await this.canSendMedicationNotifications(); if (!canSend) { throw new Error('药品通知权限不足'); } return await notificationService.sendImmediateNotification({ title: '用药提醒测试', body: `这是 ${medication.name} 的测试通知 (${medication.dosageValue}${medication.dosageUnit})`, data: { type: NotificationTypes.MEDICATION_REMINDER, medicationId: medication.id, medicationName: medication.name, dosage: `${medication.dosageValue}${medication.dosageUnit}`, }, sound: true, priority: 'high', }); } catch (error) { console.error('发送测试药品通知失败:', error); throw error; } } /** * 获取所有已安排的药品通知 */ async getMedicationNotifications(): Promise { try { const allNotifications = await notificationService.getAllScheduledNotifications(); // 过滤出药品相关的通知 return allNotifications.filter(notification => notification.content.data?.type === NotificationTypes.MEDICATION_REMINDER ); } catch (error) { console.error('获取药品通知失败:', error); return []; } } } // 导出单例实例 export const medicationNotificationService = MedicationNotificationService.getInstance();