完善导检单预览

This commit is contained in:
xianyi
2025-12-25 17:27:01 +08:00
parent b552ff4963
commit 44e3926e14
5 changed files with 230 additions and 16 deletions

View File

@@ -1,8 +1,8 @@
import { useEffect, useRef, useState } from 'react';
import { submitDaojiandanSign } from '../../api';
import { getDaojiandanPdf as getDaojiandanPdfApi, submitDaojiandanSign } from '../../api';
import type { ExamClient } from '../../data/mockData';
import { setExamActionRecord } from '../../utils/examActions';
import { setExamActionRecord, setDaojiandanPdf, getDaojiandanPdf } from '../../utils/examActions';
import type { SignaturePadHandle } from '../ui';
import { Button, SignaturePad } from '../ui';
@@ -15,6 +15,8 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
const [signatureSubmitted, setSignatureSubmitted] = useState(false);
const [submitLoading, setSubmitLoading] = useState(false);
const [submitMessage, setSubmitMessage] = useState<string | null>(null);
const [showPreview, setShowPreview] = useState(false);
const [fetchLoading, setFetchLoading] = useState(false);
const signaturePadRef = useRef<SignaturePadHandle | null>(null);
const printRef = useRef<HTMLDivElement>(null);
const iframeRef = useRef<HTMLIFrameElement>(null);
@@ -47,7 +49,14 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
if (res.Status === 200 && res.Data?.pdf_url) {
setSubmitMessage('签名提交成功,正在加载导检单...');
setSignatureSubmitted(true);
setPdfUrl(res.Data.pdf_url);
const pdfUrlValue = res.Data.pdf_url;
const pdfNameValue = res.Data.pdf_name || '导检单';
setPdfUrl(pdfUrlValue);
// 保存导检单PDF信息到localStorage
setDaojiandanPdf(examId, {
pdf_name: pdfNameValue,
pdf_url: pdfUrlValue,
});
// 记录打印导检单是否签名操作
setExamActionRecord(examId, 'printSign', true);
} else {
@@ -61,6 +70,62 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
}
};
// 组件加载时检查localStorage如果有则直接展示
useEffect(() => {
const examId = Number(client.id);
if (!examId) return;
const storedPdf = getDaojiandanPdf(examId);
if (storedPdf && storedPdf.pdf_url) {
setPdfUrl(storedPdf.pdf_url);
setShowPreview(true);
}
}, [client.id]);
// 获取导检单PDF优先使用localStorage没有则调用接口
const handleFetchPdf = async () => {
const examId = Number(client.id);
if (!examId) {
setError('无效的体检ID');
return;
}
setFetchLoading(true);
setError(null);
try {
// 先尝试从localStorage获取
const storedPdf = getDaojiandanPdf(examId);
if (storedPdf && storedPdf.pdf_url) {
setPdfUrl(storedPdf.pdf_url);
setShowPreview(true);
setFetchLoading(false);
return;
}
// 如果没有存储的,则调用接口获取
const res = await getDaojiandanPdfApi({ exam_id: examId });
if (res.Status === 200 && res.Data?.pdf_url) {
const pdfUrlValue = res.Data.pdf_url;
const pdfNameValue = res.Data.pdf_name || '导检单';
setPdfUrl(pdfUrlValue);
// 保存到localStorage
setDaojiandanPdf(examId, {
pdf_name: pdfNameValue,
pdf_url: pdfUrlValue,
});
setShowPreview(true);
} else {
setError(res.Message || '获取导检单失败');
}
} catch (err) {
console.error('获取导检单失败', err);
setError('获取导检单失败,请稍后重试');
} finally {
setFetchLoading(false);
}
};
useEffect(() => {
if (!pdfUrl) return;
@@ -110,7 +175,7 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
<div>
<div className='text-sm font-semibold'> · </div>
<div className='text-[11px] text-gray-500 mt-1'>
{signatureSubmitted
{signatureSubmitted || showPreview
? '此为预览页面,实际打印效果以院内打印机为准。'
: '请先完成签名签名后将生成导检单PDF'}
</div>
@@ -120,6 +185,38 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
<div>{client.id}</div>
<div>{new Date().toLocaleDateString('zh-CN')}</div>
</div>
{!showPreview && !signatureSubmitted && (
<Button
className='px-4 py-1.5 text-xs bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50 disabled:cursor-not-allowed'
onClick={handleFetchPdf}
disabled={fetchLoading}
>
{fetchLoading ? '加载中...' : '查看'}
</Button>
)}
{showPreview && !signatureSubmitted && (
<>
<Button
className='px-4 py-1.5 text-xs bg-gray-600 hover:bg-gray-700 text-white'
onClick={() => {
setShowPreview(false);
setPdfUrl(null);
setPdfBlobUrl(null);
setPdfReady(false);
setError(null);
}}
>
</Button>
<Button
className='px-4 py-1.5 text-xs bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50 disabled:cursor-not-allowed'
onClick={handlePrint}
disabled={loading || !pdfReady || !pdfUrl}
>
</Button>
</>
)}
{signatureSubmitted && (
<Button
className='px-4 py-1.5 text-xs bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50 disabled:cursor-not-allowed'
@@ -132,7 +229,7 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
</div>
</div>
{!signatureSubmitted ? (
{!signatureSubmitted && !showPreview ? (
<div className='flex flex-col gap-4'>
<div className='text-sm font-medium text-gray-900'></div>
<div className='ui7-signature-wrapper border rounded-xl overflow-hidden bg-gray-50'>
@@ -169,6 +266,10 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
</Button>
</div>
</div>
) : fetchLoading ? (
<div className='flex items-center justify-center py-12 text-gray-500'>
<div>...</div>
</div>
) : loading ? (
<div className='flex items-center justify-center py-12 text-gray-500'>
<div>PDF...</div>
@@ -176,17 +277,30 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
) : error ? (
<div className='flex flex-col items-center justify-center py-12 text-gray-500'>
<div className='mb-2'>{error}</div>
<Button
className='px-4 py-1.5 text-xs'
onClick={() => {
setError(null);
setPdfUrl(null);
setSignatureSubmitted(false);
signaturePadRef.current?.clear();
}}
>
</Button>
{signatureSubmitted ? (
<Button
className='px-4 py-1.5 text-xs'
onClick={() => {
setError(null);
setPdfUrl(null);
setSignatureSubmitted(false);
setShowPreview(false);
signaturePadRef.current?.clear();
}}
>
</Button>
) : (
<Button
className='px-4 py-1.5 text-xs'
onClick={() => {
setError(null);
setShowPreview(false);
}}
>
</Button>
)}
</div>
) : pdfUrl ? (
<div className='w-full'>