feat: 优化内容

This commit is contained in:
richarjiang
2025-08-29 16:01:13 +08:00
parent 93db9e2928
commit e9b593a07e
5 changed files with 889 additions and 101 deletions

View File

@@ -14,7 +14,9 @@ import {
View,
} from 'react-native';
// 导入统一的食物类型定义
import { DEFAULT_IMAGE_FOOD } from '@/constants/Image';
import type { FoodItem } from '@/types/food';
import { Image } from 'expo-image';
// 导入统一的食物类型定义
@@ -25,12 +27,11 @@ interface NutritionInfo {
carbs: number; // 碳水化合物(克)
}
// 单位选项
const UNIT_OPTIONS = [
{ id: 'gram', name: '', ratio: 1 },
{ id: 'small', name: '份', ratio: 0.8 },
{ id: 'medium', name: '份', ratio: 1.2 },
{ id: 'large', name: '大份', ratio: 1.5 },
// 快捷选择选项基于100克的倍数
const QUICK_SELECT_OPTIONS = [
{ id: 'small', name: '小份', amount: 80 }, // 80克
{ id: 'medium', name: '份', amount: 120 }, // 120克
{ id: 'large', name: '份', amount: 150 }, // 150克
];
// 食物详情弹窗属性
@@ -41,9 +42,24 @@ export interface FoodDetailModalProps {
onSave: (food: FoodItem, amount: number, unit: string) => void;
}
// 模拟营养数据
const getNutritionInfo = (foodId: string): NutritionInfo => {
const nutritionData: Record<string, NutritionInfo> = {
// 获取营养数据优先使用FoodItem中的数据
const getNutritionInfo = (food: FoodItem): NutritionInfo => {
// 检查是否有任何营养数据
const hasNutritionData = food.protein !== undefined ||
food.fat !== undefined ||
food.carbohydrate !== undefined;
if (hasNutritionData) {
// 优先使用FoodItem中的营养数据
return {
protein: food.protein || 0,
fat: food.fat || 0,
carbs: food.carbohydrate || 0,
};
}
// 如果FoodItem中没有营养数据使用模拟数据作为后备
const fallbackNutritionData: Record<string, NutritionInfo> = {
'5': { protein: 0.8, fat: 0.6, carbs: 14.5 }, // 猕猴桃
'1': { protein: 0.2, fat: 0.0, carbs: 0.1 }, // 咖啡
'2': { protein: 12.8, fat: 11.1, carbs: 0.7 }, // 荷包蛋
@@ -56,7 +72,7 @@ const getNutritionInfo = (foodId: string): NutritionInfo => {
'10': { protein: 4.0, fat: 1.2, carbs: 22.8 }, // 玉米
};
return nutritionData[foodId] || { protein: 0, fat: 0, carbs: 0 };
return fallbackNutritionData[food.id] || { protein: 0, fat: 0, carbs: 0 };
};
export function FoodDetailModal({
@@ -66,7 +82,6 @@ export function FoodDetailModal({
onSave
}: FoodDetailModalProps) {
const [amount, setAmount] = useState('100');
const [selectedUnit, setSelectedUnit] = useState(UNIT_OPTIONS[0]);
const [isFavorite, setIsFavorite] = useState(false);
const [keyboardHeight, setKeyboardHeight] = useState(0);
@@ -98,7 +113,6 @@ export function FoodDetailModal({
if (visible && food) {
console.log('FoodDetailModal: 接收到食物数据:', food);
setAmount('100');
setSelectedUnit(UNIT_OPTIONS[0]);
setIsFavorite(false);
}
}, [visible, food]);
@@ -116,19 +130,22 @@ export function FoodDetailModal({
return null;
}
const nutrition = getNutritionInfo(food.id);
const nutrition = getNutritionInfo(food);
const amountNum = parseFloat(amount) || 0;
const unitRatio = selectedUnit.ratio;
const finalAmount = amountNum * unitRatio;
// 计算实际营养值
const actualCalories = Math.round((food.calories * finalAmount) / 100);
const actualProtein = ((nutrition.protein * finalAmount) / 100).toFixed(1);
const actualFat = ((nutrition.fat * finalAmount) / 100).toFixed(1);
const actualCarbs = ((nutrition.carbs * finalAmount) / 100).toFixed(1);
// 计算实际营养值(基于输入的克数)
const actualCalories = Math.round((food.calories * amountNum) / 100);
const actualProtein = ((nutrition.protein * amountNum) / 100).toFixed(1);
const actualFat = ((nutrition.fat * amountNum) / 100).toFixed(1);
const actualCarbs = ((nutrition.carbs * amountNum) / 100).toFixed(1);
// 快捷选择处理函数
const handleQuickSelect = (selectedAmount: number) => {
setAmount(selectedAmount.toString());
};
const handleSave = () => {
onSave(food, finalAmount, selectedUnit.name);
onSave(food, amountNum, '克');
onClose();
};
@@ -180,7 +197,10 @@ export function FoodDetailModal({
{/* 食物信息 */}
<View style={styles.foodHeader}>
<View style={styles.foodInfo}>
<Text style={styles.foodEmoji}>{food.emoji || '🍽️'}</Text>
<Image
style={styles.foodImage}
source={{ uri: food.imageUrl || DEFAULT_IMAGE_FOOD }}
/>
<Text style={styles.foodName}>{food.name}</Text>
</View>
<TouchableOpacity
@@ -217,31 +237,34 @@ export function FoodDetailModal({
{/* 数量输入 */}
<View style={styles.amountContainer}>
<TextInput
style={styles.amountInput}
value={amount}
onChangeText={setAmount}
keyboardType="numeric"
selectTextOnFocus
/>
<View style={styles.inputWithUnit}>
<TextInput
style={styles.amountInput}
value={amount}
onChangeText={setAmount}
keyboardType="numeric"
selectTextOnFocus
/>
<Text style={styles.unitLabel}></Text>
</View>
</View>
{/* 单位选择 */}
<View style={styles.unitContainer}>
{UNIT_OPTIONS.map((unit) => (
{/* 快捷选择 */}
<View style={styles.quickSelectContainer}>
{QUICK_SELECT_OPTIONS.map((option) => (
<TouchableOpacity
key={unit.id}
key={option.id}
style={[
styles.unitOption,
selectedUnit.id === unit.id && styles.unitOptionActive
styles.quickSelectOption,
amount === option.amount.toString() && styles.quickSelectOptionActive
]}
onPress={() => setSelectedUnit(unit)}
onPress={() => handleQuickSelect(option.amount)}
>
<Text style={[
styles.unitText,
selectedUnit.id === unit.id && styles.unitTextActive
styles.quickSelectText,
amount === option.amount.toString() && styles.quickSelectTextActive
]}>
{unit.name}
{option.name}
</Text>
</TouchableOpacity>
))}
@@ -329,6 +352,11 @@ const styles = StyleSheet.create({
alignItems: 'center',
flex: 1,
},
foodImage: {
width: 40,
height: 40,
marginRight: 12,
},
foodEmoji: {
fontSize: 40,
marginRight: 12,
@@ -366,25 +394,36 @@ const styles = StyleSheet.create({
alignItems: 'center',
paddingVertical: 16,
},
amountInput: {
inputWithUnit: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#E8F5E8',
borderRadius: 12,
paddingHorizontal: 24,
paddingHorizontal: 20,
paddingVertical: 16,
},
amountInput: {
fontSize: 24,
fontWeight: '600',
color: '#4CAF50',
textAlign: 'center',
minWidth: 120,
minWidth: 80,
backgroundColor: 'transparent',
},
unitContainer: {
unitLabel: {
fontSize: 18,
fontWeight: '500',
color: '#4CAF50',
marginLeft: 8,
},
quickSelectContainer: {
flexDirection: 'row',
justifyContent: 'center',
paddingHorizontal: screenWidth > 400 ? 24 : 16,
paddingBottom: 20,
gap: screenWidth > 400 ? 16 : 12, // 根据屏幕宽度调整间距
},
unitOption: {
quickSelectOption: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 20,
@@ -392,15 +431,15 @@ const styles = StyleSheet.create({
minWidth: 60,
alignItems: 'center',
},
unitOptionActive: {
quickSelectOptionActive: {
backgroundColor: '#4CAF50',
},
unitText: {
quickSelectText: {
fontSize: 14,
color: '#666',
fontWeight: '500',
},
unitTextActive: {
quickSelectTextActive: {
color: '#FFFFFF',
},
saveButton: {