feat(用药管理): 集成AI智能分析功能,提供用药依从性深度洞察和专业健康建议

This commit is contained in:
richarjiang
2025-12-01 10:49:35 +08:00
parent a309123b35
commit a47f0fb72e
15 changed files with 1792 additions and 468 deletions

View File

@@ -1,14 +1,17 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
Animated,
InteractionManager,
StyleSheet,
Text,
TouchableOpacity,
View,
ViewStyle
Animated,
InteractionManager,
StyleSheet,
Text,
TouchableOpacity,
View,
ViewStyle
} from 'react-native';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { ChallengeType } from '@/services/challengesApi';
import { reportChallengeProgress, selectChallengeList } from '@/store/challengesSlice';
import { fetchHourlyStepSamples, fetchStepCount, HourlyStepData } from '@/utils/health';
import { logger } from '@/utils/logger';
import dayjs from 'dayjs';
@@ -20,8 +23,8 @@ import { AnimatedNumber } from './AnimatedNumber';
// import Svg, { Rect } from 'react-native-svg';
interface StepsCardProps {
curDate: Date
stepGoal: number;
curDate: Date;
stepGoal?: number;
style?: ViewStyle;
}
@@ -31,9 +34,20 @@ const StepsCard: React.FC<StepsCardProps> = ({
}) => {
const { t } = useTranslation();
const router = useRouter();
const dispatch = useAppDispatch();
const challenges = useAppSelector(selectChallengeList);
const [stepCount, setStepCount] = useState(0)
const [hourlySteps, setHourSteps] = useState<HourlyStepData[]>([])
const [stepCount, setStepCount] = useState(0);
const [hourlySteps, setHourSteps] = useState<HourlyStepData[]>([]);
// 过滤出已参加的步数挑战
const joinedStepsChallenges = useMemo(
() => challenges.filter((challenge) => challenge.type === ChallengeType.STEP && challenge.isJoined && challenge.status === 'ongoing'),
[challenges]
);
// 跟踪上次上报的记录,避免重复上报
const lastReportedRef = useRef<{ date: string; value: number } | null>(null);
const getStepData = useCallback(async (date: Date) => {
@@ -59,6 +73,42 @@ const StepsCard: React.FC<StepsCardProps> = ({
}
}, [curDate]);
// 步数挑战进度上报逻辑
useEffect(() => {
if (!curDate || !stepCount || !joinedStepsChallenges.length) {
return;
}
// 如果当前日期不是今天,不上报
if (!dayjs(curDate).isSame(dayjs(), 'day')) {
return;
}
const dateKey = dayjs(curDate).format('YYYY-MM-DD');
const lastReport = lastReportedRef.current;
if (lastReport && lastReport.date === dateKey && lastReport.value === stepCount) {
return;
}
const reportProgress = async () => {
const stepsChallenge = joinedStepsChallenges.find((c) => c.type === ChallengeType.STEP);
if (!stepsChallenge) {
return;
}
try {
await dispatch(reportChallengeProgress({ id: stepsChallenge.id, value: stepCount })).unwrap();
} catch (error) {
logger.warn('StepsCard: Challenge progress report failed', { error, challengeId: stepsChallenge.id });
}
lastReportedRef.current = { date: dateKey, value: stepCount };
};
reportProgress();
}, [dispatch, joinedStepsChallenges, curDate, stepCount]);
// 优化:减少动画值数量,只为有数据的小时创建动画
const animatedValues = useRef<Map<number, Animated.Value>>(new Map()).current;