导检单和加项单PDF加载状态
This commit is contained in:
@@ -68,6 +68,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
const [daojiandanSubmitLoading, setDaojiandanSubmitLoading] = useState(false);
|
const [daojiandanSubmitLoading, setDaojiandanSubmitLoading] = useState(false);
|
||||||
const [daojiandanSubmitMessage, setDaojiandanSubmitMessage] = useState<string | null>(null);
|
const [daojiandanSubmitMessage, setDaojiandanSubmitMessage] = useState<string | null>(null);
|
||||||
const [showDaojiandanPreview, setShowDaojiandanPreview] = useState(false);
|
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 [addItemBillUrl, setAddItemBillUrl] = useState<string | null>(null);
|
||||||
const [addItemBillName, setAddItemBillName] = useState<string>('加项单');
|
const [addItemBillName, setAddItemBillName] = useState<string>('加项单');
|
||||||
@@ -77,6 +82,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
const addItemBillSignaturePadRef = useRef<SignaturePadHandle | null>(null);
|
const addItemBillSignaturePadRef = useRef<SignaturePadHandle | null>(null);
|
||||||
const [addItemBillSubmitLoading, setAddItemBillSubmitLoading] = useState(false);
|
const [addItemBillSubmitLoading, setAddItemBillSubmitLoading] = useState(false);
|
||||||
const [addItemBillSubmitMessage, setAddItemBillSubmitMessage] = useState<string | null>(null);
|
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;
|
const busy = signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading;
|
||||||
|
|
||||||
@@ -453,6 +463,314 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
renderAllPages();
|
renderAllPages();
|
||||||
}, [pdfData]);
|
}, [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 = () => {
|
const handlePrint = () => {
|
||||||
if (!pdfBlobUrl || !pdfReady || !canvasContainerRef.current) return;
|
if (!pdfBlobUrl || !pdfReady || !canvasContainerRef.current) return;
|
||||||
|
|
||||||
@@ -1574,13 +1892,19 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-1 bg-gray-100 overflow-auto'>
|
<div className='flex-1 bg-gray-100 overflow-auto'>
|
||||||
<div className='flex justify-center p-4'>
|
{daojiandanPdfLoading ? (
|
||||||
<iframe
|
<div className='flex items-center justify-center h-full text-white'>
|
||||||
src={daojiandanUrl}
|
<div>正在加载PDF...</div>
|
||||||
className='w-full h-full min-h-[600px] border rounded-lg bg-white'
|
|
||||||
title='导检单预览'
|
|
||||||
/>
|
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -1670,13 +1994,19 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-1 bg-gray-100 overflow-auto'>
|
<div className='flex-1 bg-gray-100 overflow-auto'>
|
||||||
<div className='flex justify-center p-4'>
|
{addItemBillPdfLoading ? (
|
||||||
<iframe
|
<div className='flex items-center justify-center h-full text-white'>
|
||||||
src={addItemBillUrl}
|
<div>正在加载PDF...</div>
|
||||||
className='w-full h-full min-h-[600px] border rounded-lg bg-white'
|
|
||||||
title='加项单预览'
|
|
||||||
/>
|
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user