完善签到
This commit is contained in:
@@ -99,8 +99,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
const [selectedOptionalItem, setSelectedOptionalItem] = useState<number | null>(null);
|
||||
// 是否已经确认过可选项目(如果后端已有记录,视为已确认)
|
||||
const [optionalConfirmed, setOptionalConfirmed] = useState(false);
|
||||
// 是否显示“请先确认体检项目,确认后不可修改”的提示
|
||||
// 是否显示"请先确认体检项目,确认后不可修改"的提示
|
||||
const [showOptionalConfirmTip, setShowOptionalConfirmTip] = useState(false);
|
||||
// 跟踪当前 examId 是否已加载过导检单和知情同意书
|
||||
const pdfsLoadedForExamIdRef = useRef<number | null>(null);
|
||||
// 使用 ref 存储最新的可选项目状态,确保 refreshTijianPdfs 能读取到最新值
|
||||
const optionalItemListRef = useRef<OutputPhysicalExamItemInfo[]>([]);
|
||||
const optionalConfirmedRef = useRef<boolean>(false);
|
||||
|
||||
const busy =
|
||||
signLoading ||
|
||||
@@ -117,7 +122,13 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
return () => onBusyChange?.(false);
|
||||
}, [busy, onBusyChange]);
|
||||
|
||||
const refreshTijianPdfs = async (examIdValue: number) => {
|
||||
const refreshTijianPdfs = async (examIdValue: number, checkOptional: boolean = true) => {
|
||||
// 如果还有可选项目未确认,不执行接口请求(使用 ref 确保读取最新值)
|
||||
if (checkOptional && optionalItemListRef.current.length > 0 && !optionalConfirmedRef.current) {
|
||||
console.log('跳过 pdf-file-get 请求:可选项目未确认', { optionalItemListLength: optionalItemListRef.current.length, optionalConfirmed: optionalConfirmedRef.current });
|
||||
return;
|
||||
}
|
||||
|
||||
setConsentLoading(true);
|
||||
|
||||
try {
|
||||
@@ -182,19 +193,138 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化加载体检 PDF 列表(导检单、知情同意书、加项单)
|
||||
useEffect(() => {
|
||||
if (!examId) {
|
||||
setConsentList([]);
|
||||
setDaojiandanUrl(null);
|
||||
setIsDaojiandanSigned(false);
|
||||
// 加载可选项目列表 & 操作记录(优先使用记录,无记录时才调用可选项目接口)
|
||||
const loadOptionalItems = async () => {
|
||||
if (!examId) return;
|
||||
setOptionalItemLoading(true);
|
||||
try {
|
||||
// 先获取操作记录
|
||||
const recordRes = await getExamOptionRecordList({ exam_id: examId });
|
||||
|
||||
|
||||
console.log("操作记录请求", recordRes);
|
||||
// 若任意记录 is_abandon=1,则视为"已确定"(已做过弃选/确认动作),不可再确认
|
||||
let hasConfirmedRecord = false;
|
||||
let selectedFromRecord: number | null = null;
|
||||
let itemsFromRecord: OutputPhysicalExamItemInfo[] = [];
|
||||
|
||||
if (recordRes.Status === 200 && recordRes.Data && recordRes.Data.length > 0) {
|
||||
hasConfirmedRecord = recordRes.Data.some((r) => r.is_abandon === 1);
|
||||
|
||||
// 从记录中构建可选项目列表(只显示 is_abandon=0 的记录)
|
||||
itemsFromRecord = recordRes.Data
|
||||
.filter((r) => r.is_abandon === 0 && r.combination_code)
|
||||
.map((r) => {
|
||||
const codeNum = Number(r.combination_code);
|
||||
const packageNum = r.package_code ? Number(r.package_code) : null;
|
||||
if (!Number.isFinite(codeNum)) return null;
|
||||
return {
|
||||
combination_code: codeNum,
|
||||
combination_name: r.combination_name || '',
|
||||
package_code: Number.isFinite(packageNum) ? packageNum : null,
|
||||
} as OutputPhysicalExamItemInfo;
|
||||
})
|
||||
.filter((item): item is OutputPhysicalExamItemInfo => item !== null);
|
||||
|
||||
// 预选:优先取 is_abandon=0 的组合码(若有)
|
||||
const selectedRecord = recordRes.Data.find(
|
||||
(r) => r.is_abandon === 0 && r.combination_code
|
||||
);
|
||||
if (selectedRecord?.combination_code) {
|
||||
const codeNum = Number(selectedRecord.combination_code);
|
||||
if (Number.isFinite(codeNum)) {
|
||||
selectedFromRecord = codeNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有记录,使用记录构建的列表;否则调用可选项目接口
|
||||
if (itemsFromRecord.length > 0) {
|
||||
// 根据 combination_code 去重,保留第一个出现的项目
|
||||
const uniqueItems = itemsFromRecord.filter((item, index, self) =>
|
||||
index === self.findIndex((t) => t.combination_code === item.combination_code)
|
||||
);
|
||||
setOptionalItemList(uniqueItems);
|
||||
optionalItemListRef.current = uniqueItems;
|
||||
|
||||
if (selectedFromRecord != null && uniqueItems.some((i) => i.combination_code === selectedFromRecord)) {
|
||||
setSelectedOptionalItem(selectedFromRecord);
|
||||
} else {
|
||||
setSelectedOptionalItem(null);
|
||||
}
|
||||
// 只要存在可选项目:默认未确认;但若出现 is_abandon=1 记录,则视为已确定
|
||||
setOptionalConfirmed(hasConfirmedRecord);
|
||||
optionalConfirmedRef.current = hasConfirmedRecord;
|
||||
setShowOptionalConfirmTip(false);
|
||||
} else {
|
||||
// 没有记录,调用可选项目接口
|
||||
const listRes = await getExamOptionalItemList({ physical_exam_id: examId });
|
||||
|
||||
if (listRes.Status === 200 && listRes.Data?.listOptionalItem) {
|
||||
const items = listRes.Data.listOptionalItem;
|
||||
// 根据 combination_code 去重,保留第一个出现的项目
|
||||
const uniqueItems = items.filter((item, index, self) =>
|
||||
index === self.findIndex((t) => t.combination_code === item.combination_code)
|
||||
);
|
||||
setOptionalItemList(uniqueItems);
|
||||
optionalItemListRef.current = uniqueItems;
|
||||
|
||||
// 无历史记录,默认不选
|
||||
setSelectedOptionalItem(null);
|
||||
// 只要存在可选项目:默认未确认
|
||||
setOptionalConfirmed(false);
|
||||
optionalConfirmedRef.current = false;
|
||||
setShowOptionalConfirmTip(false);
|
||||
} else {
|
||||
setOptionalItemList([]);
|
||||
optionalItemListRef.current = [];
|
||||
setSelectedOptionalItem(null);
|
||||
setOptionalConfirmed(true);
|
||||
optionalConfirmedRef.current = true;
|
||||
setShowOptionalConfirmTip(false);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取可选项目/记录失败', err);
|
||||
setOptionalItemList([]);
|
||||
optionalItemListRef.current = [];
|
||||
setSelectedOptionalItem(null);
|
||||
setOptionalConfirmed(true);
|
||||
optionalConfirmedRef.current = true;
|
||||
setShowOptionalConfirmTip(false);
|
||||
} finally {
|
||||
setOptionalItemLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载 PDF 的逻辑(知情同意书、导检单)
|
||||
const loadPdfs = async (currentExamId: number) => {
|
||||
// 如果已经为当前 examId 加载过,不再重复加载
|
||||
if (pdfsLoadedForExamIdRef.current === currentExamId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化时加载知情同意书和导检单
|
||||
// 使用 ref 确保读取最新值:如果没有可选项目,或者有可选项目但已确认,才加载导检单和知情同意书
|
||||
console.log('检查是否应该加载 PDF,ref 值:', {
|
||||
optionalItemListLength: optionalItemListRef.current.length,
|
||||
optionalConfirmed: optionalConfirmedRef.current
|
||||
});
|
||||
const shouldLoadPdfs = optionalItemListRef.current.length === 0 || optionalConfirmedRef.current;
|
||||
|
||||
if (!shouldLoadPdfs) {
|
||||
console.log('跳过所有 PDF 接口请求:可选项目未确认', {
|
||||
optionalItemListLength: optionalItemListRef.current.length,
|
||||
optionalConfirmed: optionalConfirmedRef.current
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
pdfsLoadedForExamIdRef.current = currentExamId;
|
||||
|
||||
// 初始化时加载知情同意书
|
||||
const loadTongyishu = async () => {
|
||||
try {
|
||||
const res = await getTongyishuPdf({ exam_id: examId });
|
||||
const res = await getTongyishuPdf({ exam_id: currentExamId });
|
||||
if (res.Status === 200 && res.Data?.list_pdf_url) {
|
||||
const list = res.Data.list_pdf_url;
|
||||
const mappedConsent: OutputTongyishuFileInfo[] = list.map((item) => ({
|
||||
@@ -212,9 +342,9 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
// 初始化时加载导检单(未签名版本也可以查看)
|
||||
const loadDaojiandan = async () => {
|
||||
try {
|
||||
const res = await getDaojiandanPdf({ exam_id: examId });
|
||||
console.log("未签名导检单请求");
|
||||
const res = await getDaojiandanPdf({ exam_id: currentExamId });
|
||||
if (res.Status === 200 && res.Data?.pdf_url) {
|
||||
// 如果 refreshTijianPdfs 没有设置导检单URL,则使用这里获取的未签名版本
|
||||
setDaojiandanUrl((prev) => prev || res.Data?.pdf_url || null);
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -222,85 +352,58 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载可选项目列表 & 操作记录(用于判断是否已选择)
|
||||
const loadOptionalItems = async () => {
|
||||
if (!examId) return;
|
||||
setOptionalItemLoading(true);
|
||||
try {
|
||||
const [listRes, recordRes] = await Promise.all([
|
||||
getExamOptionalItemList({ physical_exam_id: examId }),
|
||||
getExamOptionRecordList({ exam_id: examId }),
|
||||
]);
|
||||
|
||||
if (listRes.Status === 200 && listRes.Data?.listOptionalItem) {
|
||||
const items = listRes.Data.listOptionalItem;
|
||||
// 根据 combination_code 去重,保留第一个出现的项目
|
||||
const uniqueItems = items.filter((item, index, self) =>
|
||||
index === self.findIndex((t) => t.combination_code === item.combination_code)
|
||||
);
|
||||
setOptionalItemList(uniqueItems);
|
||||
|
||||
// 若任意记录 is_abandon=1,则视为“已确定”(已做过弃选/确认动作),不可再确认
|
||||
let hasConfirmedRecord = false;
|
||||
let selectedFromRecord: number | null = null;
|
||||
if (recordRes.Status === 200 && recordRes.Data) {
|
||||
hasConfirmedRecord = recordRes.Data.some((r) => r.is_abandon === 1);
|
||||
|
||||
// 预选:优先取 is_abandon=0 的组合码(若有)
|
||||
const selectedRecord = recordRes.Data.find(
|
||||
(r) => r.is_abandon === 0 && r.combination_code
|
||||
);
|
||||
if (selectedRecord?.combination_code) {
|
||||
const codeNum = Number(selectedRecord.combination_code);
|
||||
if (Number.isFinite(codeNum)) {
|
||||
selectedFromRecord = codeNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uniqueItems.length > 0) {
|
||||
if (
|
||||
selectedFromRecord != null &&
|
||||
uniqueItems.some((i) => i.combination_code === selectedFromRecord)
|
||||
) {
|
||||
// 有历史记录时,仅做“默认选中”,不标记为已确认
|
||||
setSelectedOptionalItem(selectedFromRecord);
|
||||
} else {
|
||||
// 无历史记录,默认不选
|
||||
setSelectedOptionalItem(null);
|
||||
}
|
||||
// 只要存在可选项目:默认未确认;但若出现 is_abandon=1 记录,则视为已确定
|
||||
setOptionalConfirmed(hasConfirmedRecord);
|
||||
setShowOptionalConfirmTip(false);
|
||||
} else {
|
||||
// 没有可选项目,则视为无需确认
|
||||
setSelectedOptionalItem(null);
|
||||
setOptionalConfirmed(true);
|
||||
setShowOptionalConfirmTip(false);
|
||||
}
|
||||
} else {
|
||||
setOptionalItemList([]);
|
||||
setSelectedOptionalItem(null);
|
||||
setOptionalConfirmed(true);
|
||||
setShowOptionalConfirmTip(false);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取可选项目/记录失败', err);
|
||||
setOptionalItemList([]);
|
||||
setSelectedOptionalItem(null);
|
||||
setOptionalConfirmed(true);
|
||||
setShowOptionalConfirmTip(false);
|
||||
} finally {
|
||||
setOptionalItemLoading(false);
|
||||
// 加载 PDF
|
||||
loadTongyishu().then(() => {
|
||||
// 调用 refreshTijianPdfs 前再次检查可选项目状态(使用 ref 确保读取最新值)
|
||||
if (optionalItemListRef.current.length === 0 || optionalConfirmedRef.current) {
|
||||
refreshTijianPdfs(currentExamId, true);
|
||||
}
|
||||
};
|
||||
});
|
||||
loadDaojiandan();
|
||||
};
|
||||
|
||||
// 先加载知情同意书和导检单,然后刷新所有PDF状态(包括签名状态)
|
||||
Promise.all([loadTongyishu(), loadDaojiandan(), loadOptionalItems()]).then(() => {
|
||||
refreshTijianPdfs(examId);
|
||||
// 初始化:先检查可选项
|
||||
useEffect(() => {
|
||||
if (!examId) {
|
||||
setConsentList([]);
|
||||
setDaojiandanUrl(null);
|
||||
setIsDaojiandanSigned(false);
|
||||
optionalItemListRef.current = [];
|
||||
optionalConfirmedRef.current = true;
|
||||
pdfsLoadedForExamIdRef.current = null;
|
||||
setOptionalItemLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 先设置 loading 为 true
|
||||
setOptionalItemLoading(true);
|
||||
optionalItemListRef.current = [];
|
||||
optionalConfirmedRef.current = false;
|
||||
pdfsLoadedForExamIdRef.current = null;
|
||||
|
||||
// 先检查可选项,选择完毕后才请求导检单接口
|
||||
loadOptionalItems().then(() => {
|
||||
// loadOptionalItems 完成后,ref 已经更新,直接调用加载 PDF 的逻辑
|
||||
console.log('loadOptionalItems 完成,ref 已更新', {
|
||||
optionalItemListLength: optionalItemListRef.current.length,
|
||||
optionalConfirmed: optionalConfirmedRef.current
|
||||
});
|
||||
// 直接调用加载 PDF 的逻辑,不依赖第二个 useEffect
|
||||
loadPdfs(examId);
|
||||
});
|
||||
}, [examId]);
|
||||
|
||||
// 监听可选项目确认状态变化,确认后才加载导检单和知情同意书
|
||||
useEffect(() => {
|
||||
if (!examId) return;
|
||||
|
||||
// 仅在可选项目状态从"未确认"变为"已确认"时,加载 PDF
|
||||
if (optionalConfirmed && optionalItemList.length > 0 && pdfsLoadedForExamIdRef.current !== examId) {
|
||||
console.log('可选项目已确认,开始加载 PDF');
|
||||
loadPdfs(examId);
|
||||
}
|
||||
}, [examId, optionalConfirmed]);
|
||||
|
||||
const handlePickFile = () => {
|
||||
// 有可选项目但尚未确认时,禁止拍照并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
@@ -413,6 +516,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
}
|
||||
if (optionalItemList.length === 0) {
|
||||
setOptionalConfirmed(true);
|
||||
optionalConfirmedRef.current = true;
|
||||
setShowOptionalConfirmTip(false);
|
||||
return;
|
||||
}
|
||||
@@ -429,6 +533,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
// 没有未选项目需要移除,直接标记为已确认
|
||||
if (unselectedCodes.length === 0) {
|
||||
setOptionalConfirmed(true);
|
||||
optionalConfirmedRef.current = true;
|
||||
setShowOptionalConfirmTip(false);
|
||||
setMessage('可选项目已确定');
|
||||
setTimeout(() => setMessage(null), 3000);
|
||||
@@ -444,12 +549,10 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
});
|
||||
if (res.Status === 200 && res.Data?.is_success === 1) {
|
||||
setOptionalConfirmed(true);
|
||||
optionalConfirmedRef.current = true;
|
||||
setShowOptionalConfirmTip(false);
|
||||
// 刷新剩余可选项目列表(理论上只剩一个)
|
||||
const refreshRes = await getExamOptionalItemList({ physical_exam_id: examId });
|
||||
if (refreshRes.Status === 200 && refreshRes.Data?.listOptionalItem) {
|
||||
setOptionalItemList(refreshRes.Data.listOptionalItem);
|
||||
}
|
||||
// 刷新操作记录列表(不再调用 optional-item-list 接口,避免恢复已移除的项目)
|
||||
await loadOptionalItems();
|
||||
setMessage('可选项目已确定');
|
||||
setTimeout(() => setMessage(null), 3000);
|
||||
} else {
|
||||
@@ -510,8 +613,14 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
signaturePadRef.current?.clear();
|
||||
|
||||
// 更新签名状态(刷新统一 PDF 列表)
|
||||
if (examId) {
|
||||
refreshTijianPdfs(examId);
|
||||
// 如果还有可选项目未确认,不执行接口请求(使用 ref 确保读取最新值)
|
||||
if (examId && (optionalItemListRef.current.length === 0 || optionalConfirmedRef.current)) {
|
||||
refreshTijianPdfs(examId, true);
|
||||
} else if (examId) {
|
||||
console.log('跳过 pdf-file-get 请求:可选项目未确认(签名成功后)', {
|
||||
optionalItemListLength: optionalItemListRef.current.length,
|
||||
optionalConfirmed: optionalConfirmedRef.current
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
} else {
|
||||
@@ -708,6 +817,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
useEffect(() => {
|
||||
if (!showAddItemBillPreview || !currentAddItemBill?.pdf_url) {
|
||||
setAddItemBillPdfData(null);
|
||||
setAddItemBillPdfLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -726,9 +836,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
})
|
||||
.then((arrayBuffer) => {
|
||||
setAddItemBillPdfData(arrayBuffer);
|
||||
setAddItemBillPdfLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('加项单PDF 拉取失败', err);
|
||||
setAddItemBillPdfLoading(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
@@ -738,56 +850,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
};
|
||||
}, [showAddItemBillPreview, currentAddItemBill?.pdf_url]);
|
||||
|
||||
// 渲染加项单 PDF
|
||||
useEffect(() => {
|
||||
if (!addItemBillPdfData || !addItemBillCanvasContainerRef.current) return;
|
||||
|
||||
const renderAllPages = async () => {
|
||||
try {
|
||||
const pdf = await pdfjsLib.getDocument({ data: addItemBillPdfData }).promise;
|
||||
|
||||
if (!addItemBillCanvasContainerRef.current) return;
|
||||
|
||||
// 清空容器
|
||||
addItemBillCanvasContainerRef.current.innerHTML = '';
|
||||
|
||||
const scale = 3.0;
|
||||
|
||||
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.style.maxWidth = '100%';
|
||||
canvas.style.height = 'auto';
|
||||
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;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('加项单PDF 渲染失败', err);
|
||||
}
|
||||
};
|
||||
|
||||
renderAllPages();
|
||||
}, [addItemBillPdfData]);
|
||||
|
||||
// 导检单预览:使用 pdfjs 渲染到 canvas
|
||||
useEffect(() => {
|
||||
if (!showDaojiandanPreview || !daojiandanUrl || !daojiandanCanvasContainerRef.current) return;
|
||||
@@ -1236,7 +1298,8 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
setAddItemBillSubmitMessage('签名提交成功');
|
||||
|
||||
// 签名成功后刷新统一 PDF 列表,获取最新的加项单签名状态和地址
|
||||
if (examId) {
|
||||
// 如果还有可选项目未确认,不执行接口请求(使用 ref 确保读取最新值)
|
||||
if (examId && (optionalItemListRef.current.length === 0 || optionalConfirmedRef.current)) {
|
||||
try {
|
||||
const refreshRes = await getTijianPdfFile({ exam_id: examId as number });
|
||||
const list: OutputTijianPdfFileInfo[] = refreshRes.Data || [];
|
||||
@@ -1997,74 +2060,95 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<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'>导检单</span>
|
||||
{isDaojiandanSigned && (
|
||||
<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'>
|
||||
{isDaojiandanSigned ? (
|
||||
// 已签名:显示打印和查看按钮
|
||||
<>
|
||||
<Button
|
||||
className='py-1.5 px-3 bg-blue-600 hover:bg-blue-700 text-white'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止打印并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
handleDaojiandanDirectPrint();
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
打印
|
||||
</Button>
|
||||
<Button
|
||||
className='py-1.5 px-3'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止查看并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
setShowDaojiandanPreview(true);
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
</>
|
||||
) : daojiandanUrl ? (
|
||||
// 未签名但有导检单:显示查看和签名按钮
|
||||
<>
|
||||
<Button
|
||||
className='py-1.5 px-3'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止查看并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
setShowDaojiandanPreview(true);
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
{/* 只有在没有可选项目,或者有可选项目但已确认时,才显示导检单 */}
|
||||
{(optionalItemList.length === 0 || optionalConfirmed) && (
|
||||
<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'>导检单</span>
|
||||
{isDaojiandanSigned && (
|
||||
<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'>
|
||||
{isDaojiandanSigned ? (
|
||||
// 已签名:显示打印和查看按钮
|
||||
<>
|
||||
<Button
|
||||
className='py-1.5 px-3 bg-blue-600 hover:bg-blue-700 text-white'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止打印并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
handleDaojiandanDirectPrint();
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
打印
|
||||
</Button>
|
||||
<Button
|
||||
className='py-1.5 px-3'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止查看并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
setShowDaojiandanPreview(true);
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
</>
|
||||
) : daojiandanUrl ? (
|
||||
// 未签名但有导检单:显示查看和签名按钮
|
||||
<>
|
||||
<Button
|
||||
className='py-1.5 px-3'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止查看并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
setShowDaojiandanPreview(true);
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
<Button
|
||||
className='py-1.5 px-3'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止签名并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
setShowDaojiandanSignature(true);
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
签名
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
// 没有导检单:只显示签名按钮
|
||||
<Button
|
||||
className='py-1.5 px-3'
|
||||
onClick={() => {
|
||||
@@ -2081,28 +2165,10 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
|
||||
>
|
||||
签名
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
// 没有导检单:只显示签名按钮
|
||||
<Button
|
||||
className='py-1.5 px-3'
|
||||
onClick={() => {
|
||||
if (busy) return;
|
||||
// 有可选项目但尚未确认时,禁止签名并提示先确认项目
|
||||
if (optionalItemList.length > 0 && !optionalConfirmed) {
|
||||
setMessage('请先确认体检项目');
|
||||
setShowOptionalConfirmTip(true);
|
||||
return;
|
||||
}
|
||||
setShowDaojiandanSignature(true);
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
签名
|
||||
</Button>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* 加项单列表(可能有多个) */}
|
||||
{addItemBillList.length > 0 &&
|
||||
addItemBillList.map((bill) => {
|
||||
|
||||
Reference in New Issue
Block a user