更新新签到

This commit is contained in:
xianyi
2026-01-07 16:39:41 +08:00
parent 0a43bba87f
commit f6f2405d19
3 changed files with 159 additions and 517 deletions

View File

@@ -4,7 +4,6 @@ import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url';
import { getDaojiandanPdf as getDaojiandanPdfApi, submitDaojiandanSign, editDaojiandanPrintStatus } from '../../api'; import { getDaojiandanPdf as getDaojiandanPdfApi, submitDaojiandanSign, editDaojiandanPrintStatus } from '../../api';
import type { ExamClient } from '../../data/mockData'; import type { ExamClient } from '../../data/mockData';
import { setExamActionRecord, setDaojiandanPdf, getDaojiandanPdf } from '../../utils/examActions';
import type { SignaturePadHandle } from '../ui'; import type { SignaturePadHandle } from '../ui';
import { Button, SignaturePad } from '../ui'; import { Button, SignaturePad } from '../ui';
@@ -69,17 +68,7 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
setSubmitMessage('签名提交成功,正在加载导检单...'); setSubmitMessage('签名提交成功,正在加载导检单...');
setSignatureSubmitted(true); setSignatureSubmitted(true);
const pdfUrlValue = res.Data.pdf_url; const pdfUrlValue = res.Data.pdf_url;
const pdfNameValue = res.Data.pdf_name || '导检单';
setPdfUrl(pdfUrlValue); setPdfUrl(pdfUrlValue);
// 保存导检单PDF信息到localStorage
setDaojiandanPdf(examId, {
pdf_name: pdfNameValue,
pdf_url: pdfUrlValue,
is_signed: true,
});
// 记录打印导检单是否签名操作
setExamActionRecord(examId, 'printSign', true);
// 更新导检单打印状态 // 更新导检单打印状态
try { try {
await editDaojiandanPrintStatus({ exam_id: examId }); await editDaojiandanPrintStatus({ exam_id: examId });
@@ -102,12 +91,6 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
useEffect(() => { useEffect(() => {
const examId = Number(client.id); const examId = Number(client.id);
if (!examId) return; if (!examId) return;
const storedPdf = getDaojiandanPdf(examId);
if (storedPdf && storedPdf.pdf_url) {
setPdfUrl(storedPdf.pdf_url);
setShowPreview(true);
}
}, [client.id]); }, [client.id]);
// 获取导检单PDF优先使用localStorage没有则调用接口 // 获取导检单PDF优先使用localStorage没有则调用接口
@@ -122,16 +105,6 @@ export const ExamPrintPanel = ({ client }: { client: ExamClient }) => {
setError(null); setError(null);
try { try {
// 先尝试从localStorage获取
const storedPdf = getDaojiandanPdf(examId);
if (storedPdf && storedPdf.pdf_url) {
setPdfUrl(storedPdf.pdf_url);
setShowPreview(true);
setFetchLoading(false);
return;
}
// 如果没有存储的,则调用接口获取
const res = await getDaojiandanPdfApi({ exam_id: examId }); const res = await getDaojiandanPdfApi({ exam_id: examId });
if (res.Status === 200 && res.Data?.pdf_url) { if (res.Status === 200 && res.Data?.pdf_url) {
const pdfUrlValue = res.Data.pdf_url; const pdfUrlValue = res.Data.pdf_url;

View File

@@ -2,19 +2,8 @@ import { useEffect, useRef, useState } from 'react';
import * as pdfjsLib from 'pdfjs-dist'; import * as pdfjsLib from 'pdfjs-dist';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url'; import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url';
import type { OutputTongyishuFileInfo } from '../../api'; import type { OutputTongyishuFileInfo, OutputTijianPdfFileInfo } from '../../api';
import { getTongyishuPdf, signInMedicalExamCenter, submitTongyishuSign, submitDaojiandanSign, editDaojiandanPrintStatus, getDaojiandanPdf as getDaojiandanPdfApi, submitAddItemBillSign } from '../../api'; import { signInMedicalExamCenter, submitTongyishuSign, submitDaojiandanSign, editDaojiandanPrintStatus, submitAddItemBillSign, getTijianPdfFile } from '../../api';
import {
setExamActionRecord,
setTongyishuPdfList,
getTongyishuPdfList,
setDaojiandanPdf,
getDaojiandanPdf as getDaojiandanPdfFromStorage,
setAddItemBillPdf,
getAddItemBillPdf as getAddItemBillPdfFromStorage,
type TongyishuPdfInfo,
type AddItemBillPdfInfo,
} from '../../utils/examActions';
import type { SignaturePadHandle } from '../ui'; import type { SignaturePadHandle } from '../ui';
import { Button, SignaturePad } from '../ui'; import { Button, SignaturePad } from '../ui';
@@ -74,14 +63,22 @@ 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 [addItemBillList, setAddItemBillList] = useState<AddItemBillPdfInfo[]>([]);
const [currentAddItemBill, setCurrentAddItemBill] = useState<AddItemBillPdfInfo | null>(null);
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);
const [addItemBillSubmitLoading, setAddItemBillSubmitLoading] = useState(false); const [addItemBillSubmitLoading, setAddItemBillSubmitLoading] = useState(false);
const [addItemBillSubmitMessage, setAddItemBillSubmitMessage] = useState<string | null>(null); const [addItemBillSubmitMessage, setAddItemBillSubmitMessage] = useState<string | null>(null);
type AddItemBillItem = {
pdf_sort: number;
combinationCode: string;
payment_status?: string | null;
payment_status_name?: string | null;
pdf_name: string;
pdf_url: string;
is_signed: boolean;
};
const [addItemBillList, setAddItemBillList] = useState<AddItemBillItem[]>([]);
const [currentAddItemBill, setCurrentAddItemBill] = useState<AddItemBillItem | null>(null);
const [addItemBillPdfData, setAddItemBillPdfData] = useState<ArrayBuffer | null>(null); const [addItemBillPdfData, setAddItemBillPdfData] = useState<ArrayBuffer | null>(null);
const [addItemBillPdfLoading, setAddItemBillPdfLoading] = useState(false); const [addItemBillPdfLoading, setAddItemBillPdfLoading] = useState(false);
const [addItemBillPdfReady, setAddItemBillPdfReady] = useState(false); const [addItemBillPdfReady, setAddItemBillPdfReady] = useState(false);
@@ -95,6 +92,86 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
return () => onBusyChange?.(false); return () => onBusyChange?.(false);
}, [busy, onBusyChange]); }, [busy, onBusyChange]);
const refreshTijianPdfs = async (examIdValue: number) => {
setConsentLoading(true);
setConsentMessage(null);
try {
const res = await getTijianPdfFile({ exam_id: examIdValue });
const list: OutputTijianPdfFileInfo[] = res.Data || [];
// 知情同意书列表pdf_type = 2
const consentItems = list.filter((item) => item.pdf_type === 2);
const mappedConsent: OutputTongyishuFileInfo[] = consentItems.map((item) => ({
pdf_name: item.pdf_name || '',
pdf_url: item.sign_pdf_url || item.pdf_url || '',
combination_code: item.combination_code ?? null,
is_signed: item.is_sign === 1,
}));
setConsentList(mappedConsent);
// 已签名的组合码,用于一键打印等逻辑
const signedCodes =
consentItems
.filter((item) => item.is_sign === 1 && item.combination_code !== null && item.combination_code !== undefined)
.map((item) => Number(item.combination_code))
.filter((n) => Number.isFinite(n)) || [];
setSignedCombinationCodes(signedCodes);
if (!mappedConsent.length) {
setConsentMessage(res.Message || '暂无知情同意书');
}
// 导检单pdf_type = 1取第一条
const daojiandan = list.find((item) => item.pdf_type === 1);
if (daojiandan) {
const url = daojiandan.sign_pdf_url || daojiandan.pdf_url || null;
setDaojiandanUrl(url);
setIsDaojiandanSigned(daojiandan.is_sign === 1);
} else {
setDaojiandanUrl(null);
setIsDaojiandanSigned(false);
}
// 加项单pdf_type = 3完全由新接口提供列表和签名状态
const addItemFromApi = list.filter((item) => item.pdf_type === 3);
if (addItemFromApi.length > 0) {
const addItemList: AddItemBillItem[] = addItemFromApi.map((item) => ({
pdf_sort: item.combination_code ?? 0,
combinationCode: String(item.combination_code ?? ''),
payment_status: item.is_pay != null ? String(item.is_pay) : null,
payment_status_name: item.is_pay_name ?? null,
pdf_name: item.pdf_name || '加项单',
pdf_url: item.sign_pdf_url || item.pdf_url || '',
is_signed: item.is_sign === 1,
}));
setAddItemBillList(addItemList);
const unsigned = addItemList.find((bill) => bill.is_signed !== true);
setCurrentAddItemBill(unsigned || addItemList[0] || null);
} else {
setAddItemBillList([]);
setCurrentAddItemBill(null);
}
} catch (err) {
console.error('获取体检PDF列表失败', err);
setConsentMessage('知情同意书加载失败,请稍后重试');
} finally {
setConsentLoading(false);
}
};
// 初始化加载体检 PDF 列表(导检单、知情同意书、加项单)
useEffect(() => {
if (!examId) {
setConsentList([]);
setConsentMessage('缺少体检ID无法获取知情同意书');
setDaojiandanUrl(null);
setIsDaojiandanSigned(false);
return;
}
refreshTijianPdfs(examId);
}, [examId]);
const handlePickFile = () => { const handlePickFile = () => {
fileInputRef.current?.click(); fileInputRef.current?.click();
}; };
@@ -170,10 +247,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
const ok = res.Status === 200 && res.Data?.is_success === 0; const ok = res.Status === 200 && res.Data?.is_success === 0;
if (ok) { if (ok) {
setMessage('签到成功'); setMessage('签到成功');
// 记录身份证拍照与签到操作
if (examId) {
setExamActionRecord(examId, 'idCardSignIn', true);
}
} else { } else {
setMessage(res.Message || '签到失败'); setMessage(res.Message || '签到失败');
} }
@@ -210,20 +283,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
if (res.Status === 200) { if (res.Status === 200) {
setSubmitMessage('签名提交成功'); setSubmitMessage('签名提交成功');
// 记录体检知情同意书的签字操作 // 更新本地已签名组合码(立刻刷新按钮状态)
if (examId) {
setExamActionRecord(examId, 'consentSign', true);
}
// 存储返回的PDF列表标记为已签名
if (res.Data?.list_pdf_url && Array.isArray(res.Data.list_pdf_url) && examId) {
const pdfList: TongyishuPdfInfo[] = res.Data.list_pdf_url.map((item) => ({
pdf_name: item.pdf_name || '',
pdf_url: item.pdf_url || '',
combination_code: item.combination_code ?? null,
is_signed: true,
}));
setTongyishuPdfList(examId, pdfList);
}
setSignedCombinationCodes((prev) => { setSignedCombinationCodes((prev) => {
const code = Number(previewPdf.combination_code); const code = Number(previewPdf.combination_code);
if (!Number.isFinite(code)) return prev || []; if (!Number.isFinite(code)) return prev || [];
@@ -234,6 +294,11 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
setPreviewPdf(null); setPreviewPdf(null);
setSubmitMessage(null); setSubmitMessage(null);
signaturePadRef.current?.clear(); signaturePadRef.current?.clear();
// 更新签名状态(刷新统一 PDF 列表)
if (examId) {
refreshTijianPdfs(examId);
}
}, 2000); }, 2000);
} else { } else {
setSubmitMessage(res.Message || '签名提交失败'); setSubmitMessage(res.Message || '签名提交失败');
@@ -246,121 +311,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
} }
}; };
useEffect(() => {
if (!examId) {
setConsentList([]);
setConsentMessage('缺少体检ID无法获取知情同意书');
return;
}
setConsentLoading(true);
setConsentMessage(null);
// 先检查 localStorage 中是否有已签名的知情同意书
const storedList = getTongyishuPdfList(examId);
const signedFromStored =
storedList
?.filter((pdf) => pdf.is_signed === true && pdf.combination_code !== null && pdf.combination_code !== undefined)
.map((pdf) => Number(pdf.combination_code))
.filter((n) => Number.isFinite(n)) || [];
setSignedCombinationCodes(signedFromStored);
const allSigned = storedList && storedList.length > 0 && storedList.every((pdf) => pdf.is_signed === true);
// 如果所有知情同意书都已签名,直接使用 localStorage 中的数据,不请求接口
if (allSigned && storedList) {
const mergedList = storedList.map((pdf) => ({
pdf_name: pdf.pdf_name,
pdf_url: pdf.pdf_url,
combination_code: pdf.combination_code ?? null,
}));
setConsentList(mergedList);
setConsentLoading(false);
return;
}
// 如果有未签名的,请求接口获取最新列表
getTongyishuPdf({ exam_id: examId })
.then((res) => {
const list = res.Data?.list_pdf_url || [];
// 合并接口返回的数据和本地已保存的已签名 PDF
let mergedList = list;
if (storedList && storedList.length > 0) {
mergedList = list.map((item) => {
if (item.combination_code === undefined || item.combination_code === null) return item;
const code = Number(item.combination_code);
if (!Number.isFinite(code)) return item;
const matched = storedList.find(
(pdf) => pdf.combination_code !== null && Number(pdf.combination_code) === code && pdf.is_signed === true,
);
// 如果本地有已签名的版本,优先使用
if (matched && matched.pdf_url && matched.is_signed === true) {
return {
...item,
pdf_url: matched.pdf_url,
pdf_name: matched.pdf_name || item.pdf_name,
};
}
return item;
});
}
setConsentList(mergedList);
if (!list.length) {
setConsentMessage(res.Data?.message || '暂无知情同意书');
}
})
.catch((err) => {
console.error('获取知情同意书失败', err);
setConsentMessage('知情同意书加载失败,请稍后重试');
})
.finally(() => setConsentLoading(false));
}, [examId]);
// 组件加载时检查导检单localStorage如果没有则调用接口获取未签名的导检单
useEffect(() => {
if (!examId) return;
// 先检查 localStorage 中的导检单
const storedPdf = getDaojiandanPdfFromStorage(examId);
if (storedPdf && storedPdf.pdf_url) {
setDaojiandanUrl(storedPdf.pdf_url);
// 使用 localStorage 中保存的 is_signed 字段判断是否已签名
setIsDaojiandanSigned(storedPdf.is_signed === true);
} else {
// 如果 localStorage 中没有导检单,调用接口获取未签名的导检单用于查看和签名
const fetchDaojiandan = async () => {
try {
const res = await getDaojiandanPdfApi({ exam_id: examId });
if (res.Status === 200 && res.Data?.pdf_url) {
const pdfUrlValue = res.Data.pdf_url;
// 不保存到 localStorage只用于显示和签名
setDaojiandanUrl(pdfUrlValue);
setIsDaojiandanSigned(false); // 接口获取的是未签名的
}
} catch (err) {
console.error('获取导检单失败', err);
}
};
fetchDaojiandan();
}
// 检查加项单PDF可能有多个
const storedAddItemBillList = getAddItemBillPdfFromStorage(examId);
if (storedAddItemBillList && storedAddItemBillList.length > 0) {
setAddItemBillList(storedAddItemBillList);
// 默认选中第一个未签名的加项单,如果都已签名则选中第一个
const unsigned = storedAddItemBillList.find((item) => item.is_signed !== true);
setCurrentAddItemBill(unsigned || storedAddItemBillList[0]);
} else {
// 没有加项单:不再主动调用接口获取,因为新接口需要 CombinationCode仅支付时知道
setAddItemBillList([]);
setCurrentAddItemBill(null);
}
}, [examId]);
// 加载 PDF 数据 // 加载 PDF 数据
useEffect(() => { useEffect(() => {
if (!previewPdf?.pdf_url) { if (!previewPdf?.pdf_url) {
@@ -1026,16 +976,6 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
setDaojiandanUrl(pdfUrlValue); setDaojiandanUrl(pdfUrlValue);
setIsDaojiandanSigned(true); // 签名成功后标记为已签名 setIsDaojiandanSigned(true); // 签名成功后标记为已签名
// 保存导检单PDF信息到localStorage标记为已签名
setDaojiandanPdf(examId, {
pdf_name: pdfNameValue,
pdf_url: pdfUrlValue,
is_signed: true,
});
// 记录打印导检单是否签名操作
setExamActionRecord(examId, 'printSign', true);
// 更新导检单打印状态 // 更新导检单打印状态
try { try {
await editDaojiandanPrintStatus({ exam_id: examId }); await editDaojiandanPrintStatus({ exam_id: examId });
@@ -1090,43 +1030,36 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
sign_file: blob, sign_file: blob,
}); });
if (res.Status === 200 && res.Data?.pdf_url) { if (res.Status === 200) {
setAddItemBillSubmitMessage('签名提交成功'); setAddItemBillSubmitMessage('签名提交成功');
const pdfUrlValue = res.Data.pdf_url;
const pdfNameValue = res.Data.pdf_name || '加项单';
// 更新当前加项单为已签名,并更新本地列表与 localStorage
setAddItemBillList((prev) => {
const next = prev.map((item) => {
if (item.pdf_sort === currentAddItemBill.pdf_sort) {
const updated: AddItemBillPdfInfo = {
...item,
pdf_name: pdfNameValue,
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,
};
// 同步写入 localStorage
setAddItemBillPdf(examId, updated);
return updated;
}
return item;
});
return next;
});
setCurrentAddItemBill((prev) => // 签名成功后刷新统一 PDF 列表,获取最新的加项单签名状态和地址
prev && prev.pdf_sort === currentAddItemBill.pdf_sort if (examId) {
? { try {
...prev, const refreshRes = await getTijianPdfFile({ exam_id: examId as number });
pdf_name: pdfNameValue, const list: OutputTijianPdfFileInfo[] = refreshRes.Data || [];
pdf_url: pdfUrlValue, const addItemFromApi = list.filter((item) => item.pdf_type === 3);
payment_status: res.Data?.payment_status ?? prev.payment_status ?? null, if (addItemFromApi.length > 0) {
payment_status_name: res.Data?.payment_status_name ?? prev.payment_status_name ?? null, const addItemList: AddItemBillItem[] = addItemFromApi.map((item) => ({
is_signed: true, pdf_sort: item.combination_code ?? 0,
combinationCode: String(item.combination_code ?? ''),
payment_status: item.is_pay != null ? String(item.is_pay) : null,
payment_status_name: item.is_pay_name ?? null,
pdf_name: item.pdf_name || '加项单',
pdf_url: item.sign_pdf_url || item.pdf_url || '',
is_signed: item.is_sign === 1,
}));
setAddItemBillList(addItemList);
const unsigned = addItemList.find((bill) => bill.is_signed !== true);
setCurrentAddItemBill(unsigned || addItemList[0] || null);
} else {
setAddItemBillList([]);
setCurrentAddItemBill(null);
} }
: prev } catch (e) {
); console.error('刷新加项单列表失败', e);
}
}
setTimeout(() => { setTimeout(() => {
setShowAddItemBillSignature(false); setShowAddItemBillSignature(false);
@@ -1146,7 +1079,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
}; };
// 加项单直接打印 // 加项单直接打印
const handleAddItemBillDirectPrint = async (target: AddItemBillPdfInfo | null) => { const handleAddItemBillDirectPrint = async (target: AddItemBillItem | null) => {
if (!target?.pdf_url) return; if (!target?.pdf_url) return;
try { try {
@@ -1443,23 +1376,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
for (const item of consentList) { for (const item of consentList) {
if (item.combination_code === undefined || item.combination_code === null) continue; if (item.combination_code === undefined || item.combination_code === null) continue;
if (!signedCombinationCodes.includes(Number(item.combination_code))) continue; if (!signedCombinationCodes.includes(Number(item.combination_code))) continue;
const targetUrl = item.pdf_url;
let targetUrl = item.pdf_url;
// 如果本地已保存签名后的PDF列表则优先使用签名后的PDF地址
if (examId) {
const storedList = getTongyishuPdfList(examId);
if (storedList && item.combination_code !== undefined && item.combination_code !== null) {
const code = Number(item.combination_code);
const matched = storedList.find(
(pdf) => pdf.combination_code !== null && Number(pdf.combination_code) === code,
);
if (matched && matched.pdf_url) {
targetUrl = matched.pdf_url;
}
}
}
if (!targetUrl) continue; if (!targetUrl) continue;
try { try {
@@ -1769,24 +1686,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
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;
let target = item; handleDirectPrint(item);
// 如果本地已保存签名后的PDF列表则优先使用签名后的PDF地址
if (examId) {
const storedList = getTongyishuPdfList(examId);
if (storedList && item.combination_code !== undefined && item.combination_code !== null) {
const code = Number(item.combination_code);
const matched = storedList.find(
(pdf) => pdf.combination_code !== null && Number(pdf.combination_code) === code,
);
if (matched && matched.pdf_url) {
target = {
...item,
pdf_url: matched.pdf_url,
};
}
}
}
handleDirectPrint(target);
}} }}
disabled={busy} disabled={busy}
> >
@@ -1798,26 +1698,7 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
onClick={() => { onClick={() => {
if (busy) return; if (busy) return;
let target = item; setPreviewPdf(item);
// 如果本地已保存签名后的PDF列表则优先使用签名后的PDF地址
if (examId) {
const storedList = getTongyishuPdfList(examId);
if (storedList && item.combination_code !== undefined && item.combination_code !== null) {
const code = Number(item.combination_code);
const matched = storedList.find(
(pdf) => pdf.combination_code !== null && Number(pdf.combination_code) === code,
);
if (matched && matched.pdf_url) {
target = {
...item,
pdf_url: matched.pdf_url,
};
}
}
}
setPreviewPdf(target);
}} }}
disabled={busy} disabled={busy}
> >
@@ -2128,6 +2009,17 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
> >
</Button> </Button>
<Button
className='py-1 px-3 hover:bg-blue-700 text-white'
onClick={() => {
if (busy) return;
setShowDaojiandanPreview(false);
setShowDaojiandanSignature(true);
}}
disabled={busy}
>
</Button>
<Button className='py-1 px-3' onClick={() => !busy && setShowDaojiandanPreview(false)} disabled={busy}> <Button className='py-1 px-3' onClick={() => !busy && setShowDaojiandanPreview(false)} disabled={busy}>
</Button> </Button>
@@ -2217,19 +2109,17 @@ export const ExamSignPanel = ({ examId, onBusyChange }: ExamSignPanelProps) => {
</Button> </Button>
)} )}
{!currentAddItemBill.is_signed && ( <Button
<Button className='py-1 px-3 hover:bg-blue-700 text-white'
className='py-1 px-3 bg-blue-600 hover:bg-blue-700 text-white' onClick={() => {
onClick={() => { if (busy) return;
if (busy) return; setShowAddItemBillPreview(false);
setShowAddItemBillPreview(false); setShowAddItemBillSignature(true);
setShowAddItemBillSignature(true); }}
}} disabled={busy}
disabled={busy} >
>
</Button>
</Button>
)}
<Button className='py-1 px-3' onClick={() => !busy && setShowAddItemBillPreview(false)} disabled={busy}> <Button className='py-1 px-3' onClick={() => !busy && setShowAddItemBillPreview(false)} disabled={busy}>
</Button> </Button>

View File

@@ -40,20 +40,9 @@ export interface ExamActionRecord {
/** /**
* 获取操作记录 * 获取操作记录
*/ */
export const getExamActionRecord = (examId: string | number): ExamActionRecord | null => { export const getExamActionRecord = (_examId: string | number): ExamActionRecord | null => {
if (typeof window === 'undefined') return null; // 已废弃,不再从本地存储读取
return null;
const key = getExamActionKey(examId);
const raw = localStorage.getItem(key);
if (!raw) return null;
try {
const parsed = JSON.parse(raw);
return parsed as ExamActionRecord;
} catch (err) {
console.warn('操作记录解析失败', err);
return null;
}
}; };
/** /**
@@ -64,223 +53,13 @@ export const setExamActionRecord = (
action: keyof ExamActionRecord, action: keyof ExamActionRecord,
value: boolean = true value: boolean = true
): void => { ): void => {
if (typeof window === 'undefined') return; // 已废弃,不再写入本地存储
const key = getExamActionKey(examId);
const existing = getExamActionRecord(examId) || {};
const updated: ExamActionRecord = {
...existing,
[action]: value,
timestamp: new Date().toISOString(),
};
localStorage.setItem(key, JSON.stringify(updated));
}; };
/** /**
* 检查操作是否已完成 * 检查操作是否已完成
*/ */
export const isExamActionDone = (examId: string | number, action: keyof ExamActionRecord): boolean => { export const isExamActionDone = (examId: string | number, action: keyof ExamActionRecord): boolean => {
const record = getExamActionRecord(examId); // 已废弃,统一由实时数据决定
return record?.[action] === true; return false;
}; };
/**
* 知情同意书PDF信息
*/
export interface TongyishuPdfInfo {
/** PDF文件名称 */
pdf_name: string;
/** PDF文件地址 */
pdf_url: string;
/** 组合代码 */
combination_code?: number | null;
/** 是否已签名 */
is_signed?: boolean;
}
/**
* 获取知情同意书PDF列表的存储 key
*/
export const getTongyishuPdfListKey = (examId: string | number): string => {
const today = getTodayString();
return `yh_tongyishu_pdf_list_${today}_${examId}`;
};
/**
* 存储知情同意书PDF列表
*/
export const setTongyishuPdfList = (
examId: string | number,
pdfList: TongyishuPdfInfo[]
): void => {
if (typeof window === 'undefined') return;
const key = getTongyishuPdfListKey(examId);
localStorage.setItem(key, JSON.stringify(pdfList));
};
/**
* 获取知情同意书PDF列表
*/
export const getTongyishuPdfList = (examId: string | number): TongyishuPdfInfo[] | null => {
if (typeof window === 'undefined') return null;
const key = getTongyishuPdfListKey(examId);
const raw = localStorage.getItem(key);
if (!raw) return null;
try {
const parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed as TongyishuPdfInfo[] : null;
} catch (err) {
console.warn('知情同意书PDF列表解析失败', err);
return null;
}
};
/**
* 导检单PDF信息
*/
export interface DaojiandanPdfInfo {
/** PDF文件名称 */
pdf_name: string;
/** PDF文件地址 */
pdf_url: string;
/** 是否已签名 */
is_signed?: boolean;
}
/**
* 获取导检单PDF的存储 key
*/
export const getDaojiandanPdfKey = (examId: string | number): string => {
const today = getTodayString();
return `yh_daojiandan_pdf_${today}_${examId}`;
};
/**
* 存储导检单PDF信息
*/
export const setDaojiandanPdf = (
examId: string | number,
pdfInfo: DaojiandanPdfInfo
): void => {
if (typeof window === 'undefined') return;
const key = getDaojiandanPdfKey(examId);
localStorage.setItem(key, JSON.stringify(pdfInfo));
};
/**
* 获取导检单PDF信息
*/
export const getDaojiandanPdf = (examId: string | number): DaojiandanPdfInfo | null => {
if (typeof window === 'undefined') return null;
const key = getDaojiandanPdfKey(examId);
const raw = localStorage.getItem(key);
if (!raw) return null;
try {
const parsed = JSON.parse(raw);
return parsed as DaojiandanPdfInfo;
} catch (err) {
console.warn('导检单PDF信息解析失败', err);
return null;
}
};
/**
* 加项单PDF信息
*/
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_name: string;
/** PDF文件地址 */
pdf_url: string;
/** 是否已签名 */
is_signed?: boolean;
}
/**
* 获取加项单PDF的存储 key
*/
export const getAddItemBillPdfKey = (examId: string | number): string => {
const today = getTodayString();
return `yh_add_item_bill_pdf_${today}_${examId}`;
};
/**
* 存储加项单PDF信息
*/
export const setAddItemBillPdf = (
examId: string | number,
pdfInfo: AddItemBillPdfInfo
): void => {
if (typeof window === 'undefined') return;
const key = getAddItemBillPdfKey(examId);
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信息
*/
export const getAddItemBillPdf = (examId: string | number): AddItemBillPdfInfo[] | null => {
if (typeof window === 'undefined') return null;
const key = getAddItemBillPdfKey(examId);
const raw = localStorage.getItem(key);
if (!raw) return null;
try {
const parsed = JSON.parse(raw);
if (Array.isArray(parsed)) {
return parsed as AddItemBillPdfInfo[];
}
if (parsed && typeof parsed === 'object') {
// 兼容旧版本(单个对象)
return [parsed as AddItemBillPdfInfo];
}
return null;
} catch (err) {
console.warn('加项单PDF信息解析失败', err);
return null;
}
};