feat(web): Web 前端功能完善 — API 扩展 + 组件优化
- 新增 AI 透析分析 API + 药物提醒 API - MediaPicker/ThemeSwitcher/usePaginatedData 优化 - 健康管理页面组件增强(Banner/Consultation/Doctor/MediaLibrary 等) - PluginCRUDPage 导入优化
This commit is contained in:
23
apps/web/src/api/ai/dialysis.ts
Normal file
23
apps/web/src/api/ai/dialysis.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import client from '../client';
|
||||
|
||||
export interface DialysisRiskRequest {
|
||||
patient_id: string;
|
||||
dialysis_session_id?: string;
|
||||
}
|
||||
|
||||
export interface DialysisRiskAssessment {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
risk_level: string;
|
||||
risk_factors: string[];
|
||||
recommendations: string[];
|
||||
kdigo_stage?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export const dialysisRiskApi = {
|
||||
assess: async (data: DialysisRiskRequest) => {
|
||||
const resp = await client.post('/ai/dialysis/risk-assessment', data);
|
||||
return resp.data.data as DialysisRiskAssessment;
|
||||
},
|
||||
};
|
||||
@@ -27,6 +27,10 @@ export const suggestionApi = {
|
||||
const resp = await client.post(`/ai/suggestions/${id}/approve`, { action });
|
||||
return resp.data.data as { id: string; status: string };
|
||||
},
|
||||
execute: async (id: string) => {
|
||||
const resp = await client.post(`/ai/suggestions/${id}/execute`);
|
||||
return resp.data.data as { id: string; status: string };
|
||||
},
|
||||
getComparison: async (id: string) => {
|
||||
const resp = await client.get(`/ai/suggestions/${id}/comparison`);
|
||||
return resp.data.data as ComparisonReport;
|
||||
|
||||
@@ -9,6 +9,42 @@ export interface TypeDistribution {
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface ProviderInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
provider_type: string;
|
||||
is_active: boolean;
|
||||
model_name?: string;
|
||||
}
|
||||
|
||||
export interface ProviderHealth {
|
||||
provider_id: string;
|
||||
status: string;
|
||||
latency_ms?: number;
|
||||
last_checked_at?: string;
|
||||
}
|
||||
|
||||
export interface QuotaSummary {
|
||||
provider_id: string;
|
||||
quota_limit: number;
|
||||
quota_used: number;
|
||||
quota_remaining: number;
|
||||
period: string;
|
||||
}
|
||||
|
||||
export interface BudgetStatus {
|
||||
total_budget: number;
|
||||
spent: number;
|
||||
remaining: number;
|
||||
period: string;
|
||||
}
|
||||
|
||||
export interface CostEstimate {
|
||||
analysis_type: string;
|
||||
estimated_cost: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export const usageApi = {
|
||||
overview: async () => {
|
||||
const resp = await client.get('/ai/usage/overview');
|
||||
@@ -18,4 +54,24 @@ export const usageApi = {
|
||||
const resp = await client.get('/ai/usage/by-type');
|
||||
return resp.data.data as TypeDistribution[];
|
||||
},
|
||||
listProviders: async () => {
|
||||
const resp = await client.get('/ai/providers');
|
||||
return resp.data.data as ProviderInfo[];
|
||||
},
|
||||
getProvidersHealth: async () => {
|
||||
const resp = await client.get('/ai/providers/health');
|
||||
return resp.data.data as ProviderHealth[];
|
||||
},
|
||||
getQuotaSummary: async () => {
|
||||
const resp = await client.get('/ai/quota/summary');
|
||||
return resp.data.data as QuotaSummary[];
|
||||
},
|
||||
getBudgetStatus: async () => {
|
||||
const resp = await client.get('/ai/budget/status');
|
||||
return resp.data.data as BudgetStatus;
|
||||
},
|
||||
getCostEstimate: async (params: { analysis_type: string }) => {
|
||||
const resp = await client.get('/ai/cost/estimate', { params });
|
||||
return resp.data.data as CostEstimate;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -86,3 +86,32 @@ export const alertRuleApi = {
|
||||
deactivate: (id: string, version: number) =>
|
||||
client.put(`/health/alert-rules/${id}/deactivate`, { version }).then((r) => r.data.data as AlertRule),
|
||||
};
|
||||
|
||||
// --- Critical Alerts API ---
|
||||
|
||||
export interface CriticalAlert {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
patient_name?: string;
|
||||
alert_type: string;
|
||||
severity: string;
|
||||
title: string;
|
||||
detail?: Record<string, unknown>;
|
||||
status: string;
|
||||
acknowledged_by?: string;
|
||||
acknowledged_at?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export const criticalAlertApi = {
|
||||
list: (params?: { page?: number; page_size?: number }) =>
|
||||
client.get('/health/critical-alerts', { params }).then((r) => r.data.data as PaginatedResponse<CriticalAlert>),
|
||||
|
||||
get: (id: string) =>
|
||||
client.get(`/health/critical-alerts/${id}`).then((r) => r.data.data as CriticalAlert),
|
||||
|
||||
acknowledge: (id: string, req: { notes?: string }) =>
|
||||
client.post(`/health/critical-alerts/${id}/acknowledge`, req).then((r) => r.data),
|
||||
};
|
||||
|
||||
@@ -149,11 +149,11 @@ export const articleApi = {
|
||||
return data.data;
|
||||
},
|
||||
|
||||
delete: async (id: string) => {
|
||||
delete: async (id: string, version: number) => {
|
||||
const { data } = await client.delete<{
|
||||
success: boolean;
|
||||
data: null;
|
||||
}>(`/health/articles/${id}`);
|
||||
}>(`/health/articles/${id}`, { data: { version } });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
@@ -196,6 +196,14 @@ export const articleApi = {
|
||||
}>(`/health/articles/${id}/view`);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
listRevisions: async (id: string, params?: { page?: number; page_size?: number }) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PaginatedResponse<Record<string, unknown>>;
|
||||
}>(`/health/articles/${id}/revisions`, { params });
|
||||
return data.data;
|
||||
},
|
||||
};
|
||||
|
||||
// --- Category API ---
|
||||
|
||||
@@ -102,4 +102,36 @@ export const consultationApi = {
|
||||
}>('/health/consultation-messages', req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
pollMessages: async (
|
||||
sessionId: string,
|
||||
afterId?: string,
|
||||
) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: Message[];
|
||||
}>(`/health/consultation-sessions/${sessionId}/messages/poll`, {
|
||||
params: { after_id: afterId, timeout: 25 },
|
||||
timeout: 30000,
|
||||
});
|
||||
return data.data;
|
||||
},
|
||||
|
||||
markSessionRead: async (id: string) => {
|
||||
await client.put(`/health/consultation-sessions/${id}/read`);
|
||||
},
|
||||
|
||||
exportSessions: async (params?: {
|
||||
status?: string;
|
||||
patient_id?: string;
|
||||
doctor_id?: string;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PaginatedResponse<Session>;
|
||||
}>('/health/consultation-sessions/export', { params });
|
||||
return data.data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -105,4 +105,12 @@ export const dialysisApi = {
|
||||
}>(`/health/dialysis-records/${id}/review`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
completeRecord: async (id: string, version: number) => {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: DialysisRecord;
|
||||
}>(`/health/dialysis-records/${id}/complete`, { version });
|
||||
return data.data;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -77,7 +77,7 @@ export const doctorApi = {
|
||||
return data.data;
|
||||
},
|
||||
|
||||
delete: async (id: string) => {
|
||||
await client.delete(`/health/doctors/${id}`);
|
||||
delete: async (id: string, version: number) => {
|
||||
await client.delete(`/health/doctors/${id}`, { data: { version } });
|
||||
},
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@ export const familyProxyApi = {
|
||||
const { data } = await client.post<{
|
||||
success: boolean;
|
||||
data: FamilyMember;
|
||||
}>(`/health/patients/${patientId}/family-members/${familyMemberId}/grant-access?version=${version}`, req);
|
||||
}>(`/health/patients/${patientId}/family-members/${familyMemberId}/grant-access`, { ...req, version });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@ export const familyProxyApi = {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: FamilyMember;
|
||||
}>(`/health/patients/${patientId}/family-members/${familyMemberId}/revoke-access?version=${version}`);
|
||||
}>(`/health/patients/${patientId}/family-members/${familyMemberId}/revoke-access`, { version });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
@@ -95,7 +95,7 @@ export const familyProxyApi = {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: FamilyPatientSummary[];
|
||||
}>('/health/family/my-patients');
|
||||
}>('/health/family/patients');
|
||||
return data.data;
|
||||
},
|
||||
|
||||
|
||||
@@ -249,6 +249,14 @@ export const healthDataApi = {
|
||||
return data.data;
|
||||
},
|
||||
|
||||
generateTrend: async (patientId: string, req: { indicator: string; start_date?: string; end_date?: string }) => {
|
||||
const { data } = await client.post<{
|
||||
success: boolean;
|
||||
data: TrendData;
|
||||
}>(`/health/patients/${patientId}/trends/generate`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
getIndicatorTimeseries: async (patientId: string, indicator: string) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
|
||||
75
apps/web/src/api/health/medicationReminders.ts
Normal file
75
apps/web/src/api/health/medicationReminders.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import client from '../client';
|
||||
import type { PaginatedResponse } from '../types';
|
||||
|
||||
// --- Types ---
|
||||
|
||||
export interface MedicationReminder {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
medication_name: string;
|
||||
dosage?: string;
|
||||
frequency: string;
|
||||
time_slots: string[];
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
is_active: boolean;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface CreateMedicationReminderReq {
|
||||
patient_id: string;
|
||||
medication_name: string;
|
||||
dosage?: string;
|
||||
frequency?: string;
|
||||
time_slots?: string[];
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
is_active?: boolean;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface UpdateMedicationReminderReq {
|
||||
medication_name?: string;
|
||||
dosage?: string;
|
||||
frequency?: string;
|
||||
time_slots?: string[];
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
is_active?: boolean;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
// --- API ---
|
||||
|
||||
export const medicationReminderApi = {
|
||||
list: async (patientId: string, params?: { page?: number; page_size?: number }) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PaginatedResponse<MedicationReminder>;
|
||||
}>(`/health/patients/${patientId}/medication-reminders`, { params });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
create: async (req: CreateMedicationReminderReq) => {
|
||||
const { data } = await client.post<{
|
||||
success: boolean;
|
||||
data: MedicationReminder;
|
||||
}>('/health/medication-reminders', req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
update: async (id: string, req: UpdateMedicationReminderReq & { version: number }) => {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: MedicationReminder;
|
||||
}>(`/health/medication-reminders/${id}`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
delete: async (id: string, version: number) => {
|
||||
await client.delete(`/health/medication-reminders/${id}`, { data: { version } });
|
||||
},
|
||||
};
|
||||
@@ -294,7 +294,7 @@ export const pointsApi = {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: PointsRule;
|
||||
}>(`/health/admin/points/rules/${id}`, { data: req, version: req.version });
|
||||
}>(`/health/admin/points/rules/${id}`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
@@ -325,7 +325,7 @@ export const pointsApi = {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: PointsProduct;
|
||||
}>(`/health/admin/points/products/${id}`, { data: req, version: req.version });
|
||||
}>(`/health/admin/points/products/${id}`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user