diff --git a/app/.gitignore b/app/.gitignore index 55b90c0..b1cb42c 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -2,6 +2,7 @@ node_modules/ dist/ out/ release/ +*.tsbuildinfo *.log .env .env.* diff --git a/app/package.json b/app/package.json index 06c1d04..de7a658 100644 --- a/app/package.json +++ b/app/package.json @@ -9,7 +9,6 @@ }, "scripts": { "dev": "electron-vite dev", - "dev:dll": "electron-vite dev -- --with-dll", "build": "electron-vite build", "preview": "electron-vite preview", "typecheck": "vue-tsc --noEmit -p tsconfig.web.json", @@ -33,6 +32,10 @@ "build": { "appId": "com.cardsoon.machine", "productName": "卡树数据卡打印系统", + "asar": true, + "asarUnpack": [ + "**/node_modules/koffi/**" + ], "directories": { "output": "release" }, diff --git a/app/resources/cardsoon.config.example.json b/app/resources/cardsoon.config.example.json deleted file mode 100644 index 0b0dba0..0000000 --- a/app/resources/cardsoon.config.example.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "designAppPath": "C:\\myData\\projects\\sideline\\shanghaikashu\\SoonMachine\\app\\release\\卡树数据卡打印系统-0.0.1-win\\卡树数据卡打印系统.exe" -} diff --git a/app/resources/cardsoon.config.json b/app/resources/cardsoon.config.json index 0b0dba0..c2b0c14 100644 --- a/app/resources/cardsoon.config.json +++ b/app/resources/cardsoon.config.json @@ -1,3 +1,3 @@ { - "designAppPath": "C:\\myData\\projects\\sideline\\shanghaikashu\\SoonMachine\\app\\release\\卡树数据卡打印系统-0.0.1-win\\卡树数据卡打印系统.exe" + "designAppPath": "D:\\SoonProject\\SoonDesign\\build\\win-unpacked\\SoonDesign.exe" } diff --git a/app/resources/native/freetype.dll b/app/resources/native/freetype.dll new file mode 100644 index 0000000..6296082 Binary files /dev/null and b/app/resources/native/freetype.dll differ diff --git a/app/resources/native/opencv_world490d.dll b/app/resources/native/opencv_world490d.dll new file mode 100644 index 0000000..bbb64ad Binary files /dev/null and b/app/resources/native/opencv_world490d.dll differ diff --git a/app/resources/native/workDll.dll b/app/resources/native/workDll.dll index 14224cc..d142bea 100644 Binary files a/app/resources/native/workDll.dll and b/app/resources/native/workDll.dll differ diff --git a/app/scripts/check-native-dlls.js b/app/scripts/check-native-dlls.js index 8d64740..08f6a06 100644 --- a/app/scripts/check-native-dlls.js +++ b/app/scripts/check-native-dlls.js @@ -9,13 +9,15 @@ const required = [ 'dcrf32.dll', 'Entry.dll', 'libpng16.dll', - 'zint.dll' + 'zint.dll', + 'freetype.dll', + 'opencv_world490d.dll' ] const missing = required.filter((name) => !fs.existsSync(path.join(nativeDir, name))) if (missing.length) { console.error(`resources/native 缺少: ${missing.join(', ')}`) - console.error('请从 docs/API/lib 复制 7 个 dll(不含 .lib)') + console.error('请从 docs/API/lib 复制完整 native 依赖(不含 .lib)') process.exit(1) } -console.log('resources/native: 7 dll 齐全') +console.log(`resources/native: ${required.length} dll 齐全`) diff --git a/app/src/main/index.ts b/app/src/main/index.ts index 12523d8..5ced19e 100644 --- a/app/src/main/index.ts +++ b/app/src/main/index.ts @@ -4,14 +4,29 @@ import { join } from 'path' app.commandLine.appendSwitch('disable-gpu-shader-disk-cache') import log from 'electron-log' + +if (app.isPackaged) { + app.disableHardwareAcceleration() +} + +const gotSingleInstanceLock = app.requestSingleInstanceLock() +if (!gotSingleInstanceLock) { + app.quit() +} + import { suppressKnownDllStderr } from './utils/suppress-dll-stderr' import { loadAppFileConfig } from './services/app-config' import { migrateTraceConfig, setTraceWebContents } from './utils/trace-bridge' -import { setupNativeWorkingDir } from './services/native-path' -import { configStore } from './services/config-store' suppressKnownDllStderr() + +process.on('uncaughtException', (err) => { + log.error('uncaughtException', err) + dialog.showErrorBox('程序异常', err instanceof Error ? err.message : String(err)) +}) + import { registerIpcHandlers, handleBeforeQuit } from './ipc/register-handlers' +import { ensureDllInitialized } from './services/dll-bootstrap' import { setPollMainWindow } from './services/poll-manager' import { DESIGN_WIDTH, DESIGN_HEIGHT, contentHeightForWidth } from '@shared/viewport' @@ -19,7 +34,13 @@ let mainWindow: BrowserWindow | null = null const MIN_CONTENT_WIDTH = 960 -/** 默认内容区:约 85% 工作区宽,高 720:360 */ +function focusMainWindow(): void { + if (!mainWindow) return + if (mainWindow.isMinimized()) mainWindow.restore() + mainWindow.show() + 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)) @@ -71,7 +92,6 @@ function createWindow(): void { } }) - // 内容区 720:360,与 useScale 一致 mainWindow.on('resize', () => { if (!mainWindow) return const [cw, ch] = mainWindow.getContentSize() @@ -86,6 +106,14 @@ function createWindow(): void { mainWindow = null }) + mainWindow.webContents.on('render-process-gone', (_event, details) => { + log.error('render-process-gone', details) + dialog.showErrorBox( + '界面进程异常退出', + `reason=${details.reason} exitCode=${details.exitCode}\n请查看 %APPDATA%\\cardsoon-machine\\logs\\main.log` + ) + }) + if (process.env.ELECTRON_RENDERER_URL) { mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL) } else { @@ -93,24 +121,26 @@ function createWindow(): void { } } -app.whenReady().then(() => { - try { - if (app.isPackaged) { - configStore.set('skipDllInit', false) - } else { - const withDll = - process.argv.includes('--with-dll') || - process.argv.includes('--no-skip-dll-init') - configStore.set('skipDllInit', !withDll) - if (!withDll) { - log.info('skipDllInit enabled (dev default); use npm run dev:dll to load workDll') - } - } +if (gotSingleInstanceLock) { + app.on('second-instance', () => { + focusMainWindow() + }) +} +app.whenReady().then(async () => { + if (!gotSingleInstanceLock) return + + try { migrateTraceConfig() loadAppFileConfig() - setupNativeWorkingDir() + log.info('app startup', { packaged: app.isPackaged, execPath: process.execPath }) registerIpcHandlers() + try { + const r = await ensureDllInitialized() + if (r.warning) log.warn(r.warning) + } catch (e) { + log.error('startup DLL init failed', e) + } createWindow() if (!app.isPackaged) { globalShortcut.register('CommandOrControl+Shift+I', () => { diff --git a/app/src/main/ipc/register-handlers.ts b/app/src/main/ipc/register-handlers.ts index ed40457..0732a69 100644 --- a/app/src/main/ipc/register-handlers.ts +++ b/app/src/main/ipc/register-handlers.ts @@ -1,34 +1,19 @@ -import { app, dialog, shell } from 'electron' +import { dialog, shell } from 'electron' import fs from 'fs' import log from 'electron-log' import { CS_FAIL, CS_OK } from '../constants' import { assertNotBusy, assertReady, mainAppState } from '../services/app-state' import { configStore } from '../services/config-store' -import { - startJobPoll, - startUsbPoll, - stopAllPolls, - stopJobPoll, - stopUsbPoll, - getPollMainWindow -} from '../services/poll-manager' +import { startUsbPoll, startJobPoll, stopAllPolls, stopJobPoll, stopUsbPoll, stopCardPositionPoll, startCardPositionPoll, getPollMainWindow, isJobPollActive } from '../services/poll-manager' import { parsePrinterInfoFromDll, type PrinterStatusSnapshot } from '@shared/printer-info' import { cleanPathPattern, getDirectorySizeBytes } from '../utils/dir-size' import { getDesignAppPath } from '../services/app-config' import { openDesignApp } from '../services/open-design-app' +import { writeJobCsv, type JobCsvRow } from '../utils/job-csv' import { parseSoonTemplate } from '../utils/parse-soon' -import { - dllAdminJobCancel, - dllCopyFromUsb, - dllGetPrinterErrorStr, - dllGetPrinterInfo, - dllInit, - dllPrinterReject, - dllPrinterReset, - dllRestJobEx, - isCancelApiAvailable, - isRejectApiAvailable -} from '../services/work-dll.service' +import { stageJobPayloadJson } from '../utils/stage-job-payload' +import { ensureDllInitialized, isDllInitAttempted } from '../services/dll-bootstrap' +import { loadDllModule } from '../services/dll-loader' import { tracedHandle } from './traced-handler' function ok(data?: T) { @@ -39,63 +24,49 @@ function fail(code: number, message: string) { return { ok: false as const, code, message } } -let dllInitAttempted = false +function summarizeStagedPayload(json: string): Record { + try { + const p = JSON.parse(json) as Record + return { + task_id: p.task_id, + has_copy_task: p.has_copy_task, + has_print_task: p.has_print_task, + path_file_count: Array.isArray(p.path_file) ? p.path_file.length : 0, + json_file: p.json_file, + udf_file: p.udf_file + } + } catch { + return { parseError: true } + } +} function parseBool(v: unknown): boolean { return v === true || v === 'true' || v === 1 || v === '1' || String(v).toLowerCase() === 'true' } export function registerIpcHandlers(): void { - tracedHandle('dll:init', (_e, params) => { - if (dllInitAttempted) { - return ok({ - skipped: true, - printerReady: false, - warning: '已初始化,跳过重复 Init' - }) - } + tracedHandle('dll:init', async (_e, params) => { stopAllPolls() try { - const sharedDir = params?.sharedDir || (configStore.get('sharedDir') as string) - fs.mkdirSync(sharedDir, { recursive: true }) - const code = dllInit({ - sharedDir, - keepCombinedImage: params?.keepCombinedImage, - stopOnFailure: params?.stopOnFailure, - cleanTaskFile: params?.cleanTaskFile, - autoRetryTimes: params?.autoRetryTimes, - rejectConfig: params?.rejectConfig, - logLevel: params?.logLevel, - outBack: params?.outBack - }) - dllInitAttempted = true - mainAppState.initialized = true - configStore.set('sharedDir', sharedDir) - if (code === CS_OK) { - return ok({ code, printerReady: true }) - } - return ok({ - code, - printerReady: false, - warning: '打印机未连接或驱动未就绪,界面可浏览,接好设备后可在设置中重试 Init' - }) + const r = await ensureDllInitialized(params) + return ok({ code: r.code, warning: r.warning }) } catch (err) { - mainAppState.initialized = false return fail(CS_FAIL, String(err)) } }) - tracedHandle('dll:printer-info', () => { + tracedHandle('dll:printer-info', async () => { try { assertReady() - const r = dllGetPrinterInfo() + const dll = await loadDllModule() + const r = dll.dllGetPrinterInfo() if (!r.json) { const cached = configStore.get('lastPrinterStatus') if (cached) { return ok({ ...cached, fromCache: true, - liveError: r.code <= 0 ? '未连接打印机' : `GetPrinterInfo code=${r.code}` + liveError: r.code <= 0 ? '未连接打印机' : `GetPrinterInfoEx code=${r.code}` }) } return fail(0, '未连接打印机') @@ -112,77 +83,139 @@ export function registerIpcHandlers(): void { } }) - tracedHandle('dll:printer-reset', () => { + tracedHandle('dll:printer-reset', async () => { try { assertReady() - const code = dllPrinterReset() + const dll = await loadDllModule() + const code = dll.dllPrinterReset() return code === CS_OK ? ok() : fail(code, '重置失败') } catch (err) { return fail(CS_FAIL, String(err)) } }) - tracedHandle('dll:printer-reject', () => { + tracedHandle('dll:printer-reject', async () => { try { assertReady() - if (!isRejectApiAvailable()) return fail(CS_FAIL, 'REJECT_API_UNAVAILABLE') - const code = dllPrinterReject() + const dll = await loadDllModule() + if (!dll.isRejectApiAvailable()) return fail(CS_FAIL, 'REJECT_API_UNAVAILABLE') + const code = dll.dllPrinterReject() return code === CS_OK ? ok() : fail(code, '废卡失败') } catch (err) { return fail(CS_FAIL, String(err)) } }) - tracedHandle('dll:printer-error-str', (_e, errorNo?: number) => { + tracedHandle('dll:printer-error-str', async (_e, errorNo?: number) => { + if (!mainAppState.initialized) return ok({ text: '' }) try { - assertReady() - return ok({ text: dllGetPrinterErrorStr(errorNo ?? -1) }) + const dll = await loadDllModule() + return ok({ text: dll.dllGetPrinterErrorStr(errorNo ?? -1) }) } catch (err) { - return fail(CS_FAIL, String(err)) + log.warn('dll:printer-error-str', err) + return ok({ text: '' }) } }) - tracedHandle('dll:job-create', (_e, json: string) => { + tracedHandle('dll:job-create', async (_e, json: string, opts?: { resubmit?: boolean }) => { try { assertReady() - assertNotBusy() - const r = dllRestJobEx(json) - if (r.code !== CS_OK) return fail(r.code, 'RestJobEx 失败') + if (opts?.resubmit) { + if (mainAppState.mode !== 'distributing') { + return fail(CS_FAIL, '当前不在分发任务会话中') + } + stopCardPositionPoll() + } else { + assertNotBusy() + } + const dll = await loadDllModule() + const sharedDir = configStore.get('sharedDir') as string + let staged: { json: string; taskDir: string } + try { + staged = stageJobPayloadJson(json, sharedDir, dll) + } catch (err) { + const msg = err instanceof Error ? err.message : String(err) + return fail(CS_FAIL, msg) + } + log.info('RestJobEx staging', { + taskDir: staged.taskDir, + summary: summarizeStagedPayload(staged.json) + }) + const r = dll.dllRestJobEx(staged.json) + if (r.code !== CS_OK) { + log.warn('RestJobEx rejected', { code: r.code, json: staged.json.slice(0, 800) }) + const errText = dll.dllGetPrinterErrorStr(r.code) + let detail = errText ? `${errText} (code=${r.code})` : `RestJobEx 失败 (code=${r.code})` + if (r.code === -1 && !errText) { + detail += + ':请确认模板路径、变量 CSV(udf_file)及拷贝路径有效,且打印机/任务目录已就绪' + } + return fail(r.code, detail) + } + if (!r.jobId?.trim()) { + return fail(CS_FAIL, 'RestJobEx 未返回 jobId') + } mainAppState.mode = 'distributing' mainAppState.activeJobId = r.jobId return ok({ jobId: r.jobId }) } catch (err) { - if (String(err).includes('BUSY')) return fail(CS_FAIL, '已有任务在执行') - return fail(CS_FAIL, String(err)) + const msg = String(err) + if (msg.includes('BUSY')) return fail(CS_FAIL, '已有任务在执行') + if (msg.includes('NOT_INITIALIZED')) { + return fail(CS_FAIL, '系统未初始化,请重启应用') + } + return fail(CS_FAIL, msg) } }) - tracedHandle('dll:job-cancel', (_e, jobId: string) => { + tracedHandle('dll:job-cancel', async (_e, jobId: string) => { + const id = String(jobId || mainAppState.activeJobId || '').trim() + stopJobPoll(true) + mainAppState.mode = 'ready' + mainAppState.activeJobId = '' + if (!id) return ok() + if (!mainAppState.initialized) return ok() try { - assertReady() - const id = jobId || mainAppState.activeJobId - stopJobPoll(true) - let code = CS_OK - if (isCancelApiAvailable()) { - code = dllAdminJobCancel(id) - } - mainAppState.mode = 'ready' - mainAppState.activeJobId = '' + const dll = await loadDllModule() + if (!dll.isCancelApiAvailable()) return ok() + const code = dll.dllAdminJobCancel(id) return code === CS_OK ? ok() : fail(code, '取消失败') } catch (err) { - return fail(CS_FAIL, String(err)) + log.warn('dll:job-cancel', err) + return ok() } }) - tracedHandle('dll:usb-copy', (_e, req: { destFolder: string; cardOutput: number }) => { + tracedHandle('dll:usb-copy', async (_e, req: { destFolder: string; cardOutput: number; resubmit?: boolean }) => { try { assertReady() - assertNotBusy() - const code = dllCopyFromUsb(req.destFolder, req.cardOutput) + if (req.resubmit) { + if (mainAppState.mode !== 'usbCopying') { + return fail(CS_FAIL, '当前不在数据收集会话中') + } + stopCardPositionPoll() + } else { + assertNotBusy() + } + const destFolder = String(req.destFolder || '').trim() + if (!destFolder) return fail(CS_FAIL, '请先选择数据导入目录') + fs.mkdirSync(destFolder, { recursive: true }) + + const dll = await loadDllModule() + if (dll.isUsbReaderApiAvailable()) { + const moveCode = dll.dllPrinterMoveToUsbReader() + if (moveCode !== CS_OK) { + log.warn('MoveToUsbReader before copy', { moveCode }) + } + } + + const code = dll.dllCopyFromUsb(destFolder, req.cardOutput) if (code !== CS_OK) { - return fail(code, '可能已有任务在执行') + const errText = dll.dllGetPrinterErrorStr(code) + return fail(code, errText || '启动 USB 收集失败') } mainAppState.mode = 'usbCopying' + startUsbPoll() return ok() } catch (err) { if (String(err).includes('BUSY')) return fail(CS_FAIL, '已有任务在执行') @@ -195,8 +228,8 @@ export function registerIpcHandlers(): void { return ok() }) - tracedHandle('poll:job-stop', () => { - stopJobPoll(true) + tracedHandle('poll:job-stop', (_e, opts?: { resetMode?: boolean }) => { + stopJobPoll(opts?.resetMode !== false) return ok() }) @@ -205,9 +238,27 @@ export function registerIpcHandlers(): void { return ok() }) - tracedHandle('poll:usb-stop', () => { - stopUsbPoll() - mainAppState.mode = 'ready' + tracedHandle('poll:usb-stop', (_e, opts?: { resetMode?: boolean }) => { + stopUsbPoll(opts?.resetMode !== false) + return ok() + }) + + tracedHandle('poll:card-position-start', async () => { + try { + assertReady() + const dll = await loadDllModule() + if (!dll.isCardPositionApiAvailable()) { + return fail(CS_FAIL, '当前 DLL 不支持卡位查询,无法自动续做') + } + startCardPositionPoll() + return ok() + } catch (err) { + return fail(CS_FAIL, String(err)) + } + }) + + tracedHandle('poll:card-position-stop', () => { + stopCardPositionPoll() return ok() }) @@ -253,6 +304,19 @@ export function registerIpcHandlers(): void { return ok({ items }) }) + tracedHandle( + 'fs:write-job-csv', + (_e, payload: { taskId: string; rows: JobCsvRow[] }) => { + try { + const sharedDir = configStore.get('sharedDir') as string + const csvPath = writeJobCsv(sharedDir, payload.taskId, payload.rows || []) + return ok({ path: csvPath }) + } catch (err) { + return fail(CS_FAIL, err instanceof Error ? err.message : String(err)) + } + } + ) + tracedHandle('fs:parse-soon', (_e, filePath: string) => { try { const soonPath = String(filePath || '').trim() @@ -272,26 +336,19 @@ export function registerIpcHandlers(): void { templateDir: string traceEnabled: boolean lastPrinterStatus?: PrinterStatusSnapshot - skipDllInit?: boolean + dllInitialized: boolean } = { sharedDir: configStore.get('sharedDir'), templateDir: configStore.get('templateDir'), traceEnabled: configStore.get('traceEnabled', true), - lastPrinterStatus: configStore.get('lastPrinterStatus') - } - if (!app.isPackaged) { - payload.skipDllInit = configStore.get('skipDllInit', false) + lastPrinterStatus: configStore.get('lastPrinterStatus'), + dllInitialized: mainAppState.initialized } return ok(payload) }) tracedHandle('config:set', (_e, patch: Record) => { Object.entries(patch).forEach(([k, v]) => { - if (k === 'skipDllInit') { - if (app.isPackaged) return - configStore.set(k, parseBool(v)) - return - } if (k === 'traceEnabled' || k === 'dllTraceEnabled') { configStore.set('traceEnabled', parseBool(v)) return @@ -314,19 +371,24 @@ export function registerIpcHandlers(): void { return ok() }) - tracedHandle('dll:reject-available', () => ok({ available: isRejectApiAvailable() })) + tracedHandle('dll:reject-available', async () => { + const dll = await loadDllModule() + return ok({ available: dll.isRejectApiAvailable() }) + }) } export async function handleBeforeQuit(): Promise { + const dll = isDllInitAttempted() ? await loadDllModule().catch(() => null) : null const shouldCancel = mainAppState.mode === 'distributing' && !!mainAppState.activeJobId && - isCancelApiAvailable() + isJobPollActive() && + !!dll?.isCancelApiAvailable() const cancelJobId = mainAppState.activeJobId stopAllPolls() - if (shouldCancel && cancelJobId) { + if (shouldCancel && cancelJobId && dll) { try { - dllAdminJobCancel(cancelJobId) + dll.dllAdminJobCancel(cancelJobId) } catch (e) { log.warn('before-quit cancel', e) } diff --git a/app/src/main/services/app-config.ts b/app/src/main/services/app-config.ts index 20a1bdf..2f654c6 100644 --- a/app/src/main/services/app-config.ts +++ b/app/src/main/services/app-config.ts @@ -6,7 +6,6 @@ import { getProcessExecDir } from './native-path' export const APP_CONFIG_FILENAME = 'cardsoon.config.json' -/** 与 cardsoon.config.json 键名一致,后续配置在此扩展 */ export interface AppFileConfig { designAppPath: string } @@ -16,7 +15,6 @@ const defaults: AppFileConfig = { } let cached: AppFileConfig | null = null -let loadedFrom = '' function bundledConfigPath(): string { if (app.isPackaged) { @@ -46,7 +44,6 @@ export function loadAppFileConfig(): AppFileConfig { if (!fs.existsSync(filePath)) continue try { cached = parseConfigFile(filePath) - loadedFrom = filePath log.info(`Loaded ${APP_CONFIG_FILENAME} from ${filePath}`) return cached } catch (e) { @@ -55,18 +52,12 @@ export function loadAppFileConfig(): AppFileConfig { } cached = { ...defaults } - loadedFrom = '' log.warn( `${APP_CONFIG_FILENAME} not found (checked: ${configSearchPaths().join(', ')}), using defaults` ) return cached } -export function getAppConfigLoadedPath(): string { - loadAppFileConfig() - return loadedFrom -} - export function getDesignAppPath(): string { return loadAppFileConfig().designAppPath } diff --git a/app/src/main/services/config-store.ts b/app/src/main/services/config-store.ts index 875c504..a945cde 100644 --- a/app/src/main/services/config-store.ts +++ b/app/src/main/services/config-store.ts @@ -6,23 +6,15 @@ import type { PrinterStatusSnapshot } from '@shared/printer-info' interface AppConfig { sharedDir: string templateDir: string - /** G2 门禁 false:启动即 SAPI_Init;仅调试可改 true */ - skipDllInit: boolean - /** true:IPC/DLL 等调用输出到 DevTools 控制台 */ traceEnabled: boolean - /** 上次成功的 GetPrinterInfo 解析结果,供离线/失败时展示 */ lastPrinterStatus?: PrinterStatusSnapshot } -const defaultShared = path.join('C:', 'PrintTasks') - export const configStore = new Store({ name: 'cardsoon-config', defaults: { - sharedDir: defaultShared, + sharedDir: path.join('C:', 'PrintTasks'), templateDir: path.join(app.getPath('userData'), 'Cardsoon', 'templates'), - // 正式版始终 Init;仅开发时可通过 --skip-dll-init 临时跳过 - skipDllInit: false, traceEnabled: true } }) diff --git a/app/src/main/services/dll-bootstrap.ts b/app/src/main/services/dll-bootstrap.ts new file mode 100644 index 0000000..9541093 --- /dev/null +++ b/app/src/main/services/dll-bootstrap.ts @@ -0,0 +1,51 @@ +import fs from 'fs' +import log from 'electron-log' +import { CS_OK } from '../constants' +import { mainAppState } from './app-state' +import { configStore } from './config-store' +import { loadDllModule } from './dll-loader' +import type { InitParams } from './work-dll.service' + +let dllInitAttempted = false + +export function isDllInitAttempted(): boolean { + return dllInitAttempted +} + +export async function ensureDllInitialized( + params?: Partial +): Promise<{ code: number; warning?: string }> { + if (dllInitAttempted) { + return { code: CS_OK } + } + const sharedDir = + params?.sharedDir || (configStore.get('sharedDir') as string) || 'C:\\PrintTasks' + try { + const dll = await loadDllModule() + fs.mkdirSync(sharedDir, { recursive: true }) + const code = dll.dllInit({ + sharedDir, + keepCombinedImage: params?.keepCombinedImage, + stopOnFailure: params?.stopOnFailure, + cleanTaskFile: params?.cleanTaskFile, + autoRetryTimes: params?.autoRetryTimes, + rejectConfig: params?.rejectConfig, + logLevel: params?.logLevel, + outBack: params?.outBack + }) + dllInitAttempted = true + mainAppState.initialized = true + configStore.set('sharedDir', sharedDir) + log.info('DLL initialized', { sharedDir, code }) + if (code === CS_OK) return { code } + return { + code, + warning: '打印机未连接或驱动未就绪,可继续配置任务,接好设备后重启应用' + } + } catch (err) { + mainAppState.initialized = false + dllInitAttempted = false + log.error('DLL init failed', err) + throw err + } +} diff --git a/app/src/main/services/dll-loader.ts b/app/src/main/services/dll-loader.ts new file mode 100644 index 0000000..c3b7e52 --- /dev/null +++ b/app/src/main/services/dll-loader.ts @@ -0,0 +1,20 @@ +import { setupNativeWorkingDir } from './native-path' + +type DllModule = typeof import('./work-dll.service') + +let dllMod: DllModule | null = null +let nativeReady = false + +function ensureNativeEnv(): void { + if (nativeReady) return + setupNativeWorkingDir() + nativeReady = true +} + +export async function loadDllModule(): Promise { + ensureNativeEnv() + if (!dllMod) { + dllMod = await import('./work-dll.service') + } + return dllMod +} diff --git a/app/src/main/services/native-path.ts b/app/src/main/services/native-path.ts index b19eed5..a6751b8 100644 --- a/app/src/main/services/native-path.ts +++ b/app/src/main/services/native-path.ts @@ -88,5 +88,10 @@ export function setupNativeWorkingDir(): void { if (!process.env.PATH?.toLowerCase().includes(nativeDir.toLowerCase())) { process.env.PATH = `${pathHead}${path.delimiter}${process.env.PATH || ''}` } - log.debug(`Native DLL search path: ${nativeDir}; cwd kept at ${process.cwd()}`) + try { + process.chdir(execDir) + } catch (e) { + log.warn(`chdir to ${execDir} failed`, e) + } + log.debug(`Native DLL search path: ${nativeDir}; cwd=${process.cwd()}`) } diff --git a/app/src/main/services/open-design-app.ts b/app/src/main/services/open-design-app.ts index c7da18d..97435df 100644 --- a/app/src/main/services/open-design-app.ts +++ b/app/src/main/services/open-design-app.ts @@ -2,7 +2,7 @@ import { shell } from 'electron' import fs from 'fs' import path from 'path' -export function validateDesignAppPath(exePath: string): { ok: true } | { ok: false; message: string } { +function validateDesignAppPath(exePath: string): { ok: true } | { ok: false; message: string } { const p = exePath.trim() if (!p) { return { ok: false, message: '请在 cardsoon.config.json 中配置 designAppPath' } @@ -14,7 +14,6 @@ export function validateDesignAppPath(exePath: string): { ok: true } | { ok: fal return { ok: true } } -/** 由系统启动外部程序;空字符串表示成功,非空为失败原因 */ export async function openDesignApp( exePath: string ): Promise<{ ok: true } | { ok: false; message: string }> { diff --git a/app/src/main/services/poll-manager.ts b/app/src/main/services/poll-manager.ts index c93a725..b41751c 100644 --- a/app/src/main/services/poll-manager.ts +++ b/app/src/main/services/poll-manager.ts @@ -1,12 +1,20 @@ import { BrowserWindow } from 'electron' import log from 'electron-log' -import { POLL_INTERVAL_MS } from '../constants' +import { POLL_INTERVAL_MS, CS_OK } from '../constants' +import { + USB_TASK_COMPLETED, + USB_TASK_FAILED, + clampUsbCopyProgress, + usbTaskStatusHint +} from '@shared/usb-copy-state' import { mainAppState } from './app-state' import { emitTrace } from '../utils/trace-bridge' -import { dllGetJobStateById, dllGetUsbCopyState } from './work-dll.service' +import { loadDllModule } from './dll-loader' let jobTimer: ReturnType | null = null let usbTimer: ReturnType | null = null +let cardTimer: ReturnType | null = null +let usbPollGen = 0 let jobId = '' let mainWindow: BrowserWindow | null = null @@ -35,84 +43,145 @@ export function stopJobPoll(resetMode = false): void { } } -export function stopUsbPoll(): void { +export function stopUsbPoll(resetMode = false): void { + usbPollGen += 1 if (usbTimer) { clearInterval(usbTimer) usbTimer = null } + if (resetMode && mainAppState.mode === 'usbCopying') { + mainAppState.mode = 'ready' + } +} + +export function stopCardPositionPoll(): void { + if (cardTimer) { + clearInterval(cardTimer) + cardTimer = null + } } export function stopAllPolls(): void { stopJobPoll(true) - stopUsbPoll() + stopUsbPoll(true) + stopCardPositionPoll() } export function startJobPoll(id: string): void { stopJobPoll(false) jobId = id jobTimer = setInterval(() => { - try { - const r = dllGetJobStateById(jobId) - const failed = r.jobState === 4 - const cancelled = r.jobState === 6 - const finished = r.jobState === 100 - const terminal = failed || cancelled - const tick = { - jobId, - queryErrorCode: r.queryErrorCode, - jobState: r.jobState, - progress: r.progress, - terminal, - failed, - cancelled, - finished - } - emitTrace('[poll] job:poll-tick', tick) - send('job:poll-tick', tick) - if (r.queryErrorCode !== 0) { - log.warn('GetJobStateById query failed', r.queryErrorCode) - stopJobPoll(true) - return - } - if (failed || cancelled) { + void (async () => { + try { + const dll = await loadDllModule() + const r = dll.dllGetJobStateById(jobId) + const failed = r.jobState === 4 + const cancelled = r.jobState === 6 + const finished = r.jobState === 100 + const terminal = failed || cancelled + const tick = { + jobId, + queryErrorCode: r.queryErrorCode, + jobState: r.jobState, + progress: r.progress, + terminal, + failed, + cancelled, + finished + } + emitTrace('[poll] job:poll-tick', tick) + send('job:poll-tick', tick) + if (r.queryErrorCode !== 0) { + log.warn('GetJobStateById query failed', r.queryErrorCode) + return + } + if (failed || cancelled) { + stopJobPoll(true) + } else if (finished) { + stopJobPoll(false) + } + } catch (e) { + log.error('job poll error', e) stopJobPoll(true) } - } catch (e) { - log.error('job poll error', e) - stopJobPoll(true) - } + })() }, POLL_INTERVAL_MS) } export function startUsbPoll(): void { - stopUsbPoll() + stopUsbPoll(false) + const gen = usbPollGen + void pollUsbOnce(gen).catch((e) => log.error('usb poll error', e)) usbTimer = setInterval(() => { - try { - const r = dllGetUsbCopyState() - const failed = r.taskStatus === 3 - const success = r.taskStatus === 2 - const terminal = failed || success - const tick = { - taskStatus: r.taskStatus, - progress: r.progress, - terminal, - failed, - success - } - emitTrace('[poll] usb:poll-tick', tick) - send('usb:poll-tick', tick) - if (terminal) { - stopUsbPoll() - mainAppState.mode = 'ready' - } - } catch (e) { + void pollUsbOnce(gen).catch((e) => { log.error('usb poll error', e) - stopUsbPoll() - mainAppState.mode = 'ready' - } + stopUsbPoll(true) + }) + }, POLL_INTERVAL_MS) +} + +async function pollUsbOnce(gen: number): Promise { + if (gen !== usbPollGen) return + const dll = await loadDllModule() + if (gen !== usbPollGen) return + const r = dll.dllGetUsbCopyState() + if (gen !== usbPollGen) return + const copyProgress = clampUsbCopyProgress(r.progress) + const failed = r.taskStatus === USB_TASK_FAILED + const success = r.taskStatus === USB_TASK_COMPLETED + const terminal = failed || success + let errorMessage = '' + if (failed) { + const errText = dll.dllGetPrinterErrorStr(-1) + errorMessage = errText || usbTaskStatusHint(USB_TASK_FAILED) + } + const tick = { + queryCode: r.queryCode, + taskStatus: r.taskStatus, + progress: copyProgress, + terminal, + failed, + success, + errorMessage + } + emitTrace('[poll] usb:poll-tick', tick) + if (gen !== usbPollGen) return + send('usb:poll-tick', tick) + if (r.queryCode !== CS_OK) { + log.warn('GetUsbCopyState query failed', r.queryCode) + return + } + if (terminal) { + stopUsbPoll(false) + } +} + +export function startCardPositionPoll(): void { + stopCardPositionPoll() + cardTimer = setInterval(() => { + void (async () => { + try { + const dll = await loadDllModule() + if (!dll.isCardPositionApiAvailable()) return + const r = dll.dllGetPrinterCardPosition() + const tick = { queryCode: r.queryCode, position: r.position } + emitTrace('[poll] card:position-tick', tick) + send('card:position-tick', tick) + } catch (e) { + log.error('card position poll error', e) + } + })() }, POLL_INTERVAL_MS) } export function getActiveJobId(): string { return jobId } + +export function isJobPollActive(): boolean { + return jobTimer !== null +} + +export function isUsbPollActive(): boolean { + return usbTimer !== null +} diff --git a/app/src/main/services/work-dll.service.ts b/app/src/main/services/work-dll.service.ts index fa93a4e..ebe33f2 100644 --- a/app/src/main/services/work-dll.service.ts +++ b/app/src/main/services/work-dll.service.ts @@ -1,5 +1,6 @@ import path from 'path' import koffi from 'koffi' +import log from 'electron-log' import { CS_OK, JOB_ID_BUF_SIZE, LOG_FATAL_FLAG } from '../constants' import { emitTrace, isTraceEnabled } from '../utils/trace-bridge' import { getNativeDir } from './native-path' @@ -22,6 +23,10 @@ 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_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 // eslint-disable-next-line @typescript-eslint/no-explicit-any let SAPI_RestJobEx: any = null @@ -37,8 +42,18 @@ let SAPI_GetUsbCopyState: any = null let SAPI_PrinterResetprinter: any = null // eslint-disable-next-line @typescript-eslint/no-explicit-any let SAPI_PrinterMovetoreject: any = null +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let SAPI_PrinterMovetousbreader: any = null +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let SAPI_GetPrinterCardPosition: any = null +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let SAPI_UploadFile: any = null let hasRejectApi = false +let hasCardPositionApi = false let hasCancelApi = false +let hasUploadApi = false +let hasPrinterInfoEx = false +let hasUsbReaderApi = false let loggedCancelMissing = false let loggedRejectMissing = false @@ -63,6 +78,31 @@ function traceCall(name: string, args: Record | undefined, f } } +function readPrinterJsonFromOutPtr(len: number, outPtr: Buffer): { code: number; json?: Record } { + if (len <= 0) return { code: len } + const ptr = koffi.decode(outPtr, 0, 'void *') as number + if (!ptr) return { code: len } + try { + const jsonStr = koffi.decode(ptr, 'char', len) as string + if (!jsonStr?.trim()) return { code: len } + try { + return { code: len, json: JSON.parse(jsonStr) as Record } + } catch { + return { code: len } + } + } finally { + if (SAPI_FreePrinterInfo) { + try { + SAPI_FreePrinterInfo(ptr) + } catch (e) { + log.warn('SAPI_FreePrinterInfo', e) + } + } else { + koffi.free(ptr) + } + } +} + function loadLibrary(): void { if (lib) return const dllPath = path.join(getNativeDir(), 'workDll.dll') @@ -79,6 +119,25 @@ 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_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 { + SAPI_UploadFile = lib.func('int __stdcall SAPI_UploadFile(str, str, str)') + hasUploadApi = true + } catch { + SAPI_UploadFile = null + hasUploadApi = false + log.warn('SAPI_UploadFile not in workDll') + } + try { SAPI_AdminJobCancel = lib.func('int __stdcall SAPI_AdminJobCancel(str)') hasCancelApi = true @@ -101,6 +160,33 @@ function loadLibrary(): void { emitTrace('[dll] SAPI_PrinterMovetoreject not in workDll (optional)') } } + + try { + SAPI_PrinterMovetousbreader = lib.func('int __stdcall SAPI_PrinterMovetousbreader()') + hasUsbReaderApi = true + } catch { + SAPI_PrinterMovetousbreader = null + hasUsbReaderApi = false + emitTrace('[dll] SAPI_PrinterMovetousbreader not in workDll (optional)') + } + + try { + SAPI_GetPrinterCardPosition = lib.func('int __stdcall SAPI_GetPrinterCardPosition(_Out_ int *)') + hasCardPositionApi = true + } catch { + SAPI_GetPrinterCardPosition = null + hasCardPositionApi = false + emitTrace('[dll] SAPI_GetPrinterCardPosition not in workDll (optional)') + } + + log.info('workDll loaded', { + upload: hasUploadApi, + printerInfoEx: hasPrinterInfoEx, + cancel: hasCancelApi, + reject: hasRejectApi, + usbReader: hasUsbReaderApi, + cardPosition: hasCardPositionApi + }) } export function isRejectApiAvailable(): boolean { @@ -113,6 +199,21 @@ export function isCancelApiAvailable(): boolean { return hasCancelApi } +export function isUploadApiAvailable(): boolean { + loadLibrary() + return hasUploadApi +} + +export function isUsbReaderApiAvailable(): boolean { + loadLibrary() + return hasUsbReaderApi +} + +export function isCardPositionApiAvailable(): boolean { + loadLibrary() + return hasCardPositionApi +} + export function dllInit(params: InitParams): number { return traceCall( 'SAPI_Init', @@ -142,29 +243,33 @@ export function dllInit(params: InitParams): number { ) } -export function dllGetPrinterInfo(): { code: number; json?: Record } { - return traceCall('SAPI_GetPrinterInfo', undefined, () => { +function dllGetPrinterInfoInternal( + apiName: 'SAPI_GetPrinterInfo' | 'SAPI_GetPrinterInfoEx', + fn: (outPtr: Buffer) => number +): { code: number; json?: Record } { + return traceCall(apiName, undefined, () => { loadLibrary() const outPtr = koffi.alloc('void *', 8) try { - const len = SAPI_GetPrinterInfo!(outPtr) as number - if (len <= 0) return { code: len } - const ptr = koffi.decode(outPtr, 0, 'void *') as number - if (!ptr) return { code: len } - const jsonStr = koffi.decode(ptr, 'char', len) as string - koffi.free(ptr) - if (!jsonStr?.trim()) return { code: len } - try { - return { code: len, json: JSON.parse(jsonStr) as Record } - } catch { - return { code: len } - } + const len = fn(outPtr) as number + return readPrinterJsonFromOutPtr(len, outPtr) } finally { koffi.free(outPtr) } }) } +export function dllGetPrinterInfo(): { code: number; json?: Record } { + 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)) +} + export function dllGetPrinterErrorStr(errorNo = -1): string { return traceCall('SAPI_GetPrinterErrorStr', { errorNo }, () => { loadLibrary() @@ -173,6 +278,18 @@ export function dllGetPrinterErrorStr(errorNo = -1): string { }) } +export function dllUploadFile(userDir: string, fileName: string, fileText: string): number { + return traceCall( + 'SAPI_UploadFile', + { userDir, fileName, bytes: Buffer.byteLength(fileText ?? '', 'utf8') }, + () => { + loadLibrary() + if (!SAPI_UploadFile) throw new Error('UPLOAD_API_UNAVAILABLE') + return SAPI_UploadFile(userDir, fileName, fileText) as number + } + ) +} + export function dllRestJobEx(json: string): { code: number; jobId: string } { return traceCall('SAPI_RestJobEx', { jsonBytes: Buffer.byteLength(json ?? '', 'utf8') }, () => { loadLibrary() @@ -216,13 +333,22 @@ export function dllCopyFromUsb(destFolder: string, cardOutput: number): number { }) } -export function dllGetUsbCopyState(): { taskStatus: number; progress: number } { +export function dllGetUsbCopyState(): { + queryCode: number + taskStatus: number + /** copy_progress 0-100 */ + progress: number +} { return traceCall('SAPI_GetUsbCopyState', undefined, () => { loadLibrary() const taskStatus = [0] - const progress = [0] - SAPI_GetUsbCopyState!(taskStatus, progress) - return { taskStatus: taskStatus[0], progress: progress[0] } + const copyProgress = [0] + const queryCode = SAPI_GetUsbCopyState!(taskStatus, copyProgress) as number + return { + queryCode, + taskStatus: taskStatus[0], + progress: copyProgress[0] + } }) } @@ -233,6 +359,14 @@ export function dllPrinterReset(): number { }) } +export function dllPrinterMoveToUsbReader(): number { + return traceCall('SAPI_PrinterMovetousbreader', undefined, () => { + loadLibrary() + if (!SAPI_PrinterMovetousbreader) throw new Error('USB_READER_API_UNAVAILABLE') + return SAPI_PrinterMovetousbreader() as number + }) +} + export function dllPrinterReject(): number { return traceCall('SAPI_PrinterMovetoreject', undefined, () => { loadLibrary() @@ -240,3 +374,13 @@ export function dllPrinterReject(): number { return SAPI_PrinterMovetoreject() as number }) } + +export function dllGetPrinterCardPosition(): { queryCode: number; position: number } { + return traceCall('SAPI_GetPrinterCardPosition', undefined, () => { + loadLibrary() + if (!SAPI_GetPrinterCardPosition) throw new Error('CARD_POSITION_API_UNAVAILABLE') + const position = [0] + const queryCode = SAPI_GetPrinterCardPosition!(position) as number + return { queryCode, position: position[0] } + }) +} diff --git a/app/src/main/utils/job-csv.ts b/app/src/main/utils/job-csv.ts new file mode 100644 index 0000000..039e975 --- /dev/null +++ b/app/src/main/utils/job-csv.ts @@ -0,0 +1,21 @@ +import fs from 'fs' +import path from 'path' + +export interface JobCsvRow { + originName: string + value: string +} + +export function buildSoonCsvText(rows: JobCsvRow[]): string { + const line1 = rows.map((r) => r.originName).join(',') + const line2 = rows.map((r) => r.value).join(',') + return `${line1}\n${line2}` +} + +export function writeJobCsv(sharedDir: string, taskId: string, rows: JobCsvRow[]): string { + const dir = path.join(sharedDir, taskId) + fs.mkdirSync(dir, { recursive: true }) + const csvPath = path.join(dir, 'temp.csv') + fs.writeFileSync(csvPath, buildSoonCsvText(rows), 'utf8') + return csvPath +} diff --git a/app/src/main/utils/parse-soon.ts b/app/src/main/utils/parse-soon.ts index d51e199..e990a7c 100644 --- a/app/src/main/utils/parse-soon.ts +++ b/app/src/main/utils/parse-soon.ts @@ -4,6 +4,7 @@ import { pathToFileURL } from 'url' export interface TemplateFieldRow { label: string value: string + originName: string } export interface ParsedSoonTemplate { @@ -12,6 +13,8 @@ export interface ParsedSoonTemplate { fields: TemplateFieldRow[] } +const SOON_FIELD_TYPES = new Set([1, 3, 4, 5]) + function pickArray(obj: Record, key: string): Record[] { const entry = Object.entries(obj).find(([k]) => k.toLowerCase() === key.toLowerCase()) if (!Array.isArray(entry?.[1])) return [] @@ -38,18 +41,53 @@ function sideLabel(side: 'front' | 'back'): string { return side === 'front' ? '正面' : '背面' } -function resolveAssetPath(soonPath: string, ref: string): string { +function toImageUrl(soonPath: string, ref: string): string { if (!ref) return '' + if (/^(data:|https?:|file:)/i.test(ref)) return ref const clean = ref.replace(/^file:\/\//i, '') const abs = path.isAbsolute(clean) ? clean : path.join(path.dirname(soonPath), clean) return pathToFileURL(abs).href } -function toFieldLabel(name: string, side: 'front' | 'back'): string { - return `${name} [${sideLabel(side)}]` +function resolveAssetPath(soonPath: string, ref: string): string { + return toImageUrl(soonPath, ref) } -export function parseSoonTemplate(soonPath: string, raw: Record): ParsedSoonTemplate { +function toFieldLabel(name: string, side: 'front' | 'back'): string { + return `${name}[${sideLabel(side)}]` +} + +function parseSoonWorkerDisk(soonPath: string, raw: Record): ParsedSoonTemplate { + const fields: TemplateFieldRow[] = [] + + const appendSide = (arr: unknown, side: '正面' | '背面') => { + if (!Array.isArray(arr)) return + for (const item of arr) { + if (!item || typeof item !== 'object') continue + const o = item as Record + const type = Number(o.type) + if (!SOON_FIELD_TYPES.has(type)) continue + const name = String(o.name ?? '').trim() + if (!name) continue + const value = o.DefaultText == null ? '' : String(o.DefaultText) + fields.push({ label: `${name}[${side}]`, value, originName: name }) + } + } + + appendSide(raw.frontData, '正面') + appendSide(raw.backData, '背面') + + const frontPic = String(raw.frontDisplayPic ?? '').trim() + const backPic = String(raw.backDisplayPic ?? '').trim() + + return { + frontImageUrl: toImageUrl(soonPath, frontPic), + backImageUrl: toImageUrl(soonPath, backPic), + fields + } +} + +function parseSoonLegacy(soonPath: string, raw: Record): ParsedSoonTemplate { const imgs = pickArray(raw, 'Img') const texts = pickArray(raw, 'Text') @@ -66,7 +104,7 @@ export function parseSoonTemplate(soonPath: string, raw: Record if (side === 'front') { if (!frontImageUrl) frontImageUrl = url const name = pickStr(item, ['name', 'field', 'key']) || 'IMAGE' - fields.push({ label: toFieldLabel(name, 'front'), value: fileRef }) + fields.push({ label: toFieldLabel(name, 'front'), value: fileRef, originName: name }) } else if (!backImageUrl) { backImageUrl = url } @@ -78,8 +116,20 @@ export function parseSoonTemplate(soonPath: string, raw: Record const value = pickStr(item, ['value', 'text', 'default', 'content', 'data']) let side = sideOf(item) if (!side) side = /image|img|front/i.test(name) ? 'front' : 'back' - fields.push({ label: toFieldLabel(name, side), value }) + fields.push({ label: toFieldLabel(name, side), value, originName: name }) }) return { frontImageUrl, backImageUrl, fields } } + +export function parseSoonTemplate(soonPath: string, raw: Record): ParsedSoonTemplate { + if ( + Array.isArray(raw.frontData) || + Array.isArray(raw.backData) || + raw.frontDisplayPic != null || + raw.backDisplayPic != null + ) { + return parseSoonWorkerDisk(soonPath, raw) + } + return parseSoonLegacy(soonPath, raw) +} diff --git a/app/src/main/utils/stage-job-payload.ts b/app/src/main/utils/stage-job-payload.ts new file mode 100644 index 0000000..bcbab85 --- /dev/null +++ b/app/src/main/utils/stage-job-payload.ts @@ -0,0 +1,163 @@ +import fs from 'fs' +import path from 'path' +import log from 'electron-log' +import { CS_OK } from '../constants' +import { cleanPathPattern } from '@shared/path-pattern' +import { getDirectorySizeBytes } from './dir-size' + +export type JobStageDll = { + dllUploadFile: (userDir: string, fileName: string, fileText: string) => number + isUploadApiAvailable: () => boolean +} + +function copyIfExists(src: string, dest: string): void { + if (!fs.existsSync(src)) return + fs.mkdirSync(path.dirname(dest), { recursive: true }) + fs.copyFileSync(src, dest) +} + +function uploadText( + dll: JobStageDll, + userDir: string, + fileName: string, + text: string +): boolean { + if (!dll.isUploadApiAvailable()) return false + const code = dll.dllUploadFile(userDir, fileName, fileText) + if (code !== CS_OK) { + log.warn('SAPI_UploadFile failed', { userDir, fileName, code }) + return false + } + return true +} + +function stageSoonAssets(taskDir: string, soonSrc: string, soonDest: string): void { + copyIfExists(soonSrc, soonDest) + let raw: Record + try { + raw = JSON.parse(fs.readFileSync(soonDest, 'utf8')) as Record + } catch (e) { + log.warn('stageSoonAssets: parse soon failed', e) + return + } + const soonDir = path.dirname(soonSrc) + for (const key of ['frontDisplayPic', 'backDisplayPic']) { + const ref = raw[key] + if (typeof ref !== 'string' || !ref.trim()) continue + const clean = ref.replace(/^file:\/\//i, '').trim() + const assetSrc = path.isAbsolute(clean) ? clean : path.join(soonDir, clean) + const assetDest = path.join(taskDir, path.basename(clean)) + copyIfExists(assetSrc, assetDest) + } +} + +/** 保留目录级 path_file,不展开为单文件列表 */ +function normalizeCopyPaths(payload: Record): void { + if (!Array.isArray(payload.path_file)) { + throw new Error('拷贝任务缺少 path_file') + } + const normalized: string[] = [] + for (const entry of payload.path_file) { + if (typeof entry !== 'string' || !entry.trim()) continue + const target = cleanPathPattern(entry) + if (!target || !fs.existsSync(target)) { + throw new Error(`拷贝路径不存在: ${entry}`) + } + let st: fs.Stats + try { + st = fs.statSync(target) + } catch { + throw new Error(`拷贝路径不可访问: ${target}`) + } + if (st.isFile()) { + normalized.push(target) + continue + } + if (!st.isDirectory()) { + throw new Error(`拷贝路径无效: ${target}`) + } + if (getDirectorySizeBytes(target) <= 0) { + throw new Error(`拷贝路径下没有可拷贝的文件: ${target}`) + } + normalized.push(target) + } + if (normalized.length === 0) { + throw new Error('拷贝路径下没有可拷贝的文件') + } + payload.path_file = normalized +} + +/** staging 后按 has_* 裁剪字段,并校验 RestJobEx 必填项 */ +function finalizeRestJobPayload(payload: Record): void { + const hasCopy = payload.has_copy_task === true + const hasPrint = payload.has_print_task === true + if (!hasCopy && !hasPrint) { + throw new Error('任务需包含拷贝或打印') + } + + if (hasPrint) { + if (typeof payload.json_file !== 'string' || !payload.json_file.trim()) { + throw new Error('打印任务缺少 json_file') + } + if (!payload.udf_file) delete payload.udf_file + } else { + delete payload.json_file + delete payload.udf_file + } + + if (hasCopy) { + const paths = payload.path_file + if ( + !Array.isArray(paths) || + paths.length === 0 || + !paths.every((p) => typeof p === 'string' && p.trim()) + ) { + throw new Error('拷贝任务缺少 path_file') + } + } else { + delete payload.path_file + } +} + +/** 通过 SAPI_UploadFile + 本地落盘,准备 RestJobEx 所需路径 */ +export function stageJobPayloadJson( + json: string, + sharedDir: string, + dll: JobStageDll +): { json: string; taskDir: string } { + const payload = JSON.parse(json) as Record + const taskId = String(payload.task_id || '').trim() + if (!taskId) throw new Error('task_id 缺失') + + const taskDir = path.join(sharedDir, taskId) + fs.mkdirSync(taskDir, { recursive: true }) + const userDir = taskId + + const udfFile = payload.udf_file + if (typeof udfFile === 'string' && udfFile.trim() && fs.existsSync(udfFile.trim())) { + const csvText = fs.readFileSync(udfFile.trim(), 'utf8') + if (!uploadText(dll, userDir, 'temp.csv', csvText)) { + copyIfExists(udfFile.trim(), path.join(taskDir, 'temp.csv')) + } + payload.udf_file = path.join(taskDir, 'temp.csv') + } + + const jsonFile = payload.json_file + if (typeof jsonFile === 'string' && jsonFile.trim()) { + const src = jsonFile.trim() + const base = path.basename(src) + const dest = path.join(taskDir, base) + const soonText = fs.readFileSync(src, 'utf8') + uploadText(dll, userDir, base, soonText) + stageSoonAssets(taskDir, src, dest) + payload.json_file = dest + } + + if (payload.has_copy_task === true) { + normalizeCopyPaths(payload) + } + + finalizeRestJobPayload(payload) + + return { json: JSON.stringify(payload), taskDir } +} diff --git a/app/src/preload/index.ts b/app/src/preload/index.ts index 0ebb9db..9753429 100644 --- a/app/src/preload/index.ts +++ b/app/src/preload/index.ts @@ -14,18 +14,21 @@ const channels = { 'poll:job-stop', 'poll:usb-start', 'poll:usb-stop', + 'poll:card-position-start', + 'poll:card-position-stop', 'dialog:open-directory', 'dialog:open-file', 'fs:path-exists', 'fs:dir-size', 'fs:parse-soon', + 'fs:write-job-csv', 'config:get', 'config:set', 'shell:open-path', 'design:open', 'dll:reject-available' ] as const, - on: ['job:poll-tick', 'usb:poll-tick', 'app:trace'] as const + on: ['job:poll-tick', 'usb:poll-tick', 'card:position-tick', 'app:trace'] as const } const cardsoonApi = { diff --git a/app/src/renderer/index.html b/app/src/renderer/index.html index 5397b51..395249a 100644 --- a/app/src/renderer/index.html +++ b/app/src/renderer/index.html @@ -4,7 +4,7 @@ 卡树数据卡打印系统 diff --git a/app/src/renderer/src/api/cardsoon.ts b/app/src/renderer/src/api/cardsoon.ts index 86e0770..e434e33 100644 --- a/app/src/renderer/src/api/cardsoon.ts +++ b/app/src/renderer/src/api/cardsoon.ts @@ -1,5 +1,5 @@ import { parsePrinterInfoFromDll } from '@shared/printer-info' -import type { InitParamsDTO, IpcResult, JobPollPayload, UsbPollPayload } from '@/types/ipc' +import type { InitParamsDTO, IpcResult, JobPollPayload, UsbPollPayload, CardPositionPollPayload } from '@/types/ipc' import type { PrinterStatusDisplay } from '@/types/printer' function api() { @@ -34,32 +34,43 @@ export async function dllPrinterErrorStr(errorNo = -1): Promise> } -export async function dllJobCreate(json: string): Promise> { - return api().invoke('dll:job-create', json) as Promise> +export async function dllJobCreate( + json: string, + opts?: { resubmit?: boolean } +): Promise> { + return api().invoke('dll:job-create', json, opts) as Promise> } export async function dllJobCancel(jobId: string): Promise { return api().invoke('dll:job-cancel', jobId) as Promise } -export async function dllUsbCopy(destFolder: string, cardOutput: number): Promise { - return api().invoke('dll:usb-copy', { destFolder, cardOutput }) as Promise +export async function dllUsbCopy( + destFolder: string, + cardOutput: number, + opts?: { resubmit?: boolean } +): Promise { + return api().invoke('dll:usb-copy', { destFolder, cardOutput, resubmit: opts?.resubmit }) as Promise } export async function pollJobStart(jobId: string): Promise { return api().invoke('poll:job-start', jobId) as Promise } -export async function pollJobStop(): Promise { - return api().invoke('poll:job-stop') as Promise +export async function pollJobStop(opts?: { resetMode?: boolean }): Promise { + return api().invoke('poll:job-stop', opts) as Promise } -export async function pollUsbStart(): Promise { - return api().invoke('poll:usb-start') as Promise +export async function pollUsbStop(opts?: { resetMode?: boolean }): Promise { + return api().invoke('poll:usb-stop', opts) as Promise } -export async function pollUsbStop(): Promise { - return api().invoke('poll:usb-stop') as Promise +export async function pollCardPositionStart(): Promise { + return api().invoke('poll:card-position-start') as Promise +} + +export async function pollCardPositionStop(): Promise { + return api().invoke('poll:card-position-stop') as Promise } export function onJobPollTick(cb: (p: JobPollPayload) => void): () => void { @@ -70,6 +81,10 @@ export function onUsbPollTick(cb: (p: UsbPollPayload) => void): () => void { return api().on('usb:poll-tick', cb as (...args: unknown[]) => void) } +export function onCardPositionTick(cb: (p: CardPositionPollPayload) => void): () => void { + return api().on('card:position-tick', cb as (...args: unknown[]) => void) +} + export async function dialogOpenDirectory(): Promise> { return api().invoke('dialog:open-directory') as Promise> } @@ -92,11 +107,26 @@ export async function fsDirSize( > } +export async function fsWriteJobCsv(payload: { + taskId: string + rows: { originName: string; value: string }[] +}): Promise> { + return api().invoke('fs:write-job-csv', payload) as Promise> +} + export async function fsParseSoon(filePath: string): Promise< - IpcResult<{ frontImageUrl: string; backImageUrl: string; fields: { label: string; value: string }[] }> + IpcResult<{ + frontImageUrl: string + backImageUrl: string + fields: { label: string; value: string; originName: string }[] + }> > { return api().invoke('fs:parse-soon', filePath) as Promise< - IpcResult<{ frontImageUrl: string; backImageUrl: string; fields: { label: string; value: string }[] }> + IpcResult<{ + frontImageUrl: string + backImageUrl: string + fields: { label: string; value: string; originName: string }[] + }> > } @@ -106,7 +136,7 @@ export async function configGet(): Promise< templateDir: string traceEnabled: boolean lastPrinterStatus?: PrinterStatusDisplay - skipDllInit?: boolean + dllInitialized: boolean }> > { return api().invoke('config:get') as Promise< @@ -115,7 +145,7 @@ export async function configGet(): Promise< templateDir: string traceEnabled: boolean lastPrinterStatus?: PrinterStatusDisplay - skipDllInit?: boolean + dllInitialized: boolean }> > } diff --git a/app/src/renderer/src/components/DistributeSettingsModal.vue b/app/src/renderer/src/components/DistributeSettingsModal.vue deleted file mode 100644 index 60dc593..0000000 --- a/app/src/renderer/src/components/DistributeSettingsModal.vue +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - diff --git a/app/src/renderer/src/composables/useAppBootstrap.ts b/app/src/renderer/src/composables/useAppBootstrap.ts index 5488035..3bc9f63 100644 --- a/app/src/renderer/src/composables/useAppBootstrap.ts +++ b/app/src/renderer/src/composables/useAppBootstrap.ts @@ -1,131 +1,75 @@ import { onMounted } from 'vue' import { notify } from '@/composables/useNotify' -import { - configGet, - dllInit, - dllPrinterInfo, - dllRejectAvailable, - parsePrinterInfo -} from '@/api/cardsoon' -import type { PrinterStatusDisplay } from '@/types/printer' +import { applyPrinterPayload, refreshPrinterHeader } from '@/composables/usePrinterStatus' +import { configGet, dllInit, dllRejectAvailable } from '@/api/cardsoon' import { useAppStore } from '@/stores/app' import { useConfigStore } from '@/stores/config' let bootstrapped = false -function applyPrinterPayload( - configStore: ReturnType, - data: Record -): void { - const snapshot = data.snapshot as PrinterStatusDisplay | undefined - if (snapshot) { - configStore.setPrinter(snapshot) - return +function placeholderStatus(configStore: ReturnType, text: string): void { + if (configStore.printer.statusText === '—') { + configStore.setPrinter({ ...configStore.printer, statusText: text }) } - if (data.fromCache && !data.printerList) { - const { fromCache: _f, liveError: _e, ribbonType, statusText, serialNo, printedCount } = data - configStore.setPrinter({ - ribbonType: String(ribbonType ?? '—'), - statusText: String(statusText ?? '—'), - serialNo: String(serialNo ?? '—'), - printedCount: Number(printedCount ?? 0) - }) - return - } - configStore.setPrinter(parsePrinterInfo(data)) } -export function useAppBootstrap(): { - retryInit: () => Promise - refreshHeader: () => Promise -} { +export function useAppBootstrap(): void { const appStore = useAppStore() const configStore = useConfigStore() - async function hydratePrinterFromLocal(): Promise { + async function hydrateFromConfig() { const cfg = await configGet() if (cfg.ok && cfg.data?.lastPrinterStatus) { configStore.setPrinter(cfg.data.lastPrinterStatus) } + if (cfg.ok && cfg.data?.sharedDir) { + configStore.setSharedDir(cfg.data.sharedDir) + } + return cfg } - async function refreshHeader(): Promise { - const info = await dllPrinterInfo() - if (info.ok && info.data) { - applyPrinterPayload(configStore, info.data) - if (info.data.fromCache) { - const msg = String(info.data.liveError || '未连接打印机') - configStore.setPrinter({ - ...configStore.printer, - statusText: msg - }) - } - return + async function syncRejectApi(): Promise { + try { + const rej = await dllRejectAvailable() + if (rej.ok && rej.data) configStore.rejectApiAvailable = rej.data.available + } catch { + /* optional API */ } - const cfg = await configGet() - if (cfg.ok && cfg.data?.lastPrinterStatus) { - configStore.setPrinter({ - ...cfg.data.lastPrinterStatus, - statusText: info.message || '未连接打印机' - }) - return - } - configStore.setPrinter({ - ...configStore.printer, - statusText: info.message || '未连接打印机' - }) } - async function doInit(): Promise { - await hydratePrinterFromLocal() + async function bootstrap(): Promise { + const cfg = await hydrateFromConfig() + if (cfg.ok && cfg.data?.dllInitialized) { + appStore.setInitialized(true) + placeholderStatus(configStore, '就绪') + await syncRejectApi() + window.setTimeout(() => void refreshPrinterHeader(configStore), 1500) + return + } - const cfg = await configGet() const sharedDir = cfg.data?.sharedDir || '' configStore.setSharedDir(sharedDir) - if (import.meta.env.DEV && cfg.data?.skipDllInit === true) { - appStore.setInitialized(false, '开发模式已跳过 DLL 初始化') - configStore.setPrinter({ ...configStore.printer, statusText: '未初始化(开发)' }) - return - } - const init = await dllInit({ sharedDir }) if (!init.ok) { appStore.setInitialized(false, init.message || 'Init 失败') - configStore.setPrinter({ ...configStore.printer, statusText: '未初始化' }) + configStore.setPrinter({ ...configStore.printer, statusText: '初始化失败' }) notify.error(init.message || '初始化失败,请检查任务目录权限') return } - appStore.setInitialized(true) - const initMeta = init.data as - | { warning?: string; skipped?: boolean; printerReady?: boolean } - | undefined - if (initMeta?.warning) notify.warning(initMeta.warning) - // Init 未就绪时 GetPrinterInfo 可能触发原生 DLL 崩溃,仅用本地缓存 - if (initMeta?.skipped) { - await hydratePrinterFromLocal() - return - } - if (initMeta?.printerReady === true) { - await refreshHeader() - try { - const rej = await dllRejectAvailable() - if (rej.ok && rej.data) configStore.rejectApiAvailable = rej.data.available - } catch { - /* optional API */ - } - return - } - await hydratePrinterFromLocal() + appStore.setInitialized(true) + const initMeta = init.data as { warning?: string } | undefined + if (initMeta?.warning) notify.warning(initMeta.warning) + placeholderStatus(configStore, initMeta?.warning ? '未连接打印机' : '就绪') + await syncRejectApi() + window.setTimeout(() => void refreshPrinterHeader(configStore), 1500) } onMounted(() => { if (bootstrapped) return bootstrapped = true window.setTimeout(() => { - void doInit() - }, 300) + void bootstrap() + }, 100) }) - - return { retryInit: doInit, refreshHeader } } diff --git a/app/src/renderer/src/composables/useNotify.ts b/app/src/renderer/src/composables/useNotify.ts index d1c6e23..580f678 100644 --- a/app/src/renderer/src/composables/useNotify.ts +++ b/app/src/renderer/src/composables/useNotify.ts @@ -11,9 +11,9 @@ export const notify = { info: (message: string, durationMs?: number) => push('info', message, durationMs) } -const INIT_HINT = '系统未初始化,请进入「数据分发 → 设置」重试 Init' +const INIT_HINT = '系统未就绪,请重启应用或检查打印机与任务目录' /** 未初始化等业务拦截时的统一提示 */ export function notifyRequireInit(action?: string): void { - notify.warning(action ? `系统未初始化,无法${action}` : INIT_HINT) + notify.warning(action ? `系统未就绪,无法${action}` : INIT_HINT) } diff --git a/app/src/renderer/src/composables/usePrinterStatus.ts b/app/src/renderer/src/composables/usePrinterStatus.ts new file mode 100644 index 0000000..6b881ab --- /dev/null +++ b/app/src/renderer/src/composables/usePrinterStatus.ts @@ -0,0 +1,39 @@ +import { dllPrinterInfo, parsePrinterInfo } from '@/api/cardsoon' +import { useConfigStore } from '@/stores/config' +import type { PrinterStatusDisplay } from '@/types/printer' + +export function applyPrinterPayload( + configStore: ReturnType, + data: Record +): void { + const snapshot = data.snapshot as PrinterStatusDisplay | undefined + if (snapshot) { + configStore.setPrinter(snapshot) + return + } + if (data.printerList != null || data.serial_no != null || data.SerialNo != null) { + configStore.setPrinter(parsePrinterInfo(data)) + return + } + if (data.fromCache) { + configStore.setPrinter({ + ribbonType: String(data.ribbonType ?? configStore.printer.ribbonType), + statusText: String(data.statusText ?? configStore.printer.statusText), + serialNo: String(data.serialNo ?? configStore.printer.serialNo), + printedCount: Number(data.printedCount ?? configStore.printer.printedCount) + }) + } +} + +export async function refreshPrinterHeader( + configStore: ReturnType +): Promise { + try { + const info = await dllPrinterInfo() + if (info.ok && info.data) { + applyPrinterPayload(configStore, info.data) + } + } catch { + /* 无打印机时不阻塞 */ + } +} diff --git a/app/src/renderer/src/mocks/job-poll.ts b/app/src/renderer/src/mocks/job-poll.ts deleted file mode 100644 index ad3ebfc..0000000 --- a/app/src/renderer/src/mocks/job-poll.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { onMounted, onUnmounted, ref } from 'vue' -import { useJobStore } from '@/stores/job' - -const CIRCLE_LEN = 283 - -export function useMockJobPoll() { - const progress = ref(0) - const jobStore = useJobStore() - let timer: ReturnType | null = null - - const strokeOffset = ref(CIRCLE_LEN) - - function tick() { - progress.value = Math.min(100, progress.value + 8) - strokeOffset.value = CIRCLE_LEN - (CIRCLE_LEN * progress.value) / 100 - if (progress.value >= 100) { - jobStore.successCount += 1 - progress.value = 0 - strokeOffset.value = CIRCLE_LEN - } - } - - onMounted(() => { - timer = setInterval(tick, 1000) - }) - - onUnmounted(() => { - if (timer) clearInterval(timer) - }) - - return { progress, strokeOffset } -} diff --git a/app/src/renderer/src/mocks/printer.ts b/app/src/renderer/src/mocks/printer.ts deleted file mode 100644 index 1334a50..0000000 --- a/app/src/renderer/src/mocks/printer.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { PrinterStatusDisplay } from '@/types/printer' - -/** 阶段一 Header 展示;阶段二由 GetPrinterInfo 替换 */ -export const mockPrinterStatus: PrinterStatusDisplay = { - ribbonType: 'YMCKO', - statusText: '50/300', - serialNo: 'S103B29035', - printedCount: 190 -} diff --git a/app/src/renderer/src/router/guards.ts b/app/src/renderer/src/router/guards.ts index 03432d4..1238456 100644 --- a/app/src/renderer/src/router/guards.ts +++ b/app/src/renderer/src/router/guards.ts @@ -1,43 +1,43 @@ -import type { Router } from 'vue-router' -import { useJobStore } from '@/stores/job' -import { useAppStore } from '@/stores/app' - -export function setupRouterGuards(router: Router): void { - router.beforeEach((to, from) => { - const job = useJobStore() - const app = useAppStore() - - if (to.path === '/distribute/running' && !job.jobId) { - return { path: '/distribute/config' } - } - - if (to.path === '/distribute/failed' && job.failCount === 0) { - return { path: '/distribute/config' } - } - - if (to.path === '/collect/running' && app.mode !== 'usbCopying') { - return { path: '/collect' } - } - - if (to.path === '/collect' && app.mode === 'distributing') { - return { path: '/home' } - } - - if (app.mode === 'usbCopying') { - if (to.path.startsWith('/distribute')) return { path: '/collect/running' } - if (from.path === '/collect/running') { - const allowed = ['/collect/running', '/collect', '/home'] - if (!allowed.includes(to.path)) return false - } - } - - if (from.path === '/distribute/running' && to.path !== '/distribute/failed') { - if (to.path !== '/distribute/config') { - app.setMode('ready') - return { path: '/distribute/config' } - } - } - - return true - }) -} +import type { Router } from 'vue-router' +import { useJobStore } from '@/stores/job' +import { useAppStore } from '@/stores/app' + +export function setupRouterGuards(router: Router): void { + router.beforeEach((to, from) => { + const job = useJobStore() + const app = useAppStore() + + if (to.path === '/distribute/running' && !job.jobId && app.mode !== 'distributing') { + return { path: '/distribute/config' } + } + + if (to.path === '/distribute/failed') { + return { path: '/distribute/config' } + } + + if (to.path === '/collect/running' && app.mode !== 'usbCopying' && app.mode !== 'ready') { + return { path: '/collect' } + } + + if (to.path === '/collect' && app.mode === 'distributing') { + return { path: '/home' } + } + + if (app.mode === 'usbCopying' && to.path.startsWith('/distribute')) { + return { path: '/collect/running' } + } + + if (from.path === '/distribute/running' && app.mode === 'distributing') { + if (to.path === '/distribute/config') return true + return { path: '/distribute/config' } + } + + if (from.path === '/collect/running' && app.mode === 'usbCopying') { + const allowed = ['/collect/running', '/collect', '/home'] + if (!allowed.includes(to.path)) return { path: '/collect/running' } + } + + return true + }) +} + \ No newline at end of file diff --git a/app/src/renderer/src/stores/distributeForm.ts b/app/src/renderer/src/stores/distributeForm.ts index 603c159..2d36518 100644 --- a/app/src/renderer/src/stores/distributeForm.ts +++ b/app/src/renderer/src/stores/distributeForm.ts @@ -3,6 +3,7 @@ import { defineStore } from 'pinia' export interface TemplateFieldRow { label: string value: string + originName: string } export interface TemplatePreview { diff --git a/app/src/renderer/src/styles/pages/page1.css b/app/src/renderer/src/styles/pages/page1.css index d5e7066..15f459b 100644 --- a/app/src/renderer/src/styles/pages/page1.css +++ b/app/src/renderer/src/styles/pages/page1.css @@ -22,7 +22,8 @@ align-items: flex-start; gap: 12px; padding: 20px 30px; - min-width: 220px; + min-width: 0; + max-width: 50%; } /* 面板标题 */ @@ -51,6 +52,8 @@ /* ========== 路径选择 - 大按钮设计 ========== */ .m-path-box { width: 100%; + min-width: 0; + box-sizing: border-box; padding: 12px 16px; background: #f8f9fa; border: 1px solid #dee2e6; @@ -59,6 +62,16 @@ font-weight: 600; color: #495057; font-family: monospace; + overflow: hidden; +} + +.m-path-text { + display: block; + width: 100%; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .m-path-btn { diff --git a/app/src/renderer/src/styles/pages/page1.scss b/app/src/renderer/src/styles/pages/page1.scss deleted file mode 100644 index d5e7066..0000000 --- a/app/src/renderer/src/styles/pages/page1.scss +++ /dev/null @@ -1,128 +0,0 @@ -/* - Page 4 - 数据导入模式 - 手机横屏优化:左右分栏,大触摸区域,紧凑布局 -*/ - -/* ========== 手机横屏核心布局 ========== */ -.l-mobile-landscape { - display: flex; - align-items: center; - justify-content: center; - gap: 0; - padding: 0 60px; - height: 100%; - flex: 1; -} - -/* 配置面板 */ -.m-config-panel { - flex: 1; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 12px; - padding: 20px 30px; - min-width: 220px; -} - -/* 面板标题 */ -.m-panel-title { - font-size: 14px; - font-weight: 700; - color: #495057; - margin: 0; - display: flex; - align-items: center; - gap: 8px; -} - -.m-panel-title i { - color: var(--cs-primary); - font-size: 16px; -} - -/* 垂直分隔线 */ -.m-divider-v { - width: 1px; - height: 100px; - background: #e9ecef; -} - -/* ========== 路径选择 - 大按钮设计 ========== */ -.m-path-box { - width: 100%; - padding: 12px 16px; - background: #f8f9fa; - border: 1px solid #dee2e6; - border-radius: 6px; - font-size: 13px; - font-weight: 600; - color: #495057; - font-family: monospace; -} - -.m-path-btn { - width: 100%; - height: 44px; - background: #fff; - border: 1px solid #ced4da; - border-radius: 6px; - font-size: 13px; - font-weight: 600; - color: #495057; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - gap: 6px; - transition: all 0.2s ease; -} - -.m-path-btn:hover { - border-color: var(--cs-primary); - color: var(--cs-primary); -} - -.m-path-btn i { - color: var(--cs-primary); -} - -/* ========== 单选按钮 - 大触摸区域 ========== */ -.m-radio-group { - display: flex; - flex-direction: column; - gap: 10px; - width: 100%; -} - -.m-radio-item { - display: flex; - align-items: center; - gap: 10px; - padding: 12px 16px; - background: #fff; - border: 1px solid #dee2e6; - border-radius: 6px; - cursor: pointer; - font-size: 14px; - font-weight: 600; - color: #495057; - transition: all 0.2s ease; -} - -.m-radio-item input { - width: 18px; - height: 18px; - margin: 0; - cursor: pointer; - accent-color: var(--cs-primary); -} - -.m-radio-item:hover { - border-color: var(--cs-primary); -} - -.m-radio-item:has(input:checked) { - border-color: var(--cs-primary); - background: rgba(0, 128, 0, 0.05); -} diff --git a/app/src/renderer/src/styles/pages/page2.scss b/app/src/renderer/src/styles/pages/page2.scss deleted file mode 100644 index 760ade6..0000000 --- a/app/src/renderer/src/styles/pages/page2.scss +++ /dev/null @@ -1,360 +0,0 @@ -/* - Page 8 - 循环任务执行中样式 - 左右分布布局:左 = 状态+工作流,右 = 大圆环 - Index 首页也复用此样式 -*/ - -/* ========== Index 首页仪表板样式 ========== */ -.l-dashboard { - display: flex; - align-items: center; - justify-content: center; - gap: 60px; - padding: 20px 80px; - height: 100%; - flex: 1; -} - -/* 区域标题 */ -.m-section-title { - font-size: 11px; - font-weight: 700; - color: #adb5bd; - margin-bottom: 12px; - text-transform: uppercase; - letter-spacing: 1px; - padding-left: 4px; -} - -/* ========== 工具区域(左) ========== */ -.m-tool-section { - width: 180px; - flex-shrink: 0; -} - -.m-tool-grid { - display: flex; - flex-direction: column; - gap: 8px; -} - -.m-tool-btn { - width: 100%; - height: 48px; - background: #fff; - border: 1px solid #dee2e6; - border-radius: 6px; - display: flex; - align-items: center; - justify-content: flex-start; - padding: 0 16px; - gap: 10px; - font-size: 13px; - font-weight: 600; - color: #495057; - cursor: pointer; - transition: all 0.2s ease; -} - -.m-tool-btn i { - font-size: 16px; - color: #6c757d; - width: 20px; - text-align: center; - transition: color 0.2s ease; -} - -.m-tool-btn:hover { - border-color: var(--cs-primary); - box-shadow: 0 4px 12px rgba(0, 128, 0, 0.1); -} - -.m-tool-btn:hover i { - color: var(--cs-primary); -} - -/* ========== 垂直分隔线 ========== */ -.m-divider { - width: 1px; - height: 140px; - background: linear-gradient(to bottom, transparent, #dee2e6, transparent); -} - -/* ========== 任务区域(右) ========== */ -.m-task-section { - flex: 1; - max-width: 400px; -} - -.m-task-grid { - display: flex; - gap: 12px; -} - -.m-task-card { - flex: 1; - min-height: 100px; - background: #fff; - border: 1px solid #e9ecef; - border-radius: 8px; - padding: 20px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 10px; - cursor: pointer; - transition: all 0.25s ease; -} - -.m-task-icon { - width: 42px; - height: 42px; - border-radius: 8px; - background: #f8f9fa; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.25s ease; -} - -.m-task-icon i { - font-size: 18px; - color: #6c757d; - transition: color 0.25s ease; -} - -.m-task-info { - text-align: center; -} - -.m-task-info h4 { - font-size: 14px; - font-weight: 800; - color: #495057; - margin: 0 0 4px 0; - transition: color 0.25s ease; -} - -.m-task-info p { - font-size: 11px; - color: #adb5bd; - margin: 0; - font-weight: 500; -} - -/* 悬停效果 - 绿色主题 */ -.m-task-card:hover { - border-color: var(--cs-primary); - box-shadow: 0 6px 16px rgba(0, 128, 0, 0.12); - transform: translateY(-2px); -} - -.m-task-card:hover .m-task-icon { - background: var(--cs-primary); -} - -.m-task-card:hover .m-task-icon i { - color: #fff; -} - -.m-task-card:hover h4 { - color: var(--cs-primary); -} - -/* 停止按钮样式 - 醒目红色 */ -.c-nav-btn--stop { - background: linear-gradient(135deg, #dc3545 0%, #c82333 100%) !important; - box-shadow: 0 3px 10px rgba(220, 53, 69, 0.35) !important; - width: 48px !important; - height: 48px !important; -} - -.c-nav-btn--stop i { - color: #fff !important; - font-size: 18px !important; -} - -.c-nav-btn--stop span { - color: #fff !important; - font-weight: 700 !important; -} - -.c-nav-btn--stop:hover { - background: linear-gradient(135deg, #c82333 0%, #a71d2a 100%) !important; - box-shadow: 0 4px 14px rgba(220, 53, 69, 0.45) !important; -} - -/* ========== 核心布局:左右分布 ========== */ -.l-hero-container { - display: flex !important; - flex-direction: row !important; - align-items: center !important; - justify-content: center !important; - gap: 80px !important; - padding: 0 120px !important; -} - -/* 左侧面板:状态 + 工作流 */ -.m-left-panel { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 30px; - flex: 1; - max-width: 380px; -} - -/* 右侧面板:圆环进度 */ -.m-right-panel { - flex: 0 0 auto; - display: flex; - align-items: center; - justify-content: center; -} - -/* ========== 状态消息 - 左对齐 ========== */ -.c-status-panel { - text-align: left !important; - width: 100% !important; -} - -.c-status-title.is-looping { - color: var(--cs-primary); - font-size: 24px; - font-weight: 800; - display: flex; - align-items: center; - gap: 12px; - margin-bottom: 6px; - justify-content: flex-start; -} - -.c-status-title.is-looping::before { - content: ''; - width: 12px; - height: 12px; - background: var(--cs-primary); - border-radius: 50%; - animation: blink 1.5s infinite; -} - -@keyframes blink { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.3; } -} - -.c-status-sub { - text-align: left !important; - font-size: 13px !important; -} - -/* 统计计数文字 */ -.c-status-counter { - font-size: 12px; - color: #6c757d; - font-weight: 600; - margin: 8px 0 0 0; -} - -.c-status-counter .ok { - color: var(--cs-primary); - font-weight: 800; -} - -.c-status-counter .err { - color: #dc3545; - font-weight: 800; -} - -/* ========== 4步工作流 - 直接渲染 ========== */ -.m-steps-flow { - display: flex; - align-items: center; - justify-content: flex-start; - gap: 0; - width: 100%; - padding-top: 10px; -} - -.m-steps-flow .step-item { - display: flex; - flex-direction: column; - align-items: center; - gap: 6px; - min-width: 70px; -} - -.m-steps-flow .step-dot { - width: 14px; - height: 14px; - border-radius: 50%; - background: #dee2e6; -} - -.m-steps-flow .step-item.is-active .step-dot { - background: var(--cs-primary); - box-shadow: 0 0 0 4px rgba(0, 128, 0, 0.15); -} - -.m-steps-flow .step-label { - font-size: 11px; - font-weight: 600; - color: #adb5bd; - white-space: nowrap; -} - -.m-steps-flow .step-item.is-active .step-label { - color: var(--cs-primary); - font-weight: 700; -} - -.m-steps-flow .step-line { - width: 50px; - height: 3px; - background: #dee2e6; - margin-bottom: 18px; -} - -.m-steps-flow .step-line.is-active { - background: var(--cs-primary); -} - -/* ========== 圆形进度条 ========== */ -.m-progress-circle { - position: relative; - width: 160px; - height: 160px; -} - -.m-progress-circle svg { - transform: rotate(-90deg); - width: 100%; - height: 100%; -} - -.m-progress-circle circle { - fill: none; - stroke-width: 10; - stroke-linecap: round; -} - -.m-progress-circle .bg { - stroke: #ecf0f1; -} - -.m-progress-circle .fill { - stroke: var(--cs-primary); - stroke-dasharray: 283; - transition: stroke-dashoffset 0.5s ease; -} - -.m-progress-value { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 34px; - font-weight: 900; - color: var(--cs-primary); -} diff --git a/app/src/renderer/src/styles/pages/page3.scss b/app/src/renderer/src/styles/pages/page3.scss deleted file mode 100644 index 7ccb91a..0000000 --- a/app/src/renderer/src/styles/pages/page3.scss +++ /dev/null @@ -1,172 +0,0 @@ -/* - Page 3 - 任务失败界面 - 风格与 page8 统一:左右分布,红色错误主题 -*/ - -/* ========== 核心布局:左右分布 ========== */ -.l-hero-container { - display: flex !important; - flex-direction: row !important; - align-items: center !important; - justify-content: center !important; - gap: 80px !important; - padding: 0 120px !important; -} - -/* 左侧面板:状态 + 工作流 */ -.m-left-panel { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 30px; - flex: 1; - max-width: 380px; -} - -/* 右侧面板:错误图标 */ -.m-right-panel { - flex: 0 0 auto; - display: flex; - align-items: center; - justify-content: center; -} - -/* ========== 状态消息 - 红色错误主题 ========== */ -.c-status-panel { - text-align: left !important; - width: 100% !important; -} - -.c-status-title.is-error { - color: #dc3545; - font-size: 24px; - font-weight: 800; - display: flex; - align-items: center; - gap: 12px; - margin-bottom: 6px; - justify-content: flex-start; -} - -.c-status-title.is-error::before { - content: ''; - width: 12px; - height: 12px; - background: #dc3545; - border-radius: 50%; - animation: blink-red 1.5s infinite; -} - -@keyframes blink-red { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.3; } -} - -.c-status-sub { - text-align: left !important; - font-size: 13px !important; - color: #6c757d; -} - -/* 统计计数文字 */ -.c-status-counter { - font-size: 12px; - color: #6c757d; - font-weight: 600; - margin: 8px 0 0 0; -} - -.c-status-counter .ok { - color: #28a745; - font-weight: 800; -} - -.c-status-counter .err { - color: #dc3545; - font-weight: 800; -} - -/* ========== 4步工作流 - 红色错误主题 ========== */ -.m-steps-flow { - display: flex; - align-items: center; - justify-content: flex-start; - gap: 0; - width: 100%; - padding-top: 10px; -} - -.m-steps-flow .step-item { - display: flex; - flex-direction: column; - align-items: center; - gap: 6px; - min-width: 70px; -} - -.m-steps-flow .step-dot { - width: 14px; - height: 14px; - border-radius: 50%; - background: #dee2e6; -} - -/* 完成状态 - 绿色 */ -.m-steps-flow .step-item.is-completed .step-dot { - background: #28a745; -} - -.m-steps-flow .step-item.is-completed .step-label { - color: #28a745; - font-weight: 700; -} - -/* 错误状态 - 红色 */ -.m-steps-flow .step-item.is-error .step-dot { - background: #dc3545; - box-shadow: 0 0 0 4px rgba(220, 53, 69, 0.15); -} - -.m-steps-flow .step-item.is-error .step-label { - color: #dc3545; - font-weight: 700; -} - -.m-steps-flow .step-label { - font-size: 11px; - font-weight: 600; - color: #adb5bd; - white-space: nowrap; -} - -.m-steps-flow .step-line { - width: 50px; - height: 3px; - background: #dee2e6; - margin-bottom: 18px; -} - -.m-steps-flow .step-line.is-completed { - background: #28a745; -} - -.m-steps-flow .step-line.is-error { - background: linear-gradient(to right, #28a745 50%, #dc3545 50%); -} - -/* ========== 错误图标 - 红色大三角 ========== */ -.m-error-icon { - width: 160px; - height: 160px; - border-radius: 50%; - background: linear-gradient(135deg, #dc3545 0%, #c82333 100%); - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 8px 24px rgba(220, 53, 69, 0.3); -} - -.m-error-icon i { - font-size: 70px; - color: #fff; -} diff --git a/app/src/renderer/src/styles/pages/page4.css b/app/src/renderer/src/styles/pages/page4.css index 794ed4b..4759813 100644 --- a/app/src/renderer/src/styles/pages/page4.css +++ b/app/src/renderer/src/styles/pages/page4.css @@ -1,8 +1,3 @@ -/* - Page 7 业务样式 - 打印系统核心界面 - 基于 base.css 构建 -*/ - /* 左右栏固定 1:1,内容变化不挤占宽度 */ .app-shell__main.l-main-flex { display: grid; @@ -410,214 +405,6 @@ border-top: 1px solid #f0f0f0; } -/* 10. 设置弹窗 (Page 8) */ -.m-settings-modal { - position: absolute; - inset: 0; - display: none; - align-items: center; - justify-content: center; - z-index: 50; -} - -.m-settings-modal.is-open { - display: flex; -} - -.m-settings-modal__backdrop { - position: absolute; - inset: 0; - background: rgba(0, 0, 0, 0.24); -} - -.m-settings-modal__dialog { - position: relative; - width: min(540px, calc(100% - 20px)); - max-height: calc(100% - 12px); - min-height: 0; - background: #f3f3f3; - border: 1px solid #cfcfcf; - border-radius: 6px; - box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28); - display: flex; - flex-direction: column; - overflow: hidden; -} - -.m-settings-modal__header { - flex-shrink: 0; - height: 28px; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 8px 0 12px; - border-bottom: 1px solid #dddddd; - background: linear-gradient(to bottom, #fbfbfb, #efefef); -} - -.m-settings-modal__header h2 { - font-size: 11px; - color: #5a5a5a; - font-weight: 700; -} - -.m-settings-modal__close { - display: inline-flex; - align-items: center; - justify-content: center; - width: 22px; - height: 22px; - padding: 0; - border: none; - border-radius: 3px; - background: transparent; - color: #666; - cursor: pointer; -} - -.m-settings-modal__close:hover { - background: rgba(0, 0, 0, 0.06); - color: #333; -} - -.m-settings-modal__body { - flex: 1; - min-height: 0; - padding: 6px 10px 4px; - display: flex; - flex-direction: column; - gap: 6px; - overflow-y: auto; - overflow-x: hidden; - scrollbar-width: thin; - scrollbar-color: #bbb transparent; -} - -.m-settings-modal__body::-webkit-scrollbar { - width: 5px; -} - -.m-settings-modal__body::-webkit-scrollbar-thumb { - background: #bbb; - border-radius: 3px; -} - -.m-settings-group { - flex-shrink: 0; - border: 1px solid #d8d8d8; - background: #f5f5f5; - padding: 6px; -} - -.m-settings-group--advanced { - min-height: 0; -} - -.m-settings-group__title { - font-size: 11px; - color: #444; - margin-bottom: 4px; - font-weight: 700; -} - -.m-settings-group__panel { - background: #efefef; - border: 1px solid #d9d9d9; - padding: 6px; - overflow: visible; -} - -.m-settings-row { - display: grid; - grid-template-columns: 58px 155px 58px 1fr; - align-items: center; - column-gap: 8px; - margin-bottom: 6px; -} - -.m-settings-row:last-child { - margin-bottom: 0; - grid-template-columns: 86px 155px 1fr; -} - -.m-settings-row label { - font-size: 10px; - color: #333; - white-space: nowrap; -} - -.m-settings-row .c-app-select { - min-width: 0; -} - -.m-settings-options { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 6px; - column-gap: 14px; - align-content: start; - min-height: 0; -} - -.m-settings-check { - display: flex; - align-items: center; - gap: 6px; - font-size: 10px; - color: #333; - white-space: nowrap; -} - -.m-settings-check input[type='checkbox'] { - width: 12px; - height: 12px; - margin: 0; -} - -.m-settings-modal__footer { - flex-shrink: 0; - display: flex; - justify-content: flex-end; - align-items: center; - gap: 8px; - padding: 4px 12px 8px; - border-top: 1px solid #ddd; - background: #f3f3f3; -} - -.m-settings-modal__cancel { - display: inline-flex; - align-items: center; - gap: 4px; - min-width: 68px; - height: 24px; - padding: 0 10px; - border: 1px solid #ced4da; - border-radius: 3px; - background: #fff; - font-size: 12px; - color: #495057; - cursor: pointer; -} - -.m-settings-modal__cancel:hover { - border-color: #adb5bd; - background: #f8f9fa; -} - -.m-settings-modal__cancel .fas { - font-size: 11px; - color: #6c757d; -} - -.m-settings-modal__confirm { - min-width: 68px; - height: 24px; - font-size: 12px; - border-radius: 3px; - padding: 0 12px; -} - /* 路径提示 */ .m-path-hint { display: flex; diff --git a/app/src/renderer/src/styles/pages/page4.scss b/app/src/renderer/src/styles/pages/page4.scss deleted file mode 100644 index 6995b31..0000000 --- a/app/src/renderer/src/styles/pages/page4.scss +++ /dev/null @@ -1,660 +0,0 @@ -/* - Page 7 业务样式 - 打印系统核心界面 - 基于 base.css 构建 -*/ - -/* 布局微调:增加左侧面板宽度给新控件 */ -.m-panel--left { - flex: 5; -} -.m-panel--right { - flex: 5; -} - -/* ========== 工具栏 - 紧凑两行布局 ========== */ -.m-panel-toolbar { - padding: 10px 14px; - background: #f8f9fa; - border-bottom: 1px solid #e9ecef; - display: flex; - flex-direction: column; - gap: 8px; -} - -.toolbar-row { - display: flex; - align-items: center; - gap: 16px; -} - -.toolbar-item { - display: flex; - align-items: center; - gap: 6px; - font-size: 10px; - font-weight: 600; - color: #6c757d; - white-space: nowrap; -} - -.toolbar-item .c-input { - width: 90px; - height: 24px; - padding: 0 6px; - font-size: 9px; - border-radius: 3px; - border: 1px solid #ced4da; -} - -.toolbar-item .c-select { - width: 90px; - height: 24px; - padding: 0 6px; - font-size: 9px; - border-radius: 3px; - border: 1px solid #ced4da; -} - -/* 复选框样式 */ -.m-panel-toolbar .c-checkbox-item { - display: flex; - align-items: center; - gap: 5px; - font-size: 10px; - font-weight: 600; - color: #6c757d; - white-space: nowrap; - cursor: pointer; - padding: 2px 0; -} - -.m-panel-toolbar .c-checkbox-item input[type="checkbox"] { - width: 14px; - height: 14px; - margin: 0; - cursor: pointer; -} - -/* 加密狗数量输入框 */ -.m-panel-toolbar .c-checkbox-item .c-input.dog-count { - width: 40px; - height: 20px; - padding: 0 4px; - font-size: 9px; - text-align: center; - border-radius: 3px; - border: 1px solid #ced4da; - margin-left: 3px; -} - -/* 提示文字 */ -.m-panel-toolbar .c-checkbox-item .dog-hint { - font-size: 8px; - color: #adb5bd; - font-weight: 500; - margin-left: 2px; -} - -/* 列表业务项 (File Items) */ -.m-file-item { - display: flex; - align-items: center; - padding: 6px 10px; - border-bottom: 1px solid #f8f8f8; -} - -.m-file-item__icon { - width: 32px; - font-size: 22px; /* 图标大幅放大,对齐 case.png */ - color: var(--cs-dark-blue); - margin-right: 12px; - text-align: center; -} -.m-file-item__info { - flex: 1; -} -.m-file-item__name { - font-size: 11px; - font-weight: 600; -} -.m-file-item__meta { - font-size: 9px; - color: #999; -} -.m-file-item__delete { - border: none; - background: none; - color: var(--cs-primary); - font-size: 14px; - cursor: pointer; -} - -/* 卡片预览区 (Preview Area) */ -.m-preview-area { - background: #333; - margin: 8px; - height: 100px; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - gap: 10px; -} -.m-card-small { - width: 130px; - height: 84px; - background: white; - border-radius: 3px; - padding: 5px; - font-size: 7px; -} -.m-card-small__row { - margin-bottom: 2px; -} -/* 面板头部专用布局 */ -.c-panel__header .c-nav-group { - gap: 4px; - align-items: center; -} - -/* 优化按钮文字展示,确保不换行 */ -.c-button--mini, -.c-button--primary { - background: var(--cs-primary) !important; - color: #fff !important; - border: none !important; - border-radius: 4px; - padding: 1px 8px; /* 进一步收紧边距 */ - font-weight: 800; - font-size: 10px; - white-space: nowrap; - letter-spacing: -0.2px; /* 微调字间距 */ -} -.c-button--mini:hover { - background: var(--cs-primary-hover) !important; -} - -/* 数据详情表格 (Data Table) */ -.m-data-section { - flex: 1; - padding: 0 10px; - overflow-y: auto; -} -.m-data-table { - width: 100%; - border-collapse: collapse; - font-size: 10px; -} -.m-data-table td { - padding: 3px 0; - border-bottom: 1px solid #f5f5f5; -} -.m-data-table td:first-child { - color: #888; - width: 40%; -} - -/* 动态表单字段 (Dynamic Fields) */ -.m-dynamic-fields { - padding: 0 10px 8px; - display: flex; - flex-direction: column; - gap: 6px; -} - -.m-dynamic-row { - display: flex; - align-items: center; /* 垂直居中 */ - gap: 8px; - min-height: 24px; /* 增加最小高度确保对齐空间 */ -} - -.m-dynamic-row select, -.m-dynamic-row input[type='text'] { - border: 1px solid var(--cs-border); - border-radius: 3px; - font-size: 10px; -} - -.m-dynamic-row select { - flex: 1.2; - background: #f9f9f9; -} -.m-dynamic-row input[type='text'] { - flex: 1.8; -} - -/* 单选框组对齐优化 */ -.m-dynamic-row .radio-group { - display: flex; - align-items: center; - gap: 10px; - flex: 1.8; /* 与输入框占据同样的宽度比例,保持视觉对称 */ -} - -.m-dynamic-row label { - display: flex; - align-items: center; /* 关键:Label 内部 Flex 居中 */ - gap: 4px; - font-size: 10px; - color: #444; - cursor: pointer; - line-height: 1; /* 防止行高干扰 */ -} - -.m-dynamic-row input[type='radio'] { - margin: 0; - cursor: pointer; - width: 12px; - height: 12px; - position: relative; - top: 1px; /* 视觉补偿:单选框通常在浏览器中偏上 1px */ -} -.c-list-item { - padding: 6px 12px; - border-bottom: 1px solid #f5f6f7; -} -.c-list-item__icon { - color: #3498db; - font-size: 14px; - width: 20px; -} -.c-list-item__name { - font-size: 11px; - font-weight: 800; - color: #333; -} -.c-list-item__meta { - font-size: 9px; - color: #999; -} -.c-list-item__action { - color: #e74c3c; - font-size: 14px; -} - -/* 4. 预览区:高保真拟物化 */ -.m-preview-area { - background: #2d3436; - margin: 8px; - height: 105px; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - gap: 15px; - box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.5); -} -.m-card-small { - width: 135px; - height: 88px; - background: #fff; - border-radius: 4px; - padding: 6px; - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.6); - display: flex; - flex-direction: column; -} -.m-card-small__row { - font-size: 8px; - color: #333; - margin-bottom: 2px; - line-height: 1.2; -} -.m-card-small__label { - font-weight: 800; -} -/* 5. 业务数据表格:极致紧凑化 (2px 间距) */ -.m-data-section { padding: 2px 10px; } -.m-data-table { width: 100%; border-collapse: separate; border-spacing: 0 2px; font-size: 10px !important; } -.m-data-table td { padding: 0; border: none; vertical-align: middle; } -.m-data-table td:first-child { - color: #666; width: 35%; font-weight: 700; padding-right: 8px; -} -.m-data-table td:last-child { - color: #333; font-weight: 800; text-align: left; - background: #f9fafb; border: 1px solid #dcdfe6; border-radius: 3px; - padding: 1px 8px; height: 20px; /* 进一步压低高度 */ -} - -/* 6. 动态表单项:极致压缩 (解决挤压问题) */ -.m-dynamic-fields { padding: 0 10px 6px; display: flex; flex-direction: column; gap: 2px; } -.m-dynamic-row { display: flex; align-items: center; gap: 6px; min-height: 20px; } -.m-dynamic-row .c-select { - width: 35%; /* 强制与上方 Label 宽度一致,实现对齐 */ - height: 20px; font-size: 10px; border: 1px solid #dcdfe6; border-radius: 3px; -} -.m-dynamic-row .c-input { - flex: 1; height: 20px; font-size: 10px; border: 1px solid #dcdfe6; border-radius: 3px; padding: 0 8px; -} -.m-dynamic-row .m-file-item__delete { - font-size: 12px; color: #999; padding: 0 4px; -} -.m-dynamic-row label { display: flex; align-items: center; gap: 4px; cursor: pointer; color: #444; font-size: 10px; } - -/* 7. 主色调回归:Page 3 式工业绿 */ -.c-button--primary { - background: var(--cs-primary) !important; - border-color: #3b633a !important; -} - -/* 8. 进度条深度美化 (极致窄版 - 12px 极简设计) */ -.c-progress { - height: 12px; /* 极致窄版,节省空间 */ - background: #dee2e6; - border-radius: 6px; - position: relative; - overflow: hidden; - margin: 2px 10px; /* 减小外边距 */ - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15); - border: 1px solid #adb5bd; -} -.c-progress-fill { - height: 100%; - background: linear-gradient(to bottom, #40c057, #2f9e44); - border-radius: 5px; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3); -} -.c-progress-text { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - font-size: 8.5px; /* 极致字号 */ - font-weight: 800; - color: #fff; - text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4); - z-index: 2; - line-height: 12px; -} - -/* 9. Footer 区域收缩 */ -.c-panel__footer { - padding: 4px 0 !important; /* 彻底压缩 Footer 高度 */ - min-height: auto !important; - border-top: 1px solid #f0f0f0; -} - -/* 10. 设置弹窗 (Page 8) */ -.m-settings-modal { - position: absolute; - inset: 0; - display: none; - align-items: center; - justify-content: center; - z-index: 50; -} - -.m-settings-modal.is-open { - display: flex; -} - -.m-settings-modal__backdrop { - position: absolute; - inset: 0; - background: rgba(0, 0, 0, 0.24); -} - -.m-settings-modal__dialog { - position: relative; - width: 560px; - min-height: 265px; - background: #f3f3f3; - border: 1px solid #cfcfcf; - border-radius: 6px; - box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28); - display: flex; - flex-direction: column; -} - -.m-settings-modal__header { - height: 28px; - display: flex; - align-items: center; - padding: 0 12px; - border-bottom: 1px solid #dddddd; - background: linear-gradient(to bottom, #fbfbfb, #efefef); -} - -.m-settings-modal__header h2 { - font-size: 11px; - color: #5a5a5a; - font-weight: 700; -} - -.m-settings-modal__body { - flex: 1; - padding: 8px 12px 6px; - display: flex; - flex-direction: column; - gap: 8px; -} - -.m-settings-group { - border: 1px solid #d8d8d8; - background: #f5f5f5; - padding: 8px; -} - -.m-settings-group--advanced { - min-height: 132px; -} - -.m-settings-group__title { - font-size: 11px; - color: #444; - margin-bottom: 7px; - font-weight: 700; -} - -.m-settings-group__panel { - background: #efefef; - border: 1px solid #d9d9d9; - padding: 8px; -} - -.m-settings-row { - display: grid; - grid-template-columns: 58px 155px 58px 1fr; - align-items: center; - column-gap: 8px; - margin-bottom: 6px; -} - -.m-settings-row:last-child { - margin-bottom: 0; - grid-template-columns: 86px 155px 1fr; -} - -.m-settings-row label { - font-size: 10px; - color: #333; - white-space: nowrap; -} - -.m-settings-row .c-select { - height: 20px; - font-size: 10px; - border-radius: 2px; - border-color: #c9c9c9; - background: #fff; -} - -.m-settings-options { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 12px; - column-gap: 22px; - align-content: start; - min-height: 92px; -} - -.m-settings-check { - display: flex; - align-items: center; - gap: 6px; - font-size: 10px; - color: #333; - white-space: nowrap; -} - -.m-settings-check input[type='checkbox'] { - width: 12px; - height: 12px; - margin: 0; -} - -.m-settings-modal__footer { - display: flex; - justify-content: flex-end; - padding: 0 12px 10px; -} - -.m-settings-modal__confirm { - min-width: 68px; - height: 22px; - font-size: 10px; - border-radius: 3px; - padding: 0 12px; -} - -/* 路径提示 */ -.m-path-hint { - display: flex; - align-items: center; - gap: 6px; - padding: 8px 12px; - background: #f8f9fa; - border-bottom: 1px solid #e9ecef; - font-size: 10px; - color: #6c757d; -} - -.m-path-hint i { - color: var(--cs-dark-grey); - font-size: 12px; -} - -/* 路径列表项 */ -.c-path-item { - display: flex; - align-items: center; - padding: 6px 12px; - border-bottom: 1px solid #f5f6f7; -} - -.c-path-item__info { - flex: 1; -} - -.c-path-item__name { - font-size: 11px; - font-weight: 700; - color: #333; -} - -.c-path-item__meta { - font-size: 9px; - color: #999; - margin-top: 2px; -} - -.c-path-item__delete { - border: none; - background: none; - color: #e74c3c; - font-size: 16px; - cursor: pointer; - padding: 2px 6px; - font-weight: 800; -} - -/* 标签预览区 */ -.c-preview-area { - background: #2d3436; - margin: 8px; - height: 105px; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - gap: 15px; - box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.5); -} - -.c-card-small { - width: 135px; - height: 88px; - background: #fff; - border-radius: 4px; - padding: 6px; - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.6); - display: flex; - flex-direction: column; -} - -.c-card-small__row { - font-size: 8px; - color: #333; - margin-bottom: 2px; - line-height: 1.2; -} - -.c-card-small__label { - font-weight: 800; -} - -/* 紧凑数据表格 */ -.c-data-table-mini { - width: 100%; - border-collapse: separate; - border-spacing: 0 2px; - font-size: 9px; -} - -.c-data-table-mini td { - padding: 0; - border: none; - vertical-align: middle; -} - -.c-data-table-mini td:first-child { - color: #666; - width: 35%; - font-weight: 700; - padding-right: 8px; - font-size: 8px; -} - -.c-data-table-mini td:last-child { - color: #333; - font-weight: 800; - text-align: left; - background: #f9fafb; - border: 1px solid #dcdfe6; - border-radius: 3px; - padding: 1px 6px; - height: 18px; - font-size: 8px; -} - -.c-data-table-mini td:last-child.c-path-cell { - background: transparent; - border: none; - padding: 0; - display: flex; - align-items: center; - justify-content: space-between; -} - -.c-path-update { - color: var(--cs-primary); - font-weight: 800; - cursor: pointer; - padding: 0 4px; - font-size: 10px; -} diff --git a/app/src/renderer/src/styles/shell.css b/app/src/renderer/src/styles/shell.css index 555bd85..6027b6d 100644 --- a/app/src/renderer/src/styles/shell.css +++ b/app/src/renderer/src/styles/shell.css @@ -1,4 +1,3 @@ -/* Electron 壳层:覆盖 design 原型用的深色信箱背景 */ html, body, #app { @@ -13,7 +12,6 @@ body, position: relative; } -/* 720×360 逻辑画布;内容区同比例;useScale 按 innerWidth/720 顶对齐 */ .app-shell { position: absolute; left: 0; @@ -25,11 +23,6 @@ body, overflow: hidden; } -/* - * 首页两侧「空白」主要来自 page2.css 的 .l-dashboard: - * padding 左右 + justify-content:center + 左栏固定 180px / 右栏 max-width:400px - * 在 DevTools 里选中 main.app-shell__main.l-dashboard 可看到盒模型 - */ .app-shell__main.l-dashboard { padding: 20px 40px; gap: 48px; @@ -75,7 +68,6 @@ body, margin-bottom: 2px; } -/* 与 page2.css 中 .m-tool-btn i / .m-task-icon i 对齐 */ .m-tool-btn .fas { font-size: 16px; color: #6c757d; diff --git a/app/src/renderer/src/types/ipc.ts b/app/src/renderer/src/types/ipc.ts index 672ba87..9b931ff 100644 --- a/app/src/renderer/src/types/ipc.ts +++ b/app/src/renderer/src/types/ipc.ts @@ -28,9 +28,19 @@ export interface JobPollPayload { } export interface UsbPollPayload { + /** SAPI_GetUsbCopyState 返回值,0 表示成功 */ + queryCode: number + /** task_status: 0 preparing, 1 copying, 2 completed, 3 failed */ taskStatus: number + /** copy_progress 0-100 */ progress: number terminal: boolean failed: boolean success: boolean + errorMessage?: string +} + +export interface CardPositionPollPayload { + queryCode: number + position: number } diff --git a/app/src/renderer/src/types/printer.ts b/app/src/renderer/src/types/printer.ts index 6e7fe0d..9a3ce19 100644 --- a/app/src/renderer/src/types/printer.ts +++ b/app/src/renderer/src/types/printer.ts @@ -5,7 +5,6 @@ export interface PrinterStatusDisplay { printedCount: number } -/** Init 前 Header 占位;阶段二由 GetPrinterInfo 覆盖 */ export const defaultPrinterStatus: PrinterStatusDisplay = { ribbonType: '—', statusText: '—', diff --git a/app/src/renderer/src/utils/buildJobConfig.ts b/app/src/renderer/src/utils/buildJobConfig.ts index 415cbce..04df431 100644 --- a/app/src/renderer/src/utils/buildJobConfig.ts +++ b/app/src/renderer/src/utils/buildJobConfig.ts @@ -1,32 +1,47 @@ import type { DistributeFormState } from '@/stores/distributeForm' import { cleanPathPattern } from '@shared/path-pattern' +import { resolveJobTasks } from '@/utils/validateJobConfig' + +export interface BuildJobOptions { + taskId: string + udfFile?: string +} + +export function buildJobConfig( + form: DistributeFormState, + opts: BuildJobOptions +): Record { + const { hasCopy, hasPrint } = resolveJobTasks(form) + const needFormat = form.formatType !== 'none' -export function buildJobConfig(form: DistributeFormState): Record { - const taskId = `T${Date.now()}` - const hasCopy = form.pathList.length > 0 - const hasPrint = !!form.templateFile.trim() const body: Record = { - task_id: taskId, + task_id: opts.taskId, print_copys: 1, has_print_task: hasPrint, has_copy_task: hasCopy, label: form.volumeLabel || 'DATA_CARD', file_type: String(form.copyType), zone_type: form.copyType === 1 ? '1' : '0', - need_format: form.formatType !== 'none', + need_format: needFormat, format_file: form.formatType === 'ntfs' ? 'NTFS' : 'FAT', disk_size: '16GB', dongle_install_count: form.dongleEnabled ? form.dongleMode : -1 } + if (hasCopy) { body.path_file = form.pathList.map((x) => cleanPathPattern(x.path)) } + if (hasPrint) { body.json_file = form.templateFile.trim() body.print_flag = 1 + const udf = opts.udfFile?.trim() + if (udf) body.udf_file = udf } + if (form.generateIso) body.is_generate_iso = true if (form.generateZip) body.is_generate_zip = true if (form.failPrintLabel) body.is_printer_record_logo = true + return body } diff --git a/app/src/renderer/src/utils/createDistributeJob.ts b/app/src/renderer/src/utils/createDistributeJob.ts new file mode 100644 index 0000000..8dd3ebb --- /dev/null +++ b/app/src/renderer/src/utils/createDistributeJob.ts @@ -0,0 +1,42 @@ +import { genTaskId } from '@shared/gen-task-id' +import { buildJobConfig } from '@/utils/buildJobConfig' +import { resolveJobTasks } from '@/utils/validateJobConfig' +import { dllJobCreate, fsWriteJobCsv } from '@/api/cardsoon' +import type { DistributeFormState } from '@/stores/distributeForm' + +function printFieldRows(form: DistributeFormState) { + return (form.templatePreview?.fields ?? []).map((f) => ({ + originName: f.originName || f.label.replace(/\[.*\]$/, ''), + value: f.value ?? '' + })) +} + +export async function createDistributeJob( + form: DistributeFormState, + opts?: { resubmit?: boolean } +): Promise<{ ok: true; jobId: string } | { ok: false; message: string }> { + const { hasCopy, hasPrint } = resolveJobTasks(form) + if (!hasCopy && !hasPrint) { + return { ok: false, message: '请配置拷贝路径或打印模板' } + } + + const taskId = genTaskId() + let udfFile = '' + if (hasPrint) { + const rows = printFieldRows(form) + if (rows.length > 0) { + const csv = await fsWriteJobCsv({ taskId, rows }) + if (!csv.ok || !csv.data?.path) { + return { ok: false, message: csv.message || '生成打印变量 CSV 失败' } + } + udfFile = csv.data.path + } + } + + const json = JSON.stringify(buildJobConfig(form, { taskId, udfFile })) + const created = await dllJobCreate(json, opts) + if (!created.ok || !created.data?.jobId) { + return { ok: false, message: created.message || '创建任务失败' } + } + return { ok: true, jobId: created.data.jobId } +} diff --git a/app/src/renderer/src/utils/job-state.ts b/app/src/renderer/src/utils/job-state.ts index 7831972..a7961cb 100644 --- a/app/src/renderer/src/utils/job-state.ts +++ b/app/src/renderer/src/utils/job-state.ts @@ -58,7 +58,3 @@ export function mapJobStateToUi(jobState: number) { } } } - -export function shouldUseProgress(jobState: number): boolean { - return jobState === 2 || jobState === 3 -} diff --git a/app/src/renderer/src/utils/validateJobConfig.ts b/app/src/renderer/src/utils/validateJobConfig.ts index ff5a87f..3b7339e 100644 --- a/app/src/renderer/src/utils/validateJobConfig.ts +++ b/app/src/renderer/src/utils/validateJobConfig.ts @@ -1,8 +1,13 @@ import type { DistributeFormState } from '@/stores/distributeForm' -export function validateJobConfig(f: DistributeFormState): string | null { - const hasCopy = f.pathList.length > 0 +export function resolveJobTasks(f: DistributeFormState): { hasCopy: boolean; hasPrint: boolean } { + const hasCopy = f.pathList.some((p) => !!p.path.trim()) const hasPrint = !!f.templateFile.trim() + return { hasCopy, hasPrint } +} + +export function validateJobConfig(f: DistributeFormState): string | null { + const { hasCopy, hasPrint } = resolveJobTasks(f) if (!hasCopy && !hasPrint) return '请配置拷贝路径或打印模板' if (hasPrint && !/\.soon$/i.test(f.templateFile.trim())) return '请选择 .soon 模板' if (hasCopy && f.pathList.some((p) => !p.path.trim())) return '路径不能为空' diff --git a/app/src/renderer/src/utils/validateJobPreflight.ts b/app/src/renderer/src/utils/validateJobPreflight.ts new file mode 100644 index 0000000..6a9761d --- /dev/null +++ b/app/src/renderer/src/utils/validateJobPreflight.ts @@ -0,0 +1,33 @@ +import type { DistributeFormState } from '@/stores/distributeForm' +import { fsPathExists } from '@/api/cardsoon' +import { resolveJobTasks, validateJobConfig } from '@/utils/validateJobConfig' + +function totalCopyBytes(form: DistributeFormState): number { + return form.pathList.reduce((sum, item) => sum + (item.sizeBytes || 0), 0) +} + +/** 提交/续做前:配置 + 路径存在性 + 拷贝体积 */ +export async function validateJobPreflight(form: DistributeFormState): Promise { + const err = validateJobConfig(form) + if (err) return err + + const { hasCopy, hasPrint } = resolveJobTasks(form) + if (hasCopy) { + const paths = form.pathList.map((x) => x.path) + const ex = await fsPathExists(paths) + if (ex.ok && ex.data?.missing.length) { + return `路径不存在: ${ex.data.missing.join(', ')}` + } + if (totalCopyBytes(form) <= 0) { + return '拷贝路径下没有可拷贝的文件' + } + } + if (hasPrint) { + const soon = form.templateFile.trim() + const ex = await fsPathExists([soon]) + if (ex.ok && ex.data?.missing.length) { + return '模板文件不存在' + } + } + return null +} diff --git a/app/src/renderer/src/views/DataCollectView.vue b/app/src/renderer/src/views/DataCollectView.vue index 46deedf..196c6d5 100644 --- a/app/src/renderer/src/views/DataCollectView.vue +++ b/app/src/renderer/src/views/DataCollectView.vue @@ -21,7 +21,9 @@ 数据导入地址
- {{ collectStore.destPath || '未选择目录' }} + {{ + collectStore.destPath || '未选择目录' + }}
@@ -137,10 +137,16 @@ import { CARD_CAPACITY_BYTES, CARD_CAPACITY_GB } from '@/constants/cardCapacity' import { useDistributeFormStore } from '@/stores/distributeForm' import { useJobStore } from '@/stores/job' import { useAppStore } from '@/stores/app' -import { validateJobConfig } from '@/utils/validateJobConfig' -import { buildJobConfig } from '@/utils/buildJobConfig' +import { validateJobPreflight } from '@/utils/validateJobPreflight' +import { createDistributeJob } from '@/utils/createDistributeJob' import { formatBytesAsGb, formatBytesCompact } from '@/utils/formatBytes' -import { dialogOpenDirectory, dialogOpenSoon, dllJobCreate, fsDirSize, fsParseSoon, fsPathExists } from '@/api/cardsoon' +import { + dialogOpenDirectory, + dialogOpenSoon, + dllJobCancel, + fsDirSize, + fsParseSoon +} from '@/api/cardsoon' const router = useRouter() const formStore = useDistributeFormStore() @@ -158,7 +164,8 @@ const totalLoadedBytes = computed(() => const loadPercent = computed(() => { if (!formStore.pathList.length) return 0 - return Math.min(100, Math.round((totalLoadedBytes.value / CARD_CAPACITY_BYTES) * 100)) + const pct = Math.min(100, Math.round((totalLoadedBytes.value / CARD_CAPACITY_BYTES) * 100)) + return pct > 0 ? pct : 1 }) const hasTemplatePreview = computed( @@ -219,10 +226,6 @@ function removePath(idx: number): void { } async function pickTemplate(): Promise { - if (!canUse.value) { - notifyRequireInit('选择打印模板') - return - } const r = await dialogOpenSoon() if (!r.ok) { notify.error(r.message || '打开模板选择失败') @@ -255,37 +258,29 @@ async function onSubmit(): Promise { return } if (jobStore.submitting) return - const err = validateJobConfig(formStore) + const err = await validateJobPreflight(formStore) if (err) { notify.warning(err) return } - const paths = formStore.pathList.map((x) => x.path) - if (paths.length) { - const ex = await fsPathExists(paths) - if (ex.ok && ex.data?.missing.length) { - notify.error(`路径不存在: ${ex.data.missing.join(', ')}`) - return - } - } - if (formStore.templateFile.trim()) { - const ex = await fsPathExists([formStore.templateFile.trim()]) - if (ex.ok && ex.data?.missing.length) { - notify.error('模板文件不存在') - return - } - } jobStore.submitting = true try { - const json = JSON.stringify(buildJobConfig(formStore)) - const created = await dllJobCreate(json) - if (!created.ok || !created.data?.jobId) { - notify.error(created.message || '创建任务失败') + const created = await createDistributeJob(formStore) + if (!created.ok) { + notify.error(created.message) return } - jobStore.setActiveJob(created.data.jobId) + const newJobId = created.jobId + jobStore.setActiveJob(newJobId) appStore.setMode('distributing') - await router.push('/distribute/running') + try { + await router.push('/distribute/running') + } catch { + await dllJobCancel(newJobId) + jobStore.clearActiveJob() + appStore.setMode('ready') + notify.error('无法进入运行页,已取消任务') + } } finally { jobStore.submitting = false } diff --git a/app/src/renderer/src/views/DistributeFailedView.vue b/app/src/renderer/src/views/DistributeFailedView.vue index 0251c5a..d10d99f 100644 --- a/app/src/renderer/src/views/DistributeFailedView.vue +++ b/app/src/renderer/src/views/DistributeFailedView.vue @@ -54,8 +54,13 @@ const errorText = ref('') onMounted(async () => { appStore.setMode('ready') await pollJobStop() - const r = await dllPrinterErrorStr(-1) - errorText.value = r.ok && r.data?.text ? r.data.text : '' + jobStore.clearActiveJob() + try { + const r = await dllPrinterErrorStr(-1) + errorText.value = r.ok && r.data?.text ? r.data.text : '' + } catch { + errorText.value = '' + } }) function onBack(): void { diff --git a/app/src/renderer/src/views/DistributeRunningView.vue b/app/src/renderer/src/views/DistributeRunningView.vue index 321b884..9ac14a0 100644 --- a/app/src/renderer/src/views/DistributeRunningView.vue +++ b/app/src/renderer/src/views/DistributeRunningView.vue @@ -1,29 +1,64 @@ diff --git a/app/src/shared/card-position.ts b/app/src/shared/card-position.ts new file mode 100644 index 0000000..2ee50c2 --- /dev/null +++ b/app/src/shared/card-position.ts @@ -0,0 +1,2 @@ +/** workDll 卡位:备卡位,检测到后可自动重提任务 */ +export const POSITION_PREPARE = 13 diff --git a/app/src/shared/gen-task-id.ts b/app/src/shared/gen-task-id.ts new file mode 100644 index 0000000..13efc90 --- /dev/null +++ b/app/src/shared/gen-task-id.ts @@ -0,0 +1,4 @@ +/** RestJobEx JSON 根字段 task_id */ +export function genTaskId(): string { + return `T${Date.now()}` +} diff --git a/app/src/shared/printer-info.ts b/app/src/shared/printer-info.ts index e65dcf0..43fec5d 100644 --- a/app/src/shared/printer-info.ts +++ b/app/src/shared/printer-info.ts @@ -1,4 +1,3 @@ -/** DLL GetPrinterInfo JSON → Header 展示字段(与 mocks/printer 一致) */ export interface PrinterStatusSnapshot { ribbonType: string statusText: string @@ -6,28 +5,78 @@ export interface PrinterStatusSnapshot { printedCount: number } -export function parsePrinterInfoFromDll(json: Record): PrinterStatusSnapshot { - const list = (json.printerList as Record[]) || [] - const p = list[0] || {} - const serial = - p.szPrinterSerial ?? p.PrinterSerial ?? p.SerialNo ?? p.PrinterName ?? '—' +const PRINTER_STATUS_MAP: Record = { + I: '空闲', + B: '忙碌', + P: '正在打印' +} - let statusText = '—' - const direct = p.PrinterType ?? p.PrinterStatus ?? p.Status - if (direct != null && String(direct).trim() !== '') { - statusText = String(direct) - } else { - const remain = p.RibbonRemain ?? p.RemainCount - const capacity = p.RibbonCapacity ?? p.Capacity ?? p.MaxCount +function pickFirst(obj: Record, keys: string[]): unknown { + for (const k of keys) { + const v = obj[k] + if (v != null && String(v).trim() !== '') return v + } + return undefined +} + +function normalizeStatus(raw: unknown): string { + if (raw == null) return '—' + if (typeof raw === 'number' && raw > 0 && raw < 128) { + const c = String.fromCharCode(raw) + return PRINTER_STATUS_MAP[c] ?? c + } + const s = String(raw).trim() + if (!s) return '—' + return PRINTER_STATUS_MAP[s] ?? s +} + +function snapshotFromRecord(row: Record): PrinterStatusSnapshot { + const serial = pickFirst(row, [ + 'serial_no', + 'SerialNo', + 'serialNo', + 'szPrinterSerial', + 'PrinterSerial', + 'PrinterName' + ]) + const statusRaw = pickFirst(row, [ + 'printer_status', + 'PrinterStatus', + 'PrinterType', + 'Status' + ]) + const ribbon = pickFirst(row, ['ribbon_type', 'RibbonType', 'RibbonAmount']) + const printed = pickFirst(row, ['printed_count', 'PrintedCount', 'PrintCount', 'printedCount']) + + let statusText = normalizeStatus(statusRaw) + if (statusText === '—') { + const remain = row.RibbonRemain ?? row.RemainCount + const capacity = row.RibbonCapacity ?? row.Capacity ?? row.MaxCount if (remain != null && capacity != null) { statusText = `${remain}/${capacity}` } } return { - ribbonType: String(p.RibbonType ?? '—'), + ribbonType: String(ribbon ?? '—'), statusText, - serialNo: String(serial), - printedCount: Number(p.PrintedCount ?? p.PrintCount ?? 0) + serialNo: String(serial ?? '—'), + printedCount: Number(printed ?? 0) } } + +/** SAPI_GetPrinterInfoEx(扁平 JSON)与 SAPI_GetPrinterInfo(printerList) */ +export function parsePrinterInfoFromDll(json: Record): PrinterStatusSnapshot { + const flatSerial = pickFirst(json, ['serial_no', 'SerialNo', 'serialNo', 'szPrinterSerial']) + const flatStatus = pickFirst(json, ['printer_status', 'PrinterStatus']) + if (flatSerial != null || flatStatus != null) { + return snapshotFromRecord(json) + } + + const list = (json.printerList as Record[]) || [] + if (list.length > 0) { + return snapshotFromRecord(list[0] as Record) + } + + return snapshotFromRecord(json) +} diff --git a/app/src/shared/usb-copy-state.ts b/app/src/shared/usb-copy-state.ts new file mode 100644 index 0000000..799097b --- /dev/null +++ b/app/src/shared/usb-copy-state.ts @@ -0,0 +1,33 @@ +/** SAPI_GetUsbCopyState: task_status(0=preparing, 1=copying, 2=completed, 3=failed) */ +export const USB_TASK_PREPARING = 0 +export const USB_TASK_COPYING = 1 +export const USB_TASK_COMPLETED = 2 +export const USB_TASK_FAILED = 3 + +/** @deprecated 使用 USB_TASK_PREPARING */ +export const USB_TASK_IDLE = USB_TASK_PREPARING +/** @deprecated 使用 USB_TASK_COMPLETED */ +export const USB_TASK_SUCCESS = USB_TASK_COMPLETED + +export function clampUsbCopyProgress(value: number): number { + return Math.min(100, Math.max(0, Math.round(value))) +} + +export function usbTaskStatusHint(status: number): string { + switch (status) { + case USB_TASK_PREPARING: + return '准备读取数据卡,请确认卡片已插入读卡位' + case USB_TASK_COPYING: + return '正在从卡片拷贝数据' + case USB_TASK_COMPLETED: + return '拷贝完成' + case USB_TASK_FAILED: + return 'USB 收集失败:未检测到卡片存储、读卡失败或无法移动到 USB 读卡位' + default: + return `USB 任务状态异常 (taskStatus=${status})` + } +} + +export function isUsbCopyTerminal(status: number): boolean { + return status === USB_TASK_COMPLETED || status === USB_TASK_FAILED +} diff --git a/app/tsconfig.web.tsbuildinfo b/app/tsconfig.web.tsbuildinfo index 4896c2b..27f692f 100644 --- a/app/tsconfig.web.tsbuildinfo +++ b/app/tsconfig.web.tsbuildinfo @@ -1 +1 @@ -{"program":{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/@vue/shared/dist/shared.d.ts","./node_modules/@babel/types/lib/index.d.ts","./node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/@vue/compiler-core/dist/compiler-core.d.ts","./node_modules/@vue/compiler-dom/dist/compiler-dom.d.ts","./node_modules/@vue/reactivity/dist/reactivity.d.ts","./node_modules/@vue/runtime-core/dist/runtime-core.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts","./node_modules/vue/dist/vue.d.mts","./node_modules/vue-demi/lib/index.d.ts","./node_modules/pinia/dist/pinia.d.ts","./src/renderer/src/stores/toast.ts","./src/renderer/src/composables/usenotify.ts","./src/shared/printer-info.ts","./src/renderer/src/types/ipc.ts","./src/renderer/src/types/printer.ts","./src/renderer/src/api/cardsoon.ts","./src/renderer/src/stores/app.ts","./src/renderer/src/stores/config.ts","./src/renderer/src/composables/useappbootstrap.ts","./src/renderer/src/app.vue.ts","./src/renderer/src/components/appfooter.vue.ts","./src/renderer/src/components/appheader.vue.ts","./src/renderer/src/assets/icons/index.ts","./src/renderer/src/components/appicon.vue.ts","./src/renderer/src/constants/selectoptions.ts","./src/renderer/src/components/appselect.vue.ts","./src/renderer/src/components/apptoasthost.vue.ts","./src/renderer/src/stores/distributeform.ts","./src/renderer/src/components/distributesettingsmodal.vue.ts","./src/renderer/src/components/navbutton.vue.ts","./src/renderer/src/components/workflowsteps.vue.ts","./src/shared/viewport.ts","./src/renderer/src/composables/usescale.ts","./src/renderer/src/layouts/appshell.vue.ts","./node_modules/vue-router/dist/router-cwonjprp.d.mts","./node_modules/vue-router/dist/vue-router.d.mts","./src/renderer/src/stores/collect.ts","./src/renderer/src/views/datacollectview.vue.ts","./src/renderer/src/constants/cardcapacity.ts","./src/renderer/src/stores/job.ts","./src/renderer/src/utils/validatejobconfig.ts","./src/shared/path-pattern.ts","./src/renderer/src/utils/buildjobconfig.ts","./src/renderer/src/utils/formatbytes.ts","./src/renderer/src/views/distributeconfigview.vue.ts","./src/renderer/src/views/distributefailedview.vue.ts","./src/renderer/src/utils/job-state.ts","./src/renderer/src/views/distributerunningview.vue.ts","./src/renderer/src/views/homeview.vue.ts","./node_modules/vue/jsx-runtime/index.d.ts","./__vls_types.d.ts","./node_modules/vite/types/hmrpayload.d.ts","./node_modules/vite/types/customevent.d.ts","./node_modules/vite/types/hot.d.ts","./node_modules/vite/types/importglob.d.ts","./node_modules/vite/types/importmeta.d.ts","./node_modules/vite/client.d.ts","./src/renderer/src/env.d.ts","./src/renderer/src/router/guards.ts","./src/renderer/src/router/index.ts","./src/renderer/src/main.ts","./src/renderer/src/mocks/job-poll.ts","./src/renderer/src/mocks/printer.ts","./node_modules/@types/ms/index.d.ts","./node_modules/@types/debug/index.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/ts5.6/globals.typedarray.d.ts","./node_modules/@types/node/ts5.6/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/dom-events.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/ts5.6/index.d.ts","./node_modules/@types/fs-extra/index.d.ts","./node_modules/@types/lodash/common/common.d.ts","./node_modules/@types/lodash/common/array.d.ts","./node_modules/@types/lodash/common/collection.d.ts","./node_modules/@types/lodash/common/date.d.ts","./node_modules/@types/lodash/common/function.d.ts","./node_modules/@types/lodash/common/lang.d.ts","./node_modules/@types/lodash/common/math.d.ts","./node_modules/@types/lodash/common/number.d.ts","./node_modules/@types/lodash/common/object.d.ts","./node_modules/@types/lodash/common/seq.d.ts","./node_modules/@types/lodash/common/string.d.ts","./node_modules/@types/lodash/common/util.d.ts","./node_modules/@types/lodash/index.d.ts","./node_modules/@types/lodash-es/add.d.ts","./node_modules/@types/lodash-es/after.d.ts","./node_modules/@types/lodash-es/ary.d.ts","./node_modules/@types/lodash-es/assign.d.ts","./node_modules/@types/lodash-es/assignin.d.ts","./node_modules/@types/lodash-es/assigninwith.d.ts","./node_modules/@types/lodash-es/assignwith.d.ts","./node_modules/@types/lodash-es/at.d.ts","./node_modules/@types/lodash-es/attempt.d.ts","./node_modules/@types/lodash-es/before.d.ts","./node_modules/@types/lodash-es/bind.d.ts","./node_modules/@types/lodash-es/bindall.d.ts","./node_modules/@types/lodash-es/bindkey.d.ts","./node_modules/@types/lodash-es/camelcase.d.ts","./node_modules/@types/lodash-es/capitalize.d.ts","./node_modules/@types/lodash-es/castarray.d.ts","./node_modules/@types/lodash-es/ceil.d.ts","./node_modules/@types/lodash-es/chain.d.ts","./node_modules/@types/lodash-es/chunk.d.ts","./node_modules/@types/lodash-es/clamp.d.ts","./node_modules/@types/lodash-es/clone.d.ts","./node_modules/@types/lodash-es/clonedeep.d.ts","./node_modules/@types/lodash-es/clonedeepwith.d.ts","./node_modules/@types/lodash-es/clonewith.d.ts","./node_modules/@types/lodash-es/compact.d.ts","./node_modules/@types/lodash-es/concat.d.ts","./node_modules/@types/lodash-es/cond.d.ts","./node_modules/@types/lodash-es/conforms.d.ts","./node_modules/@types/lodash-es/conformsto.d.ts","./node_modules/@types/lodash-es/constant.d.ts","./node_modules/@types/lodash-es/countby.d.ts","./node_modules/@types/lodash-es/create.d.ts","./node_modules/@types/lodash-es/curry.d.ts","./node_modules/@types/lodash-es/curryright.d.ts","./node_modules/@types/lodash-es/debounce.d.ts","./node_modules/@types/lodash-es/deburr.d.ts","./node_modules/@types/lodash-es/defaults.d.ts","./node_modules/@types/lodash-es/defaultsdeep.d.ts","./node_modules/@types/lodash-es/defaultto.d.ts","./node_modules/@types/lodash-es/defer.d.ts","./node_modules/@types/lodash-es/delay.d.ts","./node_modules/@types/lodash-es/difference.d.ts","./node_modules/@types/lodash-es/differenceby.d.ts","./node_modules/@types/lodash-es/differencewith.d.ts","./node_modules/@types/lodash-es/divide.d.ts","./node_modules/@types/lodash-es/drop.d.ts","./node_modules/@types/lodash-es/dropright.d.ts","./node_modules/@types/lodash-es/droprightwhile.d.ts","./node_modules/@types/lodash-es/dropwhile.d.ts","./node_modules/@types/lodash-es/each.d.ts","./node_modules/@types/lodash-es/eachright.d.ts","./node_modules/@types/lodash-es/endswith.d.ts","./node_modules/@types/lodash-es/entries.d.ts","./node_modules/@types/lodash-es/entriesin.d.ts","./node_modules/@types/lodash-es/eq.d.ts","./node_modules/@types/lodash-es/escape.d.ts","./node_modules/@types/lodash-es/escaperegexp.d.ts","./node_modules/@types/lodash-es/every.d.ts","./node_modules/@types/lodash-es/extend.d.ts","./node_modules/@types/lodash-es/extendwith.d.ts","./node_modules/@types/lodash-es/fill.d.ts","./node_modules/@types/lodash-es/filter.d.ts","./node_modules/@types/lodash-es/find.d.ts","./node_modules/@types/lodash-es/findindex.d.ts","./node_modules/@types/lodash-es/findkey.d.ts","./node_modules/@types/lodash-es/findlast.d.ts","./node_modules/@types/lodash-es/findlastindex.d.ts","./node_modules/@types/lodash-es/findlastkey.d.ts","./node_modules/@types/lodash-es/first.d.ts","./node_modules/@types/lodash-es/flatmap.d.ts","./node_modules/@types/lodash-es/flatmapdeep.d.ts","./node_modules/@types/lodash-es/flatmapdepth.d.ts","./node_modules/@types/lodash-es/flatten.d.ts","./node_modules/@types/lodash-es/flattendeep.d.ts","./node_modules/@types/lodash-es/flattendepth.d.ts","./node_modules/@types/lodash-es/flip.d.ts","./node_modules/@types/lodash-es/floor.d.ts","./node_modules/@types/lodash-es/flow.d.ts","./node_modules/@types/lodash-es/flowright.d.ts","./node_modules/@types/lodash-es/foreach.d.ts","./node_modules/@types/lodash-es/foreachright.d.ts","./node_modules/@types/lodash-es/forin.d.ts","./node_modules/@types/lodash-es/forinright.d.ts","./node_modules/@types/lodash-es/forown.d.ts","./node_modules/@types/lodash-es/forownright.d.ts","./node_modules/@types/lodash-es/frompairs.d.ts","./node_modules/@types/lodash-es/functions.d.ts","./node_modules/@types/lodash-es/functionsin.d.ts","./node_modules/@types/lodash-es/get.d.ts","./node_modules/@types/lodash-es/groupby.d.ts","./node_modules/@types/lodash-es/gt.d.ts","./node_modules/@types/lodash-es/gte.d.ts","./node_modules/@types/lodash-es/has.d.ts","./node_modules/@types/lodash-es/hasin.d.ts","./node_modules/@types/lodash-es/head.d.ts","./node_modules/@types/lodash-es/identity.d.ts","./node_modules/@types/lodash-es/includes.d.ts","./node_modules/@types/lodash-es/indexof.d.ts","./node_modules/@types/lodash-es/initial.d.ts","./node_modules/@types/lodash-es/inrange.d.ts","./node_modules/@types/lodash-es/intersection.d.ts","./node_modules/@types/lodash-es/intersectionby.d.ts","./node_modules/@types/lodash-es/intersectionwith.d.ts","./node_modules/@types/lodash-es/invert.d.ts","./node_modules/@types/lodash-es/invertby.d.ts","./node_modules/@types/lodash-es/invoke.d.ts","./node_modules/@types/lodash-es/invokemap.d.ts","./node_modules/@types/lodash-es/isarguments.d.ts","./node_modules/@types/lodash-es/isarray.d.ts","./node_modules/@types/lodash-es/isarraybuffer.d.ts","./node_modules/@types/lodash-es/isarraylike.d.ts","./node_modules/@types/lodash-es/isarraylikeobject.d.ts","./node_modules/@types/lodash-es/isboolean.d.ts","./node_modules/@types/lodash-es/isbuffer.d.ts","./node_modules/@types/lodash-es/isdate.d.ts","./node_modules/@types/lodash-es/iselement.d.ts","./node_modules/@types/lodash-es/isempty.d.ts","./node_modules/@types/lodash-es/isequal.d.ts","./node_modules/@types/lodash-es/isequalwith.d.ts","./node_modules/@types/lodash-es/iserror.d.ts","./node_modules/@types/lodash-es/isfinite.d.ts","./node_modules/@types/lodash-es/isfunction.d.ts","./node_modules/@types/lodash-es/isinteger.d.ts","./node_modules/@types/lodash-es/islength.d.ts","./node_modules/@types/lodash-es/ismap.d.ts","./node_modules/@types/lodash-es/ismatch.d.ts","./node_modules/@types/lodash-es/ismatchwith.d.ts","./node_modules/@types/lodash-es/isnan.d.ts","./node_modules/@types/lodash-es/isnative.d.ts","./node_modules/@types/lodash-es/isnil.d.ts","./node_modules/@types/lodash-es/isnull.d.ts","./node_modules/@types/lodash-es/isnumber.d.ts","./node_modules/@types/lodash-es/isobject.d.ts","./node_modules/@types/lodash-es/isobjectlike.d.ts","./node_modules/@types/lodash-es/isplainobject.d.ts","./node_modules/@types/lodash-es/isregexp.d.ts","./node_modules/@types/lodash-es/issafeinteger.d.ts","./node_modules/@types/lodash-es/isset.d.ts","./node_modules/@types/lodash-es/isstring.d.ts","./node_modules/@types/lodash-es/issymbol.d.ts","./node_modules/@types/lodash-es/istypedarray.d.ts","./node_modules/@types/lodash-es/isundefined.d.ts","./node_modules/@types/lodash-es/isweakmap.d.ts","./node_modules/@types/lodash-es/isweakset.d.ts","./node_modules/@types/lodash-es/iteratee.d.ts","./node_modules/@types/lodash-es/join.d.ts","./node_modules/@types/lodash-es/kebabcase.d.ts","./node_modules/@types/lodash-es/keyby.d.ts","./node_modules/@types/lodash-es/keys.d.ts","./node_modules/@types/lodash-es/keysin.d.ts","./node_modules/@types/lodash-es/last.d.ts","./node_modules/@types/lodash-es/lastindexof.d.ts","./node_modules/@types/lodash-es/lowercase.d.ts","./node_modules/@types/lodash-es/lowerfirst.d.ts","./node_modules/@types/lodash-es/lt.d.ts","./node_modules/@types/lodash-es/lte.d.ts","./node_modules/@types/lodash-es/map.d.ts","./node_modules/@types/lodash-es/mapkeys.d.ts","./node_modules/@types/lodash-es/mapvalues.d.ts","./node_modules/@types/lodash-es/matches.d.ts","./node_modules/@types/lodash-es/matchesproperty.d.ts","./node_modules/@types/lodash-es/max.d.ts","./node_modules/@types/lodash-es/maxby.d.ts","./node_modules/@types/lodash-es/mean.d.ts","./node_modules/@types/lodash-es/meanby.d.ts","./node_modules/@types/lodash-es/memoize.d.ts","./node_modules/@types/lodash-es/merge.d.ts","./node_modules/@types/lodash-es/mergewith.d.ts","./node_modules/@types/lodash-es/method.d.ts","./node_modules/@types/lodash-es/methodof.d.ts","./node_modules/@types/lodash-es/min.d.ts","./node_modules/@types/lodash-es/minby.d.ts","./node_modules/@types/lodash-es/mixin.d.ts","./node_modules/@types/lodash-es/multiply.d.ts","./node_modules/@types/lodash-es/negate.d.ts","./node_modules/@types/lodash-es/noop.d.ts","./node_modules/@types/lodash-es/now.d.ts","./node_modules/@types/lodash-es/nth.d.ts","./node_modules/@types/lodash-es/ntharg.d.ts","./node_modules/@types/lodash-es/omit.d.ts","./node_modules/@types/lodash-es/omitby.d.ts","./node_modules/@types/lodash-es/once.d.ts","./node_modules/@types/lodash-es/orderby.d.ts","./node_modules/@types/lodash-es/over.d.ts","./node_modules/@types/lodash-es/overargs.d.ts","./node_modules/@types/lodash-es/overevery.d.ts","./node_modules/@types/lodash-es/oversome.d.ts","./node_modules/@types/lodash-es/pad.d.ts","./node_modules/@types/lodash-es/padend.d.ts","./node_modules/@types/lodash-es/padstart.d.ts","./node_modules/@types/lodash-es/parseint.d.ts","./node_modules/@types/lodash-es/partial.d.ts","./node_modules/@types/lodash-es/partialright.d.ts","./node_modules/@types/lodash-es/partition.d.ts","./node_modules/@types/lodash-es/pick.d.ts","./node_modules/@types/lodash-es/pickby.d.ts","./node_modules/@types/lodash-es/property.d.ts","./node_modules/@types/lodash-es/propertyof.d.ts","./node_modules/@types/lodash-es/pull.d.ts","./node_modules/@types/lodash-es/pullall.d.ts","./node_modules/@types/lodash-es/pullallby.d.ts","./node_modules/@types/lodash-es/pullallwith.d.ts","./node_modules/@types/lodash-es/pullat.d.ts","./node_modules/@types/lodash-es/random.d.ts","./node_modules/@types/lodash-es/range.d.ts","./node_modules/@types/lodash-es/rangeright.d.ts","./node_modules/@types/lodash-es/rearg.d.ts","./node_modules/@types/lodash-es/reduce.d.ts","./node_modules/@types/lodash-es/reduceright.d.ts","./node_modules/@types/lodash-es/reject.d.ts","./node_modules/@types/lodash-es/remove.d.ts","./node_modules/@types/lodash-es/repeat.d.ts","./node_modules/@types/lodash-es/replace.d.ts","./node_modules/@types/lodash-es/rest.d.ts","./node_modules/@types/lodash-es/result.d.ts","./node_modules/@types/lodash-es/reverse.d.ts","./node_modules/@types/lodash-es/round.d.ts","./node_modules/@types/lodash-es/sample.d.ts","./node_modules/@types/lodash-es/samplesize.d.ts","./node_modules/@types/lodash-es/set.d.ts","./node_modules/@types/lodash-es/setwith.d.ts","./node_modules/@types/lodash-es/shuffle.d.ts","./node_modules/@types/lodash-es/size.d.ts","./node_modules/@types/lodash-es/slice.d.ts","./node_modules/@types/lodash-es/snakecase.d.ts","./node_modules/@types/lodash-es/some.d.ts","./node_modules/@types/lodash-es/sortby.d.ts","./node_modules/@types/lodash-es/sortedindex.d.ts","./node_modules/@types/lodash-es/sortedindexby.d.ts","./node_modules/@types/lodash-es/sortedindexof.d.ts","./node_modules/@types/lodash-es/sortedlastindex.d.ts","./node_modules/@types/lodash-es/sortedlastindexby.d.ts","./node_modules/@types/lodash-es/sortedlastindexof.d.ts","./node_modules/@types/lodash-es/sorteduniq.d.ts","./node_modules/@types/lodash-es/sorteduniqby.d.ts","./node_modules/@types/lodash-es/split.d.ts","./node_modules/@types/lodash-es/spread.d.ts","./node_modules/@types/lodash-es/startcase.d.ts","./node_modules/@types/lodash-es/startswith.d.ts","./node_modules/@types/lodash-es/stubarray.d.ts","./node_modules/@types/lodash-es/stubfalse.d.ts","./node_modules/@types/lodash-es/stubobject.d.ts","./node_modules/@types/lodash-es/stubstring.d.ts","./node_modules/@types/lodash-es/stubtrue.d.ts","./node_modules/@types/lodash-es/subtract.d.ts","./node_modules/@types/lodash-es/sum.d.ts","./node_modules/@types/lodash-es/sumby.d.ts","./node_modules/@types/lodash-es/tail.d.ts","./node_modules/@types/lodash-es/take.d.ts","./node_modules/@types/lodash-es/takeright.d.ts","./node_modules/@types/lodash-es/takerightwhile.d.ts","./node_modules/@types/lodash-es/takewhile.d.ts","./node_modules/@types/lodash-es/tap.d.ts","./node_modules/@types/lodash-es/template.d.ts","./node_modules/@types/lodash-es/templatesettings.d.ts","./node_modules/@types/lodash-es/throttle.d.ts","./node_modules/@types/lodash-es/thru.d.ts","./node_modules/@types/lodash-es/times.d.ts","./node_modules/@types/lodash-es/toarray.d.ts","./node_modules/@types/lodash-es/tofinite.d.ts","./node_modules/@types/lodash-es/tointeger.d.ts","./node_modules/@types/lodash-es/tolength.d.ts","./node_modules/@types/lodash-es/tolower.d.ts","./node_modules/@types/lodash-es/tonumber.d.ts","./node_modules/@types/lodash-es/topairs.d.ts","./node_modules/@types/lodash-es/topairsin.d.ts","./node_modules/@types/lodash-es/topath.d.ts","./node_modules/@types/lodash-es/toplainobject.d.ts","./node_modules/@types/lodash-es/tosafeinteger.d.ts","./node_modules/@types/lodash-es/tostring.d.ts","./node_modules/@types/lodash-es/toupper.d.ts","./node_modules/@types/lodash-es/transform.d.ts","./node_modules/@types/lodash-es/trim.d.ts","./node_modules/@types/lodash-es/trimend.d.ts","./node_modules/@types/lodash-es/trimstart.d.ts","./node_modules/@types/lodash-es/truncate.d.ts","./node_modules/@types/lodash-es/unary.d.ts","./node_modules/@types/lodash-es/unescape.d.ts","./node_modules/@types/lodash-es/union.d.ts","./node_modules/@types/lodash-es/unionby.d.ts","./node_modules/@types/lodash-es/unionwith.d.ts","./node_modules/@types/lodash-es/uniq.d.ts","./node_modules/@types/lodash-es/uniqby.d.ts","./node_modules/@types/lodash-es/uniqueid.d.ts","./node_modules/@types/lodash-es/uniqwith.d.ts","./node_modules/@types/lodash-es/unset.d.ts","./node_modules/@types/lodash-es/unzip.d.ts","./node_modules/@types/lodash-es/unzipwith.d.ts","./node_modules/@types/lodash-es/update.d.ts","./node_modules/@types/lodash-es/updatewith.d.ts","./node_modules/@types/lodash-es/uppercase.d.ts","./node_modules/@types/lodash-es/upperfirst.d.ts","./node_modules/@types/lodash-es/values.d.ts","./node_modules/@types/lodash-es/valuesin.d.ts","./node_modules/@types/lodash-es/without.d.ts","./node_modules/@types/lodash-es/words.d.ts","./node_modules/@types/lodash-es/wrap.d.ts","./node_modules/@types/lodash-es/xor.d.ts","./node_modules/@types/lodash-es/xorby.d.ts","./node_modules/@types/lodash-es/xorwith.d.ts","./node_modules/@types/lodash-es/zip.d.ts","./node_modules/@types/lodash-es/zipobject.d.ts","./node_modules/@types/lodash-es/zipobjectdeep.d.ts","./node_modules/@types/lodash-es/zipwith.d.ts","./node_modules/@types/lodash-es/index.d.ts","./node_modules/@types/web-bluetooth/index.d.ts","./node_modules/@types/yauzl/index.d.ts"],"fileInfos":[{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0",{"version":"0","affectsGlobalScope":true},"0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0",{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0"],"root":[[77,100],[103,115],117,[124,129]],"options":{"composite":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":true},"fileIdsList":[[71,73,74,76,102,116,136,141],[66,136,141],[136,141],[130,136,141],[136,141,154,188],[136,141,202],[136,141,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506],[136,141,190,192,193,194,195,196,197,198,199,200,201,202],[136,141,190,191,193,194,195,196,197,198,199,200,201,202],[136,141,191,192,193,194,195,196,197,198,199,200,201,202],[136,141,190,191,192,194,195,196,197,198,199,200,201,202],[136,141,190,191,192,193,195,196,197,198,199,200,201,202],[136,141,190,191,192,193,194,196,197,198,199,200,201,202],[136,141,190,191,192,193,194,195,197,198,199,200,201,202],[136,141,190,191,192,193,194,195,196,198,199,200,201,202],[136,141,190,191,192,193,194,195,196,197,199,200,201,202],[136,141,190,191,192,193,194,195,196,197,198,200,201,202],[136,141,190,191,192,193,194,195,196,197,198,199,201,202],[136,141,190,191,192,193,194,195,196,197,198,199,200,202],[136,141,190,191,192,193,194,195,196,197,198,199,200,201],[136,138,141],[136,140,141],[136,141,146,173],[136,141,142,153,154,161,170,181],[136,141,142,143,153,161],[132,133,136,141],[136,141,144,182],[136,141,145,146,154,162],[136,141,146,170,178],[136,141,147,149,153,161],[136,141,148],[136,141,149,150],[136,141,153],[136,141,152,153],[136,140,141,153],[136,141,153,154,155,170,181],[136,141,153,154,155,170],[136,141,153,156,161,170,181],[136,141,153,154,156,157,161,170,178,181],[136,141,156,158,170,178,181],[136,141,153,159],[136,141,160,181,186],[136,141,149,153,161,170],[136,141,162],[136,141,163],[136,140,141,164],[136,141,165,180,186],[136,141,166],[136,141,167],[136,141,153,168],[136,141,168,169,182,184],[136,141,153,170,171,172],[136,141,170,172],[136,141,170,171],[136,141,173],[136,141,174],[136,141,153,176,177],[136,141,176,177],[136,141,146,161,170,178],[136,141,179],[141],[134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187],[136,141,161,180],[136,141,156,167,181],[136,141,146,182],[136,141,170,183],[136,141,184],[136,141,185],[136,141,146,153,155,164,170,181,184,186],[136,141,170,187],[136,141,153,170,188],[65,66,67,136,141],[68,136,141],[65,136,141],[65,70,71,73,136,141],[70,71,72,73,136,141],[74,75,102,136,141],[122,136,141],[118,136,141],[119,136,141],[120,121,136,141],[74,76,102,136,141],[74,76,101,102,136,141],[69,73,136,141],[73,136,141],[79,80,81,136,141],[74,76,85,102,136,141],[74,76,84,102,136,141],[74,76,89,102,136,141],[74,76,91,102,136,141],[74,76,77,89,90,102,136,141],[74,76,78,82,83,84,85,90,91,92,94,102,136,141],[74,76,89,90,102,136,141],[74,76,78,81,82,83,84,102,136,141],[77,136,141],[74,76,98,102,136,141],[80,123,136,141],[74,76,93,99,102,136,141],[74,76,82,86,102,123,126,136,141],[74,76,102,106,136,141],[81,136,141],[83,102,106,136,141],[102,104,111,112,114,115,125,136,141],[76,136,141],[76,81,136,141],[94,108,136,141],[94,136,141],[74,76,78,82,83,87,88,90,96,100,102,103,136,141],[74,76,78,82,83,87,88,90,91,92,94,96,100,102,105,106,107,109,110,136,141],[74,76,82,83,87,88,90,94,96,97,100,102,106,136,141],[74,76,78,80,82,83,87,88,96,97,100,102,103,106,113,136,141],[74,76,78,82,83,84,87,88,90,100,102,136,141],[66],[],[71,73,74,76,102,116,150,155],[71,73,74,76,102,116,207,212],[71,73,74,76,102,116],[218],[221,222,223,224,225,226,227,228,229,230,231,232],[220,222,223,224,225,226,227,228,229,230,231,232],[220,221,223,224,225,226,227,228,229,230,231,232],[220,221,222,224,225,226,227,228,229,230,231,232],[220,221,222,223,225,226,227,228,229,230,231,232],[220,221,222,223,224,226,227,228,229,230,231,232],[220,221,222,223,224,225,227,228,229,230,231,232],[220,221,222,223,224,225,226,228,229,230,231,232],[220,221,222,223,224,225,226,227,229,230,231,232],[220,221,222,223,224,225,226,227,228,230,231,232],[220,221,222,223,224,225,226,227,228,229,231,232],[220,221,222,223,224,225,226,227,228,229,230,232],[220,221,222,223,224,225,226,227,228,229,230,231],[232],[71,73,74,76,102,116,209,214],[71,73,74,76,102,116,210,215],[71,73,74,76,102,116,208,213],[71,73,74,76,102,116,211,216],[71,73,74,76,102,116,212,217],[71,73,74,76,102,116,213,218],[71,73,74,76,102,116,214,219],[71,73,74,76,102,116,215],[71,73,74,76,102,116,216],[71,73,74,76,102,116,217],[71,73,74,76,102,116,218],[71,73,74,76,102,116,219],[71,73,74,76,102,116,149,154],[71,73,74,76,102,116,157,162],[71,73,74,76,102,116,158,163],[71,73,74,76,102,116,159,164],[71,73,74,76,102,116,160,165],[71,73,74,76,102,116,161,166],[71,73,74,76,102,116,162,167],[71,73,74,76,102,116,153,158],[71,73,74,76,102,116,151,156],[71,73,74,76,102,116,152,157],[71,73,74,76,102,116,163,168],[71,73,74,76,102,116,164,169],[71,73,74,76,102,116,165,170],[71,73,74,76,102,116,166,171],[71,73,74,76,102,116,167,172],[71,73,74,76,102,116,168,173],[71,73,74,76,102,116,169,174],[71,73,74,76,102,116,170,175],[71,73,74,76,102,116,171,176],[71,73,74,76,102,116,172,177],[71,73,74,76,102,116,173,178],[71,73,74,76,102,116,174,179],[71,73,74,76,102,116,156,161],[71,73,74,76,102,116,175,180],[71,73,74,76,102,116,176,181],[71,73,74,76,102,116,177,182],[71,73,74,76,102,116,178,183],[71,73,74,76,102,116,179,184],[71,73,74,76,102,116,180,185],[71,73,74,76,102,116,181,186],[71,73,74,76,102,116,182,187],[71,73,74,76,102,116,183,188],[81],[71,73,74,76,102,116,184,189],[71,73,74,76,102,116,185,190],[71,73,74,76,102,116,186,191],[71,73,74,76,102,116,187,192],[71,73,74,76,102,116,188,193],[71,73,74,76,102,116,190,195],[71,73,74,76,102,116,189,194],[71,73,74,76,102,116,191,196],[71,73,74,76,102,116,192,197],[71,73,74,76,102,116,193,198],[71,73,74,76,102,116,194,199],[71,73,74,76,102,116,195,200],[71,73,74,76,102,116,196,201],[71,73,74,76,102,116,197,202],[71,73,74,76,102,116,155,160],[71,73,74,76,102,116,154,159],[71,73,74,76,102,116,206,211],[71,73,74,76,102,116,198,203],[71,73,74,76,102,116,199,204],[71,73,74,76,102,116,200,205],[71,73,74,76,102,116,201,206],[71,73,74,76,102,116,202,207],[71,73,74,76,102,116,203,208],[71,73,74,76,102,116,204,209],[71,73,74,76,102,116,205,210],[65,66,67],[68],[65],[65,70,71,73],[70,71,72,73],[74,75,102],[71,73,74,76,102,116,142,147],[71,73,74,76,102,116,138,143],[71,73,74,76,102,116,137,142],[71,73,74,76,102,116,139,144],[71,73,74,76,102,116,140,145],[71,73,74,76,102,116,141,146],[74,76,102],[74,76,101,102],[69,73],[73],[80,81],[74,76,82,83,84,102],[77,166,171],[155,160],[161,166],[71,73,74,76,102,116,143,148],[71,73,74,76,102,116,146,151],[71,73,74,76,102,116,147,152],[71,73,74,76,102,116,148,153],[71,73,74,76,102,116,144,149],[71,73,74,76,102,116,145,150],[76],[76,81,165],[76,166,171],[94],[152,157],[142,147]],"referencedMap":[[117,1],[67,2],[66,3],[131,4],[189,5],[203,6],[204,6],[205,6],[206,6],[207,6],[208,6],[209,6],[210,6],[211,6],[212,6],[213,6],[214,6],[215,6],[216,6],[217,6],[218,6],[219,6],[220,6],[221,6],[222,6],[223,6],[224,6],[225,6],[226,6],[227,6],[228,6],[229,6],[230,6],[231,6],[232,6],[233,6],[234,6],[235,6],[236,6],[237,6],[238,6],[239,6],[240,6],[241,6],[242,6],[243,6],[244,6],[245,6],[246,6],[247,6],[248,6],[249,6],[250,6],[251,6],[252,6],[253,6],[254,6],[255,6],[256,6],[257,6],[258,6],[259,6],[260,6],[261,6],[262,6],[263,6],[264,6],[265,6],[266,6],[267,6],[268,6],[269,6],[270,6],[271,6],[272,6],[273,6],[274,6],[275,6],[276,6],[277,6],[278,6],[279,6],[280,6],[281,6],[282,6],[283,6],[284,6],[285,6],[286,6],[287,6],[288,6],[289,6],[290,6],[291,6],[292,6],[293,6],[294,6],[295,6],[296,6],[297,6],[298,6],[299,6],[507,7],[300,6],[301,6],[302,6],[303,6],[304,6],[305,6],[306,6],[307,6],[308,6],[309,6],[310,6],[311,6],[312,6],[313,6],[314,6],[315,6],[316,6],[317,6],[318,6],[319,6],[320,6],[321,6],[322,6],[323,6],[324,6],[325,6],[326,6],[327,6],[328,6],[329,6],[330,6],[331,6],[332,6],[333,6],[334,6],[335,6],[336,6],[337,6],[338,6],[339,6],[340,6],[341,6],[342,6],[343,6],[344,6],[345,6],[346,6],[347,6],[348,6],[349,6],[350,6],[351,6],[352,6],[353,6],[354,6],[355,6],[356,6],[357,6],[358,6],[359,6],[360,6],[361,6],[362,6],[363,6],[364,6],[365,6],[366,6],[367,6],[368,6],[369,6],[370,6],[371,6],[372,6],[373,6],[374,6],[375,6],[376,6],[377,6],[378,6],[379,6],[380,6],[381,6],[382,6],[383,6],[384,6],[385,6],[386,6],[387,6],[388,6],[389,6],[390,6],[391,6],[392,6],[393,6],[394,6],[395,6],[396,6],[397,6],[398,6],[399,6],[400,6],[401,6],[402,6],[403,6],[404,6],[405,6],[406,6],[407,6],[408,6],[409,6],[410,6],[411,6],[412,6],[413,6],[414,6],[415,6],[416,6],[417,6],[418,6],[419,6],[420,6],[421,6],[422,6],[423,6],[424,6],[425,6],[426,6],[427,6],[428,6],[429,6],[430,6],[431,6],[432,6],[433,6],[434,6],[435,6],[436,6],[437,6],[438,6],[439,6],[440,6],[441,6],[442,6],[443,6],[444,6],[445,6],[446,6],[447,6],[448,6],[449,6],[450,6],[451,6],[452,6],[453,6],[454,6],[455,6],[456,6],[457,6],[458,6],[459,6],[460,6],[461,6],[462,6],[463,6],[464,6],[465,6],[466,6],[467,6],[468,6],[469,6],[470,6],[471,6],[472,6],[473,6],[474,6],[475,6],[476,6],[477,6],[478,6],[479,6],[480,6],[481,6],[482,6],[483,6],[484,6],[485,6],[486,6],[487,6],[488,6],[489,6],[490,6],[491,6],[492,6],[493,6],[494,6],[495,6],[496,6],[497,6],[498,6],[499,6],[500,6],[501,6],[502,6],[503,6],[504,6],[505,6],[506,6],[191,8],[192,9],[190,10],[193,11],[194,12],[195,13],[196,14],[197,15],[198,16],[199,17],[200,18],[201,19],[202,20],[130,3],[138,21],[139,21],[140,22],[141,23],[142,24],[143,25],[134,26],[132,3],[133,3],[144,27],[145,28],[146,29],[147,30],[148,31],[149,32],[150,32],[151,33],[152,34],[153,35],[154,36],[155,37],[137,3],[156,38],[157,39],[158,40],[159,41],[160,42],[161,43],[162,44],[163,45],[164,46],[165,47],[166,48],[167,49],[168,50],[169,51],[170,52],[172,53],[171,54],[173,55],[174,56],[175,3],[176,57],[177,58],[178,59],[179,60],[136,61],[135,3],[188,62],[180,63],[181,64],[182,65],[183,66],[184,67],[185,68],[186,69],[187,70],[508,3],[509,71],[68,72],[69,73],[70,74],[71,75],[73,76],[65,3],[72,3],[76,77],[63,3],[64,3],[12,3],[14,3],[13,3],[2,3],[15,3],[16,3],[17,3],[18,3],[19,3],[20,3],[21,3],[22,3],[3,3],[4,3],[23,3],[27,3],[24,3],[25,3],[26,3],[28,3],[29,3],[30,3],[5,3],[31,3],[32,3],[33,3],[34,3],[6,3],[38,3],[35,3],[36,3],[37,3],[39,3],[7,3],[40,3],[45,3],[46,3],[41,3],[42,3],[43,3],[44,3],[8,3],[50,3],[47,3],[48,3],[49,3],[51,3],[9,3],[52,3],[53,3],[54,3],[57,3],[55,3],[56,3],[58,3],[59,3],[10,3],[1,3],[11,3],[62,3],[61,3],[60,3],[123,78],[119,79],[118,3],[120,80],[121,3],[122,81],[75,82],[101,82],[102,83],[74,84],[116,85],[82,86],[86,87],[89,3],[87,82],[88,88],[90,89],[92,90],[93,91],[95,92],[96,93],[97,82],[85,94],[78,95],[99,96],[105,3],[91,3],[124,97],[100,98],[127,99],[128,100],[129,101],[125,102],[126,103],[83,104],[103,104],[84,105],[94,104],[106,104],[77,104],[80,3],[81,3],[109,106],[110,3],[113,3],[107,107],[104,108],[111,109],[112,110],[114,111],[115,112],[108,3],[79,3],[98,3]],"exportedModulesMap":[[117,1],[67,113],[66,114],[131,115],[189,116],[203,117],[204,117],[205,117],[206,117],[207,117],[208,117],[209,117],[210,117],[211,117],[212,117],[213,117],[214,117],[215,117],[216,117],[217,117],[218,114],[219,118],[220,119],[221,120],[222,121],[223,122],[224,123],[225,124],[226,125],[227,126],[228,127],[229,128],[230,129],[231,130],[232,131],[233,132],[234,132],[235,132],[236,132],[237,132],[238,132],[239,132],[240,132],[241,132],[242,132],[243,132],[244,132],[245,132],[246,132],[247,132],[248,132],[249,132],[250,132],[251,132],[252,132],[253,132],[254,132],[255,132],[256,132],[257,132],[258,132],[259,132],[260,132],[261,132],[262,132],[263,132],[264,132],[265,132],[266,132],[267,132],[268,132],[269,132],[270,132],[271,132],[272,132],[273,132],[274,132],[275,132],[276,132],[277,132],[278,132],[279,132],[280,132],[281,132],[282,132],[283,132],[284,132],[285,132],[286,132],[287,132],[288,132],[289,132],[290,132],[291,132],[292,132],[293,132],[294,132],[295,132],[296,132],[297,132],[298,132],[299,132],[507,132],[300,132],[301,132],[302,132],[303,132],[304,132],[305,132],[306,132],[307,132],[308,132],[309,132],[310,132],[311,132],[312,132],[313,132],[314,132],[315,132],[316,132],[317,132],[318,132],[319,132],[320,132],[321,132],[322,132],[323,132],[324,132],[325,132],[326,132],[327,132],[328,132],[329,132],[330,132],[331,132],[332,132],[333,132],[334,132],[335,132],[336,132],[337,132],[338,132],[339,132],[340,132],[341,132],[342,132],[343,132],[344,132],[345,132],[346,132],[347,132],[348,132],[349,132],[350,132],[351,132],[352,132],[353,132],[354,132],[355,132],[356,132],[357,132],[358,132],[359,132],[360,132],[361,132],[362,132],[363,132],[364,132],[365,132],[366,132],[367,132],[368,132],[369,132],[370,132],[371,132],[372,132],[373,132],[374,132],[375,132],[376,132],[377,132],[378,132],[379,132],[380,132],[381,132],[382,132],[383,132],[384,132],[385,132],[386,132],[387,132],[388,132],[389,132],[390,132],[391,132],[392,132],[393,132],[394,132],[395,132],[396,132],[397,132],[398,132],[399,132],[400,132],[401,132],[402,132],[403,132],[404,132],[405,132],[406,132],[407,132],[408,132],[409,132],[410,132],[411,132],[412,132],[413,132],[414,132],[415,132],[416,132],[417,132],[418,132],[419,132],[420,132],[421,132],[422,132],[423,132],[424,132],[425,132],[426,132],[427,132],[428,132],[429,132],[430,132],[431,132],[432,132],[433,132],[434,132],[435,132],[436,132],[437,132],[438,132],[439,132],[440,132],[441,132],[442,132],[443,132],[444,132],[445,132],[446,132],[447,132],[448,132],[449,132],[450,132],[451,132],[452,132],[453,132],[454,132],[455,132],[456,132],[457,132],[458,132],[459,132],[460,132],[461,132],[462,132],[463,132],[464,132],[465,132],[466,132],[467,132],[468,132],[469,132],[470,132],[471,132],[472,132],[473,132],[474,132],[475,132],[476,132],[477,132],[478,132],[479,132],[480,132],[481,132],[482,132],[483,132],[484,132],[485,132],[486,132],[487,132],[488,132],[489,132],[490,132],[491,132],[492,132],[493,132],[494,132],[495,132],[496,132],[497,132],[498,132],[499,132],[500,132],[501,132],[502,132],[503,132],[504,132],[505,132],[506,132],[191,133],[192,134],[190,135],[193,136],[194,137],[195,138],[196,139],[197,140],[198,141],[199,142],[200,143],[201,144],[202,117],[130,145],[138,146],[139,147],[140,148],[141,149],[142,150],[143,151],[134,152],[132,153],[133,154],[144,155],[145,156],[146,157],[147,158],[148,159],[149,160],[150,161],[151,162],[152,163],[153,164],[154,165],[155,166],[137,167],[156,168],[157,169],[158,170],[159,171],[160,172],[161,173],[162,174],[163,175],[164,176],[165,177],[166,178],[167,179],[168,180],[169,181],[170,182],[172,183],[171,184],[173,185],[174,186],[175,187],[176,188],[177,189],[178,190],[179,191],[136,192],[135,193],[188,194],[180,195],[181,196],[182,197],[183,198],[184,199],[185,200],[186,201],[187,202],[508,132],[509,132],[68,203],[69,204],[70,205],[71,206],[73,207],[65,114],[72,114],[76,208],[63,114],[64,114],[12,114],[14,114],[13,114],[2,114],[15,114],[16,114],[17,114],[18,114],[19,114],[20,114],[21,114],[22,114],[3,114],[4,114],[23,114],[27,114],[24,114],[25,114],[26,114],[28,114],[29,114],[30,114],[5,114],[31,114],[32,114],[33,114],[34,114],[6,114],[38,114],[35,114],[36,114],[37,114],[39,114],[7,114],[40,114],[45,114],[46,114],[41,114],[42,114],[43,114],[44,114],[8,114],[50,114],[47,114],[48,114],[49,114],[51,114],[9,114],[52,114],[53,114],[54,114],[57,114],[55,114],[56,114],[58,114],[59,114],[10,114],[1,114],[11,114],[62,114],[61,114],[60,114],[123,209],[119,210],[118,211],[120,212],[121,213],[122,214],[75,215],[101,215],[102,216],[74,217],[116,218],[82,219],[86,87],[89,114],[87,82],[88,88],[90,89],[92,90],[93,91],[95,92],[96,93],[97,82],[85,220],[78,221],[99,215],[105,222],[91,223],[124,224],[100,98],[127,225],[128,226],[129,227],[125,228],[126,229],[83,230],[103,230],[84,231],[94,230],[106,230],[77,232],[80,114],[81,114],[109,233],[110,222],[113,114],[107,233],[104,108],[111,109],[112,110],[114,111],[115,112],[108,234],[79,235],[98,114]],"semanticDiagnosticsPerFile":[117,67,66,131,189,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,507,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,191,192,190,193,194,195,196,197,198,199,200,201,202,130,138,139,140,141,142,143,134,132,133,144,145,146,147,148,149,150,151,152,153,154,155,137,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,172,171,173,174,175,176,177,178,179,136,135,188,180,181,182,183,184,185,186,187,508,509,68,69,70,71,73,65,72,76,63,64,12,14,13,2,15,16,17,18,19,20,21,22,3,4,23,27,24,25,26,28,29,30,5,31,32,33,34,6,38,35,36,37,39,7,40,45,46,41,42,43,44,8,50,47,48,49,51,9,52,53,54,57,55,56,58,59,10,1,11,62,61,60,123,119,118,120,121,122,75,101,102,74,116,82,86,89,87,88,90,92,93,95,96,97,85,78,99,105,91,124,100,127,128,129,125,126,83,103,84,94,106,77,80,81,109,110,113,107,104,111,112,114,115,108,79,98],"affectedFilesPendingEmit":[82,86,89,87,88,90,92,93,95,96,97,85,78,99,105,91,100,127,128,129,125,126,83,103,84,94,106,77,80,81,109,110,113,107,104,111,112,114,115,108,79,98],"emitSignatures":[77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,103,104,105,106,107,108,109,110,111,112,113,114,115]},"version":"5.3.3"} \ No newline at end of file +{"program":{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/@vue/shared/dist/shared.d.ts","./node_modules/@babel/types/lib/index.d.ts","./node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/@vue/compiler-core/dist/compiler-core.d.ts","./node_modules/@vue/compiler-dom/dist/compiler-dom.d.ts","./node_modules/@vue/reactivity/dist/reactivity.d.ts","./node_modules/@vue/runtime-core/dist/runtime-core.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@vue/runtime-dom/dist/runtime-dom.d.ts","./node_modules/vue/dist/vue.d.mts","./node_modules/vue-demi/lib/index.d.ts","./node_modules/pinia/dist/pinia.d.ts","./src/renderer/src/stores/toast.ts","./src/renderer/src/composables/usenotify.ts","./src/shared/printer-info.ts","./src/renderer/src/types/ipc.ts","./src/renderer/src/types/printer.ts","./src/renderer/src/api/cardsoon.ts","./src/renderer/src/stores/config.ts","./src/renderer/src/composables/useprinterstatus.ts","./src/renderer/src/stores/app.ts","./src/renderer/src/composables/useappbootstrap.ts","./src/renderer/src/app.vue.ts","./src/renderer/src/components/appfooter.vue.ts","./src/renderer/src/components/appheader.vue.ts","./src/renderer/src/assets/icons/index.ts","./src/renderer/src/components/appicon.vue.ts","./src/renderer/src/constants/selectoptions.ts","./src/renderer/src/components/appselect.vue.ts","./src/renderer/src/components/apptoasthost.vue.ts","./src/renderer/src/components/navbutton.vue.ts","./src/renderer/src/components/workflowsteps.vue.ts","./src/shared/viewport.ts","./src/renderer/src/composables/usescale.ts","./src/renderer/src/layouts/appshell.vue.ts","./node_modules/vue-router/dist/router-cwonjprp.d.mts","./node_modules/vue-router/dist/vue-router.d.mts","./src/renderer/src/stores/collect.ts","./src/renderer/src/views/datacollectview.vue.ts","./src/renderer/src/constants/cardcapacity.ts","./src/renderer/src/stores/distributeform.ts","./src/renderer/src/stores/job.ts","./src/renderer/src/utils/validatejobconfig.ts","./src/renderer/src/utils/validatejobpreflight.ts","./src/shared/gen-task-id.ts","./src/shared/path-pattern.ts","./src/renderer/src/utils/buildjobconfig.ts","./src/renderer/src/utils/createdistributejob.ts","./src/renderer/src/utils/formatbytes.ts","./src/renderer/src/views/distributeconfigview.vue.ts","./src/renderer/src/views/distributefailedview.vue.ts","./src/renderer/src/utils/job-state.ts","./src/shared/card-position.ts","./src/shared/usb-copy-state.ts","./src/renderer/src/views/distributerunningview.vue.ts","./src/renderer/src/views/homeview.vue.ts","./node_modules/vue/jsx-runtime/index.d.ts","./__vls_types.d.ts","./node_modules/vite/types/hmrpayload.d.ts","./node_modules/vite/types/customevent.d.ts","./node_modules/vite/types/hot.d.ts","./node_modules/vite/types/importglob.d.ts","./node_modules/vite/types/importmeta.d.ts","./node_modules/vite/client.d.ts","./src/renderer/src/env.d.ts","./src/renderer/src/router/guards.ts","./src/renderer/src/router/index.ts","./src/renderer/src/main.ts","./node_modules/@types/ms/index.d.ts","./node_modules/@types/debug/index.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/ts5.6/globals.typedarray.d.ts","./node_modules/@types/node/ts5.6/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/dom-events.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/ts5.6/index.d.ts","./node_modules/@types/fs-extra/index.d.ts","./node_modules/@types/lodash/common/common.d.ts","./node_modules/@types/lodash/common/array.d.ts","./node_modules/@types/lodash/common/collection.d.ts","./node_modules/@types/lodash/common/date.d.ts","./node_modules/@types/lodash/common/function.d.ts","./node_modules/@types/lodash/common/lang.d.ts","./node_modules/@types/lodash/common/math.d.ts","./node_modules/@types/lodash/common/number.d.ts","./node_modules/@types/lodash/common/object.d.ts","./node_modules/@types/lodash/common/seq.d.ts","./node_modules/@types/lodash/common/string.d.ts","./node_modules/@types/lodash/common/util.d.ts","./node_modules/@types/lodash/index.d.ts","./node_modules/@types/lodash-es/add.d.ts","./node_modules/@types/lodash-es/after.d.ts","./node_modules/@types/lodash-es/ary.d.ts","./node_modules/@types/lodash-es/assign.d.ts","./node_modules/@types/lodash-es/assignin.d.ts","./node_modules/@types/lodash-es/assigninwith.d.ts","./node_modules/@types/lodash-es/assignwith.d.ts","./node_modules/@types/lodash-es/at.d.ts","./node_modules/@types/lodash-es/attempt.d.ts","./node_modules/@types/lodash-es/before.d.ts","./node_modules/@types/lodash-es/bind.d.ts","./node_modules/@types/lodash-es/bindall.d.ts","./node_modules/@types/lodash-es/bindkey.d.ts","./node_modules/@types/lodash-es/camelcase.d.ts","./node_modules/@types/lodash-es/capitalize.d.ts","./node_modules/@types/lodash-es/castarray.d.ts","./node_modules/@types/lodash-es/ceil.d.ts","./node_modules/@types/lodash-es/chain.d.ts","./node_modules/@types/lodash-es/chunk.d.ts","./node_modules/@types/lodash-es/clamp.d.ts","./node_modules/@types/lodash-es/clone.d.ts","./node_modules/@types/lodash-es/clonedeep.d.ts","./node_modules/@types/lodash-es/clonedeepwith.d.ts","./node_modules/@types/lodash-es/clonewith.d.ts","./node_modules/@types/lodash-es/compact.d.ts","./node_modules/@types/lodash-es/concat.d.ts","./node_modules/@types/lodash-es/cond.d.ts","./node_modules/@types/lodash-es/conforms.d.ts","./node_modules/@types/lodash-es/conformsto.d.ts","./node_modules/@types/lodash-es/constant.d.ts","./node_modules/@types/lodash-es/countby.d.ts","./node_modules/@types/lodash-es/create.d.ts","./node_modules/@types/lodash-es/curry.d.ts","./node_modules/@types/lodash-es/curryright.d.ts","./node_modules/@types/lodash-es/debounce.d.ts","./node_modules/@types/lodash-es/deburr.d.ts","./node_modules/@types/lodash-es/defaults.d.ts","./node_modules/@types/lodash-es/defaultsdeep.d.ts","./node_modules/@types/lodash-es/defaultto.d.ts","./node_modules/@types/lodash-es/defer.d.ts","./node_modules/@types/lodash-es/delay.d.ts","./node_modules/@types/lodash-es/difference.d.ts","./node_modules/@types/lodash-es/differenceby.d.ts","./node_modules/@types/lodash-es/differencewith.d.ts","./node_modules/@types/lodash-es/divide.d.ts","./node_modules/@types/lodash-es/drop.d.ts","./node_modules/@types/lodash-es/dropright.d.ts","./node_modules/@types/lodash-es/droprightwhile.d.ts","./node_modules/@types/lodash-es/dropwhile.d.ts","./node_modules/@types/lodash-es/each.d.ts","./node_modules/@types/lodash-es/eachright.d.ts","./node_modules/@types/lodash-es/endswith.d.ts","./node_modules/@types/lodash-es/entries.d.ts","./node_modules/@types/lodash-es/entriesin.d.ts","./node_modules/@types/lodash-es/eq.d.ts","./node_modules/@types/lodash-es/escape.d.ts","./node_modules/@types/lodash-es/escaperegexp.d.ts","./node_modules/@types/lodash-es/every.d.ts","./node_modules/@types/lodash-es/extend.d.ts","./node_modules/@types/lodash-es/extendwith.d.ts","./node_modules/@types/lodash-es/fill.d.ts","./node_modules/@types/lodash-es/filter.d.ts","./node_modules/@types/lodash-es/find.d.ts","./node_modules/@types/lodash-es/findindex.d.ts","./node_modules/@types/lodash-es/findkey.d.ts","./node_modules/@types/lodash-es/findlast.d.ts","./node_modules/@types/lodash-es/findlastindex.d.ts","./node_modules/@types/lodash-es/findlastkey.d.ts","./node_modules/@types/lodash-es/first.d.ts","./node_modules/@types/lodash-es/flatmap.d.ts","./node_modules/@types/lodash-es/flatmapdeep.d.ts","./node_modules/@types/lodash-es/flatmapdepth.d.ts","./node_modules/@types/lodash-es/flatten.d.ts","./node_modules/@types/lodash-es/flattendeep.d.ts","./node_modules/@types/lodash-es/flattendepth.d.ts","./node_modules/@types/lodash-es/flip.d.ts","./node_modules/@types/lodash-es/floor.d.ts","./node_modules/@types/lodash-es/flow.d.ts","./node_modules/@types/lodash-es/flowright.d.ts","./node_modules/@types/lodash-es/foreach.d.ts","./node_modules/@types/lodash-es/foreachright.d.ts","./node_modules/@types/lodash-es/forin.d.ts","./node_modules/@types/lodash-es/forinright.d.ts","./node_modules/@types/lodash-es/forown.d.ts","./node_modules/@types/lodash-es/forownright.d.ts","./node_modules/@types/lodash-es/frompairs.d.ts","./node_modules/@types/lodash-es/functions.d.ts","./node_modules/@types/lodash-es/functionsin.d.ts","./node_modules/@types/lodash-es/get.d.ts","./node_modules/@types/lodash-es/groupby.d.ts","./node_modules/@types/lodash-es/gt.d.ts","./node_modules/@types/lodash-es/gte.d.ts","./node_modules/@types/lodash-es/has.d.ts","./node_modules/@types/lodash-es/hasin.d.ts","./node_modules/@types/lodash-es/head.d.ts","./node_modules/@types/lodash-es/identity.d.ts","./node_modules/@types/lodash-es/includes.d.ts","./node_modules/@types/lodash-es/indexof.d.ts","./node_modules/@types/lodash-es/initial.d.ts","./node_modules/@types/lodash-es/inrange.d.ts","./node_modules/@types/lodash-es/intersection.d.ts","./node_modules/@types/lodash-es/intersectionby.d.ts","./node_modules/@types/lodash-es/intersectionwith.d.ts","./node_modules/@types/lodash-es/invert.d.ts","./node_modules/@types/lodash-es/invertby.d.ts","./node_modules/@types/lodash-es/invoke.d.ts","./node_modules/@types/lodash-es/invokemap.d.ts","./node_modules/@types/lodash-es/isarguments.d.ts","./node_modules/@types/lodash-es/isarray.d.ts","./node_modules/@types/lodash-es/isarraybuffer.d.ts","./node_modules/@types/lodash-es/isarraylike.d.ts","./node_modules/@types/lodash-es/isarraylikeobject.d.ts","./node_modules/@types/lodash-es/isboolean.d.ts","./node_modules/@types/lodash-es/isbuffer.d.ts","./node_modules/@types/lodash-es/isdate.d.ts","./node_modules/@types/lodash-es/iselement.d.ts","./node_modules/@types/lodash-es/isempty.d.ts","./node_modules/@types/lodash-es/isequal.d.ts","./node_modules/@types/lodash-es/isequalwith.d.ts","./node_modules/@types/lodash-es/iserror.d.ts","./node_modules/@types/lodash-es/isfinite.d.ts","./node_modules/@types/lodash-es/isfunction.d.ts","./node_modules/@types/lodash-es/isinteger.d.ts","./node_modules/@types/lodash-es/islength.d.ts","./node_modules/@types/lodash-es/ismap.d.ts","./node_modules/@types/lodash-es/ismatch.d.ts","./node_modules/@types/lodash-es/ismatchwith.d.ts","./node_modules/@types/lodash-es/isnan.d.ts","./node_modules/@types/lodash-es/isnative.d.ts","./node_modules/@types/lodash-es/isnil.d.ts","./node_modules/@types/lodash-es/isnull.d.ts","./node_modules/@types/lodash-es/isnumber.d.ts","./node_modules/@types/lodash-es/isobject.d.ts","./node_modules/@types/lodash-es/isobjectlike.d.ts","./node_modules/@types/lodash-es/isplainobject.d.ts","./node_modules/@types/lodash-es/isregexp.d.ts","./node_modules/@types/lodash-es/issafeinteger.d.ts","./node_modules/@types/lodash-es/isset.d.ts","./node_modules/@types/lodash-es/isstring.d.ts","./node_modules/@types/lodash-es/issymbol.d.ts","./node_modules/@types/lodash-es/istypedarray.d.ts","./node_modules/@types/lodash-es/isundefined.d.ts","./node_modules/@types/lodash-es/isweakmap.d.ts","./node_modules/@types/lodash-es/isweakset.d.ts","./node_modules/@types/lodash-es/iteratee.d.ts","./node_modules/@types/lodash-es/join.d.ts","./node_modules/@types/lodash-es/kebabcase.d.ts","./node_modules/@types/lodash-es/keyby.d.ts","./node_modules/@types/lodash-es/keys.d.ts","./node_modules/@types/lodash-es/keysin.d.ts","./node_modules/@types/lodash-es/last.d.ts","./node_modules/@types/lodash-es/lastindexof.d.ts","./node_modules/@types/lodash-es/lowercase.d.ts","./node_modules/@types/lodash-es/lowerfirst.d.ts","./node_modules/@types/lodash-es/lt.d.ts","./node_modules/@types/lodash-es/lte.d.ts","./node_modules/@types/lodash-es/map.d.ts","./node_modules/@types/lodash-es/mapkeys.d.ts","./node_modules/@types/lodash-es/mapvalues.d.ts","./node_modules/@types/lodash-es/matches.d.ts","./node_modules/@types/lodash-es/matchesproperty.d.ts","./node_modules/@types/lodash-es/max.d.ts","./node_modules/@types/lodash-es/maxby.d.ts","./node_modules/@types/lodash-es/mean.d.ts","./node_modules/@types/lodash-es/meanby.d.ts","./node_modules/@types/lodash-es/memoize.d.ts","./node_modules/@types/lodash-es/merge.d.ts","./node_modules/@types/lodash-es/mergewith.d.ts","./node_modules/@types/lodash-es/method.d.ts","./node_modules/@types/lodash-es/methodof.d.ts","./node_modules/@types/lodash-es/min.d.ts","./node_modules/@types/lodash-es/minby.d.ts","./node_modules/@types/lodash-es/mixin.d.ts","./node_modules/@types/lodash-es/multiply.d.ts","./node_modules/@types/lodash-es/negate.d.ts","./node_modules/@types/lodash-es/noop.d.ts","./node_modules/@types/lodash-es/now.d.ts","./node_modules/@types/lodash-es/nth.d.ts","./node_modules/@types/lodash-es/ntharg.d.ts","./node_modules/@types/lodash-es/omit.d.ts","./node_modules/@types/lodash-es/omitby.d.ts","./node_modules/@types/lodash-es/once.d.ts","./node_modules/@types/lodash-es/orderby.d.ts","./node_modules/@types/lodash-es/over.d.ts","./node_modules/@types/lodash-es/overargs.d.ts","./node_modules/@types/lodash-es/overevery.d.ts","./node_modules/@types/lodash-es/oversome.d.ts","./node_modules/@types/lodash-es/pad.d.ts","./node_modules/@types/lodash-es/padend.d.ts","./node_modules/@types/lodash-es/padstart.d.ts","./node_modules/@types/lodash-es/parseint.d.ts","./node_modules/@types/lodash-es/partial.d.ts","./node_modules/@types/lodash-es/partialright.d.ts","./node_modules/@types/lodash-es/partition.d.ts","./node_modules/@types/lodash-es/pick.d.ts","./node_modules/@types/lodash-es/pickby.d.ts","./node_modules/@types/lodash-es/property.d.ts","./node_modules/@types/lodash-es/propertyof.d.ts","./node_modules/@types/lodash-es/pull.d.ts","./node_modules/@types/lodash-es/pullall.d.ts","./node_modules/@types/lodash-es/pullallby.d.ts","./node_modules/@types/lodash-es/pullallwith.d.ts","./node_modules/@types/lodash-es/pullat.d.ts","./node_modules/@types/lodash-es/random.d.ts","./node_modules/@types/lodash-es/range.d.ts","./node_modules/@types/lodash-es/rangeright.d.ts","./node_modules/@types/lodash-es/rearg.d.ts","./node_modules/@types/lodash-es/reduce.d.ts","./node_modules/@types/lodash-es/reduceright.d.ts","./node_modules/@types/lodash-es/reject.d.ts","./node_modules/@types/lodash-es/remove.d.ts","./node_modules/@types/lodash-es/repeat.d.ts","./node_modules/@types/lodash-es/replace.d.ts","./node_modules/@types/lodash-es/rest.d.ts","./node_modules/@types/lodash-es/result.d.ts","./node_modules/@types/lodash-es/reverse.d.ts","./node_modules/@types/lodash-es/round.d.ts","./node_modules/@types/lodash-es/sample.d.ts","./node_modules/@types/lodash-es/samplesize.d.ts","./node_modules/@types/lodash-es/set.d.ts","./node_modules/@types/lodash-es/setwith.d.ts","./node_modules/@types/lodash-es/shuffle.d.ts","./node_modules/@types/lodash-es/size.d.ts","./node_modules/@types/lodash-es/slice.d.ts","./node_modules/@types/lodash-es/snakecase.d.ts","./node_modules/@types/lodash-es/some.d.ts","./node_modules/@types/lodash-es/sortby.d.ts","./node_modules/@types/lodash-es/sortedindex.d.ts","./node_modules/@types/lodash-es/sortedindexby.d.ts","./node_modules/@types/lodash-es/sortedindexof.d.ts","./node_modules/@types/lodash-es/sortedlastindex.d.ts","./node_modules/@types/lodash-es/sortedlastindexby.d.ts","./node_modules/@types/lodash-es/sortedlastindexof.d.ts","./node_modules/@types/lodash-es/sorteduniq.d.ts","./node_modules/@types/lodash-es/sorteduniqby.d.ts","./node_modules/@types/lodash-es/split.d.ts","./node_modules/@types/lodash-es/spread.d.ts","./node_modules/@types/lodash-es/startcase.d.ts","./node_modules/@types/lodash-es/startswith.d.ts","./node_modules/@types/lodash-es/stubarray.d.ts","./node_modules/@types/lodash-es/stubfalse.d.ts","./node_modules/@types/lodash-es/stubobject.d.ts","./node_modules/@types/lodash-es/stubstring.d.ts","./node_modules/@types/lodash-es/stubtrue.d.ts","./node_modules/@types/lodash-es/subtract.d.ts","./node_modules/@types/lodash-es/sum.d.ts","./node_modules/@types/lodash-es/sumby.d.ts","./node_modules/@types/lodash-es/tail.d.ts","./node_modules/@types/lodash-es/take.d.ts","./node_modules/@types/lodash-es/takeright.d.ts","./node_modules/@types/lodash-es/takerightwhile.d.ts","./node_modules/@types/lodash-es/takewhile.d.ts","./node_modules/@types/lodash-es/tap.d.ts","./node_modules/@types/lodash-es/template.d.ts","./node_modules/@types/lodash-es/templatesettings.d.ts","./node_modules/@types/lodash-es/throttle.d.ts","./node_modules/@types/lodash-es/thru.d.ts","./node_modules/@types/lodash-es/times.d.ts","./node_modules/@types/lodash-es/toarray.d.ts","./node_modules/@types/lodash-es/tofinite.d.ts","./node_modules/@types/lodash-es/tointeger.d.ts","./node_modules/@types/lodash-es/tolength.d.ts","./node_modules/@types/lodash-es/tolower.d.ts","./node_modules/@types/lodash-es/tonumber.d.ts","./node_modules/@types/lodash-es/topairs.d.ts","./node_modules/@types/lodash-es/topairsin.d.ts","./node_modules/@types/lodash-es/topath.d.ts","./node_modules/@types/lodash-es/toplainobject.d.ts","./node_modules/@types/lodash-es/tosafeinteger.d.ts","./node_modules/@types/lodash-es/tostring.d.ts","./node_modules/@types/lodash-es/toupper.d.ts","./node_modules/@types/lodash-es/transform.d.ts","./node_modules/@types/lodash-es/trim.d.ts","./node_modules/@types/lodash-es/trimend.d.ts","./node_modules/@types/lodash-es/trimstart.d.ts","./node_modules/@types/lodash-es/truncate.d.ts","./node_modules/@types/lodash-es/unary.d.ts","./node_modules/@types/lodash-es/unescape.d.ts","./node_modules/@types/lodash-es/union.d.ts","./node_modules/@types/lodash-es/unionby.d.ts","./node_modules/@types/lodash-es/unionwith.d.ts","./node_modules/@types/lodash-es/uniq.d.ts","./node_modules/@types/lodash-es/uniqby.d.ts","./node_modules/@types/lodash-es/uniqueid.d.ts","./node_modules/@types/lodash-es/uniqwith.d.ts","./node_modules/@types/lodash-es/unset.d.ts","./node_modules/@types/lodash-es/unzip.d.ts","./node_modules/@types/lodash-es/unzipwith.d.ts","./node_modules/@types/lodash-es/update.d.ts","./node_modules/@types/lodash-es/updatewith.d.ts","./node_modules/@types/lodash-es/uppercase.d.ts","./node_modules/@types/lodash-es/upperfirst.d.ts","./node_modules/@types/lodash-es/values.d.ts","./node_modules/@types/lodash-es/valuesin.d.ts","./node_modules/@types/lodash-es/without.d.ts","./node_modules/@types/lodash-es/words.d.ts","./node_modules/@types/lodash-es/wrap.d.ts","./node_modules/@types/lodash-es/xor.d.ts","./node_modules/@types/lodash-es/xorby.d.ts","./node_modules/@types/lodash-es/xorwith.d.ts","./node_modules/@types/lodash-es/zip.d.ts","./node_modules/@types/lodash-es/zipobject.d.ts","./node_modules/@types/lodash-es/zipobjectdeep.d.ts","./node_modules/@types/lodash-es/zipwith.d.ts","./node_modules/@types/lodash-es/index.d.ts","./node_modules/@types/web-bluetooth/index.d.ts","./node_modules/@types/yauzl/index.d.ts"],"fileInfos":[{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0",{"version":"0","affectsGlobalScope":true},"0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0",{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0","0","0","0",{"version":"0","affectsGlobalScope":true},{"version":"0","affectsGlobalScope":true},"0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0",{"version":"0","affectsGlobalScope":true},"0"],"root":[[77,99],[102,120],122,[129,132]],"options":{"composite":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":true},"fileIdsList":[[71,73,74,76,101,121,139,144],[66,139,144],[139,144],[133,139,144],[139,144,157,191],[139,144,205],[139,144,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509],[139,144,193,195,196,197,198,199,200,201,202,203,204,205],[139,144,193,194,196,197,198,199,200,201,202,203,204,205],[139,144,194,195,196,197,198,199,200,201,202,203,204,205],[139,144,193,194,195,197,198,199,200,201,202,203,204,205],[139,144,193,194,195,196,198,199,200,201,202,203,204,205],[139,144,193,194,195,196,197,199,200,201,202,203,204,205],[139,144,193,194,195,196,197,198,200,201,202,203,204,205],[139,144,193,194,195,196,197,198,199,201,202,203,204,205],[139,144,193,194,195,196,197,198,199,200,202,203,204,205],[139,144,193,194,195,196,197,198,199,200,201,203,204,205],[139,144,193,194,195,196,197,198,199,200,201,202,204,205],[139,144,193,194,195,196,197,198,199,200,201,202,203,205],[139,144,193,194,195,196,197,198,199,200,201,202,203,204],[139,141,144],[139,143,144],[139,144,149,176],[139,144,145,156,157,164,173,184],[139,144,145,146,156,164],[135,136,139,144],[139,144,147,185],[139,144,148,149,157,165],[139,144,149,173,181],[139,144,150,152,156,164],[139,144,151],[139,144,152,153],[139,144,156],[139,144,155,156],[139,143,144,156],[139,144,156,157,158,173,184],[139,144,156,157,158,173],[139,144,156,159,164,173,184],[139,144,156,157,159,160,164,173,181,184],[139,144,159,161,173,181,184],[139,144,156,162],[139,144,163,184,189],[139,144,152,156,164,173],[139,144,165],[139,144,166],[139,143,144,167],[139,144,168,183,189],[139,144,169],[139,144,170],[139,144,156,171],[139,144,171,172,185,187],[139,144,156,173,174,175],[139,144,173,175],[139,144,173,174],[139,144,176],[139,144,177],[139,144,156,179,180],[139,144,179,180],[139,144,149,164,173,181],[139,144,182],[144],[137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190],[139,144,164,183],[139,144,159,170,184],[139,144,149,185],[139,144,173,186],[139,144,187],[139,144,188],[139,144,149,156,158,167,173,184,187,189],[139,144,173,190],[139,144,156,173,191],[65,66,67,139,144],[68,139,144],[65,139,144],[65,70,71,73,139,144],[70,71,72,73,139,144],[74,75,101,139,144],[127,139,144],[123,139,144],[124,139,144],[125,126,139,144],[74,76,101,139,144],[74,76,100,101,139,144],[69,73,139,144],[73,139,144],[79,80,81,139,144],[74,76,86,101,139,144],[74,76,83,101,139,144],[74,76,90,101,139,144],[74,76,92,101,139,144],[74,76,77,90,91,101,139,144],[74,76,90,91,101,139,144],[74,76,78,82,83,84,85,101,139,144],[77,139,144],[81,82,83,139,144],[74,76,97,101,139,144],[80,128,139,144],[74,76,94,98,101,139,144],[74,76,82,87,101,128,131,139,144],[85,101,106,139,144],[101,103,114,115,119,120,130,139,144],[76,139,144],[76,81,139,144],[105,107,110,139,144],[82,105,107,109,111,139,144],[105,139,144],[82,105,107,139,144],[74,76,78,82,85,88,89,91,95,99,101,102,139,144],[74,76,78,82,85,88,89,91,92,93,95,99,101,104,105,106,108,112,113,139,144],[74,76,82,85,88,89,91,95,96,99,101,105,106,139,144],[74,76,78,80,82,85,88,89,91,95,96,99,101,102,105,106,108,112,116,117,118,139,144],[74,76,78,82,83,84,85,88,89,91,99,101,139,144],[66,163,168],[163,168],[71,73,74,76,101,121,151,156],[163,168,192,207,213],[163,168,206],[163,168,188,207],[163,168,183,194,208],[163,168,173,209],[163,168,197,210],[163,168,211],[163,168,212],[163,168,173,180,182,191,197,208,211,213],[163,168,197,214],[161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214],[163,168,181,215],[163,168,218,219,220,221,222,223,224,225,226,227,228,229],[163,168,217,219,220,221,222,223,224,225,226,227,228,229],[163,168,217,218,220,221,222,223,224,225,226,227,228,229],[163,168,217,218,219,221,222,223,224,225,226,227,228,229],[163,168,217,218,219,220,222,223,224,225,226,227,228,229],[163,168,217,218,219,220,221,223,224,225,226,227,228,229],[163,168,217,218,219,220,221,222,224,225,226,227,228,229],[163,168,217,218,219,220,221,222,223,225,226,227,228,229],[163,168,217,218,219,220,221,222,223,224,226,227,228,229],[163,168,217,218,219,220,221,222,223,224,225,227,228,229],[163,168,217,218,219,220,221,222,223,224,225,226,228,229],[163,168,217,218,219,220,221,222,223,224,225,226,227,229],[163,168,217,218,219,220,221,222,223,224,225,226,227,228],[163,168,229],[163,168,194],[163,168,180,195],[163,168,193],[163,168,195,196,209,211],[163,168,180,197,198,199],[163,168,197,198],[163,168,197,199],[163,168,200],[163,168,201],[163,168,180,203,204],[163,168,203,204],[163,168,173,188,197,205],[71,73,74,76,101,121,150,155],[71,73,74,76,101,121,159,164],[71,73,74,76,101,121,160,165],[71,73,74,76,101,121,161,166],[71,73,74,76,101,121,162,167],[71,73,74,76,101,121,163,168],[71,73,74,76,101,121,155,160],[71,73,74,76,101,121,152,157],[71,73,74,76,101,121,154,159],[146,163,168],[147,163,168],[148,150,163,168],[151,163,168],[80,152,163,168],[85,101,106,163,168],[101,154,163,168],[74,76,82,101,152,155,163,168],[157,163,168],[71,73,74,76,101,121,158,163],[159,160,163,168],[168],[163,165,168],[163,167,168],[163,168,173,200],[163,168,169,180,181,188,197,208],[163,168,169,170,180,188],[163,168,171,209],[163,168,172,173,181,189],[163,168,173,197,205],[163,168,175],[163,168,174,176,180,188],[163,168,176,177],[163,168,180],[163,168,179,180],[163,167,168,180],[163,168,180,181,182,197,208],[163,168,180,181,182,197],[71,73,74,76,101,121,157,162],[71,73,74,76,101,121,156,161],[163,167,168,191],[163,168,180,183,188,197,208],[163,168,180,181,183,184,188,197,205,208],[163,168,183,185,197,205,208],[163,168,180,186],[163,168,187,208,213],[163,168,176,180,188,197],[163,168,189],[163,168,190],[65,66,67,163,168],[68,163,168],[65,163,168],[65,70,71,73,163,168],[70,71,72,73,163,168],[74,75,101,163,168],[71,73,74,76,101,121,145,150],[71,73,74,76,101,121,141,146],[71,73,74,76,101,121,140,145],[71,73,74,76,101,121,142,147],[71,73,74,76,101,121,143,148],[71,73,74,76,101,121,144,149],[74,76,101,163,168],[74,76,100,101,163,168],[69,73,163,168],[73,163,168],[79,80,81,163,168],[74,76,78,81,82,83,85,101,163,168],[77,163,168],[81,82,83,148,153],[74,76,97,101,163,168],[71,73,74,76,101,121,146,151],[71,73,74,76,101,121,149,154],[71,73,74,76,101,121,147,152],[71,73,74,76,101,121,148,153],[76,163,168],[76,81,163,168],[105,149,163,168],[82,105,111,151,156],[105,163,168],[82,105,107,143,148],[151,156],[142,147],[71,73,74,76,101,121,153,158],[152,157]],"referencedMap":[[122,1],[67,2],[66,3],[134,4],[192,5],[206,6],[207,6],[208,6],[209,6],[210,6],[211,6],[212,6],[213,6],[214,6],[215,6],[216,6],[217,6],[218,6],[219,6],[220,6],[221,6],[222,6],[223,6],[224,6],[225,6],[226,6],[227,6],[228,6],[229,6],[230,6],[231,6],[232,6],[233,6],[234,6],[235,6],[236,6],[237,6],[238,6],[239,6],[240,6],[241,6],[242,6],[243,6],[244,6],[245,6],[246,6],[247,6],[248,6],[249,6],[250,6],[251,6],[252,6],[253,6],[254,6],[255,6],[256,6],[257,6],[258,6],[259,6],[260,6],[261,6],[262,6],[263,6],[264,6],[265,6],[266,6],[267,6],[268,6],[269,6],[270,6],[271,6],[272,6],[273,6],[274,6],[275,6],[276,6],[277,6],[278,6],[279,6],[280,6],[281,6],[282,6],[283,6],[284,6],[285,6],[286,6],[287,6],[288,6],[289,6],[290,6],[291,6],[292,6],[293,6],[294,6],[295,6],[296,6],[297,6],[298,6],[299,6],[300,6],[301,6],[302,6],[510,7],[303,6],[304,6],[305,6],[306,6],[307,6],[308,6],[309,6],[310,6],[311,6],[312,6],[313,6],[314,6],[315,6],[316,6],[317,6],[318,6],[319,6],[320,6],[321,6],[322,6],[323,6],[324,6],[325,6],[326,6],[327,6],[328,6],[329,6],[330,6],[331,6],[332,6],[333,6],[334,6],[335,6],[336,6],[337,6],[338,6],[339,6],[340,6],[341,6],[342,6],[343,6],[344,6],[345,6],[346,6],[347,6],[348,6],[349,6],[350,6],[351,6],[352,6],[353,6],[354,6],[355,6],[356,6],[357,6],[358,6],[359,6],[360,6],[361,6],[362,6],[363,6],[364,6],[365,6],[366,6],[367,6],[368,6],[369,6],[370,6],[371,6],[372,6],[373,6],[374,6],[375,6],[376,6],[377,6],[378,6],[379,6],[380,6],[381,6],[382,6],[383,6],[384,6],[385,6],[386,6],[387,6],[388,6],[389,6],[390,6],[391,6],[392,6],[393,6],[394,6],[395,6],[396,6],[397,6],[398,6],[399,6],[400,6],[401,6],[402,6],[403,6],[404,6],[405,6],[406,6],[407,6],[408,6],[409,6],[410,6],[411,6],[412,6],[413,6],[414,6],[415,6],[416,6],[417,6],[418,6],[419,6],[420,6],[421,6],[422,6],[423,6],[424,6],[425,6],[426,6],[427,6],[428,6],[429,6],[430,6],[431,6],[432,6],[433,6],[434,6],[435,6],[436,6],[437,6],[438,6],[439,6],[440,6],[441,6],[442,6],[443,6],[444,6],[445,6],[446,6],[447,6],[448,6],[449,6],[450,6],[451,6],[452,6],[453,6],[454,6],[455,6],[456,6],[457,6],[458,6],[459,6],[460,6],[461,6],[462,6],[463,6],[464,6],[465,6],[466,6],[467,6],[468,6],[469,6],[470,6],[471,6],[472,6],[473,6],[474,6],[475,6],[476,6],[477,6],[478,6],[479,6],[480,6],[481,6],[482,6],[483,6],[484,6],[485,6],[486,6],[487,6],[488,6],[489,6],[490,6],[491,6],[492,6],[493,6],[494,6],[495,6],[496,6],[497,6],[498,6],[499,6],[500,6],[501,6],[502,6],[503,6],[504,6],[505,6],[506,6],[507,6],[508,6],[509,6],[194,8],[195,9],[193,10],[196,11],[197,12],[198,13],[199,14],[200,15],[201,16],[202,17],[203,18],[204,19],[205,20],[133,3],[141,21],[142,21],[143,22],[144,23],[145,24],[146,25],[137,26],[135,3],[136,3],[147,27],[148,28],[149,29],[150,30],[151,31],[152,32],[153,32],[154,33],[155,34],[156,35],[157,36],[158,37],[140,3],[159,38],[160,39],[161,40],[162,41],[163,42],[164,43],[165,44],[166,45],[167,46],[168,47],[169,48],[170,49],[171,50],[172,51],[173,52],[175,53],[174,54],[176,55],[177,56],[178,3],[179,57],[180,58],[181,59],[182,60],[139,61],[138,3],[191,62],[183,63],[184,64],[185,65],[186,66],[187,67],[188,68],[189,69],[190,70],[511,3],[512,71],[68,72],[69,73],[70,74],[71,75],[73,76],[65,3],[72,3],[76,77],[63,3],[64,3],[12,3],[14,3],[13,3],[2,3],[15,3],[16,3],[17,3],[18,3],[19,3],[20,3],[21,3],[22,3],[3,3],[4,3],[23,3],[27,3],[24,3],[25,3],[26,3],[28,3],[29,3],[30,3],[5,3],[31,3],[32,3],[33,3],[34,3],[6,3],[38,3],[35,3],[36,3],[37,3],[39,3],[7,3],[40,3],[45,3],[46,3],[41,3],[42,3],[43,3],[44,3],[8,3],[50,3],[47,3],[48,3],[49,3],[51,3],[9,3],[52,3],[53,3],[54,3],[57,3],[55,3],[56,3],[58,3],[59,3],[10,3],[1,3],[11,3],[62,3],[61,3],[60,3],[128,78],[124,79],[123,3],[125,80],[126,3],[127,81],[75,82],[100,82],[101,83],[74,84],[121,85],[82,86],[87,87],[90,3],[88,82],[89,88],[91,89],[93,90],[94,91],[95,92],[96,82],[86,93],[78,94],[84,95],[98,96],[104,3],[92,3],[129,97],[99,98],[132,99],[130,100],[131,101],[85,102],[102,102],[83,103],[105,102],[106,102],[77,102],[80,3],[81,3],[111,104],[112,105],[113,3],[116,3],[107,106],[108,107],[103,108],[114,109],[115,110],[119,111],[120,112],[117,3],[109,3],[110,3],[79,3],[118,3],[97,3]],"exportedModulesMap":[[122,1],[67,113],[66,114],[134,115],[192,116],[206,117],[207,118],[208,119],[209,120],[210,121],[211,122],[212,123],[213,124],[214,125],[215,126],[216,127],[217,128],[218,129],[219,130],[220,131],[221,132],[222,133],[223,134],[224,135],[225,136],[226,137],[227,138],[228,139],[229,140],[230,141],[231,141],[232,141],[233,141],[234,141],[235,141],[236,141],[237,141],[238,141],[239,141],[240,141],[241,141],[242,141],[243,141],[244,141],[245,141],[246,141],[247,141],[248,141],[249,141],[250,141],[251,141],[252,141],[253,141],[254,141],[255,141],[256,141],[257,141],[258,141],[259,141],[260,141],[261,141],[262,141],[263,141],[264,141],[265,141],[266,141],[267,141],[268,141],[269,141],[270,141],[271,141],[272,141],[273,141],[274,141],[275,141],[276,141],[277,141],[278,141],[279,141],[280,141],[281,141],[282,141],[283,141],[284,141],[285,141],[286,141],[287,141],[288,141],[289,141],[290,141],[291,141],[292,141],[293,141],[294,141],[295,141],[296,141],[297,141],[298,141],[299,141],[300,141],[301,141],[302,141],[510,141],[303,141],[304,141],[305,141],[306,141],[307,141],[308,141],[309,141],[310,141],[311,141],[312,141],[313,141],[314,141],[315,141],[316,141],[317,141],[318,141],[319,141],[320,141],[321,141],[322,141],[323,141],[324,141],[325,141],[326,141],[327,141],[328,141],[329,141],[330,141],[331,141],[332,141],[333,141],[334,141],[335,141],[336,141],[337,141],[338,141],[339,141],[340,141],[341,141],[342,141],[343,141],[344,141],[345,141],[346,141],[347,141],[348,141],[349,141],[350,141],[351,141],[352,141],[353,141],[354,141],[355,141],[356,141],[357,141],[358,141],[359,141],[360,141],[361,141],[362,141],[363,141],[364,141],[365,141],[366,141],[367,141],[368,141],[369,141],[370,141],[371,141],[372,141],[373,141],[374,141],[375,141],[376,141],[377,141],[378,141],[379,141],[380,141],[381,141],[382,141],[383,141],[384,141],[385,141],[386,141],[387,141],[388,141],[389,141],[390,141],[391,141],[392,141],[393,141],[394,141],[395,141],[396,141],[397,141],[398,141],[399,141],[400,141],[401,141],[402,141],[403,141],[404,141],[405,141],[406,141],[407,141],[408,141],[409,141],[410,141],[411,141],[412,141],[413,141],[414,141],[415,141],[416,141],[417,141],[418,141],[419,141],[420,141],[421,141],[422,141],[423,141],[424,141],[425,141],[426,141],[427,141],[428,141],[429,141],[430,141],[431,141],[432,141],[433,141],[434,141],[435,141],[436,141],[437,141],[438,141],[439,141],[440,141],[441,141],[442,141],[443,141],[444,141],[445,141],[446,141],[447,141],[448,141],[449,141],[450,141],[451,141],[452,141],[453,141],[454,141],[455,141],[456,141],[457,141],[458,141],[459,141],[460,141],[461,141],[462,141],[463,141],[464,141],[465,141],[466,141],[467,141],[468,141],[469,141],[470,141],[471,141],[472,141],[473,141],[474,141],[475,141],[476,141],[477,141],[478,141],[479,141],[480,141],[481,141],[482,141],[483,141],[484,141],[485,141],[486,141],[487,141],[488,141],[489,141],[490,141],[491,141],[492,141],[493,141],[494,141],[495,141],[496,141],[497,141],[498,141],[499,141],[500,141],[501,141],[502,141],[503,141],[504,141],[505,141],[506,141],[507,141],[508,141],[509,141],[194,142],[195,143],[193,144],[196,145],[197,146],[198,147],[199,148],[200,149],[201,150],[202,114],[203,151],[204,152],[205,153],[133,154],[141,155],[142,156],[143,157],[144,158],[145,159],[146,114],[137,160],[135,161],[136,162],[147,163],[148,164],[149,114],[150,114],[151,165],[152,166],[153,167],[154,168],[155,169],[156,170],[157,114],[158,171],[140,172],[159,114],[160,114],[161,173],[162,114],[163,174],[164,114],[165,175],[166,175],[167,176],[168,177],[169,178],[170,179],[171,180],[172,181],[173,182],[175,183],[174,184],[176,185],[177,185],[178,186],[179,187],[180,188],[181,189],[182,190],[139,191],[138,192],[191,193],[183,194],[184,195],[185,196],[186,197],[187,198],[188,199],[189,200],[190,201],[511,141],[512,141],[68,202],[69,203],[70,204],[71,205],[73,206],[65,114],[72,114],[76,207],[63,114],[64,114],[12,114],[14,114],[13,114],[2,114],[15,114],[16,114],[17,114],[18,114],[19,114],[20,114],[21,114],[22,114],[3,114],[4,114],[23,114],[27,114],[24,114],[25,114],[26,114],[28,114],[29,114],[30,114],[5,114],[31,114],[32,114],[33,114],[34,114],[6,114],[38,114],[35,114],[36,114],[37,114],[39,114],[7,114],[40,114],[45,114],[46,114],[41,114],[42,114],[43,114],[44,114],[8,114],[50,114],[47,114],[48,114],[49,114],[51,114],[9,114],[52,114],[53,114],[54,114],[57,114],[55,114],[56,114],[58,114],[59,114],[10,114],[1,114],[11,114],[62,114],[61,114],[60,114],[128,208],[124,209],[123,210],[125,211],[126,212],[127,213],[75,214],[100,214],[101,215],[74,216],[121,217],[82,218],[87,87],[90,114],[88,82],[89,88],[91,89],[93,90],[94,91],[95,92],[96,82],[86,219],[78,220],[84,221],[98,222],[104,114],[92,114],[129,223],[99,98],[132,224],[130,225],[131,226],[85,227],[102,227],[83,228],[105,227],[106,227],[77,227],[80,114],[81,114],[111,229],[112,230],[113,114],[116,114],[107,231],[108,232],[103,108],[114,109],[115,110],[119,111],[120,112],[117,233],[109,234],[110,235],[79,114],[118,236],[97,114]],"semanticDiagnosticsPerFile":[122,67,66,134,192,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,510,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,194,195,193,196,197,198,199,200,201,202,203,204,205,133,141,142,143,144,145,146,137,135,136,147,148,149,150,151,152,153,154,155,156,157,158,140,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,175,174,176,177,178,179,180,181,182,139,138,191,183,184,185,186,187,188,189,190,511,512,68,69,70,71,73,65,72,76,63,64,12,14,13,2,15,16,17,18,19,20,21,22,3,4,23,27,24,25,26,28,29,30,5,31,32,33,34,6,38,35,36,37,39,7,40,45,46,41,42,43,44,8,50,47,48,49,51,9,52,53,54,57,55,56,58,59,10,1,11,62,61,60,128,124,123,125,126,127,75,100,101,74,121,82,87,90,88,89,91,93,94,95,96,86,78,84,98,104,92,129,99,132,130,131,85,102,83,105,106,77,80,81,111,112,113,116,107,108,103,114,115,119,120,117,109,110,79,118,97],"affectedFilesPendingEmit":[82,87,90,88,89,91,93,94,95,96,86,78,84,98,104,92,99,132,130,131,85,102,83,105,106,77,80,81,111,112,113,116,107,108,103,114,115,119,120,117,109,110,79,118,97],"emitSignatures":[77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,102,103,104,105,106,107,108,109,111,112,113,114,115,116,117,118,119,120]},"version":"5.3.3"} \ No newline at end of file