- 集成流式AI分析接口,支持实时展示分析结果 - 添加VIP权限校验和会员弹窗引导 - 使用Markdown渲染AI分析内容 - 优化底部按钮布局,AI分析按钮占2/3宽度 - 支持请求取消和错误处理 - 自动滚动到分析结果区域 - InfoCard组件优化,图标、标签和箭头排列在同一行
331 lines
7.7 KiB
TypeScript
331 lines
7.7 KiB
TypeScript
/**
|
|
* 药物管理 API 服务
|
|
*/
|
|
|
|
import type {
|
|
DailyMedicationStats,
|
|
Medication,
|
|
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 }
|
|
);
|
|
} |