优化bug

This commit is contained in:
24kycj
2026-09-09 10:36:42 +08:00
parent 19858f9a62
commit ac566846c9
36 changed files with 1325 additions and 290 deletions
+8 -16
View File
@@ -1,4 +1,4 @@
import { app, BrowserWindow, dialog, globalShortcut, screen } from 'electron'
import { app, BrowserWindow, dialog, globalShortcut } from 'electron'
import { join } from 'path'
app.commandLine.appendSwitch('disable-gpu-shader-disk-cache')
@@ -14,10 +14,12 @@ if (!gotSingleInstanceLock) {
app.quit()
}
import { ensureConsoleUtf8 } from './utils/ensure-console-utf8'
import { suppressKnownDllStderr } from './utils/suppress-dll-stderr'
import { loadAppFileConfig, applyFileConfigToStore } from './services/app-config'
import { migrateTraceConfig, setTraceWebContents } from './utils/trace-bridge'
ensureConsoleUtf8()
suppressKnownDllStderr()
process.on('uncaughtException', (err) => {
@@ -41,24 +43,12 @@ function focusMainWindow(): void {
mainWindow.focus()
}
function getDefaultWindowSize(): { width: number; height: number } {
const { width: sw, height: sh } = screen.getPrimaryDisplay().workAreaSize
let w = Math.max(1280, Math.min(Math.floor(sw * 0.85), 1600))
let h = contentHeightForWidth(w)
const maxH = Math.floor(sh * 0.85)
if (h > maxH) {
h = Math.max(contentHeightForWidth(MIN_CONTENT_WIDTH), maxH)
w = Math.round((h * DESIGN_WIDTH) / DESIGN_HEIGHT)
}
return { width: w, height: h }
}
function createWindow(): void {
const { width, height } = getDefaultWindowSize()
// 目标设备屏幕为 720x360,窗口默认 1:1 显示设计稿大小
mainWindow = new BrowserWindow({
useContentSize: true,
width,
height,
width: DESIGN_WIDTH,
height: DESIGN_HEIGHT,
minWidth: MIN_CONTENT_WIDTH,
minHeight: contentHeightForWidth(MIN_CONTENT_WIDTH),
show: false,
@@ -94,6 +84,8 @@ function createWindow(): void {
mainWindow.on('resize', () => {
if (!mainWindow) return
// 最大化时让窗口填满屏幕,不强制 2:1 内容比例
if (mainWindow.isMaximized()) return
const [cw, ch] = mainWindow.getContentSize()
const wantH = contentHeightForWidth(cw)
if (Math.abs(ch - wantH) > 2) {
+29 -1
View File
@@ -107,7 +107,9 @@ export function registerIpcHandlers(): void {
ribbonType: cached?.ribbonType ?? '—',
ribbonAmount: cached?.ribbonAmount ?? '—',
statusText: parsed.statusText,
serialNo: cached?.serialNo ?? '—'
serialNo: cached?.serialNo ?? '—',
printerName: cached?.printerName ?? '—',
isSingleSide: cached?.isSingleSide ?? false
}
configStore.set('lastPrinterStatus', snapshot)
return ok({ statusText: parsed.statusText, statusCode: code })
@@ -152,6 +154,32 @@ export function registerIpcHandlers(): void {
}
})
// 读卡:移动卡片到读取区(SAPI_PrinterMovetousbreader
tracedHandle('dll:printer-read-card', async () => {
try {
assertReady()
const dll = await loadDllModule()
if (!dll.isUsbReaderApiAvailable()) return fail(CS_FAIL, 'USB_READER_API_UNAVAILABLE')
const code = dll.dllPrinterMoveToUsbReader()
return code === CS_OK ? ok() : fail(code, '读卡失败')
} catch (err) {
return fail(CS_FAIL, String(err))
}
})
// 退卡:移动卡片到出卡区(SAPI_PrinterMovetohopper
tracedHandle('dll:printer-eject-card', async () => {
try {
assertReady()
const dll = await loadDllModule()
if (!dll.isHopperApiAvailable()) return fail(CS_FAIL, 'HOPPER_API_UNAVAILABLE')
const code = dll.dllPrinterMoveToHopper()
return code === CS_OK ? ok() : fail(code, '退卡失败')
} catch (err) {
return fail(CS_FAIL, String(err))
}
})
tracedHandle('dll:printer-error-str', async (_e, errorNo?: number) => {
if (!mainAppState.initialized) return ok({ text: '' })
try {
+3 -1
View File
@@ -23,7 +23,9 @@ export async function openDesignApp(
const target = path.resolve(exePath.trim())
const err = await shell.openPath(target)
if (err) {
return { ok: false, message: err }
// 用户在 UAC/系统弹窗中点击"否"或被系统拒绝时,shell.openPath 返回通用错误字符串
// 不把原始 "Failed to Open Path" 直接抛给用户,给出可读说明
return { ok: false, message: '打开设计软件失败,可能已被取消或需要管理员权限' }
}
return { ok: true }
}
+41 -1
View File
@@ -24,6 +24,8 @@ let SAPI_Init: any = null
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let SAPI_GetPrinterInfo: any = null
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let SAPI_FreePrinterInfo: any = null
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let SAPI_GetPrinterErrorStr: any = null
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let SAPI_RestJobEx: any = null
@@ -77,6 +79,20 @@ function traceCall<T>(name: string, args: Record<string, unknown> | undefined, f
}
}
function freePrinterInfoPtr(ptr: number): void {
if (!ptr) return
// DLL 堆分配的缓冲区必须用 DLL 导出的释放函数;koffi.free 会触发 STATUS_HEAP_CORRUPTION
if (SAPI_FreePrinterInfo) {
try {
SAPI_FreePrinterInfo(ptr)
} catch (e) {
log.warn('SAPI_FreePrinterInfo failed', e)
}
return
}
log.warn('SAPI_FreePrinterInfo unavailable; printer info buffer not freed')
}
function readPrinterJsonFromOutPtr(len: number, outPtr: Buffer): { code: number; json?: Record<string, unknown> } {
if (len <= 0) return { code: len }
const ptr = koffi.decode(outPtr, 0, 'void *') as number
@@ -90,7 +106,7 @@ function readPrinterJsonFromOutPtr(len: number, outPtr: Buffer): { code: number;
return { code: len }
}
} finally {
koffi.free(ptr)
freePrinterInfoPtr(ptr)
}
}
@@ -110,6 +126,13 @@ function loadLibrary(): void {
SAPI_GetUsbCopyState = lib.func('int __stdcall SAPI_GetUsbCopyState(_Out_ int *, _Out_ int *)')
SAPI_PrinterResetprinter = lib.func('int __stdcall SAPI_PrinterResetprinter()')
try {
SAPI_FreePrinterInfo = lib.func('void __stdcall SAPI_FreePrinterInfo(void *)')
} catch {
SAPI_FreePrinterInfo = null
log.warn('SAPI_FreePrinterInfo not in workDll')
}
try {
SAPI_UploadFile = lib.func('int __stdcall SAPI_UploadFile(str, str, str)')
hasUploadApi = true
@@ -151,6 +174,15 @@ function loadLibrary(): void {
emitTrace('[dll] SAPI_PrinterMovetousbreader not in workDll (optional)')
}
try {
SAPI_PrinterMovetohopper = lib.func('int __stdcall SAPI_PrinterMovetohopper()')
hasHopperApi = true
} catch {
SAPI_PrinterMovetohopper = null
hasHopperApi = false
emitTrace('[dll] SAPI_PrinterMovetohopper not in workDll (optional)')
}
try {
SAPI_GetPrinterCardPosition = lib.func('int __stdcall SAPI_GetPrinterCardPosition(_Out_ int *)')
hasCardPositionApi = true
@@ -354,6 +386,14 @@ export function dllPrinterMoveToUsbReader(): number {
})
}
export function dllPrinterMoveToHopper(): number {
return traceCall('SAPI_PrinterMovetohopper', undefined, () => {
loadLibrary()
if (!SAPI_PrinterMovetohopper) throw new Error('HOPPER_API_UNAVAILABLE')
return SAPI_PrinterMovetohopper() as number
})
}
export function dllPrinterReject(): number {
return traceCall('SAPI_PrinterMovetoreject', undefined, () => {
loadLibrary()
+21
View File
@@ -0,0 +1,21 @@
import koffi from 'koffi'
/** Windows 控制台默认多为 GBKDLL 日志为 UTF-8,会导致中文乱码。 */
export function ensureConsoleUtf8(): void {
if (process.platform !== 'win32') return
try {
const kernel32 = koffi.load('kernel32.dll')
const SetConsoleOutputCP = kernel32.func('bool __stdcall SetConsoleOutputCP(uint32)')
const SetConsoleCP = kernel32.func('bool __stdcall SetConsoleCP(uint32)')
SetConsoleOutputCP(65001)
SetConsoleCP(65001)
} catch {
/* ignore: no console or API unavailable */
}
try {
if (process.stdout.setDefaultEncoding) process.stdout.setDefaultEncoding('utf8')
if (process.stderr.setDefaultEncoding) process.stderr.setDefaultEncoding('utf8')
} catch {
/* ignore */
}
}