更新打印
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 { Document, Page } from "react-pdf";
|
||||||
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
|
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
|
||||||
import "./UI8.css";
|
import "./UI8.css";
|
||||||
@@ -10,6 +10,10 @@ import ui8A from "../../assets/ui8A.png";
|
|||||||
import ui8B from "../../assets/ui8B.png";
|
import ui8B from "../../assets/ui8B.png";
|
||||||
import { getDaojiandanPdf } from "../../api/hisApi";
|
import { getDaojiandanPdf } from "../../api/hisApi";
|
||||||
|
|
||||||
|
const PREFERRED_PRINTER_KEY = "preferredPrinterName";
|
||||||
|
|
||||||
|
type PrinterInfo = ElectronPrinterInfo;
|
||||||
|
|
||||||
// 独立的 PDF 渲染组件,使用 React.memo 避免不必要的重新渲染
|
// 独立的 PDF 渲染组件,使用 React.memo 避免不必要的重新渲染
|
||||||
const PdfRenderer = React.memo<{
|
const PdfRenderer = React.memo<{
|
||||||
pdfFiles: string[];
|
pdfFiles: string[];
|
||||||
@@ -62,6 +66,13 @@ const UI8: React.FC = () => {
|
|||||||
const [pdfFiles, setPdfFiles] = useState<string[]>([]);
|
const [pdfFiles, setPdfFiles] = useState<string[]>([]);
|
||||||
const [pageCounts, setPageCounts] = useState<Record<number, number>>({});
|
const [pageCounts, setPageCounts] = useState<Record<number, number>>({});
|
||||||
const [originPdfUrls, setOriginPdfUrls] = useState<string[]>([]);
|
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 getExamId = () => {
|
||||||
const storedId = localStorage.getItem("selectedExamId");
|
const storedId = localStorage.getItem("selectedExamId");
|
||||||
@@ -118,15 +129,20 @@ const UI8: React.FC = () => {
|
|||||||
setPageCounts({});
|
setPageCounts({});
|
||||||
|
|
||||||
const examId = getExamId();
|
const examId = getExamId();
|
||||||
window.electronAPI?.log("info", `[UI8] 开始获取导检单 PDF,exam_id=${examId}`);
|
let pdfUrl = "";
|
||||||
const res = await getDaojiandanPdf(parseInt(examId, 10));
|
const consentSignature = localStorage.getItem("consentSignature");
|
||||||
if (res.Status !== 200) {
|
if (consentSignature) {
|
||||||
throw new Error(res.Message || "获取导检单PDF失败");
|
pdfUrl = consentSignature;
|
||||||
}
|
} else {
|
||||||
|
window.electronAPI?.log("info", `[UI8] 开始获取导检单 PDF,exam_id=${examId}`);
|
||||||
const pdfUrl = res.Data?.pdf_url;
|
const res = await getDaojiandanPdf(parseInt(examId, 10));
|
||||||
if (!pdfUrl) {
|
if (res.Status !== 200) {
|
||||||
throw new Error("未获取到导检单 PDF");
|
throw new Error(res.Message || "获取导检单PDF失败");
|
||||||
|
}
|
||||||
|
pdfUrl = res.Data?.pdf_url;
|
||||||
|
if (!pdfUrl) {
|
||||||
|
throw new Error("未获取到导检单 PDF");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setOriginPdfUrls([pdfUrl]);
|
setOriginPdfUrls([pdfUrl]);
|
||||||
@@ -147,6 +163,107 @@ const UI8: React.FC = () => {
|
|||||||
loadPdf();
|
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(() => {
|
const handleBack = useCallback(() => {
|
||||||
navigate(-1);
|
navigate(-1);
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
@@ -168,6 +285,11 @@ const UI8: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (printers.length > 0 && !selectedPrinter) {
|
||||||
|
alert("请先选择打印机");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsPrinting(true);
|
setIsPrinting(true);
|
||||||
try {
|
try {
|
||||||
const printData =
|
const printData =
|
||||||
@@ -176,10 +298,13 @@ const UI8: React.FC = () => {
|
|||||||
: originPdfUrls[0];
|
: originPdfUrls[0];
|
||||||
const dataType = printData.startsWith("data:") ? "base64数据" : "远程文件路径";
|
const dataType = printData.startsWith("data:") ? "base64数据" : "远程文件路径";
|
||||||
window.electronAPI.log("info", `开始打印PDF (${dataType}): ${printData.substring(0, 100)}...`);
|
window.electronAPI.log("info", `开始打印PDF (${dataType}): ${printData.substring(0, 100)}...`);
|
||||||
|
|
||||||
const result = await window.electronAPI.printPdf(printData);
|
const printResult = await window.electronAPI.printPdf(
|
||||||
if (!result.success) {
|
printData,
|
||||||
const errorMsg = `打印失败: ${result.error || "未知错误"}`;
|
selectedPrinter ? { printerName: selectedPrinter } : undefined
|
||||||
|
);
|
||||||
|
if (!printResult.success) {
|
||||||
|
const errorMsg = `打印失败: ${printResult.error || "未知错误"}`;
|
||||||
window.electronAPI.log("error", errorMsg);
|
window.electronAPI.log("error", errorMsg);
|
||||||
alert(errorMsg);
|
alert(errorMsg);
|
||||||
} else {
|
} else {
|
||||||
@@ -194,7 +319,7 @@ const UI8: React.FC = () => {
|
|||||||
setIsPrinting(false);
|
setIsPrinting(false);
|
||||||
navigate("/UI9");
|
navigate("/UI9");
|
||||||
}
|
}
|
||||||
}, [originPdfUrls, pdfFiles]);
|
}, [originPdfUrls, pdfFiles, printers.length, selectedPrinter]);
|
||||||
|
|
||||||
const handlePageCountUpdate = useCallback((index: number, numPages: number) => {
|
const handlePageCountUpdate = useCallback((index: number, numPages: number) => {
|
||||||
window.electronAPI?.log("info", `[UI8] PDF渲染成功 (index=${index}),共 ${numPages} 页`);
|
window.electronAPI?.log("info", `[UI8] PDF渲染成功 (index=${index}),共 ${numPages} 页`);
|
||||||
@@ -216,6 +341,59 @@ const UI8: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="basic-root">
|
<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-white-block">
|
||||||
<div className="basic-content">
|
<div className="basic-content">
|
||||||
<div className="ui8-pdf-container">
|
<div className="ui8-pdf-container">
|
||||||
@@ -230,14 +408,14 @@ const UI8: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ui8-right-section">
|
<div className="ui8-right-section">
|
||||||
<img src={ui8A} alt="" />
|
<img src={ui8A} alt="" />
|
||||||
<img src={ui8B} alt="" />
|
<img src={ui8B} alt="" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="basic-confirm-section">
|
<div className="basic-confirm-section">
|
||||||
<BackButton text="返回" onClick={handleBack} />
|
<BackButton text="返回" onClick={handleBack} />
|
||||||
<ConfirmButton
|
<ConfirmButton
|
||||||
text={isPrinting ? "打印中..." : "打印"}
|
text={isPrinting ? "打印中..." : "打印"}
|
||||||
onClick={handleConfirm}
|
onClick={handleConfirm}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user