UNPKG

bytefun

Version:

一个打通了原型设计、UI设计与代码转换、跨平台原生代码开发等的平台

1,705 lines (1,306 loc) 107 kB
import * as vscode from 'vscode'; import { SidebarProvider } from './sidebarProvider'; import { EditorProvider } from './editorProvider'; import { ProjectManager } from './projectManager'; import { execGen } from './apiMdToApiTs'; import { TemplateCodeGen } from './TemplateCodeGen'; import { FileLockManager } from './SingleInstanceManager'; import * as crypto from 'crypto'; import * as fs from 'fs'; import * as path from 'path'; import { WorkspaceUtils } from './workspaceUtils'; let fileWatchers: vscode.FileSystemWatcher[] = []; let workspaceWatcher: vscode.Disposable | undefined; let sidebarProvider: SidebarProvider | undefined; let editorProvider: EditorProvider | undefined; let lockManager: FileLockManager | undefined; // 简单的文件变化防重复处理 const fileHashes = new Map<string, string>(); const lastProcessTimes = new Map<string, number>(); // 内存中保存的UI设计进度数据,用于版本对比 let cachedUIDesignProgress: any = null; /** * 检查是否应该处理HTML文件(简单的hash对比+时间防抖) */ function shouldProcessHtmlFile(filePath: string): boolean { try { if (!fs.existsSync(filePath)) { return false; } const now = Date.now(); const content = fs.readFileSync(filePath, 'utf8'); const currentHash = crypto.createHash('md5').update(content).digest('hex'); const lastHash = fileHashes.get(filePath); const lastTime = lastProcessTimes.get(filePath) || 0; // 如果hash相同,跳过 if (lastHash === currentHash) { return false; } // 如果时间间隔太短(1秒内),跳过 if (now - lastTime < 1000) { return false; } // 更新记录 fileHashes.set(filePath, currentHash); lastProcessTimes.set(filePath, now); return true; } catch (error) { console.error('检查文件失败:', error); return true; // 出错时默认处理 } } /** * 初始化UI设计进度缓存数据 */ function initializeUIDesignProgressCache(): void { try { const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { return; } const uiDesignProgressPath = path.join(workspaceRoot, 'doc', 'UI设计进度.json'); if (fs.existsSync(uiDesignProgressPath)) { const content = fs.readFileSync(uiDesignProgressPath, 'utf8'); cachedUIDesignProgress = JSON.parse(content); } else { cachedUIDesignProgress = null; } } catch (error) { console.error('❌ [ByteFun] 初始化UI设计进度缓存失败:', error); cachedUIDesignProgress = null; } } /** * 比较UI设计进度数据,找出版本变化的页面 */ function findVersionChangedPages(oldProgress: any, newProgress: any): any[] { const changedPages: any[] = []; try { if (!oldProgress || !newProgress) { return changedPages; } const oldModules = oldProgress.modules || []; const newModules = newProgress.modules || []; // 遍历新的模块和页面 for (const newModule of newModules) { if (!newModule.pages || !Array.isArray(newModule.pages)) { continue; } for (const newPage of newModule.pages) { const pageNameEN = newPage.pageNameEN; const newVersion = newPage.version; if (!pageNameEN) { continue; } // 在旧数据中查找对应的页面 let oldVersion = null; for (const oldModule of oldModules) { if (!oldModule.pages || !Array.isArray(oldModule.pages)) { continue; } const oldPage = oldModule.pages.find((page: any) => page.pageNameEN === pageNameEN); if (oldPage) { oldVersion = oldPage.version; break; } } // 比较版本 if (oldVersion !== newVersion) { changedPages.push(newPage); } } } return changedPages; } catch (error) { console.error('❌ [ByteFun] 对比UI设计进度版本失败:', error); return changedPages; } } /** * 根据页面英文名查找对应的HTML文件路径 */ function findHtmlFilePath(pageNameEN: string): string | null { try { const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { return null; } const srcDir = path.join(workspaceRoot, 'src'); // 在src目录下递归查找对应的HTML文件 function searchHtmlFile(searchDir: string, targetName: string): string | null { try { if (!fs.existsSync(searchDir)) { return null; } const items = fs.readdirSync(searchDir, { withFileTypes: true }); for (const item of items) { if (item.isDirectory()) { // 递归搜索子目录 const subDirPath = path.join(searchDir, item.name); const result = searchHtmlFile(subDirPath, targetName); if (result) { return result; } } else if (item.isFile()) { // 检查是否是目标HTML文件 const fileName = item.name; const fileNameWithoutExt = path.basename(fileName, '.html'); if (fileName.endsWith('.html') && (fileNameWithoutExt === targetName || fileName === targetName)) { return path.join(searchDir, fileName); } } } return null; } catch (error) { console.error('❌ [ByteFun] 搜索HTML文件失败:', error); return null; } } const htmlFilePath = searchHtmlFile(srcDir, pageNameEN); if (htmlFilePath) { } else { } return htmlFilePath; } catch (error) { console.error('❌ [ByteFun] 查找HTML文件路径失败:', error); return null; } } export function activate(context: vscode.ExtensionContext) { // 增加事件监听器的最大限制,防止 MaxListenersExceededWarning try { const EventEmitter = require('events'); EventEmitter.defaultMaxListeners = 50; // 增加到50个监听器 } catch (error) { console.error('❌ [ByteFun] 设置事件监听器限制失败:', error); } // 清理之前可能存在的资源 cleanupResources(); // 初始化文件锁管理器 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (workspaceRoot) { lockManager = new FileLockManager(workspaceRoot); console.log('✅ [ByteFun] 文件锁管理器已初始化'); } // 初始化项目管理器并设置当前项目 UID const projectManager = ProjectManager.getInstance(); // 初始化UI设计进度缓存数据 initializeUIDesignProgressCache(); // 初始化当前项目的聊天会话(如果是ByteFun项目的话) initializeCurrentProjectChatSessions(); // 注册webview视图提供者 sidebarProvider = new SidebarProvider(context.extensionUri); // 延迟触发初始的工作区状态检查 setTimeout(() => { sidebarProvider?.handleWorkspaceChange(); }, 500); // 创建webview提供者 editorProvider = new EditorProvider(context); // 监听项目文件变化 const projectFileWatcher = vscode.workspace.createFileSystemWatcher('**/.bytefun/project.json'); projectFileWatcher.onDidCreate(() => { sidebarProvider?.handleWorkspaceChange(); }); projectFileWatcher.onDidDelete(() => { sidebarProvider?.handleWorkspaceChange(); }); fileWatchers.push(projectFileWatcher); // 监听UI设计进度文件变化 const uiDesignProgressWatcher = vscode.workspace.createFileSystemWatcher('**/doc/UI设计进度.json'); uiDesignProgressWatcher.onDidChange((uri) => { handleUIDesignProgressChange(uri.fsPath, editorProvider!); }); uiDesignProgressWatcher.onDidCreate((uri) => { handleUIDesignProgressChange(uri.fsPath, editorProvider!); }); fileWatchers.push(uiDesignProgressWatcher); // 监听产品设计进度文件变化 const productProgressWatcher = vscode.workspace.createFileSystemWatcher('**/doc/整体模块分析进度.json'); productProgressWatcher.onDidChange((uri) => { handleProductProgressFileChange(uri.fsPath, sidebarProvider!); }); productProgressWatcher.onDidCreate((uri) => { handleProductProgressFileChange(uri.fsPath, sidebarProvider!); }); fileWatchers.push(productProgressWatcher); // 监听数据库配置文件变化 const dbJsonWatcher = vscode.workspace.createFileSystemWatcher('**/backend/doc/db.json'); dbJsonWatcher.onDidChange((uri) => { handleDbJsonFileChange(uri.fsPath); }); dbJsonWatcher.onDidCreate((uri) => { handleDbJsonFileChange(uri.fsPath); }); fileWatchers.push(dbJsonWatcher); // 监听前端代码开发进度文件变化 const frontendProgressWatcher = vscode.workspace.createFileSystemWatcher('**/doc/前端代码开发进度.json'); frontendProgressWatcher.onDidChange((uri) => { handleFrontendProgressFileChange(uri.fsPath, sidebarProvider!); }); frontendProgressWatcher.onDidCreate((uri) => { handleFrontendProgressFileChange(uri.fsPath, sidebarProvider!); }); fileWatchers.push(frontendProgressWatcher); // 监听后端代码开发进度文件变化 const backendProgressWatcher = vscode.workspace.createFileSystemWatcher('**/doc/后端代码开发进度.json'); backendProgressWatcher.onDidChange((uri) => { handleBackendProgressFileChange(uri.fsPath, sidebarProvider!); }); backendProgressWatcher.onDidCreate((uri) => { handleBackendProgressFileChange(uri.fsPath, sidebarProvider!); }); fileWatchers.push(backendProgressWatcher); // 监听UI设计配置文件变化 const uiDesignConfigWatcher = vscode.workspace.createFileSystemWatcher('**/.bytefun/ui-design-config.json'); uiDesignConfigWatcher.onDidChange((uri) => { handleUIDesignConfigChange(uri.fsPath); }); uiDesignConfigWatcher.onDidCreate((uri) => { handleUIDesignConfigChange(uri.fsPath); }); fileWatchers.push(uiDesignConfigWatcher); // 监听PRD设计配置文件变化 const prdDesignConfigWatcher = vscode.workspace.createFileSystemWatcher('**/.bytefun/prd-design-config.json'); prdDesignConfigWatcher.onDidChange((uri) => { handlePrdDesignConfigChange(uri.fsPath); }); prdDesignConfigWatcher.onDidCreate((uri) => { handlePrdDesignConfigChange(uri.fsPath); }); fileWatchers.push(prdDesignConfigWatcher); // 监听业务逻辑设计文件变化 const businessLogicWatcher = vscode.workspace.createFileSystemWatcher('**/.bytefun/*-module-business-logic.json'); businessLogicWatcher.onDidChange((uri) => { handleBusinessLogicFileChange(uri.fsPath, sidebarProvider!); }); businessLogicWatcher.onDidCreate((uri) => { handleBusinessLogicFileChange(uri.fsPath, sidebarProvider!); }); fileWatchers.push(businessLogicWatcher); // 监听后端设计配置文件变化 const backendDesignConfigWatcher = vscode.workspace.createFileSystemWatcher('**/.bytefun/backend-design-config.json'); backendDesignConfigWatcher.onDidChange((uri) => { handleBackendDesignConfigChange(uri.fsPath, sidebarProvider!); }); backendDesignConfigWatcher.onDidCreate((uri) => { handleBackendDesignConfigChange(uri.fsPath, sidebarProvider!); }); fileWatchers.push(backendDesignConfigWatcher); // 将两个provider设置为全局可访问,以便处理消息通信 (global as any).bytefunSidebarProvider = sidebarProvider; (global as any).bytefunEditorProvider = editorProvider; // 暴露全局方法来更新文件处理记录,避免触发文件监听器 (global as any).updateFileProcessRecord = (filePath: string, hash: string, time: number) => { try { fileHashes.set(filePath, hash); lastProcessTimes.set(filePath, time); } catch (error) { console.error('❌ [ByteFun] 更新文件处理记录失败:', error); } }; const webviewRegistration = vscode.window.registerWebviewViewProvider('bytefunView', sidebarProvider, { webviewOptions: { retainContextWhenHidden: true } }); context.subscriptions.push(webviewRegistration); // 注册命令:打开ByteFun编辑器tab const openEditorCommand = vscode.commands.registerCommand('bytefun.openEditor', () => { editorProvider?.openOrFocusEditor(context); }); // 注册命令:工作台按钮 const openWorkspaceCommand = vscode.commands.registerCommand('bytefun.openWorkspace', () => { // 发送消息到webviewProvider(会自动确保tab已激活) const bytefunEditorProvider = (global as any).bytefunEditorProvider; if (bytefunEditorProvider) { bytefunEditorProvider.ensureWebviewActiveAndExecute(() => { const success = bytefunEditorProvider.sendMessageToWebview({ type: 'openProjects', data: { source: 'workspace-button', action: 'openProjects' } }); if (success) { } else { } }); } }); // 注册命令:我的库按钮 const openLibraryCommand = vscode.commands.registerCommand('bytefun.openLibrary', () => { // 发送消息到webviewProvider(会自动确保tab已激活) const bytefunEditorProvider = (global as any).bytefunEditorProvider; if (bytefunEditorProvider) { bytefunEditorProvider.ensureWebviewActiveAndExecute(() => { const success = bytefunEditorProvider.sendMessageToWebview({ type: 'openLibrary', data: { source: 'library-button', action: 'openLibrary' } }); if (success) { } else { } }); } }); // 注册命令:设计稿按钮 const openDesignFileCommand = vscode.commands.registerCommand('bytefun.openDesignFile', async () => { await checkAndOpenFile('src/index.html', '设计稿还没设计', 'design'); }); // 注册命令:需求文档按钮 const openRequirementsDocCommand = vscode.commands.registerCommand('bytefun.openRequirementsDoc', async () => { await checkAndOpenFile('doc/产品需求文档.md', '需求产品文档还没设计', 'requirements'); }); /** * 检查文件是否存在,如果存在则打开,否则显示提示信息 */ async function checkAndOpenFile(relativePath: string, notExistMessage: string, type: 'design' | 'requirements'): Promise<void> { try { if (!sidebarProvider) { vscode.window.showErrorMessage('侧边栏提供器未初始化'); return; } if (type === 'design') { // 打开设计稿 - 使用与其他功能一致的方式 await sidebarProvider.handleOpenDesignPreview(); } else { // 打开产品需求文档 - 使用与产品角色tab相同的逻辑 await sidebarProvider.handleOpenPrdDesignSpec(); } } catch (error) { console.error(`❌ [ByteFun] 打开${type === 'design' ? '设计稿' : '需求文档'}失败:`, error); vscode.window.showErrorMessage(`打开${type === 'design' ? '设计稿' : '需求文档'}失败: ${error}`); } } // 监听工作区变化,重新初始化项目 UID 和聊天会话 workspaceWatcher = vscode.workspace.onDidChangeWorkspaceFolders(() => { // 延迟一下确保项目UID已设置 setTimeout(() => { // 重新初始化UI设计进度缓存 initializeUIDesignProgressCache(); initializeCurrentProjectChatSessions(); // 通知侧边栏工作区变化 sidebarProvider?.handleWorkspaceChange(); }, 100); }); // 监听活动栏视图的可见性变化 const colorThemeWatcher = vscode.window.onDidChangeActiveColorTheme(() => { // 当切换到ByteFun活动栏时触发 editorProvider?.openOrFocusEditor(context); }); // 将所有需要清理的资源添加到context.subscriptions context.subscriptions.push( openEditorCommand, openWorkspaceCommand, openLibraryCommand, openDesignFileCommand, openRequirementsDocCommand, workspaceWatcher, colorThemeWatcher, ...fileWatchers ); } // 初始化当前项目的聊天会话 function initializeCurrentProjectChatSessions() { try { const projectManager = ProjectManager.getInstance(); const uid = projectManager.getUID(); const projectID = projectManager.getCurrentProjectID(); if (uid && projectID) { projectManager.initializeDefaultChatSessions(uid, projectID); } else { } } catch (error) { console.error('❌ [ByteFun] 初始化聊天会话失败:', error); } } // 处理UI设计进度文件变化 function handleUIDesignProgressChange(filePath: string, editorProvider: EditorProvider) { if (!lockManager) { console.warn('⚠️ [ByteFun] 文件锁管理器未初始化,跳过UI设计进度文件处理'); return; } // 使用文件锁执行,防止多个VS Code窗口重复处理 lockManager.executeWithLock(async () => { try { // 检查文件是否存在 if (!fs.existsSync(filePath)) { // 如果文件不存在,清空缓存 cachedUIDesignProgress = null; return; } // 读取新的UI设计进度数据 let newUIDesignProgress: any = null; try { const content = fs.readFileSync(filePath, 'utf8'); newUIDesignProgress = JSON.parse(content); } catch (parseError) { console.error('❌ [ByteFun] 解析UI设计进度JSON失败:', parseError); return; } // 与缓存数据进行对比 const changedPages = findVersionChangedPages(cachedUIDesignProgress, newUIDesignProgress); if (changedPages.length === 0) { // 即使没有变化,也要更新缓存(可能是其他字段变化了) cachedUIDesignProgress = newUIDesignProgress; return; } // 处理每个版本变化的页面 let processedCount = 0; for (const changedPage of changedPages) { const pageNameEN = changedPage.pageNameEN; // 查找对应的HTML文件路径 const htmlFilePath = findHtmlFilePath(pageNameEN); if (htmlFilePath) { // 调用原来的HTML文件变化处理逻辑,传递changedPage对象 handleHtmlFileChange(htmlFilePath, editorProvider, changedPage); processedCount++; } else { } } // 更新缓存数据 cachedUIDesignProgress = newUIDesignProgress; } catch (error) { console.error('❌ [ByteFun] 处理UI设计进度文件变化失败:', error); throw error; } }, { timeout: 30000, retryDelay: 1000, maxRetries: 2, cleanupDelay: 2000 }).catch(error => { console.error('❌ [ByteFun] UI设计进度文件锁执行失败:', error); }); } // 处理HTML文件变化 export function handleHtmlFileChange(filePath: string, editorProvider: EditorProvider, changedPage?: any) { try { // 提取文件名 const fileName = filePath.split('/').pop() || ''; const fileNameLower = fileName.toLowerCase(); // 排除index.html和tempHtmlCode.html if (fileNameLower === 'index.html' || fileNameLower === 'temphtmlcode.html') { return; } // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } // 读取文件内容 const content = fs.readFileSync(filePath, 'utf8'); // 检查HTML结构是否包含style和body if (!content.includes('<style') && !content.includes('</style>')) { return; } if (!content.includes('<body') && !content.includes('</body>')) { return; } // 使用sidebarProvider的检查方法来判断页面内容容器是否有实际内容 const sidebarProvider = (global as any).bytefunSidebarProvider; if (sidebarProvider) { const hasContent = sidebarProvider.checkPageContentContainer(filePath); if (!hasContent) { return; } } else { return; } // 调用handleUIDesignFileCreated方法,传递changedPage参数 editorProvider.handleUIDesignFileCreated(filePath, changedPage); // 处理UI设计进度概览 if (sidebarProvider) { sidebarProvider.handleUIDesignProgress(); } else { } } catch (error) { console.error('❌ [ByteFun] 处理HTML文件变化失败:', error); } } // 处理产品设计进度文件变化 function handleProductProgressFileChange(filePath: string, sidebarProvider: SidebarProvider) { if (!lockManager) { console.warn('⚠️ [ByteFun] 文件锁管理器未初始化,跳过产品设计进度文件处理'); return; } lockManager.executeWithLock(async () => { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } if (sidebarProvider) { sidebarProvider.handleProductDesignProgress(); } else { } } catch (error) { console.error('❌ [ByteFun] 处理产品设计进度文件变化失败:', error); throw error; } }, { timeout: 15000, maxRetries: 1 }).catch(error => { console.error('❌ [ByteFun] 产品设计进度文件锁执行失败:', error); }); } // 处理globalApiInterfaceList文件变化 function handleApiListFileChange(filePath: string) { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } // 获取工作区根目录 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { return; } const outputPath = path.join(workspaceRoot, 'src', 'backendApi'); // 直接调用 execGen 方法生成 API 类型文件 execGen(filePath, outputPath); } catch (error) { console.error('❌ [ByteFun] 处理globalApiInterfaceList文件变化失败:', error); } } // 处理数据库配置文件变化 function handleDbJsonFileChange(filePath: string) { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } // 获取工作区根目录 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { return; } const jsonPath = path.join(workspaceRoot, 'doc', 'db.json'); const outputBaseDir = path.join(workspaceRoot, 'backend', 'bytefun-boot-biz-common'); // 调用 TemplateCodeGen 的 generateAllFiles 方法 TemplateCodeGen.generateAllFiles(jsonPath, outputBaseDir) .then(() => { }) .catch((error) => { console.error('❌ [ByteFun] 代码文件生成失败:', error); }); } catch (error) { console.error('❌ [ByteFun] 处理数据库配置文件变化失败:', error); } } // 处理前端代码开发进度文件变化 function handleFrontendProgressFileChange(filePath: string, sidebarProvider: SidebarProvider) { if (!lockManager) { console.warn('⚠️ [ByteFun] 文件锁管理器未初始化,跳过前端代码开发进度文件处理'); return; } lockManager.executeWithLock(async () => { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } if (sidebarProvider) { // 调用 SidebarProvider 的 handleLoadFrontendDevItems 方法刷新前端开发tab (sidebarProvider as any).handleLoadFrontendDevItems(); } else { } } catch (error) { console.error('❌ [ByteFun] 处理前端代码开发进度文件变化失败:', error); throw error; } }, { timeout: 15000, maxRetries: 1 }).catch(error => { console.error('❌ [ByteFun] 前端代码开发进度文件锁执行失败:', error); }); } // 处理后端代码开发进度文件变化 function handleBackendProgressFileChange(filePath: string, sidebarProvider: SidebarProvider) { if (!lockManager) { console.warn('⚠️ [ByteFun] 文件锁管理器未初始化,跳过后端代码开发进度文件处理'); return; } lockManager.executeWithLock(async () => { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } if (sidebarProvider) { // 调用 SidebarProvider 的 handleLoadBackendDevItems 方法刷新后端开发tab (sidebarProvider as any).handleLoadBackendDevItems(); } else { } } catch (error) { console.error('❌ [ByteFun] 处理后端代码开发进度文件变化失败:', error); throw error; } }, { timeout: 15000, maxRetries: 1 }).catch(error => { console.error('❌ [ByteFun] 后端代码开发进度文件锁执行失败:', error); }); } // 处理业务逻辑设计文件变化 function handleBusinessLogicFileChange(filePath: string, sidebarProvider: SidebarProvider) { if (!lockManager) { console.warn('⚠️ [ByteFun] 文件锁管理器未初始化,跳过业务逻辑设计文件处理'); return; } lockManager.executeWithLock(async () => { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } // 生成业务逻辑设计Markdown文件 generateBusinessLogicMarkdown(filePath); if (sidebarProvider) { // 获取工作区根目录 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { console.error('❌ [ByteFun] 无法获取工作空间文件夹'); return; } // 调用 SidebarProvider 的方法生成或更新UI设计进度文件 sidebarProvider.generateOrUpdateUIProgressFile(workspaceRoot); // 调用 SidebarProvider 的方法生成或更新前端代码开发进度.json文件 sidebarProvider.generateOrUpdateFrontendCodeProgressFile(workspaceRoot); } else { } } catch (error) { console.error('❌ [ByteFun] 处理业务逻辑设计文件变化失败:', error); throw error; } }, { timeout: 20000, maxRetries: 1 }).catch(error => { console.error('❌ [ByteFun] 业务逻辑设计文件锁执行失败:', error); }); } // 处理后端设计配置文件变化 function handleBackendDesignConfigChange(filePath: string, sidebarProvider: SidebarProvider) { if (!lockManager) { console.warn('⚠️ [ByteFun] 文件锁管理器未初始化,跳过后端设计配置文件处理'); return; } lockManager.executeWithLock(async () => { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } // 读取并解析JSON配置文件 let backendConfig: any; try { const content = fs.readFileSync(filePath, 'utf8'); backendConfig = JSON.parse(content); } catch (parseError) { console.error('❌ [ByteFun] 解析后端设计配置JSON失败:', parseError); return; } // 生成API文档markdown内容 const markdownContent = generateBackendApiDocumentMd(backendConfig); if (markdownContent) { // 确定输出文件路径 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (workspaceRoot) { const bytefunDir = path.join(workspaceRoot, '.bytefun'); const outputPath = path.join(bytefunDir, 'globalApiInterfaceList.md'); // 确保.bytefun目录存在 if (!fs.existsSync(bytefunDir)) { fs.mkdirSync(bytefunDir, { recursive: true }); } // 写入markdown文件 fs.writeFileSync(outputPath, markdownContent, 'utf8'); } } handleApiListFileChange(filePath); if (sidebarProvider) { // 获取工作区根目录 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { console.error('❌ [ByteFun] 无法获取工作空间文件夹'); return; } // 调用 SidebarProvider 的方法生成或更新后端代码开发进度.json文件 sidebarProvider.generateOrUpdateBackendCodeProgressFile(workspaceRoot); } } catch (error) { console.error('❌ [ByteFun] 处理后端设计配置文件变化失败:', error); throw error; } }, { timeout: 25000, maxRetries: 1 }).catch(error => { console.error('❌ [ByteFun] 后端设计配置文件锁执行失败:', error); }); } // 处理UI设计配置文件变化 function handleUIDesignConfigChange(filePath: string) { try { // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } // 读取并解析JSON配置文件 let uiConfig: any; try { const content = fs.readFileSync(filePath, 'utf8'); uiConfig = JSON.parse(content); } catch (parseError) { console.error('❌ [ByteFun] 解析UI设计配置JSON失败:', parseError); return; } // 生成UI设计规范markdown内容 const markdownContent = generateUIDesignSpecMd(uiConfig); if (!markdownContent) { return; } // 确定输出文件路径 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { return; } const bytefunDir = path.join(workspaceRoot, '.bytefun'); const outputPath = path.join(bytefunDir, 'UI设计规范.md'); // 确保.bytefun目录存在 if (!fs.existsSync(bytefunDir)) { fs.mkdirSync(bytefunDir, { recursive: true }); } // 写入markdown文件 fs.writeFileSync(outputPath, markdownContent, 'utf8'); // 解析uiConfig生成对应的css样式定义文件'src/uiDesign.css' const cssContent = generateUIDesignCss(uiConfig); if (cssContent) { const srcDir = path.join(workspaceRoot, 'src'); const cssOutputPath = path.join(srcDir, 'uiDesign.css'); // 确保src目录存在 if (!fs.existsSync(srcDir)) { fs.mkdirSync(srcDir, { recursive: true }); } // 写入CSS文件 fs.writeFileSync(cssOutputPath, cssContent, 'utf8'); // 将:root变量插入到所有xxxPage.html文件中 insertRootVariablesToHtmlFiles(workspaceRoot, cssContent); } else { } } catch (error) { console.error('❌ [ByteFun] 处理UI设计配置文件变化失败:', error); } } // 用于防止递归触发文件变化处理的标志 let isUpdatingPrdConfig = false; // 处理PRD设计配置文件变化 function handlePrdDesignConfigChange(filePath: string) { try { // 如果正在更新配置,跳过处理避免递归 if (isUpdatingPrdConfig) { console.log('🔄 [ByteFun] 跳过PRD配置处理,避免递归触发'); return; } // 检查文件是否存在 const fs = require('fs'); if (!fs.existsSync(filePath)) { return; } // 读取并解析JSON配置文件 let prdConfig: any; let originalContent: string; try { originalContent = fs.readFileSync(filePath, 'utf8'); prdConfig = JSON.parse(originalContent); } catch (parseError) { console.error('❌ [ByteFun] 解析PRD设计配置JSON失败:', parseError); return; } // 处理业务逻辑流程图内容,去掉换行符后的空格 let needsUpdate = false; const businessLogicFlow = prdConfig?.productRequirementDocument?.sections?.businessLogicFlow; if (businessLogicFlow && typeof businessLogicFlow.content === 'string') { const originalFlowContent = businessLogicFlow.content; // 去掉换行符\n后紧接着的N个空格字符 const cleanedFlowContent = originalFlowContent.replace(/\n\s+/g, '\n'); if (originalFlowContent !== cleanedFlowContent) { console.log('🔧 [ByteFun] 检测到流程图内容需要格式化,去除换行后多余空格'); businessLogicFlow.content = cleanedFlowContent; needsUpdate = true; } } // 如果需要更新,写回文件 if (needsUpdate) { try { // 设置标志防止递归触发 isUpdatingPrdConfig = true; const updatedContent = JSON.stringify(prdConfig, null, 2); fs.writeFileSync(filePath, updatedContent, 'utf8'); console.log('✅ [ByteFun] PRD配置文件流程图内容已格式化并更新'); // 更新文件处理记录,避免触发文件监听器 const crypto = require('crypto'); const newHash = crypto.createHash('md5').update(updatedContent).digest('hex'); const currentTime = Date.now(); if (typeof (global as any).updateFileProcessRecord === 'function') { (global as any).updateFileProcessRecord(filePath, newHash, currentTime); } } catch (writeError) { console.error('❌ [ByteFun] 写入PRD配置文件失败:', writeError); } finally { // 延迟重置标志,确保文件监听器有足够时间处理 setTimeout(() => { isUpdatingPrdConfig = false; }, 1000); } } // 生成PRD需求文档markdown内容 const markdownContent = generatePrdRequirementDocMd(prdConfig); if (!markdownContent) { return; } // 确定输出文件路径 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { return; } const bytefunDir = path.join(workspaceRoot, '.bytefun'); // 确保.bytefun目录存在 if (!fs.existsSync(bytefunDir)) { fs.mkdirSync(bytefunDir, { recursive: true }); } // 写入markdown文件 const outputPath = path.join(bytefunDir, '产品需求文档.md'); fs.writeFileSync(outputPath, markdownContent, 'utf8'); // 更新整体模块分析进度文件 updateModuleAnalysisProgress(prdConfig, workspaceRoot); // 处理模块业务逻辑文件创建 handleModuleBusinessLogicFiles(prdConfig, bytefunDir); } catch (error) { console.error('❌ [ByteFun] 处理PRD设计配置文件变化失败:', error); } } // 更新整体模块分析进度文件 function updateModuleAnalysisProgress(prdConfig: any, workspaceRoot: string) { try { // 检查是否存在functionalRequirements.moduleList const moduleList = prdConfig?.productRequirementDocument?.sections?.functionalRequirements?.moduleList; if (!moduleList || !Array.isArray(moduleList)) { return; } const fs = require('fs'); const path = require('path'); // 构建整体模块分析进度文件路径 const docDir = path.join(workspaceRoot, 'doc'); const analysisProgressPath = path.join(docDir, '整体模块分析进度.json'); // 确保doc目录存在 if (!fs.existsSync(docDir)) { fs.mkdirSync(docDir, { recursive: true }); } // 读取现有的进度数据(如果存在) let existingProgress: any = null; let existingModules: any[] = []; if (fs.existsSync(analysisProgressPath)) { try { const existingContent = fs.readFileSync(analysisProgressPath, 'utf8'); existingProgress = JSON.parse(existingContent); if (existingProgress && Array.isArray(existingProgress.modules)) { existingModules = existingProgress.modules; } } catch (parseError) { } } // 创建模块映射,用于快速查找现有模块(基于enName) const existingModuleMap = new Map(); existingModules.forEach(module => { if (module.moduleNameEN) { existingModuleMap.set(module.moduleNameEN, module); } }); // 构建新的模块列表 const newModules: any[] = []; moduleList.forEach((module: any, index: number) => { const enName = module.enName; const cnName = module.cnName; if (!enName) { return; } // 检查模块是否已存在 const existingModule = existingModuleMap.get(enName); if (existingModule) { // 如果模块已存在,只修改ID,其他字段保持不变 newModules.push({ ...existingModule, id: index + 1 // ID从1开始 }); } else { // 如果是新模块,创建新的模块对象 const newModule = { id: index + 1, // ID从1开始 moduleNameCN: cnName || enName, moduleNameEN: enName, status: 'pending' }; newModules.push(newModule); } }); // 构建完整的进度数据 const progressData = { totalModules: newModules.length, modules: newModules }; // 写入文件 const jsonContent = JSON.stringify(progressData, null, 2); fs.writeFileSync(analysisProgressPath, jsonContent, 'utf8'); } catch (error) { console.error('❌ [ByteFun] 更新整体模块分析进度文件失败:', error); } } // 处理模块业务逻辑文件创建 function handleModuleBusinessLogicFiles(prdConfig: any, bytefunDir: string) { try { // 检查是否存在functionalRequirements.moduleList const moduleList = prdConfig?.productRequirementDocument?.sections?.functionalRequirements?.moduleList; if (!moduleList || !Array.isArray(moduleList)) { return; } const fs = require('fs'); // 遍历moduleList moduleList.forEach((module: any, index: number) => { const enName = module.enName; if (!enName) { return; } // 检查是否已存在包含该enName的模块业务逻辑文件 const existingFiles = fs.readdirSync(bytefunDir).filter((file: string) => file.includes(`${enName}-module-business-logic.json`) ); if (existingFiles.length > 0) { return; } // 创建新的模块业务逻辑文件 const moduleIndex = index + 1; // 从1开始 const fileName = `${moduleIndex}-${enName}-module-business-logic.json`; const filePath = path.join(bytefunDir, fileName); // 创建模板JSON内容 const templateData = { "moduleBusinessLogicDesign": { "title": `${module.cnName || enName}模块业务逻辑设计`, "moduleNameCN": module.cnName, "moduleNameEN": enName, "sections": { "moduleIntroduction": { "title": "一、功能模块介绍", "content": "xxx(说明该功能模块的职责和流程)" }, "pageRequirements": { "title": "二、页面详细信息列表", "pageList": [ { "title": "1、xxx页", "isSubPage": false, "cnName": "xxx页", "enName": "xxxPage", "content": [ { "title": "1.1、页面组成部分(从上往下、从左到右)", "content": "xxx(说明该页面的组成部分,比如:顶部搜索栏、推荐轮播、分类、热门推荐、新品速递、推荐书籍列表)" }, { "title": "1.2、数据来源", "content": "xxx(说明该页面可能需要的网络数据、代码写死的数据、本地持久化的数据等)" }, { "title": "1.3、用户操作", "content": "xxx(说明该页面的用户交互操作流程)" }, { "title": "1.4、依赖后端API接口", "content": "xxx(说明该页面的依赖的后端API接口有哪些)" } ] }, { "title": "2、xxx子页面", "isSubPage": true, "cnName": "xxx子页面", "enName": "xxxSubPage", "content": [ { "title": "1.1、页面组成部分(从上往下、从左到右)", "content": "xxx(说明该页面的组成部分,比如:头部个人信息、各种订单入口、收藏与历史、设置、关于)" }, { "title": "1.2、数据来源", "content": "xxx(说明该页面可能需要的网络数据、代码写死的数据、本地持久化的数据等)" }, { "title": "1.3、用户操作", "content": "xxx(说明该页面的用户交互操作流程)" }, { "title": "1.4、依赖后端API接口", "content": "xxx(说明该页面的依赖的后端API接口有哪些)" } ] } ] }, "businessLogicFlow": { "title": "三、页面业务逻辑流程图", "content": "flowchart TD\n A[启动应用] --> B{是否首次启动}\n ... X -->|关注作者| J" } } } }; // 写入文件 fs.writeFileSync(filePath, JSON.stringify(templateData, null, 2), 'utf8'); }); } catch (error) { console.error('❌ [ByteFun] 处理模块业务逻辑文件创建失败:', error); } } // 生成业务逻辑设计Markdown文件 function generateBusinessLogicMarkdown(filePath: string) { try { // 读取并解析JSON文件 const fs = require('fs'); const path = require('path'); if (!fs.existsSync(filePath)) { return; } let businessLogicData: any; try { const content = fs.readFileSync(filePath, 'utf8'); businessLogicData = JSON.parse(content); } catch (parseError) { console.error('❌ [ByteFun] 解析业务逻辑JSON失败:', parseError); return; } // 检查JSON结构 const moduleDesign = businessLogicData?.moduleBusinessLogicDesign; if (!moduleDesign) { return; } // 生成Markdown内容 const markdownContent = convertBusinessLogicToMarkdown(moduleDesign); if (!markdownContent) { return; } // 获取工作区根目录 const workspaceRoot = WorkspaceUtils.getProjectRootPath(); if (!workspaceRoot) { return; } const bytefunDir = path.join(workspaceRoot, '.bytefun'); // 确保.bytefun目录存在 if (!fs.existsSync(bytefunDir)) { fs.mkdirSync(bytefunDir, { recursive: true }); } // 构建输出文件路径 const moduleNameCN = moduleDesign.moduleNameCN || '未知模块'; const fileName = `${moduleNameCN}业务逻辑设计.md`; const outputPath = path.join(bytefunDir, fileName); // 写入Markdown文件 fs.writeFileSync(outputPath, markdownContent, 'utf8'); } catch (error) { console.error('❌ [ByteFun] 生成业务逻辑设计Markdown文件失败:', error); } } // 将业务逻辑JSON转换为Markdown内容 function convertBusinessLogicToMarkdown(moduleDesign: any): string { try { let markdown = ''; // 主标题 if (moduleDesign.title) { markdown += `# ${moduleDesign.title}\n\n`; } // 模块基本信息 if (moduleDesign.moduleNameCN || moduleDesign.moduleNameEN) { markdown += '## 模块信息\n\n'; if (moduleDesign.moduleNameCN) { markdown += `**中文名称:** ${moduleDesign.moduleNameCN}\n\n`; } if (moduleDesign.moduleNameEN) { markdown += `**英文名称:** ${moduleDesign.moduleNameEN}\n\n`; } } // 处理各个章节 if (moduleDesign.sections) { const sections = moduleDesign.sections; // 功能模块介绍 if (sections.moduleIntroduction) { markdown += convertBusinessLogicSection(sections.moduleIntroduction, 2); } // 页面详细信息列表 if (sections.pageRequirements) { markdown += convertPageRequirementsSection(sections.pageRequirements, 2); } // 业务逻辑流程图 if (sections.businessLogicFlow) { markdown += convertBusinessLogicFlowSection(sections.businessLogicFlow, 2); } // 处理其他可能的章节 Object.keys(sections).forEach(sectionKey => { if (!['moduleIntroduction', 'pageRequirements', 'businessLogicFlow'].includes(sectionKey)) { markdown += convertBusinessLogicSection(sections[sectionKey], 2); } }); } return markdown; } catch (error) { console.error('❌ [ByteFun] 转换业务逻辑为Markdown失败:', error); return ''; } } // 转换普通章节 function convertBusinessLogicSection(section: any, level: number): string { let markdown = ''; const headerPrefix = '#'.repeat(level); if (section.title) { markdown += `${headerPrefix} ${section.title}\n\n`; } if (section.content) { if (typeof section.content === 'string') { markdown += `${section.content}\n\n`; } } return markdown; } // 转换页面需求章节 function convertPageRequirementsSection(section: any, level: number): string { let markdown = ''; const headerPrefix = '#'.repeat(level); if (section.title) { markdown += `${headerPrefix} ${section.title}\n\n`; } if (section.pageList && Array.isArray(section.pageList)) { section.pageList.forEach((page: any) => { // 页面标题 if (page.title) { markdown += `${headerPrefix}# ${page.title}\n\n`; } // 页面基本信息 if (page.cnName || page.enName || page.isSubPage !== undefined) { markdown += '**页面信息:**\n\n'; if (page.cnName) { markdown += `- **中文名称:** ${page.cnName}\n`; } if (page.enName) { markdown += `- **英文名称:** ${page.enName}\n`; } if (page.isSubPage !== undefined) { markdown += `- **子页面:** ${page.isSubPage ? '是' : '否'}\n`; } markdown += '\n'; } // 页面详细内容 if (page.content && Array.isArray(page.content)) { page.content.forEach((contentItem: any) => { if (contentItem.title) { markdown += `${headerPrefix}## ${contentItem.title}\n\n`; } if (contentItem.content) { markdown += `${contentItem.content}\n\n`; } }); } }); } return markdown; } // 转换业务逻辑流程图章节 function convertBusinessLogicFlowSection(section: any, level: number): string { let markdown = ''; const headerPrefix = '#'.repeat(level); if (section.title) { markdown += `${headerPrefix} ${section.title}\n\n`; } if (section.content) { if (typeof section.content === 'string') { // 检查是否是流程图内容 if (section.content.includes('flowchart') || section.content.includes('graph')) { markdown += '```mermaid\n'; markdown += section.content; markdown += '\n```\n\n'; } else { markdown += `${section.content}\n\n`; } } } return markdown; } // 生成PRD需求文档markdown内容 function generatePrdRequirementDocMd(prdData: any): string { try { if (!prdData?.productRequirementDocument) { throw new Error('无效的PRD数据结构'); } const prd = prdData.productRequirementDocument; let markdown = ''; // 文档标题 markdown += `# ${prd.title}\n\n`; // 遍历所有章节 if (prd.sections) { Object.keys(prd.sections).forEach(sectionKey => { const section = prd.sections[sectionKey]; markdown += generatePrdSectionMarkdown(section); }); } return markdown; } catch (error) { console.error('❌ [ByteFun] 生成PRD Markdown内容失败:', error); return `# 产品需求文档\n\n生成失败: ${error}`; } } // 生成后端API文档markdown内容 function generateBackendApiDocumentMd(backendConfig: any): string { try { if (!backendConfig?.projectName || !backendConfig?.moduleList) { throw new Error('无效的后端配置数据结构'); } let markdown = ''; const projectName = backendConfig.projectName; const moduleList = backendConfig.moduleList; // 文档标题 markdown += `# ${projectName} - 后端API接口文档\n\n`; // 模块详细信息 moduleList.forEach((module: any, moduleIndex: number) => { markdown += generateModuleApiMarkdown(module, moduleIndex + 1); }); return markdown; } catch (error) { console.error('❌ [ByteFun] 生成后端API文档Markdown内容失败:', error); return `# 后端API接口文档\n\n生成失败: ${error}`; } } // 生成模块API的Markdown内容 function generateModuleApiMarkdown(module: any, moduleNumber: number): string { try { let markdown = ''; const moduleTitle = module.moduleCnName || module.moduleEnName || `模块${moduleNumber}`; // 模块标题 markdown += `## ${moduleTitle}\n\n`; // 模块基本信息 if (module.moduleEnName) { markdown += `**模块标识**: ${module.moduleEnName}\n\n`; } if (module.description) { markdown += `**模块描述**: ${module.description}\n\n`; } // API列表 if (module.apiList && Array.isArray(module.apiList) && module.apiList.length > 0) { module.apiList.forEach((api: any, apiIndex: number) => { markdown += generateSingleApiMarkdown(api, apiIndex + 1); }); } else { markdown += `*该模块暂无API接口*\n\n`; } return markdown; } catch (error) { console.error('❌ [ByteFun] 生成模块API Markdown失败:', error); return `### ${module.moduleCnName || '未知模块'}\n\n生成失败: ${error}\n\n`; } } // 生成单个API的Markdown内容 functio