导检单和加项单PDF加载状态

This commit is contained in:
xianyi
2026-01-06 10:00:03 +08:00
parent 166db349ff
commit 6a6e7dd83d

View File

@@ -68,6 +68,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const [daojiandanSubmitLoading, setDaojiandanSubmitLoading] = useState(false);
const [daojiandanSubmitMessage, setDaojiandanSubmitMessage] = useState<string | null>(null);
const [showDaojiandanPreview, setShowDaojiandanPreview] = useState(false);
const [daojiandanPdfData, setDaojiandanPdfData] = useState<ArrayBuffer | null>(null);
const [daojiandanPdfLoading, setDaojiandanPdfLoading] = useState(false);
const [daojiandanPdfReady, setDaojiandanPdfReady] = useState(false);
const [daojiandanPdfBlobUrl, setDaojiandanPdfBlobUrl] = useState<string | null>(null);
const daojiandanCanvasContainerRef = useRef<HTMLDivElement>(null);
// 加项单相关状态
const [addItemBillUrl, setAddItemBillUrl] = useState<string | null>(null);
const [addItemBillName, setAddItemBillName] = useState<string>('加项单');
@@ -77,6 +82,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const addItemBillSignaturePadRef = useRef<SignaturePadHandle | null>(null);
const [addItemBillSubmitLoading, setAddItemBillSubmitLoading] = useState(false);
const [addItemBillSubmitMessage, setAddItemBillSubmitMessage] = useState<string | null>(null);
const [addItemBillPdfData, setAddItemBillPdfData] = useState<ArrayBuffer | null>(null);
const [addItemBillPdfLoading, setAddItemBillPdfLoading] = useState(false);
const [addItemBillPdfReady, setAddItemBillPdfReady] = useState(false);
const [addItemBillPdfBlobUrl, setAddItemBillPdfBlobUrl] = useState<string | null>(null);
const addItemBillCanvasContainerRef = useRef<HTMLDivElement>(null);
const busy = signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading;
@@ -453,6 +463,314 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
renderAllPages();
}, [pdfData]);
// 加载导检单 PDF 数据
useEffect(() => {
if (!showDaojiandanPreview || !daojiandanUrl) {
setDaojiandanPdfData(null);
setDaojiandanPdfBlobUrl(null);
setDaojiandanPdfReady(false);
return;
}
let objectUrl: string | null = null;
setDaojiandanPdfReady(false);
setDaojiandanPdfLoading(true);
setDaojiandanPdfData(null);
fetch(daojiandanUrl)
.then((resp) => {
if (!resp.ok) throw new Error('获取PDF文件失败');
return resp.blob();
})
.then((blob) => {
objectUrl = URL.createObjectURL(blob);
setDaojiandanPdfBlobUrl(objectUrl);
return blob.arrayBuffer();
})
.then((arrayBuffer) => {
setDaojiandanPdfData(arrayBuffer);
setDaojiandanPdfLoading(false);
})
.catch((err) => {
console.error('导检单PDF 拉取失败', err);
setDaojiandanPdfLoading(false);
});
return () => {
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
}
};
}, [showDaojiandanPreview, daojiandanUrl]);
// 渲染导检单 PDF
useEffect(() => {
if (!daojiandanPdfData || !daojiandanCanvasContainerRef.current) return;
setDaojiandanPdfReady(false);
const renderAllPages = async () => {
try {
const pdf = await pdfjsLib.getDocument({ data: daojiandanPdfData }).promise;
if (!daojiandanCanvasContainerRef.current) return;
// 清空容器
daojiandanCanvasContainerRef.current.innerHTML = '';
const scale = 1.2;
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;
canvas.style.display = 'block';
canvas.style.marginBottom = '10px';
canvas.className = 'mx-auto border rounded-lg shadow-sm';
daojiandanCanvasContainerRef.current.appendChild(canvas);
const renderContext = {
canvasContext: context,
viewport: viewport,
} as any;
await page.render(renderContext).promise;
}
setDaojiandanPdfReady(true);
} catch (err) {
console.error('导检单PDF 渲染失败', err);
setDaojiandanPdfLoading(false);
}
};
renderAllPages();
}, [daojiandanPdfData]);
// 加载加项单 PDF 数据
useEffect(() => {
if (!showAddItemBillPreview || !addItemBillUrl) {
setAddItemBillPdfData(null);
setAddItemBillPdfBlobUrl(null);
setAddItemBillPdfReady(false);
return;
}
let objectUrl: string | null = null;
setAddItemBillPdfReady(false);
setAddItemBillPdfLoading(true);
setAddItemBillPdfData(null);
fetch(addItemBillUrl)
.then((resp) => {
if (!resp.ok) throw new Error('获取PDF文件失败');
return resp.blob();
})
.then((blob) => {
objectUrl = URL.createObjectURL(blob);
setAddItemBillPdfBlobUrl(objectUrl);
return blob.arrayBuffer();
})
.then((arrayBuffer) => {
setAddItemBillPdfData(arrayBuffer);
setAddItemBillPdfLoading(false);
})
.catch((err) => {
console.error('加项单PDF 拉取失败', err);
setAddItemBillPdfLoading(false);
});
return () => {
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
}
};
}, [showAddItemBillPreview, addItemBillUrl]);
// 渲染加项单 PDF
useEffect(() => {
if (!addItemBillPdfData || !addItemBillCanvasContainerRef.current) return;
setAddItemBillPdfReady(false);
const renderAllPages = async () => {
try {
const pdf = await pdfjsLib.getDocument({ data: addItemBillPdfData }).promise;
if (!addItemBillCanvasContainerRef.current) return;
// 清空容器
addItemBillCanvasContainerRef.current.innerHTML = '';
const scale = 1.2;
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;
canvas.style.display = 'block';
canvas.style.marginBottom = '10px';
canvas.className = 'mx-auto border rounded-lg shadow-sm';
addItemBillCanvasContainerRef.current.appendChild(canvas);
const renderContext = {
canvasContext: context,
viewport: viewport,
} as any;
await page.render(renderContext).promise;
}
setAddItemBillPdfReady(true);
} catch (err) {
console.error('加项单PDF 渲染失败', err);
setAddItemBillPdfLoading(false);
}
};
renderAllPages();
}, [addItemBillPdfData]);
// 导检单预览:使用 pdfjs 渲染到 canvas
useEffect(() => {
if (!showDaojiandanPreview || !daojiandanUrl || !daojiandanCanvasContainerRef.current) return;
const container = daojiandanCanvasContainerRef.current;
let cancelled = false;
const renderDaojiandan = async () => {
try {
setDaojiandanPdfLoading(true);
container.innerHTML = '';
const resp = await fetch(daojiandanUrl);
if (!resp.ok) throw new Error('获取PDF文件失败');
const blob = await resp.blob();
const arrayBuffer = await blob.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
const scale = 1.2;
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
if (cancelled) return;
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;
canvas.style.display = 'block';
canvas.style.marginBottom = '10px';
canvas.className = 'mx-auto border rounded-lg shadow-sm';
container.appendChild(canvas);
const renderContext = {
canvasContext: context,
viewport: viewport,
} as any;
await page.render(renderContext).promise;
}
} catch (err) {
console.error('导检单PDF 渲染失败', err);
} finally {
if (!cancelled) {
setDaojiandanPdfLoading(false);
}
}
};
renderDaojiandan();
return () => {
cancelled = true;
container.innerHTML = '';
};
}, [showDaojiandanPreview, daojiandanUrl]);
// 加项单预览:使用 pdfjs 渲染到 canvas
useEffect(() => {
if (!showAddItemBillPreview || !addItemBillUrl || !addItemBillCanvasContainerRef.current) return;
const container = addItemBillCanvasContainerRef.current;
let cancelled = false;
const renderAddItemBill = async () => {
try {
setAddItemBillPdfLoading(true);
container.innerHTML = '';
const resp = await fetch(addItemBillUrl);
if (!resp.ok) throw new Error('获取PDF文件失败');
const blob = await resp.blob();
const arrayBuffer = await blob.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
const scale = 1.2;
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
if (cancelled) return;
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;
canvas.style.display = 'block';
canvas.style.marginBottom = '10px';
canvas.className = 'mx-auto border rounded-lg shadow-sm';
container.appendChild(canvas);
const renderContext = {
canvasContext: context,
viewport: viewport,
} as any;
await page.render(renderContext).promise;
}
} catch (err) {
console.error('加项单PDF 渲染失败', err);
} finally {
if (!cancelled) {
setAddItemBillPdfLoading(false);
}
}
};
renderAddItemBill();
return () => {
cancelled = true;
container.innerHTML = '';
};
}, [showAddItemBillPreview, addItemBillUrl]);
const handlePrint = () => {
if (!pdfBlobUrl || !pdfReady || !canvasContainerRef.current) return;
@@ -1574,13 +1892,19 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
</div>
</div>
<div className='flex-1 bg-gray-100 overflow-auto'>
<div className='flex justify-center p-4'>
<iframe
src={daojiandanUrl}
className='w-full h-full min-h-[600px] border rounded-lg bg-white'
title='导检单预览'
/>
</div>
{daojiandanPdfLoading ? (
<div className='flex items-center justify-center h-full text-white'>
<div>PDF...</div>
</div>
) : daojiandanPdfData ? (
<div className='flex justify-center p-4'>
<div ref={daojiandanCanvasContainerRef} className='w-full' />
</div>
) : (
<div className='flex items-center justify-center h-full text-white'>
<div>PDF加载失败</div>
</div>
)}
</div>
</div>
)
@@ -1670,13 +1994,19 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
</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>
{addItemBillPdfLoading ? (
<div className='flex items-center justify-center h-full text-white'>
<div>PDF...</div>
</div>
) : addItemBillPdfData ? (
<div className='flex justify-center p-4'>
<div ref={addItemBillCanvasContainerRef} className='w-full' />
</div>
) : (
<div className='flex items-center justify-center h-full text-white'>
<div>PDF加载失败</div>
</div>
)}
</div>
</div>
)