完善打印
This commit is contained in:
@@ -356,17 +356,22 @@ export const ExamAddonPanel = ({ client }: ExamAddonPanelProps) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 获取加项PDF
|
// 获取加项PDF(按本次支付的组合代码生成对应的加项单)
|
||||||
const fetchAddItemBillPdf = async (examId: number) => {
|
const fetchAddItemBillPdf = async (examId: number, combinationItemCodes: string) => {
|
||||||
try {
|
try {
|
||||||
// 调用接口获取加项PDF
|
// 调用接口获取加项PDF
|
||||||
const res = await getAddItemBillPdf({
|
const res = await getAddItemBillPdf({
|
||||||
exam_id: examId,
|
exam_id: examId,
|
||||||
|
CombinationCode: combinationItemCodes,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.Status === 200 && res.Data?.pdf_url) {
|
if (res.Status === 200 && res.Data?.pdf_url && res.Data?.pdf_sort !== undefined && res.Data?.pdf_sort !== null) {
|
||||||
// 保存加项PDF信息到localStorage(未签名状态)
|
// 保存加项PDF信息到localStorage(未签名状态)
|
||||||
setAddItemBillPdf(examId, {
|
setAddItemBillPdf(examId, {
|
||||||
|
pdf_sort: res.Data.pdf_sort,
|
||||||
|
combinationCode: combinationItemCodes,
|
||||||
|
payment_status: res.Data.payment_status ?? null,
|
||||||
|
payment_status_name: res.Data.payment_status_name ?? null,
|
||||||
pdf_name: res.Data.pdf_name || '加项单',
|
pdf_name: res.Data.pdf_name || '加项单',
|
||||||
pdf_url: res.Data.pdf_url,
|
pdf_url: res.Data.pdf_url,
|
||||||
is_signed: false,
|
is_signed: false,
|
||||||
@@ -392,7 +397,8 @@ export const ExamAddonPanel = ({ client }: ExamAddonPanelProps) => {
|
|||||||
discount_rate: number;
|
discount_rate: number;
|
||||||
}>,
|
}>,
|
||||||
pay_type: number,
|
pay_type: number,
|
||||||
company_id: number
|
company_id: number,
|
||||||
|
combinationItemCodes: string
|
||||||
) => {
|
) => {
|
||||||
if (pollingTimerRef.current) {
|
if (pollingTimerRef.current) {
|
||||||
clearInterval(pollingTimerRef.current);
|
clearInterval(pollingTimerRef.current);
|
||||||
@@ -424,8 +430,8 @@ export const ExamAddonPanel = ({ client }: ExamAddonPanelProps) => {
|
|||||||
setQrcodeUrl(null);
|
setQrcodeUrl(null);
|
||||||
// 清空已选项目
|
// 清空已选项目
|
||||||
setSelectedIds(new Set());
|
setSelectedIds(new Set());
|
||||||
// 获取加项PDF
|
// 获取本次支付对应的加项PDF
|
||||||
fetchAddItemBillPdf(physical_exam_id).then((success) => {
|
fetchAddItemBillPdf(physical_exam_id, combinationItemCodes).then((success) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
setPaymentMessage('支付成功,加项单已生成');
|
setPaymentMessage('支付成功,加项单已生成');
|
||||||
} else {
|
} else {
|
||||||
@@ -497,7 +503,7 @@ export const ExamAddonPanel = ({ client }: ExamAddonPanelProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取组合项目代码(用于生成二维码接口,多个加项逗号分隔)
|
// 获取组合项目代码(用于生成二维码接口 & 生成加项单,多个加项逗号分隔)
|
||||||
const combinationItemCodes = listAddItemCombination
|
const combinationItemCodes = listAddItemCombination
|
||||||
.map((item) => item.combination_item_code)
|
.map((item) => item.combination_item_code)
|
||||||
.join(',');
|
.join(',');
|
||||||
@@ -534,7 +540,8 @@ export const ExamAddonPanel = ({ client }: ExamAddonPanelProps) => {
|
|||||||
patient_id,
|
patient_id,
|
||||||
listAddItemCombination,
|
listAddItemCombination,
|
||||||
12, // 微信支付
|
12, // 微信支付
|
||||||
0 // 自费模式,company_id 传 0
|
0, // 自费模式,company_id 传 0
|
||||||
|
combinationItemCodes
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setPaymentMessage(res.Message || '生成支付二维码失败');
|
setPaymentMessage(res.Message || '生成支付二维码失败');
|
||||||
@@ -564,8 +571,8 @@ export const ExamAddonPanel = ({ client }: ExamAddonPanelProps) => {
|
|||||||
if (result === 'success' || result === '1' || result === 'SUCCESS') {
|
if (result === 'success' || result === '1' || result === 'SUCCESS') {
|
||||||
setPaymentMessage('挂账成功,正在生成加项单...');
|
setPaymentMessage('挂账成功,正在生成加项单...');
|
||||||
setSelectedIds(new Set());
|
setSelectedIds(new Set());
|
||||||
// 获取加项PDF
|
// 获取本次挂账对应的加项PDF
|
||||||
fetchAddItemBillPdf(physical_exam_id).then((success) => {
|
fetchAddItemBillPdf(physical_exam_id, combinationItemCodes).then((success) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
setPaymentMessage('挂账成功,加项单已生成');
|
setPaymentMessage('挂账成功,加项单已生成');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
setAddItemBillPdf,
|
setAddItemBillPdf,
|
||||||
getAddItemBillPdf as getAddItemBillPdfFromStorage,
|
getAddItemBillPdf as getAddItemBillPdfFromStorage,
|
||||||
type TongyishuPdfInfo,
|
type TongyishuPdfInfo,
|
||||||
|
type AddItemBillPdfInfo,
|
||||||
} from '../../utils/examActions';
|
} from '../../utils/examActions';
|
||||||
import type { SignaturePadHandle } from '../ui';
|
import type { SignaturePadHandle } from '../ui';
|
||||||
import { Button, SignaturePad } from '../ui';
|
import { Button, SignaturePad } from '../ui';
|
||||||
@@ -73,10 +74,9 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
const [daojiandanPdfReady, setDaojiandanPdfReady] = useState(false);
|
const [daojiandanPdfReady, setDaojiandanPdfReady] = useState(false);
|
||||||
const [daojiandanPdfBlobUrl, setDaojiandanPdfBlobUrl] = useState<string | null>(null);
|
const [daojiandanPdfBlobUrl, setDaojiandanPdfBlobUrl] = useState<string | null>(null);
|
||||||
const daojiandanCanvasContainerRef = useRef<HTMLDivElement>(null);
|
const daojiandanCanvasContainerRef = useRef<HTMLDivElement>(null);
|
||||||
// 加项单相关状态
|
// 加项单相关状态(支持多个加项单)
|
||||||
const [addItemBillUrl, setAddItemBillUrl] = useState<string | null>(null);
|
const [addItemBillList, setAddItemBillList] = useState<AddItemBillPdfInfo[]>([]);
|
||||||
const [addItemBillName, setAddItemBillName] = useState<string>('加项单');
|
const [currentAddItemBill, setCurrentAddItemBill] = useState<AddItemBillPdfInfo | null>(null);
|
||||||
const [isAddItemBillSigned, setIsAddItemBillSigned] = useState(false); // 加项单是否已签名
|
|
||||||
const [showAddItemBillPreview, setShowAddItemBillPreview] = useState(false);
|
const [showAddItemBillPreview, setShowAddItemBillPreview] = useState(false);
|
||||||
const [showAddItemBillSignature, setShowAddItemBillSignature] = useState(false);
|
const [showAddItemBillSignature, setShowAddItemBillSignature] = useState(false);
|
||||||
const addItemBillSignaturePadRef = useRef<SignaturePadHandle | null>(null);
|
const addItemBillSignaturePadRef = useRef<SignaturePadHandle | null>(null);
|
||||||
@@ -362,31 +362,17 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
fetchDaojiandan();
|
fetchDaojiandan();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查加项单PDF(逻辑和导检单一样)
|
// 检查加项单PDF(可能有多个)
|
||||||
const storedAddItemBill = getAddItemBillPdfFromStorage(examId);
|
const storedAddItemBillList = getAddItemBillPdfFromStorage(examId);
|
||||||
if (storedAddItemBill && storedAddItemBill.pdf_url) {
|
if (storedAddItemBillList && storedAddItemBillList.length > 0) {
|
||||||
setAddItemBillUrl(storedAddItemBill.pdf_url);
|
setAddItemBillList(storedAddItemBillList);
|
||||||
setAddItemBillName(storedAddItemBill.pdf_name || '加项单');
|
// 默认选中第一个未签名的加项单,如果都已签名则选中第一个
|
||||||
// 使用 localStorage 中保存的 is_signed 字段判断是否已签名
|
const unsigned = storedAddItemBillList.find((item) => item.is_signed !== true);
|
||||||
setIsAddItemBillSigned(storedAddItemBill.is_signed === true);
|
setCurrentAddItemBill(unsigned || storedAddItemBillList[0]);
|
||||||
} else {
|
} else {
|
||||||
// 如果 localStorage 中没有加项单,调用接口获取未签名的加项单用于查看和签名
|
// 没有加项单:不再主动调用接口获取,因为新接口需要 CombinationCode(仅支付时知道)
|
||||||
const fetchAddItemBill = async () => {
|
setAddItemBillList([]);
|
||||||
try {
|
setCurrentAddItemBill(null);
|
||||||
const res = await getAddItemBillPdfApi({ exam_id: examId });
|
|
||||||
if (res.Status === 200 && res.Data?.pdf_url) {
|
|
||||||
const pdfUrlValue = res.Data.pdf_url;
|
|
||||||
const pdfNameValue = res.Data.pdf_name || '加项单';
|
|
||||||
// 不保存到 localStorage,只用于显示和签名
|
|
||||||
setAddItemBillUrl(pdfUrlValue);
|
|
||||||
setAddItemBillName(pdfNameValue);
|
|
||||||
setIsAddItemBillSigned(false); // 接口获取的是未签名的
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取加项单失败', err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
fetchAddItemBill();
|
|
||||||
}
|
}
|
||||||
}, [examId]);
|
}, [examId]);
|
||||||
|
|
||||||
@@ -578,9 +564,9 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
renderAllPages();
|
renderAllPages();
|
||||||
}, [daojiandanPdfData]);
|
}, [daojiandanPdfData]);
|
||||||
|
|
||||||
// 加载加项单 PDF 数据
|
// 加载加项单 PDF 数据(当前选中的加项单)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!showAddItemBillPreview || !addItemBillUrl) {
|
if (!showAddItemBillPreview || !currentAddItemBill?.pdf_url) {
|
||||||
setAddItemBillPdfData(null);
|
setAddItemBillPdfData(null);
|
||||||
setAddItemBillPdfBlobUrl(null);
|
setAddItemBillPdfBlobUrl(null);
|
||||||
setAddItemBillPdfReady(false);
|
setAddItemBillPdfReady(false);
|
||||||
@@ -592,7 +578,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
setAddItemBillPdfLoading(true);
|
setAddItemBillPdfLoading(true);
|
||||||
setAddItemBillPdfData(null);
|
setAddItemBillPdfData(null);
|
||||||
|
|
||||||
fetch(addItemBillUrl)
|
fetch(currentAddItemBill.pdf_url)
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
if (!resp.ok) throw new Error('获取PDF文件失败');
|
if (!resp.ok) throw new Error('获取PDF文件失败');
|
||||||
return resp.blob();
|
return resp.blob();
|
||||||
@@ -616,7 +602,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
URL.revokeObjectURL(objectUrl);
|
URL.revokeObjectURL(objectUrl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [showAddItemBillPreview, addItemBillUrl]);
|
}, [showAddItemBillPreview, currentAddItemBill?.pdf_url]);
|
||||||
|
|
||||||
// 渲染加项单 PDF
|
// 渲染加项单 PDF
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -736,29 +722,19 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
};
|
};
|
||||||
}, [showDaojiandanPreview, daojiandanUrl]);
|
}, [showDaojiandanPreview, daojiandanUrl]);
|
||||||
|
|
||||||
// 加项单预览:使用 pdfjs 渲染到 canvas
|
// 加项单预览:使用 pdfjs 渲染到 canvas(依赖加载好的 addItemBillPdfData)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!showAddItemBillPreview || !addItemBillUrl || !addItemBillCanvasContainerRef.current) return;
|
if (!showAddItemBillPreview || !addItemBillPdfData || !addItemBillCanvasContainerRef.current) return;
|
||||||
|
|
||||||
const container = addItemBillCanvasContainerRef.current;
|
const container = addItemBillCanvasContainerRef.current;
|
||||||
let cancelled = false;
|
container.innerHTML = '';
|
||||||
|
|
||||||
const renderAddItemBill = async () => {
|
const renderAddItemBill = async () => {
|
||||||
try {
|
try {
|
||||||
setAddItemBillPdfLoading(true);
|
const pdf = await pdfjsLib.getDocument({ data: addItemBillPdfData }).promise;
|
||||||
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 = 3.0;
|
const scale = 3.0;
|
||||||
|
|
||||||
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
||||||
if (cancelled) return;
|
|
||||||
|
|
||||||
const page = await pdf.getPage(pageNum);
|
const page = await pdf.getPage(pageNum);
|
||||||
const viewport = page.getViewport({ scale });
|
const viewport = page.getViewport({ scale });
|
||||||
|
|
||||||
@@ -785,20 +761,15 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('加项单PDF 渲染失败', err);
|
console.error('加项单PDF 渲染失败', err);
|
||||||
} finally {
|
|
||||||
if (!cancelled) {
|
|
||||||
setAddItemBillPdfLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
renderAddItemBill();
|
renderAddItemBill();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
};
|
};
|
||||||
}, [showAddItemBillPreview, addItemBillUrl]);
|
}, [showAddItemBillPreview, addItemBillPdfData]);
|
||||||
|
|
||||||
const handlePrint = () => {
|
const handlePrint = () => {
|
||||||
if (!pdfBlobUrl || !pdfReady || !canvasContainerRef.current || !previewPdf) return;
|
if (!pdfBlobUrl || !pdfReady || !canvasContainerRef.current || !previewPdf) return;
|
||||||
@@ -1104,13 +1075,18 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加项单签名提交
|
// 加项单签名提交(针对当前选中的加项单)
|
||||||
const handleSubmitAddItemBillSign = async () => {
|
const handleSubmitAddItemBillSign = async () => {
|
||||||
if (!examId) {
|
if (!examId) {
|
||||||
setAddItemBillSubmitMessage('缺少必要信息,无法提交签名');
|
setAddItemBillSubmitMessage('缺少必要信息,无法提交签名');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!currentAddItemBill) {
|
||||||
|
setAddItemBillSubmitMessage('没有可签名的加项单');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const dataUrl = addItemBillSignaturePadRef.current?.toDataURL('image/png');
|
const dataUrl = addItemBillSignaturePadRef.current?.toDataURL('image/png');
|
||||||
if (!dataUrl) {
|
if (!dataUrl) {
|
||||||
setAddItemBillSubmitMessage('请先完成签名');
|
setAddItemBillSubmitMessage('请先完成签名');
|
||||||
@@ -1124,6 +1100,8 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
|
|
||||||
const res = await submitAddItemBillSign({
|
const res = await submitAddItemBillSign({
|
||||||
exam_id: examId,
|
exam_id: examId,
|
||||||
|
pdf_sort: currentAddItemBill.pdf_sort,
|
||||||
|
combinationCode: currentAddItemBill.combinationCode,
|
||||||
sign_file: blob,
|
sign_file: blob,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1131,16 +1109,39 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
setAddItemBillSubmitMessage('签名提交成功');
|
setAddItemBillSubmitMessage('签名提交成功');
|
||||||
const pdfUrlValue = res.Data.pdf_url;
|
const pdfUrlValue = res.Data.pdf_url;
|
||||||
const pdfNameValue = res.Data.pdf_name || '加项单';
|
const pdfNameValue = res.Data.pdf_name || '加项单';
|
||||||
setAddItemBillUrl(pdfUrlValue);
|
// 更新当前加项单为已签名,并更新本地列表与 localStorage
|
||||||
setAddItemBillName(pdfNameValue);
|
setAddItemBillList((prev) => {
|
||||||
setIsAddItemBillSigned(true); // 签名成功后标记为已签名
|
const next = prev.map((item) => {
|
||||||
|
if (item.pdf_sort === currentAddItemBill.pdf_sort) {
|
||||||
// 保存加项单PDF信息到localStorage(标记为已签名)
|
const updated: AddItemBillPdfInfo = {
|
||||||
setAddItemBillPdf(examId, {
|
...item,
|
||||||
pdf_name: pdfNameValue,
|
pdf_name: pdfNameValue,
|
||||||
pdf_url: pdfUrlValue,
|
pdf_url: pdfUrlValue,
|
||||||
|
payment_status: res.Data?.payment_status ?? item.payment_status ?? null,
|
||||||
|
payment_status_name: res.Data?.payment_status_name ?? item.payment_status_name ?? null,
|
||||||
is_signed: true,
|
is_signed: true,
|
||||||
|
};
|
||||||
|
// 同步写入 localStorage
|
||||||
|
setAddItemBillPdf(examId, updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
});
|
});
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
|
||||||
|
setCurrentAddItemBill((prev) =>
|
||||||
|
prev && prev.pdf_sort === currentAddItemBill.pdf_sort
|
||||||
|
? {
|
||||||
|
...prev,
|
||||||
|
pdf_name: pdfNameValue,
|
||||||
|
pdf_url: pdfUrlValue,
|
||||||
|
payment_status: res.Data?.payment_status ?? prev.payment_status ?? null,
|
||||||
|
payment_status_name: res.Data?.payment_status_name ?? prev.payment_status_name ?? null,
|
||||||
|
is_signed: true,
|
||||||
|
}
|
||||||
|
: prev
|
||||||
|
);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setShowAddItemBillSignature(false);
|
setShowAddItemBillSignature(false);
|
||||||
@@ -1160,11 +1161,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 加项单直接打印
|
// 加项单直接打印
|
||||||
const handleAddItemBillDirectPrint = async () => {
|
const handleAddItemBillDirectPrint = async (target: AddItemBillPdfInfo | null) => {
|
||||||
if (!addItemBillUrl) return;
|
if (!target?.pdf_url) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(addItemBillUrl);
|
const response = await fetch(target.pdf_url);
|
||||||
if (!response.ok) throw new Error('获取PDF文件失败');
|
if (!response.ok) throw new Error('获取PDF文件失败');
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
const arrayBuffer = await blob.arrayBuffer();
|
const arrayBuffer = await blob.arrayBuffer();
|
||||||
@@ -1200,7 +1201,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>加项单打印</title>
|
<title>${target.pdf_name || '加项单打印'}</title>
|
||||||
<style>
|
<style>
|
||||||
@media print {
|
@media print {
|
||||||
body {
|
body {
|
||||||
@@ -1544,9 +1545,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理加项单(如果有且已签名)
|
// 处理加项单(如果有且已签名)
|
||||||
if (addItemBillUrl && isAddItemBillSigned) {
|
if (addItemBillList.length > 0) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(addItemBillUrl);
|
for (const bill of addItemBillList) {
|
||||||
|
if (!bill.pdf_url || bill.is_signed !== true) continue;
|
||||||
|
const response = await fetch(bill.pdf_url);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
const arrayBuffer = await blob.arrayBuffer();
|
const arrayBuffer = await blob.arrayBuffer();
|
||||||
@@ -1573,6 +1576,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
allImages.push(canvas.toDataURL('image/png'));
|
allImages.push(canvas.toDataURL('image/png'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('处理加项单失败', err);
|
console.error('处理加项单失败', err);
|
||||||
}
|
}
|
||||||
@@ -1913,12 +1917,24 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 加项单 */}
|
{/* 加项单列表(可能有多个) */}
|
||||||
{addItemBillUrl && (
|
{addItemBillList.length > 0 &&
|
||||||
<div className='flex items-center justify-between gap-3 p-2 rounded-xl border bg-white shadow-sm'>
|
addItemBillList.map((bill) => {
|
||||||
|
const isSigned = bill.is_signed === true;
|
||||||
|
const isCurrent = currentAddItemBill && currentAddItemBill.pdf_sort === bill.pdf_sort;
|
||||||
|
const displayName =
|
||||||
|
bill.pdf_name && bill.pdf_name.length > 12 ? bill.pdf_name.slice(0, 12) + '...' : bill.pdf_name || '加项单';
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={bill.pdf_sort}
|
||||||
|
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'>{addItemBillName.length > 12 ? addItemBillName.slice(0, 12) + "..." : addItemBillName}</span>
|
<span className='truncate'>
|
||||||
{isAddItemBillSigned && (
|
{displayName}
|
||||||
|
{typeof bill.pdf_sort === 'number' ? `(#${bill.pdf_sort})` : ''}
|
||||||
|
</span>
|
||||||
|
{isSigned && (
|
||||||
<img
|
<img
|
||||||
src='/sign.png'
|
src='/sign.png'
|
||||||
alt='已签名'
|
alt='已签名'
|
||||||
@@ -1928,58 +1944,48 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
{isAddItemBillSigned ? (
|
{isSigned && bill.pdf_url && (
|
||||||
// 已签名:显示打印和查看按钮
|
|
||||||
<>
|
|
||||||
<Button
|
<Button
|
||||||
className='py-1.5 px-3 bg-blue-600 hover:bg-blue-700 text-white'
|
className='py-1.5 px-3 bg-blue-600 hover:bg-blue-700 text-white'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (busy) return;
|
if (busy) return;
|
||||||
handleAddItemBillDirectPrint();
|
handleAddItemBillDirectPrint(bill);
|
||||||
}}
|
}}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
>
|
>
|
||||||
打印
|
打印
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
|
{bill.pdf_url && (
|
||||||
<Button
|
<Button
|
||||||
className='py-1.5 px-3'
|
className='py-1.5 px-3'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (busy) return;
|
if (busy) return;
|
||||||
|
setCurrentAddItemBill(bill);
|
||||||
setShowAddItemBillPreview(true);
|
setShowAddItemBillPreview(true);
|
||||||
}}
|
}}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
>
|
>
|
||||||
查看
|
查看
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
)}
|
||||||
) : (
|
{!isSigned && (
|
||||||
// 未签名:显示查看和签名按钮
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
className='py-1.5 px-3'
|
|
||||||
onClick={() => {
|
|
||||||
if (busy) return;
|
|
||||||
setShowAddItemBillPreview(true);
|
|
||||||
}}
|
|
||||||
disabled={busy}
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</Button>
|
|
||||||
<Button
|
<Button
|
||||||
className='py-1.5 px-3'
|
className='py-1.5 px-3'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (busy) return;
|
if (busy) return;
|
||||||
|
setCurrentAddItemBill(bill);
|
||||||
setShowAddItemBillSignature(true);
|
setShowAddItemBillSignature(true);
|
||||||
}}
|
}}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
>
|
>
|
||||||
签名
|
签名
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -2213,21 +2219,21 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
showAddItemBillPreview && addItemBillUrl && (
|
showAddItemBillPreview && currentAddItemBill && currentAddItemBill.pdf_url && (
|
||||||
<div className='fixed inset-0 z-[60] bg-black/75 flex flex-col'>
|
<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='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='text-sm font-medium truncate pr-3'>{currentAddItemBill.pdf_name || '加项单'}</div>
|
||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
{isAddItemBillSigned && (
|
{currentAddItemBill.is_signed && (
|
||||||
<Button
|
<Button
|
||||||
className='py-1 px-3 bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50 disabled:cursor-not-allowed'
|
className='py-1 px-3 bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-50 disabled:cursor-not-allowed'
|
||||||
onClick={handleAddItemBillDirectPrint}
|
onClick={() => handleAddItemBillDirectPrint(currentAddItemBill)}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
>
|
>
|
||||||
打印
|
打印
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!isAddItemBillSigned && (
|
{!currentAddItemBill.is_signed && (
|
||||||
<Button
|
<Button
|
||||||
className='py-1 px-3 bg-blue-600 hover:bg-blue-700 text-white'
|
className='py-1 px-3 bg-blue-600 hover:bg-blue-700 text-white'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -196,6 +196,14 @@ export const getDaojiandanPdf = (examId: string | number): DaojiandanPdfInfo | n
|
|||||||
* 加项单PDF信息
|
* 加项单PDF信息
|
||||||
*/
|
*/
|
||||||
export interface AddItemBillPdfInfo {
|
export interface AddItemBillPdfInfo {
|
||||||
|
/** 加项单编号(接口返回的 pdf_sort) */
|
||||||
|
pdf_sort: number;
|
||||||
|
/** 加项组合代码(多个加项项目,用逗号拼接,例如:123,456) */
|
||||||
|
combinationCode: string;
|
||||||
|
/** 支付状态 (1-未支付 2-已支付) */
|
||||||
|
payment_status?: string | null;
|
||||||
|
/** 支付状态名称 (1-未支付 2-已支付) */
|
||||||
|
payment_status_name?: string | null;
|
||||||
/** PDF文件名称 */
|
/** PDF文件名称 */
|
||||||
pdf_name: string;
|
pdf_name: string;
|
||||||
/** PDF文件地址 */
|
/** PDF文件地址 */
|
||||||
@@ -222,13 +230,38 @@ export const setAddItemBillPdf = (
|
|||||||
if (typeof window === 'undefined') return;
|
if (typeof window === 'undefined') return;
|
||||||
|
|
||||||
const key = getAddItemBillPdfKey(examId);
|
const key = getAddItemBillPdfKey(examId);
|
||||||
localStorage.setItem(key, JSON.stringify(pdfInfo));
|
const raw = localStorage.getItem(key);
|
||||||
|
let list: AddItemBillPdfInfo[] = [];
|
||||||
|
|
||||||
|
if (raw) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
list = parsed as AddItemBillPdfInfo[];
|
||||||
|
} else if (parsed && typeof parsed === 'object') {
|
||||||
|
// 兼容旧版本(单个对象)
|
||||||
|
list = [parsed as AddItemBillPdfInfo];
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('加项单PDF信息解析失败,将重置为新列表', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 pdf_sort 去重:同一个 pdf_sort 覆盖旧数据
|
||||||
|
const index = list.findIndex((item) => item.pdf_sort === pdfInfo.pdf_sort);
|
||||||
|
if (index >= 0) {
|
||||||
|
list[index] = pdfInfo;
|
||||||
|
} else {
|
||||||
|
list.push(pdfInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem(key, JSON.stringify(list));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取加项单PDF信息
|
* 获取加项单PDF信息
|
||||||
*/
|
*/
|
||||||
export const getAddItemBillPdf = (examId: string | number): AddItemBillPdfInfo | null => {
|
export const getAddItemBillPdf = (examId: string | number): AddItemBillPdfInfo[] | null => {
|
||||||
if (typeof window === 'undefined') return null;
|
if (typeof window === 'undefined') return null;
|
||||||
|
|
||||||
const key = getAddItemBillPdfKey(examId);
|
const key = getAddItemBillPdfKey(examId);
|
||||||
@@ -237,7 +270,14 @@ export const getAddItemBillPdf = (examId: string | number): AddItemBillPdfInfo |
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(raw);
|
const parsed = JSON.parse(raw);
|
||||||
return parsed as AddItemBillPdfInfo;
|
if (Array.isArray(parsed)) {
|
||||||
|
return parsed as AddItemBillPdfInfo[];
|
||||||
|
}
|
||||||
|
if (parsed && typeof parsed === 'object') {
|
||||||
|
// 兼容旧版本(单个对象)
|
||||||
|
return [parsed as AddItemBillPdfInfo];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('加项单PDF信息解析失败', err);
|
console.warn('加项单PDF信息解析失败', err);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user