feat(miniprogram): 医护端小程序页面 — 8 页面覆盖患者/咨询/随访/报告
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

Iteration 2 医护端前端核心页面:

- 新增 doctor.ts service 层(仪表盘/患者/咨询/随访/报告 API)
- 升级医生首页:接入真实仪表盘数据 + 快捷操作入口
- 患者管理:搜索 + 标签筛选 + 详情页(基本信息/过敏史/健康概览)
- 咨询回复:会话列表 + 状态筛选 + 聊天详情 + 发送消息 + 关闭会话
- 随访管理:任务列表 + 状态筛选 + 详情 + 填写随访记录
- 报告解读:化验报告列表 + 异常高亮 + 指标表格 + 医生审核注释
- 修复 login 页面重复解构
- 注册 8 个新页面路由到 app.config.ts
This commit is contained in:
iven
2026-04-26 13:32:08 +08:00
parent a0b72b0f73
commit 3723cd93c0
21 changed files with 2795 additions and 28 deletions

View File

@@ -0,0 +1,296 @@
import { api } from './request';
// ── Dashboard ──────────────────────────────────────
export interface DoctorDashboard {
total_patients: number;
active_sessions: number;
unread_messages: number;
pending_follow_ups: number;
today_consultations: number;
}
export async function getDashboard() {
return api.get<DoctorDashboard>('/health/doctor/dashboard');
}
// ── Patient (doctor view) ──────────────────────────
export interface PatientItem {
id: string;
name: string;
gender?: string;
birth_date?: string;
phone?: string;
status?: string;
tags?: { id: string; name: string; color?: string }[];
last_visit_date?: string;
version: number;
}
export interface PatientDetail extends PatientItem {
blood_type?: string;
allergy_history?: string;
medical_history_summary?: string;
emergency_contact_name?: string;
emergency_contact_phone?: string;
source?: string;
notes?: string;
}
export interface HealthSummary {
latest_vital_signs?: {
record_date: string;
systolic_bp?: number;
diastolic_bp?: number;
heart_rate?: number;
weight?: number;
blood_sugar?: number;
};
active_conditions?: string[];
recent_lab_reports?: { id: string; report_date: string; report_type: string; abnormal_count: number }[];
upcoming_appointments?: { id: string; appointment_date: string; type: string }[];
pending_follow_ups?: number;
}
export interface PatientTag {
id: string;
name: string;
color?: string;
is_system?: boolean;
}
export async function listPatients(params?: {
page?: number;
page_size?: number;
search?: string;
tag_id?: string;
}) {
return api.get<{ data: PatientItem[]; total: number }>('/health/patients', params);
}
export async function getPatient(id: string) {
return api.get<PatientDetail>(`/health/patients/${id}`);
}
export async function getHealthSummary(patientId: string) {
return api.get<HealthSummary>(`/health/patients/${patientId}/health-summary`);
}
export async function listPatientTags() {
return api.get<{ data: PatientTag[]; total: number }>('/health/patient-tags');
}
// ── Consultation (doctor view) ─────────────────────
export interface ConsultationSession {
id: string;
patient_id: string;
patient_name?: string;
doctor_id: string | null;
consultation_type: string;
status: string;
subject: string | null;
last_message: string | null;
last_message_at: string | null;
unread_count_doctor?: number;
created_at: string;
}
export interface ConsultationMessage {
id: string;
session_id: string;
sender_id: string;
sender_role: string;
content_type: string;
content: string;
created_at: string;
}
export async function listSessions(params?: {
page?: number;
page_size?: number;
status?: string;
}) {
return api.get<{ data: ConsultationSession[]; total: number }>(
'/health/consultation-sessions',
params,
);
}
export async function getSession(id: string) {
return api.get<ConsultationSession>(`/health/consultation-sessions/${id}`);
}
export async function listMessages(sessionId: string, params?: { page?: number; page_size?: number }) {
return api.get<{ data: ConsultationMessage[]; total: number }>(
`/health/consultation-sessions/${sessionId}/messages`,
params,
);
}
export async function sendMessage(sessionId: string, content: string, contentType = 'text') {
return api.post<ConsultationMessage>('/health/consultation-messages', {
session_id: sessionId,
content_type: contentType,
content,
});
}
export async function markSessionRead(sessionId: string) {
return api.put<void>(`/health/consultation-sessions/${sessionId}/read`);
}
export async function closeSession(sessionId: string) {
return api.put<void>(`/health/consultation-sessions/${sessionId}/close`);
}
// ── Follow-up (doctor view) ────────────────────────
export interface FollowUpTask {
id: string;
patient_id: string;
patient_name?: string;
assigned_to?: string;
follow_up_type: string;
planned_date: string;
content_template?: string;
status: string;
created_at: string;
version: number;
}
export interface FollowUpRecord {
id: string;
task_id: string;
executed_by?: string;
executed_date: string;
result?: string;
patient_condition?: string;
medical_advice?: string;
next_follow_up_date?: string;
created_at: string;
}
export async function listFollowUpTasks(params?: {
page?: number;
page_size?: number;
status?: string;
patient_id?: string;
}) {
return api.get<{ data: FollowUpTask[]; total: number }>('/health/follow-up-tasks', params);
}
export async function getFollowUpTask(id: string) {
return api.get<FollowUpTask>(`/health/follow-up-tasks/${id}`);
}
export async function updateFollowUpTask(id: string, data: Record<string, unknown>, version: number) {
return api.put<FollowUpTask>(`/health/follow-up-tasks/${id}`, { ...data, version });
}
export async function createFollowUpRecord(taskId: string, data: {
result?: string;
patient_condition?: string;
medical_advice?: string;
next_follow_up_date?: string;
}) {
return api.post<FollowUpRecord>(`/health/follow-up-tasks/${taskId}/records`, data);
}
export async function listFollowUpRecords(params?: { task_id?: string; page?: number }) {
return api.get<{ data: FollowUpRecord[]; total: number }>('/health/follow-up-records', params);
}
// ── Lab Report (doctor view) ───────────────────────
export interface LabReportItem {
id: string;
report_date: string;
report_type: string;
status: string;
abnormal_count?: number;
reviewed_by?: string;
reviewed_at?: string;
doctor_notes?: string;
version: number;
}
export interface LabReportDetail extends LabReportItem {
items?: {
name: string;
value: number;
unit?: string;
reference_min?: number;
reference_max?: number;
is_abnormal?: boolean;
}[];
image_urls?: string[];
}
export async function listLabReports(patientId: string, params?: { page?: number; page_size?: number }) {
return api.get<{ data: LabReportItem[]; total: number }>(
`/health/patients/${patientId}/lab-reports`,
params,
);
}
export async function getLabReport(patientId: string, reportId: string) {
return api.get<LabReportDetail>(`/health/patients/${patientId}/lab-reports/${reportId}`);
}
export async function reviewLabReport(
patientId: string,
reportId: string,
data: { doctor_notes?: string; version: number },
) {
return api.put<LabReportDetail>(
`/health/patients/${patientId}/lab-reports/${reportId}/review`,
data,
);
}
// ── Appointments (doctor view) ─────────────────────
export async function listAppointments(params?: {
page?: number;
page_size?: number;
status?: string;
date?: string;
}) {
return api.get<{ data: any[]; total: number }>('/health/appointments', params);
}
// ── Statistics ─────────────────────────────────────
export interface PatientStats {
total: number;
active: number;
new_this_month: number;
by_source?: Record<string, number>;
}
export interface ConsultationStats {
total: number;
active: number;
avg_response_time_minutes?: number;
}
export interface FollowUpStats {
total: number;
completed: number;
overdue: number;
completion_rate?: number;
}
export async function getPatientStats() {
return api.get<PatientStats>('/health/admin/statistics/patients');
}
export async function getConsultationStats() {
return api.get<ConsultationStats>('/health/admin/statistics/consultations');
}
export async function getFollowUpStats() {
return api.get<FollowUpStats>('/health/admin/statistics/follow-ups');
}