diff --git a/apps/web/src/pages/health/AppointmentList.tsx b/apps/web/src/pages/health/AppointmentList.tsx index 789508d..ddfcce9 100644 --- a/apps/web/src/pages/health/AppointmentList.tsx +++ b/apps/web/src/pages/health/AppointmentList.tsx @@ -28,6 +28,7 @@ import { DrawerForm } from '../../components/DrawerForm'; import { EntityName } from '../../components/EntityName'; import { formatDateTime } from '../../utils/format'; import { usePaginatedData } from '../../hooks/usePaginatedData'; +import { useApiRequest } from '../../hooks/useApiRequest'; /** 预约类型选项 */ const APPOINTMENT_TYPE_OPTIONS = [ @@ -127,6 +128,8 @@ export default function AppointmentList() { }, }); + const { execute } = useApiRequest(); + const handleFilterChange = useCallback( (key: keyof AppointmentFilters, value: unknown) => { setFilters((prev) => ({ ...prev, [key]: value })); @@ -168,17 +171,15 @@ export default function AppointmentList() { okText: '确认', cancelText: '取消', onOk: async () => { - try { - await appointmentApi.updateStatus(record.id, { + const result = await execute( + () => appointmentApi.updateStatus(record.id, { status: newStatus, version: record.version, ...(newStatus === 'cancelled' && { cancel_reason: cancelReason }), - }); - message.success('状态更新成功'); - refresh(); - } catch { - message.error('状态更新失败'); - } + }), + '状态更新成功', + ); + if (result !== null) refresh(); }, }); } else { @@ -188,16 +189,14 @@ export default function AppointmentList() { okText: '确认', cancelText: '取消', onOk: async () => { - try { - await appointmentApi.updateStatus(record.id, { + const result = await execute( + () => appointmentApi.updateStatus(record.id, { status: newStatus, version: record.version, - }); - message.success('状态更新成功'); - refresh(); - } catch { - message.error('状态更新失败'); - } + }), + '状态更新成功', + ); + if (result !== null) refresh(); }, }); } @@ -246,27 +245,26 @@ export default function AppointmentList() { message.warning('请选择医护'); return; } - try { - setSubmitting(true); - const req: CreateAppointmentReq = { - patient_id: selectedPatientId, - doctor_id: selectedDoctorId, - appointment_date: (values.appointment_date as Dayjs).format('YYYY-MM-DD'), - start_time: (values.start_time as Dayjs).format('HH:mm'), - end_time: (values.end_time as Dayjs).format('HH:mm'), - appointment_type: (values.appointment_type as string) || 'outpatient', - notes: (values.notes as string) || undefined, - }; - await appointmentApi.create(req); - message.success('预约创建成功'); + setSubmitting(true); + const req: CreateAppointmentReq = { + patient_id: selectedPatientId, + doctor_id: selectedDoctorId, + appointment_date: (values.appointment_date as Dayjs).format('YYYY-MM-DD'), + start_time: (values.start_time as Dayjs).format('HH:mm'), + end_time: (values.end_time as Dayjs).format('HH:mm'), + appointment_type: (values.appointment_type as string) || 'outpatient', + notes: (values.notes as string) || undefined, + }; + const result = await execute( + () => appointmentApi.create(req), + '预约创建成功', + ); + setSubmitting(false); + if (result !== null) { setDrawerOpen(false); setSelectedPatientId(undefined); setSelectedDoctorId(undefined); refresh(); - } catch { - message.error('创建预约失败'); - } finally { - setSubmitting(false); } }; diff --git a/apps/web/src/pages/health/FollowUpTaskList.tsx b/apps/web/src/pages/health/FollowUpTaskList.tsx index 5505aec..bc568a0 100644 --- a/apps/web/src/pages/health/FollowUpTaskList.tsx +++ b/apps/web/src/pages/health/FollowUpTaskList.tsx @@ -9,7 +9,6 @@ import { DatePicker, Space, Popconfirm, - message, } from 'antd'; import { PlusOutlined, EditOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'; import type { ColumnsType, TablePaginationConfig } from 'antd/es/table'; @@ -24,6 +23,7 @@ import { EntityName } from '../../components/EntityName'; import { DrawerForm } from '../../components/DrawerForm'; import { formatDate, formatDateTime } from '../../utils/format'; import { usePaginatedData } from '../../hooks/usePaginatedData'; +import { useApiRequest } from '../../hooks/useApiRequest'; const STATUS_OPTIONS = [ { value: 'pending', label: '待处理' }, @@ -90,6 +90,8 @@ export default function FollowUpTaskList() { defaultFilters: {}, }); + const { execute } = useApiRequest(); + // Create task modal const [createOpen, setCreateOpen] = useState(false); const [createLoading, setCreateLoading] = useState(false); @@ -113,26 +115,30 @@ export default function FollowUpTaskList() { // Create task const handleCreate = async () => { + let values: CreateFollowUpTaskReq; try { - const values = await createForm.validateFields(); - setCreateLoading(true); - const plannedDate = values.planned_date; - await followUpApi.createTask({ + values = await createForm.validateFields(); + } catch (err: unknown) { + if (err && typeof err === 'object' && 'errorFields' in err) return; + return; + } + setCreateLoading(true); + const plannedDate = values.planned_date; + const result = await execute( + () => followUpApi.createTask({ patient_id: values.patient_id, follow_up_type: values.follow_up_type, planned_date: dayjs.isDayjs(plannedDate) ? plannedDate.format('YYYY-MM-DD') : plannedDate, assigned_to: values.assigned_to, content_template: values.content_template, - }); - message.success('随访任务创建成功'); + }), + '随访任务创建成功', + ); + setCreateLoading(false); + if (result !== null) { setCreateOpen(false); createForm.resetFields(); refresh(page); - } catch (err: unknown) { - if (err && typeof err === 'object' && 'errorFields' in err) return; // form validation - message.error('创建随访任务失败'); - } finally { - setCreateLoading(false); } }; @@ -144,9 +150,9 @@ export default function FollowUpTaskList() { const handleRecordSubmit = async (values: Record) => { if (!activeTask) return; - try { - setRecordLoading(true); - await followUpApi.createRecord(activeTask.id, { + setRecordLoading(true); + const result = await execute( + () => followUpApi.createRecord(activeTask.id, { executed_date: (values.executed_date as dayjs.Dayjs).format('YYYY-MM-DD'), result: values.result as string, patient_condition: values.patient_condition as string, @@ -154,15 +160,14 @@ export default function FollowUpTaskList() { next_follow_up_date: values.next_follow_up_date ? (values.next_follow_up_date as dayjs.Dayjs).format('YYYY-MM-DD') : undefined, - }); - message.success('随访记录填写成功'); + }), + '随访记录填写成功', + ); + setRecordLoading(false); + if (result !== null) { setRecordOpen(false); setActiveTask(null); refresh(page); - } catch { - message.error('填写随访记录失败'); - } finally { - setRecordLoading(false); } }; @@ -178,35 +183,37 @@ export default function FollowUpTaskList() { const handleAssign = async () => { if (!assignTask) return; + let values: { assigned_to: string }; try { - const values = await assignForm.validateFields(); - setAssignLoading(true); - const req: UpdateFollowUpTaskReq & { version: number } = { - assigned_to: values.assigned_to, - version: assignTask.version, - }; - await followUpApi.updateTask(assignTask.id, req); - message.success('分配成功'); + values = await assignForm.validateFields(); + } catch (err: unknown) { + if (err && typeof err === 'object' && 'errorFields' in err) return; + return; + } + setAssignLoading(true); + const req: UpdateFollowUpTaskReq & { version: number } = { + assigned_to: values.assigned_to, + version: assignTask.version, + }; + const result = await execute( + () => followUpApi.updateTask(assignTask.id, req), + '分配成功', + ); + setAssignLoading(false); + if (result !== null) { setAssignOpen(false); setAssignTask(null); refresh(page); - } catch (err: unknown) { - if (err && typeof err === 'object' && 'errorFields' in err) return; - message.error('分配失败'); - } finally { - setAssignLoading(false); } }; // Delete const handleDelete = async (record: FollowUpTask) => { - try { - await followUpApi.deleteTask(record.id, record.version); - message.success('删除成功'); - refresh(page); - } catch { - message.error('删除失败'); - } + const result = await execute( + () => followUpApi.deleteTask(record.id, record.version), + '删除成功', + ); + if (result !== null) refresh(page); }; // --- Columns --- diff --git a/apps/web/src/pages/health/PatientList.tsx b/apps/web/src/pages/health/PatientList.tsx index a95eb02..35abe94 100644 --- a/apps/web/src/pages/health/PatientList.tsx +++ b/apps/web/src/pages/health/PatientList.tsx @@ -9,7 +9,6 @@ import { Select, Popconfirm, DatePicker, - message, } from 'antd'; import { PlusOutlined, @@ -29,6 +28,7 @@ import { AuthButton } from '../../components/AuthButton'; import { PageContainer } from '../../components/PageContainer'; import { DrawerForm } from '../../components/DrawerForm'; import { usePaginatedData } from '../../hooks/usePaginatedData'; +import { useApiRequest } from '../../hooks/useApiRequest'; import { calcAge, formatDateTime } from '../../utils/format'; import { dayjs } from '../../utils/dayjs'; @@ -53,6 +53,9 @@ export default function PatientList() { const [editingPatient, setEditingPatient] = useState(null); const [selectedRowKeys, setSelectedRowKeys] = useState([]); + // ---- API 请求 Hook ---- + const { execute } = useApiRequest(); + // ---- 分页数据 Hook ---- const { data: patients, @@ -125,39 +128,36 @@ export default function PatientList() { notes: values.notes as string | undefined, }; - try { - if (editingPatient) { - const req: UpdatePatientReq & { version: number } = { - ...payload, - version: editingPatient.version, - }; - await patientApi.update(editingPatient.id, req); - message.success('患者信息更新成功'); - } else { + const successMsg = editingPatient ? '患者信息更新成功' : '患者创建成功'; + const result = await execute( + async () => { + if (editingPatient) { + const req: UpdatePatientReq & { version: number } = { + ...payload, + version: editingPatient.version, + }; + return patientApi.update(editingPatient.id, req); + } const req: CreatePatientReq = payload; - await patientApi.create(req); - message.success('患者创建成功'); - } + return patientApi.create(req); + }, + successMsg, + '操作失败', + ); + if (result !== null) { closeModal(); refresh(); - } catch (err: unknown) { - const errorMsg = - (err as { response?: { data?: { message?: string } } })?.response?.data - ?.message || '操作失败'; - message.error(errorMsg); } }; const handleDelete = async (id: string) => { - try { - const patient = patients.find((p) => p.id === id); - const version = patient?.version ?? 0; - await patientApi.delete(id, version); - message.success('患者已删除'); - refresh(); - } catch { - message.error('删除失败'); - } + const patient = patients.find((p) => p.id === id); + const version = patient?.version ?? 0; + const result = await execute( + () => patientApi.delete(id, version), + '患者已删除', + ); + if (result !== null) refresh(); }; const openCreateModal = () => { @@ -166,12 +166,14 @@ export default function PatientList() { }; const openEditModal = async (record: PatientListItem) => { - try { - const detail = await patientApi.get(record.id); + const detail = await execute( + () => patientApi.get(record.id), + undefined, + '获取患者详情失败', + ); + if (detail) { setEditingPatient(detail); setModalOpen(true); - } catch { - message.error('获取患者详情失败'); } };