feat(challenges): 排行榜支持单位显示与健身圆环自动上报进度
- ChallengeRankingItem 新增 unit 字段,支持按单位格式化今日进度 - FitnessRingsCard 监听圆环闭合,自动向进行中的运动挑战上报 1 次进度 - 过滤已结束挑战,确保睡眠、喝水、运动进度仅上报进行中活动 - 移除 StressMeter 调试日志与 challengesSlice 多余打印
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
import React, { useState, useCallback, useRef } from 'react';
|
||||
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
|
||||
import { router } from 'expo-router';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import { CircularRing } from './CircularRing';
|
||||
import { ROUTES } from '@/constants/Routes';
|
||||
import { fetchActivityRingsForDate, ActivityRingsData } from '@/utils/health';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { ChallengeType } from '@/services/challengesApi';
|
||||
import { reportChallengeProgress, selectChallengeList } from '@/store/challengesSlice';
|
||||
import { ActivityRingsData, fetchActivityRingsForDate } from '@/utils/health';
|
||||
import { logger } from '@/utils/logger';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import dayjs from 'dayjs';
|
||||
import { router } from 'expo-router';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { CircularRing } from './CircularRing';
|
||||
|
||||
type FitnessRingsCardProps = {
|
||||
style?: any;
|
||||
@@ -21,9 +26,17 @@ export function FitnessRingsCard({
|
||||
selectedDate,
|
||||
resetToken,
|
||||
}: FitnessRingsCardProps) {
|
||||
const dispatch = useAppDispatch();
|
||||
const challenges = useAppSelector(selectChallengeList);
|
||||
const [activityData, setActivityData] = useState<ActivityRingsData | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const loadingRef = useRef(false);
|
||||
const lastReportedRef = useRef<{ date: string } | null>(null);
|
||||
|
||||
const joinedExerciseChallenges = useMemo(
|
||||
() => challenges.filter((challenge) => challenge.type === ChallengeType.EXERCISE && challenge.isJoined && challenge.status === 'ongoing'),
|
||||
[challenges]
|
||||
);
|
||||
|
||||
// 获取健身圆环数据 - 在页面聚焦、日期变化、从后台切换到前台时触发
|
||||
useFocusEffect(
|
||||
@@ -52,6 +65,63 @@ export function FitnessRingsCard({
|
||||
}, [selectedDate])
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedDate || !activityData || !joinedExerciseChallenges.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dayjs(selectedDate).isSame(dayjs(), 'day')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
activeEnergyBurned,
|
||||
activeEnergyBurnedGoal,
|
||||
appleExerciseTime,
|
||||
appleExerciseTimeGoal,
|
||||
appleStandHours,
|
||||
appleStandHoursGoal,
|
||||
} = activityData;
|
||||
|
||||
if (
|
||||
activeEnergyBurnedGoal <= 0 ||
|
||||
appleExerciseTimeGoal <= 0 ||
|
||||
appleStandHoursGoal <= 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const allRingsClosed =
|
||||
activeEnergyBurned >= activeEnergyBurnedGoal &&
|
||||
appleExerciseTime >= appleExerciseTimeGoal &&
|
||||
appleStandHours >= appleStandHoursGoal;
|
||||
|
||||
if (!allRingsClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dateKey = dayjs(selectedDate).format('YYYY-MM-DD');
|
||||
if (lastReportedRef.current?.date === dateKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
const exerciseChallenge = joinedExerciseChallenges[0];
|
||||
if (!exerciseChallenge) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reportProgressAsync = async () => {
|
||||
try {
|
||||
await dispatch(reportChallengeProgress({ id: exerciseChallenge.id, value: 1 })).unwrap();
|
||||
lastReportedRef.current = { date: dateKey };
|
||||
} catch (error) {
|
||||
logger.warn('FitnessRingsCard: 挑战进度上报失败', { error, challengeId: exerciseChallenge.id });
|
||||
}
|
||||
};
|
||||
|
||||
reportProgressAsync();
|
||||
}, [activityData, dispatch, joinedExerciseChallenges, selectedDate]);
|
||||
|
||||
// 使用获取到的数据或默认值
|
||||
const activeCalories = activityData?.activeEnergyBurned ?? 0;
|
||||
const activeCaloriesGoal = activityData?.activeEnergyBurnedGoal ?? 350;
|
||||
@@ -229,4 +299,4 @@ const styles = StyleSheet.create({
|
||||
minWidth: 25,
|
||||
textAlign: 'right',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user