| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /**
- * 工作流管理模块
- * 负责工作流的保存、删除、读取等操作
- */
- import { ipcMain } from 'electron';
- import { readdir, writeFile, readFile, mkdir, rm, stat } from 'fs/promises';
- import { join, dirname } from 'path';
- import { fileURLToPath } from 'url';
- const __filename = fileURLToPath(import.meta.url);
- const __dirname = dirname(__filename);
- /**
- * 获取 static/processing 目录下的所有文件夹
- * @returns {Promise<Array<{name: string, createdAt: Date}>>}
- */
- export async function getStaticFolders() {
- try {
- const staticPath = join(__dirname, '..', 'static', 'processing');
- const entries = await readdir(staticPath, { withFileTypes: true });
-
- const folders = [];
- for (const entry of entries) {
- if (entry.isDirectory()) {
- const folderPath = join(staticPath, entry.name);
- const stats = await stat(folderPath);
- folders.push({
- name: entry.name,
- createdAt: stats.birthtime || stats.mtime, // 使用创建时间,如果没有则使用修改时间
- });
- }
- }
-
- // 按创建时间排序,最新的在前
- return folders.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
- } catch (error) {
- console.error('Failed to read static/processing folders:', error);
- return [];
- }
- }
- /**
- * 读取 processing.json 文件
- * @param {string} folderName - 工作流文件夹名称
- * @returns {Promise<Object|null>} 解析后的 JSON 对象,失败返回 null
- */
- export async function readProcessingJson(folderName) {
- try {
- const jsonPath = join(__dirname, '..', 'static', 'processing', folderName, 'processing.json');
- const jsonContent = await readFile(jsonPath, 'utf-8');
-
- // 解析 JSON(处理可能的格式问题,如注释、尾随逗号等)
- // 先尝试直接解析
- let parsed;
- try {
- parsed = JSON.parse(jsonContent);
- } catch (parseError) {
- // 如果直接解析失败,尝试清理注释和尾随逗号(简单处理)
- let cleaned = jsonContent
- .replace(/\/\/.*$/gm, '') // 移除单行注释
- .replace(/\/\*[\s\S]*?\*\//g, '') // 移除多行注释
- .replace(/,(\s*[}\]])/g, '$1'); // 移除尾随逗号(在 ] 或 } 之前的逗号)
-
- try {
- parsed = JSON.parse(cleaned);
- } catch (retryError) {
- console.error(`JSON 解析失败 [${folderName}]:`, parseError.message);
- console.error('原始内容:', jsonContent.substring(0, 500));
- throw new Error(`JSON 格式错误: ${parseError.message}`);
- }
- }
- // 处理不同的 JSON 格式
- // 如果直接是数组,包装成对象
- if (Array.isArray(parsed)) {
- return { actions: parsed };
- }
-
- // 如果已经是对象,直接返回
- if (parsed && typeof parsed === 'object') {
- // 如果已经有 actions 字段,直接返回
- if (parsed.actions) {
- return parsed;
- }
- // 如果没有 actions 字段,尝试查找数组字段
- for (const key in parsed) {
- if (Array.isArray(parsed[key])) {
- return { actions: parsed[key], ...parsed };
- }
- }
- }
- // 如果解析成功但没有 actions 字段,返回错误信息
- if (!parsed || (typeof parsed === 'object' && !parsed.actions && !Array.isArray(parsed))) {
- console.error(`processing.json 格式错误 [${folderName}]: 缺少 actions 字段`);
- return null;
- }
-
- return parsed;
- } catch (error) {
- console.error(`读取 processing.json 失败 [${folderName}]:`, error.message);
- return null;
- }
- }
- /**
- * 保存工作流到 static/processing 目录
- * @param {Object} workflowJson - 工作流 JSON 对象
- * @param {Array} imagesData - 图片数据数组(包含 base64 和 name)
- * @returns {Promise<{success: boolean, error?: string, folderName?: string, path?: string}>}
- */
- export async function saveWorkflow(workflowJson, imagesData = []) {
- try {
- // 支持新旧格式
- const hasActions = Array.isArray(workflowJson.actions) || Array.isArray(workflowJson);
- if (!workflowJson || typeof workflowJson !== 'object' || !hasActions) {
- return { success: false, error: '工作流格式错误:缺少 actions 数组' };
- }
- // 生成文件夹名称(使用时间戳)
- const now = new Date();
- const timestamp = now.getFullYear() +
- String(now.getMonth() + 1).padStart(2, '0') +
- String(now.getDate()).padStart(2, '0') + '_' +
- String(now.getHours()).padStart(2, '0') +
- String(now.getMinutes()).padStart(2, '0') +
- String(now.getSeconds()).padStart(2, '0');
- const folderName = workflowJson.name || `工作流_${timestamp}`;
- // 创建工作流文件夹
- const workflowPath = join(__dirname, '..', 'static', 'processing', folderName);
- await mkdir(workflowPath, { recursive: true });
- // 保存 processing.json
- const jsonPath = join(workflowPath, 'processing.json');
- const jsonContent = JSON.stringify(workflowJson, null, '\t');
- await writeFile(jsonPath, jsonContent, 'utf-8');
- // 保存图片
- if (imagesData && Array.isArray(imagesData) && imagesData.length > 0) {
- for (const imageData of imagesData) {
- if (imageData.base64 && imageData.name) {
- try {
- // 将base64转换为Buffer
- const imageBuffer = Buffer.from(imageData.base64, 'base64');
- const imagePath = join(workflowPath, imageData.name);
- await writeFile(imagePath, imageBuffer);
- // 图片已保存日志(不显示)
- } catch (imageError) {
- console.error(`保存图片失败 ${imageData.name}:`, imageError);
- }
- }
- }
- }
- console.log(`工作流已保存: ${folderName}`);
- return { success: true, folderName, path: workflowPath };
- } catch (error) {
- console.error('保存工作流失败:', error);
- return { success: false, error: error.message };
- }
- }
- /**
- * 删除工作流文件夹
- * @param {string} folderName - 工作流文件夹名称
- * @returns {Promise<{success: boolean, error?: string, folderName?: string}>}
- */
- export async function deleteWorkflow(folderName) {
- try {
- if (!folderName || typeof folderName !== 'string') {
- return { success: false, error: '文件夹名称无效' };
- }
- // 构建文件夹路径
- const workflowPath = join(__dirname, '..', 'static', 'processing', folderName);
- // 删除整个文件夹(包括所有内容)
- await rm(workflowPath, { recursive: true, force: true });
- console.log(`工作流已删除: ${folderName}`);
- return { success: true, folderName };
- } catch (error) {
- console.error('删除工作流失败:', error);
- return { success: false, error: error.message };
- }
- }
- /**
- * 注册工作流管理相关的 IPC handlers
- */
- export function registerIpcHandlers() {
- // 获取工作流文件夹列表
- ipcMain.handle('get-static-folders', async () => {
- return await getStaticFolders();
- });
- // 读取 processing.json 文件
- ipcMain.handle('read-processing-json', async (event, folderName) => {
- return await readProcessingJson(folderName);
- });
- // 保存工作流
- ipcMain.handle('save-workflow', async (event, workflowJson, imagesData) => {
- return await saveWorkflow(workflowJson, imagesData);
- });
- // 删除工作流
- ipcMain.handle('delete-workflow', async (event, folderName) => {
- return await deleteWorkflow(folderName);
- });
- }
|