perf(health): 随访列表内联负责人名称 — 消除 N+1 查询
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

follow_up list_tasks 批量查询 users 表获取 assigned_to_name,
前端移除 doctorLabels 逐条请求缓存,直接使用后端内联字段。
This commit is contained in:
iven
2026-04-27 13:22:46 +08:00
parent 2519ad8fee
commit a5646ddbb3
4 changed files with 36 additions and 30 deletions

View File

@@ -7,6 +7,7 @@ export interface FollowUpTask {
patient_id: string;
assigned_to?: string;
patient_name?: string;
assigned_to_name?: string;
follow_up_type: string;
planned_date: string;
status: string;

View File

@@ -15,7 +15,6 @@ import { PlusOutlined, EditOutlined, SwapOutlined, DeleteOutlined } from '@ant-d
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
import dayjs from 'dayjs';
import { followUpApi, type FollowUpTask, type CreateFollowUpTaskReq, type UpdateFollowUpTaskReq } from '../../api/health/followUp';
import { getUser } from '../../api/users';
import { StatusTag } from './components/StatusTag';
import { PatientSelect } from './components/PatientSelect';
import { DoctorSelect } from './components/DoctorSelect';
@@ -94,9 +93,6 @@ export default function FollowUpTaskList() {
const [assignForm] = Form.useForm<AssignFormValues>();
const [assignTask, setAssignTask] = useState<FollowUpTask | null>(null);
// Doctor label cache (for assignee display from users table)
const [doctorLabels, setDoctorLabels] = useState<Record<string, string>>({});
const isDark = useThemeMode();
// --- Data fetching ---
@@ -106,30 +102,12 @@ export default function FollowUpTaskList() {
const result = await followUpApi.listTasks(params);
setTasks(result.data);
setTotal(result.total);
// Batch resolve assignee names (from users table, not inlined by backend)
const assigneeIds = [...new Set(result.data.map((t: FollowUpTask) => t.assigned_to).filter((x): x is string => !!x))];
const missingIds = assigneeIds.filter((id) => !doctorLabels[id]);
if (missingIds.length > 0) {
const newDoctorLabels: Record<string, string> = {};
await Promise.allSettled(
missingIds.map(async (id) => {
try {
const u = await getUser(id);
newDoctorLabels[id] = u.display_name || u.username;
} catch { /* skip */ }
}),
);
if (Object.keys(newDoctorLabels).length > 0) {
setDoctorLabels((prev) => ({ ...prev, ...newDoctorLabels }));
}
}
} catch {
message.error('加载随访任务失败');
} finally {
setLoading(false);
}
}, [doctorLabels]);
}, []);
useEffect(() => {
fetchTasks(query);
@@ -247,9 +225,11 @@ export default function FollowUpTaskList() {
}
};
// Store labels from selects
// Store labels from selects for immediate display
const handleDoctorLabel = (id: string, label: string) => {
setDoctorLabels((prev) => ({ ...prev, [id]: label }));
setTasks((prev) =>
prev.map((t) => (t.assigned_to === id ? { ...t, assigned_to_name: label } : t)),
);
};
// --- Columns ---
@@ -288,8 +268,8 @@ export default function FollowUpTaskList() {
dataIndex: 'assigned_to',
key: 'assigned_to',
width: 140,
render: (id: string | undefined) =>
id ? doctorLabels[id] || id.slice(0, 8) : '-',
render: (_: unknown, record: FollowUpTask) =>
record.assigned_to ? record.assigned_to_name || record.assigned_to.slice(0, 8) : '-',
},
{
title: '创建时间',