@@ -83,9 +83,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const [ addItemBillPdfLoading , setAddItemBillPdfLoading ] = useState ( false ) ;
const [ addItemBillPdfLoading , setAddItemBillPdfLoading ] = useState ( false ) ;
const [ addItemBillPdfReady , setAddItemBillPdfReady ] = useState ( false ) ;
const [ addItemBillPdfReady , setAddItemBillPdfReady ] = useState ( false ) ;
const [ addItemBillPdfBlobUrl , setAddItemBillPdfBlobUrl ] = useState < string | null > ( null ) ;
const [ addItemBillPdfBlobUrl , setAddItemBillPdfBlobUrl ] = useState < string | null > ( null ) ;
const [ batchPrintLoading , setBatchPrintLoading ] = useState ( false ) ;
const addItemBillCanvasContainerRef = useRef < HTMLDivElement > ( null ) ;
const addItemBillCanvasContainerRef = useRef < HTMLDivElement > ( null ) ;
const busy = signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading ;
const busy =
signLoading || submitLoading || consentLoading || pdfLoading || daojiandanSubmitLoading || addItemBillSubmitLoading || batchPrintLoading ;
useEffect ( ( ) = > {
useEffect ( ( ) = > {
onBusyChange ? . ( busy ) ;
onBusyChange ? . ( busy ) ;
@@ -135,12 +137,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
setIsDaojiandanSigned ( false ) ;
setIsDaojiandanSigned ( false ) ;
}
}
// 加项单( pdf_type = 3) : 完全由新接口提供列表和签名状态
// 加项单( pdf_type = 3) : 完全由新接口提供列表和签名状态(直接使用接口返回的字段)
const addItemFromApi = list . filter ( ( item ) = > item . pdf_type === 3 ) ;
const addItemFromApi = list . filter ( ( item ) = > item . pdf_type === 3 ) ;
if ( addItemFromApi . length > 0 ) {
if ( addItemFromApi . length > 0 ) {
const addItemList : AddItemBillItem [ ] = addItemFromApi . map ( ( item ) = > ( {
const addItemList : AddItemBillItem [ ] = addItemFromApi . map ( ( item ) = > ( {
pdf_sort : item.combination_code ? ? 0 ,
// 这里直接使用接口返回的 pdf_sort / combination_code / is_pay / is_pay_name
combinationCode : String ( item . combination_code ? ? '' ) ,
pdf_sort : item.pdf_sort ? ? 0 ,
combinationCode : item.combination_code != null ? String ( item . combination_code ) : '' ,
payment_status : item.is_pay != null ? String ( item . is_pay ) : null ,
payment_status : item.is_pay != null ? String ( item . is_pay ) : null ,
payment_status_name : item.is_pay_name ? ? null ,
payment_status_name : item.is_pay_name ? ? null ,
pdf_name : item.pdf_name || '加项单' ,
pdf_name : item.pdf_name || '加项单' ,
@@ -825,7 +828,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
<body>
<body>
<div class="button-container">
<div class="button-container">
<button class="close-button" onclick="window.close()">关闭</button>
<button class="close-button" onclick="window.close()">关闭</button>
<button class="print-button" onclick="window.print()">打印</button>
<button class="print-button" onclick="window.print(); setTimeout(() => window.close(), 1000); ">打印</button>
</div>
</div>
` ) ;
` ) ;
@@ -958,7 +961,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
<body>
<body>
<div class="button-container">
<div class="button-container">
<button class="close-button" onclick="window.close()">关闭</button>
<button class="close-button" onclick="window.close()">关闭</button>
<button class="print-button" onclick="window.print()">打印</button>
<button class="print-button" onclick="window.print(); setTimeout(() => window.close(), 1000); ">打印</button>
</div>
</div>
` ) ;
` ) ;
@@ -1084,8 +1087,9 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const addItemFromApi = list . filter ( ( item ) = > item . pdf_type === 3 ) ;
const addItemFromApi = list . filter ( ( item ) = > item . pdf_type === 3 ) ;
if ( addItemFromApi . length > 0 ) {
if ( addItemFromApi . length > 0 ) {
const addItemList : AddItemBillItem [ ] = addItemFromApi . map ( ( item ) = > ( {
const addItemList : AddItemBillItem [ ] = addItemFromApi . map ( ( item ) = > ( {
pdf_sort : item.combination_code ? ? 0 ,
// 同样直接使用接口返回的字段,保持与 refreshTijianPdfs 一致
combinationCode : String ( item . combination_code ? ? '' ) ,
pdf_sort : item.pdf_sort ? ? 0 ,
combinationCode : item.combination_code != null ? String ( item . combination_code ) : '' ,
payment_status : item.is_pay != null ? String ( item . is_pay ) : null ,
payment_status : item.is_pay != null ? String ( item . is_pay ) : null ,
payment_status_name : item.is_pay_name ? ? null ,
payment_status_name : item.is_pay_name ? ? null ,
pdf_name : item.pdf_name || '加项单' ,
pdf_name : item.pdf_name || '加项单' ,
@@ -1231,7 +1235,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
<body>
<body>
<div class="button-container">
<div class="button-container">
<button class="close-button" onclick="window.close()">关闭</button>
<button class="close-button" onclick="window.close()">关闭</button>
<button class="print-button" onclick="window.print()">打印</button>
<button class="print-button" onclick="window.print(); setTimeout(() => window.close(), 1000); ">打印</button>
</div>
</div>
` ) ;
` ) ;
@@ -1363,7 +1367,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
<body>
<body>
<div class="button-container">
<div class="button-container">
<button class="close-button" onclick="window.close()">关闭</button>
<button class="close-button" onclick="window.close()">关闭</button>
<button class="print-button" onclick="window.print()">打印</button>
<button class="print-button" onclick="window.print(); setTimeout(() => window.close(), 1000); ">打印</button>
</div>
</div>
` ) ;
` ) ;
@@ -1414,8 +1418,9 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
// 一键打印所有文档
// 一键打印所有文档
const handleBatchPrint = async ( ) = > {
const handleBatchPrint = async ( ) = > {
if ( busy ) return ;
if ( busy || batchPrintLoading ) return ;
setBatchPrintLoading ( true ) ;
try {
try {
const allImages : string [ ] = [ ] ;
const allImages : string [ ] = [ ] ;
const scale = 3.0 ;
const scale = 3.0 ;
@@ -1612,7 +1617,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
<body>
<body>
<div class="button-container">
<div class="button-container">
<button class="close-button" onclick="window.close()">关闭</button>
<button class="close-button" onclick="window.close()">关闭</button>
<button class="print-button" onclick="window.print()">打印</button>
<button class="print-button" onclick="window.print(); setTimeout(() => window.close(), 1000); ">打印</button>
</div>
</div>
` ) ;
` ) ;
@@ -1647,6 +1652,8 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
} catch ( err ) {
} catch ( err ) {
console . error ( '一键打印失败' , err ) ;
console . error ( '一键打印失败' , err ) ;
alert ( '一键打印失败,请稍后重试' ) ;
alert ( '一键打印失败,请稍后重试' ) ;
} finally {
setBatchPrintLoading ( false ) ;
}
}
} ;
} ;
@@ -1700,9 +1707,9 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
< Button
< Button
className = 'py-1 px-3 bg-green-600 hover:bg-green-700 text-white text-xs'
className = 'py-1 px-3 bg-green-600 hover:bg-green-700 text-white text-xs'
onClick = { handleBatchPrint }
onClick = { handleBatchPrint }
disabled = { busy }
disabled = { busy || batchPrintLoading }
>
>
一 键 打 印
{ batchPrintLoading ? '加载中...' : '一键打印' }
< / Button >
< / Button >
) }
) }
< / div >
< / div >
@@ -1718,7 +1725,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
className = 'flex items-center justify-between gap-3 p-2 rounded-xl border bg-white shadow-sm'
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' >
< div className = 'text-sm text-gray-800 truncate flex items-center gap-2 relative pr-20' >
< span className = 'truncate' > { item . pdf_name . length > 12 ? item . pdf_name . slice ( 0 , 12 ) + "..." : item . pdf_name } < / span >
< span className = 'truncate' > { item . pdf_name . length > 10 ? item . pdf_name . slice ( 0 , 10 ) + "..." : item . pdf_name } < / span >
{ item . combination_code !== undefined && signedCombinationCodes . includes ( Number ( item . combination_code ) ) && (
{ item . combination_code !== undefined && signedCombinationCodes . includes ( Number ( item . combination_code ) ) && (
< img
< img
src = '/sign.png'
src = '/sign.png'
@@ -1845,7 +1852,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
< div className = 'text-sm text-gray-800 truncate flex items-center gap-2 relative pr-20' >
< div className = 'text-sm text-gray-800 truncate flex items-center gap-2 relative pr-20' >
< span className = 'truncate' >
< span className = 'truncate' >
{ displayName }
{ displayName }
{ typeof bill . pdf_sort === 'number' ? ` ( #${ bill . pdf_sort } ) ` : '' }
{ typeof bill . pdf_sort === 'number' ? ` ` : '' }
< / span >
< / span >
{ bill . payment_status_name && (
{ bill . payment_status_name && (
< span className = 'text-xs text-gray-500 whitespace-nowrap' > { bill . payment_status_name } < / span >
< span className = 'text-xs text-gray-500 whitespace-nowrap' > { bill . payment_status_name } < / span >