fix: Phase 1.3 完善修复 — 管理端对接 + HMS清理 + 编辑器加载
- feat(web): ClassList.tsx 对接 update/deactivate/reset-code API - 编辑班级: PUT /diary/classes/:id - 停用班级: PATCH /diary/classes/:id/deactivate (Popconfirm 确认) - 重置班级码: POST /diary/classes/:id/reset-code (Popconfirm 确认) - 数据源改用 listAll() 获取所有班级 - fix(web): JournalList.tsx 班级筛选改用 classApi.listAll() - fix(app): EditorPage 加载已有日记数据 (journalId 非空时) - 从 Isar 恢复笔画/元素/标签/心情/标题 - _EditorView 改为 StatefulWidget + initState 加载 - chore(web): HMS 遗留代码清理 - 删除 api/copilot.ts, healthFixtures.ts, healthHandlers.ts - AuditLogViewer 资源类型替换为日记模块类型 - auth.test.ts / renderWithProviders 权限码 health.* → diary.* - docs: 确认 M6 NotificationService 为误报 (已在 3 处调用)
This commit is contained in:
@@ -1,66 +0,0 @@
|
||||
import client from './client';
|
||||
import type { PaginatedResponse } from './types';
|
||||
|
||||
// --- Types ---
|
||||
|
||||
export type InsightType = 'risk_score' | 'anomaly' | 'follow_up_hint' | 'consult_hint';
|
||||
export type InsightSource = 'rule' | 'llm' | 'hybrid';
|
||||
export type RiskLevel = 'low' | 'medium' | 'high' | 'critical';
|
||||
|
||||
export interface MatchedRule {
|
||||
rule_id: string;
|
||||
name: string;
|
||||
score: number;
|
||||
severity: string;
|
||||
suggestion?: string;
|
||||
}
|
||||
|
||||
export interface RiskScore {
|
||||
score: number;
|
||||
level: RiskLevel;
|
||||
matched_rules: MatchedRule[];
|
||||
}
|
||||
|
||||
export interface CopilotInsight {
|
||||
id: string;
|
||||
patient_id: string;
|
||||
insight_type: InsightType;
|
||||
source: InsightSource;
|
||||
severity: 'info' | 'warning' | 'critical';
|
||||
title: string;
|
||||
content: Record<string, unknown>;
|
||||
rule_matches?: MatchedRule[];
|
||||
llm_supplement?: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
// --- API Functions ---
|
||||
|
||||
export async function getPatientRisk(patientId: string) {
|
||||
const { data } = await client.get<{ success: boolean; data: RiskScore }>(`/copilot/patients/${patientId}/risk`);
|
||||
return data.data;
|
||||
}
|
||||
|
||||
export async function listInsights(params: {
|
||||
patient_id?: string;
|
||||
insight_type?: string;
|
||||
severity?: string;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}) {
|
||||
const { data } = await client.get<{ success: boolean; data: PaginatedResponse<CopilotInsight> }>('/copilot/insights', { params });
|
||||
return data.data;
|
||||
}
|
||||
|
||||
export function dismissInsight(id: string) {
|
||||
return client.post(`/copilot/insights/${id}/dismiss`);
|
||||
}
|
||||
|
||||
export function listAlerts(params?: { severity?: string; page?: number; page_size?: number }) {
|
||||
return listInsights({ insight_type: 'anomaly', ...params });
|
||||
}
|
||||
|
||||
export async function listRules(params?: { page?: number; page_size?: number }) {
|
||||
const { data } = await client.get<{ success: boolean; data: PaginatedResponse<Record<string, unknown>> }>('/copilot/rules', { params });
|
||||
return data.data;
|
||||
}
|
||||
@@ -1,20 +1,23 @@
|
||||
import client from '../client';
|
||||
import type { SchoolClass, CreateClassReq, ClassMember, PaginatedResponse } from './types';
|
||||
import type { SchoolClass, CreateClassReq, UpdateClassReq, ClassMember, PaginatedResponse } from './types';
|
||||
|
||||
export const classApi = {
|
||||
/** 班级列表 — 后端返回纯数组,前端转换为 PaginatedResponse 格式 */
|
||||
/** 班级列表 — 当前用户加入的班级 (GET /diary/classes → my_classes) */
|
||||
list: (params?: { page?: number; page_size?: number }) =>
|
||||
client.get<{ success: boolean; data: SchoolClass[] }>('/diary/classes', { params })
|
||||
.then((r) => {
|
||||
const raw = r.data.data;
|
||||
// 后端返回纯数组,包装为分页格式
|
||||
if (Array.isArray(raw)) {
|
||||
return { data: raw, total: raw.length, page: params?.page ?? 1, page_size: params?.page_size ?? 20 } as PaginatedResponse<SchoolClass>;
|
||||
}
|
||||
// 兼容:如果后端已升级为分页格式
|
||||
return raw as unknown as PaginatedResponse<SchoolClass>;
|
||||
}),
|
||||
|
||||
/** 所有班级 — 管理端用,需要 diary.class.manage 权限 (GET /diary/classes/all) */
|
||||
listAll: () =>
|
||||
client.get<{ success: boolean; data: SchoolClass[] }>('/diary/classes/all')
|
||||
.then((r) => r.data.data),
|
||||
|
||||
myClasses: () =>
|
||||
client.get<{ success: boolean; data: SchoolClass[] }>('/diary/classes/my')
|
||||
.then((r) => r.data.data),
|
||||
@@ -26,6 +29,18 @@ export const classApi = {
|
||||
create: (data: CreateClassReq) =>
|
||||
client.post('/diary/classes', data).then((r) => r.data.data),
|
||||
|
||||
/** 更新班级信息 (PUT /diary/classes/:id) */
|
||||
update: (id: string, data: UpdateClassReq) =>
|
||||
client.put(`/diary/classes/${id}`, data).then((r) => r.data.data),
|
||||
|
||||
/** 停用班级 (PATCH /diary/classes/:id/deactivate) */
|
||||
deactivate: (id: string) =>
|
||||
client.patch(`/diary/classes/${id}/deactivate`).then((r) => r.data.data),
|
||||
|
||||
/** 重置班级码 (POST /diary/classes/:id/reset-code) */
|
||||
resetCode: (id: string) =>
|
||||
client.post(`/diary/classes/${id}/reset-code`).then((r) => r.data.data),
|
||||
|
||||
listMembers: (classId: string) =>
|
||||
client.get<{ success: boolean; data: ClassMember[] }>(`/diary/classes/${classId}/members`)
|
||||
.then((r) => r.data.data),
|
||||
|
||||
@@ -50,6 +50,17 @@ export interface CreateClassReq {
|
||||
school_name?: string;
|
||||
}
|
||||
|
||||
export interface UpdateClassReq {
|
||||
name?: string;
|
||||
school_name?: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface ResetClassCodeResp {
|
||||
class_id: string;
|
||||
new_class_code: string;
|
||||
}
|
||||
|
||||
export interface ClassMember {
|
||||
user_id: string;
|
||||
role: string;
|
||||
|
||||
Reference in New Issue
Block a user