import { RadarChart } from '@/components/RadarChart'; import { ThemedText } from '@/components/ThemedText'; import { useThemeColor } from '@/hooks/useThemeColor'; import { DietRecord, calculateNutritionSummary, convertToRadarData } from '@/services/dietRecords'; import { Ionicons } from '@expo/vector-icons'; import dayjs from 'dayjs'; import React, { useMemo } from 'react'; import { Image, StyleSheet, TouchableOpacity, View } from 'react-native'; export type NutritionRecordCardProps = { record: DietRecord; onPress?: () => void; }; const NUTRITION_DIMENSIONS = [ { key: 'calories', label: '热量' }, { key: 'protein', label: '蛋白质' }, { key: 'carbohydrate', label: '碳水' }, { key: 'fat', label: '脂肪' }, { key: 'fiber', label: '纤维' }, { key: 'sodium', label: '钠' }, ]; const MEAL_TYPE_LABELS = { breakfast: '早餐', lunch: '午餐', dinner: '晚餐', snack: '加餐', other: '其他', } as const; const MEAL_TYPE_ICONS = { breakfast: 'sunny-outline', lunch: 'partly-sunny-outline', dinner: 'moon-outline', snack: 'cafe-outline', other: 'restaurant-outline', } as const; const MEAL_TYPE_COLORS = { breakfast: '#FFB366', lunch: '#4ECDC4', dinner: '#5D5FEF', snack: '#FF6B6B', other: '#9AA3AE', } as const; export function NutritionRecordCard({ record, onPress }: NutritionRecordCardProps) { const surfaceColor = useThemeColor({}, 'surface'); const textColor = useThemeColor({}, 'text'); const textSecondaryColor = useThemeColor({}, 'textSecondary'); const primaryColor = useThemeColor({}, 'primary'); // 计算单条记录的营养摘要 const nutritionSummary = useMemo(() => { return calculateNutritionSummary([record]); }, [record]); // 计算雷达图数据 const radarValues = useMemo(() => { return convertToRadarData(nutritionSummary); }, [nutritionSummary]); // 营养维度数据 const nutritionStats = useMemo(() => { return [ { label: '热量', value: record.estimatedCalories ? `${Math.round(record.estimatedCalories)} 千卡` : '-', color: '#FF6B6B' }, { label: '蛋白质', value: record.proteinGrams ? `${record.proteinGrams.toFixed(1)} g` : '-', color: '#4ECDC4' }, { label: '碳水', value: record.carbohydrateGrams ? `${record.carbohydrateGrams.toFixed(1)} g` : '-', color: '#45B7D1' }, { label: '脂肪', value: record.fatGrams ? `${record.fatGrams.toFixed(1)} g` : '-', color: '#FFA07A' }, { label: '纤维', value: record.fiberGrams ? `${record.fiberGrams.toFixed(1)} g` : '-', color: '#98D8C8' }, { label: '钠', value: record.sodiumMg ? `${Math.round(record.sodiumMg)} mg` : '-', color: '#F7DC6F' }, ]; }, [record]); const mealTypeColor = MEAL_TYPE_COLORS[record.mealType]; const mealTypeIcon = MEAL_TYPE_ICONS[record.mealType]; const mealTypeLabel = MEAL_TYPE_LABELS[record.mealType]; return ( {/* 卡片头部 */} {mealTypeLabel} {record.mealTime ? dayjs(record.mealTime).format('HH:mm') : '时间未设置'} {/* 食物信息 */} {record.imageUrl ? ( ) : ( )} {record.foodName} {record.foodDescription && ( {record.foodDescription} )} {(record.weightGrams || record.portionDescription) && ( {record.weightGrams ? `${record.weightGrams}g` : ''} {record.weightGrams && record.portionDescription ? ' • ' : ''} {record.portionDescription || ''} )} {/* 营养分析区域 */} {nutritionStats.slice(0, 4).map((stat) => ( {stat.label} {stat.value} ))} {/* 额外的营养信息 */} {nutritionStats.slice(4).map((stat) => ( {stat.label} {stat.value} ))} {/* 备注信息 */} {record.notes && ( 备注 {record.notes} )} ); } const styles = StyleSheet.create({ card: { borderRadius: 22, padding: 20, marginBottom: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.08, shadowRadius: 6, elevation: 3, }, cardHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16, }, mealInfo: { flexDirection: 'row', alignItems: 'center', }, mealTypeIndicator: { width: 36, height: 36, borderRadius: 18, justifyContent: 'center', alignItems: 'center', marginRight: 12, }, mealDetails: { justifyContent: 'center', }, mealType: { fontSize: 16, fontWeight: '700', }, mealTime: { fontSize: 13, fontWeight: '500', marginTop: 2, }, moreButton: { padding: 4, }, foodSection: { flexDirection: 'row', marginBottom: 20, }, foodImageContainer: { width: 60, height: 60, borderRadius: 12, marginRight: 12, overflow: 'hidden', }, foodImage: { width: '100%', height: '100%', }, foodImagePlaceholder: { backgroundColor: '#F5F5F5', justifyContent: 'center', alignItems: 'center', }, foodInfo: { flex: 1, justifyContent: 'center', }, foodName: { fontSize: 18, fontWeight: '700', marginBottom: 4, }, foodDescription: { fontSize: 14, fontWeight: '500', lineHeight: 20, marginBottom: 4, }, portionInfo: { fontSize: 13, fontWeight: '600', }, nutritionSection: { flexDirection: 'row', alignItems: 'center', marginBottom: 16, }, radarContainer: { marginRight: 16, }, statsContainer: { flex: 1, }, statItem: { flexDirection: 'row', alignItems: 'center', marginBottom: 12, }, statDot: { width: 8, height: 8, borderRadius: 4, marginRight: 8, }, statLabel: { fontSize: 13, fontWeight: '600', flex: 1, }, statValue: { fontSize: 13, fontWeight: '700', }, additionalStats: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 12, }, additionalStatItem: { flexDirection: 'row', alignItems: 'center', flex: 1, }, notesSection: { marginTop: 12, paddingTop: 16, borderTopWidth: 1, borderTopColor: 'rgba(0,0,0,0.08)', }, notesLabel: { fontSize: 12, fontWeight: '600', marginBottom: 6, textTransform: 'uppercase', letterSpacing: 0.5, }, notesText: { fontSize: 14, fontWeight: '500', lineHeight: 20, }, });