feat: 支持饮水记录卡片
This commit is contained in:
167
services/waterRecords.ts
Normal file
167
services/waterRecords.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import { api } from './api';
|
||||
|
||||
// 喝水记录类型
|
||||
export interface WaterRecord {
|
||||
id: string;
|
||||
userId?: string;
|
||||
amount: number; // 喝水量(毫升)
|
||||
source?: 'Manual' | 'Auto'; // 记录来源
|
||||
note?: string; // 备注
|
||||
recordedAt: string; // 记录时间 ISO格式
|
||||
createdAt: string; // 创建时间 ISO格式
|
||||
updatedAt: string; // 更新时间 ISO格式
|
||||
}
|
||||
|
||||
export enum WaterRecordSource {
|
||||
Manual = 'manual',
|
||||
Auto = 'auto',
|
||||
Other = 'other',
|
||||
}
|
||||
|
||||
// 创建喝水记录请求
|
||||
export interface CreateWaterRecordDto {
|
||||
amount: number; // 喝水量(毫升)
|
||||
recordedAt?: string; // 记录时间,默认为当前时间
|
||||
source?: WaterRecordSource; // 记录来源,默认为 'manual'
|
||||
}
|
||||
|
||||
// 更新喝水记录请求
|
||||
export interface UpdateWaterRecordDto {
|
||||
id: string;
|
||||
amount?: number; // 喝水量(毫升)
|
||||
recordedAt?: string; // 记录时间
|
||||
source?: 'Manual' | 'Auto'; // 记录来源
|
||||
note?: string; // 备注
|
||||
}
|
||||
|
||||
// 删除喝水记录请求
|
||||
export interface DeleteWaterRecordDto {
|
||||
id: string;
|
||||
}
|
||||
|
||||
// 今日喝水统计
|
||||
export interface TodayWaterStats {
|
||||
date: string; // 统计日期
|
||||
totalAmount: number; // 当日总喝水量
|
||||
dailyGoal: number; // 每日目标
|
||||
completionRate: number; // 完成率(百分比)
|
||||
recordCount: number; // 记录次数
|
||||
records?: WaterRecord[]; // 当日所有记录(可选)
|
||||
}
|
||||
|
||||
// 更新喝水目标请求
|
||||
export interface UpdateWaterGoalDto {
|
||||
dailyWaterGoal: number; // 每日喝水目标(毫升)
|
||||
}
|
||||
|
||||
// 创建喝水记录
|
||||
export async function createWaterRecord(dto: CreateWaterRecordDto): Promise<WaterRecord> {
|
||||
return await api.post('/water-records', dto);
|
||||
}
|
||||
|
||||
// 获取喝水记录列表
|
||||
export async function getWaterRecords(params?: {
|
||||
startDate?: string; // 开始日期 (YYYY-MM-DD)
|
||||
endDate?: string; // 结束日期 (YYYY-MM-DD)
|
||||
page?: number; // 页码,默认1
|
||||
limit?: number; // 每页数量,默认20
|
||||
date?: string; // 指定日期,格式:YYYY-MM-DD (向后兼容)
|
||||
}): Promise<{
|
||||
records: WaterRecord[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
hasMore: boolean;
|
||||
}> {
|
||||
const queryParams = new URLSearchParams();
|
||||
|
||||
// 处理日期范围查询
|
||||
if (params?.startDate) queryParams.append('startDate', params.startDate);
|
||||
if (params?.endDate) queryParams.append('endDate', params.endDate);
|
||||
|
||||
// 处理单日期查询(向后兼容)
|
||||
if (params?.date) queryParams.append('startDate', params.date);
|
||||
if (params?.date) queryParams.append('endDate', params.date);
|
||||
|
||||
// 处理分页
|
||||
const page = params?.page || 1;
|
||||
const limit = params?.limit || 20;
|
||||
queryParams.append('page', page.toString());
|
||||
queryParams.append('limit', limit.toString());
|
||||
|
||||
const path = `/water-records${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
|
||||
const response = await api.get<{
|
||||
records: WaterRecord[];
|
||||
pagination: {
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
totalPages: number;
|
||||
};
|
||||
}>(path);
|
||||
|
||||
const pagination = response.pagination || { page, limit, total: 0, totalPages: 0 };
|
||||
return {
|
||||
records: response.records || [],
|
||||
total: pagination.total,
|
||||
page: pagination.page,
|
||||
limit: pagination.limit,
|
||||
hasMore: pagination.page < pagination.totalPages
|
||||
};
|
||||
}
|
||||
|
||||
// 更新喝水记录
|
||||
export async function updateWaterRecord(dto: UpdateWaterRecordDto): Promise<WaterRecord> {
|
||||
const { id, ...updateData } = dto;
|
||||
return await api.put(`/water-records/${id}`, updateData);
|
||||
}
|
||||
|
||||
// 删除喝水记录
|
||||
export async function deleteWaterRecord(id: string): Promise<boolean> {
|
||||
return await api.delete(`/water-records/${id}`);
|
||||
}
|
||||
|
||||
// 更新喝水目标
|
||||
export async function updateWaterGoal(dto: UpdateWaterGoalDto): Promise<{ dailyWaterGoal: number }> {
|
||||
return await api.put('/water-records/goal/daily', dto);
|
||||
}
|
||||
|
||||
// 获取今日喝水统计
|
||||
export async function getTodayWaterStats(): Promise<TodayWaterStats> {
|
||||
return await api.get('/water-records/stats');
|
||||
}
|
||||
|
||||
// 获取指定日期的喝水统计
|
||||
export async function getWaterStatsByDate(date: string): Promise<TodayWaterStats> {
|
||||
return await api.get(`/water-records/stats?date=${date}`);
|
||||
}
|
||||
|
||||
// 按小时分组获取喝水记录(用于图表显示)
|
||||
export function groupWaterRecordsByHour(records: WaterRecord[]): { hour: number; amount: number }[] {
|
||||
const hourlyData: { hour: number; amount: number }[] = Array.from({ length: 24 }, (_, i) => ({
|
||||
hour: i,
|
||||
amount: 0,
|
||||
}));
|
||||
|
||||
records.forEach(record => {
|
||||
// 优先使用 recordedAt,如果没有则使用 createdAt
|
||||
const dateTime = record.recordedAt || record.createdAt;
|
||||
const hour = new Date(dateTime).getHours();
|
||||
if (hour >= 0 && hour < 24) {
|
||||
hourlyData[hour].amount += record.amount;
|
||||
}
|
||||
});
|
||||
|
||||
return hourlyData;
|
||||
}
|
||||
|
||||
// 获取指定日期的总喝水量
|
||||
export function getTotalWaterAmount(records: WaterRecord[]): number {
|
||||
return records.reduce((total, record) => total + record.amount, 0);
|
||||
}
|
||||
|
||||
// 计算喝水目标完成率
|
||||
export function calculateCompletionRate(totalAmount: number, dailyGoal: number): number {
|
||||
if (dailyGoal <= 0) return 0;
|
||||
return Math.min(totalAmount / dailyGoal, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user