Files
digital-pilates/services/dietRecords.ts
2025-08-29 10:13:59 +08:00

158 lines
4.3 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 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<string, any>;
source?: RecordSource;
mealTime?: string;
imageUrl?: string;
aiAnalysisResult?: Record<string, any>;
notes?: string;
};
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
}>(`/diet-records${params}`);
}
export async function addDietRecord(dto: CreateDietRecordDto): Promise<DietRecord> {
return await api.post<DietRecord>('/diet-records', dto);
}
export async function deleteDietRecord(recordId: number): Promise<void> {
await api.delete(`/diet-records/${recordId}`);
}
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)), // 钠含量越低越好
];
}