diff --git a/apps/web/src/api/health/followUp.ts b/apps/web/src/api/health/followUp.ts index 1f4aec9..c2b6a44 100644 --- a/apps/web/src/api/health/followUp.ts +++ b/apps/web/src/api/health/followUp.ts @@ -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; diff --git a/apps/web/src/pages/health/FollowUpTaskList.tsx b/apps/web/src/pages/health/FollowUpTaskList.tsx index dc245df..68470b2 100644 --- a/apps/web/src/pages/health/FollowUpTaskList.tsx +++ b/apps/web/src/pages/health/FollowUpTaskList.tsx @@ -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(); const [assignTask, setAssignTask] = useState(null); - // Doctor label cache (for assignee display from users table) - const [doctorLabels, setDoctorLabels] = useState>({}); - 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 = {}; - 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: '创建时间', diff --git a/crates/erp-health/src/dto/follow_up_dto.rs b/crates/erp-health/src/dto/follow_up_dto.rs index 379dea9..94ea328 100644 --- a/crates/erp-health/src/dto/follow_up_dto.rs +++ b/crates/erp-health/src/dto/follow_up_dto.rs @@ -50,6 +50,8 @@ pub struct FollowUpTaskResp { pub patient_id: Uuid, pub assigned_to: Option, pub patient_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub assigned_to_name: Option, pub follow_up_type: String, pub planned_date: NaiveDate, pub status: String, diff --git a/crates/erp-health/src/service/follow_up_service.rs b/crates/erp-health/src/service/follow_up_service.rs index 774c8db..8fbc7e6 100644 --- a/crates/erp-health/src/service/follow_up_service.rs +++ b/crates/erp-health/src/service/follow_up_service.rs @@ -68,9 +68,32 @@ pub async fn list_tasks( HashMap::new() }; + // 批量查询 assigned_to_name(从 users 表) + let assigned_ids: HashSet = models.iter().filter_map(|m| m.assigned_to).collect(); + let assigned_names: HashMap = if !assigned_ids.is_empty() { + let ids_csv = assigned_ids.iter().map(|id| format!("'{}'", id)).collect::>().join(","); + let sql = format!( + "SELECT id, COALESCE(display_name, username) AS name FROM users WHERE id IN ({}) AND tenant_id = '{}'", + ids_csv, tenant_id + ); + let rows = state.db.query_all(sea_orm::Statement::from_string( + sea_orm::DatabaseBackend::Postgres, sql, + )).await?; + rows.into_iter() + .filter_map(|row| { + let id: Uuid = row.try_get_by_index(0).ok()?; + let name: String = row.try_get_by_index(1).ok()?; + Some((id, name)) + }) + .collect() + } else { + HashMap::new() + }; + let data = models.into_iter().map(|m| FollowUpTaskResp { id: m.id, patient_id: m.patient_id, assigned_to: m.assigned_to, patient_name: patient_names.get(&m.patient_id).cloned(), + assigned_to_name: m.assigned_to.and_then(|uid| assigned_names.get(&uid).cloned()), follow_up_type: m.follow_up_type, planned_date: m.planned_date, status: m.status, content_template: m.content_template, related_appointment_id: m.related_appointment_id, @@ -95,7 +118,7 @@ pub async fn get_task( Ok(FollowUpTaskResp { id: m.id, patient_id: m.patient_id, assigned_to: m.assigned_to, - patient_name: None, + patient_name: None, assigned_to_name: None, follow_up_type: m.follow_up_type, planned_date: m.planned_date, status: m.status, content_template: m.content_template, related_appointment_id: m.related_appointment_id, @@ -156,7 +179,7 @@ pub async fn create_task( Ok(FollowUpTaskResp { id: m.id, patient_id: m.patient_id, assigned_to: m.assigned_to, - patient_name: None, + patient_name: None, assigned_to_name: None, follow_up_type: m.follow_up_type, planned_date: m.planned_date, status: m.status, content_template: m.content_template, related_appointment_id: m.related_appointment_id, @@ -227,7 +250,7 @@ pub async fn update_task( Ok(FollowUpTaskResp { id: m.id, patient_id: m.patient_id, assigned_to: m.assigned_to, - patient_name: None, + patient_name: None, assigned_to_name: None, follow_up_type: m.follow_up_type, planned_date: m.planned_date, status: m.status, content_template: m.content_template, related_appointment_id: m.related_appointment_id,