From f38f495008c46f704778d8a90d1ab5520c19ed9b Mon Sep 17 00:00:00 2001 From: richarjiang Date: Fri, 29 Aug 2025 10:13:59 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=A3=9F=E7=89=A9?= =?UTF-8?q?=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/food-library.tsx | 66 +++++++++++++++++++++++++++++++++-------- services/dietRecords.ts | 25 ++++++++++++++++ 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/app/food-library.tsx b/app/food-library.tsx index fa2a33b..52aef4e 100644 --- a/app/food-library.tsx +++ b/app/food-library.tsx @@ -1,6 +1,7 @@ import { FoodDetailModal } from '@/components/model/food/FoodDetailModal'; import { useFoodLibrary, useFoodSearch } from '@/hooks/useFoodLibrary'; import type { FoodItem, MealType, SelectedFoodItem } from '@/types/food'; +import { addDietRecord, type CreateDietRecordDto } from '@/services/dietRecords'; import { Ionicons } from '@expo/vector-icons'; import { Image } from 'expo-image'; import { useLocalSearchParams, useRouter } from 'expo-router'; @@ -45,6 +46,7 @@ export default function FoodLibraryScreen() { const [selectedFoodItems, setSelectedFoodItems] = useState([]); const [showMealSelector, setShowMealSelector] = useState(false); const [currentMealType, setCurrentMealType] = useState(mealType); + const [isRecording, setIsRecording] = useState(false); // 获取当前选中的分类 const selectedCategory = categories.find(cat => cat.id === selectedCategoryId); @@ -127,6 +129,47 @@ export default function FoodLibraryScreen() { setSelectedFood(null); }; + // 处理饮食记录 + const handleRecordDiet = async () => { + if (selectedFoodItems.length === 0) return; + + setIsRecording(true); + + try { + // 逐个记录选中的食物 + for (const item of selectedFoodItems) { + const dietRecordData: CreateDietRecordDto = { + mealType: currentMealType, + foodName: item.food.name, + foodDescription: item.food.description, + portionDescription: `${item.amount}${item.unit}`, + estimatedCalories: item.calories, + proteinGrams: item.food.protein ? Number(((item.food.protein * item.amount) / 100).toFixed(2)) : undefined, + carbohydrateGrams: item.food.carbohydrate ? Number(((item.food.carbohydrate * item.amount) / 100).toFixed(2)) : undefined, + fatGrams: item.food.fat ? Number(((item.food.fat * item.amount) / 100).toFixed(2)) : undefined, + fiberGrams: item.food.fiber ? Number(((item.food.fiber * item.amount) / 100).toFixed(2)) : undefined, + sugarGrams: item.food.sugar ? Number(((item.food.sugar * item.amount) / 100).toFixed(2)) : undefined, + sodiumMg: item.food.sodium ? Number(((item.food.sodium * item.amount) / 100).toFixed(2)) : undefined, + additionalNutrition: item.food.additionalNutrition, + source: 'manual', + mealTime: new Date().toISOString(), + imageUrl: item.food.imageUrl, + }; + + await addDietRecord(dietRecordData); + } + + // 记录成功后清空选择列表并返回 + setSelectedFoodItems([]); + router.back(); + } catch (error) { + console.error('记录饮食失败:', error); + // 这里可以显示错误提示 + } finally { + setIsRecording(false); + } + }; + // 处理餐次选择 const handleMealTypeSelect = (selectedMealType: MealType) => { setCurrentMealType(selectedMealType); @@ -324,20 +367,19 @@ export default function FoodLibraryScreen() { { - // 这里可以处理记录逻辑 - console.log('记录食物:', selectedFoodItems); - // 记录成功后可以清空选择列表或返回上一页 - router.back(); - }} + disabled={selectedFoodItems.length === 0 || isRecording} + onPress={handleRecordDiet} > - 记录 + {isRecording ? ( + + ) : ( + 记录 + )} diff --git a/services/dietRecords.ts b/services/dietRecords.ts index a32d6ae..b84e0be 100644 --- a/services/dietRecords.ts +++ b/services/dietRecords.ts @@ -3,6 +3,27 @@ import { api } from '@/services/api'; export type MealType = 'breakfast' | 'lunch' | 'dinner' | 'snack' | 'other'; export type RecordSource = 'manual' | 'vision' | 'other'; +export type CreateDietRecordDto = { + mealType: MealType; + foodName: string; + foodDescription?: string; + weightGrams?: number; + portionDescription?: string; + estimatedCalories?: number; + proteinGrams?: number; + carbohydrateGrams?: number; + fatGrams?: number; + fiberGrams?: number; + sugarGrams?: number; + sodiumMg?: number; + additionalNutrition?: Record; + source?: RecordSource; + mealTime?: string; + imageUrl?: string; + aiAnalysisResult?: Record; + notes?: string; +}; + export type DietRecord = { id: number; mealType: MealType; @@ -68,6 +89,10 @@ export async function getDietRecords({ }>(`/diet-records${params}`); } +export async function addDietRecord(dto: CreateDietRecordDto): Promise { + return await api.post('/diet-records', dto); +} + export async function deleteDietRecord(recordId: number): Promise { await api.delete(`/diet-records/${recordId}`); }