From 53a044f19e7a078187a503d28fed549f13224794 Mon Sep 17 00:00:00 2001 From: yinsx Date: Thu, 15 Jan 2026 11:03:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .stats.json | 2 +- lib/plugins/image/index.js | 126 +++++++++++++++++++------------------ lib/utils/stepui.js | 7 ++- 3 files changed, 71 insertions(+), 64 deletions(-) diff --git a/.stats.json b/.stats.json index adb20f3..a0db394 100644 --- a/.stats.json +++ b/.stats.json @@ -4,7 +4,7 @@ "glb2": 3 }, "image_operation": { - "compress": 8, + "compress": 9, "resize": 1 } } \ No newline at end of file diff --git a/lib/plugins/image/index.js b/lib/plugins/image/index.js index 32d014a..bf8b285 100644 --- a/lib/plugins/image/index.js +++ b/lib/plugins/image/index.js @@ -15,75 +15,77 @@ const OPERATIONS = [ const run = async () => { try { - while (true) { - // 强制清理并重新初始化键盘 - stopKeypress(); - await new Promise(resolve => setTimeout(resolve, 100)); + // 强制清理并重新初始化键盘 + stopKeypress(); + await new Promise(resolve => setTimeout(resolve, 100)); - const steps = getSteps(); - const ui = createStepUI({ title, getSteps: () => steps }); - const result = await ui.runInteractive(); - - if (!result) { - stopKeypress(); - return "back"; + const steps = getSteps(); + const ui = createStepUI({ + title, + getSteps: () => steps, + validate: (results) => { + // 验证是否有文件选择且至少有一个操作未跳过 + const files = results[0] || []; + const hasOperation = OPERATIONS.some(op => results[op.stepIndex] !== "skip"); + return files.length > 0 && hasOperation; } + }); - const files = result.results[0] || []; - const selectedOp = OPERATIONS.find(op => result.results[op.stepIndex] !== "skip"); + const result = await ui.runInteractive(); - stopKeypress(); - - // 如果没有选择文件或所有操作都跳过,重新开始 - if (!selectedOp || !files.length) { - continue; - } - - // 有效的选择,继续处理 - const params = buildProcessParams(selectedOp.id, result.results[selectedOp.stepIndex]); - - ui.showSummary([ - "源文件: " + files.join(", "), - "操作: " + selectedOp.name, - getParamLabel(selectedOp.id, params) - ]); - - const total = files.length; - let success = 0; - const failed = []; - - console.log(color.cyan(`开始处理 ${total} 个文件...\\n`)); - - for (let i = 0; i < files.length; i++) { - const file = files[i]; - const progress = `[${i + 1}/${total}]`; - console.log(color.dim(`${progress} 处理中: ${file}`)); - - try { - const outputs = await processImage(file, selectedOp.id, params); - success++; - record("image_operation", selectedOp.id); - - const outputNames = Array.isArray(outputs) - ? outputs.map(o => path.relative(process.cwd(), o)).join(", ") - : path.relative(process.cwd(), outputs); - console.log(color.green(`${progress} ✓ ${file} → ${outputNames}`)); - } catch (err) { - failed.push({ file, reason: err?.message || String(err) }); - console.log(color.red(`${progress} ✖ 失败: ${file}`)); - console.log(color.dim(" " + String(err?.message || err))); - } - } - - console.log("\\n" + color.bgGreen(color.black(" 处理完成 "))); - console.log(color.green(`成功: ${success} 个`)); - if (failed.length) console.log(color.yellow(`失败: ${failed.length} 个`)); - console.log(color.cyan(`输出目录: ${selectedOp.folder}/`)); - - await waitForKey(color.dim("按 Esc 返回"), key => key?.name === "escape" || (key?.ctrl && key?.name === "c")); + if (!result) { stopKeypress(); return "back"; } + + const files = result.results[0] || []; + const selectedOp = OPERATIONS.find(op => result.results[op.stepIndex] !== "skip"); + + stopKeypress(); + + const params = buildProcessParams(selectedOp.id, result.results[selectedOp.stepIndex]); + + ui.showSummary([ + "源文件: " + files.join(", "), + "操作: " + selectedOp.name, + getParamLabel(selectedOp.id, params) + ]); + + const total = files.length; + let success = 0; + const failed = []; + + console.log(color.cyan(`开始处理 ${total} 个文件...\\n`)); + + for (let i = 0; i < files.length; i++) { + const file = files[i]; + const progress = `[${i + 1}/${total}]`; + console.log(color.dim(`${progress} 处理中: ${file}`)); + + try { + const outputs = await processImage(file, selectedOp.id, params); + success++; + record("image_operation", selectedOp.id); + + const outputNames = Array.isArray(outputs) + ? outputs.map(o => path.relative(process.cwd(), o)).join(", ") + : path.relative(process.cwd(), outputs); + console.log(color.green(`${progress} ✓ ${file} → ${outputNames}`)); + } catch (err) { + failed.push({ file, reason: err?.message || String(err) }); + console.log(color.red(`${progress} ✖ 失败: ${file}`)); + console.log(color.dim(" " + String(err?.message || err))); + } + } + + console.log("\\n" + color.bgGreen(color.black(" 处理完成 "))); + console.log(color.green(`成功: ${success} 个`)); + if (failed.length) console.log(color.yellow(`失败: ${failed.length} 个`)); + console.log(color.cyan(`输出目录: ${selectedOp.folder}/`)); + + await waitForKey(color.dim("按 Esc 返回"), key => key?.name === "escape" || (key?.ctrl && key?.name === "c")); + stopKeypress(); + return "back"; } catch (err) { stopKeypress(); console.error(color.red("发生错误:"), err); diff --git a/lib/utils/stepui.js b/lib/utils/stepui.js index c9c4267..7f5ed71 100644 --- a/lib/utils/stepui.js +++ b/lib/utils/stepui.js @@ -3,7 +3,7 @@ import { initKeypress, onKey, stopKeypress } from "../keyboard.js"; import { clearScreen } from "./terminal.js"; export function createStepUI(options) { - const { title, getSteps, onStepChange } = options; + const { title, getSteps, onStepChange, validate } = options; let steps = []; let results = []; @@ -171,6 +171,11 @@ export function createStepUI(options) { } break; case "tab": + // 如果提供了验证函数,先验证 + if (validate && !validate(results)) { + // 验证失败,忽略此次提交 + break; + } resolved = true; stopKeypress(); setImmediate(() => resolve({ steps, results }));