feat(web): 护理计划 Web UI — Phase 2a-1
新增护理计划管理前端页面,接入后端 8 条孤立路由: - API 模块: carePlans.ts(计划 + 干预项目 + 预后测量 CRUD) - 列表页: CarePlanList.tsx(筛选/新建/编辑/删除/跳转详情) - 详情页: CarePlanDetail.tsx(计划信息 + Items/Outcomes 双 Tab CRUD) - 路由注册: /health/care-plans + /health/care-plans/:id - 菜单标题: routeTitleFallback 映射 权限: health.care-plan.list / health.care-plan.manage
This commit is contained in:
245
apps/web/src/api/health/carePlans.ts
Normal file
245
apps/web/src/api/health/carePlans.ts
Normal file
@@ -0,0 +1,245 @@
|
||||
import client from '../client';
|
||||
import type { PaginatedResponse } from '../types';
|
||||
|
||||
// --- Types ---
|
||||
|
||||
export interface CarePlan {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
plan_type: string;
|
||||
status: string;
|
||||
title: string;
|
||||
goals?: Record<string, unknown>;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface CarePlanItem {
|
||||
id: string;
|
||||
plan_id: string;
|
||||
item_type: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
status: string;
|
||||
schedule?: string;
|
||||
sort_order?: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface CarePlanOutcome {
|
||||
id: string;
|
||||
plan_id: string;
|
||||
item_id?: string;
|
||||
metric: string;
|
||||
baseline_value: string;
|
||||
target_value: string;
|
||||
current_value?: string;
|
||||
measured_at?: string;
|
||||
notes?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface CreateCarePlanReq {
|
||||
patient_id: string;
|
||||
plan_type: string;
|
||||
title: string;
|
||||
goals?: Record<string, unknown>;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface UpdateCarePlanReq {
|
||||
plan_type?: string;
|
||||
title?: string;
|
||||
status?: string;
|
||||
goals?: Record<string, unknown>;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface CreateCarePlanItemReq {
|
||||
item_type: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
schedule?: string;
|
||||
sort_order?: number;
|
||||
}
|
||||
|
||||
export interface UpdateCarePlanItemReq {
|
||||
item_type?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
status?: string;
|
||||
schedule?: string;
|
||||
sort_order?: number;
|
||||
}
|
||||
|
||||
export interface CreateCarePlanOutcomeReq {
|
||||
item_id?: string;
|
||||
metric: string;
|
||||
baseline_value: string;
|
||||
target_value: string;
|
||||
current_value?: string;
|
||||
measured_at?: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface UpdateCarePlanOutcomeReq {
|
||||
item_id?: string;
|
||||
metric?: string;
|
||||
baseline_value?: string;
|
||||
target_value?: string;
|
||||
current_value?: string;
|
||||
measured_at?: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface ListCarePlansParams {
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
patient_id?: string;
|
||||
plan_type?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
// --- Constants ---
|
||||
|
||||
export const PLAN_TYPE_OPTIONS = [
|
||||
{ label: '血液透析', value: 'hemodialysis' },
|
||||
{ label: '腹膜透析', value: 'peritoneal' },
|
||||
{ label: '慢性病管理', value: 'chronic_disease' },
|
||||
{ label: '康复计划', value: 'rehabilitation' },
|
||||
];
|
||||
|
||||
export const PLAN_STATUS_OPTIONS = [
|
||||
{ label: '草稿', value: 'draft' },
|
||||
{ label: '进行中', value: 'active' },
|
||||
{ label: '已完成', value: 'completed' },
|
||||
{ label: '已取消', value: 'cancelled' },
|
||||
];
|
||||
|
||||
export const ITEM_TYPE_OPTIONS = [
|
||||
{ label: '药物干预', value: 'medication' },
|
||||
{ label: '饮食管理', value: 'diet' },
|
||||
{ label: '运动计划', value: 'exercise' },
|
||||
{ label: '监测项目', value: 'monitoring' },
|
||||
{ label: '教育指导', value: 'education' },
|
||||
{ label: '其他', value: 'other' },
|
||||
];
|
||||
|
||||
export const PLAN_STATUS_COLOR: Record<string, string> = {
|
||||
draft: 'default',
|
||||
active: 'processing',
|
||||
completed: 'success',
|
||||
cancelled: 'error',
|
||||
};
|
||||
|
||||
// --- API ---
|
||||
|
||||
export const carePlanApi = {
|
||||
list: async (params: ListCarePlansParams) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PaginatedResponse<CarePlan>;
|
||||
}>('/health/care-plans', { params });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
get: async (id: string) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: CarePlan;
|
||||
}>(`/health/care-plans/${id}`);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
create: async (req: CreateCarePlanReq) => {
|
||||
const { data } = await client.post<{
|
||||
success: boolean;
|
||||
data: CarePlan;
|
||||
}>('/health/care-plans', req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
update: async (id: string, req: UpdateCarePlanReq & { version: number }) => {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: CarePlan;
|
||||
}>(`/health/care-plans/${id}`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
delete: async (id: string, version: number) => {
|
||||
await client.delete(`/health/care-plans/${id}`, { data: { version } });
|
||||
},
|
||||
|
||||
// --- Items ---
|
||||
|
||||
listItems: async (planId: string, params?: { page?: number; page_size?: number }) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PaginatedResponse<CarePlanItem>;
|
||||
}>(`/health/care-plans/${planId}/items`, { params });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
createItem: async (planId: string, req: CreateCarePlanItemReq) => {
|
||||
const { data } = await client.post<{
|
||||
success: boolean;
|
||||
data: CarePlanItem;
|
||||
}>(`/health/care-plans/${planId}/items`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
updateItem: async (planId: string, itemId: string, req: UpdateCarePlanItemReq & { version: number }) => {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: CarePlanItem;
|
||||
}>(`/health/care-plans/${planId}/items/${itemId}`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
deleteItem: async (planId: string, itemId: string, version: number) => {
|
||||
await client.delete(`/health/care-plans/${planId}/items/${itemId}`, { data: { version } });
|
||||
},
|
||||
|
||||
// --- Outcomes ---
|
||||
|
||||
listOutcomes: async (planId: string, params?: { page?: number; page_size?: number }) => {
|
||||
const { data } = await client.get<{
|
||||
success: boolean;
|
||||
data: PaginatedResponse<CarePlanOutcome>;
|
||||
}>(`/health/care-plans/${planId}/outcomes`, { params });
|
||||
return data.data;
|
||||
},
|
||||
|
||||
createOutcome: async (planId: string, req: CreateCarePlanOutcomeReq) => {
|
||||
const { data } = await client.post<{
|
||||
success: boolean;
|
||||
data: CarePlanOutcome;
|
||||
}>(`/health/care-plans/${planId}/outcomes`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
updateOutcome: async (planId: string, outcomeId: string, req: UpdateCarePlanOutcomeReq & { version: number }) => {
|
||||
const { data } = await client.put<{
|
||||
success: boolean;
|
||||
data: CarePlanOutcome;
|
||||
}>(`/health/care-plans/${planId}/outcomes/${outcomeId}`, req);
|
||||
return data.data;
|
||||
},
|
||||
|
||||
deleteOutcome: async (planId: string, outcomeId: string, version: number) => {
|
||||
await client.delete(`/health/care-plans/${planId}/outcomes/${outcomeId}`, { data: { version } });
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user