- 将药品AI分析从Markdown流式输出重构为结构化数据展示(V2) - 新增适合人群、不适合人群、主要成分、副作用等分类卡片展示 - 优化AI分析UI布局,采用卡片式设计提升可读性 - 新增药品跳过功能,支持用户标记本次用药为已跳过 - 修复喝水提醒逻辑,支持用户开关控制和自定义时间段配置 - 优化个人资料编辑页面键盘适配,避免输入框被遮挡 - 统一API响应码处理,兼容200和0两种成功状态码 - 更新版本号至1.0.28 BREAKING CHANGE: 药品AI分析接口从流式Markdown输出改为结构化JSON格式,旧版本分析结果将不再显示
347 lines
8.1 KiB
TypeScript
347 lines
8.1 KiB
TypeScript
/**
|
|
* 药物管理 API 服务
|
|
*/
|
|
|
|
import type {
|
|
DailyMedicationStats,
|
|
Medication,
|
|
MedicationAiAnalysisV2,
|
|
MedicationForm,
|
|
MedicationRecord,
|
|
MedicationStatus,
|
|
RepeatPattern,
|
|
} from '@/types/medication';
|
|
import { api, postTextStream, type TextStreamCallbacks } 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`);
|
|
};
|
|
|
|
// ==================== AI 分析相关 ====================
|
|
|
|
/**
|
|
* 流式获取药品 AI 分析
|
|
* @param medicationId 药品 ID
|
|
* @param callbacks 流式回调
|
|
* @returns 包含 abort 方法的对象,用于取消请求
|
|
*/
|
|
export async function analyzeMedicationStream(
|
|
medicationId: string,
|
|
callbacks: TextStreamCallbacks
|
|
) {
|
|
return postTextStream(
|
|
`/api/medications/${medicationId}/ai-analysis`,
|
|
{},
|
|
callbacks,
|
|
{ timeoutMs: 120000 }
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 获取药品 AI 分析 V2 结构化报告
|
|
* @param medicationId 药品 ID
|
|
* @returns 结构化 AI 分析结果
|
|
*/
|
|
export async function analyzeMedicationV2(
|
|
medicationId: string
|
|
): Promise<MedicationAiAnalysisV2> {
|
|
return api.post<MedicationAiAnalysisV2>(
|
|
`/api/medications/${medicationId}/ai-analysis/v2`,
|
|
{}
|
|
);
|
|
}
|