feat(medications): 实现完整的用药管理功能
添加了药物管理的核心功能,包括: - 药物列表展示和状态管理 - 添加新药物的完整流程 - 服药记录的创建和状态更新 - 药物管理界面,支持激活/停用操作 - Redux状态管理和API服务层 - 相关类型定义和辅助函数 主要文件: - app/(tabs)/medications.tsx - 主界面,集成Redux数据 - app/medications/add-medication.tsx - 添加药物流程 - app/medications/manage-medications.tsx - 药物管理界面 - store/medicationsSlice.ts - Redux状态管理 - services/medications.ts - API服务层 - types/medication.ts - 类型定义
This commit is contained in:
311
services/medications.ts
Normal file
311
services/medications.ts
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* 药物管理 API 服务
|
||||
*/
|
||||
|
||||
import type {
|
||||
DailyMedicationStats,
|
||||
Medication,
|
||||
MedicationForm,
|
||||
MedicationRecord,
|
||||
MedicationStatus,
|
||||
RepeatPattern,
|
||||
} from '@/types/medication';
|
||||
import { api } from './api';
|
||||
|
||||
// ==================== DTO 类型定义 ====================
|
||||
|
||||
/**
|
||||
* 创建药物 DTO
|
||||
*/
|
||||
export interface CreateMedicationDto {
|
||||
name: string;
|
||||
photoUrl?: string | null;
|
||||
form: MedicationForm;
|
||||
dosageValue: number;
|
||||
dosageUnit: string;
|
||||
timesPerDay: number;
|
||||
medicationTimes: string[];
|
||||
startDate: string;
|
||||
endDate?: string | null;
|
||||
repeatPattern?: RepeatPattern;
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新药物 DTO
|
||||
*/
|
||||
export interface UpdateMedicationDto extends Partial<CreateMedicationDto> {
|
||||
id: string;
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建服药记录 DTO
|
||||
*/
|
||||
export interface CreateMedicationRecordDto {
|
||||
medicationId: string;
|
||||
scheduledTime: string;
|
||||
actualTime?: string;
|
||||
status: MedicationStatus;
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新服药记录 DTO
|
||||
*/
|
||||
export interface UpdateMedicationRecordDto {
|
||||
id: string;
|
||||
actualTime?: string;
|
||||
status?: MedicationStatus;
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取药物列表参数
|
||||
*/
|
||||
export interface GetMedicationsParams {
|
||||
isActive?: boolean;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服药记录参数
|
||||
*/
|
||||
export interface GetMedicationRecordsParams {
|
||||
date?: string;
|
||||
medicationId?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
// ==================== API 函数 ====================
|
||||
|
||||
/**
|
||||
* 获取药物列表
|
||||
* @param params 查询参数
|
||||
* @returns 药物列表
|
||||
*/
|
||||
export const getMedications = async (
|
||||
params?: GetMedicationsParams
|
||||
): Promise<Medication[]> => {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params?.startDate) {
|
||||
queryParams.append('startDate', params.startDate);
|
||||
}
|
||||
if (params?.endDate) {
|
||||
queryParams.append('endDate', params.endDate);
|
||||
}
|
||||
|
||||
const query = queryParams.toString();
|
||||
const path = query ? `/medications?${query}` : '/medications';
|
||||
|
||||
const response = await api.get<{ rows: Medication[]; total: number }>(path);
|
||||
|
||||
// 处理不同的响应格式
|
||||
if (Array.isArray(response)) {
|
||||
return response;
|
||||
} else if (response && typeof response === 'object' && 'rows' in response) {
|
||||
return response.rows;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据 ID 获取单个药物
|
||||
* @param id 药物 ID
|
||||
* @returns 药物详情
|
||||
*/
|
||||
export const getMedicationById = async (id: string): Promise<Medication> => {
|
||||
return api.get<Medication>(`/medications/${id}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建新药物
|
||||
* @param dto 创建药物数据
|
||||
* @returns 创建的药物
|
||||
*/
|
||||
export const createMedication = async (
|
||||
dto: CreateMedicationDto
|
||||
): Promise<Medication> => {
|
||||
return api.post<Medication>('/medications', dto);
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新药物信息
|
||||
* @param dto 更新药物数据
|
||||
* @returns 更新后的药物
|
||||
*/
|
||||
export const updateMedication = async (
|
||||
dto: UpdateMedicationDto
|
||||
): Promise<Medication> => {
|
||||
const { id, ...data } = dto;
|
||||
return api.put<Medication>(`/medications/${id}`, data);
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除药物
|
||||
* @param id 药物 ID
|
||||
*/
|
||||
export const deleteMedication = async (id: string): Promise<void> => {
|
||||
return api.delete<void>(`/medications/${id}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 停用药物
|
||||
* @param id 药物 ID
|
||||
* @returns 更新后的药物
|
||||
*/
|
||||
export const deactivateMedication = async (id: string): Promise<Medication> => {
|
||||
return api.post<Medication>(`/medications/${id}/deactivate`, {});
|
||||
};
|
||||
|
||||
/**
|
||||
* 激活药物(暂不支持,需要通过更新接口实现)
|
||||
* @param id 药物 ID
|
||||
* @returns 更新后的药物
|
||||
*/
|
||||
export const activateMedication = async (id: string): Promise<Medication> => {
|
||||
return api.put<Medication>(`/medications/${id}`, { isActive: true });
|
||||
};
|
||||
|
||||
// ==================== 服药记录相关 ====================
|
||||
|
||||
/**
|
||||
* 获取服药记录列表
|
||||
* @param params 查询参数
|
||||
* @returns 服药记录列表
|
||||
*/
|
||||
export const getMedicationRecords = async (
|
||||
params: GetMedicationRecordsParams
|
||||
): Promise<MedicationRecord[]> => {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params.date) {
|
||||
queryParams.append('date', params.date);
|
||||
}
|
||||
if (params.medicationId) {
|
||||
queryParams.append('medicationId', params.medicationId);
|
||||
}
|
||||
if (params.startDate) {
|
||||
queryParams.append('startDate', params.startDate);
|
||||
}
|
||||
if (params.endDate) {
|
||||
queryParams.append('endDate', params.endDate);
|
||||
}
|
||||
|
||||
const query = queryParams.toString();
|
||||
const path = query ? `/medication-records?${query}` : '/medication-records';
|
||||
|
||||
return api.get<MedicationRecord[]>(path);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取今日服药记录
|
||||
* @returns 今日服药记录列表
|
||||
*/
|
||||
export const getTodayMedicationRecords = async (): Promise<MedicationRecord[]> => {
|
||||
return api.get<MedicationRecord[]>('/medication-records/today');
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建服药记录
|
||||
* @param dto 创建服药记录数据
|
||||
* @returns 创建的服药记录
|
||||
*/
|
||||
export const createMedicationRecord = async (
|
||||
dto: CreateMedicationRecordDto
|
||||
): Promise<MedicationRecord> => {
|
||||
return api.post<MedicationRecord>('/medication-records', dto);
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新服药记录
|
||||
* @param dto 更新服药记录数据
|
||||
* @returns 更新后的服药记录
|
||||
*/
|
||||
export const updateMedicationRecord = async (
|
||||
dto: UpdateMedicationRecordDto
|
||||
): Promise<MedicationRecord> => {
|
||||
const { id, ...data } = dto;
|
||||
return api.put<MedicationRecord>(`/medication-records/${id}`, data);
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除服药记录
|
||||
* @param id 服药记录 ID
|
||||
*/
|
||||
export const deleteMedicationRecord = async (id: string): Promise<void> => {
|
||||
return api.delete<void>(`/medication-records/${id}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 标记药物为已服用
|
||||
* @param recordId 服药记录 ID
|
||||
* @param actualTime 实际服药时间(可选,默认为当前时间)
|
||||
* @returns 更新后的服药记录
|
||||
*/
|
||||
export const takeMedication = async (
|
||||
recordId: string,
|
||||
actualTime?: string
|
||||
): Promise<MedicationRecord> => {
|
||||
return api.post<MedicationRecord>(`/medication-records/${recordId}/take`, {
|
||||
actualTime: actualTime || new Date().toISOString(),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 标记药物为已跳过
|
||||
* @param recordId 服药记录 ID
|
||||
* @param note 跳过原因(可选)
|
||||
* @returns 更新后的服药记录
|
||||
*/
|
||||
export const skipMedication = async (
|
||||
recordId: string,
|
||||
note?: string
|
||||
): Promise<MedicationRecord> => {
|
||||
return api.post<MedicationRecord>(`/medication-records/${recordId}/skip`, {
|
||||
note,
|
||||
});
|
||||
};
|
||||
|
||||
// ==================== 统计相关 ====================
|
||||
|
||||
/**
|
||||
* 获取指定日期的服药统计
|
||||
* @param date 日期 'YYYY-MM-DD'
|
||||
* @returns 每日服药统计
|
||||
*/
|
||||
export const getDailyStats = async (
|
||||
date: string
|
||||
): Promise<DailyMedicationStats> => {
|
||||
return api.get<DailyMedicationStats>(`/medication-stats/daily?date=${date}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取日期范围内的服药统计
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @returns 统计数据列表
|
||||
*/
|
||||
export const getStatsRange = async (
|
||||
startDate: string,
|
||||
endDate: string
|
||||
): Promise<DailyMedicationStats[]> => {
|
||||
return api.get<DailyMedicationStats[]>(
|
||||
`/medication-stats/range?startDate=${startDate}&endDate=${endDate}`
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取总体统计
|
||||
* @returns 总体统计数据
|
||||
*/
|
||||
export const getOverallStats = async (): Promise<{
|
||||
totalMedications: number;
|
||||
totalRecords: number;
|
||||
completionRate: number;
|
||||
streak: number;
|
||||
}> => {
|
||||
return api.get(`/medication-stats/overall`);
|
||||
};
|
||||
Reference in New Issue
Block a user