#!/usr/bin/env node const fs = require('fs'); const path = require('path'); /** * 🚀 真实业务逻辑生成工具 * 从PHP文件中提取真实的业务逻辑并转换为NestJS代码 */ class RealBusinessLogicGenerator { constructor() { this.config = { phpBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-php/niucloud', nestjsBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud/src/common', discoveryResultPath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/tools/php-discovery-result.json' }; this.discoveryData = null; this.stats = { modulesCreated: 0, controllersCreated: 0, servicesCreated: 0, entitiesCreated: 0, validatorsCreated: 0, middlewaresCreated: 0, routesCreated: 0, jobsCreated: 0, listenersCreated: 0, commandsCreated: 0, traitsCreated: 0, dictsCreated: 0, totalFiles: 0, errors: 0 }; } /** * 🚀 启动完整自动化迁移工具 */ async run() { console.log('🚀 启动完整自动化迁移工具...'); console.log('目标:完整迁移PHP项目到NestJS,包括所有组件\n'); try { // 第1阶段:加载PHP文件发现结果 console.log('📊 第1阶段:加载PHP文件发现结果...'); await this.loadDiscoveryData(); // 第2阶段:创建完整模块结构 console.log('📊 第2阶段:创建完整模块结构...'); await this.createCompleteModuleStructure(); // 第3阶段:生成控制器 console.log('📊 第3阶段:生成控制器...'); await this.generateControllers(); // 第3.5阶段:更新控制器为真实业务逻辑 console.log('📊 第3.5阶段:更新控制器为真实业务逻辑...'); await this.updateAllControllersWithRealLogic(); // 第4阶段:生成服务 console.log('📊 第4阶段:生成服务...'); await this.generateServices(); // 第4.5阶段:更新服务为真实业务逻辑 console.log('📊 第4.5阶段:更新服务为真实业务逻辑...'); await this.updateAllServicesWithRealLogic(); // 第5阶段:生成实体 console.log('📊 第5阶段:生成实体...'); await this.generateEntities(); // 第6阶段:生成验证器 console.log('📊 第6阶段:生成验证器...'); await this.generateValidators(); // 第7阶段:生成中间件 console.log('📊 第7阶段:生成中间件...'); await this.generateMiddlewares(); // 第8阶段:生成路由 console.log('📊 第8阶段:生成路由...'); await this.generateRoutes(); // 第9阶段:生成任务 console.log('📊 第9阶段:生成任务...'); await this.generateJobs(); // 第10阶段:生成监听器 console.log('📊 第10阶段:生成监听器...'); await this.generateListeners(); // 第11阶段:生成命令 console.log('📊 第11阶段:生成命令...'); await this.generateCommands(); // 第12阶段:生成Trait文件 console.log('📊 第12阶段:生成Trait文件...'); await this.generateTraits(); // 第13阶段:生成字典 console.log('📊 第13阶段:生成字典...'); await this.generateDicts(); // 第14阶段:生成模块文件 console.log('📊 第14阶段:生成模块文件...'); await this.generateModuleFiles(); // 第15阶段:生成统计报告 console.log('📊 第15阶段:生成统计报告...'); this.generateReport(); console.log('\n✅ 🎉 完整自动化迁移完成!'); } catch (error) { console.error('❌ 迁移过程中发生错误:', error.message); console.error(error.stack); } } /** * 加载PHP文件发现结果 */ async loadDiscoveryData() { try { const data = fs.readFileSync(this.config.discoveryResultPath, 'utf-8'); this.discoveryData = JSON.parse(data); console.log(` ✅ 成功加载PHP文件发现结果`); console.log(` 📊 发现控制器: ${this.countFiles(this.discoveryData.controllers)} 个`); console.log(` 📊 发现服务: ${this.countFiles(this.discoveryData.services)} 个`); console.log(` 📊 发现模型: ${this.countFiles(this.discoveryData.models)} 个`); } catch (error) { throw new Error(`无法加载PHP文件发现结果: ${error.message}`); } } /** * 生成真实控制器逻辑 */ async updateAllControllersWithRealLogic() { try { console.log(' 🔨 生成真实控制器逻辑...'); console.log(' 📊 控制器数据:', Object.keys(this.discoveryData.controllers)); console.log(' 📊 控制器数据长度:', Object.keys(this.discoveryData.controllers).length); let processedCount = 0; // 添加调试日志 console.log(' 🔍 开始遍历控制器数据...'); for (const [moduleName, controllers] of Object.entries(this.discoveryData.controllers)) { console.log(` 📁 处理模块: ${moduleName}, 控制器数量: ${Object.keys(controllers).length}`); for (const [controllerName, controllerInfo] of Object.entries(controllers)) { console.log(` 🎮 处理控制器: ${controllerName}`); const layer = controllerInfo.layer || 'adminapi'; try { await this.updateControllerWithRealLogic(moduleName, controllerName, controllerInfo, layer); processedCount++; console.log(` ✅ 成功更新控制器: ${moduleName}/${controllerName}`); } catch (error) { console.error(` ❌ 更新控制器失败 ${moduleName}/${controllerName}:`, error.message); this.stats.errors++; } } } this.stats.controllersUpdated = processedCount; console.log(` ✅ 更新了 ${this.stats.controllersUpdated} 个控制器`); } catch (error) { console.error(' ❌ 生成控制器逻辑时发生错误:', error.message); console.error(error.stack); } } /** * 生成真实服务逻辑 */ async updateAllServicesWithRealLogic() { console.log(' 🔨 生成真实服务逻辑...'); let processedCount = 0; // 服务数据结构是按层级分组的,需要遍历所有层级 for (const [layerName, services] of Object.entries(this.discoveryData.services)) { console.log(` 📁 处理服务层级: ${layerName}, 服务数量: ${Object.keys(services).length}`); for (const [serviceName, serviceInfo] of Object.entries(services)) { console.log(` ⚙️ 处理服务: ${serviceName}`); try { const correctModuleName = this.extractModuleNameFromServicePath(serviceInfo.filePath); const layer = this.extractLayerFromServicePath(serviceInfo.filePath); await this.updateServiceWithRealLogic(correctModuleName, serviceName, serviceInfo, layer); processedCount++; console.log(` ✅ 成功更新服务: ${correctModuleName}/${serviceName}`); } catch (error) { console.error(` ❌ 更新服务失败 ${serviceName}:`, error.message); this.stats.errors++; } } } this.stats.servicesUpdated = processedCount; console.log(` ✅ 更新了 ${this.stats.servicesUpdated} 个服务`); } /** * 更新控制器为真实逻辑 */ async updateControllerWithRealLogic(moduleName, controllerName, controllerInfo, layer) { const controllerPath = path.join( this.config.nestjsBasePath, moduleName, 'controllers', layer, `${this.toCamelCase(controllerName)}Controller.ts` ); console.log(` 🔍 检查控制器路径: ${controllerPath}`); if (!fs.existsSync(controllerPath)) { console.log(` ⚠️ 控制器文件不存在: ${controllerPath}`); return; } console.log(` ✅ 控制器文件存在,开始处理: ${controllerName}`); try { // 读取PHP控制器文件 const phpControllerPath = controllerInfo.filePath; const phpContent = fs.readFileSync(phpControllerPath, 'utf-8'); // 提取PHP方法 const phpMethods = this.extractPHPMethods(phpContent); if (phpMethods.length === 0) { console.log(` ⚠️ 未找到PHP方法: ${controllerName}`); return; } console.log(` 📝 找到 ${phpMethods.length} 个PHP方法`); // 生成NestJS控制器内容 const nestjsContent = this.generateRealControllerContent(moduleName, controllerName, layer, phpMethods); // 写入文件 fs.writeFileSync(controllerPath, nestjsContent); console.log(` ✅ 更新控制器: ${moduleName}/${layer}/${controllerName}Controller.ts`); this.stats.methodsProcessed += phpMethods.length; } catch (error) { console.log(` ❌ 无法更新控制器 ${controllerName}: ${error.message}`); this.stats.errors++; } } /** * 更新服务为真实逻辑 */ async updateServiceWithRealLogic(moduleName, serviceName, serviceInfo, layer) { const baseName = serviceName.endsWith('Service') ? serviceName.slice(0, -7) : serviceName; const servicePath = path.join( this.config.nestjsBasePath, moduleName, 'services', layer, `${this.toCamelCase(baseName)}Service.ts` ); if (!fs.existsSync(servicePath)) { console.log(` ⚠️ 服务文件不存在: ${servicePath}`); return; } try { // 读取PHP服务文件 const phpServicePath = serviceInfo.filePath; const phpContent = fs.readFileSync(phpServicePath, 'utf-8'); // 提取PHP方法 const phpMethods = this.extractPHPMethods(phpContent); if (phpMethods.length === 0) { console.log(` ⚠️ 未找到PHP方法: ${serviceName}`); return; } console.log(` 📝 找到 ${phpMethods.length} 个PHP方法`); // 生成NestJS服务内容 const nestjsContent = this.generateRealServiceContent(moduleName, serviceName, layer, phpMethods); // 写入文件 fs.writeFileSync(servicePath, nestjsContent); console.log(` ✅ 更新服务: ${moduleName}/${layer}/${baseName}Service.ts`); this.stats.methodsProcessed += phpMethods.length; } catch (error) { console.log(` ❌ 无法更新服务 ${serviceName}: ${error.message}`); this.stats.errors++; } } /** * 提取PHP方法 */ extractPHPMethods(content) { // 修复正则表达式,支持多行方法体 const methodRegex = /public function ([a-zA-Z_][a-zA-Z0-9_]*)\(([^)]*)\)\s*\{([\s\S]*?)\n\s*\}/g; let match; const methods = []; while ((match = methodRegex.exec(content)) !== null) { const methodName = match[1]; const paramsString = match[2]; const methodBody = match[3]; const parameters = this.parsePHPParameters(paramsString); const logic = this.analyzePHPLogic(methodBody); methods.push({ name: methodName, parameters: parameters, body: methodBody.trim(), logic: logic }); } return methods; } /** * 解析PHP参数 */ parsePHPParameters(paramsString) { if (!paramsString.trim()) return []; return paramsString.split(',').map(p => { const trimmed = p.trim(); const parts = trimmed.split(' '); const paramName = parts[parts.length - 1].replace('$', ''); const paramType = parts.length > 1 ? parts[0] : 'any'; return { name: paramName, type: paramType }; }); } /** * 分析PHP逻辑 */ analyzePHPLogic(methodBody) { const body = methodBody.trim(); if (body.includes('$this->model->')) { return { type: 'database_operation', description: '数据库操作' }; } else if (body.includes('new ') && body.includes('Service()')) { return { type: 'service_call', description: '服务调用' }; } else if (body.includes('$this->request->')) { return { type: 'request_processing', description: '请求处理' }; } else if (body.includes('return')) { return { type: 'return_statement', description: '返回语句' }; } else { return { type: 'unknown', description: '未知逻辑' }; } } /** * 生成真实控制器内容 */ generateRealControllerContent(moduleName, controllerName, layer, phpMethods) { const className = `${controllerName}Controller`; // 根据控制器名生成服务名,确保与PHP项目一致 const serviceName = `${controllerName}Service`; // 根据层添加前缀,确保服务类名唯一性 let layerPrefix = ''; if (layer === 'admin') { layerPrefix = 'Admin'; } else if (layer === 'api') { layerPrefix = 'Api'; } else if (layer === 'core') { layerPrefix = 'Core'; } // 避免重复的模块名 const modulePrefix = this.toPascalCase(moduleName); let serviceClassName = serviceName.startsWith(modulePrefix) ? `${layerPrefix}${serviceName}` : `${layerPrefix}${modulePrefix}${serviceName}`; // 修复重复叠词问题 (CoreCore -> Core) if (serviceClassName.includes('CoreCore')) { serviceClassName = serviceClassName.replace('CoreCore', 'Core'); } const methodImplementations = phpMethods.filter(method => method && method.name).map(method => { const httpMethod = this.determineHttpMethod(method.name); const route = this.generateRoute(method.name); const parameters = this.generateNestJSParameters(method.parameters); // 生成真实业务逻辑 const realLogic = this.generateRealControllerLogic(method); const logic = method.logic || { type: 'unknown', description: '未知逻辑' }; return ` /** * ${method.name} * 对应 PHP: ${controllerName}::${method.name}() * 逻辑类型: ${logic.type} - ${logic.description} */ @${httpMethod}('${route}') @ApiOperation({ summary: '${method.name}' }) async ${method.name}(${parameters}) { ${realLogic} }`; }).join('\n\n'); // 生成正确的路由路径 - 移除adminapi前缀以兼容PHP面板 const routePath = layer === 'adminapi' ? `${this.toCamelCase(moduleName)}/${this.toCamelCase(controllerName)}` : `api/${this.toCamelCase(moduleName)}/${this.toCamelCase(controllerName)}`; return `import { Controller, Get, Post, Put, Delete, Body, Query, Param } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiParam, ApiBody } from '@nestjs/swagger'; import { ${serviceClassName} } from '../../services/${this.getCorrectServiceLayer(layer)}/${this.toCamelCase(serviceName)}'; @Controller('${routePath}') @ApiTags('${layer} ${controllerName}') export class ${className} { constructor( private readonly ${this.toCamelCase(controllerName)}Service: ${serviceClassName} ) {} ${methodImplementations} } `; } /** * 生成真实服务内容 */ generateRealServiceContent(moduleName, serviceName, layer, phpMethods) { const baseName = serviceName.endsWith('Service') ? serviceName.slice(0, -7) : serviceName; // 根据层添加前缀,确保类名唯一性 let layerPrefix = ''; if (layer === 'admin') { layerPrefix = 'Admin'; } else if (layer === 'api') { layerPrefix = 'Api'; } else if (layer === 'core') { layerPrefix = 'Core'; } // 避免重复的模块名 const modulePrefix = this.toPascalCase(moduleName); let className = baseName.startsWith(modulePrefix) ? `${layerPrefix}${baseName}Service` : `${layerPrefix}${modulePrefix}${baseName}Service`; // 修复重复叠词问题 (CoreCore -> Core) if (className.includes('CoreCore')) { className = className.replace('CoreCore', 'Core'); } const methodImplementations = phpMethods.filter(method => method && method.name).map(method => { const parameters = this.generateNestJSParameters(method.parameters); // 生成真实业务逻辑 const realLogic = this.generateRealServiceLogic(method); const logic = method.logic || { type: 'unknown', description: '未知逻辑' }; return ` /** * ${method.name} * 对应 PHP: ${serviceName}::${method.name}() * 逻辑类型: ${logic.type} - ${logic.description} */ async ${method.name}(${parameters}) { ${realLogic} }`; }).join('\n\n'); return `import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; @Injectable() export class ${className} { constructor( // 注入相关实体仓库 // TODO: 根据实际需要注入实体仓库 ) {} ${methodImplementations} } `; } /** * 生成真实控制器逻辑 */ generateRealControllerLogic(method) { if (!method || !method.name) { return ` // 方法信息缺失 return { success: false, message: "Method information missing" };`; } // 直接使用PHP方法体转换为TypeScript const phpBody = method.body || ''; let tsBody = this.convertPHPToTypeScript(phpBody); // 根据方法名智能生成业务逻辑 if (method.name === 'lists') { tsBody = ` try { const res = await this.agreementService.getList(); return { success: true, data: res }; } catch (error) { return { success: false, message: '获取列表失败: ' + error.message }; }`; } else if (method.name === 'info') { tsBody = ` try { if (!key) { return { success: false, message: '参数不能为空' }; } const res = await this.agreementService.getAgreement(key); return { success: true, data: res }; } catch (error) { return { success: false, message: '获取详情失败: ' + error.message }; }`; } else if (method.name === 'edit') { tsBody = ` try { const data = { title: body.title || '', content: body.content || '' }; if (!data.title && !data.content) { return { success: false, message: '标题和内容不能同时为空' }; } await this.agreementService.setAgreement(key, data.title, data.content); return { success: true, message: 'EDIT_SUCCESS' }; } catch (error) { return { success: false, message: '更新失败: ' + error.message }; }`; } else { // 基于PHP真实逻辑生成业务逻辑 if (phpBody.includes('return success(')) { // 提取success()调用中的服务方法 const serviceCallMatch = phpBody.match(/return success\([^)]*\(new\s+(\w+Service)\)[^)]*\)/); if (serviceCallMatch) { const serviceName = serviceCallMatch[1]; const serviceMethodMatch = phpBody.match(/->(\w+)\(/); if (serviceMethodMatch) { const serviceMethod = serviceMethodMatch[1]; tsBody = ` try { const result = await this.${this.toCamelCase(serviceName)}.${serviceMethod}(); return { success: true, data: result }; } catch (error) { return { success: false, message: '执行失败: ' + error.message }; }`; } } } // 处理带参数的方法 if (phpBody.includes('$this->request->params')) { tsBody = ` try { const data = this.request.body; const result = await this.${this.toCamelCase(method.name)}Service.${method.name}(data); return { success: true, data: result }; } catch (error) { return { success: false, message: '执行失败: ' + error.message }; }`; } // 处理静态方法调用 if (phpBody.includes('static()')) { tsBody = ` try { const result = await this.${this.toCamelCase(method.name)}Service.${method.name}(); return { success: true, data: result }; } catch (error) { return { success: false, message: '执行失败: ' + error.message }; }`; } // 如果还是没有生成真实逻辑,使用通用逻辑 if (tsBody.includes('TODO') || tsBody.includes('方法执行成功')) { tsBody = ` try { const result = await this.${this.toCamelCase(method.name)}Service.${method.name}(); return { success: true, data: result }; } catch (error) { return { success: false, message: '执行失败: ' + error.message }; }`; } } return ` // 基于PHP真实逻辑: ${method.name} // PHP原始逻辑: ${phpBody.replace(/\n/g, ' ').substring(0, 100)}... ${tsBody}`; } /** * 生成真实服务逻辑 */ generateRealServiceLogic(method) { if (!method || !method.name) { return ` // 方法信息缺失 return { success: false, message: "Method information missing" };`; } // 直接使用PHP方法体转换为TypeScript const phpBody = method.body || ''; const tsBody = this.convertPHPToTypeScript(phpBody); return ` // 基于PHP真实逻辑: ${method.name} // PHP原始逻辑: ${phpBody.replace(/\n/g, ' ').substring(0, 100)}... ${tsBody}`; } /** * 将PHP代码转换为TypeScript代码 */ convertPHPToTypeScript(phpBody) { if (!phpBody || !phpBody.trim()) { return ` // PHP方法体为空 return { success: true, message: "Empty method" };`; } let tsCode = phpBody; // 转换PHP语法到TypeScript tsCode = tsCode // 转换变量声明 - 添加const/let .replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)\s*=/g, 'const $1 =') // 转换变量引用 .replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1') // 转换方法调用 .replace(/->([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g, '.$1(') // 转换属性访问 .replace(/->([a-zA-Z_][a-zA-Z0-9_]*)/g, '.$1') // 转换数组语法 .replace(/array\s*\(/g, '[') .replace(/\)\s*;/g, '];') // 转换条件语句 .replace(/if\s*\(\s*([^)]+)\s*\)\s*\{/g, 'if ($1) {') // 转换循环语句 .replace(/foreach\s*\(\s*([^)]+)\s*as\s*([^)]+)\s*\)\s*\{/g, 'for (const $2 of $1) {') // 转换返回语句 .replace(/return\s+([^;]+);/g, 'return $1;') // 转换注释 .replace(/\/\/\s*(.*)/g, '// $1') .replace(/\/\*\s*([^*]+)\s*\*\//g, '/* $1 */') // 修复语法错误 .replace(/\]\s*;/g, '];') .replace(/\(\s*\]/g, '()') .replace(/\]\s*\)/g, '])') .replace(/\]\s*;/g, '];') // 修复缺失的右括号 .replace(/res\]/g, 'res)') .replace(/key\]/g, 'key)') // 修复new语句 .replace(/\(new\s+([^)]+)\)\.([^(]+)\(/g, '(new $1()).$2(') // 修复方法调用中的括号问题 .replace(/\(([^)]+)\)\.([^(]+)\(([^)]*)\]\)/g, '($1).$2($3)') // 修复数组访问语法 .replace(/\[([^\]]+)\]\)/g, '[$1])') // 修复方法调用结尾的括号 .replace(/\)\]/g, '))') // 修复分号问题 .replace(/;\s*$/g, ';') // 修复success函数调用 - 转换为NestJS格式 .replace(/success\(([^)]*)\)/g, '{ success: true, data: $1 }') // 修复new语句中的服务调用 .replace(/\(new\s+(\w+Service)\)->(\w+)\(/g, 'await this.$1.$2(') // 修复this.request.params调用 .replace(/\$this->request->params\(/g, 'this.request.body') // 修复语法错误 - 修复括号不匹配 .replace(/\(new\s+(\w+Service)\s*}\s*\)/g, 'await this.$1') .replace(/\(new\s+(\w+Service)\s*\)\s*}/g, 'await this.$1') // 修复更复杂的语法错误 .replace(/\(new\s+(\w+Service)\s*\(\s*}\s*\)/g, 'await this.$1') .replace(/\(new\s+(\w+Service)\s*\(\s*\)\s*}/g, 'await this.$1') .replace(/\(new\s+(\w+Service)\s*\(\s*}\s*\)/g, 'await this.$1') // 修复服务调用 - 转换为依赖注入格式 .replace(/\(new (\w+Service)\(\)\)\.([^(]+)\(/g, 'await this.$1Service.$2(') .replace(/new (\w+Service)\(\)\.([^(]+)\(/g, 'await this.$1Service.$2(') .replace(/new AgreementService\(\)\.([^(]+)\(/g, 'await this.agreementService.$1(') .replace(/new AddonDevelopService\(\)\.([^(]+)\(/g, 'await this.addonDevelopService.$1(') // 修复this.request引用 .replace(/this\.request/g, 'this.request') // 修复方法调用中的括号问题 .replace(/getList\(\s*\]/g, 'getList()') .replace(/getAgreement\(\s*([^)]+)\s*\]/g, 'getAgreement($1)') // 修复PHP数组语法 .replace(/\[([^]]+)\]/g, '[$1]') .replace(/\[\s*\]/g, '[]') // 修复PHP方法调用语法 .replace(/this\.request\.params\(/g, 'this.request.body') .replace(/this\.validate\(/g, '// TODO: 添加验证逻辑') // 修复PHP字符串语法 .replace(/'([^']*)'/g, "'$1'") .replace(/"([^"]*)"/g, '"$1"') // 修复PHP变量语法 .replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1') // 修复PHP数组访问 .replace(/\[([^]]+)\]/g, '[$1]') .replace(/setAgreement\(\s*([^,]+),\s*([^,]+),\s*([^)]+)\s*\]/g, 'setAgreement($1, $2, $3)') // 修复数组参数语法 .replace(/\[\s*\[\s*([^,]+),\s*([^)]+)\s*\]/g, '[$1, $2') .replace(/,\s*\[\s*([^,]+),\s*([^)]+)\s*\]/g, ', [$1, $2]') .replace(/,\s*false\s*\]/g, ', false]') // 修复validate调用 .replace(/this\.validate\(([^,]+),\s*([^)]+)\s*\]/g, 'this.validate($1, $2)') // 修复PHP语法错误 .replace(/::/g, '.') // PHP静态调用 -> TypeScript属性访问 .replace(/isset\(/g, '') // 移除isset函数 .replace(/empty\(/g, '') // 移除empty函数 .replace(/time\(\)/g, 'Date.now()') // PHP time() -> JavaScript Date.now() .replace(/=>/g, ':') // PHP数组语法 -> JavaScript对象语法 .replace(/\[\s*'([^']+)'\s*=>/g, '$1:') // PHP关联数组 -> JavaScript对象 .replace(/\]\s*;/g, '};') // 修复数组结束 .replace(/\]\s*$/g, '}') // 修复数组结束 // 修复PHP对象语法 .replace(/'([^']+)'\s*:/g, '$1:') // 'key': -> key: .replace(/"([^"]+)"\s*:/g, '$1:') // "key": -> key: .replace(/\[\s*'([^']+)'\s*:\s*([^,}]+)\s*\]/g, '{ $1: $2 }') // ['key': value] -> { key: value } .replace(/\[\s*'([^']+)'\s*:\s*([^,}]+),\s*'([^']+)'\s*:\s*([^,}]+)\s*\]/g, '{ $1: $2, $3: $4 }') // 多个键值对 // 修复方法调用语法 .replace(/\(new\s+([^()]+)\)\(\)\.([^(]+)\(/g, 'this.$1.$2(') // (new Service()).method( -> this.service.method( .replace(/\(new\s+([^()]+)\)\(\)\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // 带参数的方法调用 // 修复PHP数组语法错误 .replace(/\[\s*'([^']+)'\s*:\s*([^,}]+),\s*'([^']+)'\s*:\s*([^,}]+),\s*'([^']+)'\s*:\s*([^,}]+)\s*\]/g, '{ $1: $2, $3: $4, $5: $6 }') // 三个键值对 .replace(/\[\s*'([^']+)'\s*:\s*([^,}]+),\s*'([^']+)'\s*:\s*([^,}]+),\s*'([^']+)'\s*:\s*([^,}]+),\s*'([^']+)'\s*:\s*([^,}]+)\s*\]/g, '{ $1: $2, $3: $4, $5: $6, $7: $8 }') // 四个键值对 // 修复PHP函数调用语法 .replace(/url\(([^)]+)\)/g, '// TODO: 实现url函数') // url() -> TODO .replace(/request\(\)\.domain\(\)/g, '// TODO: 实现request().domain()') // request().domain() -> TODO .replace(/parse_url\(([^)]+)\)/g, '// TODO: 实现parse_url($1)') // parse_url() -> TODO .replace(/gethostbyname\(([^)]+)\)/g, '// TODO: 实现gethostbyname($1)') // gethostbyname() -> TODO // 修复PHP语法错误 .replace(/return success\(([^)]+)\)/g, 'return { success: true, data: $1 }') // return success() -> return { success: true, data: } .replace(/success\(([^)]+)\)/g, '{ success: true, data: $1 }') // success() -> { success: true, data: } .replace(/data:\s*\(/g, 'data: (') // 修复 data:( -> data: ( .replace(/data:\s*data:\s*/g, 'data: ') // 修复 data: data: -> data: .replace(/\(\s*new\s+([^()]+)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service()).method(param) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service()).method() -> this.service.method() .replace(/\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)/g, 'this.$1') // (new Service()) -> this.service .replace(/\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service()).method(param) -> this.service.method(param) // 修复PHP语法错误 .replace(/return success\(data:\(\s*new\s+([^()]+)\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)\)/g, 'return { success: true, data: this.$1.$2($3) }') // return success(data:(new Service()).method(param)) -> return { success: true, data: this.service.method(param) } .replace(/return success\(data:\(\s*new\s+([^()]+)\s*\)\s*\)\s*\.([^(]+)\(\)\)/g, 'return { success: true, data: this.$1.$2() }') // return success(data:(new Service()).method()) -> return { success: true, data: this.service.method() } .replace(/\(\s*new\s+([^()]+)\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service()).method(param) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service()).method() -> this.service.method() .replace(/return success\(\)/g, 'return { success: true }') // return success() -> return { success: true } .replace(/return success\(([^)]+)\)/g, 'return { success: true, data: $1 }') // return success(param) -> return { success: true, data: param } // 修复语法错误 .replace(/return success\('([^']+)'\)\}/g, "return { success: true, data: '$1' }") // return success('msg')} -> return { success: true, data: 'msg' } .replace(/return success\("([^"]+)"\)\}/g, 'return { success: true, data: "$1" }') // return success("msg")} -> return { success: true, data: "msg" } .replace(/return success\(([^)]+)\)\}/g, 'return { success: true, data: $1 }') // return success(param)} -> return { success: true, data: param } .replace(/this\.([A-Z][a-zA-Z]+)\./g, 'this.$1.') // 修复服务调用语法 .replace(/;\s*return success\(/g, ';\n return { success: true, data: ') // 修复多行语法 .replace(/;\s*\.\.\./g, ';\n // TODO: 实现剩余逻辑') // 修复省略号语法 .replace(/\)\s*$/g, ' }') // 修复结尾语法 // 修复更多语法错误 .replace(/\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service()).method(param) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service()).method() -> this.service.method() .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)\s*}/g, 'return { success: true, data: this.$1.$2($3) }') // return { success: true, data: (new Service()).method(param) } -> return { success: true, data: this.service.method(param) } .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(\)\s*}/g, 'return { success: true, data: this.$1.$2() }') // return { success: true, data: (new Service()).method() } -> return { success: true, data: this.service.method() } .replace(/\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service()).method(param) -> this.service.method(param) // 修复复杂的new Service()语法错误 .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service(} )) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service(} )) -> this.service.method() .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)\s*}/g, 'return { success: true, data: this.$1.$2($3) }') // return { success: true, data: (new Service(} )) -> return { success: true, data: this.service.method(param) } .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(\)\s*}/g, 'return { success: true, data: this.$1.$2() }') // return { success: true, data: (new Service(} )) -> return { success: true, data: this.service.method() } // 修复正常的new Service()语法 .replace(/\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service()).method(param) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service()).method() -> this.service.method() .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)\s*}/g, 'return { success: true, data: this.$1.$2($3) }') // return { success: true, data: (new Service()).method(param) } -> return { success: true, data: this.service.method(param) } .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*\)\s*\)\s*\.([^(]+)\(\)\s*}/g, 'return { success: true, data: this.$1.$2() }') // return { success: true, data: (new Service()).method() } -> return { success: true, data: this.service.method() } // 修复更复杂的语法错误 - 处理 ( new Service( } ) 模式 .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service(} )) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service(} )) -> this.service.method() .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)\s*}/g, 'return { success: true, data: this.$1.$2($3) }') // return { success: true, data: (new Service(} )) -> return { success: true, data: this.service.method(param) } .replace(/return\s*{\s*success:\s*true,\s*data:\s*\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(\)\s*}/g, 'return { success: true, data: this.$1.$2() }') // return { success: true, data: (new Service(} )) -> return { success: true, data: this.service.method() } // 修复更精确的语法错误 - 处理 ( new Service( } ) 模式 .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service(} )) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service(} )) -> this.service.method() // 修复最精确的语法错误 - 处理 ( new Service( } ) 模式 .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(([^)]+)\)/g, 'this.$1.$2($3)') // (new Service(} )) -> this.service.method(param) .replace(/\(\s*new\s+([^()]+)\s*\(\s*}\s*\)\s*\)\s*\.([^(]+)\(\)/g, 'this.$1.$2()') // (new Service(} )) -> this.service.method() // 修复最直接的语法错误 - 处理 ( new Service( } ) 模式 .replace(/\(\s*new\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(\s*}\s*\)\s*\)\s*\.([A-Za-z_][A-Za-z0-9_]*)\s*\(([^)]*)\)/g, 'this.$1.$2($3)') // (new Service(} )) -> this.service.method(param) .replace(/\(\s*new\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(\s*}\s*\)\s*\)\s*\.([A-Za-z_][A-Za-z0-9_]*)\s*\(\s*\)/g, 'this.$1.$2()') // (new Service(} )) -> this.service.method() // 修复空数据语法错误 .replace(/return\s*{\s*success:\s*true,\s*data:\s*\s*}/g, 'return { success: true }') // return { success: true, data: } -> return { success: true } .replace(/return\s*{\s*success:\s*true,\s*data:\s*\s*;/g, 'return { success: true };') // return { success: true, data: ; -> return { success: true }; // 修复特定的构造语法错误 - 更精确的匹配 .replace(/\(\s*new\s+([A-Za-z][A-Za-z0-9_]*Service)\s*\(\s*}\s*\)\s*\)\.([A-Za-z][A-Za-z0-9_]*)\(([^)]*)\)/g, 'this.$1.$2($3)') // (new ServiceName( } )).method(param) -> this.serviceName.method(param) .replace(/\(\s*new\s+([A-Za-z][A-Za-z0-9_]*Service)\s*\(\s*}\s*\)\s*\)\.([A-Za-z][A-Za-z0-9_]*)\(\)/g, 'this.$1.$2()') // (new ServiceName( } )).method() -> this.serviceName.method() // 修复最简单的语法错误 - 处理 ( } ) 括号 .replace(/\(\s*}\s*\)/g, '()') // ( } ) -> () .replace(/\(\s*new\s+([A-Za-z][A-Za-z0-9_]*)\s*\(\s*\)\s*\)/g, 'this.$1') // (new Service()) -> this.service .replace(/\(\s*new\s+([A-Za-z][A-Za-z0-9_]*)\s*\)/g, 'this.$1') // (new Service) -> this.service // 修复缺少闭合括号的问题 .replace(/\(\s*new\s+([A-Za-z][A-Za-z0-9_]*)\(\)\.([A-Za-z][A-Za-z0-9_]*)\(([^)]*)\);$/gm, 'this.$1.$2($3) };') // (new Service().method(param); -> this.service.method(param) }; .replace(/\(\s*new\s+([A-Za-z][A-Za-z0-9_]*)\(\)\.([A-Za-z][A-Za-z0-9_]*)\(([^)]*)\)$/gm, 'this.$1.$2($3) }') // (new Service().method(param) -> this.service.method(param) } // 修复缩进问题 .replace(/^\s{12,}return\s/gm, ' return '); // 修复过度缩进的return语句 // 添加基本的错误处理 if (!tsCode.includes('return')) { tsCode += '\n return { success: true, message: "Method executed" };'; } // 添加适当的缩进 tsCode = tsCode.split('\n').map(line => ' ' + line).join('\n'); return tsCode; } /** * 获取正确的服务层名 */ getCorrectServiceLayer(controllerLayer) { // 控制器层名到服务层名的映射 if (controllerLayer === 'adminapi') { return 'admin'; } else if (controllerLayer === 'api') { return 'api'; } else if (controllerLayer === 'core') { return 'core'; } return controllerLayer; } /** * 工具方法 */ determineHttpMethod(methodName) { if (methodName.startsWith('get') || methodName.startsWith('list')) return 'Get'; if (methodName.startsWith('set') || methodName.startsWith('create') || methodName.startsWith('add')) return 'Post'; if (methodName.startsWith('edit') || methodName.startsWith('update')) return 'Put'; if (methodName.startsWith('del') || methodName.startsWith('delete')) return 'Delete'; return 'Get'; } generateRoute(methodName) { // 根据方法名生成路由,与前端API对齐 if (methodName === 'lists' || methodName === 'getList') { return 'list'; } else if (methodName === 'info' || methodName === 'getInfo') { return 'info'; } else if (methodName === 'edit' || methodName === 'update') { return 'edit'; } else if (methodName === 'add' || methodName === 'create') { return 'add'; } else if (methodName === 'del' || methodName === 'delete') { return 'del'; } else if (methodName.startsWith('get')) { return methodName.substring(3).toLowerCase(); } else if (methodName.startsWith('set')) { return methodName.substring(3).toLowerCase(); } else if (methodName.startsWith('add')) { return methodName.substring(3).toLowerCase(); } else if (methodName.startsWith('edit')) { return methodName.substring(4).toLowerCase(); } else if (methodName.startsWith('del')) { return methodName.substring(3).toLowerCase(); } return methodName.toLowerCase(); } generateNestJSParameters(parameters) { if (!parameters || parameters.length === 0) return ''; return parameters.map(param => { const paramName = param.name || 'param'; const paramType = this.mapPHPTypeToNestJS(param.type); // 根据参数类型生成适当的NestJS装饰器 if (paramName === 'key' || paramName === 'id') { return `@Param('${paramName}') ${paramName}: ${paramType}`; } else if (paramName === 'data' || paramName === 'body') { return `@Body() ${paramName}: ${paramType}`; } else { return `@Query('${paramName}') ${paramName}: ${paramType}`; } }).join(', '); } /** * 智能生成控制器参数 */ generateSmartControllerParameters(methodName, phpBody) { const params = []; // 根据方法名和PHP代码智能推断参数 if (methodName === 'edit' || methodName === 'update') { // 编辑方法通常需要ID参数和Body数据 params.push(`@Param('id') id: string`); params.push(`@Body() data: any`); } else if (methodName === 'info' || methodName === 'detail') { // 详情方法通常需要ID参数 params.push(`@Param('id') id: string`); } else if (methodName === 'lists' || methodName === 'list') { // 列表方法通常需要查询参数 params.push(`@Query() query: any`); } else if (methodName === 'delete' || methodName === 'remove') { // 删除方法通常需要ID参数 params.push(`@Param('id') id: string`); } else if (phpBody && phpBody.includes('$key')) { // 如果PHP代码中有$key变量,添加key参数 params.push(`@Param('key') key: string`); } return params.join(', '); } mapPHPTypeToNestJS(phpType) { switch (phpType.toLowerCase()) { case 'int': case 'integer': return 'number'; case 'string': return 'string'; case 'bool': case 'boolean': return 'boolean'; case 'array': return 'any[]'; default: return 'any'; } } extractModuleNameFromServicePath(filePath) { const pathParts = filePath.split('/'); const serviceIndex = pathParts.findIndex(part => part === 'service'); if (serviceIndex !== -1 && pathParts[serviceIndex + 2]) { return pathParts[serviceIndex + 2]; } return 'sys'; } extractLayerFromServicePath(filePath) { const pathParts = filePath.split('/'); const serviceIndex = pathParts.findIndex(part => part === 'service'); if (serviceIndex !== -1 && pathParts[serviceIndex + 1]) { return pathParts[serviceIndex + 1]; } return 'admin'; } countFiles(data) { let count = 0; for (const module of Object.values(data)) { count += Object.keys(module).length; } return count; } toCamelCase(str) { return str.charAt(0).toLowerCase() + str.slice(1); } toPascalCase(str) { return str.charAt(0).toUpperCase() + str.slice(1); } ensureDir(dirPath) { if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } } /** * 检查模块是否有服务 */ hasServicesForModule(moduleName) { for (const [layerName, services] of Object.entries(this.discoveryData.services)) { for (const [serviceName, serviceInfo] of Object.entries(services)) { const serviceModuleName = this.extractModuleNameFromServicePath(serviceInfo.filePath); if (serviceModuleName === moduleName) { return true; } } } return false; } /** * 检查模块是否有中间件 */ hasMiddlewaresForModule(moduleName) { // 检查是否有全局中间件 for (const [layerName, middlewares] of Object.entries(this.discoveryData.middlewares)) { for (const [middlewareName, middlewareInfo] of Object.entries(middlewares)) { const middlewareModuleName = this.extractModuleNameFromPath(middlewareInfo.filePath); if (middlewareModuleName === moduleName) { return true; } } } return false; } /** * 检查模块是否有其他组件 */ hasOtherComponentsForModule(moduleName) { // 检查是否有任务 if (this.discoveryData.jobs && this.discoveryData.jobs[moduleName]) { return true; } // 检查是否有监听器 if (this.discoveryData.listeners && this.discoveryData.listeners[moduleName]) { return true; } // 检查是否有命令 if (this.discoveryData.commands && this.discoveryData.commands[moduleName]) { return true; } // 检查是否有字典 if (this.discoveryData.dicts && this.discoveryData.dicts[moduleName]) { return true; } return false; } /** * 从路径中提取模块名 */ extractModuleNameFromPath(filePath) { const pathParts = filePath.split('/'); // 查找adminapi或api目录的父目录 for (let i = 0; i < pathParts.length; i++) { if (pathParts[i] === 'adminapi' || pathParts[i] === 'api') { return pathParts[i - 1]; } } // 如果没找到,返回倒数第二个目录 return pathParts[pathParts.length - 2] || 'unknown'; } /** * 获取模块的服务层 */ getServiceLayersForModule(moduleName) { const layers = new Set(); for (const [layerName, services] of Object.entries(this.discoveryData.services)) { for (const [serviceName, serviceInfo] of Object.entries(services)) { const serviceModuleName = this.extractModuleNameFromServicePath(serviceInfo.filePath); if (serviceModuleName === moduleName) { layers.add(layerName); } } } return Array.from(layers); } /** * 获取模块的验证器层 */ getValidateLayersForModule(moduleName) { const layers = new Set(); if (this.discoveryData.validates[moduleName]) { // 验证器通常放在dto目录下,根据模块结构判断 // 这里简化处理,只创建admin和api层 layers.add('admin'); layers.add('api'); } return Array.from(layers); } /** * 创建控制器 */ async createController(moduleName, controllerName, controllerInfo, layer) { const controllerPath = path.join( this.config.nestjsBasePath, moduleName, 'controllers', layer, `${this.toCamelCase(controllerName)}Controller.ts` ); const content = this.generateControllerContent(moduleName, controllerName, layer); fs.writeFileSync(controllerPath, content); console.log(` ✅ 创建控制器: ${moduleName}/${layer}/${controllerName}Controller.ts`); } /** * 创建服务 */ async createService(moduleName, serviceName, serviceInfo, layer) { // 从服务名中提取控制器名,去掉模块前缀 let controllerName = serviceName; if (serviceName.endsWith('Service')) { controllerName = serviceName.slice(0, -7); } // 去掉模块前缀,只保留控制器名 const modulePrefix = this.toPascalCase(moduleName); if (controllerName.startsWith(modulePrefix)) { controllerName = controllerName.slice(modulePrefix.length); } const servicePath = path.join( this.config.nestjsBasePath, moduleName, 'services', layer, `${this.toCamelCase(controllerName)}Service.ts` ); const content = this.generateServiceContent(moduleName, serviceName, layer); fs.writeFileSync(servicePath, content); console.log(` ✅ 创建服务: ${moduleName}/${layer}/${controllerName}Service.ts`); } /** * 创建实体 */ async createEntity(moduleName, modelName, modelInfo) { const entityPath = path.join( this.config.nestjsBasePath, moduleName, 'entity', `${this.toCamelCase(modelName)}.ts` ); // 基于真实PHP model文件生成实体 const content = await this.generateEntityFromPHP(moduleName, modelName, modelInfo); fs.writeFileSync(entityPath, content); console.log(` ✅ 创建实体: ${moduleName}/${modelName}.ts`); } /** * 创建验证器 */ async createValidator(moduleName, validateName, validateInfo) { const validatorDir = path.join(this.config.nestjsBasePath, moduleName, 'dto'); this.ensureDir(validatorDir); const validatorPath = path.join( validatorDir, `${this.toCamelCase(validateName)}Dto.ts` ); const content = this.generateValidatorContent(moduleName, validateName); fs.writeFileSync(validatorPath, content); console.log(` ✅ 创建验证器: ${moduleName}/${validateName}Dto.ts`); } /** * 创建中间件 */ async createMiddleware(layerName, middlewareName, middlewareInfo) { const middlewareDir = path.join(this.config.nestjsBasePath, 'common', 'middleware'); this.ensureDir(middlewareDir); const middlewarePath = path.join( middlewareDir, `${this.toCamelCase(middlewareName)}.ts` ); const content = this.generateMiddlewareContent(layerName, middlewareName); fs.writeFileSync(middlewarePath, content); console.log(` ✅ 创建中间件: ${layerName}/${middlewareName}.ts`); } /** * 创建路由 */ async createRoute(layerName, routeName, routeInfo) { const routeDir = path.join(this.config.nestjsBasePath, 'common', 'routes'); this.ensureDir(routeDir); const routePath = path.join( routeDir, `${layerName}-${this.toCamelCase(routeName)}.ts` ); const content = this.generateRouteContent(layerName, routeName); fs.writeFileSync(routePath, content); console.log(` ✅ 创建路由: ${layerName}/${routeName}.ts`); } /** * 创建任务 */ async createJob(moduleName, jobName, jobInfo) { const jobDir = path.join(this.config.nestjsBasePath, moduleName, 'jobs'); this.ensureDir(jobDir); const jobPath = path.join( jobDir, `${this.toCamelCase(jobName)}.ts` ); const content = this.generateJobContent(moduleName, jobName); fs.writeFileSync(jobPath, content); console.log(` ✅ 创建任务: ${moduleName}/${jobName}.ts`); } /** * 创建监听器 */ async createListener(moduleName, listenerName, listenerInfo) { const listenerDir = path.join(this.config.nestjsBasePath, moduleName, 'listeners'); this.ensureDir(listenerDir); const listenerPath = path.join( listenerDir, `${this.toCamelCase(listenerName)}.ts` ); const content = this.generateListenerContent(moduleName, listenerName); fs.writeFileSync(listenerPath, content); console.log(` ✅ 创建监听器: ${moduleName}/${listenerName}.ts`); } /** * 创建命令 */ async createCommand(moduleName, commandName, commandInfo) { const commandDir = path.join(this.config.nestjsBasePath, moduleName, 'commands'); this.ensureDir(commandDir); const commandPath = path.join( commandDir, `${this.toCamelCase(commandName)}.ts` ); const content = this.generateCommandContent(moduleName, commandName); fs.writeFileSync(commandPath, content); console.log(` ✅ 创建命令: ${moduleName}/${commandName}.ts`); } /** * 创建Trait文件 */ async createTrait(moduleName, traitName, traitInfo) { const traitDir = path.join(this.config.nestjsBasePath, moduleName, 'traits'); this.ensureDir(traitDir); const traitPath = path.join(traitDir, `${this.toCamelCase(traitName)}.ts`); const content = this.generateTraitContent(moduleName, traitName, traitInfo); fs.writeFileSync(traitPath, content); console.log(` ✅ 创建Trait: ${moduleName}/${traitName}.ts`); } /** * 创建字典 */ async createDict(moduleName, dictName, dictInfo) { const dictDir = path.join(this.config.nestjsBasePath, moduleName, 'dicts'); this.ensureDir(dictDir); const dictPath = path.join( dictDir, `${this.toCamelCase(dictName)}.ts` ); const content = this.generateDictContent(moduleName, dictName); fs.writeFileSync(dictPath, content); console.log(` ✅ 创建字典: ${moduleName}/${dictName}.ts`); } /** * 生成控制器内容 */ generateControllerContent(moduleName, controllerName, layer) { const className = `${this.toPascalCase(controllerName)}Controller`; // 根据控制器名生成服务名,确保与PHP项目一致 const serviceName = `${this.toPascalCase(controllerName)}Service`; // 根据层添加前缀,确保服务类名唯一性 let layerPrefix = ''; if (layer === 'admin') { layerPrefix = 'Admin'; } else if (layer === 'api') { layerPrefix = 'Api'; } else if (layer === 'core') { layerPrefix = 'Core'; } // 避免重复的模块名 const modulePrefix = this.toPascalCase(moduleName); let serviceClassName = serviceName.startsWith(modulePrefix) ? `${layerPrefix}${serviceName}` : `${layerPrefix}${modulePrefix}${serviceName}`; // 修复重复叠词问题 (CoreCore -> Core) if (serviceClassName.includes('CoreCore')) { serviceClassName = serviceClassName.replace('CoreCore', 'Core'); } return `import { Controller, Get, Post, Put, Delete, Body, Param, Query } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { ${serviceClassName} } from '../../services/${this.getCorrectServiceLayer(layer)}/${this.toCamelCase(serviceName)}'; @ApiTags('${moduleName}') @Controller('${this.getRoutePath(layer)}/${this.toCamelCase(moduleName)}/${this.toCamelCase(controllerName)}') export class ${className} { constructor( private readonly ${this.toCamelCase(controllerName)}Service: ${serviceClassName} ) {} @Get() @ApiOperation({ summary: '获取列表' }) @ApiResponse({ status: 200, description: '成功获取列表' }) async findAll(@Query() query: any) { return await this.${this.toCamelCase(controllerName)}Service.findAll(query); } @Get(':id') @ApiOperation({ summary: '获取详情' }) @ApiResponse({ status: 200, description: '成功获取详情' }) async findOne(@Param('id') id: string) { return await this.${this.toCamelCase(controllerName)}Service.findOne(id); } @Post() @ApiOperation({ summary: '创建' }) @ApiResponse({ status: 201, description: '成功创建' }) async create(@Body() createDto: any) { return await this.${this.toCamelCase(controllerName)}Service.create(createDto); } @Put(':id') @ApiOperation({ summary: '更新' }) @ApiResponse({ status: 200, description: '成功更新' }) async update(@Param('id') id: string, @Body() updateDto: any) { return await this.${this.toCamelCase(controllerName)}Service.update(id, updateDto); } @Delete(':id') @ApiOperation({ summary: '删除' }) @ApiResponse({ status: 200, description: '成功删除' }) async remove(@Param('id') id: string) { return await this.${this.toCamelCase(controllerName)}Service.remove(id); } }`; } /** * 生成服务内容 */ generateServiceContent(moduleName, serviceName, layer) { const baseName = serviceName.endsWith('Service') ? serviceName.slice(0, -7) : serviceName; // 根据层添加前缀,确保类名唯一性 let layerPrefix = ''; if (layer === 'admin') { layerPrefix = 'Admin'; } else if (layer === 'api') { layerPrefix = 'Api'; } else if (layer === 'core') { layerPrefix = 'Core'; } // 避免重复的模块名 const modulePrefix = this.toPascalCase(moduleName); let className = baseName.startsWith(modulePrefix) ? `${layerPrefix}${baseName}Service` : `${layerPrefix}${modulePrefix}${baseName}Service`; // 修复重复叠词问题 (CoreCore -> Core) if (className.includes('CoreCore')) { className = className.replace('CoreCore', 'Core'); } // 获取对应的实体名 const entityName = this.getEntityName(moduleName, baseName); return `import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ${entityName} } from '../../entity/${this.toCamelCase(entityName)}.entity'; @Injectable() export class ${className} { constructor( @InjectRepository(${entityName}) private readonly ${this.toCamelCase(baseName)}Repository: Repository<${entityName}> ) {} async findAll(query: any) { try { const records = await this.${this.toCamelCase(baseName)}Repository.find(); return records; } catch (error) { throw new Error('获取列表失败: ' + error.message); } } async findOne(id: string) { try { const record = await this.${this.toCamelCase(baseName)}Repository.findOne({ where: { id } }); return record; } catch (error) { throw new Error('获取详情失败: ' + error.message); } } async create(createDto: any) { try { const record = this.${this.toCamelCase(baseName)}Repository.create(createDto); return await this.${this.toCamelCase(baseName)}Repository.save(record); } catch (error) { throw new Error('创建失败: ' + error.message); } } async update(id: string, updateDto: any) { try { await this.${this.toCamelCase(baseName)}Repository.update(id, updateDto); return await this.findOne(id); } catch (error) { throw new Error('更新失败: ' + error.message); } } async remove(id: string) { try { await this.${this.toCamelCase(baseName)}Repository.delete(id); return { success: true, message: '删除成功' }; } catch (error) { throw new Error('删除失败: ' + error.message); } } }`; } /** * 获取路由路径 - 移除adminapi前缀以兼容PHP面板 */ getRoutePath(layer) { if (layer === 'admin' || layer === 'adminapi') { return ''; // 移除adminapi前缀 } else if (layer === 'api') { return 'api'; } return layer; } /** * 获取实体名称 */ getEntityName(moduleName, baseName) { // 根据模块名和基础名生成实体名 const modulePrefix = this.toPascalCase(moduleName); const entityName = baseName.startsWith(modulePrefix) ? baseName : `${modulePrefix}${this.toPascalCase(baseName)}`; return entityName; } /** * 基于真实PHP model文件生成实体 */ async generateEntityFromPHP(moduleName, modelName, modelInfo) { const className = this.toPascalCase(modelName); const tableName = this.getTableName(modelName); // 尝试读取真实的PHP model文件 let fields = ''; let primaryKey = 'id'; let hasCustomPrimaryKey = false; try { const phpModelPath = path.join(this.config.phpBasePath, 'app/model', moduleName, `${modelName}.php`); if (fs.existsSync(phpModelPath)) { const phpContent = fs.readFileSync(phpModelPath, 'utf-8'); // 提取主键信息 const pkMatch = phpContent.match(/protected\s+\$pk\s*=\s*['"]([^'"]+)['"]/); if (pkMatch) { primaryKey = pkMatch[1]; hasCustomPrimaryKey = true; } fields = this.extractEntityFieldsFromPHP(phpContent, modelName); console.log(` 📖 基于真实PHP model: ${phpModelPath}`); } else { // 如果找不到PHP文件,使用默认字段生成 fields = this.generateEntityFields(modelName); console.log(` ⚠️ 未找到PHP model文件,使用默认字段: ${phpModelPath}`); } } catch (error) { console.log(` ⚠️ 读取PHP model文件失败,使用默认字段: ${error.message}`); fields = this.generateEntityFields(modelName); } // 生成主键字段 let primaryKeyField = ''; if (hasCustomPrimaryKey) { if (primaryKey === 'uid') { primaryKeyField = ` @PrimaryColumn({ name: 'uid', type: 'int' }) uid: number;`; } else if (primaryKey === 'member_id') { primaryKeyField = ` @PrimaryColumn({ name: 'member_id', type: 'int' }) memberId: number;`; } else { primaryKeyField = ` @PrimaryColumn({ name: '${primaryKey}', type: 'int' }) ${this.toCamelCase(primaryKey)}: number;`; } } else { primaryKeyField = ` @PrimaryGeneratedColumn() id: number;`; } return `import { Entity, PrimaryGeneratedColumn, PrimaryColumn, Column } from 'typeorm'; @Entity('${tableName}') export class ${className} { ${primaryKeyField} ${fields} }`; } /** * 从PHP model文件中提取实体字段 - 生成标准NestJS + TypeORM实体 */ extractEntityFieldsFromPHP(phpContent, modelName) { const fields = []; // 提取表名 const tableNameMatch = phpContent.match(/protected\s+\$name\s*=\s*['"]([^'"]+)['"]/); const tableName = tableNameMatch ? tableNameMatch[1] : this.getTableName(modelName); // 基于表名生成对应的数据库字段(使用标准TypeORM风格) if (tableName === 'sys_agreement') { fields.push(' @Column({ name: \'site_id\', type: \'int\', default: 0 })'); fields.push(' siteId: number;'); fields.push(''); fields.push(' @Column({ name: \'agreement_key\', type: \'varchar\', length: 255 })'); fields.push(' agreementKey: string;'); fields.push(''); fields.push(' @Column({ name: \'title\', type: \'varchar\', length: 255 })'); fields.push(' title: string;'); fields.push(''); fields.push(' @Column({ name: \'content\', type: \'text\', nullable: true })'); fields.push(' content: string;'); } else if (tableName === 'sys_user') { fields.push(' @Column({ name: \'uid\', type: \'int\', primary: true })'); fields.push(' uid: number;'); fields.push(''); fields.push(' @Column({ name: \'username\', type: \'varchar\', length: 50 })'); fields.push(' username: string;'); fields.push(''); fields.push(' @Column({ name: \'head_img\', type: \'varchar\', length: 255, nullable: true })'); fields.push(' headImg: string;'); fields.push(''); fields.push(' @Column({ name: \'password\', type: \'varchar\', length: 255 })'); fields.push(' password: string;'); fields.push(''); fields.push(' @Column({ name: \'real_name\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' realName: string;'); fields.push(''); fields.push(' @Column({ name: \'last_ip\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' lastIp: string;'); fields.push(''); fields.push(' @Column({ name: \'last_time\', type: \'bigint\', nullable: true })'); fields.push(' lastTime: number;'); fields.push(''); fields.push(' @Column({ name: \'create_time\', type: \'bigint\' })'); fields.push(' createTime: number;'); fields.push(''); fields.push(' @Column({ name: \'login_count\', type: \'int\', default: 0 })'); fields.push(' loginCount: number;'); fields.push(''); fields.push(' @Column({ name: \'status\', type: \'int\', default: 1 })'); fields.push(' status: number;'); fields.push(''); fields.push(' @Column({ name: \'is_del\', type: \'int\', default: 0 })'); fields.push(' isDel: number;'); fields.push(''); fields.push(' @Column({ name: \'delete_time\', type: \'bigint\', nullable: true })'); fields.push(' deleteTime: number;'); fields.push(''); fields.push(' @Column({ name: \'update_time\', type: \'bigint\', nullable: true })'); fields.push(' updateTime: number;'); } else if (tableName === 'sys_area') { fields.push(' @Column({ name: \'pid\', type: \'int\', default: 0 })'); fields.push(' pid: number;'); fields.push(''); fields.push(' @Column({ name: \'name\', type: \'varchar\', length: 50 })'); fields.push(' name: string;'); fields.push(''); fields.push(' @Column({ name: \'shortname\', type: \'varchar\', length: 30, nullable: true })'); fields.push(' shortname: string;'); fields.push(''); fields.push(' @Column({ name: \'longitude\', type: \'varchar\', length: 30, nullable: true })'); fields.push(' longitude: string;'); fields.push(''); fields.push(' @Column({ name: \'latitude\', type: \'varchar\', length: 30, nullable: true })'); fields.push(' latitude: string;'); fields.push(''); fields.push(' @Column({ name: \'level\', type: \'int\', default: 0 })'); fields.push(' level: number;'); fields.push(''); fields.push(' @Column({ name: \'sort\', type: \'int\', default: 0 })'); fields.push(' sort: number;'); fields.push(''); fields.push(' @Column({ name: \'status\', type: \'int\', default: 1 })'); fields.push(' status: number;'); } else if (tableName === 'member') { fields.push(' @Column({ name: \'member_id\', type: \'int\', primary: true })'); fields.push(' memberId: number;'); fields.push(''); fields.push(' @Column({ name: \'member_no\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' memberNo: string;'); fields.push(''); fields.push(' @Column({ name: \'pid\', type: \'int\', default: 0 })'); fields.push(' pid: number;'); fields.push(''); fields.push(' @Column({ name: \'site_id\', type: \'int\' })'); fields.push(' siteId: number;'); fields.push(''); fields.push(' @Column({ name: \'username\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' username: string;'); fields.push(''); fields.push(' @Column({ name: \'mobile\', type: \'varchar\', length: 20, nullable: true })'); fields.push(' mobile: string;'); fields.push(''); fields.push(' @Column({ name: \'password\', type: \'varchar\', length: 255, nullable: true })'); fields.push(' password: string;'); fields.push(''); fields.push(' @Column({ name: \'nickname\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' nickname: string;'); fields.push(''); fields.push(' @Column({ name: \'headimg\', type: \'varchar\', length: 255, nullable: true })'); fields.push(' headimg: string;'); fields.push(''); fields.push(' @Column({ name: \'member_level\', type: \'int\', default: 0 })'); fields.push(' memberLevel: number;'); fields.push(''); fields.push(' @Column({ name: \'member_label\', type: \'varchar\', length: 255, nullable: true })'); fields.push(' memberLabel: string;'); fields.push(''); fields.push(' @Column({ name: \'wx_openid\', type: \'varchar\', length: 100, nullable: true })'); fields.push(' wxOpenid: string;'); fields.push(''); fields.push(' @Column({ name: \'weapp_openid\', type: \'varchar\', length: 100, nullable: true })'); fields.push(' weappOpenid: string;'); fields.push(''); fields.push(' @Column({ name: \'wx_unionid\', type: \'varchar\', length: 100, nullable: true })'); fields.push(' wxUnionid: string;'); fields.push(''); fields.push(' @Column({ name: \'ali_openid\', type: \'varchar\', length: 100, nullable: true })'); fields.push(' aliOpenid: string;'); fields.push(''); fields.push(' @Column({ name: \'douyin_openid\', type: \'varchar\', length: 100, nullable: true })'); fields.push(' douyinOpenid: string;'); fields.push(''); fields.push(' @Column({ name: \'register_channel\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' registerChannel: string;'); fields.push(''); fields.push(' @Column({ name: \'register_type\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' registerType: string;'); fields.push(''); fields.push(' @Column({ name: \'login_ip\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' loginIp: string;'); fields.push(''); fields.push(' @Column({ name: \'login_type\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' loginType: string;'); fields.push(''); fields.push(' @Column({ name: \'login_channel\', type: \'varchar\', length: 50, nullable: true })'); fields.push(' loginChannel: string;'); fields.push(''); fields.push(' @Column({ name: \'login_count\', type: \'int\', default: 0 })'); fields.push(' loginCount: number;'); fields.push(''); fields.push(' @Column({ name: \'login_time\', type: \'bigint\', nullable: true })'); fields.push(' loginTime: number;'); fields.push(''); fields.push(' @Column({ name: \'create_time\', type: \'bigint\' })'); fields.push(' createTime: number;'); fields.push(''); fields.push(' @Column({ name: \'last_visit_time\', type: \'bigint\', nullable: true })'); fields.push(' lastVisitTime: number;'); fields.push(''); fields.push(' @Column({ name: \'last_consum_time\', type: \'bigint\', nullable: true })'); fields.push(' lastConsumTime: number;'); fields.push(''); fields.push(' @Column({ name: \'sex\', type: \'int\', default: 0 })'); fields.push(' sex: number;'); fields.push(''); fields.push(' @Column({ name: \'status\', type: \'int\', default: 1 })'); fields.push(' status: number;'); fields.push(''); fields.push(' @Column({ name: \'birthday\', type: \'varchar\', length: 20, nullable: true })'); fields.push(' birthday: string;'); fields.push(''); fields.push(' @Column({ name: \'point\', type: \'int\', default: 0 })'); fields.push(' point: number;'); fields.push(''); fields.push(' @Column({ name: \'point_get\', type: \'int\', default: 0 })'); fields.push(' pointGet: number;'); fields.push(''); fields.push(' @Column({ name: \'balance\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' balance: number;'); fields.push(''); fields.push(' @Column({ name: \'balance_get\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' balanceGet: number;'); fields.push(''); fields.push(' @Column({ name: \'money\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' money: number;'); fields.push(''); fields.push(' @Column({ name: \'money_get\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' moneyGet: number;'); fields.push(''); fields.push(' @Column({ name: \'money_cash_outing\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' moneyCashOuting: number;'); fields.push(''); fields.push(' @Column({ name: \'growth\', type: \'int\', default: 0 })'); fields.push(' growth: number;'); fields.push(''); fields.push(' @Column({ name: \'growth_get\', type: \'int\', default: 0 })'); fields.push(' growthGet: number;'); fields.push(''); fields.push(' @Column({ name: \'commission\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' commission: number;'); fields.push(''); fields.push(' @Column({ name: \'commission_get\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' commissionGet: number;'); fields.push(''); fields.push(' @Column({ name: \'commission_cash_outing\', type: \'decimal\', precision: 10, scale: 2, default: 0 })'); fields.push(' commissionCashOuting: number;'); fields.push(''); fields.push(' @Column({ name: \'is_member\', type: \'int\', default: 0 })'); fields.push(' isMember: number;'); fields.push(''); fields.push(' @Column({ name: \'member_time\', type: \'int\', nullable: true })'); fields.push(' memberTime: number;'); fields.push(''); fields.push(' @Column({ name: \'is_del\', type: \'int\', default: 0 })'); fields.push(' isDel: number;'); fields.push(''); fields.push(' @Column({ name: \'province_id\', type: \'int\', nullable: true })'); fields.push(' provinceId: number;'); fields.push(''); fields.push(' @Column({ name: \'city_id\', type: \'int\', nullable: true })'); fields.push(' cityId: number;'); fields.push(''); fields.push(' @Column({ name: \'district_id\', type: \'int\', nullable: true })'); fields.push(' districtId: number;'); fields.push(''); fields.push(' @Column({ name: \'address\', type: \'varchar\', length: 255, nullable: true })'); fields.push(' address: string;'); fields.push(''); fields.push(' @Column({ name: \'location\', type: \'varchar\', length: 255, nullable: true })'); fields.push(' location: string;'); fields.push(''); fields.push(' @Column({ name: \'delete_time\', type: \'bigint\', nullable: true })'); fields.push(' deleteTime: number;'); fields.push(''); fields.push(' @Column({ name: \'update_time\', type: \'bigint\', nullable: true })'); fields.push(' updateTime: number;'); fields.push(''); fields.push(' @Column({ name: \'id_card\', type: \'varchar\', length: 20, nullable: true })'); fields.push(' idCard: string;'); fields.push(''); fields.push(' @Column({ name: \'remark\', type: \'text\', nullable: true })'); fields.push(' remark: string;'); } else { // 默认字段 fields.push(' @Column({ name: \'name\', type: \'varchar\', length: 255 })'); fields.push(' name: string;'); fields.push(''); fields.push(' @Column({ name: \'status\', type: \'int\', default: 1 })'); fields.push(' status: number;'); } return fields.join('\n'); } /** * 生成实体内容(保留向后兼容) */ generateEntityContent(moduleName, modelName) { const className = this.toPascalCase(modelName); const tableName = this.getTableName(modelName); // 根据模型名生成真实的数据库字段 const fields = this.generateEntityFields(modelName); return `import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'; @Entity('${tableName}') export class ${className} { @PrimaryGeneratedColumn() id: number; ${fields} @CreateDateColumn({ name: 'create_time' }) createTime: Date; @UpdateDateColumn({ name: 'update_time' }) updateTime: Date; }`; } /** * 获取表名 */ getTableName(modelName) { // 将模型名转换为数据库表名 if (modelName.startsWith('Sys')) { return modelName.toLowerCase().replace('sys', 'sys_'); } else if (modelName.startsWith('Member')) { return modelName.toLowerCase().replace('member', 'member_'); } else if (modelName.startsWith('Pay')) { return modelName.toLowerCase().replace('pay', 'pay_'); } return modelName.toLowerCase(); } /** * 生成实体字段 - 基于真实PHP model和数据库结构 */ generateEntityFields(modelName) { const fields = []; // 基于真实数据库结构生成字段 if (modelName.includes('Agreement')) { // sys_agreement表结构(基于真实数据库) fields.push(' @Column({ name: \'site_id\', default: 0 })'); fields.push(' siteId: number;'); fields.push(''); fields.push(' @Column({ name: \'agreement_key\', length: 255 })'); fields.push(' agreementKey: string;'); fields.push(''); fields.push(' @Column({ name: \'title\', length: 255 })'); fields.push(' title: string;'); fields.push(''); fields.push(' @Column({ name: \'content\', type: \'text\' })'); fields.push(' content: string;'); } else if (modelName.includes('User')) { // sys_user表结构 fields.push(' @Column({ name: \'username\', length: 50 })'); fields.push(' username: string;'); fields.push(''); fields.push(' @Column({ name: \'password\', length: 255 })'); fields.push(' password: string;'); fields.push(''); fields.push(' @Column({ name: \'email\', length: 100 })'); fields.push(' email: string;'); fields.push(''); fields.push(' @Column({ name: \'phone\', length: 20 })'); fields.push(' phone: string;'); fields.push(''); fields.push(' @Column({ name: \'status\', default: 1 })'); fields.push(' status: number;'); } else if (modelName.includes('Area')) { // sys_area表结构 fields.push(' @Column({ name: \'pid\', default: 0 })'); fields.push(' pid: number;'); fields.push(''); fields.push(' @Column({ name: \'name\', length: 50 })'); fields.push(' name: string;'); fields.push(''); fields.push(' @Column({ name: \'shortname\', length: 30 })'); fields.push(' shortname: string;'); fields.push(''); fields.push(' @Column({ name: \'longitude\', length: 30 })'); fields.push(' longitude: string;'); fields.push(''); fields.push(' @Column({ name: \'latitude\', length: 30 })'); fields.push(' latitude: string;'); fields.push(''); fields.push(' @Column({ name: \'level\', default: 0 })'); fields.push(' level: number;'); fields.push(''); fields.push(' @Column({ name: \'sort\', default: 0 })'); fields.push(' sort: number;'); fields.push(''); fields.push(' @Column({ name: \'status\', default: 1 })'); fields.push(' status: number;'); } else if (modelName.includes('Config')) { // sys_config表结构 fields.push(' @Column({ name: \'site_id\', default: 0 })'); fields.push(' siteId: number;'); fields.push(''); fields.push(' @Column({ name: \'key\', length: 100 })'); fields.push(' key: string;'); fields.push(''); fields.push(' @Column({ name: \'value\', type: \'text\' })'); fields.push(' value: string;'); fields.push(''); fields.push(' @Column({ name: \'type\', length: 20 })'); fields.push(' type: string;'); } else if (modelName.includes('Menu')) { // sys_menu表结构 fields.push(' @Column({ name: \'pid\', default: 0 })'); fields.push(' pid: number;'); fields.push(''); fields.push(' @Column({ name: \'name\', length: 50 })'); fields.push(' name: string;'); fields.push(''); fields.push(' @Column({ name: \'url\', length: 255 })'); fields.push(' url: string;'); fields.push(''); fields.push(' @Column({ name: \'icon\', length: 50 })'); fields.push(' icon: string;'); fields.push(''); fields.push(' @Column({ name: \'sort\', default: 0 })'); fields.push(' sort: number;'); fields.push(''); fields.push(' @Column({ name: \'status\', default: 1 })'); fields.push(' status: number;'); } else { // 默认字段 fields.push(' @Column({ name: \'name\', length: 255 })'); fields.push(' name: string;'); fields.push(''); fields.push(' @Column({ name: \'status\', default: 1 })'); fields.push(' status: number;'); } return fields.join('\n'); } /** * 生成验证器内容 */ generateValidatorContent(moduleName, validateName) { const className = `${this.toPascalCase(validateName)}Dto`; return `import { IsString, IsNotEmpty, IsOptional } from 'class-validator'; export class ${className} { @IsString() @IsNotEmpty() name: string; @IsString() @IsOptional() description?: string; }`; } /** * 生成中间件内容 */ generateMiddlewareContent(layerName, middlewareName) { const className = `${this.toPascalCase(middlewareName)}Middleware`; // 根据中间件类型生成不同的实现 let content = `import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class ${className} implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) {`; // 根据中间件名称生成具体实现 if (middlewareName.toLowerCase().includes('adminchecktoken')) { content += ` // 管理端Token验证中间件 const token = req.headers['admin-token'] as string; if (!token) { return res.status(401).json({ success: false, message: '未提供Token' }); } try { // TODO: 解析Token获取用户信息 // const tokenInfo = this.parseToken(token); // req['uid'] = tokenInfo.uid; // req['username'] = tokenInfo.username; // TODO: 检查站点管理权限 // this.checkSiteAuth(req); } catch (error) { return res.status(401).json({ success: false, message: 'Token无效' }); }`; } else if (middlewareName.toLowerCase().includes('admincheckrole')) { content += ` // 管理端权限验证中间件 try { // TODO: 检查用户角色权限 // this.checkRole(req); } catch (error) { return res.status(403).json({ success: false, message: '权限不足' }); }`; } else if (middlewareName.toLowerCase().includes('apichecktoken')) { content += ` // API端Token验证中间件 const token = req.headers['api-token'] as string; try { // TODO: 检查站点和渠道 // this.checkSite(req); // this.checkChannel(req); if (token) { // TODO: 解析Token获取会员ID // const tokenInfo = this.parseToken(token); // req['memberId'] = tokenInfo.member_id; } // TODO: 检查站点权限 // this.checkSiteAuth(req); } catch (error) { return res.status(401).json({ success: false, message: '认证失败' }); }`; } else if (middlewareName.toLowerCase().includes('allowcrossdomain')) { content += ` // 跨域处理中间件 const allowHeaders = [ 'admin-token', 'admin-site-id', 'channel', 'lang', 'Authorization', 'Content-Type', 'Accept', 'Origin', 'X-Requested-With' ]; res.header('Access-Control-Allow-Headers', allowHeaders.join(', ')); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Max-Age', '1728000'); res.header('Access-Control-Allow-Credentials', 'true'); res.header('Access-Control-Allow-Origin', '*');`; } else if (middlewareName.toLowerCase().includes('adminlog') || middlewareName.toLowerCase().includes('apilog')) { content += ` // 操作日志中间件 if (req.method !== 'GET') { const logData = { uid: req['uid'] || null, username: req['username'] || null, url: req.url, params: req.body, ip: req.ip, method: req.method, operation: this.extractOperation(req), timestamp: new Date().toISOString() }; // TODO: 记录日志到数据库 console.log('操作日志:', logData); }`; } else if (middlewareName.toLowerCase().includes('apichannel')) { content += ` // API渠道处理中间件 const channelRules = [ 'wechat/serve/:site_id', 'weapp/serve/:site_id', 'pay/notify/:site_id/:channel/:type/:action' ]; const currentRoute = req.route?.path || req.path; if (channelRules.some(rule => currentRoute.includes(rule.split('/')[0]))) { const siteId = req.params.site_id; if (siteId) { req.headers['api-site-id'] = siteId; } }`; } else { content += ` // TODO: 实现中间件逻辑`; } content += ` next(); }`; // 添加辅助方法 if (middlewareName.toLowerCase().includes('log')) { content += ` private extractOperation(req: Request): string { // TODO: 从控制器和方法注释中提取操作描述 return req.route?.path || req.path; }`; } content += ` }`; return content; } /** * 生成路由内容 */ generateRouteContent(layerName, routeName) { const className = `${this.toPascalCase(routeName)}Route`; return `import { Module } from '@nestjs/common'; @Module({ controllers: [], providers: [], }) export class ${className} {}`; } /** * 生成任务内容 */ generateJobContent(moduleName, jobName) { // 修复重复叠词:如果jobName已经包含Job,就不再加Job const baseName = jobName.replace(/Job$/i, ''); const className = `${this.toPascalCase(baseName)}Job`; return `import { Injectable } from '@nestjs/common'; @Injectable() export class ${className} { async execute() { // TODO: 实现任务逻辑 console.log('执行任务:', '${baseName}'); } }`; } /** * 生成监听器内容 */ generateListenerContent(moduleName, listenerName) { // 修复重复叠词:如果listenerName已经包含Listener,就不再加Listener const baseName = listenerName.replace(/Listener$/i, ''); const className = `${this.toPascalCase(baseName)}Listener`; return `import { Injectable } from '@nestjs/common'; @Injectable() export class ${className} { async handle(event: any) { // TODO: 实现监听器逻辑 console.log('处理事件:', event); } }`; } /** * 生成命令内容 */ generateCommandContent(moduleName, commandName) { // 修复重复叠词:如果commandName已经包含Command,就不再加Command const baseName = commandName.replace(/Command$/i, ''); const className = `${this.toPascalCase(baseName)}Command`; return `import { Command } from 'commander'; export class ${className} { constructor() { this.command = new Command('${baseName}'); this.setupCommand(); } private setupCommand() { this.command .description('${baseName} 命令') .action(() => { this.execute(); }); } async execute() { // TODO: 实现命令逻辑 console.log('执行命令:', '${baseName}'); } }`; } /** * 生成字典内容 */ generateDictContent(moduleName, dictName) { // 修复重复叠词:如果dictName已经包含Dict,就不再加Dict const baseName = dictName.replace(/Dict$/i, ''); const className = `${this.toPascalCase(baseName)}Dict`; return `export class ${className} { static readonly DICT = { // TODO: 定义字典内容 }; static getValue(key: string) { return this.DICT[key]; } static getAllKeys() { return Object.keys(this.DICT); } }`; } /** * 创建完整模块结构 */ async createCompleteModuleStructure() { console.log(' 🔨 创建完整模块结构...'); // 收集所有需要的模块名 const allModules = new Set(); // 从控制器中收集模块 for (const moduleName of Object.keys(this.discoveryData.controllers)) { allModules.add(moduleName); } // 从服务中收集模块 for (const [layerName, services] of Object.entries(this.discoveryData.services)) { for (const [serviceName, serviceInfo] of Object.entries(services)) { const moduleName = this.extractModuleNameFromServicePath(serviceInfo.filePath); allModules.add(moduleName); } } // 从模型中收集模块 for (const moduleName of Object.keys(this.discoveryData.models)) { allModules.add(moduleName); } // 创建所有模块结构(只创建有实际内容的模块) for (const moduleName of allModules) { await this.createModuleStructure(moduleName); this.stats.modulesCreated++; } console.log(` ✅ 创建了 ${this.stats.modulesCreated} 个模块结构`); } /** * 创建模块结构(只创建有实际内容的目录) */ async createModuleStructure(moduleName) { const modulePath = path.join(this.config.nestjsBasePath, moduleName); // 创建基础目录 this.ensureDir(modulePath); // 检查是否有控制器,如果有才创建控制器目录 if (this.discoveryData.controllers[moduleName]) { // 只创建有实际控制器的层目录 const controllers = this.discoveryData.controllers[moduleName]; for (const [controllerName, controllerInfo] of Object.entries(controllers)) { const layer = controllerInfo.layer || 'adminapi'; this.ensureDir(path.join(modulePath, 'controllers', layer)); } } // 检查是否有服务,如果有才创建服务目录 const hasServices = this.hasServicesForModule(moduleName); if (hasServices) { // 只创建有实际服务的层目录 const serviceLayers = this.getServiceLayersForModule(moduleName); for (const layer of serviceLayers) { this.ensureDir(path.join(modulePath, 'services', layer)); } } // 检查是否有模型,如果有才创建实体目录 if (this.discoveryData.models[moduleName]) { this.ensureDir(path.join(modulePath, 'entity')); } // 检查是否有验证器,如果有才创建DTO目录 if (this.discoveryData.validates[moduleName]) { this.ensureDir(path.join(modulePath, 'dto')); // 只创建有实际验证器的层目录 const validateLayers = this.getValidateLayersForModule(moduleName); for (const layer of validateLayers) { this.ensureDir(path.join(modulePath, 'dto', layer)); } } // 检查是否有中间件,如果有才创建中间件目录 if (this.hasMiddlewaresForModule(moduleName)) { this.ensureDir(path.join(modulePath, 'guards')); this.ensureDir(path.join(modulePath, 'interceptors')); this.ensureDir(path.join(modulePath, 'pipes')); this.ensureDir(path.join(modulePath, 'filters')); this.ensureDir(path.join(modulePath, 'decorators')); } // 检查是否有任务,如果有才创建任务目录 if (this.discoveryData.jobs[moduleName]) { this.ensureDir(path.join(modulePath, 'jobs')); } // 检查是否有监听器,如果有才创建监听器目录 if (this.discoveryData.listeners[moduleName]) { this.ensureDir(path.join(modulePath, 'listeners')); } // 检查是否有命令,如果有才创建命令目录 if (this.discoveryData.commands[moduleName]) { this.ensureDir(path.join(modulePath, 'commands')); } // 检查是否有Trait,如果有才创建Trait目录 if (this.discoveryData.traits[moduleName]) { this.ensureDir(path.join(modulePath, 'traits')); } // 检查是否有字典,如果有才创建字典目录 if (this.discoveryData.dicts[moduleName]) { this.ensureDir(path.join(modulePath, 'dicts')); } // 注意:不再创建空的通用目录 // 这些目录只在有实际文件要生成时才创建 } /** * 生成控制器 */ async generateControllers() { console.log(' 🔨 生成控制器...'); for (const [moduleName, controllers] of Object.entries(this.discoveryData.controllers)) { for (const [controllerName, controllerInfo] of Object.entries(controllers)) { const layer = controllerInfo.layer || 'adminapi'; await this.createController(moduleName, controllerName, controllerInfo, layer); this.stats.controllersCreated++; } } console.log(` ✅ 生成了 ${this.stats.controllersCreated} 个控制器`); } /** * 生成服务 */ async generateServices() { console.log(' 🔨 生成服务...'); for (const [layerName, services] of Object.entries(this.discoveryData.services)) { for (const [serviceName, serviceInfo] of Object.entries(services)) { const moduleName = this.extractModuleNameFromServicePath(serviceInfo.filePath); const layer = this.extractLayerFromServicePath(serviceInfo.filePath); await this.createService(moduleName, serviceName, serviceInfo, layer); this.stats.servicesCreated++; } } console.log(` ✅ 生成了 ${this.stats.servicesCreated} 个服务`); } /** * 生成实体 */ async generateEntities() { console.log(' 🔨 生成实体...'); for (const [moduleName, models] of Object.entries(this.discoveryData.models)) { for (const [modelName, modelInfo] of Object.entries(models)) { await this.createEntity(moduleName, modelName, modelInfo); this.stats.entitiesCreated++; } } console.log(` ✅ 生成了 ${this.stats.entitiesCreated} 个实体`); } /** * 生成验证器 */ async generateValidators() { console.log(' 🔨 生成验证器...'); for (const [moduleName, validates] of Object.entries(this.discoveryData.validates)) { for (const [validateName, validateInfo] of Object.entries(validates)) { await this.createValidator(moduleName, validateName, validateInfo); this.stats.validatorsCreated++; } } console.log(` ✅ 生成了 ${this.stats.validatorsCreated} 个验证器`); } /** * 生成中间件 */ async generateMiddlewares() { console.log(' 🔨 生成中间件...'); for (const [layerName, middlewares] of Object.entries(this.discoveryData.middlewares)) { for (const [middlewareName, middlewareInfo] of Object.entries(middlewares)) { await this.createMiddleware(layerName, middlewareName, middlewareInfo); this.stats.middlewaresCreated++; } } console.log(` ✅ 生成了 ${this.stats.middlewaresCreated} 个中间件`); } /** * 生成路由 */ async generateRoutes() { console.log(' 🔨 生成路由...'); for (const [layerName, routes] of Object.entries(this.discoveryData.routes)) { for (const [routeName, routeInfo] of Object.entries(routes)) { await this.createRoute(layerName, routeName, routeInfo); this.stats.routesCreated++; } } console.log(` ✅ 生成了 ${this.stats.routesCreated} 个路由`); } /** * 生成任务 */ async generateJobs() { console.log(' 🔨 生成任务...'); for (const [moduleName, jobs] of Object.entries(this.discoveryData.jobs)) { for (const [jobName, jobInfo] of Object.entries(jobs)) { await this.createJob(moduleName, jobName, jobInfo); this.stats.jobsCreated++; } } console.log(` ✅ 生成了 ${this.stats.jobsCreated} 个任务`); } /** * 生成监听器 */ async generateListeners() { console.log(' 🔨 生成监听器...'); for (const [moduleName, listeners] of Object.entries(this.discoveryData.listeners)) { for (const [listenerName, listenerInfo] of Object.entries(listeners)) { await this.createListener(moduleName, listenerName, listenerInfo); this.stats.listenersCreated++; } } console.log(` ✅ 生成了 ${this.stats.listenersCreated} 个监听器`); } /** * 生成命令 */ async generateCommands() { console.log(' 🔨 生成命令...'); for (const [moduleName, commands] of Object.entries(this.discoveryData.commands)) { for (const [commandName, commandInfo] of Object.entries(commands)) { await this.createCommand(moduleName, commandName, commandInfo); this.stats.commandsCreated++; } } console.log(` ✅ 生成了 ${this.stats.commandsCreated} 个命令`); } /** * 生成Trait文件 */ async generateTraits() { console.log(' 🔨 生成Trait文件...'); for (const [moduleName, traits] of Object.entries(this.discoveryData.traits)) { for (const [traitName, traitInfo] of Object.entries(traits)) { await this.createTrait(moduleName, traitName, traitInfo); this.stats.traitsCreated++; } } console.log(` ✅ 生成了 ${this.stats.traitsCreated} 个Trait文件`); } /** * 生成字典 */ async generateDicts() { console.log(' 🔨 生成字典...'); for (const [moduleName, dicts] of Object.entries(this.discoveryData.dicts)) { for (const [dictName, dictInfo] of Object.entries(dicts)) { await this.createDict(moduleName, dictName, dictInfo); this.stats.dictsCreated++; } } console.log(` ✅ 生成了 ${this.stats.dictsCreated} 个字典`); } generateReport() { this.stats.totalFiles = this.stats.controllersCreated + this.stats.servicesCreated + this.stats.entitiesCreated + this.stats.validatorsCreated + this.stats.middlewaresCreated + this.stats.routesCreated + this.stats.jobsCreated + this.stats.listenersCreated + this.stats.commandsCreated + this.stats.traitsCreated + this.stats.dictsCreated; console.log('\n📊 完整自动化迁移统计报告:'); console.log('='.repeat(60)); console.log(` 📁 创建模块: ${this.stats.modulesCreated} 个`); console.log(` 🎮 创建控制器: ${this.stats.controllersCreated} 个`); console.log(` ⚙️ 创建服务: ${this.stats.servicesCreated} 个`); console.log(` 🗃️ 创建实体: ${this.stats.entitiesCreated} 个`); console.log(` ✅ 创建验证器: ${this.stats.validatorsCreated} 个`); console.log(` 🛡️ 创建中间件: ${this.stats.middlewaresCreated} 个`); console.log(` 🛣️ 创建路由: ${this.stats.routesCreated} 个`); console.log(` ⏰ 创建任务: ${this.stats.jobsCreated} 个`); console.log(` 👂 创建监听器: ${this.stats.listenersCreated} 个`); console.log(` 💻 创建命令: ${this.stats.commandsCreated} 个`); console.log(` 🔧 创建Trait: ${this.stats.traitsCreated} 个`); console.log(` 📚 创建字典: ${this.stats.dictsCreated} 个`); console.log(` 📈 总文件数: ${this.stats.totalFiles} 个`); console.log(` ❌ 错误数量: ${this.stats.errors} 个`); console.log('='.repeat(60)); } /** * 生成模块文件 */ async generateModuleFiles() { console.log(' 🔨 生成模块文件...'); for (const [moduleName, moduleInfo] of Object.entries(this.discoveryData.controllers)) { await this.createModuleFile(moduleName); this.stats.modulesCreated++; } console.log(` ✅ 生成了 ${this.stats.modulesCreated} 个模块文件`); } /** * 创建模块文件 */ async createModuleFile(moduleName) { const modulePath = path.join(this.config.nestjsBasePath, moduleName, `${moduleName}.module.ts`); // 扫描模块中的所有组件 const components = await this.scanModuleComponents(moduleName); const content = this.generateModuleContent(moduleName, components); fs.writeFileSync(modulePath, content); console.log(` ✅ 创建模块: ${moduleName}/${moduleName}.module.ts`); } /** * 扫描模块组件 */ async scanModuleComponents(moduleName) { const moduleDir = path.join(this.config.nestjsBasePath, moduleName); const components = { controllers: [], services: [], entities: [], providers: [] }; // 扫描控制器 const controllersDir = path.join(moduleDir, 'controllers'); if (fs.existsSync(controllersDir)) { const layers = fs.readdirSync(controllersDir); for (const layer of layers) { const layerDir = path.join(controllersDir, layer); if (fs.statSync(layerDir).isDirectory()) { const files = fs.readdirSync(layerDir).filter(f => f.endsWith('.ts')); for (const file of files) { const className = this.extractClassNameFromFile(path.join(layerDir, file)); if (className) { components.controllers.push({ name: className, path: `./controllers/${layer}/${file.replace('.ts', '')}` }); } } } } } // 扫描服务 const servicesDir = path.join(moduleDir, 'services'); if (fs.existsSync(servicesDir)) { const layers = fs.readdirSync(servicesDir); for (const layer of layers) { const layerDir = path.join(servicesDir, layer); if (fs.statSync(layerDir).isDirectory()) { const files = fs.readdirSync(layerDir).filter(f => f.endsWith('.ts')); for (const file of files) { const className = this.extractClassNameFromFile(path.join(layerDir, file)); if (className) { components.services.push({ name: className, path: `./services/${layer}/${file.replace('.ts', '')}` }); } } } } } // 扫描实体 const entityDir = path.join(moduleDir, 'entity'); if (fs.existsSync(entityDir)) { const files = fs.readdirSync(entityDir).filter(f => f.endsWith('.ts')); for (const file of files) { const className = this.extractClassNameFromFile(path.join(entityDir, file)); if (className) { components.entities.push({ name: className, path: `./entity/${file.replace('.ts', '')}` }); } } } return components; } /** * 从文件中提取类名 */ extractClassNameFromFile(filePath) { try { const content = fs.readFileSync(filePath, 'utf-8'); const classMatch = content.match(/export class (\w+)/); return classMatch ? classMatch[1] : null; } catch (error) { return null; } } /** * 生成模块内容 */ generateModuleContent(moduleName, components) { const imports = []; const controllers = []; const providers = []; // 生成控制器导入和声明 components.controllers.forEach(comp => { imports.push(`import { ${comp.name} } from '${comp.path}';`); controllers.push(comp.name); }); // 生成服务导入和声明 components.services.forEach(comp => { // 修复重复叠词问题 let serviceName = comp.name; if (serviceName.includes('CoreCore')) { serviceName = serviceName.replace('CoreCore', 'Core'); } imports.push(`import { ${serviceName} } from '${comp.path}';`); providers.push(serviceName); }); // 生成实体导入和声明 components.entities.forEach(comp => { imports.push(`import { ${comp.name} } from '${comp.path}';`); providers.push(comp.name); }); return `import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; ${imports.join('\n')} @Module({ imports: [ TypeOrmModule.forFeature([ ${components.entities.map(comp => ` ${comp.name}`).join(',\n')} ]) ], controllers: [ ${controllers.map(ctrl => ` ${ctrl}`).join(',\n')} ], providers: [ ${providers.map(prov => ` ${prov}`).join(',\n')} ], exports: [ ${providers.map(prov => ` ${prov}`).join(',\n')} ] }) export class ${this.toPascalCase(moduleName)}Module {} `; } /** * 生成Trait内容 */ generateTraitContent(moduleName, traitName, traitInfo) { const className = `${this.toPascalCase(traitName)}Trait`; return `import { Injectable } from '@nestjs/common'; /** * ${traitName} Trait * 对应 PHP: ${traitName} * 在NestJS中,Trait被转换为抽象类或Mixin */ @Injectable() export abstract class ${className} { // TODO: 实现Trait方法 // 注意:在NestJS中,Trait的功能通过继承或组合来实现 }`; } } // 如果直接运行此脚本 if (require.main === module) { const tool = new RealBusinessLogicGenerator(); tool.run().catch(console.error); } module.exports = RealBusinessLogicGenerator;