refactor(health): remove basalEnergyBurned from global state and move to local component
Remove basalEnergyBurned from global health data structure and refactor BasalMetabolismCard to fetch its own data locally. This decouples the component from global state and improves data locality. - Remove basalEnergyBurned from HealthData interface and health utilities - Update BasalMetabolismCard to use selectedDate prop and fetch data locally - Simplify statistics screen by removing unused basalMetabolism variable - Update nutrition radar card to use activeCalories only for burned calories calculation
This commit is contained in:
@@ -89,7 +89,6 @@ export default function ExploreScreen() {
|
|||||||
// 解构健康数据(支持mock数据)
|
// 解构健康数据(支持mock数据)
|
||||||
const mockData = useMockData ? getTestHealthData('mock') : null;
|
const mockData = useMockData ? getTestHealthData('mock') : null;
|
||||||
const activeCalories = useMockData ? (mockData?.activeEnergyBurned ?? null) : (healthData?.activeEnergyBurned ?? null);
|
const activeCalories = useMockData ? (mockData?.activeEnergyBurned ?? null) : (healthData?.activeEnergyBurned ?? null);
|
||||||
const basalMetabolism: number | null = useMockData ? (mockData?.basalEnergyBurned ?? null) : (healthData?.basalEnergyBurned ?? null);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -230,7 +229,6 @@ export default function ExploreScreen() {
|
|||||||
date: dateString,
|
date: dateString,
|
||||||
data: {
|
data: {
|
||||||
activeCalories: data.activeEnergyBurned,
|
activeCalories: data.activeEnergyBurned,
|
||||||
basalEnergyBurned: data.basalEnergyBurned,
|
|
||||||
hrv: data.hrv,
|
hrv: data.hrv,
|
||||||
heartRate: data.heartRate,
|
heartRate: data.heartRate,
|
||||||
activeEnergyBurned: data.activeEnergyBurned,
|
activeEnergyBurned: data.activeEnergyBurned,
|
||||||
@@ -459,8 +457,8 @@ export default function ExploreScreen() {
|
|||||||
{/* 营养摄入雷达图卡片 */}
|
{/* 营养摄入雷达图卡片 */}
|
||||||
<NutritionRadarCard
|
<NutritionRadarCard
|
||||||
nutritionSummary={nutritionSummary}
|
nutritionSummary={nutritionSummary}
|
||||||
burnedCalories={(basalMetabolism || 0) + (activeCalories || 0)}
|
burnedCalories={activeCalories || 0}
|
||||||
basalMetabolism={basalMetabolism || 0}
|
basalMetabolism={0}
|
||||||
activeCalories={activeCalories || 0}
|
activeCalories={activeCalories || 0}
|
||||||
resetToken={animToken}
|
resetToken={animToken}
|
||||||
/>
|
/>
|
||||||
@@ -532,8 +530,7 @@ export default function ExploreScreen() {
|
|||||||
{/* 基础代谢卡片 */}
|
{/* 基础代谢卡片 */}
|
||||||
<FloatingCard style={styles.masonryCard} delay={1250}>
|
<FloatingCard style={styles.masonryCard} delay={1250}>
|
||||||
<BasalMetabolismCard
|
<BasalMetabolismCard
|
||||||
value={basalMetabolism}
|
selectedDate={currentSelectedDate}
|
||||||
resetToken={animToken}
|
|
||||||
style={styles.basalMetabolismCardOverride}
|
style={styles.basalMetabolismCardOverride}
|
||||||
/>
|
/>
|
||||||
</FloatingCard>
|
</FloatingCard>
|
||||||
|
|||||||
@@ -1,27 +1,48 @@
|
|||||||
import { AnimatedNumber } from '@/components/AnimatedNumber';
|
import { fetchHealthDataForDate } from '@/utils/health';
|
||||||
import { Image } from 'expo-image';
|
import { Image } from 'expo-image';
|
||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { StyleSheet, Text, View } from 'react-native';
|
import { StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
interface BasalMetabolismCardProps {
|
interface BasalMetabolismCardProps {
|
||||||
value: number | null;
|
selectedDate?: Date;
|
||||||
resetToken?: number;
|
|
||||||
style?: any;
|
style?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BasalMetabolismCard({ value, resetToken, style }: BasalMetabolismCardProps) {
|
export function BasalMetabolismCard({ selectedDate, style }: BasalMetabolismCardProps) {
|
||||||
|
const [basalMetabolism, setBasalMetabolism] = useState<number | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
// 获取基础代谢数据
|
||||||
|
useEffect(() => {
|
||||||
|
const loadBasalMetabolismData = async () => {
|
||||||
|
if (!selectedDate) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const data = await fetchHealthDataForDate(selectedDate);
|
||||||
|
setBasalMetabolism(data?.basalEnergyBurned || null);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('BasalMetabolismCard: 获取基础代谢数据失败:', error);
|
||||||
|
setBasalMetabolism(null);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadBasalMetabolismData();
|
||||||
|
}, [selectedDate]);
|
||||||
// 获取基础代谢状态描述
|
// 获取基础代谢状态描述
|
||||||
const getMetabolismStatus = () => {
|
const getMetabolismStatus = () => {
|
||||||
if (value === null || value === 0) {
|
if (basalMetabolism === null || basalMetabolism === 0) {
|
||||||
return { text: '未知', color: '#9AA3AE' };
|
return { text: '未知', color: '#9AA3AE' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 基于常见的基础代谢范围来判断状态
|
// 基于常见的基础代谢范围来判断状态
|
||||||
if (value >= 1800) {
|
if (basalMetabolism >= 1800) {
|
||||||
return { text: '高代谢', color: '#10B981' };
|
return { text: '高代谢', color: '#10B981' };
|
||||||
} else if (value >= 1400) {
|
} else if (basalMetabolism >= 1400) {
|
||||||
return { text: '正常', color: '#3B82F6' };
|
return { text: '正常', color: '#3B82F6' };
|
||||||
} else if (value >= 1000) {
|
} else if (basalMetabolism >= 1000) {
|
||||||
return { text: '偏低', color: '#F59E0B' };
|
return { text: '偏低', color: '#F59E0B' };
|
||||||
} else {
|
} else {
|
||||||
return { text: '较低', color: '#EF4444' };
|
return { text: '较低', color: '#EF4444' };
|
||||||
@@ -49,16 +70,9 @@ export function BasalMetabolismCard({ value, resetToken, style }: BasalMetabolis
|
|||||||
|
|
||||||
{/* 数值显示区域 */}
|
{/* 数值显示区域 */}
|
||||||
<View style={styles.valueSection}>
|
<View style={styles.valueSection}>
|
||||||
{value != null && value > 0 ? (
|
<Text style={styles.value}>
|
||||||
<AnimatedNumber
|
{loading ? '加载中...' : (basalMetabolism != null && basalMetabolism > 0 ? Math.round(basalMetabolism).toString() : '--')}
|
||||||
value={value}
|
</Text>
|
||||||
resetToken={resetToken}
|
|
||||||
style={styles.value}
|
|
||||||
format={(v) => Math.round(v).toString()}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Text style={styles.value}>--</Text>
|
|
||||||
)}
|
|
||||||
<Text style={styles.unit}>千卡/日</Text>
|
<Text style={styles.unit}>千卡/日</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ export interface FitnessRingsData {
|
|||||||
|
|
||||||
export interface HealthData {
|
export interface HealthData {
|
||||||
activeCalories: number | null;
|
activeCalories: number | null;
|
||||||
basalEnergyBurned: number | null;
|
|
||||||
hrv: number | null;
|
hrv: number | null;
|
||||||
heartRate: number | null;
|
heartRate: number | null;
|
||||||
activeEnergyBurned: number;
|
activeEnergyBurned: number;
|
||||||
|
|||||||
@@ -207,7 +207,6 @@ export type HourlyStandData = {
|
|||||||
|
|
||||||
export type TodayHealthData = {
|
export type TodayHealthData = {
|
||||||
activeEnergyBurned: number; // kilocalories
|
activeEnergyBurned: number; // kilocalories
|
||||||
basalEnergyBurned: number; // kilocalories - 基础代谢率
|
|
||||||
hrv: number | null; // 心率变异性 (ms)
|
hrv: number | null; // 心率变异性 (ms)
|
||||||
// 健身圆环数据
|
// 健身圆环数据
|
||||||
activeCalories: number;
|
activeCalories: number;
|
||||||
@@ -608,7 +607,6 @@ export async function fetchMaximumHeartRate(_options: HealthDataOptions): Promis
|
|||||||
function getDefaultHealthData(): TodayHealthData {
|
function getDefaultHealthData(): TodayHealthData {
|
||||||
return {
|
return {
|
||||||
activeEnergyBurned: 0,
|
activeEnergyBurned: 0,
|
||||||
basalEnergyBurned: 0,
|
|
||||||
hrv: null,
|
hrv: null,
|
||||||
activeCalories: 0,
|
activeCalories: 0,
|
||||||
activeCaloriesGoal: 350,
|
activeCaloriesGoal: 350,
|
||||||
@@ -630,13 +628,11 @@ export async function fetchHealthDataForDate(date: Date): Promise<TodayHealthDat
|
|||||||
// 并行获取所有健康数据
|
// 并行获取所有健康数据
|
||||||
const [
|
const [
|
||||||
activeEnergyBurned,
|
activeEnergyBurned,
|
||||||
basalEnergyBurned,
|
|
||||||
hrv,
|
hrv,
|
||||||
activitySummary,
|
activitySummary,
|
||||||
heartRate
|
heartRate
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
fetchActiveEnergyBurned(options),
|
fetchActiveEnergyBurned(options),
|
||||||
fetchBasalEnergyBurned(options),
|
|
||||||
fetchHeartRateVariability(options),
|
fetchHeartRateVariability(options),
|
||||||
fetchActivitySummary(options),
|
fetchActivitySummary(options),
|
||||||
fetchHeartRate(options)
|
fetchHeartRate(options)
|
||||||
@@ -644,7 +640,6 @@ export async function fetchHealthDataForDate(date: Date): Promise<TodayHealthDat
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
activeEnergyBurned,
|
activeEnergyBurned,
|
||||||
basalEnergyBurned,
|
|
||||||
hrv,
|
hrv,
|
||||||
activeCalories: Math.round(activitySummary?.activeEnergyBurned || 0),
|
activeCalories: Math.round(activitySummary?.activeEnergyBurned || 0),
|
||||||
activeCaloriesGoal: Math.round(activitySummary?.activeEnergyBurnedGoal || 350),
|
activeCaloriesGoal: Math.round(activitySummary?.activeEnergyBurnedGoal || 350),
|
||||||
|
|||||||
Reference in New Issue
Block a user