完善加项支付
This commit is contained in:
@@ -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 >
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user