diff --git a/src/components/exam/ExamSignPanel.tsx b/src/components/exam/ExamSignPanel.tsx index 31c351a..795b3a2 100644 --- a/src/components/exam/ExamSignPanel.tsx +++ b/src/components/exam/ExamSignPanel.tsx @@ -2,8 +2,8 @@ import { useEffect, useRef, useState } from 'react'; import * as pdfjsLib from 'pdfjs-dist'; import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url'; -import type { OutputTongyishuFileInfo, OutputTijianPdfFileInfo } from '../../api'; -import { signInMedicalExamCenter, submitTongyishuSign, submitDaojiandanSign, editDaojiandanPrintStatus, submitAddItemBillSign, getTijianPdfFile, getTongyishuPdf, getDaojiandanPdf } from '../../api'; +import type { OutputTongyishuFileInfo, OutputTijianPdfFileInfo, OutputPhysicalExamItemInfo } from '../../api'; +import { signInMedicalExamCenter, submitTongyishuSign, submitDaojiandanSign, editDaojiandanPrintStatus, submitAddItemBillSign, getTijianPdfFile, getTongyishuPdf, getDaojiandanPdf, getExamOptionalItemList, removeOptionalPackage } from '../../api'; import type { SignaturePadHandle } from '../ui'; import { Button, SignaturePad } from '../ui'; @@ -81,8 +81,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => { const [batchPrintLoading, setBatchPrintLoading] = useState(false); const addItemBillCanvasContainerRef = useRef(null); + // 可选项目列表相关状态 + const [optionalItemList, setOptionalItemList] = useState([]); + const [optionalItemLoading, setOptionalItemLoading] = useState(false); + const [selectedOptionalItem, setSelectedOptionalItem] = useState(null); + const busy = - signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading || batchPrintLoading; + signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading || batchPrintLoading || optionalItemLoading; useEffect(() => { onBusyChange?.(busy); @@ -194,8 +199,24 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => { } }; + // 加载可选项目列表 + const loadOptionalItems = async () => { + if (!examId) return; + setOptionalItemLoading(true); + try { + const res = await getExamOptionalItemList({ physical_exam_id: examId }); + if (res.Status === 200 && res.Data?.listOptionalItem) { + setOptionalItemList(res.Data.listOptionalItem); + } + } catch (err) { + console.error('获取可选项目列表失败', err); + } finally { + setOptionalItemLoading(false); + } + }; + // 先加载知情同意书和导检单,然后刷新所有PDF状态(包括签名状态) - Promise.all([loadTongyishu(), loadDaojiandan()]).then(() => { + Promise.all([loadTongyishu(), loadDaojiandan(), loadOptionalItems()]).then(() => { refreshTijianPdfs(examId); }); }, [examId]); @@ -268,6 +289,36 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => { setMessage('请先上传身份证照片'); return; } + if (!examId) { + setMessage('缺少体检ID'); + return; + } + + // 如果有可选项目,先移除未选中的项目 + if (optionalItemList.length > 0 && selectedOptionalItem != null) { + const unselectedCodes = optionalItemList + .map((item) => item.combination_code) + .filter((code): code is number => code != null && code !== selectedOptionalItem); + + if (unselectedCodes.length > 0) { + try { + const combinationCodeIds = unselectedCodes.join(','); + const removeRes = await removeOptionalPackage({ + physical_exam_id: examId, + combination_code_ids: combinationCodeIds, + }); + if (removeRes.Status !== 200 || removeRes.Data?.is_success !== 1) { + setMessage('移除未选项目失败:' + (removeRes.Message || '未知错误')); + return; + } + } catch (err) { + console.error('移除未选项目失败', err); + setMessage('移除未选项目失败,请稍后重试'); + return; + } + } + } + setSignLoading(true); setMessage(null); try { @@ -1620,6 +1671,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => { } }; + return (
@@ -1652,6 +1704,42 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => { {message && (
{message}
)} + {/* 可选项目列表 */} + {optionalItemLoading ? ( +
加载可选项目...
+ ) : optionalItemList.length > 0 ? ( +
+
可选项目(必选其一):
+
+ {optionalItemList.map((item) => { + const combinationCode = item.combination_code; + const isSelected = combinationCode != null && combinationCode === selectedOptionalItem; + return ( + + ); + })} +
+
+ ) : null}
{showImagePreview && previewImage && (
setShowImagePreview(false)}>