import { AnimatedNumber } from '@/components/AnimatedNumber'; import { ROUTES } from '@/constants/Routes'; import { NutritionSummary } from '@/services/dietRecords'; import { Ionicons } from '@expo/vector-icons'; import dayjs from 'dayjs'; import { router } from 'expo-router'; import React, { useMemo, useState } from 'react'; import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { RadarCategory, RadarChart } from './RadarChart'; export type NutritionRadarCardProps = { nutritionSummary: NutritionSummary | null; /** 基础代谢消耗的卡路里 */ burnedCalories?: number; /** 卡路里缺口 */ calorieDeficit?: number; /** 动画重置令牌 */ resetToken?: number; /** 餐次点击回调 */ onMealPress?: (mealType: 'breakfast' | 'lunch' | 'dinner' | 'snack') => void; }; // 营养维度定义 const NUTRITION_DIMENSIONS: RadarCategory[] = [ { key: 'calories', label: '热量' }, { key: 'protein', label: '蛋白质' }, { key: 'carbohydrate', label: '碳水' }, { key: 'fat', label: '脂肪' }, { key: 'fiber', label: '纤维' }, { key: 'sodium', label: '钠' }, ]; export function NutritionRadarCard({ nutritionSummary, burnedCalories = 1618, calorieDeficit = 0, resetToken, onMealPress }: NutritionRadarCardProps) { const [currentMealType, setCurrentMealType] = useState<'breakfast' | 'lunch' | 'dinner' | 'snack'>('breakfast'); const radarValues = useMemo(() => { // 基于推荐日摄入量计算分数 const recommendations = { calories: 2000, // 卡路里 protein: 50, // 蛋白质(g) carbohydrate: 300, // 碳水化合物(g) fat: 65, // 脂肪(g) fiber: 25, // 膳食纤维(g) sodium: 2300, // 钠(mg) }; if (!nutritionSummary) return [0, 0, 0, 0, 0, 0]; // 检查每个营养素是否有实际值,没有则返回0 const calories = nutritionSummary.totalCalories || 0; const protein = nutritionSummary.totalProtein || 0; const carbohydrate = nutritionSummary.totalCarbohydrate || 0; const fat = nutritionSummary.totalFat || 0; const fiber = nutritionSummary.totalFiber || 0; const sodium = nutritionSummary.totalSodium || 0; return [ calories > 0 ? Math.min(5, (calories / recommendations.calories) * 5) : 0, protein > 0 ? Math.min(5, (protein / recommendations.protein) * 5) : 0, carbohydrate > 0 ? Math.min(5, (carbohydrate / recommendations.carbohydrate) * 5) : 0, fat > 0 ? Math.min(5, (fat / recommendations.fat) * 5) : 0, fiber > 0 ? Math.min(5, (fiber / recommendations.fiber) * 5) : 0, sodium > 0 ? Math.min(5, Math.max(0, 5 - (sodium / recommendations.sodium) * 5)) : 0, // 钠含量越低越好 ]; }, [nutritionSummary]); const nutritionStats = useMemo(() => { return [ { label: '热量', value: nutritionSummary ? `${Math.round(nutritionSummary.totalCalories)} 千卡` : '0 千卡', color: '#FF6B6B' }, { label: '蛋白质', value: nutritionSummary ? `${nutritionSummary.totalProtein.toFixed(1)} g` : '0.0 g', color: '#4ECDC4' }, { label: '碳水', value: nutritionSummary ? `${nutritionSummary.totalCarbohydrate.toFixed(1)} g` : '0.0 g', color: '#45B7D1' }, { label: '脂肪', value: nutritionSummary ? `${nutritionSummary.totalFat.toFixed(1)} g` : '0.0 g', color: '#FFA07A' }, { label: '纤维', value: nutritionSummary ? `${nutritionSummary.totalFiber.toFixed(1)} g` : '0.0 g', color: '#98D8C8' }, { label: '钠', value: nutritionSummary ? `${Math.round(nutritionSummary.totalSodium)} mg` : '0 mg', color: '#F7DC6F' }, ]; }, [nutritionSummary]); // 计算还能吃的卡路里 const consumedCalories = nutritionSummary?.totalCalories || 0; const remainingCalories = burnedCalories - consumedCalories - calorieDeficit; // 餐次数据 const meals = [ { type: 'breakfast' as const, name: '早餐', emoji: '🥚', }, { type: 'lunch' as const, name: '午餐', emoji: '🍔', }, { type: 'dinner' as const, name: '晚餐', emoji: '🥣', }, { type: 'snack' as const, name: '加餐', emoji: '🍎', }, ]; const handleNavigateToRecords = () => { router.push(ROUTES.NUTRITION_RECORDS); }; const handleAddFood = () => { router.push(`/food-library?mealType=${currentMealType}`); }; return ( 营养摄入分析 更新: {dayjs(nutritionSummary?.updatedAt).format('MM-DD HH:mm')} {nutritionStats.map((stat, index) => ( {stat.label} {stat.value} ))} {/* 卡路里计算区域 */} 还能吃(千卡) Math.round(v).toString()} /> = 消耗 Math.round(v).toString()} /> - 饮食 Math.round(v).toString()} /> ); } const styles = StyleSheet.create({ card: { backgroundColor: '#FFFFFF', borderRadius: 22, padding: 18, shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.1, shadowRadius: 3.84, elevation: 5, }, cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16, }, cardTitle: { fontSize: 18, fontWeight: '800', color: '#192126', }, cardRightContainer: { flexDirection: 'row', alignItems: 'center', gap: 4, }, cardSubtitle: { fontSize: 12, color: '#9AA3AE', fontWeight: '600', }, contentContainer: { flexDirection: 'row', alignItems: 'center', }, radarContainer: { alignItems: 'center', marginRight: 6, }, statsContainer: { flex: 1, flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', marginLeft: 4 }, statItem: { flexDirection: 'row', alignItems: 'center', width: '48%', marginBottom: 16, }, statDot: { width: 8, height: 8, borderRadius: 4, marginRight: 8, }, statLabel: { fontSize: 12, color: '#9AA3AE', fontWeight: '600', flex: 1, }, statValue: { fontSize: 12, color: '#192126', fontWeight: '700', }, // 卡路里相关样式 calorieSection: { marginTop: 12, }, calorieTitleContainer: { flexDirection: 'row', alignItems: 'center', }, calorieIcon: { fontSize: 16, marginRight: 8, }, calorieTitle: { fontSize: 16, fontWeight: '800', color: '#192126', }, calorieContent: { }, calorieSubtitle: { fontSize: 10, color: '#64748B', fontWeight: '600', marginRight: 4, }, calculationRow: { flexDirection: 'row', alignItems: 'center', flexWrap: 'wrap', gap: 4, }, mainValue: { fontSize: 24, fontWeight: '800', color: '#192126', }, calculationText: { fontSize: 14, fontWeight: '600', color: '#64748B', }, calculationItem: { flexDirection: 'row', alignItems: 'center', gap: 2, }, calculationLabel: { fontSize: 10, color: '#64748B', fontWeight: '500', }, calculationValue: { fontSize: 12, fontWeight: '700', color: '#192126', }, mealsContainer: { flexDirection: 'row', justifyContent: 'space-between', paddingTop: 12, borderTopWidth: 1, borderTopColor: '#F1F5F9', }, mealItem: { alignItems: 'center', flex: 1, }, mealIconContainer: { position: 'relative', marginBottom: 6, }, mealEmoji: { fontSize: 24, }, addButton: { width: 16, height: 16, borderRadius: 8, backgroundColor: '#10B981', alignItems: 'center', justifyContent: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2, }, mealName: { fontSize: 10, color: '#64748B', fontWeight: '600', }, });