From 43d10332961d1ae43b8debe70a50dae17c7d8cd7 Mon Sep 17 00:00:00 2001 From: xianyi Date: Thu, 27 Nov 2025 16:32:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/UI8/UI8.tsx | 216 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 197 insertions(+), 19 deletions(-) diff --git a/src/pages/UI8/UI8.tsx b/src/pages/UI8/UI8.tsx index 4764171..7623cb6 100644 --- a/src/pages/UI8/UI8.tsx +++ b/src/pages/UI8/UI8.tsx @@ -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([]); const [pageCounts, setPageCounts] = useState>({}); const [originPdfUrls, setOriginPdfUrls] = useState([]); + const [printers, setPrinters] = useState([]); + const [selectedPrinter, setSelectedPrinter] = useState(""); + const [printersLoading, setPrintersLoading] = useState(false); + const [printerError, setPrinterError] = useState(""); + const [isPrinterDropdownOpen, setIsPrinterDropdownOpen] = + useState(false); + const printerDropdownRef = useRef(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 (
+
+
{ + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + togglePrinterDropdown(); + } + }} + > + + {printersLoading + ? "打印机加载中..." + : selectedPrinter + ? printers.find((p) => p.name === selectedPrinter)?.displayName || + selectedPrinter + : printers.length === 0 + ? "未检测到打印机" + : "请选择打印机"} + + +
+ {isPrinterDropdownOpen && printers.length > 0 && ( +
+ {printers.map((printer) => ( +
handlePrinterChange(printer.name)} + role="button" + tabIndex={0} + onKeyDown={(event) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + handlePrinterChange(printer.name); + } + }} + > + {printer.displayName || printer.name} +
+ ))} +
+ )} + {printerError && ( +
{printerError}
+ )} +
+
@@ -230,14 +408,14 @@ const UI8: React.FC = () => {
- - + +
-