Compare commits

...

2 Commits

Author SHA1 Message Date
24kycj 3918522831 chore: 更新 native 依赖
- 更新 workDll.dll

- 添加 OpenCV Release 版 opencv_world490.dll

- 添加 simhei.ttf 字体资源

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 23:21:55 +08:00
24kycj 7862ff2b2a fix: 测试联调四项修复
- 授权码并入加密狗行,password 掩码,窄宽样式

- 打印机信息仅调用 SAPI_GetPrinterInfo,移除 Ex 避免崩溃

- net_info 改为 JSON 数组,修复双重编码

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 21:08:37 +08:00
12 changed files with 42 additions and 63 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+9 -3
View File
@@ -47,7 +47,9 @@ eq('collectHosts local only', collectHostsForCopyPaths(['E:\\data'], {}), [])
const stored = new Map([['192.168.1.100', { userName: 'admin', password: 'pass', lastUsed: '' }]]) const stored = new Map([['192.168.1.100', { userName: 'admin', password: 'pass', lastUsed: '' }]])
const r1 = buildNetInfo([{ hostName: '192.168.1.100' }], (h) => stored.get(h) || null) const r1 = buildNetInfo([{ hostName: '192.168.1.100' }], (h) => stored.get(h) || null)
eq('buildNetInfo single', r1, '[{"host_name":"192.168.1.100","user_name":"admin","password":"pass"}]') eq('buildNetInfo single', r1, [
{ host_name: '192.168.1.100', user_name: 'admin', password: 'pass' }
])
const r2 = buildNetInfo( const r2 = buildNetInfo(
[ [
@@ -56,7 +58,7 @@ const r2 = buildNetInfo(
], ],
() => null () => null
) )
eq('buildNetInfo dedup', r2, '[{"host_name":"192.168.1.100","user_name":"a","password":"p"}]') eq('buildNetInfo dedup', r2, [{ host_name: '192.168.1.100', user_name: 'a', password: 'p' }])
let threw = false let threw = false
try { try {
@@ -65,7 +67,11 @@ try {
threw = e.message.includes('缺少网络凭据') threw = e.message.includes('缺少网络凭据')
} }
eq('buildNetInfo missing throws', threw, true) eq('buildNetInfo missing throws', threw, true)
eq('buildNetInfo empty list', buildNetInfo([], () => null), '') eq('buildNetInfo empty list', buildNetInfo([], () => null), [])
const jobBody = { net_info: r1 }
const jobParsed = JSON.parse(JSON.stringify(jobBody))
eq('net_info is array in job json', Array.isArray(jobParsed.net_info), true)
const pass = cases.filter((c) => c.ok).length const pass = cases.filter((c) => c.ok).length
const fail = cases.length - pass const fail = cases.length - pass
+1 -1
View File
@@ -68,7 +68,7 @@ export function registerIpcHandlers(): void {
return ok({ return ok({
...cached, ...cached,
fromCache: true, fromCache: true,
liveError: r.code <= 0 ? '未连接打印机' : `GetPrinterInfoEx code=${r.code}` liveError: r.code <= 0 ? '未连接打印机' : `GetPrinterInfo code=${r.code}`
}) })
} }
return fail(0, '未连接打印机') return fail(0, '未连接打印机')
+1 -32
View File
@@ -24,10 +24,6 @@ let SAPI_Init: any = null
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let SAPI_GetPrinterInfo: any = null let SAPI_GetPrinterInfo: any = null
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let SAPI_GetPrinterInfoEx: 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 let SAPI_GetPrinterErrorStr: any = null
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
let SAPI_RestJobEx: any = null let SAPI_RestJobEx: any = null
@@ -56,7 +52,6 @@ let hasCardPositionApi = false
let hasCheckstatusApi = false let hasCheckstatusApi = false
let hasCancelApi = false let hasCancelApi = false
let hasUploadApi = false let hasUploadApi = false
let hasPrinterInfoEx = false
let hasUsbReaderApi = false let hasUsbReaderApi = false
let loggedCancelMissing = false let loggedCancelMissing = false
let loggedRejectMissing = false let loggedRejectMissing = false
@@ -95,17 +90,9 @@ function readPrinterJsonFromOutPtr(len: number, outPtr: Buffer): { code: number;
return { code: len } return { code: len }
} }
} finally { } finally {
if (SAPI_FreePrinterInfo) {
try {
SAPI_FreePrinterInfo(ptr)
} catch (e) {
log.warn('SAPI_FreePrinterInfo', e)
}
} else {
koffi.free(ptr) koffi.free(ptr)
} }
} }
}
function loadLibrary(): void { function loadLibrary(): void {
if (lib) return if (lib) return
@@ -123,16 +110,6 @@ function loadLibrary(): void {
SAPI_GetUsbCopyState = lib.func('int __stdcall SAPI_GetUsbCopyState(_Out_ int *, _Out_ int *)') SAPI_GetUsbCopyState = lib.func('int __stdcall SAPI_GetUsbCopyState(_Out_ int *, _Out_ int *)')
SAPI_PrinterResetprinter = lib.func('int __stdcall SAPI_PrinterResetprinter()') SAPI_PrinterResetprinter = lib.func('int __stdcall SAPI_PrinterResetprinter()')
try {
SAPI_GetPrinterInfoEx = lib.func('int __stdcall SAPI_GetPrinterInfoEx(_Out_ void **)')
SAPI_FreePrinterInfo = lib.func('void __stdcall SAPI_FreePrinterInfo(void *)')
hasPrinterInfoEx = true
} catch {
SAPI_GetPrinterInfoEx = null
SAPI_FreePrinterInfo = null
hasPrinterInfoEx = false
}
try { try {
SAPI_UploadFile = lib.func('int __stdcall SAPI_UploadFile(str, str, str)') SAPI_UploadFile = lib.func('int __stdcall SAPI_UploadFile(str, str, str)')
hasUploadApi = true hasUploadApi = true
@@ -194,7 +171,6 @@ function loadLibrary(): void {
log.info('workDll loaded', { log.info('workDll loaded', {
upload: hasUploadApi, upload: hasUploadApi,
printerInfoEx: hasPrinterInfoEx,
cancel: hasCancelApi, cancel: hasCancelApi,
reject: hasRejectApi, reject: hasRejectApi,
usbReader: hasUsbReaderApi, usbReader: hasUsbReaderApi,
@@ -263,7 +239,7 @@ export function dllInit(params: InitParams): number {
} }
function dllGetPrinterInfoInternal( function dllGetPrinterInfoInternal(
apiName: 'SAPI_GetPrinterInfo' | 'SAPI_GetPrinterInfoEx', apiName: 'SAPI_GetPrinterInfo',
fn: (outPtr: Buffer) => number fn: (outPtr: Buffer) => number
): { code: number; json?: Record<string, unknown> } { ): { code: number; json?: Record<string, unknown> } {
return traceCall(apiName, undefined, () => { return traceCall(apiName, undefined, () => {
@@ -279,13 +255,6 @@ function dllGetPrinterInfoInternal(
} }
export function dllGetPrinterInfo(): { code: number; json?: Record<string, unknown> } { export function dllGetPrinterInfo(): { code: number; json?: Record<string, unknown> } {
loadLibrary()
if (hasPrinterInfoEx && SAPI_GetPrinterInfoEx) {
const ex = dllGetPrinterInfoInternal('SAPI_GetPrinterInfoEx', (p) => SAPI_GetPrinterInfoEx!(p))
if (ex.json && Object.keys(ex.json).length > 0) {
return ex
}
}
return dllGetPrinterInfoInternal('SAPI_GetPrinterInfo', (p) => SAPI_GetPrinterInfo!(p)) return dllGetPrinterInfoInternal('SAPI_GetPrinterInfo', (p) => SAPI_GetPrinterInfo!(p))
} }
@@ -110,6 +110,16 @@
margin-left: 3px; margin-left: 3px;
} }
.m-panel-toolbar .c-checkbox-item .c-input.dog-auth {
width: 110px;
height: 20px;
padding: 0 4px;
font-size: 9px;
border-radius: 3px;
border: 1px solid #ced4da;
margin-left: 6px;
}
/* 提示文字 */ /* 提示文字 */
.m-panel-toolbar .c-checkbox-item .dog-hint { .m-panel-toolbar .c-checkbox-item .dog-hint {
font-size: 9px; font-size: 9px;
+3 -3
View File
@@ -1,11 +1,12 @@
import type { DistributeFormState } from '@/stores/distributeForm' import type { DistributeFormState } from '@/stores/distributeForm'
import type { NetInfoCredential } from '@shared/network-host'
import { cleanPathPattern } from '@shared/path-pattern' import { cleanPathPattern } from '@shared/path-pattern'
import { resolveJobTasks } from '@/utils/validateJobConfig' import { resolveJobTasks } from '@/utils/validateJobConfig'
export interface BuildJobOptions { export interface BuildJobOptions {
taskId: string taskId: string
udfFile?: string udfFile?: string
netInfo?: string netInfo?: NetInfoCredential[]
} }
function formatFileForApi(formatType: Exclude<DistributeFormState['formatType'], 'none'>): string { function formatFileForApi(formatType: Exclude<DistributeFormState['formatType'], 'none'>): string {
@@ -62,8 +63,7 @@ export function buildJobConfig(
if (form.generateZip) body.is_generate_zip = true if (form.generateZip) body.is_generate_zip = true
if (form.failPrintLabel) body.is_printer_record_logo = true if (form.failPrintLabel) body.is_printer_record_logo = true
const netInfo = opts.netInfo?.trim() if (opts.netInfo?.length) body.net_info = opts.netInfo
if (netInfo) body.net_info = netInfo
return body return body
} }
@@ -1,5 +1,5 @@
import { cleanPathPattern } from '@shared/path-pattern' import { cleanPathPattern } from '@shared/path-pattern'
import { buildNetInfo, collectHostsForCopyPaths } from '@shared/network-host' import { buildNetInfo, collectHostsForCopyPaths, type NetInfoCredential } from '@shared/network-host'
import type { DistributeFormState } from '@/stores/distributeForm' import type { DistributeFormState } from '@/stores/distributeForm'
import { fsResolveNetworkHosts } from '@/api/cardsoon' import { fsResolveNetworkHosts } from '@/api/cardsoon'
import { useNetworkAuthStore } from '@/stores/networkAuth' import { useNetworkAuthStore } from '@/stores/networkAuth'
@@ -20,9 +20,9 @@ export async function resolveCopyNetworkHosts(form: DistributeFormState): Promis
return collectHostsForCopyPaths(paths, driveHostMap) return collectHostsForCopyPaths(paths, driveHostMap)
} }
export async function buildNetInfoForForm(form: DistributeFormState): Promise<string> { export async function buildNetInfoForForm(form: DistributeFormState): Promise<NetInfoCredential[]> {
const hosts = await resolveCopyNetworkHosts(form) const hosts = await resolveCopyNetworkHosts(form)
if (!hosts.length) return '' if (!hosts.length) return []
const netStore = useNetworkAuthStore() const netStore = useNetworkAuthStore()
return buildNetInfo( return buildNetInfo(
hosts.map((h) => ({ hostName: h })), hosts.map((h) => ({ hostName: h })),
@@ -34,7 +34,7 @@ async function buildJobJson(
} }
} }
let netInfo = '' let netInfo: Awaited<ReturnType<typeof buildNetInfoForForm>> = []
if (hasCopy) { if (hasCopy) {
try { try {
netInfo = await buildNetInfoForForm(form) netInfo = await buildNetInfoForForm(form)
@@ -68,18 +68,15 @@
@input="onDongleCountInput" @input="onDongleCountInput"
/> />
<span class="dog-hint">{{ dongleHint }}</span> <span class="dog-hint">{{ dongleHint }}</span>
</label>
</div>
<div v-if="formStore.dongleEnabled" class="toolbar-row">
<div class="toolbar-item toolbar-item--full">
<input <input
v-if="formStore.dongleEnabled"
v-model="formStore.dongleAuthCode" v-model="formStore.dongleAuthCode"
type="text" type="password"
class="c-input dog-auth" class="c-input dog-auth"
placeholder="请输入授权码" placeholder="授权码"
@input="onDongleAuthInput" @input="onDongleAuthInput"
/> />
</div> </label>
</div> </div>
</div> </div>
<div class="c-panel__body"> <div class="c-panel__body">
@@ -488,15 +485,6 @@ async function onSubmit(): Promise<void> {
color: #606266; color: #606266;
} }
.toolbar-item--full {
flex: 1;
}
.dog-auth {
width: 100%;
max-width: 100%;
}
.m-print-side-picker { .m-print-side-picker {
display: flex; display: flex;
gap: 16px; gap: 16px;
+9 -3
View File
@@ -22,6 +22,12 @@ export function extractDriveLetter(p: string): string {
return m ? m[1].toUpperCase() : '' return m ? m[1].toUpperCase() : ''
} }
export interface NetInfoCredential {
host_name: string
user_name: string
password: string
}
export function buildNetworkUrl(host: string, share: string): string { export function buildNetworkUrl(host: string, share: string): string {
const h = host.trim() const h = host.trim()
const s = share.trim().replace(/^[\\/]+/, '').replace(/[\\/]+$/, '') const s = share.trim().replace(/^[\\/]+/, '').replace(/[\\/]+$/, '')
@@ -52,8 +58,8 @@ export function collectHostsForCopyPaths(
export function buildNetInfo( export function buildNetInfo(
networkItems: { hostName?: string; userName?: string; password?: string }[], networkItems: { hostName?: string; userName?: string; password?: string }[],
getStored: (host: string) => { userName?: string; password?: string } | null getStored: (host: string) => { userName?: string; password?: string } | null
): string { ): NetInfoCredential[] {
const creds: { host_name: string; user_name: string; password: string }[] = [] const creds: NetInfoCredential[] = []
const seen = new Set<string>() const seen = new Set<string>()
for (const it of networkItems) { for (const it of networkItems) {
const host = (it.hostName || '').trim() const host = (it.hostName || '').trim()
@@ -71,5 +77,5 @@ export function buildNetInfo(
password password
}) })
} }
return creds.length > 0 ? JSON.stringify(creds) : '' return creds
} }