feat(water): 重构饮水模块并新增自定义提醒设置功能

- 新增饮水详情页面 `/water/detail` 展示每日饮水记录与统计
- 新增饮水设置页面 `/water/settings` 支持目标与快速添加配置
- 新增喝水提醒设置页面 `/water/reminder-settings` 支持自定义时间段与间隔
- 重构 `useWaterData` Hook,支持按日期查询与实时刷新
- 新增 `WaterNotificationHelpers.scheduleCustomWaterReminders` 实现个性化提醒
- 优化心情编辑页键盘体验,新增 `KeyboardAvoidingView` 与滚动逻辑
- 升级版本号至 1.0.14 并补充路由常量
- 补充用户偏好存储字段 `waterReminderEnabled/startTime/endTime/interval`
- 废弃后台定时任务中的旧版喝水提醒逻辑,改为用户手动管理
This commit is contained in:
richarjiang
2025-09-26 11:02:17 +08:00
parent badd68c039
commit a014998848
13 changed files with 1732 additions and 206 deletions

View File

@@ -822,6 +822,102 @@ export class WaterNotificationHelpers {
}
}
/**
* 根据用户设置安排喝水提醒通知
* @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<string[]> {
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;
}
}
/**
* 取消所有喝水提醒
*/
@@ -831,7 +927,8 @@ export class WaterNotificationHelpers {
for (const notification of notifications) {
if (notification.content.data?.type === 'water_reminder' ||
notification.content.data?.type === 'regular_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);
}