diff --git a/app/src/main/services/poll-manager.ts b/app/src/main/services/poll-manager.ts index f0f7978..1131f5a 100644 --- a/app/src/main/services/poll-manager.ts +++ b/app/src/main/services/poll-manager.ts @@ -1,5 +1,6 @@ import { BrowserWindow } from 'electron' import log from 'electron-log' +import { normalizeCardPositionQuery } from '@shared/card-position' import { POLL_INTERVAL_MS, CS_OK } from '../constants' import { USB_TASK_COMPLETED, @@ -159,7 +160,7 @@ async function pollCardPositionOnce(): Promise { const dll = await loadDllModule() if (!dll.isCardPositionApiAvailable()) return const r = dll.dllGetPrinterCardPosition() - const tick = { queryCode: r.queryCode, position: r.position } + const tick = normalizeCardPositionQuery(r.queryCode, r.position) emitTrace('[poll] card:position-tick', tick) send('card:position-tick', tick) } catch (e) { diff --git a/app/src/renderer/src/stores/job.ts b/app/src/renderer/src/stores/job.ts index a7da6a5..0f02440 100644 --- a/app/src/renderer/src/stores/job.ts +++ b/app/src/renderer/src/stores/job.ts @@ -3,6 +3,7 @@ import { defineStore } from 'pinia' export const useJobStore = defineStore('job', { state: () => ({ jobId: '', + lastJobJson: '', submitting: false, successCount: 0, failCount: 0 @@ -11,11 +12,15 @@ export const useJobStore = defineStore('job', { setActiveJob(jobId: string) { this.jobId = jobId }, + setLastJobJson(json: string) { + this.lastJobJson = json + }, clearActiveJob() { this.jobId = '' }, reset() { this.jobId = '' + this.lastJobJson = '' this.submitting = false this.successCount = 0 this.failCount = 0 diff --git a/app/src/renderer/src/utils/createDistributeJob.ts b/app/src/renderer/src/utils/createDistributeJob.ts index 8dd3ebb..002b083 100644 --- a/app/src/renderer/src/utils/createDistributeJob.ts +++ b/app/src/renderer/src/utils/createDistributeJob.ts @@ -2,6 +2,7 @@ import { genTaskId } from '@shared/gen-task-id' import { buildJobConfig } from '@/utils/buildJobConfig' import { resolveJobTasks } from '@/utils/validateJobConfig' import { dllJobCreate, fsWriteJobCsv } from '@/api/cardsoon' +import { useJobStore } from '@/stores/job' import type { DistributeFormState } from '@/stores/distributeForm' function printFieldRows(form: DistributeFormState) { @@ -11,10 +12,7 @@ function printFieldRows(form: DistributeFormState) { })) } -export async function createDistributeJob( - form: DistributeFormState, - opts?: { resubmit?: boolean } -): Promise<{ ok: true; jobId: string } | { ok: false; message: string }> { +async function buildJobJson(form: DistributeFormState): Promise<{ ok: true; json: string } | { ok: false; message: string }> { const { hasCopy, hasPrint } = resolveJobTasks(form) if (!hasCopy && !hasPrint) { return { ok: false, message: '请配置拷贝路径或打印模板' } @@ -33,7 +31,25 @@ export async function createDistributeJob( } } - const json = JSON.stringify(buildJobConfig(form, { taskId, udfFile })) + return { ok: true, json: JSON.stringify(buildJobConfig(form, { taskId, udfFile })) } +} + +export async function createDistributeJob( + form: DistributeFormState, + opts?: { resubmit?: boolean } +): Promise<{ ok: true; jobId: string } | { ok: false; message: string }> { + const jobStore = useJobStore() + let json: string + + if (opts?.resubmit && jobStore.lastJobJson) { + json = jobStore.lastJobJson + } else { + const built = await buildJobJson(form) + if (!built.ok) return built + json = built.json + jobStore.setLastJobJson(json) + } + const created = await dllJobCreate(json, opts) if (!created.ok || !created.data?.jobId) { return { ok: false, message: created.message || '创建任务失败' } diff --git a/app/src/renderer/src/views/DistributeRunningView.vue b/app/src/renderer/src/views/DistributeRunningView.vue index fdfe23e..f870c7c 100644 --- a/app/src/renderer/src/views/DistributeRunningView.vue +++ b/app/src/renderer/src/views/DistributeRunningView.vue @@ -108,7 +108,7 @@ import { import { createDistributeJob } from '@/utils/createDistributeJob' import { validateJobPreflight } from '@/utils/validateJobPreflight' import { mapJobStateToUi } from '@/utils/job-state' -import { POSITION_PREPARE } from '@shared/card-position' +import { POSITION_PREPARE, resolveCardPosition } from '@shared/card-position' import { USB_TASK_COPYING, USB_TASK_PREPARING, @@ -275,8 +275,8 @@ function canAutoResubmit(): boolean { function applyCardPosition(p: CardPositionPollPayload): void { if (!canAutoResubmit() || resubmitting) return - if (p.queryCode !== 0) return - const pos = p.position + const pos = resolveCardPosition(p.queryCode, p.position) + if (pos === null) return const enteredPrepare = pos === POSITION_PREPARE && lastCardPosition !== POSITION_PREPARE lastCardPosition = pos if (!enteredPrepare) return @@ -324,11 +324,13 @@ async function resubmitTask(): Promise { return } - const err = await validateJobPreflight(formStore) - if (err) { - notify.warning(err) - await backToWait() - return + if (!jobStore.lastJobJson) { + const err = await validateJobPreflight(formStore) + if (err) { + notify.warning(err) + await backToWait() + return + } } phase.value = 'running' setProgress(0) diff --git a/app/src/shared/card-position.ts b/app/src/shared/card-position.ts index 6d1c66b..5a48419 100644 --- a/app/src/shared/card-position.ts +++ b/app/src/shared/card-position.ts @@ -4,16 +4,30 @@ export const POSITION_PREPARE = 13 /** 卡位编号合理上限(用于解析 DLL 返回值) */ export const POSITION_MAX = 32 -/** 归一化 SAPI_GetPrinterCardPosition:兼容返回值=CS_OK 与返回值=卡位编号两种 DLL */ +/** + * 解析 SAPI_GetPrinterCardPosition。 + * 真机常见:ret=13,out=0(返回值即卡位);或 ret=0,out=卡位。 + */ +export function resolveCardPosition(queryCode: number, position: number): number | null { + if (queryCode === 0 && position >= 0 && position <= POSITION_MAX) { + return position + } + if (queryCode > 0 && queryCode <= POSITION_MAX) { + return queryCode + } + if (position > 0 && position <= POSITION_MAX) { + return position + } + return null +} + export function normalizeCardPositionQuery( ret: number, outPosition: number ): { queryCode: number; position: number } { - if (ret === 0) { - return { queryCode: 0, position: outPosition } - } - if (ret > 0 && ret <= POSITION_MAX) { - return { queryCode: 0, position: ret } + const pos = resolveCardPosition(ret, outPosition) + if (pos !== null) { + return { queryCode: 0, position: pos } } return { queryCode: ret, position: outPosition } }