完善签到可选项

This commit is contained in:
xianyi
2026-01-14 11:21:22 +08:00
parent 33d44c9728
commit d5a1892a59

View File

@@ -2,8 +2,8 @@ import { useEffect, useRef, useState } from 'react';
import * as pdfjsLib from 'pdfjs-dist'; import * as pdfjsLib from 'pdfjs-dist';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url'; import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url';
import type { OutputTongyishuFileInfo, OutputTijianPdfFileInfo } from '../../api'; import type { OutputTongyishuFileInfo, OutputTijianPdfFileInfo, OutputPhysicalExamItemInfo } from '../../api';
import { signInMedicalExamCenter, submitTongyishuSign, submitDaojiandanSign, editDaojiandanPrintStatus, submitAddItemBillSign, getTijianPdfFile, getTongyishuPdf, getDaojiandanPdf } from '../../api'; import { signInMedicalExamCenter, submitTongyishuSign, submitDaojiandanSign, editDaojiandanPrintStatus, submitAddItemBillSign, getTijianPdfFile, getTongyishuPdf, getDaojiandanPdf, getExamOptionalItemList, removeOptionalPackage } from '../../api';
import type { SignaturePadHandle } from '../ui'; import type { SignaturePadHandle } from '../ui';
import { Button, SignaturePad } from '../ui'; import { Button, SignaturePad } from '../ui';
@@ -81,8 +81,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const [batchPrintLoading, setBatchPrintLoading] = useState(false); const [batchPrintLoading, setBatchPrintLoading] = useState(false);
const addItemBillCanvasContainerRef = useRef<HTMLDivElement>(null); const addItemBillCanvasContainerRef = useRef<HTMLDivElement>(null);
// 可选项目列表相关状态
const [optionalItemList, setOptionalItemList] = useState<OutputPhysicalExamItemInfo[]>([]);
const [optionalItemLoading, setOptionalItemLoading] = useState(false);
const [selectedOptionalItem, setSelectedOptionalItem] = useState<number | null>(null);
const busy = const busy =
signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading || batchPrintLoading; signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading || batchPrintLoading || optionalItemLoading;
useEffect(() => { useEffect(() => {
onBusyChange?.(busy); 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状态包括签名状态 // 先加载知情同意书和导检单然后刷新所有PDF状态包括签名状态
Promise.all([loadTongyishu(), loadDaojiandan()]).then(() => { Promise.all([loadTongyishu(), loadDaojiandan(), loadOptionalItems()]).then(() => {
refreshTijianPdfs(examId); refreshTijianPdfs(examId);
}); });
}, [examId]); }, [examId]);
@@ -268,6 +289,36 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
setMessage('请先上传身份证照片'); setMessage('请先上传身份证照片');
return; 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); setSignLoading(true);
setMessage(null); setMessage(null);
try { try {
@@ -1620,6 +1671,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
} }
}; };
return ( return (
<div className='grid grid-cols-2 gap-4 text-sm'> <div className='grid grid-cols-2 gap-4 text-sm'>
<div className='p-4 rounded-2xl border bg-gray-50/60 flex flex-col gap-3'> <div className='p-4 rounded-2xl border bg-gray-50/60 flex flex-col gap-3'>
@@ -1652,6 +1704,42 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
{message && ( {message && (
<div className={`text-xs ${message.includes('成功') ? 'text-green-600' : 'text-amber-600'}`}>{message}</div> <div className={`text-xs ${message.includes('成功') ? 'text-green-600' : 'text-amber-600'}`}>{message}</div>
)} )}
{/* 可选项目列表 */}
{optionalItemLoading ? (
<div className='text-xs text-gray-500'>...</div>
) : optionalItemList.length > 0 ? (
<div className='mt-2 space-y-2'>
<div className='text-xs font-medium text-gray-700'></div>
<div className='max-h-32 overflow-y-auto custom-scroll space-y-1'>
{optionalItemList.map((item) => {
const combinationCode = item.combination_code;
const isSelected = combinationCode != null && combinationCode === selectedOptionalItem;
return (
<label
key={combinationCode ?? `item-${item.package_code}`}
className='flex items-center gap-2 cursor-pointer text-xs'
>
<input
type='radio'
name='optional-item'
checked={isSelected}
onChange={() => {
if (combinationCode != null) {
setSelectedOptionalItem(combinationCode);
}
}}
disabled={busy}
className='w-3 h-3'
/>
<span className={isSelected ? 'text-blue-600 font-medium' : 'text-gray-700'}>
{item.combination_name || '未命名项目'}
</span>
</label>
);
})}
</div>
</div>
) : null}
</div> </div>
{showImagePreview && previewImage && ( {showImagePreview && previewImage && (
<div className='fixed inset-0 z-[80] bg-black/90 flex items-center justify-center p-6' onClick={() => setShowImagePreview(false)}> <div className='fixed inset-0 z-[80] bg-black/90 flex items-center justify-center p-6' onClick={() => setShowImagePreview(false)}>