完善加项支付

This commit is contained in:
xianyi
2026-01-04 15:54:26 +08:00
parent f7ea59a857
commit f6cc55582e
5 changed files with 642 additions and 41 deletions

View File

@@ -10,6 +10,7 @@ import {
getTongyishuPdfList,
setDaojiandanPdf,
getDaojiandanPdf as getDaojiandanPdfFromStorage,
getAddItemBillPdf as getAddItemBillPdfFromStorage,
type TongyishuPdfInfo,
} from '../../utils/examActions';
import type { SignaturePadHandle } from '../ui';
@@ -65,6 +66,10 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const [daojiandanSubmitLoading, setDaojiandanSubmitLoading] = useState(false);
const [daojiandanSubmitMessage, setDaojiandanSubmitMessage] = useState<string | null>(null);
const [showDaojiandanPreview, setShowDaojiandanPreview] = useState(false);
// 加项单相关状态
const [addItemBillUrl, setAddItemBillUrl] = useState<string | null>(null);
const [addItemBillName, setAddItemBillName] = useState<string>('加项单');
const [showAddItemBillPreview, setShowAddItemBillPreview] = useState(false);
const busy = signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading;
@@ -301,6 +306,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
if (storedPdf && storedPdf.pdf_url) {
setDaojiandanUrl(storedPdf.pdf_url);
}
// 检查加项单PDF
const storedAddItemBill = getAddItemBillPdfFromStorage(examId);
if (storedAddItemBill && storedAddItemBill.pdf_url) {
setAddItemBillUrl(storedAddItemBill.pdf_url);
setAddItemBillName(storedAddItemBill.pdf_name || '加项单');
}
}, [examId]);
// 加载 PDF 数据
@@ -621,6 +633,100 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
}
};
// 加项单直接打印
const handleAddItemBillDirectPrint = async () => {
if (!addItemBillUrl) return;
try {
const response = await fetch(addItemBillUrl);
if (!response.ok) throw new Error('获取PDF文件失败');
const blob = await response.blob();
const arrayBuffer = await blob.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
const scale = 1.2;
const canvasImages: string[] = [];
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
const page = await pdf.getPage(pageNum);
const viewport = page.getViewport({ scale });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
if (!context) continue;
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = {
canvasContext: context,
viewport: viewport,
} as any;
await page.render(renderContext).promise;
canvasImages.push(canvas.toDataURL('image/png'));
}
const printWindow = window.open('', '_blank');
if (!printWindow) return;
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<title>加项单打印</title>
<style>
@media print {
body {
margin: 0;
padding: 0;
}
img {
max-width: 100%;
page-break-after: always;
page-break-inside: avoid;
}
img:last-child {
page-break-after: auto;
}
}
body {
margin: 0;
padding: 0;
}
img {
display: block;
width: 100%;
height: auto;
}
</style>
</head>
<body>
`);
canvasImages.forEach((imgData) => {
printWindow.document.write(`<img src="${imgData}" />`);
});
printWindow.document.write(`
</body>
</html>
`);
printWindow.document.close();
printWindow.onload = () => {
printWindow.focus();
setTimeout(() => {
printWindow.print();
}, 1000);
};
} catch (err) {
console.error('打印失败', err);
alert('打印失败,请稍后重试');
}
};
// 导检单直接打印
const handleDaojiandanDirectPrint = async () => {
if (!daojiandanUrl) return;
@@ -1108,6 +1214,42 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
)}
</div>
</div>
{/* 加项单 */}
{addItemBillUrl && (
<div className='flex items-center justify-between gap-3 p-2 rounded-xl border bg-white shadow-sm'>
<div className='text-sm text-gray-800 truncate flex items-center gap-2 relative pr-20'>
<span className='truncate'>{addItemBillName.length > 12 ? addItemBillName.slice(0, 12) + "..." : addItemBillName}</span>
<img
src='/sign.png'
alt='已生成'
className='w-16 h-16 absolute right-2 top-1/2 -translate-y-1/2 pointer-events-none select-none'
loading='lazy'
/>
</div>
<div className='flex items-center gap-2'>
<Button
className='py-1.5 px-3 bg-blue-600 hover:bg-blue-700 text-white'
onClick={() => {
if (busy) return;
handleAddItemBillDirectPrint();
}}
disabled={busy}
>
</Button>
<Button
className='py-1.5 px-3'
onClick={() => {
if (busy) return;
setShowAddItemBillPreview(true);
}}
disabled={busy}
>
</Button>
</div>
</div>
)}
</div>
)}
</div>
@@ -1283,6 +1425,36 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
</div>
)
}
{
showAddItemBillPreview && addItemBillUrl && (
<div className='fixed inset-0 z-[60] bg-black/75 flex flex-col'>
<div className='flex items-center justify-between p-4 text-white bg-gray-900/80'>
<div className='text-sm font-medium truncate pr-3'>{addItemBillName}</div>
<div className='flex items-center gap-2'>
<Button
className='py-1 px-3 bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50 disabled:cursor-not-allowed'
onClick={handleAddItemBillDirectPrint}
disabled={busy}
>
</Button>
<Button className='py-1 px-3' onClick={() => !busy && setShowAddItemBillPreview(false)} disabled={busy}>
</Button>
</div>
</div>
<div className='flex-1 bg-gray-100 overflow-auto'>
<div className='flex justify-center p-4'>
<iframe
src={addItemBillUrl}
className='w-full h-full min-h-[600px] border rounded-lg bg-white'
title='加项单预览'
/>
</div>
</div>
</div>
)
}
</div >
);
};