feat: 重构v1框架架构和清理整理
- 将preset.ts移动到config目录,符合架构规范 - 迁移php-tools到java-tools,参考Java架构而非PHP - 清理AI层文档,整合为单一README - 删除core层,专注boot和ai层 - 集成AI层与Boot层,实现100%组件集成 - 清理废弃js文件和临时报告文件 - 更新导入路径,保持代码一致性
This commit is contained in:
893
tools-v1/java-tools/generators/service-generator.js
Normal file
893
tools-v1/java-tools/generators/service-generator.js
Normal file
@@ -0,0 +1,893 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const BusinessLogicConverter = require('./business-logic-converter');
|
||||
|
||||
/**
|
||||
* ⚙️ 服务生成器
|
||||
* 专门负责生成和更新NestJS服务
|
||||
*/
|
||||
class ServiceGenerator {
|
||||
constructor() {
|
||||
this.config = {
|
||||
javaBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-java/niucloud-core/src/main/java',
|
||||
phpBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-php/niucloud', // 用于业务逻辑提取
|
||||
nestjsBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/libs/wwjcloud-core/src',
|
||||
discoveryResultPath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/tools-v1/java-tools/java-discovery-result.json'
|
||||
};
|
||||
|
||||
this.discoveryData = null;
|
||||
this.converter = new BusinessLogicConverter();
|
||||
this.stats = {
|
||||
servicesCreated: 0,
|
||||
servicesUpdated: 0,
|
||||
methodsProcessed: 0,
|
||||
errors: 0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行服务生成
|
||||
*/
|
||||
async run() {
|
||||
console.log('⚙️ 启动服务生成器...');
|
||||
|
||||
try {
|
||||
// 加载发现数据
|
||||
await this.loadDiscoveryData();
|
||||
|
||||
// 生成服务
|
||||
await this.generateServices();
|
||||
|
||||
// 更新服务为真实业务逻辑
|
||||
await this.updateAllServicesWithRealLogic();
|
||||
|
||||
// 生成统计报告
|
||||
this.generateStatsReport();
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 服务生成过程中发生错误:', error.message);
|
||||
this.stats.errors++;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载Java架构发现结果(含PHP业务逻辑)
|
||||
*/
|
||||
async loadDiscoveryData() {
|
||||
try {
|
||||
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf-8');
|
||||
this.discoveryData = JSON.parse(data);
|
||||
console.log(' ✅ 成功加载Java架构发现结果(含PHP业务逻辑)');
|
||||
} catch (error) {
|
||||
console.error(' ❌ 加载发现数据失败:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按模块动态扫描Java服务层结构,参考Java框架架构
|
||||
*/
|
||||
async scanJavaModulesAndGenerateServices() {
|
||||
console.log(' 🔨 扫描Java框架架构,生成对应的NestJS服务...');
|
||||
|
||||
const javaServicePath = path.join(this.config.javaBasePath, 'com/niu/core/service');
|
||||
const layers = ['core', 'admin', 'api'];
|
||||
let processedCount = 0;
|
||||
|
||||
// 收集所有模块 - 从Java项目中扫描
|
||||
const modules = new Set();
|
||||
for (const layer of layers) {
|
||||
const layerPath = path.join(javaServicePath, layer);
|
||||
if (fs.existsSync(layerPath)) {
|
||||
try {
|
||||
const moduleDirs = fs.readdirSync(layerPath, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
moduleDirs.forEach(module => modules.add(module));
|
||||
console.log(` 📁 发现Java ${layer}层模块: ${moduleDirs.join(', ')}`);
|
||||
} catch (error) {
|
||||
console.log(` ⚠️ 无法读取Java ${layer}层目录: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` 📊 发现 ${modules.size} 个模块: ${Array.from(modules).join(', ')}`);
|
||||
|
||||
// 为每个模块生成服务 - 按照Java的@Service + @Resource模式
|
||||
for (const moduleName of modules) {
|
||||
console.log(` 🔍 处理模块: ${moduleName} (参考Java架构)`);
|
||||
|
||||
// 检查模块在各层的存在性 - 扫描Java service/core, service/admin, service/api结构
|
||||
const moduleLayers = [];
|
||||
for (const layer of layers) {
|
||||
const moduleServicePath = path.join(javaServicePath, layer, moduleName);
|
||||
if (fs.existsSync(moduleServicePath)) {
|
||||
try {
|
||||
const files = fs.readdirSync(moduleServicePath, { withFileTypes: true });
|
||||
const javaFiles = files
|
||||
.filter(dirent => dirent.isFile() && dirent.name.endsWith('.java') && dirent.name.includes('Impl'))
|
||||
.map(dirent => dirent.name);
|
||||
if (javaFiles.length > 0) {
|
||||
moduleLayers.push({
|
||||
layer,
|
||||
serviceFiles: javaFiles,
|
||||
servicePath: moduleServicePath
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(` ⚠️ 无法读取Java模块${moduleName}/${layer}目录: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleLayers.length === 0) {
|
||||
console.log(` ⚠️ 模块 ${moduleName} 没有任何Java服务文件,跳过`);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(` 📁 模块 ${moduleName} 有 ${moduleLayers.length} 个Java服务层: ${moduleLayers.map(l => l.layer).join(', ')}`);
|
||||
|
||||
// 为每个Java服务层生成对应的NestJS服务 - 按Java架构处理core依赖
|
||||
for (const { layer, serviceFiles, servicePath } of moduleLayers) {
|
||||
for (const serviceFile of serviceFiles) {
|
||||
const javaServicePath = path.join(servicePath, serviceFile);
|
||||
|
||||
console.log(` ⚙️ 处理Java服务: ${moduleName}/${layer}/${serviceFile} -> NestJS`);
|
||||
|
||||
try {
|
||||
await this.createNestJSServiceFromJava(moduleName, serviceFile, javaServicePath, layer);
|
||||
processedCount++;
|
||||
console.log(` ✅ 成功创建NestJS服务: ${moduleName}/${layer}/${serviceFile}`);
|
||||
} catch (error) {
|
||||
console.error(` ❌ 创建NestJS服务失败 ${moduleName}/${layer}/${serviceFile}:`, error.message);
|
||||
this.stats.errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.stats.servicesCreated = processedCount;
|
||||
console.log(` ✅ 创建了 ${this.stats.servicesCreated} 个服务`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成服务
|
||||
*/
|
||||
async generateServices() {
|
||||
console.log(' 🔨 生成服务文件...');
|
||||
|
||||
// 优先扫描Java项目架构,参考Java的@Service和Core依赖模式
|
||||
await this.scanJavaModulesAndGenerateServices();
|
||||
|
||||
// 如果发现数据存在,也尝试基于发现数据生成(作为备选)
|
||||
if (this.discoveryData.services && Object.keys(this.discoveryData.services).length > 0) {
|
||||
console.log(' 🔄 基于发现数据补充生成服务...');
|
||||
await this.generateServicesFromDiscovery();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于发现数据生成服务(备选方法)
|
||||
*/
|
||||
async generateServicesFromDiscovery() {
|
||||
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);
|
||||
|
||||
// 检查Java架构是否有对应的服务目录
|
||||
if (!this.hasPHPServices(correctModuleName, layer)) {
|
||||
console.log(` ⚠️ 模块 ${correctModuleName} 在Java架构中无对应,且PHP项目中也无${layer}服务,跳过`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await this.createService(correctModuleName, serviceName, serviceInfo, layer);
|
||||
processedCount++;
|
||||
console.log(` ✅ 成功创建服务: ${correctModuleName}/${serviceName}`);
|
||||
} catch (error) {
|
||||
console.error(` ❌ 创建服务失败 ${serviceName}:`, error.message);
|
||||
this.stats.errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` ✅ 基于发现数据创建了 ${processedCount} 个服务`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有服务为真实业务逻辑
|
||||
*/
|
||||
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 createService(moduleName, serviceName, serviceInfo, layer) {
|
||||
// 先去掉层级后缀,再去掉Service后缀
|
||||
const cleanServiceName = serviceName.replace(/_(admin|api|core)$/, '');
|
||||
const baseName = cleanServiceName.endsWith('Service') ? cleanServiceName.slice(0, -7) : cleanServiceName;
|
||||
const servicePath = path.join(
|
||||
this.config.nestjsBasePath,
|
||||
moduleName,
|
||||
'services',
|
||||
layer,
|
||||
`${this.toKebabCase(baseName)}.service.ts`
|
||||
);
|
||||
|
||||
// 确保目录存在
|
||||
const serviceDir = path.dirname(servicePath);
|
||||
if (!fs.existsSync(serviceDir)) {
|
||||
fs.mkdirSync(serviceDir, { recursive: true });
|
||||
}
|
||||
|
||||
// 检查是否有对应的PHP服务文件
|
||||
// 从服务名中提取基础类名(去掉_layer后缀)
|
||||
const baseServiceName = serviceName.replace(/_(admin|api|core)$/, '');
|
||||
const phpServicePath = path.join(this.config.phpBasePath, 'app/service', layer, moduleName, `${baseServiceName}.php`);
|
||||
if (!fs.existsSync(phpServicePath)) {
|
||||
console.log(` ❌ 未找到PHP服务文件,跳过生成: ${phpServicePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 生成基础服务内容
|
||||
const serviceContent = this.generateBasicServiceContent(moduleName, serviceName, layer);
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(servicePath, serviceContent);
|
||||
console.log(` ✅ 创建服务: ${moduleName}/${layer}/${this.toKebabCase(baseName)}.service.ts`);
|
||||
|
||||
this.stats.servicesCreated++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Java服务文件创建NestJS服务 - 参考Java架构,处理core依赖
|
||||
*/
|
||||
async createNestJSServiceFromJava(moduleName, javaServiceFile, javaFilePath, layer) {
|
||||
// 确保服务目录存在
|
||||
const serviceDir = path.join(
|
||||
this.config.nestjsBasePath,
|
||||
moduleName,
|
||||
'services',
|
||||
layer
|
||||
);
|
||||
|
||||
// 从Java文件名提取服务名,去掉Impl和Service后缀
|
||||
let serviceName = javaServiceFile.replace('.java', '');
|
||||
if (serviceName.endsWith('ServiceImpl')) {
|
||||
serviceName = serviceName.replace('ServiceImpl', '');
|
||||
} else if (serviceName.endsWith('Service')) {
|
||||
serviceName = serviceName.replace('Service', '');
|
||||
}
|
||||
|
||||
const servicePath = path.join(serviceDir, `${this.toKebabCase(serviceName)}.service.ts`);
|
||||
|
||||
// 检查文件是否已存在
|
||||
if (fs.existsSync(servicePath)) {
|
||||
console.log(` ⚠️ 服务文件已存在: ${servicePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 读取Java服务文件
|
||||
const javaContent = fs.readFileSync(javaFilePath, 'utf-8');
|
||||
|
||||
// 解析Java服务的依赖关系,特别是core服务依赖
|
||||
const coreDependencies = this.extractCoreDependencies(javaContent);
|
||||
const javaMethods = this.extractJavaMethods(javaContent);
|
||||
|
||||
console.log(` 📝 从${path.basename(javaFilePath)}中找到 ${javaMethods.length} 个方法`);
|
||||
console.log(` 🔗 发现Core依赖: ${coreDependencies.join(', ')}`);
|
||||
|
||||
// 生成NestJS服务内容,处理core依赖
|
||||
const nestjsContent = this.generateNestJSServiceFromJava(moduleName, serviceName, layer, javaMethods, coreDependencies);
|
||||
|
||||
// 确保目录存在
|
||||
if (!fs.existsSync(serviceDir)) {
|
||||
fs.mkdirSync(serviceDir, { recursive: true });
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(servicePath, nestjsContent, 'utf-8');
|
||||
console.log(` ✅ 创建NestJS服务: ${moduleName}/${layer}/${this.toKebabCase(serviceName)}.service.ts`);
|
||||
|
||||
this.stats.methodsProcessed += javaMethods.length;
|
||||
this.stats.servicesCreated++;
|
||||
|
||||
} catch (error) {
|
||||
console.log(` ❌ 无法创建NestJS服务 ${serviceName}: ${error.message}`);
|
||||
this.stats.errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从PHP文件创建NestJS服务 - 参考Java架构,使用V1框架基础设施
|
||||
*/
|
||||
async createNestJSServiceFromPHP(moduleName, serviceName, phpFilePath, layer) {
|
||||
// 确保服务目录存在
|
||||
const serviceDir = path.join(
|
||||
this.config.nestjsBasePath,
|
||||
moduleName,
|
||||
'services',
|
||||
layer
|
||||
);
|
||||
|
||||
// 先去掉Service后缀
|
||||
const baseName = serviceName.endsWith('Service') ? serviceName.slice(0, -7) : serviceName;
|
||||
const servicePath = path.join(serviceDir, `${this.toKebabCase(baseName)}.service.ts`);
|
||||
|
||||
// 检查文件是否已存在
|
||||
if (fs.existsSync(servicePath)) {
|
||||
console.log(` ⚠️ 服务文件已存在: ${servicePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 读取PHP服务文件
|
||||
const phpContent = fs.readFileSync(phpFilePath, 'utf-8');
|
||||
|
||||
// 提取PHP方法
|
||||
const phpMethods = this.converter.extractPHPMethods(phpContent);
|
||||
|
||||
console.log(` 📝 从${path.basename(phpFilePath)}中找到 ${phpMethods.length} 个PHP方法`);
|
||||
|
||||
// 生成NestJS服务内容
|
||||
const nestjsContent = phpMethods.length > 0
|
||||
? this.generateRealServiceContent(moduleName, serviceName, layer, phpMethods)
|
||||
: this.generateBasicServiceContent(moduleName, serviceName, layer);
|
||||
|
||||
// 确保目录存在
|
||||
if (!fs.existsSync(serviceDir)) {
|
||||
fs.mkdirSync(serviceDir, { recursive: true });
|
||||
}
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(servicePath, nestjsContent, 'utf-8');
|
||||
console.log(` ✅ 创建服务: ${moduleName}/${layer}/${this.toKebabCase(baseName)}.service.ts`);
|
||||
|
||||
this.stats.methodsProcessed += phpMethods.length;
|
||||
this.stats.servicesCreated++;
|
||||
|
||||
} catch (error) {
|
||||
console.log(` ❌ 无法创建服务 ${serviceName}: ${error.message}`);
|
||||
this.stats.errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新服务为真实逻辑
|
||||
*/
|
||||
async updateServiceWithRealLogic(moduleName, serviceName, serviceInfo, layer) {
|
||||
// 先去掉层级后缀,再去掉Service后缀
|
||||
const cleanServiceName = serviceName.replace(/_(admin|api|core)$/, '');
|
||||
const baseName = cleanServiceName.endsWith('Service') ? cleanServiceName.slice(0, -7) : cleanServiceName;
|
||||
const servicePath = path.join(
|
||||
this.config.nestjsBasePath,
|
||||
moduleName,
|
||||
'services',
|
||||
layer,
|
||||
`${this.toKebabCase(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.converter.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}/${this.toKebabCase(baseName)}.service.ts`);
|
||||
|
||||
this.stats.methodsProcessed += phpMethods.length;
|
||||
|
||||
} catch (error) {
|
||||
console.log(` ❌ 无法更新服务 ${serviceName}: ${error.message}`);
|
||||
this.stats.errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成基础服务内容
|
||||
*/
|
||||
generateBasicServiceContent(moduleName, serviceName, layer) {
|
||||
// 先去掉层级后缀,再去掉Service后缀
|
||||
const cleanServiceName = serviceName.replace(/_(admin|api|core)$/,'');
|
||||
const baseName = cleanServiceName.endsWith('Service') ? cleanServiceName.slice(0, -7) : cleanServiceName;
|
||||
|
||||
// 正确的命名规范:服务类名(与PHP/Java保持一致)
|
||||
let className = `${baseName}Service`;
|
||||
if (layer === 'core') {
|
||||
// Core层服务需要Core前缀
|
||||
className = baseName.startsWith('Core') ? `${baseName}Service` : `Core${baseName}Service`;
|
||||
} else {
|
||||
// admin和api层直接使用业务名称
|
||||
className = `${baseName}Service`;
|
||||
}
|
||||
|
||||
// 获取V1框架基础设施和Vendor服务导入
|
||||
const infrastructureImports = this.getV1FrameworkInfrastructureImports();
|
||||
const vendorImports = this.getV1FrameworkVendorImports();
|
||||
|
||||
return `import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
${infrastructureImports}
|
||||
${vendorImports}
|
||||
|
||||
/**
|
||||
* ${className} - ${layer}层服务
|
||||
* 参考Java Spring Boot架构:@Service注解 + 依赖注入
|
||||
* 对应Java: @Service + @Resource注入,类似CoreAliappConfigServiceImpl
|
||||
* 使用V1框架基础设施:CacheService, MetricsService, TenantService等
|
||||
* 业务逻辑来源:PHP ${moduleName}/${layer}层服务
|
||||
*/
|
||||
@Injectable()
|
||||
export class ${className} {
|
||||
private readonly logger = new Logger(${className}.name);
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Object)
|
||||
private readonly repository: Repository<any>,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly metricsService: MetricsService,
|
||||
private readonly tenantService: TenantService,
|
||||
private readonly uploadService: UploadService,
|
||||
private readonly payService: PayService,
|
||||
private readonly smsService: SmsService,
|
||||
private readonly noticeService: NoticeService,
|
||||
) {}
|
||||
|
||||
// 服务方法基于Java框架风格,直接从PHP业务逻辑迁移
|
||||
// 使用V1框架提供的服务:configService, cacheService, metricsService等
|
||||
}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取V1框架基础设施导入 - 基于实际V1框架导出
|
||||
*/
|
||||
getV1FrameworkInfrastructureImports() {
|
||||
return `import { ConfigService } from '@nestjs/config';
|
||||
import { CacheService } from '@wwjcloud-boot/infra/cache/cache.service';
|
||||
import { MetricsService } from '@wwjcloud-boot/infra/metrics/metrics.service';
|
||||
import { TenantService } from '@wwjcloud-boot/infra/tenant/tenant.service';`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取V1框架Vendor服务导入 - 基于实际V1框架vendor导出
|
||||
*/
|
||||
getV1FrameworkVendorImports() {
|
||||
return `import { UploadService } from '@wwjcloud-boot/vendor/upload';
|
||||
import { PayService } from '@wwjcloud-boot/vendor/pay';
|
||||
import { SmsService } from '@wwjcloud-boot/vendor/sms';
|
||||
import { NoticeService } from '@wwjcloud-boot/vendor/notice';`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成真实服务内容
|
||||
*/
|
||||
generateRealServiceContent(moduleName, serviceName, layer, phpMethods) {
|
||||
// 先去掉层级后缀,再去掉Service后缀
|
||||
const cleanServiceName = serviceName.replace(/_(admin|api|core)$/, '');
|
||||
const baseName = cleanServiceName.endsWith('Service') ? cleanServiceName.slice(0, -7) : cleanServiceName;
|
||||
|
||||
// 正确的命名规范:服务类名(与PHP/Java保持一致)
|
||||
let className = `${baseName}Service`;
|
||||
if (layer === 'core') {
|
||||
// Core层服务需要Core前缀
|
||||
className = baseName.startsWith('Core') ? `${baseName}Service` : `Core${baseName}Service`;
|
||||
} else {
|
||||
// admin和api层直接使用业务名称
|
||||
className = `${baseName}Service`;
|
||||
}
|
||||
|
||||
const methodImplementations = phpMethods.filter(method => method && method.name).map(method => {
|
||||
console.log(`🔍 调试参数: ${method.name}`, method.parameters);
|
||||
const parameters = this.converter.generateServiceParameters(method.parameters);
|
||||
const realLogic = this.generateRealServiceLogic(method);
|
||||
const logic = method.logic || { type: 'real', description: '基于真实PHP业务逻辑' };
|
||||
|
||||
return ` /**
|
||||
* ${method.name}
|
||||
* 对应 PHP: ${serviceName}::${method.name}()
|
||||
* 逻辑类型: ${logic.type} - ${logic.description}
|
||||
*/
|
||||
async ${method.name}(${parameters}) {
|
||||
${realLogic}
|
||||
}`;
|
||||
}).join('\n\n');
|
||||
|
||||
const infrastructureImports = this.getV1FrameworkInfrastructureImports();
|
||||
const vendorImports = this.getV1FrameworkVendorImports();
|
||||
|
||||
return `import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
${infrastructureImports}
|
||||
${vendorImports}
|
||||
|
||||
/**
|
||||
* ${className} - ${layer}层服务
|
||||
* 参考Java Spring Boot架构:@Service + @Resource模式
|
||||
* 对应Java实现:类似CoreAliappConfigServiceImpl的结构
|
||||
* 使用V1框架基础设施:CacheService, MetricsService, TenantService
|
||||
* 业务逻辑迁移自:PHP ${moduleName}/${layer}层服务
|
||||
*/
|
||||
@Injectable()
|
||||
export class ${className} {
|
||||
private readonly logger = new Logger(${className}.name);
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Object)
|
||||
private readonly repository: Repository<any>,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly metricsService: MetricsService,
|
||||
private readonly tenantService: TenantService,
|
||||
private readonly uploadService: UploadService,
|
||||
private readonly payService: PayService,
|
||||
private readonly smsService: SmsService,
|
||||
private readonly noticeService: NoticeService,
|
||||
) {}
|
||||
|
||||
${methodImplementations}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成真实服务逻辑
|
||||
*/
|
||||
generateRealServiceLogic(method) {
|
||||
if (!method || !method.name) {
|
||||
return ` // 方法信息缺失
|
||||
return { success: false, message: "Method information missing" };`;
|
||||
}
|
||||
|
||||
// 使用method.logic而不是method.body
|
||||
const phpLogic = method.logic || method.body || '';
|
||||
|
||||
if (!phpLogic.trim()) {
|
||||
return ` // TODO: 实现${method.name}业务逻辑
|
||||
throw new Error('${method.name} not implemented');`;
|
||||
}
|
||||
|
||||
// 转换PHP代码到TypeScript
|
||||
const tsBody = this.converter.convertBusinessLogic('', method.name, phpLogic);
|
||||
|
||||
return ` // 基于PHP真实逻辑: ${method.name}
|
||||
// PHP原文: ${phpLogic.substring(0, 150).replace(/\n/g, ' ')}...
|
||||
${tsBody}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从服务路径提取模块名
|
||||
*/
|
||||
extractModuleNameFromServicePath(filePath) {
|
||||
// 从路径中提取模块名
|
||||
const pathParts = filePath.split('/');
|
||||
const serviceIndex = pathParts.findIndex(part => part === 'service');
|
||||
|
||||
if (serviceIndex > 0 && serviceIndex < pathParts.length - 2) {
|
||||
// service目录后面应该是层级(admin/api/core),再后面是模块名
|
||||
// 路径格式: .../app/service/admin/home/AuthSiteService.php
|
||||
// 索引: .../8 9 10 11 12
|
||||
return pathParts[serviceIndex + 2];
|
||||
}
|
||||
|
||||
// 如果找不到service目录,尝试从文件名推断
|
||||
const fileName = path.basename(filePath, '.php');
|
||||
if (fileName.includes('Service')) {
|
||||
return fileName.replace('Service', '').toLowerCase();
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* 从服务路径提取层级
|
||||
*/
|
||||
extractLayerFromServicePath(filePath) {
|
||||
// 从路径中提取层级信息
|
||||
if (filePath.includes('/admin/')) {
|
||||
return 'admin';
|
||||
} else if (filePath.includes('/api/')) {
|
||||
return 'api';
|
||||
} else if (filePath.includes('/core/')) {
|
||||
return 'core';
|
||||
}
|
||||
|
||||
return 'core'; // 默认为core层
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为驼峰命名
|
||||
*/
|
||||
toCamelCase(str) {
|
||||
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
|
||||
return index === 0 ? word.toLowerCase() : word.toUpperCase();
|
||||
}).replace(/\s+/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为PascalCase
|
||||
*/
|
||||
toPascalCase(str) {
|
||||
return str.replace(/(^|-)([a-z])/g, (match, p1, p2) => p2.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为kebab-case(我们框架的标准命名格式)
|
||||
*/
|
||||
toKebabCase(str) {
|
||||
return str
|
||||
.replace(/([A-Z])/g, '-$1')
|
||||
.replace(/^-/, '')
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查模块是否有PHP服务
|
||||
*/
|
||||
hasPHPServices(moduleName, layer) {
|
||||
const phpProjectPath = path.join(__dirname, '../../niucloud-php/niucloud');
|
||||
const servicePath = path.join(phpProjectPath, 'app/service', layer, moduleName);
|
||||
|
||||
if (!fs.existsSync(servicePath)) return false;
|
||||
|
||||
// 检查目录内是否有PHP文件
|
||||
try {
|
||||
const files = fs.readdirSync(servicePath);
|
||||
return files.some(file => file.endsWith('.php'));
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取Java服务中的Core依赖关系
|
||||
*/
|
||||
extractCoreDependencies(javaContent) {
|
||||
const coreDependencies = [];
|
||||
|
||||
// 查找 @Resource ICore*Service 依赖
|
||||
const resourcePattern = /@Resource\s+(\w+)\s+(\w+);/g;
|
||||
const imports = javaContent.match(/import\s+[\w\.]+\.ICore[\w]+Service;?/g) || [];
|
||||
|
||||
imports.forEach(importLine => {
|
||||
const serviceName = importLine.match(/ICore([\w]+)Service/)?.[1];
|
||||
if (serviceName) {
|
||||
coreDependencies.push(`Core${serviceName}Service`);
|
||||
}
|
||||
});
|
||||
|
||||
return coreDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取Java服务的方法
|
||||
*/
|
||||
extractJavaMethods(javaContent) {
|
||||
const methods = [];
|
||||
|
||||
// 简单的Java方法提取 - 查找 public 方法
|
||||
const methodPattern = /public\s+(\w+(?:<\w+>)?)\s+(\w+)\s*\(([^)]*)\)\s*\{/g;
|
||||
let match;
|
||||
|
||||
while ((match = methodPattern.exec(javaContent)) !== null) {
|
||||
const [fullMatch, returnType, methodName, parameters] = match;
|
||||
methods.push({
|
||||
name: methodName,
|
||||
returnType: returnType,
|
||||
parameters: parameters.trim(),
|
||||
body: this.extractMethodBody(javaContent, fullMatch)
|
||||
});
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取方法体(简化版)
|
||||
*/
|
||||
extractMethodBody(javaContent, methodStart) {
|
||||
// 这是一个简化的实现,实际应用中需要更复杂的解析
|
||||
const startIndex = javaContent.indexOf(methodStart);
|
||||
if (startIndex === -1) return '';
|
||||
|
||||
let braceCount = 0;
|
||||
let bodyStart = -1;
|
||||
|
||||
for (let i = startIndex; i < javaContent.length; i++) {
|
||||
if (javaContent[i] === '{') {
|
||||
braceCount++;
|
||||
if (bodyStart === -1) bodyStart = i + 1;
|
||||
} else if (javaContent[i] === '}') {
|
||||
braceCount--;
|
||||
if (braceCount === 0) {
|
||||
return javaContent.substring(bodyStart, i).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于Java服务生成NestJS服务内容
|
||||
*/
|
||||
generateNestJSServiceFromJava(moduleName, serviceName, layer, javaMethods, coreDependencies) {
|
||||
const infrastructureImports = this.getV1FrameworkInfrastructureImports();
|
||||
const vendorImports = this.getV1FrameworkVendorImports();
|
||||
|
||||
// 生成core服务依赖的导入
|
||||
const coreImports = coreDependencies.map(dep => {
|
||||
const depName = dep.replace('Core', '').replace('Service', '');
|
||||
return `import { ${dep} } from '../core/${this.toKebabCase(depName)}.service';`;
|
||||
}).join('\n');
|
||||
|
||||
// 生成core服务依赖的注入
|
||||
const coreInjections = coreDependencies.map(dep => {
|
||||
const propName = this.toCamelCase(dep.replace('Service', ''));
|
||||
return ` private readonly ${propName}: ${dep},`;
|
||||
}).join('\n');
|
||||
|
||||
const methodImplementations = javaMethods.map(method => {
|
||||
return ` /**
|
||||
* ${method.name}
|
||||
* 对应Java: ${serviceName}ServiceImpl::${method.name}()
|
||||
*/
|
||||
async ${method.name}(${this.convertJavaParametersToTS(method.parameters)}) {
|
||||
// TODO: 实现 ${method.name} 业务逻辑
|
||||
// 原始Java逻辑: ${method.body.substring(0, 100)}...
|
||||
throw new Error('${method.name} not implemented');
|
||||
}`;
|
||||
}).join('\n\n');
|
||||
|
||||
return `import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
${infrastructureImports}
|
||||
${vendorImports}
|
||||
${coreImports}
|
||||
|
||||
/**
|
||||
* ${serviceName}Service - ${layer}层服务
|
||||
* 对应Java: ${serviceName}ServiceImpl
|
||||
* 使用V1框架基础设施和Core服务依赖
|
||||
*/
|
||||
@Injectable()
|
||||
export class ${serviceName}Service {
|
||||
private readonly logger = new Logger(${serviceName}Service.name);
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Object)
|
||||
private readonly repository: Repository<any>,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly metricsService: MetricsService,
|
||||
private readonly tenantService: TenantService,
|
||||
private readonly uploadService: UploadService,
|
||||
private readonly payService: PayService,
|
||||
private readonly smsService: SmsService,
|
||||
private readonly noticeService: NoticeService,
|
||||
${coreInjections}
|
||||
) {}
|
||||
|
||||
${methodImplementations}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换Java参数到TypeScript参数(简化版)
|
||||
*/
|
||||
convertJavaParametersToTS(javaParameters) {
|
||||
if (!javaParameters.trim()) return '';
|
||||
|
||||
// 简单的Java到TS参数转换
|
||||
return javaParameters
|
||||
.split(',')
|
||||
.map(param => {
|
||||
const trimmed = param.trim();
|
||||
const [type, name] = trimmed.split(/\s+/);
|
||||
if (!name) return trimmed;
|
||||
|
||||
const tsType = this.convertJavaTypeToTS(type);
|
||||
return `${name}: ${tsType}`;
|
||||
})
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换Java类型到TypeScript类型(简化版)
|
||||
*/
|
||||
convertJavaTypeToTS(javaType) {
|
||||
const typeMap = {
|
||||
'String': 'string',
|
||||
'Integer': 'number',
|
||||
'Long': 'number',
|
||||
'Boolean': 'boolean',
|
||||
'List': 'any[]',
|
||||
'Map': 'Record<string, any>',
|
||||
'void': 'void'
|
||||
};
|
||||
|
||||
return typeMap[javaType] || 'any';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成统计报告
|
||||
*/
|
||||
generateStatsReport() {
|
||||
console.log('\n📊 服务生成统计报告');
|
||||
console.log('='.repeat(50));
|
||||
console.log(`✅ 创建服务数量: ${this.stats.servicesCreated}`);
|
||||
console.log(`🔄 更新服务数量: ${this.stats.servicesUpdated}`);
|
||||
console.log(`📝 处理方法数量: ${this.stats.methodsProcessed}`);
|
||||
console.log(`❌ 错误数量: ${this.stats.errors}`);
|
||||
console.log(`📈 成功率: ${this.stats.servicesCreated > 0 ? ((this.stats.servicesCreated - this.stats.errors) / this.stats.servicesCreated * 100).toFixed(2) : 0}%`);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此文件
|
||||
if (require.main === module) {
|
||||
const generator = new ServiceGenerator();
|
||||
generator.run().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = ServiceGenerator;
|
||||
Reference in New Issue
Block a user