- 在统计页面中引入营养摄入分析卡片,展示用户的营养数据 - 更新探索页面,增加营养数据加载逻辑,确保用户体验一致性 - 移除不再使用的推荐文章逻辑,简化代码结构 - 更新路由常量,确保路径管理集中化 - 优化体重历史记录卡片,提升用户交互体验
115 lines
3.2 KiB
TypeScript
115 lines
3.2 KiB
TypeScript
import { api } from '@/services/api';
|
||
|
||
export type MealType = 'breakfast' | 'lunch' | 'dinner' | 'snack' | 'other';
|
||
export type RecordSource = 'manual' | 'vision' | 'other';
|
||
|
||
export type DietRecord = {
|
||
id: number;
|
||
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?: any;
|
||
source: RecordSource;
|
||
mealTime?: string;
|
||
imageUrl?: string;
|
||
notes?: string;
|
||
createdAt: string;
|
||
updatedAt: string;
|
||
};
|
||
|
||
export type NutritionSummary = {
|
||
totalCalories: number;
|
||
totalProtein: number;
|
||
totalCarbohydrate: number;
|
||
totalFat: number;
|
||
totalFiber: number;
|
||
totalSugar: number;
|
||
totalSodium: number;
|
||
};
|
||
|
||
export async function getDietRecords({
|
||
startDate,
|
||
endDate,
|
||
}: {
|
||
startDate: string;
|
||
endDate: string;
|
||
}): Promise<{
|
||
records: DietRecord[]
|
||
total: number
|
||
page: number
|
||
limit: number
|
||
}> {
|
||
const params = startDate && endDate ? `?startDate=${startDate}&endDate=${endDate}` : '';
|
||
return await api.get<{
|
||
records: DietRecord[]
|
||
total: number
|
||
page: number
|
||
limit: number
|
||
}>(`/users/diet-records${params}`);
|
||
}
|
||
|
||
export function calculateNutritionSummary(records: DietRecord[]): NutritionSummary {
|
||
if (records?.length === 0) {
|
||
return {
|
||
totalCalories: 0,
|
||
totalProtein: 0,
|
||
totalCarbohydrate: 0,
|
||
totalFat: 0,
|
||
totalFiber: 0,
|
||
totalSugar: 0,
|
||
totalSodium: 0,
|
||
};
|
||
}
|
||
|
||
return records.reduce(
|
||
(summary, record) => ({
|
||
totalCalories: summary.totalCalories + (record.estimatedCalories || 0),
|
||
totalProtein: summary.totalProtein + (record.proteinGrams || 0),
|
||
totalCarbohydrate: summary.totalCarbohydrate + (record.carbohydrateGrams || 0),
|
||
totalFat: summary.totalFat + (record.fatGrams || 0),
|
||
totalFiber: summary.totalFiber + (record.fiberGrams || 0),
|
||
totalSugar: summary.totalSugar + (record.sugarGrams || 0),
|
||
totalSodium: summary.totalSodium + (record.sodiumMg || 0),
|
||
}),
|
||
{
|
||
totalCalories: 0,
|
||
totalProtein: 0,
|
||
totalCarbohydrate: 0,
|
||
totalFat: 0,
|
||
totalFiber: 0,
|
||
totalSugar: 0,
|
||
totalSodium: 0,
|
||
}
|
||
);
|
||
}
|
||
|
||
// 将营养数据转换为雷达图数据(0-5分制)
|
||
export function convertToRadarData(summary: NutritionSummary): number[] {
|
||
// 基于推荐日摄入量计算分数
|
||
const recommendations = {
|
||
calories: 2000, // 卡路里
|
||
protein: 50, // 蛋白质(g)
|
||
carbohydrate: 300, // 碳水化合物(g)
|
||
fat: 65, // 脂肪(g)
|
||
fiber: 25, // 膳食纤维(g)
|
||
sodium: 2300, // 钠(mg)
|
||
};
|
||
|
||
return [
|
||
Math.min(5, (summary.totalCalories / recommendations.calories) * 5),
|
||
Math.min(5, (summary.totalProtein / recommendations.protein) * 5),
|
||
Math.min(5, (summary.totalCarbohydrate / recommendations.carbohydrate) * 5),
|
||
Math.min(5, (summary.totalFat / recommendations.fat) * 5),
|
||
Math.min(5, (summary.totalFiber / recommendations.fiber) * 5),
|
||
Math.min(5, Math.max(0, 5 - (summary.totalSodium / recommendations.sodium) * 5)), // 钠含量越低越好
|
||
];
|
||
} |