更新打印
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { Document, Page } from "react-pdf";
|
||||
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
|
||||
import "./UI8.css";
|
||||
@@ -10,6 +10,10 @@ import ui8A from "../../assets/ui8A.png";
|
||||
import ui8B from "../../assets/ui8B.png";
|
||||
import { getDaojiandanPdf } from "../../api/hisApi";
|
||||
|
||||
const PREFERRED_PRINTER_KEY = "preferredPrinterName";
|
||||
|
||||
type PrinterInfo = ElectronPrinterInfo;
|
||||
|
||||
// 独立的 PDF 渲染组件,使用 React.memo 避免不必要的重新渲染
|
||||
const PdfRenderer = React.memo<{
|
||||
pdfFiles: string[];
|
||||
@@ -62,6 +66,13 @@ const UI8: React.FC = () => {
|
||||
const [pdfFiles, setPdfFiles] = useState<string[]>([]);
|
||||
const [pageCounts, setPageCounts] = useState<Record<number, number>>({});
|
||||
const [originPdfUrls, setOriginPdfUrls] = useState<string[]>([]);
|
||||
const [printers, setPrinters] = useState<PrinterInfo[]>([]);
|
||||
const [selectedPrinter, setSelectedPrinter] = useState<string>("");
|
||||
const [printersLoading, setPrintersLoading] = useState<boolean>(false);
|
||||
const [printerError, setPrinterError] = useState<string>("");
|
||||
const [isPrinterDropdownOpen, setIsPrinterDropdownOpen] =
|
||||
useState<boolean>(false);
|
||||
const printerDropdownRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const getExamId = () => {
|
||||
const storedId = localStorage.getItem("selectedExamId");
|
||||
@@ -118,15 +129,20 @@ const UI8: React.FC = () => {
|
||||
setPageCounts({});
|
||||
|
||||
const examId = getExamId();
|
||||
window.electronAPI?.log("info", `[UI8] 开始获取导检单 PDF,exam_id=${examId}`);
|
||||
const res = await getDaojiandanPdf(parseInt(examId, 10));
|
||||
if (res.Status !== 200) {
|
||||
throw new Error(res.Message || "获取导检单PDF失败");
|
||||
}
|
||||
|
||||
const pdfUrl = res.Data?.pdf_url;
|
||||
if (!pdfUrl) {
|
||||
throw new Error("未获取到导检单 PDF");
|
||||
let pdfUrl = "";
|
||||
const consentSignature = localStorage.getItem("consentSignature");
|
||||
if (consentSignature) {
|
||||
pdfUrl = consentSignature;
|
||||
} else {
|
||||
window.electronAPI?.log("info", `[UI8] 开始获取导检单 PDF,exam_id=${examId}`);
|
||||
const res = await getDaojiandanPdf(parseInt(examId, 10));
|
||||
if (res.Status !== 200) {
|
||||
throw new Error(res.Message || "获取导检单PDF失败");
|
||||
}
|
||||
pdfUrl = res.Data?.pdf_url;
|
||||
if (!pdfUrl) {
|
||||
throw new Error("未获取到导检单 PDF");
|
||||
}
|
||||
}
|
||||
|
||||
setOriginPdfUrls([pdfUrl]);
|
||||
@@ -147,6 +163,107 @@ const UI8: React.FC = () => {
|
||||
loadPdf();
|
||||
}, []);
|
||||
|
||||
// 加载打印机列表并恢复上次选择
|
||||
useEffect(() => {
|
||||
if (!window.electronAPI?.getPrinters) {
|
||||
setPrinterError("当前环境不支持打印机列表读取");
|
||||
return;
|
||||
}
|
||||
|
||||
let isMounted = true;
|
||||
const fetchPrinters = async () => {
|
||||
setPrintersLoading(true);
|
||||
try {
|
||||
window.electronAPI.log("info", "[UI8] 开始获取打印机列表");
|
||||
const result = await window.electronAPI.getPrinters();
|
||||
if (!isMounted) return;
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "获取打印机列表失败");
|
||||
}
|
||||
|
||||
const list = result.printers || [];
|
||||
setPrinters(list);
|
||||
|
||||
const stored = localStorage.getItem(PREFERRED_PRINTER_KEY);
|
||||
const matchedStored =
|
||||
stored && list.some((printer) => printer.name === stored)
|
||||
? stored
|
||||
: "";
|
||||
const defaultPrinter =
|
||||
matchedStored ||
|
||||
list.find((printer) => printer.isDefault)?.name ||
|
||||
list[0]?.name ||
|
||||
"";
|
||||
|
||||
if (defaultPrinter) {
|
||||
setSelectedPrinter(defaultPrinter);
|
||||
localStorage.setItem(PREFERRED_PRINTER_KEY, defaultPrinter);
|
||||
window.electronAPI.log(
|
||||
"info",
|
||||
`[UI8] 默认打印机设置为 ${defaultPrinter}`
|
||||
);
|
||||
}
|
||||
setPrinterError("");
|
||||
} catch (error) {
|
||||
const msg =
|
||||
(error as Error).message || "打印机列表获取失败,请联系管理员";
|
||||
if (isMounted) {
|
||||
setPrinterError(msg);
|
||||
}
|
||||
window.electronAPI.log("error", `[UI8] ${msg}`);
|
||||
} finally {
|
||||
if (isMounted) {
|
||||
setPrintersLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchPrinters();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handlePrinterChange = useCallback(
|
||||
(printerName: string) => {
|
||||
setSelectedPrinter(printerName);
|
||||
localStorage.setItem(PREFERRED_PRINTER_KEY, printerName);
|
||||
window.electronAPI?.log(
|
||||
"info",
|
||||
`[UI8] 用户选择打印机: ${printerName}`
|
||||
);
|
||||
setIsPrinterDropdownOpen(false);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
printerDropdownRef.current &&
|
||||
!printerDropdownRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsPrinterDropdownOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isPrinterDropdownOpen) {
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
} else {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, [isPrinterDropdownOpen]);
|
||||
|
||||
const togglePrinterDropdown = useCallback(() => {
|
||||
if (printersLoading || printers.length === 0) return;
|
||||
setIsPrinterDropdownOpen((prev) => !prev);
|
||||
}, [printers.length, printersLoading]);
|
||||
|
||||
const handleBack = useCallback(() => {
|
||||
navigate(-1);
|
||||
}, [navigate]);
|
||||
@@ -168,6 +285,11 @@ const UI8: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (printers.length > 0 && !selectedPrinter) {
|
||||
alert("请先选择打印机");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsPrinting(true);
|
||||
try {
|
||||
const printData =
|
||||
@@ -176,10 +298,13 @@ const UI8: React.FC = () => {
|
||||
: originPdfUrls[0];
|
||||
const dataType = printData.startsWith("data:") ? "base64数据" : "远程文件路径";
|
||||
window.electronAPI.log("info", `开始打印PDF (${dataType}): ${printData.substring(0, 100)}...`);
|
||||
|
||||
const result = await window.electronAPI.printPdf(printData);
|
||||
if (!result.success) {
|
||||
const errorMsg = `打印失败: ${result.error || "未知错误"}`;
|
||||
|
||||
const printResult = await window.electronAPI.printPdf(
|
||||
printData,
|
||||
selectedPrinter ? { printerName: selectedPrinter } : undefined
|
||||
);
|
||||
if (!printResult.success) {
|
||||
const errorMsg = `打印失败: ${printResult.error || "未知错误"}`;
|
||||
window.electronAPI.log("error", errorMsg);
|
||||
alert(errorMsg);
|
||||
} else {
|
||||
@@ -194,7 +319,7 @@ const UI8: React.FC = () => {
|
||||
setIsPrinting(false);
|
||||
navigate("/UI9");
|
||||
}
|
||||
}, [originPdfUrls, pdfFiles]);
|
||||
}, [originPdfUrls, pdfFiles, printers.length, selectedPrinter]);
|
||||
|
||||
const handlePageCountUpdate = useCallback((index: number, numPages: number) => {
|
||||
window.electronAPI?.log("info", `[UI8] PDF渲染成功 (index=${index}),共 ${numPages} 页`);
|
||||
@@ -216,6 +341,59 @@ const UI8: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="basic-root">
|
||||
<div className="ui8-printer-panel" ref={printerDropdownRef}>
|
||||
<div
|
||||
className={`ui8-printer-trigger ${printersLoading || printers.length === 0 ? "disabled" : ""
|
||||
} ${isPrinterDropdownOpen ? "open" : ""}`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={togglePrinterDropdown}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
togglePrinterDropdown();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
{printersLoading
|
||||
? "打印机加载中..."
|
||||
: selectedPrinter
|
||||
? printers.find((p) => p.name === selectedPrinter)?.displayName ||
|
||||
selectedPrinter
|
||||
: printers.length === 0
|
||||
? "未检测到打印机"
|
||||
: "请选择打印机"}
|
||||
</span>
|
||||
<span className="ui8-printer-arrow" />
|
||||
</div>
|
||||
{isPrinterDropdownOpen && printers.length > 0 && (
|
||||
<div className="ui8-printer-options">
|
||||
{printers.map((printer) => (
|
||||
<div
|
||||
key={printer.name}
|
||||
className={`ui8-printer-option ${printer.name === selectedPrinter ? "active" : ""
|
||||
}`}
|
||||
onClick={() => handlePrinterChange(printer.name)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
handlePrinterChange(printer.name);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{printer.displayName || printer.name}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{printerError && (
|
||||
<div className="ui8-printer-error">{printerError}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="basic-white-block">
|
||||
<div className="basic-content">
|
||||
<div className="ui8-pdf-container">
|
||||
@@ -230,14 +408,14 @@ const UI8: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="ui8-right-section">
|
||||
<img src={ui8A} alt="" />
|
||||
<img src={ui8B} alt="" />
|
||||
<img src={ui8A} alt="" />
|
||||
<img src={ui8B} alt="" />
|
||||
</div>
|
||||
|
||||
<div className="basic-confirm-section">
|
||||
<BackButton text="返回" onClick={handleBack} />
|
||||
<ConfirmButton
|
||||
text={isPrinting ? "打印中..." : "打印"}
|
||||
<ConfirmButton
|
||||
text={isPrinting ? "打印中..." : "打印"}
|
||||
onClick={handleConfirm}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user