Files
digital-pilates/services/dietRecords.ts
richarjiang 260546ff46 feat: 新增营养记录页面及相关组件
- 在应用中新增营养记录页面,展示用户的饮食记录
- 引入营养记录卡片组件,优化记录展示效果
- 更新路由常量,添加营养记录相关路径
- 修改布局文件,整合营养记录功能
- 优化数据加载逻辑,支持分页和日期过滤
2025-08-19 11:34:50 +08:00

129 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
updatedAt: string;
};
export async function getDietRecords({
startDate,
endDate,
page = 1,
limit = 10,
}: {
startDate?: string;
endDate?: string;
page?: number;
limit?: number;
}): Promise<{
records: DietRecord[]
total: number
page: number
limit: number
}> {
const searchParams = new URLSearchParams();
if (startDate) searchParams.append('startDate', startDate);
if (endDate) searchParams.append('endDate', endDate);
searchParams.append('page', page.toString());
searchParams.append('limit', limit.toString());
const params = searchParams.toString() ? `?${searchParams.toString()}` : '';
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,
updatedAt: '',
};
}
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),
updatedAt: record.updatedAt,
}),
{
totalCalories: 0,
totalProtein: 0,
totalCarbohydrate: 0,
totalFat: 0,
totalFiber: 0,
totalSugar: 0,
totalSodium: 0,
updatedAt: '',
}
);
}
// 将营养数据转换为雷达图数据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)), // 钠含量越低越好
];
}