bytefun
Version:
一个打通了原型设计、UI设计与代码转换、跨平台原生代码开发等的平台
1,705 lines (1,306 loc) • 107 kB
text/typescript
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