feat(water): 后台任务同步HealthKit饮水记录并优化目标读取逻辑
This commit is contained in:
@@ -7,19 +7,19 @@ import { useAuthGuard } from '@/hooks/useAuthGuard';
|
|||||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||||
import {
|
import {
|
||||||
fetchChallengeDetail,
|
fetchChallengeDetail,
|
||||||
|
fetchChallengeRankings,
|
||||||
joinChallenge,
|
joinChallenge,
|
||||||
leaveChallenge,
|
leaveChallenge,
|
||||||
reportChallengeProgress,
|
reportChallengeProgress,
|
||||||
fetchChallengeRankings,
|
|
||||||
selectChallengeById,
|
selectChallengeById,
|
||||||
selectChallengeDetailError,
|
selectChallengeDetailError,
|
||||||
selectChallengeDetailStatus,
|
selectChallengeDetailStatus,
|
||||||
|
selectChallengeRankingList,
|
||||||
selectJoinError,
|
selectJoinError,
|
||||||
selectJoinStatus,
|
selectJoinStatus,
|
||||||
selectLeaveError,
|
selectLeaveError,
|
||||||
selectLeaveStatus,
|
selectLeaveStatus,
|
||||||
selectProgressStatus,
|
selectProgressStatus
|
||||||
selectChallengeRankingList
|
|
||||||
} from '@/store/challengesSlice';
|
} from '@/store/challengesSlice';
|
||||||
import { Toast } from '@/utils/toast.utils';
|
import { Toast } from '@/utils/toast.utils';
|
||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ import AsyncStorage from '@/utils/kvStore';
|
|||||||
import { log } from '@/utils/logger';
|
import { log } from '@/utils/logger';
|
||||||
import { listChallenges } from '@/services/challengesApi';
|
import { listChallenges } from '@/services/challengesApi';
|
||||||
import { ChallengeNotificationHelpers, StandReminderHelpers, WaterNotificationHelpers } from '@/utils/notificationHelpers';
|
import { ChallengeNotificationHelpers, StandReminderHelpers, WaterNotificationHelpers } from '@/utils/notificationHelpers';
|
||||||
|
import { getWaterIntakeFromHealthKit } from '@/utils/health';
|
||||||
|
import { getWaterGoalFromStorage } from '@/utils/userPreferences';
|
||||||
import * as BackgroundTask from 'expo-background-task';
|
import * as BackgroundTask from 'expo-background-task';
|
||||||
import * as TaskManager from 'expo-task-manager';
|
import * as TaskManager from 'expo-task-manager';
|
||||||
import { TaskManagerTaskBody } from 'expo-task-manager';
|
import { TaskManagerTaskBody } from 'expo-task-manager';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
export const BACKGROUND_TASK_IDENTIFIER = 'com.anonymous.digitalpilates.task';
|
export const BACKGROUND_TASK_IDENTIFIER = 'com.anonymous.digitalpilates.task';
|
||||||
|
|
||||||
@@ -33,8 +36,13 @@ async function executeWaterReminderTask(): Promise<void> {
|
|||||||
const waterStats = state.water.todayStats;
|
const waterStats = state.water.todayStats;
|
||||||
const userProfile = state.user.profile;
|
const userProfile = state.user.profile;
|
||||||
|
|
||||||
// 检查是否有喝水目标设置
|
// 优先使用 Redux 中的目标,若无则读取本地存储
|
||||||
if (!waterStats || !waterStats.dailyGoal || waterStats.dailyGoal <= 0) {
|
let dailyGoal = waterStats?.dailyGoal ?? 0;
|
||||||
|
if (!dailyGoal || dailyGoal <= 0) {
|
||||||
|
dailyGoal = await getWaterGoalFromStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dailyGoal || dailyGoal <= 0) {
|
||||||
console.log('没有设置喝水目标,跳过喝水提醒');
|
console.log('没有设置喝水目标,跳过喝水提醒');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -45,11 +53,38 @@ async function executeWaterReminderTask(): Promise<void> {
|
|||||||
// 获取用户名
|
// 获取用户名
|
||||||
const userName = userProfile?.name || '朋友';
|
const userName = userProfile?.name || '朋友';
|
||||||
|
|
||||||
|
const todayRange = {
|
||||||
|
startDate: dayjs().startOf('day').toDate().toISOString(),
|
||||||
|
endDate: dayjs().endOf('day').toDate().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
let totalAmount = waterStats?.totalAmount ?? 0;
|
||||||
|
let completionRate = waterStats?.completionRate ?? (dailyGoal > 0 ? (totalAmount / dailyGoal) * 100 : 0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const healthKitRecords = await getWaterIntakeFromHealthKit(todayRange);
|
||||||
|
if (Array.isArray(healthKitRecords) && healthKitRecords.length > 0) {
|
||||||
|
totalAmount = healthKitRecords.reduce((sum: number, record: unknown) => {
|
||||||
|
if (record && typeof record === 'object' && 'value' in record) {
|
||||||
|
const { value } = record as { value?: number | string };
|
||||||
|
const numericValue = Number(value ?? 0);
|
||||||
|
return Number.isFinite(numericValue) ? sum + numericValue : sum;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}, 0);
|
||||||
|
completionRate = Math.min((totalAmount / dailyGoal) * 100, 100);
|
||||||
|
} else {
|
||||||
|
console.log('HealthKit 未返回今日饮水记录,使用应用内缓存数据');
|
||||||
|
}
|
||||||
|
} catch (healthKitError) {
|
||||||
|
console.error('从HealthKit获取饮水记录失败,使用应用内缓存数据:', healthKitError);
|
||||||
|
}
|
||||||
|
|
||||||
// 构造今日统计数据
|
// 构造今日统计数据
|
||||||
const todayWaterStats = {
|
const todayWaterStats = {
|
||||||
totalAmount: waterStats.totalAmount || 0,
|
totalAmount,
|
||||||
dailyGoal: waterStats.dailyGoal,
|
dailyGoal,
|
||||||
completionRate: waterStats.completionRate || 0
|
completionRate: Number.isFinite(completionRate) ? completionRate : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// 调用喝水通知检查函数
|
// 调用喝水通知检查函数
|
||||||
|
|||||||
Reference in New Issue
Block a user