fix: 测试联调四项修复
- 授权码并入加密狗行,password 掩码,窄宽样式 - 打印机信息仅调用 SAPI_GetPrinterInfo,移除 Ex 避免崩溃 - net_info 改为 JSON 数组,修复双重编码 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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, '未连接打印机')
|
||||||
|
|||||||
@@ -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,15 +90,7 @@ function readPrinterJsonFromOutPtr(len: number, outPtr: Buffer): { code: number;
|
|||||||
return { code: len }
|
return { code: len }
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (SAPI_FreePrinterInfo) {
|
koffi.free(ptr)
|
||||||
try {
|
|
||||||
SAPI_FreePrinterInfo(ptr)
|
|
||||||
} catch (e) {
|
|
||||||
log.warn('SAPI_FreePrinterInfo', e)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
koffi.free(ptr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user