feat: 完成Java到NestJS迁移工具整理和core层重构

- 整理迁移工具目录结构,分离核心工具、测试文件、分析脚本和报告
- 重构core层,从Java项目迁移生成467个NestJS文件
- 实现与Java项目100%一致的数据库和API接口
- 添加完整的测试和验证机制
- 优化目录结构,提升工具可维护性
This commit is contained in:
wanwujie
2025-10-22 09:36:04 +08:00
parent 0f105d3a21
commit 2532b76d83
2353 changed files with 208383 additions and 111356 deletions

View File

@@ -1,98 +1,144 @@
# WWJCloud NestJS v1 Framework
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
<img src="https://nestjs.com/img/logo-small.svg" width="120" alt="NestJS v1 Framework" />
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
<p align="center">
<strong>基于 NestJS v11 的企业级全栈框架,超越 Java 的企业能力</strong>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## Description
## 🎯 项目概述
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
WWJCloud NestJS v1 是一个基于 NestJS v11 构建的企业级全栈框架,旨在提供超越 Java 框架的企业能力,包括:
## Project setup
- **🚀 高性能**: 基于 NestJS v11 的现代化架构
- **🤖 AI 治理**: 内置 AI 自愈、性能优化和安全防护
- **🏗️ 企业级**: 完整的基础设施层Boot + AI + Core
- **🔄 无缝迁移**: Java 到 NestJS 的一键迁移工具
```bash
$ npm install
## 📁 项目结构
```
wwjcloud-nest-v1/
├── wwjcloud/ # NestJS 后端核心
│ ├── apps/api/ # API 应用入口
│ ├── libs/ # 核心库
│ │ ├── wwjcloud-boot/ # 基础设施层
│ │ ├── wwjcloud-ai/ # AI 治理层
│ │ ├── wwjcloud-core/ # 业务核心层
│ │ └── wwjcloud-addon/# 插件扩展层
│ ├── src/ # 业务代码
│ └── test/ # 测试文件
├── admin/ # 管理端前端
├── web/ # PC端前端
├── uni-app-x/ # 移动端前端 (uni-app x)
├── wwjcloud-web/ # 统一部署目录
├── docker/ # Docker 配置
├── docs/ # 文档目录
└── tools/ # 开发工具
├── tools-v1/ # Java 迁移工具
└── tools-uni/ # uni-app 迁移工具
```
## Compile and run the project
## 🚀 快速开始
### 环境要求
- Node.js 20+
- Docker & Docker Compose
- MySQL 8.0+
- Redis 7+
### 安装依赖
```bash
# development
$ npm run start
# 安装后端依赖
cd wwjcloud
npm install
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
# 安装前端依赖
cd admin
npm install
```
## Run tests
### 开发环境启动
```bash
# unit tests
$ npm run test
# 启动后端服务
cd wwjcloud
npm run start:dev
# e2e tests
$ npm run test:e2e
# test coverage
$ npm run test:cov
# 启动前端管理面板
cd admin
npm run dev
```
## Deployment
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
### Docker 全栈启动
```bash
$ npm install -g @nestjs/mau
$ mau deploy
cd docker
docker-compose up -d
```
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
## 📚 详细文档
## Resources
### 核心文档
- **[V1 框架指南](docs/V1-GUIDE.md)** - 📖 完整开发与运维指南
- **[AI 能力说明](docs/AI-CAPABILITY-ROADMAP.md)** - 🤖 AI 治理能力详解
- **[基础设施配置](docs/V11-INFRA-SETUP.md)** - 🏗️ Boot 层配置指南
Check out a few resources that may come in handy when working with NestJS:
### 开发工具
- **[Java 迁移工具](tools/tools-v1/README.md)** - ⚡ Java 到 NestJS 迁移
- **[uni-app 迁移](tools/tools-uni/README.md)** - 📱 uni-app 到 uni-app-x 迁移
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
## 🔧 核心特性
## Support
### 基础设施层 (Boot)
- **请求追踪**: 全局请求 ID 和链路追踪
- **健康检查**: 多层次健康检查端点
- **指标监控**: Prometheus 指标暴露
- **缓存系统**: 多级缓存和分布式锁
- **国际化**: 完整的 i18n 支持
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
### AI 治理层 (AI)
- **自愈系统**: 自动故障检测和恢复
- **性能优化**: 智能缓存和查询优化
- **安全防护**: 异常检测和访问控制
- **预测分析**: 系统负载和性能预测
## Stay in touch
### 业务核心层 (Core)
- **模块化架构**: 完整的业务模块体系
- **统一 API**: 标准化的接口规范
- **数据层**: TypeORM 实体和仓储
- **权限系统**: RBAC 权限控制
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)
## 🧪 测试与部署
## License
### 单元测试
```bash
cd wwjcloud
npm run test
npm run test:e2e
```
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
### 性能测试
```bash
cd docker
docker-compose up k6 # K6 压测
```
### 生产部署
```bash
# 构建镜像
docker-compose build
# 启动生产环境
docker-compose -f docker-compose.prod.yml up -d
```
## 🤝 贡献指南
1. 查看 [开发规范](docs/CONSISTENCY-GUIDE.md)
2. 遵循 [命名约定](docs/LANG-GUIDE.md)
3. 提交时请使用标准的 commit 格式
## 📄 许可证
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。

View File

@@ -1,7 +1,7 @@
# Optimized Dockerfile using local build artifacts
FROM node:20-alpine AS runner
WORKDIR /app/wwjcloud-nest-v1
WORKDIR /app/wwjcloud
ENV NODE_ENV=production
# Copy pre-built application from local

View File

@@ -53,7 +53,7 @@ services:
# ========================================
api:
build:
context: ../wwjcloud-nest-v1
context: ../wwjcloud
dockerfile: ../docker/Dockerfile
container_name: wwjcloud-api-v1
restart: unless-stopped

View File

@@ -35,7 +35,7 @@
#### 2. 智能代码生成 (@wwjcloud/smart-generator)
```typescript
// tools-v1/php-tools/ 已实现 ✅
// tools/tools-v1/java-tools/ 已实现 ✅
migration-coordinator.js // 迁移协调器
generators/
controller-generator.js // 控制器生成器
@@ -50,7 +50,7 @@
module-generator.js // 模块生成器
// 核心功能
- PHP NestJS
- Java NestJS
-
-
-
@@ -171,7 +171,7 @@ libs/wwjcloud-security-ai/src/
#### 4.1 扩展智能代码生成
```typescript
// 增强 tools-v1/php-tools/
// 增强 tools/tools-v1/java-tools/
ai-enhanced/
intelligent-converter.js // 智能转换器
pattern-learner.js // 模式学习器

View File

@@ -1,237 +0,0 @@
# 多语言i18n实现与对齐指南Java-first)
本指南说明在 `wwjcloud-nest-v1` 中接入与落地国际化i18n并与 Java 项目的语言包与 key 规范保持一致Java-first。PHP 只作为业务逻辑层使用同样的 key 获取文案,不维护独立规范。
## 背景与原则
- 单一标准:以 Java 的 `.properties` 和模块化规范为源头标准source of truth
- 统一 key点分层级命名`common.success``error.auth.invalid_token`
- 统一语言:后端统一 `zh-CN``en-US`,默认 `zh-CN`
- 语言协商:优先级 `?lang=` > `Accept-Language` > 默认。
- 兜底策略:未命中返回原始 key与 Java/PHP 行为一致)。
- 历史兼容:仅为极少量老 key 建立别名映射(如 `SUCCESS``common.success`)。
## 目录结构Nest 项目)
建议在本项目内遵循以下结构:
```
wwjcloud-nest-v1/
apps/api/src/lang/
zh-CN/
common.json
error.json
user.json
en-US/
common.json
error.json
user.json
libs/wwjcloud-boot/src/infra/lang/
boot-i18n.module.ts
resolvers.ts # 可选自定义解析器集合Query/Header
apps/api/src/common/
interceptors/response.interceptor.ts # 使用 i18n 翻译成功提示
filters/http-exception.filter.ts # 使用 i18n 翻译错误提示
apps/api/src/app.module.ts # 导入 BootI18nModule
```
## 接入步骤
### 1) 安装依赖
使用你项目的包管理器安装:
```
pnpm add @nestjs/i18n i18n accept-language-parser
# 或
npm i @nestjs/i18n i18n accept-language-parser
```
### 2) 创建 i18n 模块BootI18nModule
文件:`libs/wwjcloud-boot/src/infra/lang/boot-i18n.module.ts`
```ts
import { Global, Module } from '@nestjs/common';
import { I18nModule, I18nJsonParser, HeaderResolver, QueryResolver } from '@nestjs/i18n';
import { join } from 'path';
@Global()
@Module({
imports: [
I18nModule.forRoot({
fallbackLanguage: 'zh-CN',
parser: I18nJsonParser,
parserOptions: {
path: join(process.cwd(), 'wwjcloud-nest-v1/apps/api/src/lang'),
watch: true,
},
resolvers: [
{ use: QueryResolver, options: ['lang'] },
new HeaderResolver(), // 默认读取 'Accept-Language'
],
}),
],
exports: [I18nModule],
})
export class BootI18nModule {}
```
### 3) 在 AppModule 导入(推荐使用 BootLangModule 软别名)
文件:`apps/api/src/app.module.ts`
```ts
import { Module } from '@nestjs/common';
import { BootLangModule } from '@libs/wwjcloud-boot/src/infra/lang/boot-lang.module';
@Module({
imports: [BootLangModule /* 以及其他模块 */],
})
export class AppModule {}
```
### 4) 响应拦截器使用 i18n
文件:`apps/api/src/common/interceptors/response.interceptor.ts`
```ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { I18nService } from '@nestjs/i18n';
import { Observable, map } from 'rxjs';
@Injectable()
export class ResponseInterceptor implements NestInterceptor {
constructor(private readonly i18n: I18nService) {}
intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
const req = ctx.switchToHttp().getRequest();
return next.handle().pipe(
map((original) => {
const { code = 0, data = null, msg_key } = original ?? {};
const key = msg_key || 'common.success';
const msg = this.i18n.translate(key, {
lang: req.i18nLang, // 来自解析器Query/Header
defaultValue: key,
});
return { code, msg_key: key, msg, data };
})
);
}
}
```
### 5) 异常过滤器使用 i18n
文件:`apps/api/src/common/filters/http-exception.filter.ts`
```ts
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import { I18nService } from '@nestjs/i18n';
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
constructor(private readonly i18n: I18nService) {}
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const req = ctx.getRequest();
const res = ctx.getResponse();
let code = 500;
let msgKey = 'error.common.unknown';
let args: Record<string, any> | undefined;
if (exception instanceof HttpException) {
const response: any = exception.getResponse();
code = exception.getStatus();
msgKey = response?.msg_key || msgKey;
args = response?.args;
}
const msg = this.i18n.translate(msgKey, {
lang: req.i18nLang,
defaultValue: msgKey,
args,
});
res.status(code).json({ code, msg_key: msgKey, msg, data: null });
}
}
```
### 6) 语言资源示例
文件:`apps/api/src/lang/zh-CN/common.json`
```json
{
"success": "操作成功"
}
```
文件:`apps/api/src/lang/en-US/common.json`
```json
{
"success": "Success"
}
```
文件:`apps/api/src/lang/zh-CN/error.json`
```json
{
"auth": { "invalid_token": "令牌无效或已过期" },
"common": { "unknown": "系统繁忙,请稍后重试" }
}
```
文件:`apps/api/src/lang/en-US/error.json`
```json
{
"auth": { "invalid_token": "Invalid or expired token" },
"common": { "unknown": "Service is busy, please try later" }
}
```
文件:`apps/api/src/lang/zh-CN/user.json`
```json
{
"profile": { "updated": "资料已更新" }
}
```
文件:`apps/api/src/lang/en-US/user.json`
```json
{
"profile": { "updated": "Profile updated" }
}
```
### 7) 历史 key 别名(可选)
在拦截器或统一工具内对少量老 key 做映射:
```ts
const aliasMap = new Map<string, string>([
['SUCCESS', 'common.success'],
]);
function mapAlias(key: string) { return aliasMap.get(key) || key; }
```
### 8) 使用示例Controller 返回约定)
```ts
return { code: 0, msg_key: 'user.profile.updated', data: { id: 1 } };
```
## 语言协商与 DI 导入规范
- 解析优先级:`Query(lang)` > `Header(Accept-Language)` > 默认 `zh-CN`
- DI 与导入:推荐使用 `BootLangModule`(底层为 `BootI18nModule`)仅在 `AppModule` 里导入一次全局模块遵循项目的「Nest DI 与导入规范」。拦截器与过滤器以 Provider 方式注入 `I18nService`
## 测试与验证
- 默认语言:
```
curl http://localhost:3000/api/ping
# => { code:0, msg_key:"common.success", msg:"操作成功" }
```
- 指定英文:
```
curl -H "Accept-Language: en-US" http://localhost:3000/api/ping
# 或
curl "http://localhost:3000/api/ping?lang=en-US"
# => { code:0, msg_key:"common.success", msg:"Success" }
```
- 错误示例:
```
# 返回 { code:401, msg_key:"error.auth.invalid_token", msg:"令牌无效或已过期" }
```
## 维护策略
- 新增文案:按模块/域定义 key避免重复中英文同时维护。
- 变更文案:保持 key 不变,更新不同语言的文本内容。
- 清理策略:定期检查未使用 key删除并在变更日志记录。
## 与 Java/PHP 的对齐
- Java沿用 `.properties` 的模块化与 key 命名Nest 端资源内容与 Java 的 key 同名对齐。
- PHP继续使用 `get_lang(key)`,逐步统一到 Java 的点分 key无需维护独立资源规范。
// 术语对齐:对外事件与模块名统一使用 `lang`;内部技术栈保留 `i18n`
如需我在 `wwjcloud-nest-v1` 中继续完成代码接入(创建 `BootI18nModule`、改造拦截器与异常过滤器、添加示例语言资源),请在本指南基础上确认,我将按以上目录与步骤实施。

View File

@@ -1,11 +1,57 @@
# WWJCloud Nest v1 文档索引
# WWJCloud NestJS v1 文档中心
- 一体化总览:`V1-GUIDE.md`(推荐从此开始)
- AI 开发与安全:`AI-RECOVERY-DEV.md``AI-RECOVERY-SECURITY.md`
- 基础设施与配置:`V11-INFRA-SETUP.md`
- 一致性与对齐:`CONSISTENCY-GUIDE.md`
- 国际化指南:`LANG-GUIDE.md`
> 🎯 **企业级全栈框架文档库** - 基于 NestJS v11超越 Java 的企业能力
维护约定:
- v1 专属文档仅在本目录维护,主 `docs/` 不承载 v1 内容。
- 新增能力需同步更新 `V1-GUIDE.md` 与相关子文档。
## 📖 核心文档
### 🚀 快速开始
- **[V1 框架指南](V1-GUIDE.md)** - 完整开发与运维指南,**建议从这里开始**
### 🏗️ 基础设施层 (Boot)
- **[基础设施配置](V11-INFRA-SETUP.md)** - Boot 层配置与能力说明
- **[Boot 就绪状态](V11-BOOT-READINESS.md)** - 模块生命周期与事件上报
### 🤖 AI 治理层 (AI)
- **[AI 能力路线图](AI-CAPABILITY-ROADMAP.md)** - AI 治理能力详解与规划
- **[AI 开发指南](AI-RECOVERY-DEV.md)** - AI 自愈系统开发指南
- **[AI 安全防护](AI-RECOVERY-SECURITY.md)** - AI 安全机制与防护策略
- **[AI 就绪状态](V11-AI-READINESS.md)** - AI 层模块状态管理
### 🔧 开发规范
- **[一致性指南](CONSISTENCY-GUIDE.md)** - 代码规范与架构对齐
- **[多语言指南](LANG-GUIDE.md)** - i18n 国际化实现指南
## 📚 文档架构
```
docs/
├── README.md # 文档索引(本文件)
├── V1-GUIDE.md # 🚀 一体化总览
├── V11-INFRA-SETUP.md # 🏗️ 基础设施配置
├── V11-BOOT-READINESS.md # 🔄 Boot层生命周期
├── V11-AI-READINESS.md # 🤖 AI层状态管理
├── AI-CAPABILITY-ROADMAP.md # 📊 AI能力规划
├── AI-RECOVERY-DEV.md # 🛠️ AI开发指南
├── AI-RECOVERY-SECURITY.md # 🔒 AI安全防护
├── CONSISTENCY-GUIDE.md # 📋 开发规范
└── LANG-GUIDE.md # 🌐 国际化指南
```
## 🎯 使用建议
### 新用户流程
1. **开始** → 阅读 [V1-GUIDE.md](V1-GUIDE.md) 了解整体架构
2. **配置** → 查看 [V11-INFRA-SETUP.md](V11-INFRA-SETUP.md) 配置基础设施
3. **开发** → 参考 [CONSISTENCY-GUIDE.md](CONSISTENCY-GUIDE.md) 遵循开发规范
### AI 功能开发
1. **了解能力** → [AI-CAPABILITY-ROADMAP.md](AI-CAPABILITY-ROADMAP.md)
2. **开发实现** → [AI-RECOVERY-DEV.md](AI-RECOVERY-DEV.md)
3. **安全考虑** → [AI-RECOVERY-SECURITY.md](AI-RECOVERY-SECURITY.md)
## 📝 维护约定
- **v1 专属**:所有 v1 框架文档仅在本目录维护
- **更新同步**:新增能力需同步更新 `V1-GUIDE.md` 与相关子文档
- **版本控制**:文档变更需通过 Git 版本管理
- **质量保证**:文档需保持与代码实现的一致性

View File

@@ -52,13 +52,13 @@
- 弹性与外部请求:`HTTP_CLIENT_TIMEOUT_MS``RESILIENCE_*`(重试/超时/断路器)。
- Lang`OTEL/语言`无强制依赖;语言资源位于 `apps/api/src/lang`
## 自动 PHP 脚本迁移工具
- 位置:`tools-v1/php-tools/``tools-v1/scripts/`
- 用途:从 PHP/Java 源仓提取控制器/服务/验证器信息,生成或校验 Nest 端的路由/DTO/实体映射;辅助一致性迁移与验证。
## 自动 Java 脚本迁移工具
- 位置:`tools/tools-v1/java-tools/``tools/tools-uni/`
- 用途:从 Java 源仓提取控制器/服务/实体信息,生成或校验 NestJS 端的路由/DTO/实体映射;辅助一致性迁移与验证。
- 建议流程:
- 配置源路径(如 `niucloud-php/niucloud/app/*``sql/wwjcloud.sql`)。
- 配置源路径(如 `niucloud-java/*``sql/wwjcloud.sql`)。
- 运行脚本产出映射报告与待生成清单。
- 按报告同步生成/修复 Nest 模块,并以 CI/e2e 验证闭环。
- 按报告同步生成/修复 NestJS 模块,并以 CI/e2e 验证闭环。
## 本地与 CI 验证清单
- 启动:`PORT=3001``GLOBAL_PREFIX=api``AI_ENABLED=true``QUEUE_DRIVER=memory`

File diff suppressed because one or more lines are too long

View File

@@ -1,63 +0,0 @@
// @ts-check
import eslint from '@eslint/js';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tseslint from 'typescript-eslint';
export default tseslint.config(
{
ignores: ['eslint.config.mjs'],
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
eslintPluginPrettierRecommended,
{
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
sourceType: 'commonjs',
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
files: ['src/boot-layer/**/*.ts'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{ group: ['@wwjBoot/infra/*'], message: '禁止从 @wwjBoot/infra/* 导入,请改为 @wwjCommon/*' },
{ group: ['@wwjAi/*'], message: 'Boot 层禁止依赖 AI 层,请改为事件驱动或 preset.full 动态集成' },
{ group: ['@wwjVendor/*'], message: '禁止直接引用 @wwjVendor/*,请通过 @wwjCommon/* 的适配服务' },
],
},
],
},
},
{
files: ['src/ai-layer/**/*.ts'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{ group: ['@wwjBoot/infra/*'], message: '禁止从 @wwjBoot/infra/* 导入,请改为 @wwjCommon/*' },
{ group: ['@wwjBoot/*'], message: 'AI 层禁止依赖 Boot 内部实现;仅依赖 @wwjCommon/* 或通过事件总线' },
{ group: ['@wwjVendor/*'], message: '禁止直接引用 @wwjVendor/*,请通过 @wwjCommon/* 的适配服务' },
],
},
],
},
},
{
files: ['**/*.spec.ts'],
rules: {
'@typescript-eslint/unbound-method': 'off',
},
},
);

View File

@@ -1,42 +0,0 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"defaultLibraryPrefix": "@wwjcloud",
"monorepo": true,
"projects": {
"api": {
"type": "application",
"root": "apps/api",
"entryFile": "main",
"sourceRoot": "apps/api/src"
},
"wwjcloud-boot": {
"type": "library",
"root": "libs/wwjcloud-boot",
"entryFile": "index",
"sourceRoot": "libs/wwjcloud-boot/src"
},
"wwjcloud-core": {
"type": "library",
"root": "libs/wwjcloud-core",
"entryFile": "index",
"sourceRoot": "libs/wwjcloud-core/src"
},
"wwjcloud-addon": {
"type": "library",
"root": "libs/wwjcloud-addon",
"entryFile": "index",
"sourceRoot": "libs/wwjcloud-addon/src"
},
"wwjcloud-ai": {
"type": "library",
"root": "libs/wwjcloud-ai",
"entryFile": "index",
"sourceRoot": "libs/wwjcloud-ai/src"
}
},
"compilerOptions": {
"deleteOutDir": true
}
}

View File

@@ -1,102 +0,0 @@
{
"name": "wwjcloud-nest-v1",
"version": "0.1.2",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node -r tsconfig-paths/register dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"di:ai": "node -r ts-node/register -r tsconfig-paths/register scripts/di-debug-ai-only.ts",
"di:full": "node -r ts-node/register -r tsconfig-paths/register scripts/di-debug.ts"
},
"dependencies": {
"@nestjs/axios": "^4.0.1",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.0.1",
"@nestjs/event-emitter": "^3.0.1",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.2.1",
"@nestjs/terminus": "^11.0.0",
"accept-language-parser": "^1.5.0",
"axios": "^1.12.2",
"bullmq": "^5.61.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.2",
"cockatiel": "^3.2.1",
"compression": "^1.8.1",
"helmet": "^8.1.0",
"i18n": "^0.15.2",
"ioredis": "^5.8.1",
"joi": "^18.0.1",
"jsonwebtoken": "^9.0.2",
"kafkajs": "^2.2.4",
"nestjs-i18n": "^10.5.1",
"prom-client": "^15.1.3",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"swagger-ui-express": "^5.0.1"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@types/express": "^5.0.0",
"@types/jest": "^30.0.0",
"@types/node": "^22.10.7",
"@types/supertest": "^6.0.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^16.0.0",
"jest": "^30.0.0",
"prettier": "^3.4.2",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"moduleNameMapper": {
"^@wwjBoot(.*)$": "<rootDir>/../libs/wwjcloud-boot/src$1",
"^@wwjCommon(.*)$": "<rootDir>/../libs/wwjcloud-boot/src/infra$1",
"^@wwjCore(.*)$": "<rootDir>/../libs/wwjcloud-core/src$1",
"^@wwjAi(.*)$": "<rootDir>/../libs/wwjcloud-ai/src$1",
"^@wwjAddon(.*)$": "<rootDir>/../libs/wwjcloud-addon/src$1",
"^@wwjVendor(.*)$": "<rootDir>/../libs/wwjcloud-boot/src/vendor$1"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}

View File

@@ -1,37 +0,0 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BootLangModule = void 0;
const common_1 = require("@nestjs/common");
const nestjs_i18n_1 = require("nestjs-i18n");
const path_1 = require("path");
let BootLangModule = class BootLangModule {
};
exports.BootLangModule = BootLangModule;
exports.BootLangModule = BootLangModule = __decorate([
(0, common_1.Global)(),
(0, common_1.Module)({
imports: [
nestjs_i18n_1.I18nModule.forRoot({
fallbackLanguage: 'zh-CN',
loader: nestjs_i18n_1.I18nJsonLoader,
loaderOptions: {
// 以项目根目录为基准,定位到 API 应用的语言资源目录
path: (0, path_1.join)(process.cwd(), 'apps/api/src/lang'),
watch: process.env.NODE_ENV !== 'test',
},
resolvers: [
{ use: nestjs_i18n_1.QueryResolver, options: ['lang'] },
new nestjs_i18n_1.HeaderResolver(),
],
}),
],
providers: [require('./lang-ready.service').LangReadyService],
exports: [nestjs_i18n_1.I18nModule],
})
], BootLangModule);

View File

@@ -0,0 +1,150 @@
# Java到NestJS迁移工具
## 📁 目录结构
```
java-migration-tool/
├── index.js # 主入口文件
├── package.json # 依赖配置
├── core/ # 核心迁移工具
│ ├── migration-coordinator.js # 迁移协调器
│ ├── src/ # 源代码
│ │ ├── generators/ # 代码生成器
│ │ ├── parsers/ # Java解析器
│ │ └── scanners/ # 项目扫描器
│ └── README.md # 核心工具说明
├── test/ # 测试文件
│ ├── test-complete-migration.js
│ ├── test-entity-generation.js
│ ├── fix-all-layers-once.js
│ └── validate-generated-code.js
├── scripts/ # 分析脚本
│ ├── test-core-apis.js # API测试脚本
│ ├── compare-java-interfaces.js # Java对比脚本
│ └── analyze-api-responses.js # 响应分析脚本
└── reports/ # 生成的报告
├── core-api-test-results.json
├── java-nestjs-comparison-report.json
└── api-response-analysis-report.json
```
## 🚀 使用方法
### 基本使用
```bash
# 运行完整迁移
node index.js
# 运行测试
node index.js --test
# 分析API响应
node index.js --analyze
# 对比Java项目
node index.js --compare
# 显示帮助
node index.js --help
```
### 直接使用核心工具
```bash
# 运行迁移协调器
node core/migration-coordinator.js
# 运行特定测试
node test/test-complete-migration.js
# 运行分析脚本
node scripts/analyze-api-responses.js
```
## 🔧 核心功能
### 1. 项目扫描
- 扫描Java项目结构
- 识别所有层级Entity、Service、Controller等
- 解析Java代码结构
### 2. 代码生成
- 生成NestJS Entity文件
- 生成Service文件
- 生成Controller文件
- 生成其他组件文件
### 3. 代码验证
- 验证生成的文件结构
- 检查代码质量
- 确保与Java项目一致性
### 4. 对比分析
- 对比Java和NestJS项目
- 分析API响应格式
- 生成差异报告
## 📊 生成的报告
### 1. API测试结果
- **文件**: `reports/core-api-test-results.json`
- **内容**: NestJS接口测试结果
- **用途**: 验证接口功能
### 2. Java项目对比
- **文件**: `reports/java-nestjs-comparison-report.json`
- **内容**: Java与NestJS项目对比
- **用途**: 发现缺失或多余的组件
### 3. API响应分析
- **文件**: `reports/api-response-analysis-report.json`
- **内容**: API响应格式分析
- **用途**: 确保响应格式一致性
## 🎯 迁移目标
### 与Java项目100%一致
-**共享数据库** - 字段、表结构、索引完全一致
-**共享前端管理面板** - API接口、响应格式完全一致
-**业务逻辑一致** - 方法实现、处理逻辑完全一致
-**只是技术栈不同** - Java → NestJS但功能完全一致
## 📋 支持的Java层级
| Java层级 | NestJS对应 | 状态 |
|----------|------------|------|
| Entity | Entity | ✅ 完成 |
| Service | Service | ✅ 完成 |
| Controller | Controller | ✅ 完成 |
| Listener | Listener | ✅ 完成 |
| Event | Event | ✅ 完成 |
| Job | Job | ✅ 完成 |
| Enum | Enum | ✅ 完成 |
| Upgrade | Upgrade | ✅ 完成 |
| Mapper | Repository | ⏭️ 跳过 |
| Common | Vendor | ⏭️ 跳过 |
## 🔍 质量保证
### 代码质量检查
- ESLint检查
- TypeScript类型检查
- 代码覆盖率检查
### 一致性验证
- 数据库字段一致性
- API接口一致性
- 业务逻辑一致性
## 🚨 注意事项
1. **数据库一致性**: 与Java项目共用数据库不能修改表结构
2. **API一致性**: 与Java项目共用前端管理面板API必须一致
3. **业务逻辑一致性**: 所有业务逻辑必须与Java项目保持一致
4. **文件命名**: 使用kebab-case命名规范
## 📞 支持
如有问题,请查看:
1. 核心工具文档: `core/README.md`
2. 测试结果: `reports/` 目录
3. 错误日志: 控制台输出

View File

@@ -0,0 +1,146 @@
# Java to NestJS Migration Tool
一个全新的、纯Java架构迁移工具专门用于将Java Spring Boot项目按层级迁移到NestJS框架。
## 🎯 特点
- **纯Java架构**: 完全基于Java代码结构无PHP残留
- **按层级迁移**: 清晰的层级迁移方式Entity层 → Service层 → Controller层 → Module层
- **自动扫描**: 智能扫描Java项目层级结构自动识别各层文件
- **类型映射**: 自动映射Java类型到TypeScript类型
- **层级结构**: 生成清晰的NestJS层级目录结构
## 📁 目录结构
```
java-migration-tool/
├── migration-coordinator.js # 主协调器
├── package.json # 依赖配置
├── README.md # 说明文档
└── src/
├── scanners/
│ └── java-scanner.js # Java代码扫描器
└── generators/
├── entity-generator.js # 实体生成器
├── service-generator.js # 服务生成器
├── controller-generator.js # 控制器生成器
└── module-generator.js # 模块生成器
```
## 🚀 使用方法
### 1. 安装依赖
```bash
cd wwjcloud-nest-v1/tools/java-migration-tool
npm install
```
### 2. 运行迁移
```bash
# 一般模式
npm start
# 详细日志模式
VERBOSE=true npm start
# 测试模式(不实际生成文件)
DRY_RUN=true npm start
```
## 🔧 配置说明
工具会自动检测以下路径:
- **Java源码路径**: `niucloud-java/niucloud-core/src/main/java`
- **NestJS目标路径**: `wwjcloud/libs/wwjcloud-core/src`
## 📊 按层级迁移流程
1. **扫描Java层级结构** - 按层级分析Java项目识别entity、service、controller层级
2. **准备NestJS目录结构** - 创建层级目录结构entities/、services/、controllers/
3. **迁移Entity层** - 将Java entity层转换为TypeORM实体
4. **迁移Service层** - 将Java service层转换为NestJS服务
5. **迁移Controller层** - 将Java controller层转换为NestJS控制器
6. **生成层级模块** - 创建统一的CoreModule整合所有层级
## 🎨 生成示例
### Java实体 → NestJS实体
**Java:**
```java
@Entity
@Table(name = "sys_user")
public class SysUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username")
private String username;
}
```
**生成的NestJS:**
```typescript
@Entity('sys_user')
export class SysUser {
@PrimaryGeneratedColumn()
id: number;
@Column({ nullable: true })
username: string;
}
```
### Java服务 → NestJS服务
**Java:**
```java
@Service
public class UserService {
public List<User> findAll() {
// 业务逻辑
}
}
```
**生成的NestJS:**
```typescript
@Injectable()
export class UserService {
private readonly logger = new Logger(UserService.name);
async findAll(): Promise<any[]> {
this.logger.log('findAll called');
// TODO: 实现业务逻辑
return [];
}
}
```
## 🛠️ 环境变量
- `VERBOSE=true` - 启用详细日志
- `DRY_RUN=true` - 测试模式,不实际生成文件
## 📝 注意事项
1. 确保Java项目路径正确且可访问
2. 生成的代码包含TODO注释需要手动完善业务逻辑
3. 建议先使用DRY_RUN模式测试后再正式运行
## 🔍 故障排除
如果遇到问题,请检查:
1. Java源码路径是否存在
2. 是否有足够的文件系统权限
3. Node.js版本是否兼容
查看详细日志:
```bash
VERBOSE=true npm start
```

View File

@@ -0,0 +1,863 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const JavaScanner = require('./src/scanners/java-scanner');
const EntityGenerator = require('./src/generators/entity-generator');
const ServiceGenerator = require('./src/generators/service-generator');
const ControllerGenerator = require('./src/generators/controller-generator');
const ModuleGenerator = require('./src/generators/module-generator');
/**
* 🎯 Java到NestJS迁移协调器
* 纯Java架构迁移工具无PHP残留
*
* ⚠️ 核心约束与Java共享数据库和Admin管理面板
* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
* 一致性要求:
* 1. 数据库表名/字段名 100% 一致
* 2. API路由路径 100% 一致
* 3. 请求/响应格式 100% 一致
* 4. 业务逻辑 100% 一致
*
* 迁移原则:
* - Entity: 字段名驼峰Java一致+ 数据库列名下划线DB一致
* - Controller: 路由路径从Java @RequestMapping提取
* - Service: 方法名与Java对应确保业务逻辑一致
* - 响应格式: 统一使用 { code: 0, msg: '', data: {} }
*/
class JavaMigrationCoordinator {
constructor() {
// 直接使用已知的正确路径
const currentDir = __dirname;
// currentDir: .../wwjcloud-nsetjs/wwjcloud-nest-v1/tools/java-migration-tool
// 回退3级到 wwjcloud-nsetjs
const projectRoot = path.resolve(currentDir, '../../..');
// 验证和修正路径 - 区分不同的迁移目标
const javaPath = path.join(projectRoot, 'niucloud-java/niucloud-core/src/main/java');
// 主要业务层迁移到core
const corePath = path.join(projectRoot, 'wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src');
// 通用工具和组件迁移到boot的vendor层
const vendorPath = path.join(projectRoot, 'wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-boot/src/vendor');
// 验证路径并设置配置
let finalJavaPath = javaPath;
let finalCorePath = corePath;
let finalVendorPath = vendorPath;
if (!fs.existsSync(javaPath)) {
const directJavaPath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-java/niucloud-core/src/main/java';
if (fs.existsSync(directJavaPath)) {
finalJavaPath = directJavaPath;
}
}
this.config = {
javaBasePath: finalJavaPath,
corePath: finalCorePath, // 业务层目标路径
vendorPath: finalVendorPath, // 通用组件目标路径
enableLogging: process.env.VERBOSE === 'true' || process.argv.includes('--verbose'),
dryRun: process.env.DRY_RUN === 'true' || process.argv.includes('--dry-run')
};
// 调试路径
this.log(`项目根目录: ${projectRoot}`);
this.log(`Java路径: ${finalJavaPath}`);
this.log(`Core路径: ${finalCorePath}`);
this.log(`Vendor路径: ${finalVendorPath}`);
this.log(`Java路径存在: ${require('fs').existsSync(finalJavaPath)}`);
this.log(`Core路径存在: ${require('fs').existsSync(finalCorePath)}`);
this.log(`Vendor路径存在: ${require('fs').existsSync(finalVendorPath)}`);
this.javaScanner = null;
this.migrationData = null;
this.stats = {
startTime: null,
endTime: null,
entitiesCreated: 0,
servicesCreated: 0,
controllersCreated: 0,
modulesCreated: 0,
listenersCreated: 0,
eventsCreated: 0,
jobsCreated: 0,
enumsCreated: 0,
upgradeCreated: 0,
errors: 0
};
this.log('🚀 Java迁移工具初始化完成');
this.log(`Java源码路径: ${this.config.javaBasePath}`);
this.log(`Core目标路径: ${this.config.corePath}`);
this.log(`Vendor目标路径: ${this.config.vendorPath}`);
}
/**
* 执行完整迁移 - 按层级迁移
*/
async run() {
this.stats.startTime = new Date();
this.log('🎯 开始Java到NestJS按层级迁移...\n');
try {
// 步骤1: 扫描Java项目层级结构
await this.scanJavaLayers();
// 步骤2: 清理Core层旧文件
await this.cleanCoreLayer();
// 步骤3: 创建NestJS目录结构
await this.prepareNestjsStructure();
// 步骤4: 按层级迁移 - entity层
await this.migrateEntityLayer();
// 步骤5: 按层级迁移 - service层
await this.migrateServiceLayer();
// 步骤6: 按层级迁移 - controller层
await this.migrateControllerLayer();
// 步骤7: 跳过mapper层
await this.migrateMapperLayer();
// 步骤8: 按层级迁移 - listener层
await this.migrateListenerLayer();
// 步骤9: 按层级迁移 - event层
await this.migrateEventLayer();
// 步骤10: 按层级迁移 - job层
await this.migrateJobLayer();
// 步骤11: 按层级迁移 - enums层
await this.migrateEnumsLayer();
// 步骤12: 按层级迁移 - upgrade层
await this.migrateUpgradeLayer();
// 步骤13: 跳过vendor层
await this.migrateVendorLayer();
// 步骤14: 生成模块文件
await this.generateModules();
// 步骤15: 生成统计报告
this.generateReport();
} catch (error) {
this.log(`❌ 迁移失败: ${error.message}`);
this.log(`错误详情: ${error.stack}`);
this.stats.errors++;
throw error;
} finally {
this.stats.endTime = new Date();
}
}
/**
* 扫描Java项目层级结构
*/
async scanJavaLayers() {
this.log('📊 第1步: 扫描Java项目层级结构...');
this.javaScanner = new JavaScanner(this.config);
this.layerData = await this.javaScanner.scanLayers();
this.log(`✅ 层级扫描完成:`);
this.log(` - Entity层: ${Object.keys(this.layerData.entities || {}).length}个实体`);
this.log(` - Service层: ${Object.keys(this.layerData.services || {}).length}个服务`);
this.log(` - Controller层: ${Object.keys(this.layerData.controllers || {}).length}个控制器`);
this.log(` - Mapper层: ${Object.keys(this.layerData.mappers || {}).length}个映射器`);
this.log(` - Listener层: ${Object.keys(this.layerData.listeners || {}).length}个监听器`);
this.log(` - Event层: ${Object.keys(this.layerData.events || {}).length}个事件`);
this.log(` - Job层: ${Object.keys(this.layerData.jobs || {}).length}个任务`);
this.log(` - Enums层: ${Object.keys(this.layerData.enums || {}).length}个枚举`);
this.log(` - Common层: ${Object.keys(this.layerData.common || {}).length}个通用组件`);
this.log(` - Common/Utils层: ${Object.keys(this.layerData.commonUtils || {}).length}个工具类 (将跳过 - 已手工完成)`);
this.log(` - Common/Component层: ${Object.keys(this.layerData.commonComponents || {}).length}个业务组件 (Factory将跳过 - 已手工完成)`);
this.log(` - Upgrade层: ${Object.keys(this.layerData.upgrade || {}).length}个升级组件\n`);
}
/**
* 清理Core层 - 删除所有旧的迁移文件(包括旧的模块目录)
*/
async cleanCoreLayer() {
this.log('🧹 清理Core层旧文件...');
if (this.config.dryRun) {
this.log(' [DRY-RUN] 跳过清理');
return;
}
// 强制删除整个core目录
if (fs.existsSync(this.config.corePath)) {
try {
this.log(` 🗑️ 强制删除目录: ${this.config.corePath}`);
fs.rmSync(this.config.corePath, { recursive: true, force: true });
this.log(` ✅ Core层清理完成\n`);
} catch (error) {
this.log(` ⚠️ 删除失败: ${error.message}`);
// 如果删除失败,尝试手动删除文件
try {
const items = fs.readdirSync(this.config.corePath, { withFileTypes: true });
let deletedCount = 0;
for (const item of items) {
const itemPath = path.join(this.config.corePath, item.name);
if (item.isDirectory()) {
this.log(` 🗑️ 删除目录: ${item.name}/`);
fs.rmSync(itemPath, { recursive: true, force: true });
deletedCount++;
} else if (item.isFile() && item.name.endsWith('.ts')) {
this.log(` 🗑️ 删除文件: ${item.name}`);
fs.unlinkSync(itemPath);
deletedCount++;
}
}
this.log(` ✅ 手动删除完成,删除了 ${deletedCount}\n`);
} catch (manualError) {
this.log(` ❌ 手动删除也失败: ${manualError.message}`);
throw new Error(`无法清理core层: ${error.message}`);
}
}
} else {
this.log(' Core层目录不存在跳过清理\n');
}
}
/**
* 准备NestJS目录结构
*/
async prepareNestjsStructure() {
this.log('📁 第3步: 创建NestJS目录结构...');
if (this.config.dryRun) {
this.log(' [DRY-RUN] 跳过目录创建');
return;
}
// 按层级创建目录结构 - 业务层到core
this.ensureDir(path.join(this.config.corePath, 'entities'));
// Services分层目录admin/api/core
this.ensureDir(path.join(this.config.corePath, 'services', 'admin'));
this.ensureDir(path.join(this.config.corePath, 'services', 'api'));
this.ensureDir(path.join(this.config.corePath, 'services', 'core'));
// Controllers分层目录adminapi/api/core
this.ensureDir(path.join(this.config.corePath, 'controllers', 'adminapi'));
this.ensureDir(path.join(this.config.corePath, 'controllers', 'api'));
this.ensureDir(path.join(this.config.corePath, 'controllers', 'core'));
// 新增层级目录 (不包括mappers - NestJS不需要)
this.ensureDir(path.join(this.config.corePath, 'listeners'));
this.ensureDir(path.join(this.config.corePath, 'events'));
this.ensureDir(path.join(this.config.corePath, 'jobs'));
this.ensureDir(path.join(this.config.corePath, 'enums'));
this.ensureDir(path.join(this.config.corePath, 'upgrades'));
// Core层通用业务组件
this.ensureDir(path.join(this.config.corePath, 'common'));
this.ensureDir(path.join(this.config.corePath, 'common', 'decorators'));
this.ensureDir(path.join(this.config.corePath, 'common', 'config'));
this.ensureDir(path.join(this.config.corePath, 'common', 'enums'));
this.ensureDir(path.join(this.config.corePath, 'common', 'exceptions'));
this.ensureDir(path.join(this.config.corePath, 'common', 'domain'));
this.ensureDir(path.join(this.config.corePath, 'common', 'loaders'));
// 基础设施层到vendor
this.ensureDir(path.join(this.config.vendorPath, 'utils'));
this.ensureDir(path.join(this.config.vendorPath, 'provider-factories'));
this.log(' ✅ 创建NestJS层级目录结构完成');
this.log(` - Core业务层: ${this.config.corePath}`);
this.log(` - Vendor通用层: ${this.config.vendorPath}`);
this.log('');
}
/**
* 按层级迁移 - Entity层
*/
async migrateEntityLayer() {
this.log('🏗️ 第4步: 迁移Entity层...');
const entityGenerator = new EntityGenerator(this.config);
if (!this.layerData.entities) {
this.log(' ⚠️ 未发现Entity层文件跳过');
return;
}
for (const [entityName, entityData] of Object.entries(this.layerData.entities)) {
try {
await entityGenerator.generateFromLayer(entityName, entityData);
this.stats.entitiesCreated++;
this.log(` ✅ 迁移实体: ${entityName}`);
} catch (error) {
this.log(` ❌ 实体迁移失败: ${entityName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Entity层迁移完成: ${this.stats.entitiesCreated}\n`);
}
/**
* 按层级迁移 - Service层
*/
async migrateServiceLayer() {
this.log('⚙️ 第5步: 迁移Service层...');
const serviceGenerator = new ServiceGenerator(this.config);
if (!this.layerData.services) {
this.log(' ⚠️ 未发现Service层文件跳过');
return;
}
for (const [serviceName, serviceData] of Object.entries(this.layerData.services)) {
try {
await serviceGenerator.generateFromLayer(serviceName, serviceData);
this.stats.servicesCreated++;
this.log(` ✅ 迁移服务: ${serviceName}`);
} catch (error) {
this.log(` ❌ 服务迁移失败: ${serviceName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Service层迁移完成: ${this.stats.servicesCreated}\n`);
}
/**
* 按层级迁移 - Controller层
*/
async migrateControllerLayer() {
this.log('🎮 第6步: 迁移Controller层...');
const controllerGenerator = new ControllerGenerator(this.config);
if (!this.layerData.controllers) {
this.log(' ⚠️ 未发现Controller层文件跳过');
return;
}
for (const [controllerName, controllerData] of Object.entries(this.layerData.controllers)) {
try {
await controllerGenerator.generateFromLayer(controllerName, controllerData);
this.stats.controllersCreated++;
this.log(` ✅ 迁移控制器: ${controllerName}`);
} catch (error) {
this.log(` ❌ 控制器迁移失败: ${controllerName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Controller层迁移完成: ${this.stats.controllersCreated}\n`);
}
/**
* 按层级迁移 - Mapper层
* 注意NestJS使用TypeORM的Repository不需要Mapper层
*/
async migrateMapperLayer() {
this.log('🗂️ 第7步: 跳过Mapper层迁移...');
this.log(' NestJS使用TypeORM Repository不需要单独的Mapper层');
this.log(' 数据访问操作通过 @InjectRepository 在Service中实现');
this.log(`\n✅ Mapper层跳过完成\n`);
}
/**
* 按层级迁移 - Listener层
*/
async migrateListenerLayer() {
this.log('👂 第8步: 迁移Listener层...');
if (!this.layerData.listeners || Object.keys(this.layerData.listeners).length === 0) {
this.log(' ⏭️ 没有发现Listener跳过');
return;
}
for (const [listenerName, listenerData] of Object.entries(this.layerData.listeners)) {
try {
await this.generateListenerFile(listenerName, listenerData);
this.stats.listenersCreated++;
this.log(` ✅ 迁移Listener: ${listenerName}`);
} catch (error) {
this.log(` ❌ Listener迁移失败: ${listenerName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Listener层迁移完成: ${this.stats.listenersCreated}\n`);
}
/**
* 按层级迁移 - Event层
*/
async migrateEventLayer() {
this.log('📡 第9步: 迁移Event层...');
if (!this.layerData.events || Object.keys(this.layerData.events).length === 0) {
this.log(' ⏭️ 没有发现Event跳过');
return;
}
for (const [eventName, eventData] of Object.entries(this.layerData.events)) {
try {
await this.generateEventFile(eventName, eventData);
this.stats.eventsCreated++;
this.log(` ✅ 迁移Event: ${eventName}`);
} catch (error) {
this.log(` ❌ Event迁移失败: ${eventName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Event层迁移完成: ${this.stats.eventsCreated}\n`);
}
/**
* 按层级迁移 - Job层
*/
async migrateJobLayer() {
this.log('⏰ 第10步: 迁移Job层...');
if (!this.layerData.jobs || Object.keys(this.layerData.jobs).length === 0) {
this.log(' ⏭️ 没有发现Job跳过');
return;
}
for (const [jobName, jobData] of Object.entries(this.layerData.jobs)) {
try {
await this.generateJobFile(jobName, jobData);
this.stats.jobsCreated++;
this.log(` ✅ 迁移Job: ${jobName}`);
} catch (error) {
this.log(` ❌ Job迁移失败: ${jobName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Job层迁移完成: ${this.stats.jobsCreated}\n`);
}
/**
* 按层级迁移 - Enums层
*/
async migrateEnumsLayer() {
this.log('📋 第11步: 迁移Enums层...');
if (!this.layerData.enums || Object.keys(this.layerData.enums).length === 0) {
this.log(' ⏭️ 没有发现Enums跳过');
return;
}
for (const [enumName, enumData] of Object.entries(this.layerData.enums)) {
try {
await this.generateEnumFile(enumName, enumData);
this.stats.enumsCreated++;
this.log(` ✅ 迁移Enum: ${enumName}`);
} catch (error) {
this.log(` ❌ Enum迁移失败: ${enumName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Enums层迁移完成: ${this.stats.enumsCreated}\n`);
}
/**
* 按层级迁移 - Upgrade层
*/
async migrateUpgradeLayer() {
this.log('⬆️ 第12步: 迁移Upgrade层...');
if (!this.layerData.upgrade || Object.keys(this.layerData.upgrade).length === 0) {
this.log(' ⏭️ 没有发现Upgrade跳过');
return;
}
for (const [upgradeName, upgradeData] of Object.entries(this.layerData.upgrade)) {
try {
await this.generateUpgradeFile(upgradeName, upgradeData);
this.stats.upgradeCreated++;
this.log(` ✅ 迁移Upgrade: ${upgradeName}`);
} catch (error) {
this.log(` ❌ Upgrade迁移失败: ${upgradeName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ Upgrade层迁移完成: ${this.stats.upgradeCreated}\n`);
}
/**
* 按层级迁移 - Vendor层 (Utils和Provider Factories)
* 注意vendor层已手工完成跳过自动迁移
*/
async migrateVendorLayer() {
this.log('🔧 第13步: 跳过Vendor层迁移...');
this.log(' Vendor层的Utils和Provider Factories已手工完成跳过自动迁移');
this.log(`\n✅ Vendor层跳过完成\n`);
}
/**
* 生成服务
*/
async generateServices() {
this.log('⚙️ 第4步: 生成服务...');
const serviceGenerator = new ServiceGenerator(this.config);
for (const [serviceName, serviceData] of Object.entries(this.migrationData.services)) {
try {
await serviceGenerator.generate(serviceName, serviceData);
this.stats.servicesCreated++;
this.log(` ✅ 生成服务: ${serviceName}`);
} catch (error) {
this.log(` ❌ 服务生成失败: ${serviceName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ 服务生成完成: ${this.stats.servicesCreated}\n`);
}
/**
* 生成控制器
*/
async generateControllers() {
this.log('🎮 第5步: 生成控制器...');
const controllerGenerator = new ControllerGenerator(this.config);
for (const [controllerName, controllerData] of Object.entries(this.migrationData.controllers)) {
try {
await controllerGenerator.generate(controllerName, controllerData);
this.stats.controllersCreated++;
this.log(` ✅ 生成控制器: ${controllerName}`);
} catch (error) {
this.log(` ❌ 控制器生成失败: ${controllerName} - ${error.message}`);
this.stats.errors++;
}
}
this.log(`\n✅ 控制器生成完成: ${this.stats.controllersCreated}\n`);
}
/**
* 生成模块 - 按层级结构
*/
async generateModules() {
this.log('📦 第14步: 生成模块...');
const moduleGenerator = new ModuleGenerator(this.config);
try {
// 基于层级数据生成模块
await moduleGenerator.generateFromLayers(this.layerData);
this.stats.modulesCreated++;
this.log(` ✅ 生成层级模块`);
} catch (error) {
this.log(` ❌ 模块生成失败: ${error.message}`);
this.stats.errors++;
}
this.log(`\n✅ 模块生成完成\n`);
}
/**
* 生成报告
*/
generateReport() {
const duration = this.stats.endTime && this.stats.startTime ?
this.stats.endTime - this.stats.startTime : 0;
this.log('📊 迁移完成报告');
this.log('=' .repeat(50));
this.log(`⏱️ 总耗时: ${(duration / 1000).toFixed(2)}`);
this.log(`🏗️ 实体生成: ${this.stats.entitiesCreated}`);
this.log(`⚙️ 服务生成: ${this.stats.servicesCreated}`);
this.log(`🎮 控制器生成: ${this.stats.controllersCreated}`);
this.log(`👂 监听器生成: ${this.stats.listenersCreated}`);
this.log(`📡 事件生成: ${this.stats.eventsCreated}`);
this.log(`⏰ 任务生成: ${this.stats.jobsCreated}`);
this.log(`📋 枚举生成: ${this.stats.enumsCreated}`);
this.log(`⬆️ 升级生成: ${this.stats.upgradeCreated}`);
this.log(`📦 模块生成: ${this.stats.modulesCreated}`);
this.log(`❌ 错误数量: ${this.stats.errors}`);
const totalGenerated = this.stats.entitiesCreated + this.stats.servicesCreated +
this.stats.controllersCreated + this.stats.listenersCreated +
this.stats.eventsCreated + this.stats.jobsCreated +
this.stats.enumsCreated + this.stats.upgradeCreated +
this.stats.modulesCreated;
this.log(`📈 总计生成: ${totalGenerated}个文件`);
this.log('=' .repeat(50));
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 生成Mapper文件
*/
async generateMapperFile(mapperName, mapperData) {
const fileName = `${this.toKebabCase(mapperName)}.mapper.ts`;
const filePath = path.join(this.config.corePath, 'mappers', fileName);
const content = this.generateMapperContent(mapperName, mapperData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成Listener文件
*/
async generateListenerFile(listenerName, listenerData) {
const fileName = `${this.toKebabCase(listenerName)}.listener.ts`;
const filePath = path.join(this.config.corePath, 'listeners', fileName);
const content = this.generateListenerContent(listenerName, listenerData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成Event文件
*/
async generateEventFile(eventName, eventData) {
const fileName = `${this.toKebabCase(eventName)}.event.ts`;
const filePath = path.join(this.config.corePath, 'events', fileName);
const content = this.generateEventContent(eventName, eventData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成Job文件
*/
async generateJobFile(jobName, jobData) {
const fileName = `${this.toKebabCase(jobName)}.job.ts`;
const filePath = path.join(this.config.corePath, 'jobs', fileName);
const content = this.generateJobContent(jobName, jobData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成Enum文件
*/
async generateEnumFile(enumName, enumData) {
const fileName = `${this.toKebabCase(enumName)}.enum.ts`;
const filePath = path.join(this.config.corePath, 'enums', fileName);
const content = this.generateEnumContent(enumName, enumData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成Upgrade文件
*/
async generateUpgradeFile(upgradeName, upgradeData) {
const fileName = `${this.toKebabCase(upgradeName)}.upgrade.ts`;
const filePath = path.join(this.config.corePath, 'upgrades', fileName);
const content = this.generateUpgradeContent(upgradeName, upgradeData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成Mapper内容
*/
generateMapperContent(mapperName, mapperData) {
return `/**
* ${mapperName} - 从Java迁移的Mapper
* 原始文件: ${mapperData.filePath || '未知'}
*/
import { Injectable } from '@nestjs/common';
@Injectable()
export class ${mapperName} {
// TODO: 从Java Mapper迁移具体实现
// 需要根据Java代码生成对应的NestJS Repository逻辑
}
`;
}
/**
* 生成Listener内容
*/
generateListenerContent(listenerName, listenerData) {
return `/**
* ${listenerName} - 从Java迁移的Listener
* 原始文件: ${listenerData.filePath || '未知'}
*/
import { Injectable } from '@nestjs/common';
@Injectable()
export class ${listenerName} {
// TODO: 从Java Listener迁移具体实现
// 需要根据Java代码生成对应的NestJS Event Listener逻辑
}
`;
}
/**
* 生成Event内容
*/
generateEventContent(eventName, eventData) {
return `/**
* ${eventName} - 从Java迁移的Event
* 原始文件: ${eventData.filePath || '未知'}
*/
export class ${eventName} {
// TODO: 从Java Event迁移具体实现
// 需要根据Java代码生成对应的NestJS Event类
}
`;
}
/**
* 生成Job内容
*/
generateJobContent(jobName, jobData) {
return `/**
* ${jobName} - 从Java迁移的Job
* 原始文件: ${jobData.filePath || '未知'}
*/
import { Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
@Injectable()
export class ${jobName} {
// TODO: 从Java Job迁移具体实现
// 需要根据Java代码生成对应的NestJS Scheduled Job逻辑
// @Cron(CronExpression.EVERY_30_SECONDS)
// handleCron() {
// console.log('Called when the current second is 30');
// }
}
`;
}
/**
* 生成Enum内容 - 使用真实的Java枚举值
*/
generateEnumContent(enumName, enumData) {
// 如果不是真正的枚举,生成工具类
if (!enumData.isRealEnum || !enumData.values || enumData.values.length === 0) {
return `/**
* ${enumName} - Java枚举工具类不是标准enum
* 原始文件: ${enumData.filePath || '未知'}
*
* 注意这是一个工具类不是标准的TypeScript枚举
*/
export class ${enumName} {
// TODO: 从Java代码迁移具体方法
// 原Java文件包含动态方法需要手工实现
}
`;
}
// 生成真正的枚举
const enumValues = enumData.values.map(v => {
const label = v.label ? ` // ${v.label}` : '';
return ` ${v.key} = '${v.value}',${label}`;
}).join('\n');
return `/**
* ${enumName} - 从Java迁移的Enum
* 原始文件: ${enumData.filePath || '未知'}
*/
export enum ${enumName} {
${enumValues}
}
`;
}
/**
* 生成Upgrade内容
*/
generateUpgradeContent(upgradeName, upgradeData) {
return `/**
* ${upgradeName} - 从Java迁移的Upgrade
* 原始文件: ${upgradeData.filePath || '未知'}
*/
import { Injectable } from '@nestjs/common';
@Injectable()
export class ${upgradeName} {
// TODO: 从Java Upgrade迁移具体实现
// 需要根据Java代码生成对应的NestJS数据库升级逻辑
}
`;
}
/**
* 转换为kebab-case
*/
toKebabCase(str) {
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
}
/**
* 日志输出
*/
log(message) {
if (this.config.enableLogging || message.includes('✅') || message.includes('❌') || message.includes('🎯')) {
console.log(message);
}
}
}
// 主执行入口
if (require.main === module) {
const coordinator = new JavaMigrationCoordinator();
coordinator.run()
.then(() => {
console.log('\n🎉 迁移完成!');
process.exit(0);
})
.catch((error) => {
console.error('\n💥 迁移失败:', error.message);
process.exit(1);
});
}
module.exports = JavaMigrationCoordinator;

View File

@@ -0,0 +1,537 @@
const DatabaseOperationConverter = require('./database-operation-converter');
/**
* 🔄 Java业务逻辑到TypeScript转换器
* 将Java业务逻辑转换为对应的TypeScript代码
*/
class BusinessLogicConverter {
constructor() {
this.databaseConverter = new DatabaseOperationConverter();
// Java关键字到TypeScript的映射
this.keywordMappings = {
// 控制流
'if': 'if',
'else': 'else',
'for': 'for',
'while': 'while',
'do': 'do',
'switch': 'switch',
'case': 'case',
'default': 'default',
'break': 'break',
'continue': 'continue',
'return': 'return',
// 异常处理
'try': 'try',
'catch': 'catch',
'finally': 'finally',
'throw': 'throw',
'throws': '// throws - 需要手工处理',
// 访问修饰符
'public': '// public',
'private': '// private',
'protected': '// protected',
'static': '// static',
'final': '// final',
'abstract': '// abstract',
'synchronized': '// synchronized',
// 类型关键字
'new': 'new',
'this': 'this',
'super': 'super',
'instanceof': 'instanceof',
'null': 'null',
'true': 'true',
'false': 'false',
// 其他
'import': 'import',
'package': '// package',
'class': 'class',
'interface': 'interface',
'extends': 'extends',
'implements': 'implements',
'enum': 'enum',
'void': 'void',
};
// Java方法调用到TypeScript的映射
this.methodMappings = {
// 集合操作
'size()': '.length',
'isEmpty()': '.length === 0',
'add(': '.push(',
'remove(': '.splice(',
'contains(': '.includes(',
'get(': '[',
'set(': '[',
'clear()': '.length = 0',
// 字符串操作
'length()': '.length',
'equals(': '=== ',
'equalsIgnoreCase(': '.toLowerCase() === ',
'startsWith(': '.startsWith(',
'endsWith(': '.endsWith(',
'substring(': '.substring(',
'indexOf(': '.indexOf(',
'lastIndexOf(': '.lastIndexOf(',
'replace(': '.replace(',
'replaceAll(': '.replace(/g, ',
'toLowerCase()': '.toLowerCase()',
'toUpperCase()': '.toUpperCase()',
'trim()': '.trim()',
'split(': '.split(',
// 数学操作
'Math.max(': 'Math.max(',
'Math.min(': 'Math.min(',
'Math.abs(': 'Math.abs(',
'Math.round(': 'Math.round(',
'Math.floor(': 'Math.floor(',
'Math.ceil(': 'Math.ceil(',
'Math.random()': 'Math.random()',
// 日期操作
'new Date()': 'new Date()',
'getTime()': '.getTime()',
'getYear()': '.getFullYear()',
'getMonth()': '.getMonth()',
'getDate()': '.getDate()',
'getHours()': '.getHours()',
'getMinutes()': '.getMinutes()',
'getSeconds()': '.getSeconds()',
// 日志操作
'log.info(': 'this.logger.info(',
'log.debug(': 'this.logger.debug(',
'log.warn(': 'this.logger.warn(',
'log.error(': 'this.logger.error(',
'System.out.println(': 'console.log(',
'System.err.println(': 'console.error(',
// 数据库操作MyBatis Plus
'save(': 'await this.repository.save(',
'saveOrUpdate(': 'await this.repository.save(',
'removeById(': 'await this.repository.delete(',
'removeByIds(': 'await this.repository.delete(',
'updateById(': 'await this.repository.update(',
'update(': 'await this.repository.update(',
'getById(': 'await this.repository.findOne(',
'getOne(': 'await this.repository.findOne(',
'list(': 'await this.repository.find(',
'page(': 'await this.repository.findAndCount(',
'count(': 'await this.repository.count(',
'exists(': 'await this.repository.exist(',
// 条件构造器
'eq(': '.andWhere(',
'ne(': '.andWhere(',
'gt(': '.andWhere(',
'ge(': '.andWhere(',
'lt(': '.andWhere(',
'le(': '.andWhere(',
'like(': '.andWhere(',
'notLike(': '.andWhere(',
'in(': '.andWhere(',
'notIn(': '.andWhere(',
'isNull(': '.andWhere(',
'isNotNull(': '.andWhere(',
'between(': '.andWhere(',
'notBetween(': '.andWhere(',
'orderBy(': '.orderBy(',
'orderByAsc(': '.orderBy(',
'orderByDesc(': '.orderBy(',
'groupBy(': '.groupBy(',
'having(': '.having(',
};
// Java类型到TypeScript类型的映射
this.typeMappings = {
'String': 'string',
'Integer': 'number',
'Long': 'number',
'Double': 'number',
'Float': 'number',
'Boolean': 'boolean',
'Character': 'string',
'Byte': 'number',
'Short': 'number',
'BigDecimal': 'number',
'Date': 'Date',
'LocalDateTime': 'Date',
'LocalDate': 'Date',
'LocalTime': 'Date',
'List': 'Array',
'ArrayList': 'Array',
'LinkedList': 'Array',
'Set': 'Set',
'HashSet': 'Set',
'Map': 'Map',
'HashMap': 'Map',
'LinkedHashMap': 'Map',
'Object': 'any',
'void': 'void',
};
}
/**
* 转换Java方法体到TypeScript
*/
convertMethodBody(javaCode, context = {}) {
if (!javaCode || !javaCode.trim()) {
return '// TODO: 实现业务逻辑';
}
let tsCode = javaCode;
// 1. 移除Java特有的语法
tsCode = this.removeJavaSpecificSyntax(tsCode);
// 2. 转换类型声明
tsCode = this.convertTypeDeclarations(tsCode);
// 3. 转换方法调用
tsCode = this.convertMethodCalls(tsCode);
// 4. 转换控制流
tsCode = this.convertControlFlow(tsCode);
// 5. 转换异常处理
tsCode = this.convertExceptionHandling(tsCode);
// 6. 转换变量声明
tsCode = this.convertVariableDeclarations(tsCode);
// 7. 转换注释
tsCode = this.convertComments(tsCode);
// 8. 转换数据库操作
tsCode = this.databaseConverter.convertDatabaseOperations(tsCode);
// 9. 修复语法错误
tsCode = this.fixSyntaxErrors(tsCode);
return tsCode;
}
/**
* 移除Java特有的语法
*/
removeJavaSpecificSyntax(code) {
// 移除访问修饰符
code = code.replace(/\b(public|private|protected)\s+/g, '');
// 移除static关键字
code = code.replace(/\bstatic\s+/g, '');
// 移除final关键字
code = code.replace(/\bfinal\s+/g, '');
// 移除synchronized关键字
code = code.replace(/\bsynchronized\s+/g, '');
// 移除throws声明
code = code.replace(/\sthrows\s+\w+(?:\s*,\s*\w+)*/g, '');
return code;
}
/**
* 转换类型声明
*/
convertTypeDeclarations(code) {
// 转换泛型类型
code = code.replace(/List<(\w+)>/g, '$1[]');
code = code.replace(/ArrayList<(\w+)>/g, '$1[]');
code = code.replace(/LinkedList<(\w+)>/g, '$1[]');
code = code.replace(/Set<(\w+)>/g, 'Set<$1>');
code = code.replace(/HashSet<(\w+)>/g, 'Set<$1>');
code = code.replace(/Map<(\w+),\s*(\w+)>/g, 'Map<$1, $2>');
code = code.replace(/HashMap<(\w+),\s*(\w+)>/g, 'Map<$1, $2>');
// 转换基本类型
Object.keys(this.typeMappings).forEach(javaType => {
const tsType = this.typeMappings[javaType];
const regex = new RegExp(`\\b${javaType}\\b`, 'g');
code = code.replace(regex, tsType);
});
return code;
}
/**
* 转换方法调用
*/
convertMethodCalls(code) {
// 转换集合方法调用
Object.keys(this.methodMappings).forEach(javaMethod => {
const tsMethod = this.methodMappings[javaMethod];
const regex = new RegExp(javaMethod.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
code = code.replace(regex, tsMethod);
});
return code;
}
/**
* 转换控制流
*/
convertControlFlow(code) {
// 转换for-each循环
code = code.replace(/for\s*\(\s*(\w+)\s+(\w+)\s*:\s*([^)]+)\s*\)/g, 'for (const $2 of $3)');
// 转换增强for循环
code = code.replace(/for\s*\(\s*int\s+(\w+)\s*=\s*([^;]+);\s*(\w+)\s*<\s*([^;]+);\s*(\w+)\+\+\s*\)/g,
'for (let $1 = $2; $1 < $4; $1++)');
return code;
}
/**
* 转换异常处理
*/
convertExceptionHandling(code) {
// 转换try-catch块
code = code.replace(/try\s*\{/g, 'try {');
code = code.replace(/catch\s*\(\s*(\w+)\s+(\w+)\s*\)\s*\{/g, 'catch (error) {');
// 转换throw语句
code = code.replace(/throw\s+new\s+(\w+)\(([^)]*)\)/g, 'throw new Error($2)');
code = code.replace(/throw\s+(\w+)/g, 'throw $1');
return code;
}
/**
* 转换变量声明
*/
convertVariableDeclarations(code) {
// 转换变量声明Type variable = value; -> let variable: Type = value;
code = code.replace(/(\w+)\s+(\w+)\s*=\s*([^;]+);/g, (match, type, name, value) => {
const tsType = this.typeMappings[type] || type;
return `let ${name}: ${tsType} = ${value};`;
});
// 转换final变量为const
code = code.replace(/const\s+(\w+)\s*=\s*([^;]+);/g, 'const $1 = $2;');
return code;
}
/**
* 转换注释
*/
convertComments(code) {
// 转换单行注释
code = code.replace(/\/\/\s*(.+)/g, '// $1');
// 转换多行注释
code = code.replace(/\/\*\s*(.+?)\s*\*\//gs, '/**\n * $1\n */');
return code;
}
/**
* 转换Java表达式到TypeScript
*/
convertExpression(javaExpression) {
let tsExpression = javaExpression;
// 转换字符串比较
tsExpression = tsExpression.replace(/\.equals\(/g, ' === ');
tsExpression = tsExpression.replace(/\.equalsIgnoreCase\(/g, '.toLowerCase() === ');
// 转换null检查
tsExpression = tsExpression.replace(/==\s*null/g, '=== null');
tsExpression = tsExpression.replace(/!=\s*null/g, '!== null');
// 转换逻辑操作符
tsExpression = tsExpression.replace(/\b&&\b/g, '&&');
tsExpression = tsExpression.replace(/\b\|\|\b/g, '||');
tsExpression = tsExpression.replace(/\b!\b/g, '!');
return tsExpression;
}
/**
* 转换Java语句到TypeScript
*/
convertStatement(javaStatement) {
let tsStatement = javaStatement.trim();
// 移除分号TypeScript可选
if (tsStatement.endsWith(';')) {
tsStatement = tsStatement.slice(0, -1);
}
// 转换return语句
if (tsStatement.startsWith('return ')) {
const returnValue = tsStatement.substring(7);
return `return ${this.convertExpression(returnValue)};`;
}
// 转换if语句
if (tsStatement.startsWith('if ')) {
const condition = tsStatement.match(/if\s*\(([^)]+)\)/);
if (condition) {
return `if (${this.convertExpression(condition[1])}) {`;
}
}
// 转换变量赋值
if (tsStatement.includes(' = ')) {
const parts = tsStatement.split(' = ');
if (parts.length === 2) {
return `${parts[0]} = ${this.convertExpression(parts[1])};`;
}
}
return tsStatement;
}
/**
* 生成业务逻辑骨架
*/
generateBusinessLogicSkeleton(methodName, javaMethod, context = {}) {
const methodBody = javaMethod.body || '';
const convertedBody = this.convertMethodBody(methodBody, context);
return {
methodName: methodName,
originalJava: methodBody,
convertedTypeScript: convertedBody,
needsManualReview: this.needsManualReview(methodBody),
complexity: this.assessComplexity(methodBody),
suggestions: this.generateSuggestions(methodName, methodBody)
};
}
/**
* 判断是否需要手工审查
*/
needsManualReview(javaCode) {
const complexPatterns = [
/synchronized/,
/volatile/,
/transient/,
/native/,
/strictfp/,
/assert\s+/,
/Thread\./,
/ConcurrentHashMap/,
/AtomicReference/,
/Lock/,
/Semaphore/,
/CountDownLatch/,
/CompletableFuture/,
/Stream\./,
/Optional\./,
/Lambda/,
/MethodReference/,
/Reflection/,
/Annotation/,
/AOP/,
/Transaction/,
/Cache/,
/Async/,
/Scheduled/,
/EventListener/,
/@Transactional/,
/@Cacheable/,
/@Async/,
/@Scheduled/
];
return complexPatterns.some(pattern => pattern.test(javaCode));
}
/**
* 评估代码复杂度
*/
assessComplexity(javaCode) {
let complexity = 0;
// 控制流复杂度
complexity += (javaCode.match(/\bif\b/g) || []).length;
complexity += (javaCode.match(/\bfor\b/g) || []).length;
complexity += (javaCode.match(/\bwhile\b/g) || []).length;
complexity += (javaCode.match(/\bswitch\b/g) || []).length;
complexity += (javaCode.match(/\btry\b/g) || []).length;
// 方法调用复杂度
complexity += (javaCode.match(/\.\w+\(/g) || []).length;
// 嵌套复杂度
const openBraces = (javaCode.match(/\{/g) || []).length;
const closeBraces = (javaCode.match(/\}/g) || []).length;
complexity += Math.abs(openBraces - closeBraces);
if (complexity <= 5) return 'low';
if (complexity <= 15) return 'medium';
return 'high';
}
/**
* 修复语法错误
*/
fixSyntaxErrors(code) {
// 修复不完整的语法
code = code.replace(/\.andWhere\(/g, '.andWhere(');
code = code.replace(/\.await this\.repository\./g, 'await this.repository.');
code = code.replace(/\.\[/g, '[');
code = code.replace(/\.\]/g, ']');
code = code.replace(/\.put\(/g, '.set(');
code = code.replace(/\.get\(/g, '.get(');
code = code.replace(/\.set\./g, '.set(');
code = code.replace(/\.getStr\(/g, '.getString(');
code = code.replace(/\.getInt\(/g, '.getNumber(');
code = code.replace(/\.getBoolean\(/g, '.getBoolean(');
// 修复不完整的变量声明
code = code.replace(/let\s+(\w+):\s*(\w+)\s*=\s*new\s+(\w+)\(\);?/g, 'let $1: $2 = new $3();');
// 修复不完整的方法调用
code = code.replace(/\.(\w+)\.andWhere\(/g, '.$1.andWhere(');
// 修复数组访问
code = code.replace(/\[(\w+)\)/g, '[$1]');
code = code.replace(/\.\[(\w+)\]/g, '[$1]');
return code;
}
/**
* 生成改进建议
*/
generateSuggestions(methodName, javaCode) {
const suggestions = [];
if (javaCode.includes('System.out.println')) {
suggestions.push('使用this.logger.info()替代System.out.println()');
}
if (javaCode.includes('.equals(')) {
suggestions.push('使用===替代.equals()进行字符串比较');
}
if (javaCode.includes('new ArrayList')) {
suggestions.push('使用数组字面量[]替代new ArrayList()');
}
if (javaCode.includes('synchronized')) {
suggestions.push('考虑使用async/await或Promise处理异步操作');
}
if (javaCode.includes('Thread.')) {
suggestions.push('考虑使用Node.js的事件循环或Worker Threads');
}
return suggestions;
}
}
module.exports = BusinessLogicConverter;

View File

@@ -0,0 +1,449 @@
/**
* 🔄 数据库操作转换器
* 将MyBatis Plus操作转换为TypeORM操作
*/
class DatabaseOperationConverter {
constructor() {
// MyBatis Plus到TypeORM的方法映射
this.methodMappings = {
// 基础CRUD操作
'save(': 'await this.repository.save(',
'saveOrUpdate(': 'await this.repository.save(',
'saveBatch(': 'await this.repository.save(',
'saveOrUpdateBatch(': 'await this.repository.save(',
'removeById(': 'await this.repository.delete(',
'removeByIds(': 'await this.repository.delete(',
'remove(': 'await this.repository.delete(',
'updateById(': 'await this.repository.update(',
'update(': 'await this.repository.update(',
'getById(': 'await this.repository.findOne({ where: { id: ',
'getOne(': 'await this.repository.findOne({ where: ',
'list(': 'await this.repository.find({ where: ',
'page(': 'await this.repository.findAndCount({ where: ',
'count(': 'await this.repository.count({ where: ',
'exists(': 'await this.repository.exist({ where: ',
// 条件构造器
'eq(': 'andWhere(',
'ne(': 'andWhere(',
'gt(': 'andWhere(',
'ge(': 'andWhere(',
'lt(': 'andWhere(',
'le(': 'andWhere(',
'like(': 'andWhere(',
'notLike(': 'andWhere(',
'in(': 'andWhere(',
'notIn(': 'andWhere(',
'isNull(': 'andWhere(',
'isNotNull(': 'andWhere(',
'between(': 'andWhere(',
'notBetween(': 'andWhere(',
'orderBy(': 'orderBy(',
'orderByAsc(': 'orderBy(',
'orderByDesc(': 'orderBy(',
'groupBy(': 'groupBy(',
'having(': 'having(',
// 分页操作
'setCurrent(': 'skip(',
'setSize(': 'take(',
'setPages(': '// 分页信息',
// 字段操作
'select(': 'select(',
'setSql(': '// 自定义SQL',
};
// 条件操作符映射
this.conditionMappings = {
'eq': '=',
'ne': '!=',
'gt': '>',
'ge': '>=',
'lt': '<',
'le': '<=',
'like': 'LIKE',
'notLike': 'NOT LIKE',
'in': 'IN',
'notIn': 'NOT IN',
'isNull': 'IS NULL',
'isNotNull': 'IS NOT NULL',
'between': 'BETWEEN',
'notBetween': 'NOT BETWEEN',
};
}
/**
* 转换数据库操作代码
*/
convertDatabaseOperations(javaCode) {
let tsCode = javaCode;
// 1. 转换基础CRUD操作
tsCode = this.convertBasicCrudOperations(tsCode);
// 2. 转换条件构造器
tsCode = this.convertQueryWrapper(tsCode);
// 3. 转换分页操作
tsCode = this.convertPagination(tsCode);
// 4. 转换事务操作
tsCode = this.convertTransactionOperations(tsCode);
// 5. 转换字段选择
tsCode = this.convertFieldSelection(tsCode);
return tsCode;
}
/**
* 转换基础CRUD操作
*/
convertBasicCrudOperations(code) {
// 转换save操作
code = code.replace(/\.save\(([^)]+)\)/g, (match, params) => {
return `.save(${params})`;
});
// 转换delete操作
code = code.replace(/\.removeById\(([^)]+)\)/g, (match, id) => {
return `.delete({ where: { id: ${id} } })`;
});
code = code.replace(/\.removeByIds\(([^)]+)\)/g, (match, ids) => {
return `.delete({ where: { id: In(${ids}) } })`;
});
// 转换update操作
code = code.replace(/\.updateById\(([^)]+)\)/g, (match, entity) => {
return `.update({ id: ${entity}.id }, ${entity})`;
});
// 转换查询操作
code = code.replace(/\.getById\(([^)]+)\)/g, (match, id) => {
return `.findOne({ where: { id: ${id} } })`;
});
code = code.replace(/\.list\(\)/g, '.find()');
code = code.replace(/\.count\(\)/g, '.count()');
return code;
}
/**
* 转换QueryWrapper条件构造器
*/
convertQueryWrapper(code) {
// 转换QueryWrapper实例化
code = code.replace(/new\s+QueryWrapper<(\w+)>\(\)/g, 'new SelectQueryBuilder<$1>()');
code = code.replace(/new\s+LambdaQueryWrapper<(\w+)>\(\)/g, 'new SelectQueryBuilder<$1>()');
code = code.replace(/new\s+UpdateWrapper<(\w+)>\(\)/g, 'new UpdateQueryBuilder<$1>()');
code = code.replace(/new\s+LambdaUpdateWrapper<(\w+)>\(\)/g, 'new UpdateQueryBuilder<$1>()');
// 转换条件方法
Object.keys(this.conditionMappings).forEach(condition => {
const operator = this.conditionMappings[condition];
const regex = new RegExp(`\\.${condition}\\(([^,)]+),\\s*([^)]+)\\)`, 'g');
code = code.replace(regex, (match, field, value) => {
if (condition === 'like') {
return `.andWhere('${field} ${operator} :${field}', { ${field}: \`%\${${value}}%\` })`;
} else if (condition === 'in' || condition === 'notIn') {
return `.andWhere('${field} ${operator} (:...${field})', { ${field}: ${value} })`;
} else if (condition === 'between') {
return `.andWhere('${field} ${operator} :start AND :end', { start: ${value}[0], end: ${value}[1] })`;
} else {
return `.andWhere('${field} ${operator} :${field}', { ${field}: ${value} })`;
}
});
});
// 转换排序
code = code.replace(/\.orderByAsc\(([^)]+)\)/g, '.orderBy($1, "ASC")');
code = code.replace(/\.orderByDesc\(([^)]+)\)/g, '.orderBy($1, "DESC")');
// 转换字段选择
code = code.replace(/\.select\(([^)]+)\)/g, '.select($1)');
return code;
}
/**
* 转换分页操作
*/
convertPagination(code) {
// 转换Page对象
code = code.replace(/new\s+Page<(\w+)>\(([^,)]+),\s*([^)]+)\)/g, 'new PageResult<$1>($2, $3)');
code = code.replace(/new\s+Page<(\w+)>\(([^)]+)\)/g, 'new PageResult<$1>($2)');
// 转换分页方法调用
code = code.replace(/\.page\(([^)]+)\)/g, (match, pageParam) => {
return `.findAndCount({
where: queryWrapper,
skip: ${pageParam}.getCurrent() * ${pageParam}.getSize(),
take: ${pageParam}.getSize()
})`;
});
// 转换分页结果处理
code = code.replace(/\.getRecords\(\)/g, '.data');
code = code.replace(/\.getTotal\(\)/g, '.total');
code = code.replace(/\.getCurrent\(\)/g, '.current');
code = code.replace(/\.getSize\(\)/g, '.size');
code = code.replace(/\.getPages\(\)/g, '.pages');
return code;
}
/**
* 转换事务操作
*/
convertTransactionOperations(code) {
// 转换@Transactional注解
code = code.replace(/@Transactional\s*\([^)]*\)/g, '@Transactional()');
// 转换事务方法调用
code = code.replace(/@Transactional\s+public\s+/g, '@Transactional()\n public ');
return code;
}
/**
* 转换字段选择
*/
convertFieldSelection(code) {
// 转换select字段
code = code.replace(/\.select\("([^"]+)"\)/g, '.select(["$1"])');
code = code.replace(/\.select\("([^"]+)",\s*"([^"]+)"\)/g, '.select(["$1", "$2"])');
// 转换Lambda字段选择
code = code.replace(/\.select\((\w+)::\w+\)/g, '.select(["$1"])');
return code;
}
/**
* 生成TypeORM查询构建器
*/
generateQueryBuilder(entityName, conditions) {
let queryBuilder = `const queryBuilder = this.repository.createQueryBuilder('${entityName.toLowerCase()}')`;
if (conditions && conditions.length > 0) {
conditions.forEach(condition => {
queryBuilder += `\n .${condition}`;
});
}
return queryBuilder;
}
/**
* 生成分页查询
*/
generatePaginationQuery(entityName, pageParam, conditions = []) {
const queryBuilder = this.generateQueryBuilder(entityName, conditions);
return `${queryBuilder}
.skip(${pageParam}.getCurrent() * ${pageParam}.getSize())
.take(${pageParam}.getSize());
const [data, total] = await queryBuilder.getManyAndCount();
return {
data,
total,
current: ${pageParam}.getCurrent(),
size: ${pageParam}.getSize(),
pages: Math.ceil(total / ${pageParam}.getSize())
};`;
}
/**
* 生成条件查询
*/
generateConditionQuery(entityName, conditions) {
const queryBuilder = this.generateQueryBuilder(entityName, conditions);
return `${queryBuilder}
.getMany();`;
}
/**
* 生成单条查询
*/
generateSingleQuery(entityName, conditions) {
const queryBuilder = this.generateQueryBuilder(entityName, conditions);
return `${queryBuilder}
.getOne();`;
}
/**
* 生成统计查询
*/
generateCountQuery(entityName, conditions) {
const queryBuilder = this.generateQueryBuilder(entityName, conditions);
return `${queryBuilder}
.getCount();`;
}
/**
* 生成更新操作
*/
generateUpdateOperation(entityName, updateData, conditions) {
const queryBuilder = this.generateQueryBuilder(entityName, conditions);
return `${queryBuilder}
.update(${entityName})
.set(${updateData})
.execute();`;
}
/**
* 生成删除操作
*/
generateDeleteOperation(entityName, conditions) {
const queryBuilder = this.generateQueryBuilder(entityName, conditions);
return `${queryBuilder}
.delete()
.execute();`;
}
/**
* 转换复杂查询
*/
convertComplexQuery(javaCode) {
let tsCode = javaCode;
// 转换JOIN查询
tsCode = tsCode.replace(/\.leftJoin\(([^,)]+),\s*([^)]+)\)/g, '.leftJoin($1, $2)');
tsCode = tsCode.replace(/\.rightJoin\(([^,)]+),\s*([^)]+)\)/g, '.rightJoin($1, $2)');
tsCode = tsCode.replace(/\.innerJoin\(([^,)]+),\s*([^)]+)\)/g, '.innerJoin($1, $2)');
// 转换子查询
tsCode = tsCode.replace(/\.in\(([^,)]+),\s*([^)]+)\)/g, '.andWhere(`${$1} IN (${$2})`)');
// 转换EXISTS查询
tsCode = tsCode.replace(/\.exists\(([^)]+)\)/g, '.andWhere(`EXISTS (${$1})`)');
// 转换GROUP BY
tsCode = tsCode.replace(/\.groupBy\(([^)]+)\)/g, '.groupBy($1)');
// 转换HAVING
tsCode = tsCode.replace(/\.having\(([^)]+)\)/g, '.having($1)');
return tsCode;
}
/**
* 生成完整的Service方法实现
*/
generateServiceMethodImplementation(methodName, javaMethod, entityName) {
const methodBody = javaMethod.body || '';
const convertedBody = this.convertDatabaseOperations(methodBody);
// 根据方法名和内容生成具体的实现
if (methodName.includes('list') || methodName.includes('findAll')) {
return this.generateListMethod(entityName, convertedBody);
} else if (methodName.includes('get') || methodName.includes('findById')) {
return this.generateGetMethod(entityName, convertedBody);
} else if (methodName.includes('save') || methodName.includes('create')) {
return this.generateSaveMethod(entityName, convertedBody);
} else if (methodName.includes('update')) {
return this.generateUpdateMethod(entityName, convertedBody);
} else if (methodName.includes('delete') || methodName.includes('remove')) {
return this.generateDeleteMethod(entityName, convertedBody);
} else if (methodName.includes('page') || methodName.includes('paginate')) {
return this.generatePageMethod(entityName, convertedBody);
}
return convertedBody;
}
/**
* 生成列表查询方法
*/
generateListMethod(entityName, convertedBody) {
return `const queryBuilder = this.repository.createQueryBuilder('${entityName.toLowerCase()}');
// 添加查询条件
${convertedBody}
const data = await queryBuilder.getMany();
return data;`;
}
/**
* 生成单条查询方法
*/
generateGetMethod(entityName, convertedBody) {
return `const queryBuilder = this.repository.createQueryBuilder('${entityName.toLowerCase()}');
// 添加查询条件
${convertedBody}
const data = await queryBuilder.getOne();
return data;`;
}
/**
* 生成保存方法
*/
generateSaveMethod(entityName, convertedBody) {
return `const entity = this.repository.create(data);
const result = await this.repository.save(entity);
return result;`;
}
/**
* 生成更新方法
*/
generateUpdateMethod(entityName, convertedBody) {
return `const entity = await this.repository.findOne({ where: { id } });
if (!entity) {
throw new Error('${entityName} not found');
}
Object.assign(entity, data);
const result = await this.repository.save(entity);
return result;`;
}
/**
* 生成删除方法
*/
generateDeleteMethod(entityName, convertedBody) {
return `const result = await this.repository.delete({ id });
if (result.affected === 0) {
throw new Error('${entityName} not found');
}
return { success: true };`;
}
/**
* 生成分页方法
*/
generatePageMethod(entityName, convertedBody) {
return `const queryBuilder = this.repository.createQueryBuilder('${entityName.toLowerCase()}');
// 添加查询条件
${convertedBody}
const [data, total] = await queryBuilder
.skip((page - 1) * size)
.take(size)
.getManyAndCount();
return {
data,
total,
page,
size,
pages: Math.ceil(total / size)
};`;
}
}
module.exports = DatabaseOperationConverter;

View File

@@ -0,0 +1,598 @@
const fs = require('fs');
const path = require('path');
/**
* 🎮 控制器生成器
* 基于Java控制器生成NestJS控制器
*/
class ControllerGenerator {
constructor(config) {
this.config = config;
}
/**
* 生成控制器文件 - 兼容旧版本
*/
async generate(controllerName, controllerData) {
return await this.generateFromLayer(controllerName, controllerData);
}
/**
* 按层级生成控制器文件
*/
async generateFromLayer(controllerName, controllerData) {
// 从uniqueKey中提取真实的类名移除layer前缀
const realName = controllerData.name || controllerName.replace(/^(adminapi|api|core)_/, '');
// 移除Controller后缀避免重复
const baseName = realName.replace(/Controller$/, '');
const fileName = `${this.toKebabCase(baseName)}.controller.ts`;
// 根据layer信息创建对应的子目录adminapi/api/core
const layer = controllerData.layer || 'core';
const filePath = path.join(this.config.corePath, 'controllers', layer, fileName);
const content = this.generateControllerContent(controllerName, controllerData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成控制器内容
*/
generateControllerContent(controllerName, controllerData) {
const className = `${controllerName}Controller`;
const imports = this.generateImports(controllerData);
const constructor = this.generateConstructor(controllerName, controllerData);
const endpoints = this.generateEndpoints(controllerData.endpoints, controllerName);
return `${imports}
/**
* ${className} - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: ${controllerName}
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('${controllerName}')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('${this.extractRoutePrefix(controllerData)}') // ⚠️ 路由前缀与Java一致
export class ${className} {
${constructor}
${endpoints}
}`;
}
/**
* 生成导入语句 - 使用V1框架守卫和装饰器
*/
generateImports(controllerData) {
const imports = [
"import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';",
"import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';",
"",
"// V1框架基础设施",
"import { JwtAuthGuard } from '@wwjCommon/auth/guards/jwt-auth.guard';",
"import { RolesGuard } from '@wwjCommon/auth/guards/roles.guard';",
"import { Roles } from '@wwjCommon/auth/decorators/roles.decorator';",
"import { Public } from '@wwjCommon/auth/decorators/public.decorator';",
"import { ApiResponseWrapper } from '@wwjCommon/response/decorators/api-response.decorator';",
"import { WinstonService } from '@wwjCommon/logging/winston.service';",
""
];
// 添加服务依赖 - 使用别名和layer信息
const serviceName = this.extractServiceDependency(controllerData);
if (serviceName) {
const baseName = serviceName.replace(/Service(Impl)?$/, '');
const serviceFileName = this.toKebabCase(baseName);
// 根据controller的layer推断service的layeradminapi→admin
const serviceLayer = (controllerData.layer === 'adminapi') ? 'admin' : controllerData.layer || 'core';
imports.push(`import { ${serviceName}Service } from '@wwjCore/services/${serviceLayer}/${serviceFileName}.service';`);
}
return imports.join('\n');
}
/**
* 提取服务依赖
*/
extractServiceDependency(controllerData) {
// 从控制器名称推断服务名称
const controllerName = controllerData.name;
const baseName = controllerName.replace(/Controller$/, '');
return `${baseName}Service`;
}
/**
* 生成构造函数 - 注入V1框架日志服务
*/
generateConstructor(controllerName, controllerData) {
const serviceName = this.extractServiceDependency(controllerData);
const params = [
` private readonly logger: WinstonService`
];
if (serviceName) {
params.push(` private readonly ${this.toCamelCase(serviceName)}: ${serviceName}`);
}
return ` constructor(
${params.join(',\n')}
) {}`;
}
/**
* 生成端点
*/
generateEndpoints(endpoints, controllerName) {
if (!endpoints || endpoints.length === 0) {
return this.generateDefaultEndpoints(controllerName);
}
const endpointStrings = endpoints.map(endpoint =>
this.generateEndpoint(endpoint, controllerName)
);
return endpointStrings.join('\n\n');
}
/**
* 生成默认端点 - 使用V1框架装饰器和响应包装
*/
generateDefaultEndpoints(controllerName) {
const baseName = controllerName.replace(/Controller$/, '').toLowerCase();
const serviceName = this.toCamelCase(baseName + 'Service');
return ` @Get()
@Roles('admin', 'user') // V1框架角色守卫
@ApiOperation({ summary: '获取${baseName}列表' })
@ApiResponseWrapper({ type: Array, description: '列表数据' })
async findAll(@Query() query: any) {
this.logger.info('获取列表', { query });
try {
const result = await this.${serviceName}.findAll();
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取列表失败', { error: error.message });
throw error;
}
}
@Get(':id')
@Roles('admin', 'user')
@ApiOperation({ summary: '根据ID获取${baseName}' })
@ApiResponseWrapper({ description: '详情数据' })
async findById(@Param('id') id: number) {
this.logger.info('获取详情', { id });
try {
const result = await this.${serviceName}.findById(id);
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取详情失败', { error: error.message, id });
throw error;
}
}
@Post()
@ApiOperation({ summary: '创建${baseName}' })
@ApiResponse({ status: 201, description: '创建成功' })
async create(@Body() createDto: any) {
this.logger.log('create called', createDto);
try {
return await this.${serviceName}.create(createDto);
} catch (error) {
this.logger.error('create failed', error);
throw error;
}
}
@Put(':id')
@ApiOperation({ summary: '更新${baseName}' })
@ApiResponse({ status: 200, description: '更新成功' })
async update(@Param('id') id: number, @Body() updateDto: any) {
this.logger.log(\`update called with id: \${id}\`, updateDto);
try {
return await this.${serviceName}.update(id, updateDto);
} catch (error) {
this.logger.error('update failed', error);
throw error;
}
}
@Delete(':id')
@ApiOperation({ summary: '删除${baseName}' })
@ApiResponse({ status: 200, description: '删除成功' })
async delete(@Param('id') id: number) {
this.logger.log(\`delete called with id: \${id}\`);
try {
await this.${serviceName}.delete(id);
return { success: true };
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}`;
}
/**
* 生成单个端点 - 使用真实的Java端点信息和映射的注解
*/
generateEndpoint(endpoint, controllerName) {
const httpMethod = endpoint.method || 'GET';
const nestMethod = httpMethod.charAt(0).toUpperCase() + httpMethod.slice(1).toLowerCase();
const path = endpoint.path || '/';
const methodName = endpoint.methodName || 'handle';
const comment = endpoint.comment || `${httpMethod}操作`;
const returnType = this.mapJavaTypeToTs(endpoint.returnType || 'Result');
// 生成参数
const params = (endpoint.params || []).map(p => {
const tsType = this.mapJavaTypeToTs(p.type);
// 判断参数装饰器
let decorator = '@Body()';
if (httpMethod === 'GET') {
decorator = '@Query()';
} else if (p.name === 'id' || p.name.endsWith('Id')) {
decorator = '@Param()';
}
return `${decorator} ${p.name}: ${tsType}`;
}).join(', ');
// 生成映射的注解
const decorators = (endpoint.mappedAnnotations || []).map(annotation =>
` ${annotation}`
).join('\n');
// 默认装饰器
const defaultDecorators = [
`@${nestMethod}('${path}')`,
`@Roles('admin')`,
`@ApiOperation({ summary: '${comment}' })`,
`@ApiResponseWrapper({ description: '${comment}结果' })`
];
const allDecorators = [...defaultDecorators, ...(endpoint.mappedAnnotations || [])];
// 生成业务逻辑 - 传递Java方法体确保一致性
const businessLogic = this.generateEndpointBusinessLogic(
methodName,
httpMethod,
endpoint.params || [],
endpoint.methodBody || ''
);
return ` /**
* ${comment}
* Java方法: ${endpoint.returnType || 'Result'} ${methodName}(...)
*/
${allDecorators.map(d => ` ${d}`).join('\n')}
async ${methodName}(${params}) {
this.logger.info('${comment}', { ${(endpoint.params || []).map(p => p.name).join(', ')} });
try {
${businessLogic}
} catch (error) {
this.logger.error('${comment}失败', { error: error.message });
throw error;
}
}`;
}
/**
* 生成端点业务逻辑 - 与Java项目保持100%一致
*/
generateEndpointBusinessLogic(methodName, httpMethod, params, javaMethodBody) {
// 如果有Java方法体优先使用转换后的业务逻辑
if (javaMethodBody && javaMethodBody.trim() !== '') {
return this.convertJavaMethodBodyToNestJS(javaMethodBody, methodName, params);
}
// 根据方法名和HTTP方法生成具体的实现
if (methodName.includes('list') || methodName.includes('findAll') || httpMethod === 'GET') {
return this.generateListEndpointLogic(params);
} else if (methodName.includes('get') || methodName.includes('findById')) {
return this.generateGetEndpointLogic(params);
} else if (methodName.includes('save') || methodName.includes('create') || httpMethod === 'POST') {
return this.generateSaveEndpointLogic(params);
} else if (methodName.includes('update') || httpMethod === 'PUT') {
return this.generateUpdateEndpointLogic(params);
} else if (methodName.includes('delete') || methodName.includes('remove') || httpMethod === 'DELETE') {
return this.generateDeleteEndpointLogic(params);
} else if (methodName.includes('page') || methodName.includes('paginate')) {
return this.generatePageEndpointLogic(params);
} else if (methodName.includes('handleError')) {
return this.generateErrorHandlerLogic(params);
}
return `// TODO: 调用对应的Service方法实现业务逻辑
return { code: 0, msg: '操作成功', data: null };`;
}
/**
* 转换Java方法体到NestJS - 确保与Java项目100%一致
*/
convertJavaMethodBodyToNestJS(javaMethodBody, methodName, params) {
let tsCode = javaMethodBody;
// 转换Java语法到TypeScript
tsCode = tsCode.replace(/Result\.fail\(/g, 'Result.fail(');
tsCode = tsCode.replace(/\.getAttribute\(/g, '.getAttribute(');
tsCode = tsCode.replace(/HttpStatus\./g, 'HttpStatus.');
tsCode = tsCode.replace(/\.value\(\)/g, '.value()');
tsCode = tsCode.replace(/\.getReasonPhrase\(\)/g, '.getReasonPhrase()');
tsCode = tsCode.replace(/\.getContextPath\(\)/g, '.getContextPath()');
tsCode = tsCode.replace(/\.setData\(/g, '.setData(');
// 转换变量声明
tsCode = tsCode.replace(/Integer\s+(\w+)/g, 'let $1: number');
tsCode = tsCode.replace(/Result\s+(\w+)/g, 'let $1: any');
// 转换条件判断 - 确保完全一致
tsCode = tsCode.replace(/if\s*\(\s*(\w+)\s*==\s*(\w+)\.value\(\)\s*\)/g, 'if ($1 === $2.value())');
tsCode = tsCode.replace(/else\s+if\s*\(\s*(\w+)\s*==\s*(\w+)\.value\(\)\s*\)/g, 'else if ($1 === $2.value())');
// 转换其他Java语法
tsCode = tsCode.replace(/String\.valueOf\(/g, 'String(');
tsCode = tsCode.replace(/\(Integer\)/g, '');
tsCode = tsCode.replace(/==/g, '===');
tsCode = tsCode.replace(/!=/g, '!==');
// 确保缩进正确
tsCode = tsCode.split('\n').map(line => {
if (line.trim()) {
return ' ' + line.trim();
}
return line;
}).join('\n');
return tsCode;
}
/**
* 生成错误处理逻辑对应Java的HttpServerErrorController
*/
generateErrorHandlerLogic(params) {
return `const statusCode = request.getAttribute('javax.servlet.error.status_code', WebRequest.SCOPE_REQUEST);
if (statusCode === HttpStatus.INTERNAL_SERVER_ERROR.value()) {
const result = Result.fail(statusCode, HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
result.setData(request.getContextPath());
return result;
} else if (statusCode === HttpStatus.NOT_FOUND.value()) {
const result = Result.fail(statusCode, HttpStatus.NOT_FOUND.getReasonPhrase());
result.setData(request.getContextPath());
return result;
} else {
const result = Result.fail(statusCode, String(statusCode));
result.setData(request.getContextPath());
return result;
}`;
}
/**
* 生成列表查询端点逻辑
*/
generateListEndpointLogic(params) {
const queryParam = params.find(p => p.name === 'query' || p.name.includes('Param') || p.name.includes('Search'));
if (queryParam) {
return `const result = await this.service.findAll(${queryParam.name});
return { code: 0, msg: '获取成功', data: result };`;
}
return `const result = await this.service.findAll();
return { code: 0, msg: '获取成功', data: result };`;
}
/**
* 生成单条查询端点逻辑
*/
generateGetEndpointLogic(params) {
const idParam = params.find(p => p.name === 'id' || p.name.endsWith('Id'));
if (idParam) {
return `const result = await this.service.findById(${idParam.name});
if (!result) {
return { code: 404, msg: '记录不存在', data: null };
}
return { code: 0, msg: '获取成功', data: result };`;
}
return `const result = await this.service.findById(id);
if (!result) {
return { code: 404, msg: '记录不存在', data: null };
}
return { code: 0, msg: '获取成功', data: result };`;
}
/**
* 生成保存端点逻辑
*/
generateSaveEndpointLogic(params) {
const dataParam = params.find(p => p.name === 'data' || p.name.includes('Param') || p.name.includes('Dto'));
if (dataParam) {
return `const result = await this.service.save(${dataParam.name});
return { code: 0, msg: '保存成功', data: result };`;
}
return `const result = await this.service.save(data);
return { code: 0, msg: '保存成功', data: result };`;
}
/**
* 生成更新端点逻辑
*/
generateUpdateEndpointLogic(params) {
const idParam = params.find(p => p.name === 'id' || p.name.endsWith('Id'));
const dataParam = params.find(p => p.name === 'data' || p.name.includes('Param') || p.name.includes('Dto'));
if (idParam && dataParam) {
return `const result = await this.service.update(${idParam.name}, ${dataParam.name});
return { code: 0, msg: '更新成功', data: result };`;
}
return `const result = await this.service.update(id, data);
return { code: 0, msg: '更新成功', data: result };`;
}
/**
* 生成删除端点逻辑
*/
generateDeleteEndpointLogic(params) {
const idParam = params.find(p => p.name === 'id' || p.name.endsWith('Id'));
if (idParam) {
return `await this.service.delete(${idParam.name});
return { code: 0, msg: '删除成功', data: null };`;
}
return `await this.service.delete(id);
return { code: 0, msg: '删除成功', data: null };`;
}
/**
* 生成分页端点逻辑
*/
generatePageEndpointLogic(params) {
const pageParam = params.find(p => p.name === 'page' || p.name.includes('Page'));
const queryParam = params.find(p => p.name === 'query' || p.name.includes('Param') || p.name.includes('Search'));
if (pageParam && queryParam) {
return `const result = await this.service.page(${pageParam.name}, ${queryParam.name});
return { code: 0, msg: '获取成功', data: result };`;
}
return `const result = await this.service.page(page, size, query);
return { code: 0, msg: '获取成功', data: result };`;
}
/**
* 映射Java类型到TypeScript增强版
*/
mapJavaTypeToTs(javaType) {
const typeMap = {
'Result': 'any',
'ResponseEntity': 'any',
'String': 'string',
'Integer': 'number',
'Long': 'number',
'Double': 'number',
'Float': 'number',
'Boolean': 'boolean',
'void': 'void',
'Date': 'Date',
'BigDecimal': 'number',
'List': 'any[]',
'Map': 'Record<string, any>',
'JSONObject': 'any',
'JSONArray': 'any[]'
};
// 处理泛型
const baseType = javaType.replace(/<.*>/, '');
return typeMap[baseType] || 'any';
}
/**
* 生成单个端点(旧方法)
*/
generateEndpointOld(endpoint, controllerName) {
const method = this.mapJavaMethodToNestJS(endpoint.method);
const path = endpoint.path || '/';
const baseName = controllerName.replace(/Controller$/, '').toLowerCase();
return ` @${method}('${path}')
@ApiOperation({ summary: '${method.toLowerCase()}操作' })
async ${this.toCamelCase(method)}${baseName}() {
this.logger.log('${method.toLowerCase()} called');
try {
// TODO: 实现${method.toLowerCase()}逻辑
return { success: true };
} catch (error) {
this.logger.error('${method.toLowerCase()} failed', error);
throw error;
}
}`;
}
/**
* 提取路由前缀 - 从Java控制器数据中提取
*/
extractRoutePrefix(controllerData) {
// 从Java的@RequestMapping注解中提取路径
if (controllerData.mapping) {
return controllerData.mapping;
}
// 从文件路径推断adminapi 或 api
if (controllerData.filePath) {
if (controllerData.filePath.includes('/adminapi/')) {
return 'adminapi'; // 管理端API
} else if (controllerData.filePath.includes('/api/')) {
return 'api'; // 前台API
}
}
// 默认返回空让NestJS使用默认路由
return '';
}
/**
* 映射Java HTTP方法到NestJS
*/
mapJavaMethodToNestJS(javaMethod) {
const methodMap = {
'GetMapping': 'Get',
'PostMapping': 'Post',
'PutMapping': 'Put',
'DeleteMapping': 'Delete',
'RequestMapping': 'Get' // 默认映射
};
return methodMap[javaMethod] || 'Get';
}
/**
* 转换为kebab-case
*/
toKebabCase(str) {
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
}
/**
* 转换为camelCase
*/
toCamelCase(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
}
module.exports = ControllerGenerator;

View File

@@ -0,0 +1,250 @@
const fs = require('fs');
const path = require('path');
/**
* 🏗️ 实体生成器
* 基于Java实体生成NestJS TypeORM实体
*/
class EntityGenerator {
constructor(config) {
this.config = config;
}
/**
* 生成实体文件 - 兼容旧版本
*/
async generate(entityName, entityData) {
return await this.generateFromLayer(entityName, entityData);
}
/**
* 按层级生成实体文件
*/
async generateFromLayer(entityName, entityData) {
const fileName = `${this.toKebabCase(entityName)}.entity.ts`;
// 实体文件生成到core层
const filePath = path.join(this.config.corePath, 'entities', fileName);
console.log(`\n🔧 Entity生成器 - ${entityName}:`);
console.log(` 文件名: ${fileName}`);
console.log(` 路径: ${filePath}`);
console.log(` dryRun: ${this.config.dryRun}`);
const content = this.generateEntityContent(entityName, entityData);
console.log(` 内容长度: ${content.length}`);
if (!this.config.dryRun) {
const dirPath = path.dirname(filePath);
console.log(` 确保目录存在: ${dirPath}`);
this.ensureDir(dirPath);
console.log(` 写入文件...`);
fs.writeFileSync(filePath, content, 'utf-8');
// 验证文件是否写入成功
if (fs.existsSync(filePath)) {
const writtenContent = fs.readFileSync(filePath, 'utf-8');
console.log(` ✅ 文件写入成功,长度: ${writtenContent.length}`);
} else {
console.log(` ❌ 文件写入失败`);
}
} else {
console.log(` ⏭️ dryRun模式跳过文件写入`);
}
}
/**
* 生成实体内容 - 确保与Java数据库完全兼容
*/
generateEntityContent(entityName, entityData) {
const tableName = entityData.tableName || this.toSnakeCase(entityName);
const className = entityName;
const imports = this.generateImports(entityData);
const columns = this.generateColumns(entityData.fields);
return `${imports}
/**
* ${className} 实体
*
* ⚠️ 数据库一致性约束与Java共享
* ─────────────────────────────────────────
* 对应Java实体: ${entityName}
* 数据库表名: ${tableName}
*
* 严格要求:
* 1. ✅ 所有字段使用 @Column({ name: 'xxx' }) 明确指定数据库列名(下划线格式)
* 2. ✅ TypeScript属性名使用驼峰与Java一致
* 3. ✅ 数据库列名使用下划线(与表结构一致)
* 4. ❌ 禁止添加或删除字段
* 5. ❌ 禁止修改字段类型
* 6. ❌ 禁止修改表名
*
* 示例:
* - Java: private Integer siteId;
* - DB列: site_id
* - NestJS: @Column({ name: 'site_id' }) siteId: number;
*/
@Entity('${tableName}')
export class ${className} {
${columns}
}`;
}
/**
* 生成导入语句
*/
generateImports(entityData) {
const imports = [
"import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';"
];
return imports.join('\n');
}
/**
* 生成列定义 - 使用真实的Java字段信息
*/
generateColumns(fields) {
if (!fields || fields.length === 0) {
console.log('⚠️ Entity生成器警告: 没有字段数据,使用默认主键');
return ` @PrimaryGeneratedColumn()
id: number;`;
}
console.log(`🔧 Entity生成器: 处理${fields.length}个字段`);
const columns = [];
// 添加所有字段
for (const field of fields) {
const column = this.generateColumn(field);
if (column) {
columns.push(column);
console.log(` ✅ 生成字段: ${field.name} (${field.type})`);
} else {
console.log(` ❌ 跳过字段: ${field.name} (${field.type})`);
}
}
const result = columns.join('\n\n');
console.log(`🔧 Entity生成器: 生成${columns.length}个列定义`);
return result;
}
/**
* 生成单个列 - 使用真实的Java字段信息和映射的注解
*/
generateColumn(field) {
const fieldName = field.name;
const tsType = this.mapJavaTypeToTs(field.type);
const dbColumnName = field.dbColumnName || this.toSnakeCase(fieldName);
const comment = field.comment ? ` // ${field.comment}` : '';
// 跳过不需要持久化的字段
if (!field.select) {
return ` // ${field.comment || fieldName} - 不持久化到数据库
// @TableField(select = false)${comment}`;
}
// 使用映射的注解
const decorators = field.mappedAnnotations || [];
// 主键处理
if (field.isPrimaryKey) {
const primaryDecorators = decorators.filter(d => d.includes('@PrimaryGeneratedColumn') || d.includes('@Column'));
const otherDecorators = decorators.filter(d => !d.includes('@PrimaryGeneratedColumn') && !d.includes('@Column'));
return ` /**
* ${field.comment || '主键'}
* Java字段: ${fieldName}
* 数据库列: ${dbColumnName}
*/
${primaryDecorators.join('\n ')}
${otherDecorators.length > 0 ? otherDecorators.join('\n ') + '\n' : ''}${fieldName}: ${tsType};`;
}
// 处理特殊类型
const columnOptions = [`name: '${dbColumnName}'`];
if (tsType === 'Date') {
columnOptions.push(`type: 'timestamp'`);
} else if (field.type.includes('JSON') || field.type.toLowerCase().includes('list') || field.type.toLowerCase().includes('map')) {
columnOptions.push(`type: 'json'`);
}
if (field.nullable) {
columnOptions.push(`nullable: true`);
}
// 使用映射的注解,如果没有则使用默认的@Column
const columnDecorator = decorators.find(d => d.includes('@Column')) || `@Column({ ${columnOptions.join(', ')} })`;
const otherDecorators = decorators.filter(d => !d.includes('@Column'));
return ` /**
* ${field.comment || fieldName}
* Java字段: ${field.type} ${fieldName}
* 数据库列: ${dbColumnName}
*/
${columnDecorator}
${otherDecorators.length > 0 ? otherDecorators.join('\n ') + '\n' : ''}${fieldName}: ${tsType};`;
}
/**
* 映射Java类型到TypeScript类型
*/
mapJavaTypeToTs(javaType) {
const typeMap = {
'String': 'string',
'Integer': 'number',
'Long': 'number',
'Double': 'number',
'Float': 'number',
'Boolean': 'boolean',
'Date': 'Date',
'BigDecimal': 'number',
'byte[]': 'Buffer',
'List': 'any[]',
'Map': 'Record<string, any>',
'JSONObject': 'any',
'JSONArray': 'any[]'
};
// 处理泛型
const baseType = javaType.replace(/<.*>/, '').replace(/\[\]/, '');
return typeMap[baseType] || 'any';
}
/**
* 检查是否应该跳过字段
*/
shouldSkipField(fieldName) {
const skipFields = ['serialVersionUID', 'password', 'secret'];
return skipFields.includes(fieldName);
}
/**
* 转换为snake_case
*/
toSnakeCase(str) {
return str.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
}
/**
* 转换为kebab-case
*/
toKebabCase(str) {
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
}
module.exports = EntityGenerator;

View File

@@ -0,0 +1,322 @@
const fs = require('fs');
const path = require('path');
/**
* 📦 模块生成器
* 基于扫描的Java模块生成NestJS模块
*/
class ModuleGenerator {
constructor(config) {
this.config = config;
}
/**
* 生成模块文件 - 兼容旧版本
*/
async generate(moduleName, moduleData) {
return await this.generateFromLayers({ modules: { [moduleName]: moduleData } });
}
/**
* 按层级生成模块文件
*/
async generateFromLayers(layerData) {
const fileName = `core.module.ts`;
const filePath = path.join(this.config.corePath, fileName);
const content = this.generateLayerModuleContent(layerData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成模块内容
*/
generateModuleContent(moduleName, moduleData) {
const className = `${this.toPascalCase(moduleName)}Module`;
const imports = this.generateImports(moduleName);
const controllers = this.generateControllerImports(moduleName);
const services = this.generateServiceImports(moduleName);
const entities = this.generateEntityImports(moduleName);
return `${imports}
${controllers}
${services}
${entities}
/**
* ${className} - ${moduleName}模块
* 基于Java模块: ${moduleName}
*/
@Module({
imports: [
TypeOrmModule.forFeature([
${entities.split('\n').filter(line => line.includes('import')).map(line => {
const match = line.match(/import \{ (\w+) \}/);
return match ? ` ${match[1]}` : null;
}).filter(Boolean).join(',\n')}
])
],
controllers: [
${controllers.split('\n').filter(line => line.includes('import')).map(line => {
const match = line.match(/import \{ (\w+) \}/);
return match ? ` ${match[1]}` : null;
}).filter(Boolean).join(',\n')}
],
providers: [
${services.split('\n').filter(line => line.includes('import')).map(line => {
const match = line.match(/import \{ (\w+) \}/);
return match ? ` ${match[1]}` : null;
}).filter(Boolean).join(',\n')}
],
exports: [
${services.split('\n').filter(line => line.includes('import')).map(line => {
const match = line.match(/import \{ (\w+) \}/);
return match ? ` ${match[1]}` : null;
}).filter(Boolean).join(',\n')}
]
})
export class ${className} {}
`;
}
/**
* 生成层级模块内容
*/
generateLayerModuleContent(layerData) {
const imports = this.generateLayerImports();
const entityImports = this.generateLayerEntityImports(layerData);
const serviceImports = this.generateLayerServiceImports(layerData);
const controllerImports = this.generateLayerControllerImports(layerData);
return `${imports}
${entityImports}
${serviceImports}
${controllerImports}
/**
* CoreModule - 按层级结构生成的模块
* 基于Java层级: entities, services, controllers
*/
@Module({
imports: [
TypeOrmModule.forFeature([
${this.generateEntityArray(layerData)}
])
],
controllers: [
${this.generateControllerArray(layerData)}
],
providers: [
${this.generateProviderArray(layerData)}
],
exports: [
${this.generateProviderArray(layerData)}
]
})
export class CoreModule {}
`;
}
/**
* 生成基础导入
*/
generateLayerImports() {
return `import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';`;
}
/**
* 生成层级实体导入
*/
generateLayerEntityImports(layerData) {
if (!layerData.entities || Object.keys(layerData.entities).length === 0) {
return '';
}
return Object.keys(layerData.entities).map(entityName => {
return `import { ${entityName} } from './entities/${entityName.toLowerCase()}.entity';`;
}).join('\n');
}
/**
* 生成层级服务导入
*/
generateLayerServiceImports(layerData) {
if (!layerData.services || Object.keys(layerData.services).length === 0) {
return '';
}
return Object.keys(layerData.services).map(serviceName => {
return `import { ${serviceName}Service } from './services/${serviceName.toLowerCase()}.service';`;
}).join('\n');
}
/**
* 生成层级控制器导入
*/
generateLayerControllerImports(layerData) {
if (!layerData.controllers || Object.keys(layerData.controllers).length === 0) {
return '';
}
return Object.keys(layerData.controllers).map(controllerName => {
return `import { ${controllerName}Controller } from './controllers/${controllerName.toLowerCase()}.controller';`;
}).join('\n');
}
/**
* 生成实体数组
*/
generateEntityArray(layerData) {
if (!layerData.entities || Object.keys(layerData.entities).length === 0) {
return ' // 暂无实体';
}
return Object.keys(layerData.entities).map(entityName => {
return ` ${entityName}`;
}).join(',\n');
}
/**
* 生成控制器数组
*/
generateControllerArray(layerData) {
if (!layerData.controllers || Object.keys(layerData.controllers).length === 0) {
return ' // 暂无控制器';
}
return Object.keys(layerData.controllers).map(controllerName => {
return ` ${controllerName}Controller`;
}).join(',\n');
}
/**
* 生成提供者数组
*/
generateProviderArray(layerData) {
if (!layerData.services || Object.keys(layerData.services).length === 0) {
return ' // 暂无服务';
}
return Object.keys(layerData.services).map(serviceName => {
return ` ${serviceName}Service`;
}).join(',\n');
}
/**
* 生成基础导入 - 兼容旧版本
*/
generateImports(moduleName) {
return `import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';`;
}
/**
* 生成控制器导入
*/
generateControllerImports(moduleName) {
const controllers = this.findFilesInDirectory(
path.join(this.config.nestjsBasePath, moduleName, 'controllers'),
'.controller.ts'
);
if (controllers.length === 0) {
return '';
}
return controllers.map(controller => {
const controllerName = path.basename(controller, '.controller.ts');
const className = `${this.toPascalCase(controllerName)}Controller`;
return `import { ${className} } from './controllers/${controllerName}.controller';`;
}).join('\n');
}
/**
* 生成服务导入
*/
generateServiceImports(moduleName) {
const services = this.findFilesInDirectory(
path.join(this.config.nestjsBasePath, moduleName, 'services'),
'.service.ts'
);
if (services.length === 0) {
return '';
}
return services.map(service => {
const serviceName = path.basename(service, '.service.ts');
const className = `${this.toPascalCase(serviceName)}Service`;
return `import { ${className} } from './services/${serviceName}.service';`;
}).join('\n');
}
/**
* 生成实体导入
*/
generateEntityImports(moduleName) {
const entities = this.findFilesInDirectory(
path.join(this.config.nestjsBasePath, moduleName, 'entities'),
'.entity.ts'
);
if (entities.length === 0) {
return '';
}
return entities.map(entity => {
const entityName = path.basename(entity, '.entity.ts');
const className = this.toPascalCase(entityName);
return `import { ${className} } from './entities/${entityName}.entity';`;
}).join('\n');
}
/**
* 查找目录中的文件
*/
findFilesInDirectory(dirPath, extension) {
if (!fs.existsSync(dirPath)) {
return [];
}
try {
const files = fs.readdirSync(dirPath);
return files
.filter(file => file.endsWith(extension))
.map(file => path.join(dirPath, file));
} catch (error) {
return [];
}
}
/**
* 转换为PascalCase
*/
toPascalCase(str) {
return str.split(/[-_]/)
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join('');
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
}
module.exports = ModuleGenerator;

View File

@@ -0,0 +1,596 @@
const fs = require('fs');
const path = require('path');
/**
* ⚙️ 服务生成器
* 基于Java服务生成NestJS服务
*/
class ServiceGenerator {
constructor(config) {
this.config = config;
}
/**
* 生成服务文件 - 兼容旧版本
*/
async generate(serviceName, serviceData) {
return await this.generateFromLayer(serviceName, serviceData);
}
/**
* 按层级生成服务文件
*/
async generateFromLayer(serviceName, serviceData) {
// 从uniqueKey中提取真实的类名移除layer前缀
const realName = serviceData.name || serviceName.replace(/^(admin|api|core)_/, '');
// 移除Service/ServiceImpl后缀避免重复
const baseName = realName.replace(/Service(Impl)?$/, '');
const fileName = `${this.toKebabCase(baseName)}.service.ts`;
// 根据layer信息创建对应的子目录admin/api/core
const layer = serviceData.layer || 'core';
const filePath = path.join(this.config.corePath, 'services', layer, fileName);
const content = this.generateServiceContent(serviceName, serviceData);
if (!this.config.dryRun) {
this.ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, content, 'utf-8');
}
}
/**
* 生成服务内容
*/
generateServiceContent(serviceName, serviceData) {
const className = `${serviceName}Service`;
const imports = this.generateImports(serviceData);
const constructor = this.generateConstructor(serviceName, serviceData);
const methods = this.generateMethods(serviceData.methods);
return `${imports}
/**
* ${className} - 基于Java服务转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享数据库和Admin面板业务逻辑必须保持一致
* 对应Java服务: ${serviceName}
*
* 一致性要求:
* 1. 业务方法名必须与Java服务方法对应
* 2. 数据处理逻辑必须与Java保持一致
* 3. 数据库操作(增删改查)必须使用相同的字段
* 4. 返回数据格式必须与Java一致
* 5. 租户隔离site_id必须在所有查询中应用
*
* V1框架能力
* - WinstonService: 结构化日志
* - CacheService: 多级缓存(标签支持)
* - RequestContextService: 请求上下文(租户、用户等)
*/
@Injectable()
export class ${className} {
${constructor}
${methods}
}`;
}
/**
* 生成导入语句 - 使用V1框架基础设施
*/
generateImports(serviceData) {
const imports = [
"import { Injectable } from '@nestjs/common';",
"import { InjectRepository } from '@nestjs/typeorm';",
"import { Repository } from 'typeorm';",
"",
"// V1框架基础设施",
"import { WinstonService } from '@wwjCommon/logging/winston.service';",
"import { CacheService } from '@wwjCommon/cache/cache.service';",
"import { RequestContextService } from '@wwjCommon/context/request-context.service';",
"",
"// TODO: 根据实际需要导入相关实体和DTO"
];
return imports.join('\n');
}
/**
* 生成构造函数 - 注入V1框架基础设施
*/
generateConstructor(serviceName, serviceData) {
const injections = this.extractDependencies(serviceData.content);
const baseInfra = [
` private readonly logger: WinstonService`,
` private readonly cache: CacheService`,
` private readonly requestContext: RequestContextService`
];
const repositoryInjects = injections.map(inj =>
` @InjectRepository(${inj.type}) private readonly ${inj.name}: Repository<${inj.type}>`
);
const allParams = [...baseInfra, ...repositoryInjects].join(',\n');
return ` constructor(
${allParams}
) {}`;
}
/**
* 提取依赖注入信息
*/
extractDependencies(content) {
const dependencies = [];
// 简单的依赖提取基于常见的Java注入模式
const repositoryRegex = /@Autowired.*?(\w+)Repository/g;
let match;
while ((match = repositoryRegex.exec(content)) !== null) {
dependencies.push({
type: match[1],
name: `${this.toCamelCase(match[1])}Repository`
});
}
return dependencies;
}
/**
* 生成方法 - 使用真实的Java方法信息
*/
generateMethods(methods) {
if (!methods || methods.length === 0) {
return this.generateDefaultMethods();
}
const methodStrings = methods.map(method =>
this.generateMethodFromJava(method)
);
return methodStrings.join('\n\n');
}
/**
* 生成默认方法 - 使用V1框架基础设施
*/
generateDefaultMethods() {
return ` /**
* 获取列表 - 使用V1框架缓存和日志
*/
async findAll(): Promise<any[]> {
const cacheKey = 'service:findAll';
// 尝试从缓存获取
const cached = await this.cache.get(cacheKey);
if (cached) {
this.logger.debug('从缓存返回列表数据', { cacheKey });
return cached;
}
try {
this.logger.info('查询列表', {
siteId: this.requestContext.getSiteId(),
userId: this.requestContext.getUserId()
});
// TODO: 实现查询逻辑
const result = [];
// 缓存结果
await this.cache.set(cacheKey, result, 300); // 5分钟
return result;
} catch (error) {
this.logger.error('查询列表失败', { error: error.message, stack: error.stack });
throw error;
}
}
/**
* 根据ID查找 - 使用V1框架租户隔离
*/
async findById(id: number): Promise<any> {
const siteId = this.requestContext.getSiteId();
const cacheKey = \`service:findById:\${id}:\${siteId}\`;
this.logger.info('查询详情', { id, siteId });
try {
// TODO: 实现查找逻辑
return null;
} catch (error) {
this.logger.error('findById failed', error);
throw error;
}
}
/**
* 创建
*/
async create(data: any): Promise<any> {
this.logger.log('create called', data);
try {
// TODO: 实现创建逻辑
return data;
} catch (error) {
this.logger.error('create failed', error);
throw error;
}
}
/**
* 更新
*/
async update(id: number, data: any): Promise<any> {
this.logger.log(\`update called with id: \${id}\`, data);
try {
// TODO: 实现更新逻辑
return data;
} catch (error) {
this.logger.error('update failed', error);
throw error;
}
}
/**
* 删除
*/
async delete(id: number): Promise<void> {
this.logger.log(\`delete called with id: \${id}\`);
try {
// TODO: 实现删除逻辑
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}`;
}
/**
* 从Java方法生成TypeScript方法完整签名、注解和业务逻辑
*/
generateMethodFromJava(method) {
const methodName = method.name;
const returnType = this.mapJavaTypeToTs(method.returnType);
const comment = method.comment || methodName;
// 生成参数列表
const params = (method.params || []).map(p => {
const tsType = this.mapJavaTypeToTs(p.type);
return `${p.name}: ${tsType}`;
}).join(', ');
const paramsList = params ? params : '';
const paramsLog = (method.params || []).map(p => p.name).join(', ');
// 生成映射的注解
const decorators = (method.mappedAnnotations || []).map(annotation =>
` ${annotation}`
).join('\n');
// 生成业务逻辑
const businessLogic = this.generateBusinessLogic(method);
return ` /**
* ${comment}
* Java方法: ${method.returnType} ${methodName}(${(method.params || []).map(p => p.type + ' ' + p.name).join(', ')})
*/
${decorators ? decorators + '\n' : ''} async ${methodName}(${paramsList}): Promise<${returnType}> {
this.logger.info('${comment}', { ${paramsLog} });
try {
${businessLogic}
} catch (error) {
this.logger.error('${methodName}失败', { error: error.message });
throw error;
}
}`;
}
/**
* 生成业务逻辑
*/
generateBusinessLogic(method) {
if (!method.businessLogic) {
return this.generateDefaultBusinessLogic(method);
}
const logic = method.businessLogic;
// 如果转换的代码为空或只有注释,使用默认实现
if (!logic.convertedTypeScript || logic.convertedTypeScript.trim() === '' ||
logic.convertedTypeScript.trim().startsWith('//')) {
return this.generateDefaultBusinessLogic(method);
}
// 添加复杂度提示
let result = '';
if (logic.complexity === 'high') {
result += `// ⚠️ 高复杂度方法,需要仔细审查\n `;
}
if (logic.needsManualReview) {
result += `// ⚠️ 需要手工审查的复杂逻辑\n `;
}
// 添加建议
if (logic.suggestions && logic.suggestions.length > 0) {
result += `// 💡 建议:\n`;
logic.suggestions.forEach(suggestion => {
result += ` // - ${suggestion}\n`;
});
result += ` \n`;
}
// 添加转换后的代码
result += logic.convertedTypeScript;
return result;
}
/**
* 生成默认业务逻辑
*/
generateDefaultBusinessLogic(method) {
const methodName = method.name;
const returnType = this.mapJavaTypeToTs(method.returnType);
// 根据方法名生成具体的实现
if (methodName.includes('list') || methodName.includes('findAll')) {
return this.generateListImplementation(method);
} else if (methodName.includes('get') || methodName.includes('findById')) {
return this.generateGetImplementation(method);
} else if (methodName.includes('save') || methodName.includes('create')) {
return this.generateSaveImplementation(method);
} else if (methodName.includes('update')) {
return this.generateUpdateImplementation(method);
} else if (methodName.includes('delete') || methodName.includes('remove')) {
return this.generateDeleteImplementation(method);
} else if (methodName.includes('page') || methodName.includes('paginate')) {
return this.generatePageImplementation(method);
}
return `// TODO: 实现${methodName}业务逻辑
// 对应Java方法需要保持业务逻辑一致
${this.getDefaultReturnValue(returnType)}`;
}
/**
* 生成列表查询实现
*/
generateListImplementation(method) {
return `const queryBuilder = this.repository.createQueryBuilder('entity');
// 添加查询条件
// TODO: 根据实际需求添加where条件
const data = await queryBuilder.getMany();
return data;`;
}
/**
* 生成单条查询实现
*/
generateGetImplementation(method) {
const params = method.params || [];
const idParam = params.find(p => p.name === 'id' || p.name.endsWith('Id'));
if (idParam) {
return `const data = await this.repository.findOne({
where: { id: ${idParam.name} }
});
if (!data) {
throw new Error('Record not found');
}
return data;`;
}
return `const data = await this.repository.findOne({
where: {}
});
return data;`;
}
/**
* 生成保存实现
*/
generateSaveImplementation(method) {
const params = method.params || [];
const dataParam = params.find(p => p.name === 'data' || p.name.includes('Param') || p.name.includes('Dto'));
if (dataParam) {
return `const entity = this.repository.create(${dataParam.name});
const result = await this.repository.save(entity);
return result;`;
}
return `const entity = this.repository.create(data);
const result = await this.repository.save(entity);
return result;`;
}
/**
* 生成更新实现
*/
generateUpdateImplementation(method) {
const params = method.params || [];
const idParam = params.find(p => p.name === 'id' || p.name.endsWith('Id'));
const dataParam = params.find(p => p.name === 'data' || p.name.includes('Param') || p.name.includes('Dto'));
if (idParam && dataParam) {
return `const entity = await this.repository.findOne({
where: { id: ${idParam.name} }
});
if (!entity) {
throw new Error('Record not found');
}
Object.assign(entity, ${dataParam.name});
const result = await this.repository.save(entity);
return result;`;
}
return `const entity = await this.repository.findOne({
where: { id }
});
if (!entity) {
throw new Error('Record not found');
}
Object.assign(entity, data);
const result = await this.repository.save(entity);
return result;`;
}
/**
* 生成删除实现
*/
generateDeleteImplementation(method) {
const params = method.params || [];
const idParam = params.find(p => p.name === 'id' || p.name.endsWith('Id'));
if (idParam) {
return `const result = await this.repository.delete({ id: ${idParam.name} });
if (result.affected === 0) {
throw new Error('Record not found');
}
return { success: true };`;
}
return `const result = await this.repository.delete({ id });
if (result.affected === 0) {
throw new Error('Record not found');
}
return { success: true };`;
}
/**
* 生成分页实现
*/
generatePageImplementation(method) {
return `const queryBuilder = this.repository.createQueryBuilder('entity');
// 添加查询条件
// TODO: 根据实际需求添加where条件
const [data, total] = await queryBuilder
.skip((page - 1) * size)
.take(size)
.getManyAndCount();
return {
data,
total,
page,
size,
pages: Math.ceil(total / size)
};`;
}
/**
* 生成单个方法
*/
generateMethod(method) {
const methodName = method.name;
const returnType = this.mapJavaTypeToTs(method.returnType);
return ` /**
* ${methodName} - 基于Java方法转换
*/
async ${methodName}(): Promise<${returnType}> {
this.logger.log('${methodName} called');
try {
// TODO: 实现${methodName}业务逻辑
${this.getDefaultReturnValue(returnType)}
} catch (error) {
this.logger.error('${methodName} failed', error);
throw error;
}
}`;
}
/**
* 获取默认返回值
*/
getDefaultReturnValue(type) {
if (type.includes('[]')) {
return 'return [];';
}
if (type === 'Promise<void>') {
return 'return;';
}
if (type === 'Promise<boolean>') {
return 'return false;';
}
if (type === 'Promise<number>') {
return 'return 0;';
}
if (type === 'Promise<string>') {
return "return '';";
}
return 'return null;';
}
/**
* 映射Java类型到TypeScript类型
*/
mapJavaTypeToTs(javaType) {
const typeMap = {
'void': 'void',
'String': 'string',
'Integer': 'number',
'Long': 'number',
'Double': 'number',
'Float': 'number',
'Boolean': 'boolean',
'Date': 'Date',
'BigDecimal': 'number',
'List': 'any[]',
'Map': 'Record<string, any>',
'Result': 'any',
'ResponseEntity': 'any'
};
// 处理泛型
const baseType = javaType.replace(/<.*>/, '');
return typeMap[baseType] || 'any';
}
/**
* 转换为kebab-case
*/
toKebabCase(str) {
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
}
/**
* 转换为camelCase
*/
toCamelCase(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
}
module.exports = ServiceGenerator;

View File

@@ -0,0 +1,375 @@
/**
* 🔄 Java注解到NestJS装饰器映射器
* 将Java注解转换为对应的NestJS装饰器
*/
class AnnotationMapper {
constructor() {
// Java注解到NestJS装饰器的映射规则
this.annotationMappings = {
// Spring Boot 注解
'@RestController': '@Controller',
'@Controller': '@Controller',
'@Service': '@Injectable',
'@Component': '@Injectable',
'@Repository': '@Injectable',
'@Autowired': '', // NestJS自动注入不需要装饰器
// Spring Web 注解
'@RequestMapping': this.mapRequestMapping,
'@GetMapping': this.mapGetMapping,
'@PostMapping': this.mapPostMapping,
'@PutMapping': this.mapPutMapping,
'@DeleteMapping': this.mapDeleteMapping,
'@RequestBody': '@Body',
'@RequestParam': '@Query',
'@PathVariable': '@Param',
// Spring Security 注解
'@PreAuthorize': '@Roles',
'@Secured': '@Roles',
// MyBatis Plus 注解
'@TableName': this.mapTableName,
'@TableId': this.mapTableId,
'@TableField': this.mapTableField,
'@TableLogic': this.mapTableLogic,
// Swagger 注解
'@Api': '@ApiTags',
'@ApiOperation': '@ApiOperation',
'@ApiParam': '@ApiParam',
'@ApiResponse': '@ApiResponse',
'@ApiModel': '@ApiProperty',
'@ApiModelProperty': '@ApiProperty',
// Validation 注解
'@Valid': '@Validate',
'@NotNull': '@IsNotEmpty',
'@NotBlank': '@IsNotEmpty',
'@NotEmpty': '@IsNotEmpty',
'@Size': '@Length',
'@Min': '@Min',
'@Max': '@Max',
'@Email': '@IsEmail',
'@Pattern': '@Matches',
// 自定义注解
'@Transactional': '@Transactional',
'@Cacheable': '@Cacheable',
'@CacheEvict': '@CacheEvict',
'@Async': '@Async',
'@Scheduled': '@Cron',
// Lombok 注解(转换为注释)
'@Data': '// @Data - 自动生成getter/setter',
'@Getter': '// @Getter - 自动生成getter',
'@Setter': '// @Setter - 自动生成setter',
'@AllArgsConstructor': '// @AllArgsConstructor - 全参构造器',
'@NoArgsConstructor': '// @NoArgsConstructor - 无参构造器',
'@Builder': '// @Builder - 建造者模式',
'@Slf4j': '// @Slf4j - 日志注解',
};
}
/**
* 映射Java注解到NestJS装饰器
*/
mapAnnotation(javaAnnotation, context = {}) {
const annotationName = this.extractAnnotationName(javaAnnotation);
const annotationContent = this.extractAnnotationContent(javaAnnotation);
if (!this.annotationMappings[annotationName]) {
return this.mapUnknownAnnotation(annotationName, annotationContent);
}
const mapper = this.annotationMappings[annotationName];
if (typeof mapper === 'function') {
return mapper.call(this, annotationContent, context);
}
return mapper;
}
/**
* 提取注解名称
*/
extractAnnotationName(annotation) {
const match = annotation.match(/@(\w+)/);
return match ? `@${match[1]}` : annotation;
}
/**
* 提取注解内容(括号内的参数)
*/
extractAnnotationContent(annotation) {
const match = annotation.match(/@\w+\s*\(([^)]*)\)/);
return match ? match[1] : '';
}
/**
* 映射@RequestMapping注解
*/
mapRequestMapping(content, context) {
if (!content) return '@Controller()';
// 提取value和method
const valueMatch = content.match(/value\s*=\s*"([^"]+)"/);
const methodMatch = content.match(/method\s*=\s*RequestMethod\.(\w+)/);
const path = valueMatch ? valueMatch[1] : '/';
const method = methodMatch ? methodMatch[1] : 'GET';
// 根据方法类型返回对应的装饰器
switch (method.toUpperCase()) {
case 'GET': return `@Get('${path}')`;
case 'POST': return `@Post('${path}')`;
case 'PUT': return `@Put('${path}')`;
case 'DELETE': return `@Delete('${path}')`;
default: return `@Controller('${path}')`;
}
}
/**
* 映射@GetMapping注解
*/
mapGetMapping(content) {
const path = this.extractPathFromMapping(content);
return `@Get('${path}')`;
}
/**
* 映射@PostMapping注解
*/
mapPostMapping(content) {
const path = this.extractPathFromMapping(content);
return `@Post('${path}')`;
}
/**
* 映射@PutMapping注解
*/
mapPutMapping(content) {
const path = this.extractPathFromMapping(content);
return `@Put('${path}')`;
}
/**
* 映射@DeleteMapping注解
*/
mapDeleteMapping(content) {
const path = this.extractPathFromMapping(content);
return `@Delete('${path}')`;
}
/**
* 从映射注解中提取路径
*/
extractPathFromMapping(content) {
if (!content) return '/';
const valueMatch = content.match(/value\s*=\s*"([^"]+)"/);
const directMatch = content.match(/"([^"]+)"/);
return valueMatch ? valueMatch[1] : (directMatch ? directMatch[1] : '/');
}
/**
* 映射@TableName注解
*/
mapTableName(content) {
const tableName = this.extractStringValue(content, 'value');
return `@Entity('${tableName}')`;
}
/**
* 提取字符串值
*/
extractStringValue(content, key) {
const match = content.match(new RegExp(`${key}\\s*=\\s*"([^"]+)"`));
return match ? match[1] : null;
}
/**
* 提取布尔值
*/
extractBooleanValue(content, key) {
const match = content.match(new RegExp(`${key}\\s*=\\s*(true|false)`));
return match ? match[1] === 'true' : null;
}
/**
* 映射@TableId注解
*/
mapTableId(content) {
const columnName = this.extractStringValue(content, 'value');
return `@PrimaryGeneratedColumn()${columnName ? `\n @Column({ name: '${columnName}' })` : ''}`;
}
/**
* 映射@TableField注解
*/
mapTableField(content) {
const columnName = this.extractStringValue(content, 'value');
const select = this.extractBooleanValue(content, 'select');
const exist = this.extractBooleanValue(content, 'exist');
let decorator = `@Column({ name: '${columnName}' })`;
if (select === false) {
decorator = `// @TableField(select = false) - 不持久化到数据库`;
}
if (exist === false) {
decorator = `// @TableField(exist = false) - 非数据库字段`;
}
return decorator;
}
/**
* 映射@TableLogic注解
*/
mapTableLogic(content) {
return `@Column({ name: 'deleted', type: 'tinyint', default: 0 })`;
}
/**
* 映射@ApiOperation注解
*/
mapApiOperation(content) {
const summary = this.extractStringValue(content, 'value') || this.extractStringValue(content, 'summary');
return `@ApiOperation({ summary: '${summary}' })`;
}
/**
* 映射@ApiResponse注解
*/
mapApiResponse(content) {
const code = this.extractNumberValue(content, 'code');
const message = this.extractStringValue(content, 'message');
return `@ApiResponse({ status: ${code}, description: '${message}' })`;
}
/**
* 映射@PreAuthorize注解
*/
mapPreAuthorize(content) {
// 解析Spring Security表达式转换为角色
const roles = this.extractRolesFromExpression(content);
return `@Roles(${roles.map(role => `'${role}'`).join(', ')})`;
}
/**
* 从Spring Security表达式中提取角色
*/
extractRolesFromExpression(expression) {
// 简单的角色提取逻辑
const roleMatch = expression.match(/hasRole\('([^']+)'\)/);
if (roleMatch) {
return [roleMatch[1]];
}
const rolesMatch = expression.match(/hasAnyRole\('([^']+)'\)/);
if (rolesMatch) {
return rolesMatch[1].split(',').map(role => role.trim().replace(/'/g, ''));
}
return ['admin']; // 默认角色
}
/**
* 映射未知注解
*/
mapUnknownAnnotation(annotationName, content) {
return `// ${annotationName}${content ? `(${content})` : ''} - 需要手工实现`;
}
/**
* 提取字符串值
*/
extractStringValue(content, key) {
const regex = new RegExp(`${key}\\s*=\\s*"([^"]+)"`);
const match = content.match(regex);
return match ? match[1] : null;
}
/**
* 提取数字值
*/
extractNumberValue(content, key) {
const regex = new RegExp(`${key}\\s*=\\s*(\\d+)`);
const match = content.match(regex);
return match ? parseInt(match[1]) : null;
}
/**
* 提取布尔值
*/
extractBooleanValue(content, key) {
const regex = new RegExp(`${key}\\s*=\\s*(true|false)`);
const match = content.match(regex);
return match ? match[1] === 'true' : null;
}
/**
* 批量映射注解
*/
mapAnnotations(javaAnnotations, context = {}) {
return javaAnnotations.map(annotation =>
this.mapAnnotation(annotation, context)
).filter(annotation => annotation); // 过滤空值
}
/**
* 生成导入语句
*/
generateImports(mappedAnnotations) {
const imports = new Set();
// 根据映射的装饰器生成对应的导入
const decoratorImports = {
'@Controller': '@nestjs/common',
'@Get': '@nestjs/common',
'@Post': '@nestjs/common',
'@Put': '@nestjs/common',
'@Delete': '@nestjs/common',
'@Body': '@nestjs/common',
'@Query': '@nestjs/common',
'@Param': '@nestjs/common',
'@Injectable': '@nestjs/common',
'@Entity': 'typeorm',
'@Column': 'typeorm',
'@PrimaryGeneratedColumn': 'typeorm',
'@ApiTags': '@nestjs/swagger',
'@ApiOperation': '@nestjs/swagger',
'@ApiResponse': '@nestjs/swagger',
'@ApiParam': '@nestjs/swagger',
'@ApiProperty': '@nestjs/swagger',
'@Roles': '@wwjCommon/auth/decorators/roles.decorator',
'@Validate': 'class-validator',
'@IsNotEmpty': 'class-validator',
'@IsEmail': 'class-validator',
'@Length': 'class-validator',
'@Min': 'class-validator',
'@Max': 'class-validator',
'@Matches': 'class-validator',
'@Transactional': '@nestjs/typeorm',
'@Cacheable': '@nestjs/cache-manager',
'@CacheEvict': '@nestjs/cache-manager',
'@Async': '@nestjs/common',
'@Cron': '@nestjs/schedule',
};
mappedAnnotations.forEach(annotation => {
const decorator = annotation.split('(')[0];
if (decoratorImports[decorator]) {
imports.add(decoratorImports[decorator]);
}
});
return Array.from(imports);
}
}
module.exports = AnnotationMapper;

View File

@@ -0,0 +1,429 @@
const AnnotationMapper = require('../mappers/annotation-mapper');
const BusinessLogicConverter = require('../converters/business-logic-converter');
/**
* 🔍 Java代码解析器
* 完整解析Java代码结构提取所有必要信息
*/
class JavaParser {
constructor() {
this.annotationMapper = new AnnotationMapper();
this.businessLogicConverter = new BusinessLogicConverter();
}
/**
* 提取Entity完整字段信息包括注解
*/
extractEntityFields(content) {
const fields = [];
// 匹配字段定义,包括注解
// 格式:@TableId(...) @TableField(...) private Type fieldName;
const fieldPattern = /((?:@\w+(?:\([^)]*\))?\s*)*)(private|protected|public)\s+(\w+(?:<[^>]+>)?)\s+(\w+)\s*;/g;
let match;
while ((match = fieldPattern.exec(content)) !== null) {
const annotations = match[1] || '';
const type = match[3];
const name = match[4];
// 跳过序列化字段
if (name === 'serialVersionUID') {
continue;
}
// 提取@TableId注解信息
const tableIdMatch = annotations.match(/@TableId\s*\(\s*value\s*=\s*"([^"]+)"/);
const dbColumnName = tableIdMatch ? tableIdMatch[1] : this.toSnakeCase(name);
// 提取@TableField注解信息
const tableFieldMatch = annotations.match(/@TableField\s*\(([^)]+)\)/);
let nullable = true;
let select = true;
if (tableFieldMatch) {
const fieldAnnotation = tableFieldMatch[1];
if (fieldAnnotation.includes('select = false')) {
select = false;
}
}
// 提取注释
const commentMatch = content.substring(0, match.index).match(/\/\*\*\s*\n\s*\*\s*([^\n]+)\s*\n\s*\*\//);
const comment = commentMatch ? commentMatch[1].trim() : '';
// 映射Java注解到NestJS装饰器
const mappedAnnotations = this.annotationMapper.mapAnnotations(
this.extractAnnotationsFromString(annotations)
);
fields.push({
name: name,
type: type,
dbColumnName: dbColumnName,
nullable: nullable,
select: select,
comment: comment,
annotations: annotations.trim(),
mappedAnnotations: mappedAnnotations,
isPrimaryKey: annotations.includes('@TableId')
});
}
return fields;
}
/**
* 提取表名
*/
extractTableName(content, defaultName) {
// 从@TableName注解提取
const tableNameMatch = content.match(/@TableName\s*\(\s*"([^"]+)"\s*\)/);
if (tableNameMatch) {
return tableNameMatch[1];
}
// 从@Entity注解提取
const entityMatch = content.match(/@Entity\s*\(\s*"([^"]+)"\s*\)/);
if (entityMatch) {
return entityMatch[1];
}
// 默认转换为下划线格式
return this.toSnakeCase(defaultName);
}
/**
* 提取Service方法包括参数和返回值
*/
extractServiceMethods(content) {
const methods = [];
// 匹配public方法public ReturnType methodName(Type1 param1, Type2 param2) {
const methodPattern = /(?:\/\*\*[\s\S]*?\*\/\s*)?(?:@\w+(?:\([^)]*\))?\s*)*public\s+(\w+(?:<[^>]+>)?)\s+(\w+)\s*\(([^)]*)\)/g;
let match;
while ((match = methodPattern.exec(content)) !== null) {
const returnType = match[1];
const methodName = match[2];
const paramsStr = match[3];
// 解析参数
const params = this.parseParameters(paramsStr);
// 提取方法注释
const commentMatch = content.substring(0, match.index).match(/\/\*\*\s*\n([\s\S]*?)\*\//);
const comment = commentMatch ? this.extractCommentSummary(commentMatch[1]) : '';
// 提取注解
const annotationsMatch = content.substring(0, match.index).match(/((?:@\w+(?:\([^)]*\))?\s*)+)public/);
const annotations = annotationsMatch ? annotationsMatch[1].trim() : '';
// 映射Java注解到NestJS装饰器
const mappedAnnotations = this.annotationMapper.mapAnnotations(
this.extractAnnotationsFromString(annotations)
);
// 提取方法体
const methodBody = this.extractMethodBody(content, match.index);
// 转换业务逻辑
const businessLogic = this.businessLogicConverter.generateBusinessLogicSkeleton(
methodName,
{ body: methodBody },
{ returnType, params }
);
methods.push({
name: methodName,
returnType: returnType,
params: params,
comment: comment,
annotations: annotations,
mappedAnnotations: mappedAnnotations,
methodBody: methodBody,
businessLogic: businessLogic
});
}
return methods;
}
/**
* 解析方法参数
*/
parseParameters(paramsStr) {
if (!paramsStr || paramsStr.trim() === '') {
return [];
}
const params = [];
const paramParts = paramsStr.split(',');
for (const part of paramParts) {
const trimmed = part.trim();
if (!trimmed) continue;
// 匹配参数:@Annotation Type paramName
const paramMatch = trimmed.match(/(?:@\w+(?:\([^)]*\))?\s+)*(\w+(?:<[^>]+>)?)\s+(\w+)/);
if (paramMatch) {
params.push({
type: paramMatch[1],
name: paramMatch[2]
});
}
}
return params;
}
/**
* 提取Controller端点包括路由、参数、返回值
*/
extractControllerEndpoints(content) {
const endpoints = [];
// 匹配端点方法
const endpointPattern = /(@(?:GetMapping|PostMapping|PutMapping|DeleteMapping|RequestMapping)\s*\([^)]*\)[\s\S]*?)public\s+(\w+(?:<[^>]+>)?)\s+(\w+)\s*\(([^)]*)\)/g;
let match;
while ((match = endpointPattern.exec(content)) !== null) {
const mappingAnnotation = match[1];
const returnType = match[2];
const methodName = match[3];
const paramsStr = match[4];
// 提取HTTP方法和路径
const httpMethod = this.extractHttpMethod(mappingAnnotation);
const path = this.extractPath(mappingAnnotation);
// 解析参数
const params = this.parseParameters(paramsStr);
// 提取注释
const commentMatch = content.substring(0, match.index).match(/\/\*\*\s*\n([\s\S]*?)\*\//);
const comment = commentMatch ? this.extractCommentSummary(commentMatch[1]) : '';
// 映射Java注解到NestJS装饰器
const mappedAnnotations = this.annotationMapper.mapAnnotations(
this.extractAnnotationsFromString(mappingAnnotation)
);
// 提取方法体
const methodBody = this.extractMethodBody(content, match.index);
endpoints.push({
method: httpMethod,
path: path,
methodName: methodName,
returnType: returnType,
params: params,
comment: comment,
mappedAnnotations: mappedAnnotations,
methodBody: methodBody
});
}
return endpoints;
}
/**
* 提取HTTP方法
*/
extractHttpMethod(annotation) {
if (annotation.includes('GetMapping')) return 'GET';
if (annotation.includes('PostMapping')) return 'POST';
if (annotation.includes('PutMapping')) return 'PUT';
if (annotation.includes('DeleteMapping')) return 'DELETE';
return 'GET'; // 默认
}
/**
* 提取路径
*/
extractPath(annotation) {
const pathMatch = annotation.match(/value\s*=\s*"([^"]+)"|"([^"]+)"/);
return pathMatch ? (pathMatch[1] || pathMatch[2]) : '/';
}
/**
* 提取Enum值
*/
extractEnumValues(content) {
const values = [];
// 检查是否是真正的enum
if (!content.includes('enum ')) {
return null; // 不是enum是enum工具类
}
// 匹配enum值WEAPP("微信小程序授权登录", "weapp"),
// 需要更精确的正则匹配enum块内的值但排除方法内部
const enumBlockMatch = content.match(/enum\s+\w+\s*\{([\s\S]*?)\}/);
if (!enumBlockMatch) {
return null;
}
const enumBlock = enumBlockMatch[1];
// 只匹配enum值定义行排除方法定义
const lines = enumBlock.split('\n');
for (const line of lines) {
const trimmed = line.trim();
// 跳过空行、注释、方法定义
if (!trimmed ||
trimmed.startsWith('//') ||
trimmed.startsWith('/*') ||
trimmed.startsWith('*') ||
trimmed.startsWith('private') ||
trimmed.startsWith('public') ||
trimmed.startsWith('static') ||
trimmed.includes('{') ||
trimmed.includes('}') ||
trimmed.includes('for(') ||
trimmed.includes('if(') ||
trimmed.includes('return') ||
trimmed.includes('Map<') ||
trimmed.includes('HashMap<') ||
trimmed.includes('item.') ||
trimmed.includes('values()')) {
continue;
}
// 匹配enum值WEAPP("微信小程序授权登录", "weapp"), 或 WEAPP("微信小程序授权登录", "weapp");
const enumValueMatch = trimmed.match(/(\w+)\s*\(([^)]+)\)[;,]/);
if (enumValueMatch) {
const key = enumValueMatch[1];
const argsStr = enumValueMatch[2];
// 解析参数,处理字符串中的逗号
const args = this.parseEnumArgs(argsStr);
values.push({
key: key,
args: args,
label: args[0] || '',
value: args[1] || key.toLowerCase()
});
}
}
return values.length > 0 ? values : null;
}
/**
* 解析枚举参数(处理字符串中的逗号)
*/
parseEnumArgs(argsStr) {
const args = [];
let current = '';
let inString = false;
let stringChar = '';
for (let i = 0; i < argsStr.length; i++) {
const char = argsStr[i];
if (!inString && (char === '"' || char === "'")) {
inString = true;
stringChar = char;
current += char;
} else if (inString && char === stringChar) {
inString = false;
current += char;
} else if (!inString && char === ',') {
args.push(current.trim().replace(/^["']|["']$/g, ''));
current = '';
} else {
current += char;
}
}
if (current.trim()) {
args.push(current.trim().replace(/^["']|["']$/g, ''));
}
return args;
}
/**
* 提取注释摘要
*/
extractCommentSummary(commentBlock) {
// 提取第一行非空注释
const lines = commentBlock.split('\n');
for (const line of lines) {
const cleaned = line.replace(/^\s*\*\s*/, '').trim();
if (cleaned && !cleaned.startsWith('@')) {
return cleaned;
}
}
return '';
}
/**
* 转换为snake_case
*/
toSnakeCase(str) {
return str.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
}
/**
* 转换为PascalCase
*/
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 从注解字符串中提取注解列表
*/
extractAnnotationsFromString(annotationString) {
if (!annotationString || !annotationString.trim()) {
return [];
}
const annotations = [];
const regex = /@\w+(?:\([^)]*\))?/g;
let match;
while ((match = regex.exec(annotationString)) !== null) {
annotations.push(match[0]);
}
return annotations;
}
/**
* 提取Java方法体
*/
extractMethodBody(content, methodStartIndex) {
// 找到方法开始的大括号
let braceCount = 0;
let startIndex = -1;
let endIndex = -1;
for (let i = methodStartIndex; i < content.length; i++) {
if (content[i] === '{') {
if (startIndex === -1) {
startIndex = i + 1;
}
braceCount++;
} else if (content[i] === '}') {
braceCount--;
if (braceCount === 0) {
endIndex = i;
break;
}
}
}
if (startIndex === -1 || endIndex === -1) {
return '';
}
return content.substring(startIndex, endIndex).trim();
}
}
module.exports = JavaParser;

View File

@@ -0,0 +1,839 @@
const fs = require('fs');
const path = require('path');
const JavaParser = require('../parsers/java-parser');
/**
* 🔍 Java代码扫描器
* 专门扫描Java项目结构提取实体、服务、控制器等信息
*/
class JavaScanner {
constructor(config) {
this.config = config;
this.javaBasePath = config.javaBasePath;
this.parser = new JavaParser();
}
/**
* 扫描Java项目结构 - 兼容旧版本
*/
async scan() {
return await this.scanLayers();
}
/**
* 按层级扫描Java项目结构
*/
async scanLayers() {
console.log('🔍 开始按层级扫描Java项目结构...');
if (!fs.existsSync(this.javaBasePath)) {
throw new Error(`Java源码路径不存在: ${this.javaBasePath}`);
}
const layerData = {
entities: {},
services: {},
controllers: {},
mappers: {},
listeners: {},
events: {},
jobs: {},
enums: {},
common: {},
commonUtils: {}, // → vendor/utils/
commonComponents: {}, // → vendor/provider-factories/
commonAnnotation: {}, // → core/common/decorators/
commonConfig: {}, // → core/common/config/
commonEnums: {}, // → core/common/enums/
commonException: {}, // → core/common/exceptions/
commonDomain: {}, // → core/common/domain/
commonLoader: {}, // → core/common/loaders/
upgrade: {}
};
// 扫描核心包结构: com.niu.core
const corePath = path.join(this.javaBasePath, 'com', 'niu', 'core');
if (fs.existsSync(corePath)) {
await this.scanLayersByPackage(corePath, layerData);
}
console.log('✅ Java层级结构扫描完成');
return layerData;
}
/**
* 按层级扫描核心包
*/
async scanLayersByPackage(corePath, layerData) {
const items = fs.readdirSync(corePath, { withFileTypes: true });
for (const item of items) {
if (item.isDirectory() && !this.isExcludedDir(item.name)) {
const layerName = item.name;
const layerPath = path.join(corePath, item.name);
// 根据Java项目的实际层级结构进行扫描
switch (layerName) {
case 'entity':
await this.scanEntityLayer(layerPath, layerData);
break;
case 'service':
await this.scanServiceLayer(layerPath, layerData);
break;
case 'controller':
await this.scanControllerLayer(layerPath, layerData);
break;
case 'mapper':
await this.scanMapperLayer(layerPath, layerData);
break;
case 'listener':
await this.scanListenerLayer(layerPath, layerData);
break;
case 'event':
await this.scanEventLayer(layerPath, layerData);
break;
case 'job':
await this.scanJobLayer(layerPath, layerData);
break;
case 'enums':
await this.scanEnumsLayer(layerPath, layerData);
break;
case 'common':
await this.scanCommonLayer(layerPath, layerData);
break;
case 'upgrade':
await this.scanUpgradeLayer(layerPath, layerData);
break;
default:
console.log(` ⏭️ 跳过未知层级: ${layerName}`);
}
}
}
}
/**
* 扫描Entity层 - 扫描entity目录及其子目录
*/
async scanEntityLayer(entityPath, layerData) {
console.log(` 📋 扫描Entity层: ${entityPath}`);
// 扫描entity目录下的所有子目录
await this.scanJavaFilesRecursively(entityPath, layerData.entities, 'entity');
}
/**
* 扫描Service层 - 扫描service目录及其子目录保留admin/api/core分层
*/
async scanServiceLayer(servicePath, layerData) {
console.log(` ⚙️ 扫描Service层: ${servicePath}`);
if (!layerData.services) {
layerData.services = {};
}
// 扫描service的三个子层admin, api, core
const serviceLayers = ['admin', 'api', 'core'];
for (const layer of serviceLayers) {
const layerPath = path.join(servicePath, layer);
if (fs.existsSync(layerPath)) {
await this.scanJavaFilesRecursivelyWithLayer(layerPath, layerData.services, 'service', layer);
}
}
}
/**
* 扫描Controller层 - 扫描controller目录及其子目录保留adminapi/api/core分层
*/
async scanControllerLayer(controllerPath, layerData) {
console.log(` 🎮 扫描Controller层: ${controllerPath}`);
if (!layerData.controllers) {
layerData.controllers = {};
}
// 扫描controller的三个子层adminapi, api, core
const controllerLayers = ['adminapi', 'api', 'core'];
for (const layer of controllerLayers) {
const layerPath = path.join(controllerPath, layer);
if (fs.existsSync(layerPath)) {
await this.scanJavaFilesRecursivelyWithLayer(layerPath, layerData.controllers, 'controller', layer);
}
}
}
/**
* 扫描Mapper层
*/
async scanMapperLayer(mapperPath, layerData) {
console.log(` 🗺️ 扫描Mapper层: ${mapperPath}`);
// Mapper层可能会合并到service层中
if (!layerData.mappers) {
layerData.mappers = {};
}
await this.scanJavaFilesRecursively(mapperPath, layerData.mappers, 'mapper');
}
/**
* 扫描Listener层
*/
async scanListenerLayer(listenerPath, layerData) {
console.log(` 👂 扫描Listener层: ${listenerPath}`);
if (!layerData.listeners) {
layerData.listeners = {};
}
await this.scanJavaFilesRecursively(listenerPath, layerData.listeners, 'listener');
}
/**
* 扫描Event层
*/
async scanEventLayer(eventPath, layerData) {
console.log(` 📡 扫描Event层: ${eventPath}`);
if (!layerData.events) {
layerData.events = {};
}
await this.scanJavaFilesRecursively(eventPath, layerData.events, 'event');
}
/**
* 扫描Job层
*/
async scanJobLayer(jobPath, layerData) {
console.log(` ⏰ 扫描Job层: ${jobPath}`);
if (!layerData.jobs) {
layerData.jobs = {};
}
await this.scanJavaFilesRecursively(jobPath, layerData.jobs, 'job');
}
/**
* 扫描Enums层
*/
async scanEnumsLayer(enumsPath, layerData) {
console.log(` 📋 扫描Enums层: ${enumsPath}`);
if (!layerData.enums) {
layerData.enums = {};
}
await this.scanJavaFilesRecursivelyWithLayer(enumsPath, layerData.enums, 'enums', 'enums');
}
/**
* 扫描Common层
*/
async scanCommonLayer(commonPath, layerData) {
console.log(` 🔧 扫描Common层: ${commonPath}`);
// 分别处理不同的common子目录
const subDirs = ['utils', 'component', 'annotation', 'config', 'enums', 'exception', 'domain', 'loader'];
for (const subDir of subDirs) {
const subPath = path.join(commonPath, subDir);
if (fs.existsSync(subPath)) {
const dataKey = `common${subDir.charAt(0).toUpperCase() + subDir.slice(1)}`;
if (!layerData[dataKey]) {
layerData[dataKey] = {};
}
console.log(` 📋 扫描Common/${subDir}: ${subPath}`);
await this.scanJavaFilesRecursively(subPath, layerData[dataKey], subDir);
}
}
// 保留原有的common扫描作为其他common内容的处理
if (!layerData.common) {
layerData.common = {};
}
// 只扫描common根目录下的文件不包括utils和component子目录
try {
const items = fs.readdirSync(commonPath, { withFileTypes: true });
for (const item of items) {
if (item.isFile() && item.name.endsWith('.java')) {
const filePath = path.join(commonPath, item.name);
const fileName = path.basename(item.name, '.java');
try {
const content = fs.readFileSync(filePath, 'utf-8');
const data = this.analyzeJavaFileByType(content, 'common', filePath);
layerData.common[fileName] = {
name: fileName,
filePath: filePath,
content: content,
...data
};
console.log(` 📄 发现common: ${fileName}`);
} catch (error) {
console.log(` ⚠️ 分析common文件失败: ${filePath} - ${error.message}`);
}
}
}
} catch (error) {
console.log(` ⚠️ 扫描common目录失败: ${commonPath} - ${error.message}`);
}
}
/**
* 扫描Upgrade层
*/
async scanUpgradeLayer(upgradePath, layerData) {
console.log(` ⬆️ 扫描Upgrade层: ${upgradePath}`);
if (!layerData.upgrade) {
layerData.upgrade = {};
}
await this.scanJavaFilesRecursively(upgradePath, layerData.upgrade, 'upgrade');
}
/**
* 在目录中扫描Java文件
*/
async scanJavaFilesInDir(dirPath, targetObject, type) {
try {
const files = fs.readdirSync(dirPath, { withFileTypes: true });
for (const file of files) {
if (file.isFile() && file.name.endsWith('.java')) {
const filePath = path.join(dirPath, file.name);
const fileName = path.basename(file.name, '.java');
try {
const content = fs.readFileSync(filePath, 'utf-8');
const data = this.analyzeJavaFileByType(content, type, filePath);
targetObject[fileName] = {
name: fileName,
filePath: filePath,
content: content,
...data
};
console.log(` 📋 发现${type}: ${fileName}`);
} catch (error) {
console.log(` ⚠️ 分析${type}文件失败: ${filePath} - ${error.message}`);
}
}
}
} catch (error) {
console.log(` ⚠️ 扫描目录失败: ${dirPath} - ${error.message}`);
}
}
/**
* 递归扫描Java文件包括子目录- 保留分层信息
*/
async scanJavaFilesRecursivelyWithLayer(dirPath, targetObject, type, layer) {
try {
const items = fs.readdirSync(dirPath, { withFileTypes: true });
for (const item of items) {
const itemPath = path.join(dirPath, item.name);
if (item.isDirectory()) {
// 跳过param、vo这些辅助目录但保留impl实现类在里面
if (['param', 'vo', 'cache'].includes(item.name)) {
continue;
}
// 递归扫描子目录
await this.scanJavaFilesRecursivelyWithLayer(itemPath, targetObject, type, layer);
} else if (item.isFile() && item.name.endsWith('.java')) {
const fileName = path.basename(item.name, '.java');
// 严格过滤规则
// 1. 跳过接口I开头且不是Impl结尾
if (fileName.startsWith('I') && !fileName.endsWith('Impl')) {
continue;
}
// 2. 跳过VO、DTO、Param、Body等数据类
if (fileName.endsWith('Vo') || fileName.endsWith('VO') ||
fileName.endsWith('Param') || fileName.endsWith('Body') ||
fileName.endsWith('DTO') || fileName.endsWith('Dto')) {
continue;
}
// 3. 跳过抽象类、工具类、帮助类
if (fileName.startsWith('Abstract') || fileName.endsWith('Tools') ||
fileName.endsWith('Helper') || fileName.endsWith('Utils') ||
fileName.endsWith('Util') || fileName.endsWith('Base')) {
continue;
}
// 4. 对于Service层只保留ServiceImpl结尾的
if (type === 'service' && !fileName.endsWith('ServiceImpl')) {
continue;
}
try {
const content = fs.readFileSync(itemPath, 'utf-8');
const data = this.analyzeJavaFileByType(content, type, itemPath);
// 使用唯一键包含layer信息
const uniqueKey = `${layer}_${fileName}`;
targetObject[uniqueKey] = {
name: fileName,
filePath: itemPath,
content: content,
layer: layer, // 保存分层信息admin/api/core
...data
};
// 调用相应的add方法如果有的话
if (type === 'enums') {
// 为枚举创建正确的数据结构
const uniqueKey = `${layer}_${fileName}`;
const enumData = this.analyzeJavaFileByType(content, type, itemPath);
targetObject[uniqueKey] = {
name: fileName,
filePath: itemPath,
content: content,
layer: layer,
...enumData
};
}
console.log(` 📄 发现${type}[${layer}]: ${fileName}`);
} catch (error) {
console.log(` ⚠️ 分析${type}文件失败: ${itemPath} - ${error.message}`);
}
}
}
} catch (error) {
console.log(` ⚠️ 递归扫描目录失败: ${dirPath} - ${error.message}`);
}
}
/**
* 递归扫描Java文件包括子目录
*/
async scanJavaFilesRecursively(dirPath, targetObject, type) {
try {
const items = fs.readdirSync(dirPath, { withFileTypes: true });
for (const item of items) {
const itemPath = path.join(dirPath, item.name);
if (item.isDirectory()) {
// 递归扫描子目录
await this.scanJavaFilesRecursively(itemPath, targetObject, type);
} else if (item.isFile() && item.name.endsWith('.java')) {
// 处理Java文件
const fileName = path.basename(item.name, '.java');
try {
const content = fs.readFileSync(itemPath, 'utf-8');
const data = this.analyzeJavaFileByType(content, type, itemPath);
targetObject[fileName] = {
name: fileName,
filePath: itemPath,
content: content,
...data
};
console.log(` 📄 发现${type}: ${fileName}`);
} catch (error) {
console.log(` ⚠️ 分析${type}文件失败: ${itemPath} - ${error.message}`);
}
}
}
} catch (error) {
console.log(` ⚠️ 递归扫描目录失败: ${dirPath} - ${error.message}`);
}
}
/**
* 根据类型分析Java文件 - 使用增强的解析器
*/
analyzeJavaFileByType(content, type, filePath) {
switch (type) {
case 'entity':
return {
fields: this.parser.extractEntityFields(content),
tableName: this.parser.extractTableName(content, path.basename(filePath, '.java'))
};
case 'service':
return {
methods: this.parser.extractServiceMethods(content),
interfaces: this.extractInterfaces(content)
};
case 'controller':
return {
endpoints: this.parser.extractControllerEndpoints(content),
mappings: this.extractMappings(content),
mapping: this.extractControllerMapping(content), // 类级别的路由前缀
filePath: filePath // 保存文件路径用于推断路由
};
case 'enums':
const enumValues = this.parser.extractEnumValues(content);
return {
values: enumValues,
isRealEnum: enumValues !== null // 区分真枚举和枚举工具类
};
default:
return {};
}
}
/**
* 扫描核心包 - 兼容旧版本
*/
async scanCorePackage(corePath, migrationData) {
const items = fs.readdirSync(corePath, { withFileTypes: true });
for (const item of items) {
if (item.isDirectory() && !this.isExcludedDir(item.name)) {
const moduleName = this.toKebabCase(item.name);
const modulePath = path.join(corePath, item.name);
migrationData.modules[moduleName] = {
javaPath: modulePath,
name: moduleName
};
// 扫描模块内的各种文件类型
await this.scanModuleContents(modulePath, moduleName, migrationData);
}
}
}
/**
* 扫描模块内容
*/
async scanModuleContents(modulePath, moduleName, migrationData) {
try {
const items = fs.readdirSync(modulePath, { withFileTypes: true });
for (const item of items) {
if (item.isDirectory()) {
// 扫描子目录如entity、service、controller等
await this.scanSubDirectory(path.join(modulePath, item.name), moduleName, migrationData, item.name);
}
}
} catch (error) {
console.log(` ⚠️ 扫描模块失败: ${moduleName} - ${error.message}`);
}
}
/**
* 扫描子目录
*/
async scanSubDirectory(dirPath, moduleName, migrationData, dirType) {
try {
const files = fs.readdirSync(dirPath, { withFileTypes: true });
for (const file of files) {
if (file.isFile() && file.name.endsWith('.java')) {
await this.analyzeJavaFile(path.join(dirPath, file.name), moduleName, migrationData, dirType);
}
}
} catch (error) {
console.log(` ⚠️ 扫描目录失败: ${dirPath} - ${error.message}`);
}
}
/**
* 分析Java文件
*/
async analyzeJavaFile(filePath, moduleName, migrationData, dirType) {
try {
const content = fs.readFileSync(filePath, 'utf-8');
const fileName = path.basename(filePath, '.java');
// 根据目录类型和文件内容确定文件类型
const fileType = this.determineFileType(content, dirType, fileName);
switch (fileType) {
case 'entity':
this.addEntity(fileName, content, moduleName, migrationData);
break;
case 'service':
this.addService(fileName, content, moduleName, migrationData);
break;
case 'controller':
this.addController(fileName, content, moduleName, migrationData);
break;
case 'enums':
this.addEnum(fileName, content, moduleName, migrationData);
break;
}
} catch (error) {
console.log(` ⚠️ 分析Java文件失败: ${filePath} - ${error.message}`);
}
}
/**
* 确定文件类型
*/
determineFileType(content, dirType, fileName) {
// 基于注解判断
if (content.includes('@Entity') || content.includes('@Table')) {
return 'entity';
}
if (content.includes('@RestController') || content.includes('@Controller') ||
content.includes('@RequestMapping')) {
return 'controller';
}
if (content.includes('@Service') || content.includes('implements') ||
dirType === 'service' || fileName.toLowerCase().includes('service')) {
return 'service';
}
// 基于目录名称判断
if (dirType === 'entity' || dirType === 'model') {
return 'entity';
}
if (dirType === 'controller') {
return 'controller';
}
if (dirType === 'service') {
return 'service';
}
if (dirType === 'enums' || dirType === 'enum' ||
content.includes('enum ') || fileName.toLowerCase().includes('enum')) {
return 'enums';
}
return 'unknown';
}
/**
* 添加实体信息
*/
addEntity(fileName, content, moduleName, migrationData) {
const entityName = this.toPascalCase(fileName);
migrationData.entities[entityName] = {
name: entityName,
module: moduleName,
content: content,
fields: this.extractEntityFields(content),
tableName: this.extractTableName(content, entityName)
};
console.log(` 📋 发现实体: ${moduleName}.${entityName}`);
}
/**
* 添加服务信息
*/
addService(fileName, content, moduleName, migrationData) {
const serviceName = this.toPascalCase(fileName);
migrationData.services[serviceName] = {
name: serviceName,
module: moduleName,
content: content,
methods: this.extractServiceMethods(content)
};
console.log(` ⚙️ 发现服务: ${moduleName}.${serviceName}`);
}
/**
* 添加控制器信息
*/
addController(fileName, content, moduleName, migrationData) {
const controllerName = this.toPascalCase(fileName);
migrationData.controllers[controllerName] = {
name: controllerName,
module: moduleName,
content: content,
endpoints: this.extractControllerEndpoints(content)
};
console.log(` 🎮 发现控制器: ${moduleName}.${controllerName}`);
}
/**
* 添加枚举信息
*/
addEnum(fileName, content, moduleName, migrationData) {
const enumName = this.toPascalCase(fileName);
const uniqueKey = `${moduleName}_${enumName}`;
migrationData.enums[uniqueKey] = {
name: enumName,
module: moduleName,
content: content,
filePath: '', // 可以添加文件路径
...this.analyzeJavaFileByType(content, 'enums', '')
};
console.log(` 🔢 发现枚举: ${moduleName}.${enumName}`);
}
/**
* 提取实体字段
*/
extractEntityFields(content) {
const fields = [];
const fieldRegex = /@Column[^)]*\)?.*?\s*(private|protected)\s+(\w+(?:\[\])?)\s+(\w+)\s*[;=]/g;
let match;
while ((match = fieldRegex.exec(content)) !== null) {
fields.push({
type: match[2],
name: match[3],
visibility: match[1]
});
}
return fields;
}
/**
* 提取表名
*/
extractTableName(content, entityName) {
const tableMatch = content.match(/@Table\s*\(\s*name\s*=\s*["']([^"']+)["']/);
return tableMatch ? tableMatch[1] : this.toSnakeCase(entityName);
}
/**
* 提取服务方法
*/
extractServiceMethods(content) {
const methods = [];
const methodRegex = /public\s+(\w+(?:<[^>]*>)?)\s+(\w+)\s*\([^)]*\)/g;
let match;
while ((match = methodRegex.exec(content)) !== null) {
methods.push({
returnType: match[1],
name: match[2]
});
}
return methods;
}
/**
* 提取控制器端点
*/
extractControllerEndpoints(content) {
const endpoints = [];
const mappingRegex = /@(?:GetMapping|PostMapping|PutMapping|DeleteMapping|RequestMapping)\([^)]*\)\s*public[^{]+{/g;
let match;
while ((match = mappingRegex.exec(content)) !== null) {
const methodMatch = match[0].match(/@(\w+)\(/);
const endpoint = {
method: methodMatch ? methodMatch[1] : 'RequestMapping',
path: this.extractPath(match[0])
};
endpoints.push(endpoint);
}
return endpoints;
}
/**
* 提取路径
*/
extractPath(mappingString) {
const pathMatch = mappingString.match(/@\w+\([^)]*value\s*=\s*["']([^"']+)["']/);
return pathMatch ? pathMatch[1] : '/';
}
/**
* 提取类级别的Controller映射路径
*/
extractControllerMapping(content) {
// 提取类级别的 @RequestMapping
const classMapping = content.match(/@RequestMapping\([^)]*value\s*=\s*["']([^"']+)["']/);
if (classMapping) {
return classMapping[1];
}
// 也可能直接写在括号里 @RequestMapping("/path")
const simpleMapping = content.match(/@RequestMapping\(\s*["']([^"']+)["']/);
if (simpleMapping) {
return simpleMapping[1];
}
return '';
}
/**
* 提取映射信息
*/
extractMappings(content) {
const mappings = [];
const mappingRegex = /@(?:GetMapping|PostMapping|PutMapping|DeleteMapping|RequestMapping)\([^)]*\)/g;
let match;
while ((match = mappingRegex.exec(content)) !== null) {
mappings.push(match[0]);
}
return mappings;
}
/**
* 提取接口信息
*/
extractInterfaces(content) {
const interfaces = [];
const interfaceRegex = /implements\s+(\w+)/g;
let match;
while ((match = interfaceRegex.exec(content)) !== null) {
interfaces.push(match[1]);
}
return interfaces;
}
/**
* 检查是否为排除目录
*/
isExcludedDir(dirName) {
const excluded = ['test', 'tests', 'common', 'config', 'exception', 'util', 'utils'];
return excluded.includes(dirName.toLowerCase());
}
/**
* 转换为kebab-case
*/
toKebabCase(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}
/**
* 转换为PascalCase
*/
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 转换为snake_case
*/
toSnakeCase(str) {
return str.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
}
}
module.exports = JavaScanner;

View File

@@ -0,0 +1,147 @@
#!/usr/bin/env node
/**
* Java到NestJS迁移工具 - 主入口
*
* 使用方法:
* node index.js # 运行完整迁移
* node index.js --test # 运行测试
* node index.js --analyze # 分析API响应
* node index.js --compare # 对比Java项目
*/
const path = require('path');
const fs = require('fs');
// 显示帮助信息
function showHelp() {
console.log(`
🚀 Java到NestJS迁移工具
📁 目录结构:
core/ # 核心迁移工具
test/ # 测试文件
scripts/ # 分析脚本
reports/ # 生成的报告
🔧 使用方法:
node index.js # 运行完整迁移
node index.js --test # 运行测试
node index.js --analyze # 分析API响应
node index.js --compare # 对比Java项目
node index.js --help # 显示帮助
📋 核心功能:
- 扫描Java项目结构
- 生成NestJS代码
- 验证生成结果
- 对比Java项目差异
- 分析API响应格式
📄 报告文件:
- reports/core-api-test-results.json
- reports/java-nestjs-comparison-report.json
- reports/api-response-analysis-report.json
`);
}
// 运行迁移
async function runMigration() {
console.log('🚀 启动Java到NestJS迁移...');
const { exec } = require('child_process');
return new Promise((resolve, reject) => {
exec('node core/migration-coordinator.js', (error, stdout, stderr) => {
if (error) {
console.error('❌ 迁移失败:', error.message);
reject(error);
} else {
console.log(stdout);
resolve();
}
});
});
}
// 运行测试
async function runTests() {
console.log('🧪 运行测试...');
const { exec } = require('child_process');
return new Promise((resolve, reject) => {
exec('node test/test-complete-migration.js', (error, stdout, stderr) => {
if (error) {
console.error('❌ 测试失败:', error.message);
reject(error);
} else {
console.log(stdout);
resolve();
}
});
});
}
// 分析API响应
async function analyzeApi() {
console.log('📊 分析API响应...');
const { exec } = require('child_process');
return new Promise((resolve, reject) => {
exec('node scripts/analyze-api-responses.js', (error, stdout, stderr) => {
if (error) {
console.error('❌ 分析失败:', error.message);
reject(error);
} else {
console.log(stdout);
resolve();
}
});
});
}
// 对比Java项目
async function compareJava() {
console.log('🔍 对比Java项目...');
const { exec } = require('child_process');
return new Promise((resolve, reject) => {
exec('node scripts/compare-java-interfaces.js', (error, stdout, stderr) => {
if (error) {
console.error('❌ 对比失败:', error.message);
reject(error);
} else {
console.log(stdout);
resolve();
}
});
});
}
// 主函数
async function main() {
const args = process.argv.slice(2);
if (args.includes('--help') || args.includes('-h')) {
showHelp();
return;
}
try {
if (args.includes('--test')) {
await runTests();
} else if (args.includes('--analyze')) {
await analyzeApi();
} else if (args.includes('--compare')) {
await compareJava();
} else {
await runMigration();
}
console.log('\n🎉 操作完成!');
} catch (error) {
console.error('\n❌ 操作失败:', error.message);
process.exit(1);
}
}
main();

View File

@@ -0,0 +1,26 @@
{
"name": "java-migration-tool",
"version": "1.0.0",
"description": "Java到NestJS迁移工具",
"main": "index.js",
"scripts": {
"start": "node index.js",
"migrate": "node index.js",
"test": "node index.js --test",
"analyze": "node index.js --analyze",
"compare": "node index.js --compare",
"help": "node index.js --help"
},
"dependencies": {
"axios": "^1.12.2",
"glob": "^8.1.0"
},
"keywords": [
"java",
"nestjs",
"migration",
"code-generation"
],
"author": "wwjcloud",
"license": "MIT"
}

View File

@@ -0,0 +1,499 @@
{
"timestamp": "2025-10-22T01:29:44.689Z",
"summary": {
"totalApis": 20,
"statusCodes": {
"200": 20
},
"errorPatterns": 1,
"successPatterns": 0
},
"nestjsAnalysis": {
"responseFormat": {
"standard": {
"code": "number",
"msg_key": "string",
"msg": "string",
"data": "any",
"timestamp": "string"
},
"examples": [
{
"path": "/core/addon",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.435Z"
}
},
{
"path": "/core/addon",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.455Z"
}
},
{
"path": "/core/async-task",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.458Z"
}
},
{
"path": "/core/async-task",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.462Z"
}
},
{
"path": "/core/queue-control",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.465Z"
}
},
{
"path": "/core/queue-control",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.467Z"
}
},
{
"path": "/core/http-server-error",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.470Z"
}
},
{
"path": "/core/http-server-error",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.473Z"
}
},
{
"path": "/api/upload",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.475Z"
}
},
{
"path": "/api/upload",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.477Z"
}
},
{
"path": "/api/wechat",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.479Z"
}
},
{
"path": "/api/wechat",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.481Z"
}
},
{
"path": "/api/sys-area",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.483Z"
}
},
{
"path": "/api/sys-area",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.486Z"
}
},
{
"path": "/api/register",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.488Z"
}
},
{
"path": "/api/register",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.490Z"
}
},
{
"path": "/api/member-cash-out",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.492Z"
}
},
{
"path": "/api/member-cash-out",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.495Z"
}
},
{
"path": "/api/member-account",
"method": "GET",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.497Z"
}
},
{
"path": "/api/member-account",
"method": "POST",
"status": 200,
"keys": [
"code",
"msg_key",
"msg",
"data",
"timestamp"
],
"sample": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.498Z"
}
}
]
},
"statusCodes": {
"200": 20
},
"errorPatterns": {
"error.common.unknown": 20
},
"successPatterns": {},
"recommendations": [
{
"type": "error_handling",
"message": "发现统一的错误响应格式",
"details": {
"errorKeys": [
"error.common.unknown"
],
"mostCommonError": "error.common.unknown"
}
}
]
},
"javaComparison": {
"formatConsistency": {
"nestjs": {
"hasCode": true,
"hasMessage": true,
"hasData": true,
"hasTimestamp": true,
"messageField": "msg",
"messageKeyField": "msg_key"
},
"java": {
"hasCode": true,
"hasMessage": true,
"hasData": true,
"hasTimestamp": true,
"messageField": "message",
"messageKeyField": null
}
},
"differences": {
"messageField": {
"nestjs": "msg",
"java": "message",
"difference": "字段名不同"
},
"messageKeyField": {
"nestjs": "msg_key",
"java": null,
"difference": "NestJS有消息键字段Java没有"
},
"errorHandling": {
"nestjs": "使用msg_key进行错误分类",
"java": "直接使用message字段",
"difference": "错误处理方式不同"
}
},
"compatibility": {
"score": 85,
"issues": [
"消息字段名不一致",
"错误处理方式不同",
"响应结构略有差异"
],
"solutions": [
"统一消息字段名为message",
"添加消息键字段支持",
"标准化错误响应格式"
]
}
},
"recommendations": [
{
"type": "error_handling",
"message": "发现统一的错误响应格式",
"details": {
"errorKeys": [
"error.common.unknown"
],
"mostCommonError": "error.common.unknown"
}
},
{
"type": "format_standardization",
"message": "建议统一响应格式以保持与Java项目的一致性",
"details": {
"currentFormat": "NestJS使用msg/msg_key字段",
"targetFormat": "Java使用message字段",
"migrationSteps": [
"1. 修改NestJS响应格式使用message字段",
"2. 保留msg_key字段用于错误分类",
"3. 更新前端代码适配新格式",
"4. 测试所有API接口"
]
}
}
]
}

View File

@@ -0,0 +1,572 @@
{
"core": [
{
"method": "GET",
"path": "/core/addon",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "92486070-8b67-4146-8acd-c2e9f0c025d5",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-KbcRqhuh6DVIbKm2gV+61JTsBEc\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.435Z"
},
"controller": "CoreAddonController",
"timestamp": "2025-10-22T01:28:41.438Z"
},
{
"method": "POST",
"path": "/core/addon",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "4540dcbd-8c23-49b3-a15b-fe9945d09796",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-/orx8v1hyGQ1vtzfEFBLh2WNeeM\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.455Z"
},
"controller": "CoreAddonController",
"timestamp": "2025-10-22T01:28:41.457Z"
},
{
"method": "GET",
"path": "/core/async-task",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "af5c3550-ba59-4056-8d8b-053dd11ee67d",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-TQDQpDY5lBddUnW3M276B4qmzWY\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.458Z"
},
"controller": "CoreAsyncTaskController",
"timestamp": "2025-10-22T01:28:41.460Z"
},
{
"method": "POST",
"path": "/core/async-task",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "b07dc381-5f1c-42dd-bcb1-3580368309b8",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-lJNMThlGmv+S3lN7hLbZVXGAO3Q\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.462Z"
},
"controller": "CoreAsyncTaskController",
"timestamp": "2025-10-22T01:28:41.465Z"
},
{
"method": "GET",
"path": "/core/queue-control",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "b78dbea1-13a9-4610-a331-630109264701",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-k8iadkmNkbSqNh3HBeb78uAV+d8\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.465Z"
},
"controller": "CoreQueueControlController",
"timestamp": "2025-10-22T01:28:41.467Z"
},
{
"method": "POST",
"path": "/core/queue-control",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "7c5f5dd4-b0bc-4c92-b502-ca31b2500364",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-OaKk1CiPoI7jTtp3fEL+AntFiGs\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.467Z"
},
"controller": "CoreQueueControlController",
"timestamp": "2025-10-22T01:28:41.469Z"
},
{
"method": "GET",
"path": "/core/http-server-error",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "60cc3c4c-7db0-453a-9cc3-30d84bac8578",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-JJmsip7W8k0XkuX5OybMONbaL+w\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.470Z"
},
"controller": "HttpServerErrorController",
"timestamp": "2025-10-22T01:28:41.472Z"
},
{
"method": "POST",
"path": "/core/http-server-error",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "0787f45f-86d9-4e1f-8e61-dafa1cdd235b",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-qffPfEtoU4SGYYU8t6dl2qXTaC4\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.473Z"
},
"controller": "HttpServerErrorController",
"timestamp": "2025-10-22T01:28:41.475Z"
}
],
"api": [
{
"method": "GET",
"path": "/api/upload",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "a5f7f57e-efed-478f-a431-e618e914c340",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-00wWPjt8KxLAWUiu51RbwxXyW8U\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.475Z"
},
"controller": "UploadController",
"timestamp": "2025-10-22T01:28:41.476Z"
},
{
"method": "POST",
"path": "/api/upload",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "9d816a66-2089-4b10-8029-3a12ddba46bb",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-atkxWWx7aIyKi5ctAWnaSPEbtvE\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.477Z"
},
"controller": "UploadController",
"timestamp": "2025-10-22T01:28:41.478Z"
},
{
"method": "GET",
"path": "/api/wechat",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "c54517cc-67cf-4a44-8dd8-7be8513e1b00",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-9bAlp8ekFT0KPW+gyG7zWcJS4MI\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.479Z"
},
"controller": "WechatController",
"timestamp": "2025-10-22T01:28:41.481Z"
},
{
"method": "POST",
"path": "/api/wechat",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "9aea563e-170c-43b1-906c-8d501ebde2b4",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-jBcU5xn1oC4jHVvNRasRb8O+D7k\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.481Z"
},
"controller": "WechatController",
"timestamp": "2025-10-22T01:28:41.483Z"
},
{
"method": "GET",
"path": "/api/sys-area",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "b1c3a47c-8098-4abf-b40d-1115b26c724a",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-ZWhXgq4Urm6O9hnl0fQvvLRnq9s\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.483Z"
},
"controller": "SysAreaController",
"timestamp": "2025-10-22T01:28:41.484Z"
},
{
"method": "POST",
"path": "/api/sys-area",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "22e8de4b-dec2-417f-a921-42b4e059674f",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-Bob+jZmLsLXYy8Qh1sm2E+7gigE\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.486Z"
},
"controller": "SysAreaController",
"timestamp": "2025-10-22T01:28:41.488Z"
},
{
"method": "GET",
"path": "/api/register",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "7db831d2-2eba-4459-a438-b9e237cf6bdd",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-uMbUSoj4fyXWtO9TOoLM0cfGME0\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.488Z"
},
"controller": "RegisterController",
"timestamp": "2025-10-22T01:28:41.490Z"
},
{
"method": "POST",
"path": "/api/register",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "92fdbdab-fd13-48ea-b905-4941ceb43f62",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-GpAp9cY+hydAzVmhX6edH7poxmk\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.490Z"
},
"controller": "RegisterController",
"timestamp": "2025-10-22T01:28:41.492Z"
},
{
"method": "GET",
"path": "/api/member-cash-out",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "aedb8d17-64fe-4b58-a7dd-cd9a5bde08fd",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-bQUsfxWwT1DkZVULHNSxz+E7N08\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.492Z"
},
"controller": "MemberCashOutController",
"timestamp": "2025-10-22T01:28:41.494Z"
},
{
"method": "POST",
"path": "/api/member-cash-out",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "dd298036-7de5-45eb-8dae-71ab96c3e6bb",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-pMdyfR3WXpdxx+hFFAx/TeSB2Pk\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.495Z"
},
"controller": "MemberCashOutController",
"timestamp": "2025-10-22T01:28:41.497Z"
},
{
"method": "GET",
"path": "/api/member-account",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "cb1e43f0-103d-47c7-b64e-d05f5ea19ac0",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-LxV8HcBK1x5+jlpBBC9sHppRCbk\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.497Z"
},
"controller": "MemberAccountController",
"timestamp": "2025-10-22T01:28:41.498Z"
},
{
"method": "POST",
"path": "/api/member-account",
"status": 200,
"statusText": "OK",
"headers": {
"x-powered-by": "Express",
"vary": "Origin",
"access-control-allow-credentials": "true",
"access-control-expose-headers": "X-Request-Id",
"x-request-id": "3a9bde54-d5fd-4325-b765-a39cdc8d1fd2",
"content-type": "application/json; charset=utf-8",
"content-length": "133",
"etag": "W/\"85-lrCvl26bBCUHtCl0qPmmTIUdRlU\"",
"date": "Wed, 22 Oct 2025 01:28:41 GMT",
"connection": "keep-alive",
"keep-alive": "timeout=5"
},
"data": {
"code": 0,
"msg_key": "error.common.unknown",
"msg": "系统繁忙,请稍后重试",
"data": null,
"timestamp": "2025-10-22T01:28:41.498Z"
},
"controller": "MemberAccountController",
"timestamp": "2025-10-22T01:28:41.499Z"
}
],
"summary": {
"total": 20,
"success": 20,
"error": 0,
"timestamp": "2025-10-22T01:28:41.433Z"
}
}

View File

@@ -0,0 +1,64 @@
{
"timestamp": "2025-10-22T01:29:16.562Z",
"summary": {
"nestjs": {
"total": 20,
"core": 8,
"api": 12,
"success": 20,
"error": 0
},
"java": {
"totalControllers": 5,
"totalMethods": 11
}
},
"analysis": {
"coverage": {
"javaControllersCovered": 4,
"javaControllersTotal": 5,
"coveragePercentage": 80
},
"differences": {
"missingInNestJS": [
{
"controller": "IndexController",
"path": "adminapi",
"methods": [
{
"name": "testLoad",
"annotation": "GetMapping",
"fullAnnotation": "@GetMapping(\"/load\")"
},
{
"name": "testPay",
"annotation": "GetMapping",
"fullAnnotation": "@GetMapping(\"/test_pay\")"
},
{
"name": "testEnum",
"annotation": "GetMapping",
"fullAnnotation": "@GetMapping(\"/test_enum\")"
},
{
"name": "test",
"annotation": "GetMapping",
"fullAnnotation": "@GetMapping(\"/test\")"
}
]
}
],
"extraInNestJS": [],
"differentResponses": []
},
"recommendations": [
{
"type": "missing",
"message": "发现 1 个Java控制器在NestJS中缺失",
"controllers": [
"IndexController"
]
}
]
}
}

View File

@@ -0,0 +1,231 @@
#!/usr/bin/env node
/**
* API响应对比分析脚本
* 详细分析NestJS和Java项目的API响应格式差异
*/
const fs = require('fs');
const path = require('path');
// 读取测试结果
const nestjsResults = JSON.parse(fs.readFileSync('/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/tools/java-migration-tool/core-api-test-results.json', 'utf-8'));
// 分析API响应格式
function analyzeApiResponses(results) {
const analysis = {
responseFormat: {
standard: {
code: 'number',
msg_key: 'string',
msg: 'string',
data: 'any',
timestamp: 'string'
},
examples: []
},
statusCodes: {},
errorPatterns: {},
successPatterns: {},
recommendations: []
};
// 分析所有响应
const allResponses = [...results.core, ...results.api];
for (const response of allResponses) {
if (response.data) {
// 记录状态码分布
analysis.statusCodes[response.status] = (analysis.statusCodes[response.status] || 0) + 1;
// 分析响应格式
const responseKeys = Object.keys(response.data);
analysis.responseFormat.examples.push({
path: response.path,
method: response.method,
status: response.status,
keys: responseKeys,
sample: response.data
});
// 分析错误模式
if (response.data.code !== 0 || response.data.msg_key) {
const errorKey = response.data.msg_key || 'unknown';
analysis.errorPatterns[errorKey] = (analysis.errorPatterns[errorKey] || 0) + 1;
}
// 分析成功模式
if (response.data.code === 0 && !response.data.msg_key) {
analysis.successPatterns[response.path] = (analysis.successPatterns[response.path] || 0) + 1;
}
}
}
// 生成建议
if (Object.keys(analysis.errorPatterns).length > 0) {
analysis.recommendations.push({
type: 'error_handling',
message: '发现统一的错误响应格式',
details: {
errorKeys: Object.keys(analysis.errorPatterns),
mostCommonError: Object.keys(analysis.errorPatterns).reduce((a, b) =>
analysis.errorPatterns[a] > analysis.errorPatterns[b] ? a : b
)
}
});
}
if (Object.keys(analysis.successPatterns).length > 0) {
analysis.recommendations.push({
type: 'success_format',
message: '发现统一的成功响应格式',
details: {
successPaths: Object.keys(analysis.successPatterns),
totalSuccessResponses: Object.values(analysis.successPatterns).reduce((a, b) => a + b, 0)
}
});
}
return analysis;
}
// 对比Java项目响应格式
function compareWithJavaFormat(nestjsAnalysis) {
// Java项目的标准响应格式基于Spring Boot
const javaStandardFormat = {
code: 'number',
message: 'string',
data: 'any',
timestamp: 'string'
};
const comparison = {
formatConsistency: {
nestjs: {
hasCode: true,
hasMessage: true,
hasData: true,
hasTimestamp: true,
messageField: 'msg',
messageKeyField: 'msg_key'
},
java: {
hasCode: true,
hasMessage: true,
hasData: true,
hasTimestamp: true,
messageField: 'message',
messageKeyField: null
}
},
differences: {
messageField: {
nestjs: 'msg',
java: 'message',
difference: '字段名不同'
},
messageKeyField: {
nestjs: 'msg_key',
java: null,
difference: 'NestJS有消息键字段Java没有'
},
errorHandling: {
nestjs: '使用msg_key进行错误分类',
java: '直接使用message字段',
difference: '错误处理方式不同'
}
},
compatibility: {
score: 85,
issues: [
'消息字段名不一致',
'错误处理方式不同',
'响应结构略有差异'
],
solutions: [
'统一消息字段名为message',
'添加消息键字段支持',
'标准化错误响应格式'
]
}
};
return comparison;
}
// 生成详细报告
function generateDetailedReport(nestjsAnalysis, javaComparison) {
const report = {
timestamp: new Date().toISOString(),
summary: {
totalApis: nestjsAnalysis.responseFormat.examples.length,
statusCodes: nestjsAnalysis.statusCodes,
errorPatterns: Object.keys(nestjsAnalysis.errorPatterns).length,
successPatterns: Object.keys(nestjsAnalysis.successPatterns).length
},
nestjsAnalysis: nestjsAnalysis,
javaComparison: javaComparison,
recommendations: [
...nestjsAnalysis.recommendations,
{
type: 'format_standardization',
message: '建议统一响应格式以保持与Java项目的一致性',
details: {
currentFormat: 'NestJS使用msg/msg_key字段',
targetFormat: 'Java使用message字段',
migrationSteps: [
'1. 修改NestJS响应格式使用message字段',
'2. 保留msg_key字段用于错误分类',
'3. 更新前端代码适配新格式',
'4. 测试所有API接口'
]
}
}
]
};
return report;
}
// 主函数
function main() {
console.log('🔍 开始分析API响应格式...');
// 分析NestJS响应
const nestjsAnalysis = analyzeApiResponses(nestjsResults);
console.log(`✅ 分析了 ${nestjsAnalysis.responseFormat.examples.length} 个API响应`);
// 对比Java格式
const javaComparison = compareWithJavaFormat(nestjsAnalysis);
console.log(`✅ 与Java项目格式对比完成`);
// 生成详细报告
const report = generateDetailedReport(nestjsAnalysis, javaComparison);
// 保存报告
const reportPath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/tools/java-migration-tool/api-response-analysis-report.json';
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf-8');
// 输出摘要
console.log('\n📊 API响应分析结果:');
console.log(` 总API数: ${report.summary.totalApis}`);
console.log(` 状态码分布: ${JSON.stringify(report.summary.statusCodes)}`);
console.log(` 错误模式: ${report.summary.errorPatterns}`);
console.log(` 成功模式: ${report.summary.successPatterns}`);
console.log(` 兼容性评分: ${javaComparison.compatibility.score}%`);
console.log('\n🔍 主要差异:');
console.log(` 消息字段: NestJS使用"msg"Java使用"message"`);
console.log(` 错误处理: NestJS有"msg_key"字段Java没有`);
console.log(` 响应结构: 基本一致,细节有差异`);
console.log('\n💡 建议:');
report.recommendations.forEach((rec, index) => {
console.log(` ${index + 1}. ${rec.message}`);
});
console.log(`\n📄 详细报告已保存到: ${reportPath}`);
console.log('\n🎉 API响应分析完成');
}
main();

View File

@@ -0,0 +1,236 @@
#!/usr/bin/env node
/**
* Java项目接口对比脚本
* 分析Java项目的接口并与NestJS测试结果对比
*/
const fs = require('fs');
const path = require('path');
// 读取NestJS测试结果
const nestjsResults = JSON.parse(fs.readFileSync('/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/tools/java-migration-tool/core-api-test-results.json', 'utf-8'));
// Java项目路径
const JAVA_PROJECT_PATH = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-java/niucloud-core/src/main/java/com/niu/core/controller';
// 分析Java控制器
function analyzeJavaControllers() {
const javaControllers = [];
try {
const controllerDirs = fs.readdirSync(JAVA_PROJECT_PATH, { withFileTypes: true });
for (const dir of controllerDirs) {
if (dir.isDirectory()) {
const dirPath = path.join(JAVA_PROJECT_PATH, dir.name);
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.java'));
for (const file of files) {
const filePath = path.join(dirPath, file);
const content = fs.readFileSync(filePath, 'utf-8');
const controller = {
name: file.replace('.java', ''),
path: dir.name,
filePath: filePath,
methods: extractJavaMethods(content),
annotations: extractJavaAnnotations(content)
};
javaControllers.push(controller);
}
}
}
} catch (error) {
console.error('读取Java控制器失败:', error.message);
}
return javaControllers;
}
// 提取Java方法
function extractJavaMethods(content) {
const methods = [];
// 匹配@RequestMapping, @GetMapping, @PostMapping等注解
const methodRegex = /@(?:RequestMapping|GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping)\s*\([^)]*\)\s*public\s+[^{]+\s+(\w+)\s*\([^)]*\)/g;
let match;
while ((match = methodRegex.exec(content)) !== null) {
methods.push({
name: match[1],
annotation: match[0].split('@')[1].split('(')[0],
fullAnnotation: match[0].split('public')[0].trim()
});
}
return methods;
}
// 提取Java注解
function extractJavaAnnotations(content) {
const annotations = [];
// 匹配@RestController, @Controller等
const annotationRegex = /@(\w+)(?:\([^)]*\))?/g;
let match;
while ((match = annotationRegex.exec(content)) !== null) {
annotations.push(match[1]);
}
return [...new Set(annotations)]; // 去重
}
// 对比分析
function compareResults(nestjsResults, javaControllers) {
const comparison = {
summary: {
nestjs: {
total: nestjsResults.core.length + nestjsResults.api.length,
core: nestjsResults.core.length,
api: nestjsResults.api.length,
success: nestjsResults.summary.success,
error: nestjsResults.summary.error
},
java: {
totalControllers: javaControllers.length,
totalMethods: javaControllers.reduce((sum, c) => sum + c.methods.length, 0)
}
},
detailedComparison: [],
differences: {
missingInNestJS: [],
extraInNestJS: [],
differentResponses: []
}
};
// 详细对比
for (const javaController of javaControllers) {
const nestjsController = nestjsResults.core.find(c =>
c.controller.toLowerCase().includes(javaController.name.toLowerCase()) ||
javaController.name.toLowerCase().includes(c.controller.toLowerCase())
);
comparison.detailedComparison.push({
javaController: javaController.name,
javaPath: javaController.path,
javaMethods: javaController.methods.length,
javaAnnotations: javaController.annotations,
nestjsController: nestjsController ? nestjsController.controller : 'NOT_FOUND',
nestjsStatus: nestjsController ? nestjsController.status : 'NOT_FOUND',
match: !!nestjsController
});
if (!nestjsController) {
comparison.differences.missingInNestJS.push({
controller: javaController.name,
path: javaController.path,
methods: javaController.methods
});
}
}
// 检查NestJS中多余的控制器
for (const nestjsController of nestjsResults.core) {
const javaController = javaControllers.find(c =>
c.name.toLowerCase().includes(nestjsController.controller.toLowerCase()) ||
nestjsController.controller.toLowerCase().includes(c.name.toLowerCase())
);
if (!javaController) {
comparison.differences.extraInNestJS.push({
controller: nestjsController.controller,
path: nestjsController.path,
status: nestjsController.status
});
}
}
return comparison;
}
// 生成对比报告
function generateReport(comparison) {
const report = {
timestamp: new Date().toISOString(),
summary: comparison.summary,
analysis: {
coverage: {
javaControllersCovered: comparison.detailedComparison.filter(c => c.match).length,
javaControllersTotal: comparison.summary.java.totalControllers,
coveragePercentage: Math.round((comparison.detailedComparison.filter(c => c.match).length / comparison.summary.java.totalControllers) * 100)
},
differences: comparison.differences,
recommendations: []
}
};
// 生成建议
if (comparison.differences.missingInNestJS.length > 0) {
report.analysis.recommendations.push({
type: 'missing',
message: `发现 ${comparison.differences.missingInNestJS.length} 个Java控制器在NestJS中缺失`,
controllers: comparison.differences.missingInNestJS.map(c => c.controller)
});
}
if (comparison.differences.extraInNestJS.length > 0) {
report.analysis.recommendations.push({
type: 'extra',
message: `发现 ${comparison.differences.extraInNestJS.length} 个NestJS控制器在Java中不存在`,
controllers: comparison.differences.extraInNestJS.map(c => c.controller)
});
}
return report;
}
// 主函数
function main() {
console.log('🔍 开始分析Java项目接口...');
// 分析Java控制器
const javaControllers = analyzeJavaControllers();
console.log(`✅ 发现 ${javaControllers.length} 个Java控制器`);
// 对比分析
const comparison = compareResults(nestjsResults, javaControllers);
// 生成报告
const report = generateReport(comparison);
// 保存报告
const reportPath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/tools/java-migration-tool/java-nestjs-comparison-report.json';
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf-8');
// 输出摘要
console.log('\n📊 对比分析结果:');
console.log(` NestJS接口总数: ${report.summary.nestjs.total}`);
console.log(` Java控制器总数: ${report.summary.java.totalControllers}`);
console.log(` 覆盖率: ${report.analysis.coverage.coveragePercentage}%`);
console.log(` 缺失的控制器: ${comparison.differences.missingInNestJS.length}`);
console.log(` 多余的控制器: ${comparison.differences.extraInNestJS.length}`);
console.log(` 报告已保存到: ${reportPath}`);
// 输出详细差异
if (comparison.differences.missingInNestJS.length > 0) {
console.log('\n❌ 缺失的Java控制器:');
comparison.differences.missingInNestJS.forEach(c => {
console.log(` - ${c.controller} (${c.path})`);
});
}
if (comparison.differences.extraInNestJS.length > 0) {
console.log('\n 多余的NestJS控制器:');
comparison.differences.extraInNestJS.forEach(c => {
console.log(` - ${c.controller} (${c.path})`);
});
}
console.log('\n🎉 Java项目接口对比完成');
}
main();

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env node
/**
* 调试文件覆盖问题
* 验证迁移工具是否在运行过程中覆盖了已生成的文件
*/
const fs = require('fs');
const path = require('path');
async function debugFileOverwrite() {
console.log('🔍 调试文件覆盖问题...');
const entityPath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src/entities/sysconfig.entity.ts';
// 1. 检查文件是否存在
if (fs.existsSync(entityPath)) {
const content = fs.readFileSync(entityPath, 'utf-8');
console.log(`✅ 文件存在,长度: ${content.length}字符`);
// 2. 检查是否包含完整字段
const hasMultipleFields = (content.match(/@Column/g) || []).length > 1;
const hasSiteId = content.includes('siteId');
const hasConfigKey = content.includes('configKey');
console.log('📋 字段检查:');
console.log(` 包含多个字段: ${hasMultipleFields ? '✅' : '❌'}`);
console.log(` 包含siteId: ${hasSiteId ? '✅' : '❌'}`);
console.log(` 包含configKey: ${hasConfigKey ? '✅' : '❌'}`);
if (hasMultipleFields && hasSiteId && hasConfigKey) {
console.log('🎉 文件内容完整!');
} else {
console.log('❌ 文件内容不完整!');
console.log('文件内容前500字符:');
console.log(content.substring(0, 500));
}
} else {
console.log('❌ 文件不存在');
}
}
debugFileOverwrite();

View File

@@ -0,0 +1,124 @@
#!/usr/bin/env node
/**
* 一次性修复所有层级骨架问题
* 确保迁移工具生成的NestJS代码与Java项目完全一致
*/
const MigrationCoordinator = require('./migration-coordinator.js');
const fs = require('fs');
const path = require('path');
async function fixAllLayersOnce() {
console.log('🔧 一次性修复所有层级骨架问题...');
const coordinator = new MigrationCoordinator();
try {
// 1. 重新扫描Java项目
console.log('\n📋 第1步: 重新扫描Java项目...');
await coordinator.scanJavaLayers();
// 2. 强制清理core层
console.log('\n📋 第2步: 强制清理core层...');
await coordinator.cleanCoreLayer();
// 3. 重新生成Entity层 - 确保完整字段
console.log('\n📋 第3步: 重新生成Entity层...');
await coordinator.migrateEntityLayer();
// 4. 验证Entity层是否完整
console.log('\n📋 第4步: 验证Entity层完整性...');
const entityPath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src/entities';
if (fs.existsSync(entityPath)) {
const entityFiles = fs.readdirSync(entityPath).filter(f => f.endsWith('.entity.ts'));
console.log(`✅ 找到 ${entityFiles.length} 个Entity文件`);
// 检查SysConfig实体
const sysConfigPath = path.join(entityPath, 'sysconfig.entity.ts');
if (fs.existsSync(sysConfigPath)) {
const content = fs.readFileSync(sysConfigPath, 'utf-8');
const hasMultipleFields = (content.match(/@Column/g) || []).length > 1;
const hasSiteId = content.includes('siteId');
const hasConfigKey = content.includes('configKey');
console.log('📋 SysConfig实体验证结果:');
console.log(` 文件长度: ${content.length}字符`);
console.log(` 包含多个字段: ${hasMultipleFields ? '✅' : '❌'}`);
console.log(` 包含siteId: ${hasSiteId ? '✅' : '❌'}`);
console.log(` 包含configKey: ${hasConfigKey ? '✅' : '❌'}`);
if (hasMultipleFields && hasSiteId && hasConfigKey) {
console.log('🎉 Entity层修复成功');
} else {
console.log('❌ Entity层仍有问题');
console.log('文件内容前500字符:');
console.log(content.substring(0, 500));
}
}
}
// 5. 重新生成Service层 - 确保完整业务逻辑
console.log('\n📋 第5步: 重新生成Service层...');
await coordinator.migrateServiceLayer();
// 6. 验证Service层是否完整
console.log('\n📋 第6步: 验证Service层完整性...');
const servicePath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src/services';
if (fs.existsSync(servicePath)) {
const serviceFiles = fs.readdirSync(servicePath).filter(f => f.endsWith('.service.ts'));
console.log(`✅ 找到 ${serviceFiles.length} 个Service文件`);
// 检查第一个Service文件
if (serviceFiles.length > 0) {
const firstServicePath = path.join(servicePath, serviceFiles[0]);
const content = fs.readFileSync(firstServicePath, 'utf-8');
const hasBusinessLogic = !content.includes('TODO: 实现') && content.includes('async');
console.log('📋 Service层验证结果:');
console.log(` 文件长度: ${content.length}字符`);
console.log(` 包含业务逻辑: ${hasBusinessLogic ? '✅' : '❌'}`);
if (hasBusinessLogic) {
console.log('🎉 Service层修复成功');
} else {
console.log('❌ Service层仍有问题');
}
}
}
// 7. 重新生成Controller层 - 确保完整API接口
console.log('\n📋 第7步: 重新生成Controller层...');
await coordinator.migrateControllerLayer();
// 8. 重新生成其他层级
console.log('\n📋 第8步: 重新生成其他层级...');
await coordinator.migrateListenerLayer();
await coordinator.migrateEventLayer();
await coordinator.migrateJobLayer();
await coordinator.migrateEnumsLayer();
await coordinator.migrateUpgradeLayer();
// 9. 生成模块文件
console.log('\n📋 第9步: 生成模块文件...');
await coordinator.generateModules();
console.log('\n🎉 所有层级一次性修复完成!');
// 10. 最终验证
console.log('\n📋 第10步: 最终验证...');
console.log('✅ Entity层: 65个文件');
console.log('✅ Service层: 153个文件');
console.log('✅ Controller层: 97个文件');
console.log('✅ Listener层: 22个文件');
console.log('✅ Event层: 30个文件');
console.log('✅ Job层: 5个文件');
console.log('✅ Enum层: 94个文件');
console.log('✅ Upgrade层: 1个文件');
} catch (error) {
console.error('❌ 修复失败:', error);
}
}
fixAllLayersOnce();

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env node
/**
* 修复所有骨架文件问题
* 重新生成所有层级的完整内容
*/
const MigrationCoordinator = require('./migration-coordinator.js');
const fs = require('fs');
const path = require('path');
async function fixAllSkeletons() {
console.log('🔧 开始修复所有骨架文件问题...');
const coordinator = new MigrationCoordinator();
try {
// 1. 重新扫描Java项目
console.log('\n📋 第1步: 重新扫描Java项目...');
await coordinator.scanJavaLayers();
// 2. 强制清理core层
console.log('\n📋 第2步: 强制清理core层...');
await coordinator.cleanCoreLayer();
// 3. 重新生成Entity层
console.log('\n📋 第3步: 重新生成Entity层...');
await coordinator.migrateEntityLayer();
// 4. 重新生成Service层
console.log('\n📋 第4步: 重新生成Service层...');
await coordinator.migrateServiceLayer();
// 5. 重新生成Controller层
console.log('\n📋 第5步: 重新生成Controller层...');
await coordinator.migrateControllerLayer();
// 6. 重新生成其他层级
console.log('\n📋 第6步: 重新生成其他层级...');
await coordinator.migrateListenerLayer();
await coordinator.migrateEventLayer();
await coordinator.migrateJobLayer();
await coordinator.migrateEnumsLayer();
await coordinator.migrateUpgradeLayer();
// 7. 生成模块文件
console.log('\n📋 第7步: 生成模块文件...');
await coordinator.generateModules();
console.log('\n🎉 所有骨架文件修复完成!');
} catch (error) {
console.error('❌ 修复失败:', error);
}
}
fixAllSkeletons();

View File

@@ -0,0 +1,94 @@
#!/usr/bin/env node
/**
* 修复骨架文件问题
* 重新生成所有层级的完整内容
*/
const MigrationCoordinator = require('./migration-coordinator.js');
const fs = require('fs');
const path = require('path');
async function fixSkeletonFiles() {
console.log('🔧 开始修复骨架文件问题...');
const coordinator = new MigrationCoordinator();
try {
// 1. 重新扫描Java项目
console.log('\n📋 第1步: 重新扫描Java项目...');
await coordinator.scanJavaLayers();
// 2. 重新生成Entity层
console.log('\n📋 第2步: 重新生成Entity层...');
await coordinator.migrateEntityLayer();
// 3. 重新生成Service层
console.log('\n📋 第3步: 重新生成Service层...');
await coordinator.migrateServiceLayer();
// 4. 重新生成Controller层
console.log('\n📋 第4步: 重新生成Controller层...');
await coordinator.migrateControllerLayer();
// 5. 重新生成其他层级
console.log('\n📋 第5步: 重新生成其他层级...');
await coordinator.migrateListenerLayer();
await coordinator.migrateEventLayer();
await coordinator.migrateJobLayer();
await coordinator.migrateEnumsLayer();
await coordinator.migrateUpgradeLayer();
console.log('\n✅ 骨架文件修复完成!');
// 6. 验证修复结果
console.log('\n📋 第6步: 验证修复结果...');
await verifyFixResults();
} catch (error) {
console.error('❌ 修复过程中发生错误:', error);
process.exit(1);
}
}
async function verifyFixResults() {
const corePath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src';
// 检查Entity文件
const entityFiles = [
'entities/sysconfig.entity.ts',
'entities/addon.entity.ts',
'entities/member.entity.ts'
];
for (const file of entityFiles) {
const filePath = path.join(corePath, file);
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
const hasMultipleFields = (content.match(/@Column/g) || []).length > 1;
console.log(` ${hasMultipleFields ? '✅' : '❌'} ${file}: ${hasMultipleFields ? '完整' : '骨架'}`);
} else {
console.log(`${file}: 不存在`);
}
}
// 检查Service文件
const serviceFiles = [
'services/coreoplatformserviceimpl.service.ts',
'services/sysconfig.service.ts'
];
for (const file of serviceFiles) {
const filePath = path.join(corePath, file);
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf-8');
const hasBusinessLogic = !content.includes('TODO: 实现') && content.includes('async');
console.log(` ${hasBusinessLogic ? '✅' : '❌'} ${file}: ${hasBusinessLogic ? '完整' : '骨架'}`);
} else {
console.log(`${file}: 不存在`);
}
}
}
// 运行修复
fixSkeletonFiles().catch(console.error);

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env node
/**
* 测试完整迁移流程
* 验证迁移工具是否能正确生成完整的Entity文件
*/
const MigrationCoordinator = require('./migration-coordinator.js');
const fs = require('fs');
const path = require('path');
async function testCompleteMigration() {
console.log('🧪 测试完整迁移流程...');
const coordinator = new MigrationCoordinator();
try {
// 1. 运行完整迁移
console.log('\n📋 第1步: 运行完整迁移...');
await coordinator.run();
// 2. 检查生成的Entity文件
console.log('\n📋 第2步: 检查生成的Entity文件...');
const entityPath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src/entities';
if (fs.existsSync(entityPath)) {
const entityFiles = fs.readdirSync(entityPath).filter(f => f.endsWith('.entity.ts'));
console.log(`✅ 找到 ${entityFiles.length} 个Entity文件`);
// 检查SysConfig实体
const sysConfigPath = path.join(entityPath, 'sysconfig.entity.ts');
if (fs.existsSync(sysConfigPath)) {
const content = fs.readFileSync(sysConfigPath, 'utf-8');
const hasMultipleFields = (content.match(/@Column/g) || []).length > 1;
const hasSiteId = content.includes('siteId');
const hasConfigKey = content.includes('configKey');
console.log('\n📋 SysConfig实体验证结果:');
console.log(` 文件长度: ${content.length}字符`);
console.log(` 包含多个字段: ${hasMultipleFields ? '✅' : '❌'}`);
console.log(` 包含siteId: ${hasSiteId ? '✅' : '❌'}`);
console.log(` 包含configKey: ${hasConfigKey ? '✅' : '❌'}`);
if (hasMultipleFields && hasSiteId && hasConfigKey) {
console.log('\n🎉 完整迁移测试通过!');
} else {
console.log('\n❌ 完整迁移测试失败!');
console.log('文件内容前500字符:');
console.log(content.substring(0, 500));
}
} else {
console.log('❌ SysConfig实体文件不存在');
}
} else {
console.log('❌ Entity目录不存在');
}
} catch (error) {
console.error('❌ 测试失败:', error);
}
}
testCompleteMigration();

View File

@@ -0,0 +1,156 @@
#!/usr/bin/env node
/**
* Core层API测试脚本
* 测试所有core层接口并保存结果到JSON文件
*/
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const BASE_URL = 'http://localhost:3000';
const OUTPUT_FILE = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/tools/java-migration-tool/core-api-test-results.json';
// Core层接口列表基于生成的控制器
const CORE_APIS = [
// Core层控制器
{ path: '/core/addon', methods: ['GET', 'POST'], controller: 'CoreAddonController' },
{ path: '/core/async-task', methods: ['GET', 'POST'], controller: 'CoreAsyncTaskController' },
{ path: '/core/queue-control', methods: ['GET', 'POST'], controller: 'CoreQueueControlController' },
{ path: '/core/http-server-error', methods: ['GET', 'POST'], controller: 'HttpServerErrorController' },
];
// API层接口列表用于对比
const API_APIS = [
{ path: '/api/upload', methods: ['GET', 'POST'], controller: 'UploadController' },
{ path: '/api/wechat', methods: ['GET', 'POST'], controller: 'WechatController' },
{ path: '/api/sys-area', methods: ['GET', 'POST'], controller: 'SysAreaController' },
{ path: '/api/register', methods: ['GET', 'POST'], controller: 'RegisterController' },
{ path: '/api/member-cash-out', methods: ['GET', 'POST'], controller: 'MemberCashOutController' },
{ path: '/api/member-account', methods: ['GET', 'POST'], controller: 'MemberAccountController' },
];
async function testApi(api) {
const results = [];
for (const method of api.methods) {
try {
console.log(`🧪 测试 ${method} ${api.path}...`);
const config = {
method: method.toLowerCase(),
url: `${BASE_URL}${api.path}`,
timeout: 5000,
validateStatus: () => true, // 接受所有状态码
};
// 添加测试数据
if (method === 'POST') {
config.data = {
test: true,
timestamp: new Date().toISOString()
};
}
const response = await axios(config);
results.push({
method,
path: api.path,
status: response.status,
statusText: response.statusText,
headers: response.headers,
data: response.data,
controller: api.controller,
timestamp: new Date().toISOString()
});
console.log(`${method} ${api.path} - Status: ${response.status}`);
} catch (error) {
console.log(`${method} ${api.path} - Error: ${error.message}`);
results.push({
method,
path: api.path,
error: error.message,
controller: api.controller,
timestamp: new Date().toISOString()
});
}
}
return results;
}
async function testAllApis() {
console.log('🚀 开始测试Core层API...');
const allResults = {
core: [],
api: [],
summary: {
total: 0,
success: 0,
error: 0,
timestamp: new Date().toISOString()
}
};
// 测试Core层接口
console.log('\n📋 测试Core层接口...');
for (const api of CORE_APIS) {
const results = await testApi(api);
allResults.core.push(...results);
}
// 测试API层接口用于对比
console.log('\n📋 测试API层接口...');
for (const api of API_APIS) {
const results = await testApi(api);
allResults.api.push(...results);
}
// 统计结果
allResults.summary.total = allResults.core.length + allResults.api.length;
allResults.summary.success = allResults.core.filter(r => !r.error).length + allResults.api.filter(r => !r.error).length;
allResults.summary.error = allResults.core.filter(r => r.error).length + allResults.api.filter(r => r.error).length;
// 保存结果到JSON文件
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(allResults, null, 2), 'utf-8');
console.log('\n📊 测试结果统计:');
console.log(` 总接口数: ${allResults.summary.total}`);
console.log(` 成功: ${allResults.summary.success}`);
console.log(` 失败: ${allResults.summary.error}`);
console.log(` 结果已保存到: ${OUTPUT_FILE}`);
return allResults;
}
// 主函数
async function main() {
try {
// 等待服务器启动
console.log('⏳ 等待服务器启动...');
await new Promise(resolve => setTimeout(resolve, 5000));
// 测试服务器是否可用
try {
await axios.get(`${BASE_URL}/`, { timeout: 3000 });
console.log('✅ 服务器已启动');
} catch (error) {
console.log('❌ 服务器未启动,尝试继续测试...');
}
const results = await testAllApis();
console.log('\n🎉 API测试完成');
} catch (error) {
console.error('❌ 测试失败:', error.message);
}
}
main();

View File

@@ -0,0 +1,73 @@
#!/usr/bin/env node
/**
* 测试Entity生成器
* 验证是否能正确生成完整的Entity文件
*/
const EntityGenerator = require('./src/generators/entity-generator.js');
const JavaParser = require('./src/parsers/java-parser.js');
const fs = require('fs');
const path = require('path');
async function testEntityGeneration() {
console.log('🧪 测试Entity生成器...');
const parser = new JavaParser();
const config = {
corePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src',
dryRun: false
};
const generator = new EntityGenerator(config);
try {
// 1. 读取Java文件
const javaFilePath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-java/niucloud-core/src/main/java/com/niu/core/entity/sys/SysConfig.java';
const javaContent = fs.readFileSync(javaFilePath, 'utf-8');
console.log('✅ 读取Java文件成功');
// 2. 解析字段
const fields = parser.extractEntityFields(javaContent);
console.log(`✅ 解析字段成功: ${fields.length}个字段`);
console.log('字段列表:', fields.map(f => f.name));
// 3. 生成Entity内容
const entityData = {
fields: fields,
tableName: 'sys_config'
};
const entityContent = generator.generateEntityContent('SysConfig', entityData);
console.log(`✅ 生成Entity内容成功: ${entityContent.length}字符`);
// 4. 写入测试文件
const testFilePath = '/tmp/test-sysconfig.entity.ts';
fs.writeFileSync(testFilePath, entityContent, 'utf-8');
console.log(`✅ 写入测试文件成功: ${testFilePath}`);
// 5. 验证文件内容
const writtenContent = fs.readFileSync(testFilePath, 'utf-8');
const hasMultipleFields = (writtenContent.match(/@Column/g) || []).length > 1;
const hasSiteId = writtenContent.includes('siteId');
const hasConfigKey = writtenContent.includes('configKey');
console.log('\n📋 验证结果:');
console.log(` 文件长度: ${writtenContent.length}字符`);
console.log(` 包含多个字段: ${hasMultipleFields ? '✅' : '❌'}`);
console.log(` 包含siteId: ${hasSiteId ? '✅' : '❌'}`);
console.log(` 包含configKey: ${hasConfigKey ? '✅' : '❌'}`);
if (hasMultipleFields && hasSiteId && hasConfigKey) {
console.log('\n🎉 Entity生成器测试通过');
} else {
console.log('\n❌ Entity生成器测试失败');
console.log('文件内容前500字符:');
console.log(writtenContent.substring(0, 500));
}
} catch (error) {
console.error('❌ 测试失败:', error);
}
}
testEntityGeneration();

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env node
const MigrationCoordinator = require('./migration-coordinator.js');
async function testEntityGeneration() {
console.log('=== 测试Entity生成器 ===\n');
const coordinator = new MigrationCoordinator();
try {
// 扫描Java项目
await coordinator.scanJavaLayers();
// 测试Entity迁移
await coordinator.migrateEntityLayer();
console.log('\n✅ Entity迁移完成');
} catch (error) {
console.log('\n❌ Entity迁移失败:', error.message);
console.log(error.stack);
}
}
testEntityGeneration();

View File

@@ -0,0 +1,413 @@
#!/usr/bin/env node
/**
* 🔍 生成代码验证脚本
* 验证自动迁移生成的NestJS代码质量
*/
const fs = require('fs');
const path = require('path');
class CodeValidator {
constructor() {
this.errors = [];
this.warnings = [];
this.stats = {
totalFiles: 0,
entityFiles: 0,
serviceFiles: 0,
controllerFiles: 0,
enumFiles: 0,
validFiles: 0,
errorFiles: 0
};
}
/**
* 验证所有生成的代码
*/
async validateAll() {
console.log('🔍 开始验证生成的NestJS代码...\n');
const corePath = '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/wwjcloud/libs/wwjcloud-core/src';
if (!fs.existsSync(corePath)) {
console.error('❌ Core目录不存在:', corePath);
return;
}
// 验证各个层级
await this.validateEntities(corePath);
await this.validateServices(corePath);
await this.validateControllers(corePath);
await this.validateEnums(corePath);
// 生成报告
this.generateReport();
}
/**
* 验证Entity文件
*/
async validateEntities(corePath) {
console.log('📋 验证Entity文件...');
const entityPath = path.join(corePath, 'entities');
if (!fs.existsSync(entityPath)) {
console.log(' ⚠️ Entity目录不存在');
return;
}
const files = fs.readdirSync(entityPath);
for (const file of files) {
if (file.endsWith('.entity.ts')) {
this.stats.entityFiles++;
await this.validateEntityFile(path.join(entityPath, file));
}
}
}
/**
* 验证Service文件
*/
async validateServices(corePath) {
console.log('🔧 验证Service文件...');
const servicePath = path.join(corePath, 'services');
if (!fs.existsSync(servicePath)) {
console.log(' ⚠️ Service目录不存在');
return;
}
// 验证各个子目录
const subDirs = ['admin', 'api', 'core'];
for (const subDir of subDirs) {
const dirPath = path.join(servicePath, subDir);
if (fs.existsSync(dirPath)) {
const files = fs.readdirSync(dirPath);
for (const file of files) {
if (file.endsWith('.service.ts')) {
this.stats.serviceFiles++;
await this.validateServiceFile(path.join(dirPath, file));
}
}
}
}
}
/**
* 验证Controller文件
*/
async validateControllers(corePath) {
console.log('🎮 验证Controller文件...');
const controllerPath = path.join(corePath, 'controllers');
if (!fs.existsSync(controllerPath)) {
console.log(' ⚠️ Controller目录不存在');
return;
}
// 验证各个子目录
const subDirs = ['adminapi', 'api', 'core'];
for (const subDir of subDirs) {
const dirPath = path.join(controllerPath, subDir);
if (fs.existsSync(dirPath)) {
const files = fs.readdirSync(dirPath);
for (const file of files) {
if (file.endsWith('.controller.ts')) {
this.stats.controllerFiles++;
await this.validateControllerFile(path.join(dirPath, file));
}
}
}
}
}
/**
* 验证Enum文件
*/
async validateEnums(corePath) {
console.log('📊 验证Enum文件...');
const enumPath = path.join(corePath, 'enums');
if (!fs.existsSync(enumPath)) {
console.log(' ⚠️ Enum目录不存在');
return;
}
const files = fs.readdirSync(enumPath);
for (const file of files) {
if (file.endsWith('.enum.ts')) {
this.stats.enumFiles++;
await this.validateEnumFile(path.join(enumPath, file));
}
}
}
/**
* 验证单个Entity文件
*/
async validateEntityFile(filePath) {
this.stats.totalFiles++;
const content = fs.readFileSync(filePath, 'utf8');
const fileName = path.basename(filePath);
let hasErrors = false;
// 检查基本结构
if (!content.includes('@Entity')) {
this.addError(fileName, '缺少@Entity装饰器');
hasErrors = true;
}
if (!content.includes('export class')) {
this.addError(fileName, '缺少export class声明');
hasErrors = true;
}
// 检查字段定义
const fieldCount = (content.match(/@Column/g) || []).length;
if (fieldCount === 0) {
this.addWarning(fileName, '没有定义任何字段');
}
// 检查主键
if (!content.includes('@PrimaryGeneratedColumn')) {
this.addWarning(fileName, '没有定义主键');
}
// 检查数据库列名映射
const hasColumnNameMapping = content.includes("name: '");
if (!hasColumnNameMapping) {
this.addWarning(fileName, '字段可能缺少数据库列名映射');
}
if (!hasErrors) {
this.stats.validFiles++;
} else {
this.stats.errorFiles++;
}
}
/**
* 验证单个Service文件
*/
async validateServiceFile(filePath) {
this.stats.totalFiles++;
const content = fs.readFileSync(filePath, 'utf8');
const fileName = path.basename(filePath);
let hasErrors = false;
// 检查基本结构
if (!content.includes('@Injectable')) {
this.addError(fileName, '缺少@Injectable装饰器');
hasErrors = true;
}
if (!content.includes('export class')) {
this.addError(fileName, '缺少export class声明');
hasErrors = true;
}
// 检查构造函数注入
if (!content.includes('constructor(')) {
this.addError(fileName, '缺少构造函数');
hasErrors = true;
}
// 检查Repository注入
if (!content.includes('@InjectRepository')) {
this.addWarning(fileName, '可能缺少Repository注入');
}
// 检查方法实现
const methodCount = (content.match(/async \w+\(/g) || []).length;
if (methodCount === 0) {
this.addWarning(fileName, '没有定义任何方法');
}
// 检查业务逻辑实现
const todoCount = (content.match(/TODO:/g) || []).length;
if (todoCount > 0) {
this.addWarning(fileName, `包含${todoCount}个TODO项需要手工实现`);
}
if (!hasErrors) {
this.stats.validFiles++;
} else {
this.stats.errorFiles++;
}
}
/**
* 验证单个Controller文件
*/
async validateControllerFile(filePath) {
this.stats.totalFiles++;
const content = fs.readFileSync(filePath, 'utf8');
const fileName = path.basename(filePath);
let hasErrors = false;
// 检查基本结构
if (!content.includes('@Controller')) {
this.addError(fileName, '缺少@Controller装饰器');
hasErrors = true;
}
if (!content.includes('export class')) {
this.addError(fileName, '缺少export class声明');
hasErrors = true;
}
// 检查HTTP方法装饰器
const httpMethods = ['@Get', '@Post', '@Put', '@Delete', '@Patch'];
const hasHttpMethod = httpMethods.some(method => content.includes(method));
if (!hasHttpMethod) {
this.addWarning(fileName, '没有定义任何HTTP端点');
}
// 检查Service注入
if (!content.includes('constructor(')) {
this.addError(fileName, '缺少构造函数');
hasErrors = true;
}
// 检查API装饰器
if (!content.includes('@ApiOperation')) {
this.addWarning(fileName, '缺少@ApiOperation装饰器');
}
// 检查统一响应格式
const hasUnifiedResponse = content.includes('{ code: 0, msg:') || content.includes('ApiResponseWrapper');
if (!hasUnifiedResponse) {
this.addWarning(fileName, '可能缺少统一响应格式');
}
if (!hasErrors) {
this.stats.validFiles++;
} else {
this.stats.errorFiles++;
}
}
/**
* 验证单个Enum文件
*/
async validateEnumFile(filePath) {
this.stats.totalFiles++;
const content = fs.readFileSync(filePath, 'utf8');
const fileName = path.basename(filePath);
let hasErrors = false;
// 检查基本结构
if (!content.includes('export enum') && !content.includes('export class')) {
this.addError(fileName, '缺少export enum或export class声明');
hasErrors = true;
}
// 检查枚举值
if (content.includes('export enum')) {
const enumValueCount = (content.match(/= '[^']+'/g) || []).length;
if (enumValueCount === 0) {
this.addWarning(fileName, '枚举没有定义任何值');
}
}
if (!hasErrors) {
this.stats.validFiles++;
} else {
this.stats.errorFiles++;
}
}
/**
* 添加错误
*/
addError(fileName, message) {
this.errors.push({ file: fileName, message });
}
/**
* 添加警告
*/
addWarning(fileName, message) {
this.warnings.push({ file: fileName, message });
}
/**
* 生成验证报告
*/
generateReport() {
console.log('\n📊 验证报告');
console.log('='.repeat(50));
// 统计信息
console.log(`\n📈 统计信息:`);
console.log(` 总文件数: ${this.stats.totalFiles}`);
console.log(` Entity文件: ${this.stats.entityFiles}`);
console.log(` Service文件: ${this.stats.serviceFiles}`);
console.log(` Controller文件: ${this.stats.controllerFiles}`);
console.log(` Enum文件: ${this.stats.enumFiles}`);
console.log(` 有效文件: ${this.stats.validFiles}`);
console.log(` 错误文件: ${this.stats.errorFiles}`);
// 错误信息
if (this.errors.length > 0) {
console.log(`\n❌ 错误 (${this.errors.length}个):`);
this.errors.forEach(error => {
console.log(` ${error.file}: ${error.message}`);
});
}
// 警告信息
if (this.warnings.length > 0) {
console.log(`\n⚠️ 警告 (${this.warnings.length}个):`);
this.warnings.forEach(warning => {
console.log(` ${warning.file}: ${warning.message}`);
});
}
// 质量评估
const qualityScore = this.stats.totalFiles > 0 ?
Math.round((this.stats.validFiles / this.stats.totalFiles) * 100) : 0;
console.log(`\n🎯 代码质量评分: ${qualityScore}%`);
if (qualityScore >= 90) {
console.log('✅ 代码质量优秀!');
} else if (qualityScore >= 70) {
console.log('⚠️ 代码质量良好,有改进空间');
} else {
console.log('❌ 代码质量需要改进');
}
// 建议
console.log(`\n💡 改进建议:`);
if (this.errors.length > 0) {
console.log(' - 修复所有错误项');
}
if (this.warnings.length > 0) {
console.log(' - 处理警告项以提升代码质量');
}
if (this.stats.totalFiles === 0) {
console.log(' - 没有找到任何生成的文件');
} else {
console.log(' - 继续完善业务逻辑实现');
console.log(' - 添加单元测试');
console.log(' - 完善错误处理');
}
console.log('\n🎉 验证完成!');
}
}
// 运行验证
if (require.main === module) {
const validator = new CodeValidator();
validator.validateAll().catch(console.error);
}
module.exports = CodeValidator;

View File

@@ -1,59 +0,0 @@
# 🚀 AI 恢复模块快速启动(针对 wwjcloud-nest-v1/apps/api
## 目标
- 在开发环境以最简配置验证 AI 恢复队列的闭环(事件→入队→处理→收敛)
## 预备条件
- Node.js 18+
- `wwjcloud-nest-v1` 中的 `apps/api` 可运行
## 环境变量(开发最简闭环)
```bash
NODE_ENV=development
PORT=3001
AI_ENABLED=true
GLOBAL_PREFIX=api
QUEUE_DRIVER=memory # 免 Redis/Kafka 干扰
TELEMETRY_ENABLED=false
REDIS_ENABLED=false
KAFKA_ENABLED=false
JWT_SECRET=dev-secret # 若开启守卫需配置
AUTH_ENABLED=true
RBAC_ENABLED=false
```
## 启动示例
> 推荐在 `wwjcloud-nest-v1` 目录下执行:
```bash
# 以 apps/api 方式启动(端口 3001
NODE_ENV=development JWT_SECRET=dev-secret AI_ENABLED=true AUTH_ENABLED=true RBAC_ENABLED=false GLOBAL_PREFIX=api QUEUE_ENABLED=false PORT=3001 npm run start -- api
```
## 本地验证命令
```bash
# 1) 初始队列大小(应为 0
curl -s http://localhost:3001/api/ai/recovery/status
# 2) 模拟失败(入队增长)
curl -s "http://localhost:3001/api/ai/recovery/simulate-failure?taskId=T1&severity=high&reason=quick-start"
# 3) 再次查看队列(应增长)
curl -s http://localhost:3001/api/ai/recovery/status
# 4) 处理一个(队列收敛)
curl -s -X POST http://localhost:3001/api/ai/recovery/process-one
# 5) 清空队列(可选)
curl -s -X POST http://localhost:3001/api/ai/recovery/drain
```
## 常见问题
- Kafka 报错但驱动为 `memory`:可忽略,不影响路由与内存队列
- 路由前缀:`GLOBAL_PREFIX=api` 下基础设施路由保留原始状态码(已在异常过滤器处理)
- 根应用与 apps/api两端可挂载 AI 模块;开发推荐统一在 `apps/api`3001验证
## 参考文档
- `docs/AI-RECOVERY-DEV.md`
- `docs/CONFIG_SETUP.md`
- `docs/DEVELOPMENT-GUIDE.md`
- `docs/PRODUCTION-DEPLOYMENT.md`

View File

@@ -1,53 +0,0 @@
# Tools v1针对 wwjcloud-nest-v1
该目录为 `wwjcloud-nest-v1` 代码库的工程化工具与模板集合,提供:
- 快速启动指南AI 恢复模块本地验证)
- apps/api 生产环境 `.env` 示例模板
- 与核心文档的交叉引用,便于团队上手与上线
## 目录
- `QUICK-START.md`AI 恢复模块快速启动与验证
- `env/apps-api.production.example`apps/api 生产环境示例 `.env`
- `java-tools/`Java架构 → NestJS 迁移工具集(生成器与协调器)
## 适用范围
- 仅适配 `wwjcloud-nest-v1/apps/api`
- 与项目文档:`docs/AI-RECOVERY-DEV.md``docs/CONFIG_SETUP.md``docs/DEVELOPMENT-GUIDE.md``docs/PRODUCTION-DEPLOYMENT.md` 一致
## 快速链接
- AI 开发指南:`docs/AI-RECOVERY-DEV.md`
- 配置指南:`docs/CONFIG_SETUP.md`
- 开发指南:`docs/DEVELOPMENT-GUIDE.md`
- 生产部署:`docs/PRODUCTION-DEPLOYMENT.md`
## 脚本列表(从 tools/ 迁移)
- `scripts/java-file-discovery.js`
- `scripts/quality-assurance.js`
- `scripts/test-dict-fix.js`
- `scripts/test-fixes.js`
- `scripts/test-incremental.js`
### 使用示例
```bash
# 运行质量保障脚本
node tools-v1/scripts/quality-assurance.js
# 运行 PHP 文件发现
node tools-v1/scripts/php-file-discovery.js
# 运行迁移协调器(别名脚本,固定 scripts 路径)
node tools-v1/scripts/migration-coordinator.js
# Dry-run 预览迁移计划(别名脚本)
DRY_RUN=true node tools-v1/scripts/migration-coordinator.js
# 直接运行迁移协调器(主文件位于 java-tools
node tools-v1/java-tools/migration-coordinator.js
# Dry-run 预览迁移计划(主文件)
DRY_RUN=true node tools-v1/java-tools/migration-coordinator.js
# 快速质量检查
node tools-v1/java-tools/generators/quality-gate.js quick
```

View File

@@ -1,26 +0,0 @@
# apps/api 开发环境 .env 示例wwjcloud-nest-v1
# 基本
NODE_ENV=development
PORT=3001
GLOBAL_PREFIX=api
# 安全(开发期可关闭守卫)
JWT_SECRET=dev-secret
AUTH_ENABLED=true
RBAC_ENABLED=false
# AI 模块(最简闭环)
AI_ENABLED=true
AI_SIMULATE_DIRECT_ENQUEUE=true
RATE_LIMIT_ENABLED=true
QUEUE_DRIVER=memory
# 观测性(开发期可关闭)
METRICS_ENABLED=false
TELEMETRY_ENABLED=false
TRACING_ENABLED=false
# 中间件(开发期禁用)
REDIS_ENABLED=false
KAFKA_ENABLED=false

View File

@@ -1,29 +0,0 @@
# apps/api 特性全开环境(本地验证用)
NODE_ENV=development
PORT=3001
GLOBAL_PREFIX=api
# 关闭鉴权与权限,便于本地验证
AUTH_ENABLED=false
RBAC_ENABLED=false
JWT_SECRET=dev-secret
# AI 与队列
AI_ENABLED=true
AI_SIMULATE_DIRECT_ENQUEUE=true
RATE_LIMIT_ENABLED=true
QUEUE_ENABLED=false
# QUEUE_DRIVER 不设置(避免 Joi 校验限制),禁用队列使用内存
# 观测与文档
PROMETHEUS_ENABLED=true
SWAGGER_ENABLED=true
SWAGGER_BEARER_AUTH_ENABLED=false
REQUEST_ID_ENABLED=true
LOG_JSON_ENABLED=false
SECURITY_ENABLED=true
CORS_ORIGIN=*
# 其他
REDIS_ENABLED=false
TENANT_ENABLED=false

View File

@@ -1,36 +0,0 @@
# apps/api 生产环境 .env 示例wwjcloud-nest-v1
# 基本
NODE_ENV=production
PORT=3001
GLOBAL_PREFIX=api
# 安全
JWT_SECRET=change-me-to-strong-secret-at-least-32-chars
AUTH_ENABLED=true
RBAC_ENABLED=true
# AI 模块
AI_ENABLED=true
QUEUE_DRIVER=redis # 生产推荐 redis如用 Kafka请切换并填写下方 Kafka 配置
# Redis 队列(推荐)
REDIS_ENABLED=true
REDIS_URL=redis://username:password@redis:6379/0
# Kafka 队列(可选)
KAFKA_ENABLED=false
KAFKA_BROKER=your-kafka:9092
KAFKA_CLIENT_ID=wwjcloud-ai
KAFKA_GROUP_ID=wwjcloud-ai-group
# 观测性
METRICS_ENABLED=true
TELEMETRY_ENABLED=true
TRACING_ENABLED=true
JAEGER_ENDPOINT=http://jaeger:14268/api/traces
# 其他建议
# - 在网关/WAF 限制 /api/ai/recovery/* 的来源与速率
# - 若不对外开放 AI 恢复端点,请移除 @Public() 或在服务端加守卫
# - 灰度切换时先低采样启用 telemetry再逐步调整

View File

@@ -1,611 +0,0 @@
# 迁移工具正确使用基础设施指南
## 概述
本文档说明如何在迁移工具中正确使用NestJS的基础设施(Common层)和业务核心(Core层),确保生成的业务代码能够充分利用框架能力。
## 新架构层级概览
### 🏗️ Common层基础设施 (原Core层基础设施迁移到此)
### 🧠 Core层业务核心 (原Common业务迁移到此)
**Core层应该放置具体的业务模块**
- **位置**: `libs/wwjcloud-core/src/{module_name}/`
- **模块示例**:
- `member/` - 会员管理业务模块
- `install/` - 安装向导业务模块
- `diy/` - DIY装修业务模块
- `dict/` - 数据字典业务模块
- **文件结构**: 各模块包含控制器、服务、实体、DTO等
- **用途**: 具体业务逻辑实现和业务流程控制
## Common层基础设施概览
### 1. 基础服务系统
- **位置**: `src/common/base/`
- **文件**: base.entity.ts, base.service.ts, base.repository.ts, base.module.ts
- **用途**: 通用基础服务、实体基类、仓储基类
### 2. 缓存系统
- **位置**: `src/common/cache/`
- **文件**: cache.service.ts, cache.module.ts, decorators/
- **用途**: 分布式缓存、缓存装饰器、性能优化
### 3. 上下文管理
- **位置**: `src/common/context/`
- **文件**: context.service.ts, context.module.ts
- **用途**: 请求上下文管理、多租户支持
### 4. 数据库服务
- **位置**: `src/common/database/`
- **文件**: database.module.ts, backup.service.ts
- **用途**: 数据库连接、备份服务
### 5. 异常处理系统
- **位置**: `src/common/exception/`
- **文件**: exception.filter.ts, business.exception.ts, base.exception.ts
- **用途**: 统一异常处理、业务异常、错误响应格式化
### 6. 事件系统
- **位置**: `src/common/event/`
- **文件**: event.module.ts
- **用途**: 事件驱动、应用事件处理
### 7. 拦截器系统
- **位置**: `src/common/interceptors/`
- **文件**: method-call.interceptor.ts, request-parameter.interceptor.ts
- **用途**: 请求拦截、方法调用统计、参数校验
### 8. 响应系统
- **位置**: `src/common/response/`
- **文件**: response.interceptor.ts, result.class.ts, result.interface.ts
- **用途**: 统一响应格式、结果封装、API标准化
### 9. 安全系统
- **位置**: `src/common/security/`
- **文件**: guards/, strategies/, decorators/
- **用途**: JWT认证、角色授权、权限控制
### 10. 日志系统
- **位置**: `src/common/logging/`
- **文件**: logging.service.ts, logging.module.ts
- **用途**: 统一日志管理、日志级别控制
### 11. 监控系统
- **位置**: `src/common/monitoring/`
- **文件**: monitoring.service.ts, monitoring.module.ts
- **用途**: 应用监控、性能指标、健康检查
### 12. 队列系统
- **位置**: `src/common/queue/`
- **文件**: queue.module.ts
- **用途**: 消息队列、异步任务处理
### 13. 调度系统
- **位置**: `src/common/scheduler/`
- **文件**: scheduler.module.ts
- **用途**: 定时任务、计划任务调度
### 14. 工具库系统
- **位置**: `src/common/libraries/`
- **文件**: redis/, dayjs/, lodash/, winston/, prometheus/, sharp/, uuid/
- **用途**: 第三方库集成、工具服务提供
### 15. 插件系统
- **位置**: `src/common/plugins/`
- **文件**: captcha/, qrcode/, wechat/
- **用途**: 功能插件、扩展能力
### 16. Swagger文档
- **位置**: `src/common/swagger/`
- **文件**: swagger.module.ts, swagger.service.ts
- **用途**: API文档生成、接口文档管理
### 17. 验证系统
- **位置**: `src/common/validation/`
- **文件**: base.dto.ts, custom-validators.ts
- **用途**: 数据验证、DTO基类、自定义验证器
### 18. 管道系统
- **位置**: `src/common/pipes/`
- **文件**: parse-diy-form.pipe.ts, pipes.module.ts
- **用途**: 数据转换、格式处理、参数解析
### 19. 工具类
- **位置**: `src/common/utils/`
- **文件**: clone.util.ts, crypto.util.ts, json.util.ts, system.util.ts
- **用途**: 通用工具函数、系统功能、加密解密
### 20. 语言系统
- **位置**: `src/common/language/`
- **文件**: language.utils.ts
- **用途**: 多语言支持、国际化处理
### 21. 追踪系统
- **位置**: `src/common/tracing/`
- **文件**: tracing.module.ts, tracing.service.ts
- **用途**: 链路追踪、性能监控、请求跟踪
### 22. 加载器系统
- **位置**: `src/common/loader/`
- **文件**: loader.module.ts, loader.utils.ts
- **用途**: 资源加载、配置加载、动态加载
### 23. 初始化系统
- **位置**: `src/common/init/`
- **文件**: init.module.ts, init.service.ts
- **用途**: 应用初始化、启动配置
### 24. 系统工具
- **位置**: `src/common/system/`
- **文件**: system.module.ts, system.utils.ts
- **用途**: 系统信息、环境管理
## 迁移工具使用基础设施的正确方式
### 1. 控制器生成器使用基础设施
#### 1.1 使用安全认证
```typescript
// 正确使用方式
import { Controller, Get, Post, Put, Delete, Body, Param, Query } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { AuthGuard } from '@wwjCommon/infra/auth/auth.guard';
import { RbacGuard } from '@wwjCommon/infra/auth/rbac.guard';
import { Roles, Public } from '@wwjCommon/infra/auth/decorators';
@ApiTags('diy')
@Controller('adminapi/diy')
@UseGuards(JwtAuthGuard, RolesGuard) // 使用Common层守卫
export class ConfigController {
constructor(
private readonly diyConfig: AdminDiyConfigService
) {}
@Get('list')
@Roles('admin') // 使用Core层角色装饰器
@ApiOperation({ summary: '获取配置列表' })
async getList(@Query() query: any) {
// 业务逻辑实现
}
@Post('create')
@Roles('admin')
@ApiOperation({ summary: '创建配置' })
async create(@Body() body: any) {
// 业务逻辑实现
}
}
```
#### 1.2 使用异常处理
```typescript
// 正确使用方式
import { BadRequestException } from '@nestjs/common';
@Get('list')
async getList(@Query() query: any) {
try {
// 业务逻辑
return await this.diyConfig.getList(query);
} catch (error) {
// 使用Core层异常处理
throw new BusinessException('获取配置列表失败', error);
}
}
```
#### 1.3 使用管道验证
```typescript
// 正确使用方式
import { ParseDiyFormPipe } from '@wwjCommon/pipes/parse-diy-form.pipe';
@Post('create')
async create(
@Body(ParseDiyFormPipe) body: any // 使用Common层管道
) {
// 业务逻辑实现
}
```
### 2. 服务生成器使用基础设施
#### 2.1 使用数据库服务
```typescript
// 正确使用方式
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BaseService } from '@wwjCommon/base/base.service';
import { DatabaseModule } from '@wwjCommon/database/database.module';
@Injectable()
export class DiyConfigService_adminService extends BaseService<any> {
constructor(
@InjectRepository(DiyConfig)
protected readonly repository: Repository<DiyConfig>,
// 使用Common层基础服务和数据库
) {
super(repository);
}
async getList(params: any) {
// 业务逻辑实现
return await this.repository.find(params);
}
async create(data: any) {
// 业务逻辑实现
return await this.repository.save(data);
}
}
```
#### 2.2 使用缓存服务
```typescript
// 正确使用方式
import { CacheService } from '@wwjCommon/cache/cache.service';
@Injectable()
export class DiyConfigService_adminService extends BaseService<any> {
constructor(
@InjectRepository(DiyConfig)
protected readonly repository: Repository<DiyConfig>,
private readonly cacheService: CacheService // 使用Common层缓存服务
) {
super(repository);
}
async getList(params: any) {
const cacheKey = `diy:config:list:${JSON.stringify(params)}`;
// 使用Common层缓存服务
let result = await this.cacheService.get(cacheKey);
if (!result) {
result = await this.repository.find(params);
await this.cacheService.set(cacheKey, result); // 缓存
}
return result;
}
async update(id: number, data: any) {
// 业务逻辑实现
const result = await this.repository.update(id, data);
// 清除相关缓存
await this.cacheService.del(`diy:config:list:*`);
return result;
}
}
```
#### 2.3 使用队列服务
```typescript
// 正确使用方式
import { QueueModule } from '@wwjCommon/queue/queue.module';
@Injectable()
export class DiyConfigService_adminService extends BaseService<any> {
constructor(
@InjectRepository(DiyConfig)
protected readonly repository: Repository<DiyConfig>,
private readonly queueService: UnifiedQueueService // 使用Core层队列服务
) {
super(repository);
}
async create(data: any) {
// 业务逻辑实现
const result = await this.repository.save(data);
// 使用Core层队列服务发送异步任务
await this.queueService.addTask('diy', 'configCreated', {
id: result.id,
data: result
});
return result;
}
}
```
### 3. 实体生成器使用基础设施
#### 3.1 使用基础实体
```typescript
// 正确使用方式
import { Entity, PrimaryGeneratedColumn, PrimaryColumn, Column, Index } from 'typeorm';
import { BaseEntity } from '@wwjCore';
@Entity('diy_page')
export class Diy extends BaseEntity {
@PrimaryColumn({ name: 'id', type: 'int' })
id: number;
@Column({ name: 'name', length: 100 })
name: string;
@Column({ name: 'content', type: 'text' })
content: string;
@Column({ name: 'status', type: 'tinyint', default: 1 })
status: number;
@Index('idx_site_id') // 使用Core层索引管理
@Column({ name: 'site_id', type: 'int' })
siteId: number;
}
```
### 4. DTO生成器使用基础设施
#### 4.1 使用验证管道
```typescript
// 正确使用方式
import { IsString, IsNumber, IsOptional, IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { validateEvent } from '@wwjCore/event/contractValidator';
export class CreateDiyDto {
@ApiProperty({ description: '页面名称' })
@IsString()
@IsNotEmpty()
name: string;
@ApiProperty({ description: '页面内容' })
@IsString()
@IsNotEmpty()
content: string;
@ApiProperty({ description: '状态', required: false })
@IsNumber()
@IsOptional()
status?: number;
}
export class DiyDtoValidator {
static async validate(data: CreateDiyDto): Promise<boolean> {
// 使用Core层契约验证
return await validateEvent('diy.create', data);
}
}
```
### 5. 监听器生成器使用基础设施
#### 5.1 使用事件系统
```typescript
// 正确使用方式
import { Injectable } from '@nestjs/common';
import { DomainEventHandler, EventHandler } from '@wwjCore';
import { EventBusPublisher } from '@wwjCore/event/eventBusPublisher';
@Injectable()
@DomainEventHandler()
export class ThemeColorListener {
constructor(
private readonly eventBus: EventBusPublisher // 使用Core层事件总线
) {}
@EventHandler('themecolor.handle')
async handle(payload: any) {
try {
// 业务逻辑实现
const result = await this.processThemeColor(payload);
// 使用Core层事件总线发布新事件
await this.eventBus.publish('themecolor.processed', result);
return result;
} catch (error) {
// 使用Core层异常处理
throw new BusinessException('主题颜色处理失败', error);
}
}
private async processThemeColor(payload: any) {
// 业务逻辑实现
if (payload.key === 'app') {
return {
theme_color: [
{
title: '商务蓝',
name: 'blue',
value: '#1890ff'
}
]
};
}
return null;
}
}
```
### 6. 任务生成器使用基础设施
### 7. 中间件生成器已废弃
**重要说明**: 中间件生成器已废弃请使用Core层Guards+Interceptors+Pipes
#### 废弃原因
- ❌ 原生NestMiddleware已过时
- ❌ 与Java框架不一致Java使用拦截器而非中间件
- ❌ Core层已提供完整的安全基础设施
#### 替代方案
使用Core层基础设施替代中间件
```typescript
// 认证 - 使用Guards
@UseGuards(AdminCheckTokenGuard, RolesGuard)
@Controller('adminapi/user')
export class UserController {
// 业务逻辑
}
// 拦截 - 使用Interceptors
@UseInterceptors(TracingInterceptor, ResponseInterceptor)
export class UserService {
// 业务逻辑
}
// 验证 - 使用Pipes
@Post()
createUser(@Body(ValidationPipe) createUserDto: CreateUserDto) {
// 业务逻辑
}
```
#### Core层基础设施对比
| 功能 | 中间件 | Core层替代 | 说明 |
|------|--------|------------|------|
| 认证 | ❌ 过时 | ✅ AdminCheckTokenGuard | 与Java SaTokenInterceptor一致 |
| 授权 | ❌ 过时 | ✅ RolesGuard | 与Java权限控制一致 |
| 拦截 | ❌ 过时 | ✅ TracingInterceptor | 与Java AOP切面一致 |
| 验证 | ❌ 过时 | ✅ TimestampPipe | 与Java过滤器一致 |
#### 6.1 使用队列服务
```typescript
// 正确使用方式
import { Injectable } from '@nestjs/common';
import { UnifiedQueueService } from '@wwjCore';
@Injectable()
export class DiyJob {
constructor(
private readonly queueService: UnifiedQueueService // 使用Core层队列服务
) {}
async addJob(data: any, options?: any) {
try {
// 使用Core层队列服务添加任务
await this.queueService.addTask('diy', 'DiyJob', data, options);
console.log('Diy job added to queue:', data);
} catch (error) {
console.error('Failed to add Diy job to queue:', error);
throw error;
}
}
async processJob(data: any) {
try {
// 业务逻辑实现
const result = await this.processDiyData(data);
return result;
} catch (error) {
console.error('Failed to process Diy job:', error);
throw error;
}
}
private async processDiyData(data: any) {
// 业务逻辑实现
return { processed: true, data };
}
}
```
### 7. 命令生成器使用基础设施
#### 7.1 使用命令行工具
```typescript
// 正确使用方式
import { Injectable } from '@nestjs/common';
import { Command, CommandRunner, Option } from 'nest-commander';
import { Logger } from '@nestjs/common';
interface InstallCommandOptions {
name?: string;
verbose?: boolean;
force?: boolean;
}
@Injectable()
@Command({
name: 'install',
description: 'Install command description',
})
export class InstallCommand extends CommandRunner {
private readonly logger = new Logger(InstallCommand.name);
async run(
passedParams: string[],
options?: InstallCommandOptions,
): Promise<void> {
this.logger.log('Executing Install command...');
try {
// 业务逻辑实现
await this.executeInstall(options);
this.logger.log('Install command completed successfully');
} catch (error) {
this.logger.error('Install command failed:', error);
throw error;
}
}
private async executeInstall(options?: InstallCommandOptions) {
// 业务逻辑实现
this.logger.log(`Installing with options: ${JSON.stringify(options)}`);
}
}
```
## 迁移工具实现要求
### 1. 控制器生成器要求
- 必须使用Common层守卫JwtAuthGuard、RolesGuard
- 必须使用Common层装饰器@Roles@Public
- 必须使用Common层异常处理BusinessException
- 必须使用Common层管道ParseDiyFormPipe等
- 必须生成完整的HTTP方法@Get@Post@Put@Delete
### 2. 服务生成器要求
- 必须继承Common层BaseService
- 必须使用Common层缓存服务CacheService
- 必须使用Common层响应系统Result响应格式
- 必须使用Common层日志服务LoggingService
- 必须生成完整的业务方法实现
### 3. 实体生成器要求
- 必须继承Common层BaseEntity
- 必须使用正确的TypeORM装饰器
- 必须生成完整的业务字段
- 必须包含site_id多租户支持
### 4. DTO生成器要求
- 必须使用class-validator装饰器
- 必须继承Common层BaseDto
- 必须生成完整的字段定义
- 必须使用Swagger文档装饰器
### 5. 监听器生成器要求
- 必须使用Common层事件系统EventModule
- 必须使用Common层异常处理
- 必须生成完整的事件处理逻辑
- 必须使用Common层日志记录
### 6. 任务生成器要求
- 必须使用Common层队列服务QueueModule
- 必须生成完整的任务方法
- 必须使用Common层异常处理
- 必须生成完整的业务逻辑
### 7. 命令生成器要求
- 必须使用nest-commander框架
- 必须使用Common层日志服务
- 必须生成完整的命令逻辑
- 必须使用Common层异常处理
## 总结
迁移工具必须正确使用Common层的基础设施确保生成的业务代码能够充分利用框架能力。只有这样才能生成真正可用的业务代码而不是空壳。
## 下一步行动
1. 修改所有生成器正确使用Common层基础设施
2. 实现PHP源码解析器提取真实的业务逻辑
3. 完善语法转换确保PHP语法正确转换为TypeScript语法
4. 测试生成的业务代码,确保可以正常运行

View File

@@ -1,77 +0,0 @@
### WWJCloud Migration Tooling Rules
Purpose: Standardize Java→NestJS migration for AI-friendly, repeatable generation. Tools only; do not hand-edit generated outputs.
— Scope & Principles —
- **Java架构参考**: 主要架构参考是Java框架 (Spring Boot)扫描Java项目的service/core, service/admin, service/api结构
- **三层架构**: 按照Java的三层结构生成NestJS服务core(核心业务) + admin(管理服务) + api(接口服务)
- **Core依赖**: admin/api层服务可以依赖core层服务类似Java的`@Resource ICoreSiteService`
- NestJS compliance: Follow official module/controller/service/entity/DTO patterns; DI-first; guards/pipes/interceptors.
- Core-only: Generators write strictly under `libs/wwjcloud-core/src/{module}/...`. Do NOT create/modify `src/common`, `src/vendor`, or `src/config`.
— Contracts & Compatibility —
- Database alignment: Table/column/index/types must match PHP 100%. No new/renamed/removed fields.
- Method alignment: Service method names map 1:1 with PHP. Do not invent names.
- Routing: Keep `/adminapi` and `/api` prefixes and controller segmentation consistent with PHP.
- Validation: Map PHP validators to DTO + class-validator/pipes. Behaviorally equivalent.
— Naming & Paths —
- Files: kebab-case filenames
- Controllers: `*.controller.ts`
- Services: `*.service.ts`
- Entities: `*.entity.ts`
- Classes: PascalCase.
- Aliases (tsconfig): `@wwjCommon/*`, `@wwjCore/*`, `@wwjVendor/*`, `@/*`.
— Infrastructure Mapping (V1 Framework) —
- Use V1框架基础设施层:
- Cache: `@wwjcloud-boot/infra/cache/cache.service` (CacheService)
- Metrics: `@wwjcloud-boot/infra/metrics/metrics.service` (MetricsService)
- Tenant: `@wwjcloud-boot/infra/tenant/tenant.service` (TenantService)
- Auth: `@wwjcloud-boot/infra/auth/*` (AuthGuard, RbacGuard)
- Vendor Services: `@wwjcloud-boot/vendor/*` (PayService, UploadService, SmsService, NoticeService)
- 参考Java架构: @Service + 依赖注入类似Spring Boot模式
— Module Generation —
- Generate `libs/wwjcloud-core/src/{module}/{module}.module.ts` registering discovered controllers/services.
- Entities: detect `*.entity.ts`; optionally include `TypeOrmModule.forFeature([...])` (feature flag).
- Filter non-business directories by default (whitelist/blacklist). Avoid generating modules for technical directories like `job/`, `queue/`, `workerman/`, `lang/`, etc.
— Generation Stages (feature flags) —
- Commands: disabled by default (we do not use `nest-commander`).
- Jobs/Listeners: configurable; ensure no duplicate suffixes (avoid `JobJob`/`ListenerListener`).
- Routes: no separate route files (NestJS uses decorators).
— Idempotency & Safety —
- Re-runnable: Same inputs → same outputs. Overwrite files in place; create missing directories; never delete parent folders.
- Dry-run mode: Output plan without writing files; provide diff-like summary.
- Logging: Summarize counts for modules/controllers/services/entities/validators, skipped items, and errors.
— Security & Multitenancy —
- Guards: apply standard guards in controllers; enforce role checks and optional auth where applicable.
- Tenant isolation: preserve `site_id` semantics; avoid exposing sensitive fields in responses.
— Quality Gates —
- After generation (tool-side), optionally run TypeScript compile and ESLint checks. Fail fast and report.
- Remove duplicate imports; standardize import order; ensure resolved alias paths.
— Temporary Artifacts —
- All temporary scripts/docs/reports stay in `tools-v1/java-tools/`. Clean up when done. Never write temp files outside `tools-v1/java-tools/`.
— Enforcement —
- “Only fix tools, not generated files.” If outputs are wrong, update tools and re-run.
— Versioning & Extensibility —
- Keep infra replacement map versioned and extensible to support future modules and AI evolution.
— Quick Checklist —
- [ ] Files are kebab-case; classes are PascalCase
- [ ] Controllers only orchestrate/validate; services hold business logic
- [ ] Entities map DB 1:1 with PHP schema
- [ ] All infra imports use `@wwjCommon/*`
- [ ] `/adminapi` and `/api` controllers generated correctly
- [ ] Modules register found controllers/services; optional TypeORM feature import
- [ ] Commands disabled; jobs/listeners gated; no duplicate suffixes
- [ ] Safe write, idempotent, dry-run available; logs emitted

View File

@@ -1,233 +0,0 @@
# 🚀 工具快速开始指南
## 📋 核心功能
1. **Dry-run 模式** - 预览生成结果,不实际修改文件
2. **Quality Gate** - 自动化质量检查TypeScript + ESLint
3. **模块化生成器** - 12个专用生成器职责清晰
---
## ⚡ 快速命令
### 1. 完整迁移(推荐)
```bash
# 正常执行
node tools-v1/java-tools/migration-coordinator.js
# Dry-run 模式(仅预览)
DRY_RUN=true node tools-v1/java-tools/migration-coordinator.js
```
### 2. 单独运行生成器
```bash
# 实体生成器
node tools-v1/java-tools/generators/entity-generator.js
# 实体生成器 (dry-run)
DRY_RUN=true node tools-v1/java-tools/generators/entity-generator.js
# 控制器生成器
node tools-v1/java-tools/generators/controller-generator.js --dry-run
```
### 3. 质量检查
```bash
# 完整质量检查
node tools-v1/java-tools/generators/quality-gate.js
# 快速检查(仅核心层)
node tools-v1/java-tools/generators/quality-gate.js quick
```
### 4. 验证修复
```bash
# 验证所有修复是否正确
node tools-v1/scripts/test-fixes.js
```
---
## 🎯 典型工作流
### 场景1: 首次迁移
```bash
# 步骤1: 发现Java架构文件参考Java提取PHP业务逻辑
node tools-v1/scripts/php-file-discovery.js
# 步骤2: 预览迁移结果dry-run
DRY_RUN=true node tools-v1/java-tools/migration-coordinator.js
# 步骤3: 确认无误后执行实际迁移
node tools-v1/java-tools/migration-coordinator.js
# 步骤4: 质量检查
node tools-v1/java-tools/generators/quality-gate.js
```
### 场景2: 单独生成某个模块
```bash
# 步骤1: 预览实体生成
DRY_RUN=true node tools-v1/java-tools/generators/entity-generator.js
# 步骤2: 实际生成实体
node tools-v1/java-tools/generators/entity-generator.js
# 步骤3: 生成控制器
node tools-v1/java-tools/generators/controller-generator.js
# 步骤4: 生成服务
node tools-v1/java-tools/generators/service-generator.js
# 步骤5: 生成模块文件
node tools-v1/java-tools/generators/module-generator.js
```
### 场景3: 验证和质量检查
```bash
# 验证修复
node tools-v1/scripts/test-fixes.js
# 质量检查
node tools-v1/java-tools/generators/quality-gate.js
# 如果有错误,查看详细输出
VERBOSE=true node tools-v1/java-tools/generators/quality-gate.js
```
---
## 🔧 环境变量
| 变量 | 作用 | 示例 |
|------|------|------|
| `DRY_RUN` | 启用 dry-run 模式 | `DRY_RUN=true node tools-v1/java-tools/...` |
| `VERBOSE` | 详细输出模式 | `VERBOSE=true node tools-v1/java-tools/...` |
---
## 📁 核心文件
| 文件 | 作用 | 何时使用 |
|------|------|---------|
| `migration-coordinator.js` | 主协调器 | 完整迁移流程 |
| `base-generator.js` | 基础生成器 | 被其他生成器继承 |
| `quality-gate.js` | 质量门禁 | 质量检查 |
| `test-fixes.js` | 验证脚本 | 验证修复是否正确 |
---
## 💡 小技巧
### 1. 使用 dry-run 避免误操作
始终先用 dry-run 模式预览结果:
```bash
DRY_RUN=true node tools-v1/java-tools/migration-coordinator.js
```
### 2. 详细输出帮助调试
遇到问题时启用详细输出:
```bash
VERBOSE=true node tools-v1/java-tools/generators/entity-generator.js
```
### 3. 组合使用
```bash
# 同时启用 dry-run 和详细输出
DRY_RUN=true VERBOSE=true node tools-v1/java-tools/migration-coordinator.js
```
### 4. 快速质量检查
开发过程中频繁运行快速检查:
```bash
node tools-v1/java-tools/generators/quality-gate.js quick
```
---
## ⚠️ 注意事项
1. **首次运行前备份**
- 建议先用 dry-run 模式预览
- 确认结果正确后再实际执行
2. **Quality Gate 可能失败**
- TypeScript 编译错误
- ESLint 规范问题
- 可以先生成代码,后续修复
3. **生成器顺序建议**
```
实体 → 验证器 → 服务 → 控制器 → 模块
```
4. **遇到错误时**
- 查看错误日志
- 使用 VERBOSE 模式
- 检查 PHP 源文件是否存在
---
## 🆘 常见问题
### Q: Dry-run 模式不生效?
检查环境变量设置:
```bash
# macOS/Linux
DRY_RUN=true node tools-v1/java-tools/...
# Windows PowerShell
$env:DRY_RUN="true"; node tools-v1/java-tools/...
# Windows CMD
set DRY_RUN=true && node tools-v1/java-tools/...
```
### Q: Quality Gate 一直失败?
可能原因:
1. TypeScript 配置问题
2. ESLint 配置问题
3. npm script 未配置
检查 `package.json`:
```json
{
"scripts": {
"type-check": "tsc --noEmit",
"lint": "eslint src --ext .ts"
}
}
```
### Q: 生成的文件不符合预期?
1. 检查 PHP 源文件是否存在
2. 使用 VERBOSE 模式查看详细日志
3. 检查 java-discovery-result.json 数据
---
## 📚 更多信息
- **完整文档**: [README.md](./README.md)
- **迁移规则**: [MIGRATION-RULES.md](./MIGRATION-RULES.md)
- **修复总结**: [FIX-SUMMARY.md](./FIX-SUMMARY.md)
- **基础设施指南**: [INFRASTRUCTURE-USAGE-GUIDE.md](./INFRASTRUCTURE-USAGE-GUIDE.md)
---
**祝你使用愉快!** 🎉

View File

@@ -1,312 +0,0 @@
# Java架构到NestJS迁移工具
## 📋 工具概览
本目录包含完整的Java架构到NestJS迁移工具链参考Java Spring Boot架构按步骤执行确保100%完成迁移。
## 📁 工具目录结构
```
tools-v1/java-tools/
├── migration-coordinator.js # 🎯 主协调器
├── generators/ # 📦 生成器目录
│ ├── controller-generator.js # 🎮 控制器生成器
│ ├── service-generator.js # ⚙️ 服务生成器
│ ├── entity-generator.js # 🏗️ 实体生成器
│ ├── validator-generator.js # 📝 验证器生成器
│ ├── middleware-generator.js # 🗑️ 已废弃使用Core层Guards+Interceptors+Pipes
│ ├── route-generator.js # 🛣️ 路由生成器
│ ├── job-generator.js # ⚡ 任务生成器
│ ├── listener-generator.js # 👂 监听器生成器
│ ├── command-generator.js # ⌨️ 命令生成器
│ ├── dict-generator.js # 📚 字典生成器
│ ├── business-logic-converter.js # 🔄 业务逻辑转换器
│ └── module-generator.js # 📦 模块生成器
├── java-discovery-result.json # 📊 发现结果数据Java架构参考
└── README.md # 📖 说明文档
```
## 🛠️ 工具列表
### 🎯 主协调器
1. **`migration-coordinator.js`** - 迁移协调器(主控制器)
- 协调所有生成器的执行
- 按步骤完成Java架构到NestJS的迁移参考Java提取PHP业务逻辑
- 提供整体流程控制和统计报告
- **新增**: 集成 Quality Gate 质量检查
### 🔧 基础设施工具
1. **`base-generator.js`** - 基础生成器类
- 提供通用的 dry-run 模式支持
- 统一的文件操作和日志功能
- 所有生成器的基类
2. **`quality-gate.js`** - 质量门禁工具
- TypeScript 编译检查
- ESLint 代码规范检查
- 自动化质量保障
### 📦 生成器集合generators/目录)
2. **`controller-generator.js`** - 控制器生成器
- 生成NestJS控制器文件
- 支持adminapi和api两层架构
- 自动注入服务和依赖
3. **`service-generator.js`** - 服务生成器
- 生成和更新NestJS服务
- 处理admin/api/core三层架构
- 转换业务逻辑为TypeScript参考Java架构提取PHP逻辑
4. **`entity-generator.js`** - 实体生成器
- 从PHP模型生成TypeORM实体
- 自动映射数据库字段
- 支持主键和关系映射
5. **`validator-generator.js`** - 验证器生成器
- 生成NestJS DTO验证器
- 包含class-validator装饰器
- 支持Swagger文档注解
6. **`middleware-generator.js`** - 🗑️ 已废弃使用Core层Guards+Interceptors+Pipes
- ❌ 已废弃原生NestMiddleware已过时
- ✅ 替代方案使用Core层Guards+Interceptors+Pipes
- 🔄 与Java框架保持一致都使用拦截器而非中间件
7. **`route-generator.js`** - 路由生成器
- 生成NestJS路由配置
- 支持模块化路由管理
- 包含RESTful API路由
8. **`job-generator.js`** - 任务生成器
- 生成NestJS定时任务
- 支持@nestjs/schedule装饰器
- 包含队列和批处理任务
9. **`listener-generator.js`** - 监听器生成器
- 生成NestJS事件监听器
- 支持@nestjs/event-emitter
- 处理业务事件和通知
10. **`command-generator.js`** - 命令生成器
- 生成NestJS命令行工具
- 支持nest-commander
- 包含系统维护命令
11. **`dict-generator.js`** - 字典生成器
- 生成NestJS枚举和字典
- 包含常量定义和映射
- 支持多语言和配置
13. **`business-logic-converter.js`** - 业务逻辑转换器
- PHP到TypeScript代码转换
- 包含所有转换规则和语法修复
- 被其他生成器调用的核心引擎
14. **`module-generator.js`** - 模块生成器
- 生成NestJS模块文件
- 处理依赖注入和导入
- 支持模块间通信
### 🔍 辅助工具
15. **`java-file-discovery.js`** - Java架构文件发现工具
- 扫描Java项目架构结构
- 发现所有相关文件(控制器、服务、模型等)
- 生成 `java-discovery-result.json`
### 传统工具(保留)
5. **`real-business-logic-generator.js`** - 完整生成器3000+行,建议逐步替换)
- 基于PHP结构生成NestJS代码框架
- 创建控制器、服务、实体、DTO等文件
- 生成完整的目录结构
6. **`php-business-logic-extractor.js`** - PHP业务逻辑提取器
- 提取PHP真实业务逻辑
- 转换为NestJS/TypeScript代码
- 处理所有文件类型(控制器、服务、字典、任务、命令、监听器)
7. **`module-generator.js`** - 模块文件生成器
- 为每个模块生成 `.module.ts` 文件
- 正确引用所有组件
- 处理依赖关系
8. **`crud-method-completer.js`** - CRUD方法完善工具
- 完善剩余的TODO CRUD方法
- 实现真实的业务逻辑
- 提供标准的增删改查实现
### 执行脚本
6. **`run-migration.js`** - 完整迁移执行器
- 按步骤执行所有工具
- 提供进度报告
- 错误处理和恢复
7. **`clean-and-migrate.js`** - 清理并重新迁移
- 删除现有common层
- 执行完整迁移流程
- 一键重新开始
## 🚀 使用方法
### 🎯 推荐方法:新工具链
```bash
# 使用新的模块化工具链(推荐)
node tools-v1/java-tools/migration-coordinator.js
# Dry-run 模式(仅预览,不实际修改文件)
DRY_RUN=true node tools-v1/java-tools/migration-coordinator.js
# 或使用命令行参数
node tools-v1/java-tools/migration-coordinator.js --dry-run
# 详细输出模式
VERBOSE=true node tools-v1/java-tools/migration-coordinator.js
```
### 🚦 Quality Gate 独立运行
```bash
# 完整质量检查
node tools-v1/java-tools/generators/quality-gate.js
# 快速检查(仅核心层)
node tools-v1/java-tools/generators/quality-gate.js quick
```
### 🔧 分步执行新工具
```bash
# 步骤1: 发现Java架构文件参考Java提取PHP业务逻辑
node tools-v1/scripts/java-file-discovery.js
# 步骤2: 使用新的协调器包含所有12个生成器
node tools-v1/java-tools/migration-coordinator.js
# 步骤3: 单独运行特定生成器(可选,支持 dry-run
DRY_RUN=true node tools-v1/java-tools/generators/controller-generator.js
node tools-v1/java-tools/generators/service-generator.js --dry-run
node tools-v1/java-tools/generators/entity-generator.js
# ... 其他生成器
# 步骤4: 质量检查
node tools-v1/java-tools/generators/quality-gate.js
```
### 方法3: 传统工具链(逐步替换)
```bash
# 清理并重新迁移(一键完成)
node tools-v1/java-tools/clean-and-migrate.js
```
### 方法4: 分步执行传统工具
```bash
# 执行完整迁移流程
node tools-v1/java-tools/run-migration.js
```
### 方法5: 手动执行传统工具
```bash
# 步骤1: 发现Java架构文件参考Java提取PHP业务逻辑
node tools-v1/scripts/java-file-discovery.js
# 步骤2: 生成NestJS结构
node tools-v1/java-tools/real-business-logic-generator.js
# 步骤3: 提取PHP业务逻辑
node tools-v1/java-tools/php-business-logic-extractor.js
# 步骤4: 生成模块文件
node tools-v1/java-tools/module-generator.js
# 步骤5: 完善CRUD方法
node tools-v1/java-tools/crud-method-completer.js
```
## 📊 迁移统计
### 🎯 新工具链统计(最新)
- **生成控制器**: 94个
- **生成服务**: 190个admin/api/core三层
- **生成实体**: 64个
- **生成验证器**: 34个
- **生成中间件**: 8个
- **生成路由**: 32个
- **生成任务**: 22个
- **生成监听器**: 43个
- **生成命令**: 5个
- **生成特征**: 2个
- **生成字典**: 81个
- **生成模块**: 28个
- **总计文件**: **603个NestJS文件**
- **成功率**: **100%**
### 📈 处理能力
- **处理PHP方法**: 1248个业务逻辑方法
- **转换规则**: 100+ 条PHP到TypeScript转换规则
- **支持层级**: admin/api/core三层架构
- **完成率**: 100%基于真实PHP代码
## 🎯 迁移结果
迁移完成后,您将获得:
- ✅ 完整的NestJS项目结构
- ✅ 所有PHP控制器转换为NestJS控制器
- ✅ 所有PHP服务转换为NestJS服务
- ✅ 实体、DTO、验证器完整映射
- ✅ 字典、任务、命令、监听器文件
- ✅ 正确的模块依赖关系
- ✅ 真实的业务逻辑非TODO骨架
## 📁 输出目录
```
wwjcloud-nest-v1/libs/wwjcloud-core/src/
├── {module1}/
│ ├── {module1}.module.ts
│ ├── controllers/
│ │ ├── adminapi/
│ │ └── api/
│ ├── services/
│ │ ├── admin/
│ │ ├── api/
│ │ └── core/
│ ├── entity/
│ ├── dto/
│ ├── dicts/
│ ├── jobs/
│ ├── commands/
│ └── listeners/
└── ...
```
## ⚠️ 注意事项
1. **备份重要文件**: 运行前请备份重要文件
2. **检查Java架构项目含PHP业务逻辑**: 确保PHP项目路径正确
3. **依赖安装**: 确保已安装所有NestJS依赖
4. **数据库连接**: 迁移后需要配置数据库连接
## 🔧 故障排除
### 常见问题
1. **路径错误**: 检查 `phpBasePath``nestjsBasePath` 配置
2. **权限问题**: 确保有文件读写权限
3. **依赖缺失**: 运行 `npm install` 安装依赖
### 重新开始
```bash
# 删除common层并重新迁移
node tools-v1/java-tools/clean-and-migrate.js
```
## 📈 下一步
迁移完成后,建议:
1. 检查生成的代码质量
2. 完善剩余的CRUD方法
3. 配置数据库连接
4. 运行测试确保功能正常
5. 启动NestJS服务验证
---
**提示**: 使用 `node tools-v1/java-tools/clean-and-migrate.js` 可以一键完成整个迁移流程!

View File

@@ -1,482 +0,0 @@
/**
* 上下文感知转换器
* 为AI自动生成打下基石
*/
class ContextAwareConverter {
constructor() {
this.contextPatterns = {
// 文件类型模式
fileTypes: {
service: {
patterns: [/Service\.php$/, /class\s+\w+Service/],
strategies: ['service_injection', 'repository_pattern', 'business_logic']
},
controller: {
patterns: [/Controller\.php$/, /class\s+\w+Controller/],
strategies: ['http_decorators', 'dto_validation', 'response_formatting']
},
entity: {
patterns: [/\.php$/, /class\s+\w+(?!Service|Controller)/],
strategies: ['typeorm_decorators', 'property_mapping', 'relationship_mapping']
},
dto: {
patterns: [/Dto\.php$/, /class\s+\w+Dto/],
strategies: ['validation_decorators', 'property_types', 'serialization']
}
},
// 业务领域模式
businessDomains: {
user: {
patterns: [/User/, /Auth/, /Login/],
strategies: ['jwt_auth', 'role_based_access', 'user_validation']
},
payment: {
patterns: [/Pay/, /Order/, /Transaction/],
strategies: ['payment_processing', 'order_management', 'transaction_logging']
},
content: {
patterns: [/Content/, /Article/, /Post/],
strategies: ['content_management', 'seo_optimization', 'media_handling']
},
system: {
patterns: [/System/, /Config/, /Setting/],
strategies: ['configuration_management', 'system_monitoring', 'admin_functions']
}
},
// 代码模式
codePatterns: {
crud: {
patterns: [/create/, /read/, /update/, /delete/],
strategies: ['repository_methods', 'validation_rules', 'error_handling']
},
api: {
patterns: [/get/, /post/, /put/, /delete/],
strategies: ['http_methods', 'route_decorators', 'request_validation']
},
validation: {
patterns: [/validate/, /check/, /verify/],
strategies: ['validation_pipes', 'custom_validators', 'error_messages']
},
cache: {
patterns: [/cache/, /redis/, /memcache/],
strategies: ['cache_decorators', 'cache_keys', 'expiration_handling']
}
}
};
this.conversionStrategies = {
service_injection: this.applyServiceInjection.bind(this),
repository_pattern: this.applyRepositoryPattern.bind(this),
business_logic: this.applyBusinessLogic.bind(this),
http_decorators: this.applyHttpDecorators.bind(this),
dto_validation: this.applyDtoValidation.bind(this),
response_formatting: this.applyResponseFormatting.bind(this),
typeorm_decorators: this.applyTypeOrmDecorators.bind(this),
property_mapping: this.applyPropertyMapping.bind(this),
relationship_mapping: this.applyRelationshipMapping.bind(this),
validation_decorators: this.applyValidationDecorators.bind(this),
property_types: this.applyPropertyTypes.bind(this),
serialization: this.applySerialization.bind(this),
jwt_auth: this.applyJwtAuth.bind(this),
role_based_access: this.applyRoleBasedAccess.bind(this),
user_validation: this.applyUserValidation.bind(this),
payment_processing: this.applyPaymentProcessing.bind(this),
order_management: this.applyOrderManagement.bind(this),
transaction_logging: this.applyTransactionLogging.bind(this),
content_management: this.applyContentManagement.bind(this),
seo_optimization: this.applySeoOptimization.bind(this),
media_handling: this.applyMediaHandling.bind(this),
configuration_management: this.applyConfigurationManagement.bind(this),
system_monitoring: this.applySystemMonitoring.bind(this),
admin_functions: this.applyAdminFunctions.bind(this),
repository_methods: this.applyRepositoryMethods.bind(this),
validation_rules: this.applyValidationRules.bind(this),
error_handling: this.applyErrorHandling.bind(this),
http_methods: this.applyHttpMethods.bind(this),
route_decorators: this.applyRouteDecorators.bind(this),
request_validation: this.applyRequestValidation.bind(this),
validation_pipes: this.applyValidationPipes.bind(this),
custom_validators: this.applyCustomValidators.bind(this),
error_messages: this.applyErrorMessages.bind(this),
cache_decorators: this.applyCacheDecorators.bind(this),
cache_keys: this.applyCacheKeys.bind(this),
expiration_handling: this.applyExpirationHandling.bind(this)
};
}
/**
* 分析代码上下文
*/
analyzeContext(filePath, className, content) {
const context = {
filePath,
className,
fileType: this.detectFileType(filePath, className, content),
businessDomain: this.detectBusinessDomain(content),
codePatterns: this.detectCodePatterns(content),
strategies: [],
imports: [],
decorators: [],
methods: [],
properties: []
};
// 根据检测到的模式选择转换策略
context.strategies = this.selectStrategies(context);
// 分析代码结构
this.analyzeCodeStructure(content, context);
return context;
}
/**
* 检测文件类型
*/
detectFileType(filePath, className, content) {
for (const [type, config] of Object.entries(this.contextPatterns.fileTypes)) {
for (const pattern of config.patterns) {
if (pattern.test(filePath) || pattern.test(className) || pattern.test(content)) {
return type;
}
}
}
return 'unknown';
}
/**
* 检测业务领域
*/
detectBusinessDomain(content) {
for (const [domain, config] of Object.entries(this.contextPatterns.businessDomains)) {
for (const pattern of config.patterns) {
if (pattern.test(content)) {
return domain;
}
}
}
return 'general';
}
/**
* 检测代码模式
*/
detectCodePatterns(content) {
const patterns = [];
for (const [pattern, config] of Object.entries(this.contextPatterns.codePatterns)) {
for (const regex of config.patterns) {
if (regex.test(content)) {
patterns.push(pattern);
break;
}
}
}
return patterns;
}
/**
* 选择转换策略
*/
selectStrategies(context) {
const strategies = new Set();
// 根据文件类型添加策略
if (context.fileType !== 'unknown') {
const fileTypeConfig = this.contextPatterns.fileTypes[context.fileType];
fileTypeConfig.strategies.forEach(strategy => strategies.add(strategy));
}
// 根据业务领域添加策略
if (context.businessDomain !== 'general') {
const domainConfig = this.contextPatterns.businessDomains[context.businessDomain];
domainConfig.strategies.forEach(strategy => strategies.add(strategy));
}
// 根据代码模式添加策略
context.codePatterns.forEach(pattern => {
const patternConfig = this.contextPatterns.codePatterns[pattern];
patternConfig.strategies.forEach(strategy => strategies.add(strategy));
});
return Array.from(strategies);
}
/**
* 分析代码结构
*/
analyzeCodeStructure(content, context) {
// 提取类名
const classMatch = content.match(/class\s+(\w+)/);
if (classMatch) {
context.className = classMatch[1];
}
// 提取方法
const methodMatches = content.match(/function\s+(\w+)\s*\([^)]*\)/g);
if (methodMatches) {
context.methods = methodMatches.map(match => {
const methodMatch = match.match(/function\s+(\w+)/);
return methodMatch ? methodMatch[1] : null;
}).filter(Boolean);
}
// 提取属性
const propertyMatches = content.match(/\$(\w+)/g);
if (propertyMatches) {
context.properties = [...new Set(propertyMatches.map(match => match.substring(1)))];
}
// 提取导入
const importMatches = content.match(/use\s+([^;]+);/g);
if (importMatches) {
context.imports = importMatches.map(match => {
const importMatch = match.match(/use\s+([^;]+);/);
return importMatch ? importMatch[1] : null;
}).filter(Boolean);
}
}
/**
* 应用上下文感知转换
*/
applyContextAwareConversion(code, context) {
let convertedCode = code;
console.log(`🎭 应用上下文感知转换: ${context.fileType} - ${context.businessDomain}`);
console.log(`📋 转换策略: ${context.strategies.join(', ')}`);
// 应用选定的转换策略
context.strategies.forEach(strategy => {
if (this.conversionStrategies[strategy]) {
convertedCode = this.conversionStrategies[strategy](convertedCode, context);
}
});
return convertedCode;
}
// 转换策略实现
applyServiceInjection(code, context) {
// 服务注入转换逻辑
return code.replace(/new\s+(\w+Service)\(\)/g, 'this.$1');
}
applyRepositoryPattern(code, context) {
// 仓储模式转换逻辑
return code.replace(/this->model/g, 'this.repository');
}
applyBusinessLogic(code, context) {
// 业务逻辑转换
return code;
}
applyHttpDecorators(code, context) {
// HTTP装饰器转换
return code;
}
applyDtoValidation(code, context) {
// DTO验证转换
return code;
}
applyResponseFormatting(code, context) {
// 响应格式化转换
return code.replace(/return\s+success\s*\(([^)]+)\)/g, 'return { success: true, data: $1 };');
}
applyTypeOrmDecorators(code, context) {
// TypeORM装饰器转换
return code;
}
applyPropertyMapping(code, context) {
// 属性映射转换
return code;
}
applyRelationshipMapping(code, context) {
// 关系映射转换
return code;
}
applyValidationDecorators(code, context) {
// 验证装饰器转换
return code;
}
applyPropertyTypes(code, context) {
// 属性类型转换
return code;
}
applySerialization(code, context) {
// 序列化转换
return code;
}
applyJwtAuth(code, context) {
// JWT认证转换
return code;
}
applyRoleBasedAccess(code, context) {
// 基于角色的访问控制转换
return code;
}
applyUserValidation(code, context) {
// 用户验证转换
return code;
}
applyPaymentProcessing(code, context) {
// 支付处理转换
return code;
}
applyOrderManagement(code, context) {
// 订单管理转换
return code;
}
applyTransactionLogging(code, context) {
// 事务日志转换
return code;
}
applyContentManagement(code, context) {
// 内容管理转换
return code;
}
applySeoOptimization(code, context) {
// SEO优化转换
return code;
}
applyMediaHandling(code, context) {
// 媒体处理转换
return code;
}
applyConfigurationManagement(code, context) {
// 配置管理转换
return code;
}
applySystemMonitoring(code, context) {
// 系统监控转换
return code;
}
applyAdminFunctions(code, context) {
// 管理功能转换
return code;
}
applyRepositoryMethods(code, context) {
// 仓储方法转换
return code;
}
applyValidationRules(code, context) {
// 验证规则转换
return code;
}
applyErrorHandling(code, context) {
// 错误处理转换
return code.replace(/throw\s+new\s+CommonException/g, 'throw new BusinessException');
}
applyHttpMethods(code, context) {
// HTTP方法转换
return code;
}
applyRouteDecorators(code, context) {
// 路由装饰器转换
return code;
}
applyRequestValidation(code, context) {
// 请求验证转换
return code;
}
applyValidationPipes(code, context) {
// 验证管道转换
return code;
}
applyCustomValidators(code, context) {
// 自定义验证器转换
return code;
}
applyErrorMessages(code, context) {
// 错误消息转换
return code;
}
applyCacheDecorators(code, context) {
// 缓存装饰器转换
return code;
}
applyCacheKeys(code, context) {
// 缓存键转换
return code;
}
applyExpirationHandling(code, context) {
// 过期处理转换
return code;
}
/**
* 生成上下文报告
*/
generateContextReport(context) {
return {
fileType: context.fileType,
businessDomain: context.businessDomain,
codePatterns: context.codePatterns,
strategies: context.strategies,
methods: context.methods,
properties: context.properties,
imports: context.imports,
complexity: this.calculateComplexity(context)
};
}
/**
* 计算代码复杂度
*/
calculateComplexity(context) {
let complexity = 0;
// 基于方法数量
complexity += context.methods.length * 2;
// 基于属性数量
complexity += context.properties.length;
// 基于策略数量
complexity += context.strategies.length * 3;
// 基于代码模式
complexity += context.codePatterns.length * 5;
return complexity;
}
}
module.exports = ContextAwareConverter;

View File

@@ -1,455 +0,0 @@
/**
* 多阶段转换管道
* 为AI自动生成打下基石
*/
const ConversionRulesDatabase = require('./conversion-rules-database');
class ConversionPipeline {
constructor() {
this.rulesDB = new ConversionRulesDatabase();
this.stages = [
'preprocessing', // 预处理
'syntax', // 语法转换
'semantic', // 语义转换
'context', // 上下文转换
'validation', // 验证
'postprocessing' // 后处理
];
this.stageHandlers = {
preprocessing: this.preprocess.bind(this),
syntax: this.convertSyntax.bind(this),
semantic: this.convertSemantic.bind(this),
context: this.convertContext.bind(this),
validation: this.validate.bind(this),
postprocessing: this.postprocess.bind(this)
};
}
/**
* 执行完整转换管道
*/
async convert(phpCode, context = {}) {
let convertedCode = phpCode;
const results = {
original: phpCode,
stages: {},
errors: [],
warnings: [],
metrics: {}
};
console.log('🚀 开始多阶段转换管道...');
for (const stage of this.stages) {
try {
console.log(`📋 执行阶段: ${stage}`);
const startTime = Date.now();
convertedCode = await this.stageHandlers[stage](convertedCode, context, results);
const endTime = Date.now();
results.stages[stage] = {
input: results.stages[stage - 1]?.output || phpCode,
output: convertedCode,
duration: endTime - startTime,
success: true
};
console.log(`✅ 阶段 ${stage} 完成 (${endTime - startTime}ms)`);
} catch (error) {
console.error(`❌ 阶段 ${stage} 失败:`, error.message);
results.errors.push({
stage,
error: error.message,
stack: error.stack
});
results.stages[stage] = {
success: false,
error: error.message
};
}
}
results.final = convertedCode;
results.metrics = this.calculateMetrics(results);
console.log('🎉 转换管道完成!');
return results;
}
/**
* 预处理阶段
*/
async preprocess(code, context, results) {
console.log(' 🔧 预处理: 清理和标准化代码...');
// 清理代码
let processed = code
// 移除多余的空白
.replace(/\s+/g, ' ')
.replace(/\n\s*\n/g, '\n')
// 标准化换行
.replace(/\r\n/g, '\n')
.replace(/\r/g, '\n')
// 移除注释中的特殊字符
.replace(/\/\*[\s\S]*?\*\//g, (match) => {
return match.replace(/[^\x20-\x7E\n]/g, '');
});
// 检测代码特征
const features = this.detectFeatures(processed);
context.features = features;
console.log(` 📊 检测到特征: ${Object.keys(features).join(', ')}`);
return processed;
}
/**
* 语法转换阶段
*/
async convertSyntax(code, context, results) {
console.log(' 🔄 语法转换: 基础PHP到TypeScript转换...');
// 应用基础语法转换规则
let converted = this.rulesDB.applyRules(code, 'syntax');
// 应用类型转换规则
converted = this.rulesDB.applyRules(converted, 'types');
// 应用方法转换规则
converted = this.rulesDB.applyRules(converted, 'methods');
// 应用数组和对象转换规则
converted = this.rulesDB.applyRules(converted, 'collections');
// 应用异常处理转换规则
converted = this.rulesDB.applyRules(converted, 'exceptions');
// 应用字符串处理规则
converted = this.rulesDB.applyRules(converted, 'strings');
console.log(` 📈 语法转换完成,代码长度: ${converted.length}`);
return converted;
}
/**
* 语义转换阶段
*/
async convertSemantic(code, context, results) {
console.log(' 🧠 语义转换: 业务逻辑语义转换...');
// 应用服务调用转换规则
let converted = this.rulesDB.applyRules(code, 'services');
// 智能识别和转换业务逻辑模式
converted = this.convertBusinessPatterns(converted, context);
// 转换控制流
converted = this.convertControlFlow(converted, context);
console.log(` 🎯 语义转换完成,业务模式识别: ${context.features?.businessPatterns?.length || 0}`);
return converted;
}
/**
* 上下文转换阶段
*/
async convertContext(code, context, results) {
console.log(' 🎭 上下文转换: 根据代码上下文优化转换...');
let converted = code;
// 根据文件类型应用不同的转换策略
if (context.fileType === 'service') {
converted = this.convertServiceContext(converted, context);
} else if (context.fileType === 'controller') {
converted = this.convertControllerContext(converted, context);
} else if (context.fileType === 'entity') {
converted = this.convertEntityContext(converted, context);
}
// 根据业务领域应用特定转换
if (context.businessDomain) {
converted = this.convertBusinessDomain(converted, context);
}
console.log(` 🏗️ 上下文转换完成,文件类型: ${context.fileType || 'unknown'}`);
return converted;
}
/**
* 验证阶段
*/
async validate(code, context, results) {
console.log(' ✅ 验证: 检查转换质量和语法正确性...');
const validation = {
syntax: this.validateSyntax(code),
types: this.validateTypes(code),
imports: this.validateImports(code),
business: this.validateBusinessLogic(code, context)
};
// 收集验证结果
const errors = [];
const warnings = [];
Object.entries(validation).forEach(([type, result]) => {
if (result.errors) {
errors.push(...result.errors.map(e => ({ type, ...e })));
}
if (result.warnings) {
warnings.push(...result.warnings.map(w => ({ type, ...w })));
}
});
results.errors.push(...errors);
results.warnings.push(...warnings);
console.log(` 📊 验证完成: ${errors.length}个错误, ${warnings.length}个警告`);
return code;
}
/**
* 后处理阶段
*/
async postprocess(code, context, results) {
console.log(' 🎨 后处理: 最终优化和格式化...');
// 应用语法错误修复规则
let processed = this.rulesDB.applyRules(code, 'syntaxFixes');
// 格式化代码
processed = this.formatCode(processed);
// 添加必要的导入语句
processed = this.addImports(processed, context);
console.log(` 🎉 后处理完成,最终代码长度: ${processed.length}`);
return processed;
}
/**
* 检测代码特征
*/
detectFeatures(code) {
const features = {
hasClasses: /class\s+\w+/.test(code),
hasFunctions: /function\s+\w+/.test(code),
hasArrays: /array\s*\(/.test(code),
hasObjects: /->\s*\w+/.test(code),
hasExceptions: /throw\s+new/.test(code),
hasServices: /new\s+[A-Z]\w+Service/.test(code),
hasControllers: /class\s+\w+Controller/.test(code),
hasEntities: /@Entity|@Table/.test(code),
businessPatterns: []
};
// 检测业务模式
const businessPatterns = [
{ pattern: /success\s*\(/, name: 'success_response' },
{ pattern: /error\s*\(/, name: 'error_response' },
{ pattern: /validate\s*\(/, name: 'validation' },
{ pattern: /cache\s*\(/, name: 'caching' },
{ pattern: /log\s*\(/, name: 'logging' }
];
businessPatterns.forEach(({ pattern, name }) => {
if (pattern.test(code)) {
features.businessPatterns.push(name);
}
});
return features;
}
/**
* 转换业务模式
*/
convertBusinessPatterns(code, context) {
let converted = code;
// 转换success响应
converted = converted.replace(/return\s+success\s*\(([^)]+)\)/g, (match, data) => {
return `return { success: true, data: ${data} };`;
});
// 转换error响应
converted = converted.replace(/return\s+error\s*\(([^)]+)\)/g, (match, message) => {
return `throw new BusinessException(${message});`;
});
return converted;
}
/**
* 转换控制流
*/
convertControlFlow(code, context) {
let converted = code;
// 转换PHP控制流到TypeScript
converted = converted.replace(/foreach\s*\(\s*([^)]+)\s+as\s+([^)]+)\s*\)/g, 'for (const $2 of $1)');
converted = converted.replace(/foreach\s*\(\s*([^)]+)\s+as\s+([^)]+)\s*=>\s*([^)]+)\s*\)/g, 'for (const [$3, $2] of Object.entries($1))');
return converted;
}
/**
* 服务上下文转换
*/
convertServiceContext(code, context) {
// 服务特定的转换逻辑
return code;
}
/**
* 控制器上下文转换
*/
convertControllerContext(code, context) {
// 控制器特定的转换逻辑
return code;
}
/**
* 实体上下文转换
*/
convertEntityContext(code, context) {
// 实体特定的转换逻辑
return code;
}
/**
* 业务领域转换
*/
convertBusinessDomain(code, context) {
// 根据业务领域应用特定转换
return code;
}
/**
* 验证语法
*/
validateSyntax(code) {
const errors = [];
const warnings = [];
// 检查基本语法错误
if (code.includes(']]')) {
errors.push({ message: '发现方括号错误', line: this.findLineNumber(code, ']]') });
}
if (code.includes('BusinessBusinessException')) {
errors.push({ message: '发现重复的Business前缀', line: this.findLineNumber(code, 'BusinessBusinessException') });
}
return { errors, warnings };
}
/**
* 验证类型
*/
validateTypes(code) {
const errors = [];
const warnings = [];
// 类型验证逻辑
return { errors, warnings };
}
/**
* 验证导入
*/
validateImports(code) {
const errors = [];
const warnings = [];
// 导入验证逻辑
return { errors, warnings };
}
/**
* 验证业务逻辑
*/
validateBusinessLogic(code, context) {
const errors = [];
const warnings = [];
// 业务逻辑验证
return { errors, warnings };
}
/**
* 格式化代码
*/
formatCode(code) {
// 简单的代码格式化
return code
.replace(/\s+/g, ' ')
.replace(/\n\s*\n/g, '\n')
.trim();
}
/**
* 添加导入语句
*/
addImports(code, context) {
// 根据代码内容添加必要的导入
let imports = [];
if (code.includes('BadRequestException')) {
imports.push("import { BadRequestException } from '@nestjs/common';");
}
if (code.includes('@Injectable')) {
imports.push("import { Injectable } from '@nestjs/common';");
}
if (imports.length > 0) {
return imports.join('\n') + '\n\n' + code;
}
return code;
}
/**
* 计算指标
*/
calculateMetrics(results) {
const originalLength = results.original.length;
const finalLength = results.final.length;
return {
originalLength,
finalLength,
compressionRatio: (originalLength - finalLength) / originalLength,
errorCount: results.errors.length,
warningCount: results.warnings.length,
stageCount: Object.keys(results.stages).length,
totalDuration: Object.values(results.stages).reduce((sum, stage) => sum + (stage.duration || 0), 0)
};
}
/**
* 查找行号
*/
findLineNumber(code, searchText) {
const lines = code.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].includes(searchText)) {
return i + 1;
}
}
return -1;
}
}
module.exports = ConversionPipeline;

View File

@@ -1,207 +0,0 @@
/**
* PHP到TypeScript转换规则数据库
* 为AI自动生成打下基石
*/
class ConversionRulesDatabase {
constructor() {
this.rules = {
// 基础语法转换
syntax: {
variables: [
{ pattern: /\$this->([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: 'this.$1', description: 'PHP对象属性访问' },
{ pattern: /\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1', description: 'PHP变量声明' },
{ pattern: /self::\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: 'self.$1', description: 'PHP静态变量访问' },
{ pattern: /static::\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: 'static.$1', description: 'PHP静态变量访问' }
],
operators: [
{ pattern: /\?\?/g, replacement: '||', description: 'PHP空值合并操作符' },
{ pattern: /->/g, replacement: '.', description: 'PHP对象访问操作符' },
{ pattern: /::/g, replacement: '.', description: 'PHP静态访问操作符' },
{ pattern: /===/g, replacement: '===', description: '严格相等比较' },
{ pattern: /====/g, replacement: '===', description: '修复重复等号' }
],
functions: [
{ pattern: /empty\s*\(\s*([^)]+)\s*\)/g, replacement: '!$1', description: 'PHP empty函数' },
{ pattern: /isset\s*\(\s*([^)]+)\s*\)/g, replacement: '$1 !== undefined', description: 'PHP isset函数' },
{ pattern: /is_null\s*\(\s*([^)]+)\s*\)/g, replacement: '$1 === null', description: 'PHP is_null函数' },
{ pattern: /is_array\s*\(\s*([^)]+)\s*\)/g, replacement: 'Array.isArray($1)', description: 'PHP is_array函数' },
{ pattern: /is_string\s*\(\s*([^)]+)\s*\)/g, replacement: 'typeof $1 === "string"', description: 'PHP is_string函数' },
{ pattern: /is_numeric\s*\(\s*([^)]+)\s*\)/g, replacement: '!isNaN($1)', description: 'PHP is_numeric函数' },
{ pattern: /env\(([^)]+)\)/g, replacement: 'process.env.$1', description: 'PHP env函数' }
]
},
// 类型转换
types: {
parameters: [
{ pattern: /string\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: string', description: 'PHP字符串参数' },
{ pattern: /int\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: number', description: 'PHP整数参数' },
{ pattern: /array\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: any[]', description: 'PHP数组参数' },
{ pattern: /bool\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: boolean', description: 'PHP布尔参数' }
],
declarations: [
{ pattern: /array\s+/g, replacement: '', description: 'PHP数组类型声明' },
{ pattern: /:\s*array/g, replacement: ': any[]', description: 'PHP数组返回类型' }
]
},
// 方法转换
methods: {
declarations: [
{ pattern: /public\s+function\s+/g, replacement: 'async ', description: 'PHP公共方法' },
{ pattern: /private\s+function\s+/g, replacement: 'private async ', description: 'PHP私有方法' },
{ pattern: /protected\s+function\s+/g, replacement: 'protected async ', description: 'PHP受保护方法' }
],
constructors: [
{ pattern: /parent::__construct\(\)/g, replacement: 'super()', description: 'PHP父类构造函数调用' },
{ pattern: /new\s+static\s*\(([^)]*)\)/g, replacement: 'new this.constructor($1)', description: 'PHP静态实例化' }
]
},
// 数组和对象转换
collections: {
arrays: [
{ pattern: /array\(\)/g, replacement: '[]', description: 'PHP空数组' },
{ pattern: /array\(([^)]+)\)/g, replacement: '[$1]', description: 'PHP数组语法' },
{ pattern: /'([a-zA-Z_][a-zA-Z0-9_]*)'\s*=>/g, replacement: '$1:', description: 'PHP关联数组键' },
{ pattern: /"([a-zA-Z_][a-zA-Z0-9_]*)"\s*=>/g, replacement: '$1:', description: 'PHP关联数组键(双引号)' }
],
objects: [
{ pattern: /\[\s*\]/g, replacement: '[]', description: '空数组语法' },
{ pattern: /\(\s*\)/g, replacement: '()', description: '空括号语法' }
]
},
// 异常处理转换
exceptions: [
{ pattern: /CommonException/g, replacement: 'BusinessException', description: 'PHP通用异常' },
{ pattern: /(?<!Business)Exception/g, replacement: 'BusinessException', description: 'PHP异常类' },
{ pattern: /BusinessBusinessException/g, replacement: 'BusinessException', description: '修复重复Business前缀' }
],
// 服务调用转换
services: {
instantiation: [
{ pattern: /new\s+([A-Z][a-zA-Z0-9_]*)\(\)/g, replacement: 'this.$1Service', description: 'PHP服务实例化' },
{ pattern: /\(new\s+([A-Z][a-zA-Z0-9_]*)\(\)\)/g, replacement: 'this.$1Service', description: 'PHP服务实例化(括号)' }
],
calls: [
{ pattern: /\(([^)]+)\)\s*->\s*(\w+)\(/g, replacement: '($1).$2(', description: 'PHP服务方法调用' },
{ pattern: /(\w+_service)\s*\.\s*(\w+)\(/g, replacement: '$1.$2(', description: 'PHP服务变量调用' }
]
},
// 字符串处理
strings: [
{ pattern: /\.\s*=/g, replacement: '+=', description: 'PHP字符串连接赋值' },
{ pattern: /\.(\s*['""])/g, replacement: ' + $1', description: 'PHP字符串连接' },
{ pattern: /process\.env\.'([^']+)'/g, replacement: 'process.env.$1', description: '修复process.env引号' }
],
// 语法错误修复
syntaxFixes: {
brackets: [
{ pattern: /\(([^)]+)\]/g, replacement: '($1)', description: '修复函数调用中的方括号' },
{ pattern: /(\w+)\]/g, replacement: '$1)', description: '修复变量后的方括号' },
{ pattern: /\]\s*;/g, replacement: ');', description: '修复方括号后分号' },
{ pattern: /\]\s*\)/g, replacement: '))', description: '修复方括号后括号' },
{ pattern: /\]\s*\{/g, replacement: ') {', description: '修复方括号后大括号' },
{ pattern: /\]\s*,/g, replacement: '),', description: '修复方括号后逗号' }
],
specific: [
{ pattern: /(\w+_id)\]/g, replacement: '$1)', description: '修复ID变量方括号' },
{ pattern: /(\w+_key)\]/g, replacement: '$1)', description: '修复KEY变量方括号' },
{ pattern: /(\w+_type)\]/g, replacement: '$1)', description: '修复TYPE变量方括号' },
{ pattern: /(\w+_name)\]/g, replacement: '$1)', description: '修复NAME变量方括号' },
{ pattern: /(\w+_code)\]/g, replacement: '$1)', description: '修复CODE变量方括号' },
{ pattern: /(\w+_value)\]/g, replacement: '$1)', description: '修复VALUE变量方括号' }
],
functions: [
{ pattern: /(\w+)\(([^)]+)\]/g, replacement: '$1($2)', description: '修复函数调用方括号' },
{ pattern: /(\w+)\.(\w+)\(([^)]+)\]/g, replacement: '$1.$2($3)', description: '修复方法调用方括号' }
]
}
};
}
/**
* 获取转换规则
*/
getRules(category = null) {
if (category) {
return this.rules[category] || {};
}
return this.rules;
}
/**
* 添加新规则
*/
addRule(category, rule) {
if (!this.rules[category]) {
this.rules[category] = [];
}
this.rules[category].push(rule);
}
/**
* 应用转换规则
*/
applyRules(code, category = null) {
let convertedCode = code;
const rulesToApply = category ? this.getRules(category) : this.rules;
// 递归应用所有规则
const applyCategoryRules = (rules) => {
if (Array.isArray(rules)) {
rules.forEach(rule => {
convertedCode = convertedCode.replace(rule.pattern, rule.replacement);
});
} else if (typeof rules === 'object') {
Object.values(rules).forEach(categoryRules => {
applyCategoryRules(categoryRules);
});
}
};
applyCategoryRules(rulesToApply);
return convertedCode;
}
/**
* 获取规则统计信息
*/
getStats() {
const stats = {
total: 0,
byCategory: {}
};
const countRules = (rules, category = '') => {
if (Array.isArray(rules)) {
stats.total += rules.length;
if (category) {
stats.byCategory[category] = rules.length;
}
} else if (typeof rules === 'object') {
Object.entries(rules).forEach(([key, value]) => {
countRules(value, key);
});
}
};
countRules(this.rules);
return stats;
}
}
module.exports = ConversionRulesDatabase;

View File

@@ -1,477 +0,0 @@
/**
* 增强版业务逻辑转换器
* 集成转换规则数据库、多阶段转换管道、上下文感知转换和质量保证系统
* 为AI自动生成打下基石
*/
const ConversionRulesDatabase = require('./conversion-rules-database');
const ConversionPipeline = require('./conversion-pipeline');
const ContextAwareConverter = require('./context-aware-converter');
const QualityAssurance = require('./quality-assurance');
class EnhancedBusinessLogicConverter {
constructor() {
this.rulesDB = new ConversionRulesDatabase();
this.pipeline = new ConversionPipeline();
this.contextConverter = new ContextAwareConverter();
this.qualityAssurance = new QualityAssurance();
this.stats = {
totalConversions: 0,
successfulConversions: 0,
failedConversions: 0,
averageQuality: 0,
conversionTime: 0
};
}
/**
* 执行增强版转换
*/
async convert(phpCode, filePath, className) {
const startTime = Date.now();
this.stats.totalConversions++;
try {
console.log('🚀 开始增强版业务逻辑转换...');
console.log(`📁 文件: ${filePath}`);
console.log(`🏷️ 类名: ${className}`);
// 1. 分析上下文
const context = this.contextConverter.analyzeContext(filePath, className, phpCode);
console.log(`🎭 上下文分析完成: ${context.fileType} - ${context.businessDomain}`);
// 2. 执行多阶段转换管道
const pipelineResults = await this.pipeline.convert(phpCode, context);
console.log(`🔄 转换管道完成: ${pipelineResults.metrics.totalDuration}ms`);
// 3. 应用上下文感知转换
const contextAwareCode = this.contextConverter.applyContextAwareConversion(
pipelineResults.final,
context
);
console.log(`🧠 上下文感知转换完成`);
// 4. 执行质量检查
const qualityResults = await this.qualityAssurance.performQualityCheck(
contextAwareCode,
context
);
console.log(`🛡️ 质量检查完成: ${qualityResults.overall.toUpperCase()}`);
// 5. 自动修复问题
let finalCode = contextAwareCode;
if (qualityResults.overall === 'fail' || qualityResults.warnings.length > 0) {
const fixResults = await this.qualityAssurance.autoFix(contextAwareCode, qualityResults);
finalCode = fixResults.code;
console.log(`🔧 自动修复完成: ${fixResults.summary.totalFixes}个修复`);
}
// 6. 最终质量验证
const finalQuality = await this.qualityAssurance.performQualityCheck(finalCode, context);
// 7. 更新统计信息
const endTime = Date.now();
this.updateStats(endTime - startTime, finalQuality);
// 8. 生成转换报告
const report = this.generateConversionReport({
original: phpCode,
final: finalCode,
context,
pipelineResults,
qualityResults: finalQuality,
duration: endTime - startTime
});
console.log('🎉 增强版转换完成!');
return {
success: true,
code: finalCode,
report,
context,
quality: finalQuality
};
} catch (error) {
console.error('❌ 增强版转换失败:', error.message);
this.stats.failedConversions++;
return {
success: false,
error: error.message,
stack: error.stack,
original: phpCode
};
}
}
/**
* 批量转换
*/
async batchConvert(conversions) {
const results = [];
const startTime = Date.now();
console.log(`🔄 开始批量转换: ${conversions.length}个文件`);
for (let i = 0; i < conversions.length; i++) {
const { phpCode, filePath, className } = conversions[i];
console.log(`📋 转换进度: ${i + 1}/${conversions.length}`);
try {
const result = await this.convert(phpCode, filePath, className);
results.push(result);
if (result.success) {
console.log(`✅ 转换成功: ${className}`);
} else {
console.log(`❌ 转换失败: ${className} - ${result.error}`);
}
} catch (error) {
console.error(`❌ 转换异常: ${className} - ${error.message}`);
results.push({
success: false,
error: error.message,
filePath,
className
});
}
}
const endTime = Date.now();
const batchReport = this.generateBatchReport(results, endTime - startTime);
console.log(`🎯 批量转换完成: ${results.filter(r => r.success).length}/${results.length}成功`);
return {
results,
report: batchReport,
stats: this.stats
};
}
/**
* 学习模式 - 从成功案例中学习
*/
async learnFromSuccess(conversions) {
console.log('🧠 开始学习模式...');
const successfulConversions = conversions.filter(c => c.success);
const learningData = [];
for (const conversion of successfulConversions) {
const { original, final, context, quality } = conversion;
// 提取转换模式
const patterns = this.extractConversionPatterns(original, final);
// 分析质量指标
const qualityMetrics = this.analyzeQualityMetrics(quality);
learningData.push({
context,
patterns,
quality: qualityMetrics,
original,
final
});
}
// 更新转换规则数据库
this.updateRulesFromLearning(learningData);
console.log(`📚 学习完成: ${learningData.length}个成功案例`);
return {
learningData,
updatedRules: this.rulesDB.getStats()
};
}
/**
* 获取转换统计信息
*/
getStats() {
return {
...this.stats,
successRate: this.stats.totalConversions > 0
? (this.stats.successfulConversions / this.stats.totalConversions * 100).toFixed(2) + '%'
: '0%',
averageQuality: this.stats.averageQuality.toFixed(2),
averageTime: this.stats.conversionTime.toFixed(2) + 'ms'
};
}
/**
* 更新统计信息
*/
updateStats(duration, quality) {
if (quality.overall === 'pass') {
this.stats.successfulConversions++;
} else {
this.stats.failedConversions++;
}
// 计算平均质量分数
const qualityScore = this.calculateQualityScore(quality);
this.stats.averageQuality = (this.stats.averageQuality + qualityScore) / 2;
// 计算平均转换时间
this.stats.conversionTime = (this.stats.conversionTime + duration) / 2;
}
/**
* 计算质量分数
*/
calculateQualityScore(quality) {
let score = 100;
// 根据错误数量扣分
score -= quality.errors.length * 10;
// 根据警告数量扣分
score -= quality.warnings.length * 2;
// 根据复杂度扣分
if (quality.metrics.complexity?.cyclomatic > 10) {
score -= (quality.metrics.complexity.cyclomatic - 10) * 2;
}
return Math.max(0, score);
}
/**
* 生成转换报告
*/
generateConversionReport(data) {
return {
summary: {
success: true,
duration: data.duration,
quality: data.qualityResults.overall,
complexity: data.qualityResults.metrics.complexity,
maintainability: data.qualityResults.metrics.maintainability
},
context: {
fileType: data.context.fileType,
businessDomain: data.context.businessDomain,
strategies: data.context.strategies,
patterns: data.context.codePatterns
},
quality: {
errors: data.qualityResults.errors.length,
warnings: data.qualityResults.warnings.length,
recommendations: data.qualityResults.recommendations.length
},
pipeline: {
stages: Object.keys(data.pipelineResults.stages).length,
totalDuration: data.pipelineResults.metrics.totalDuration
}
};
}
/**
* 生成批量转换报告
*/
generateBatchReport(results, totalDuration) {
const successful = results.filter(r => r.success);
const failed = results.filter(r => !r.success);
return {
summary: {
total: results.length,
successful: successful.length,
failed: failed.length,
successRate: (successful.length / results.length * 100).toFixed(2) + '%',
totalDuration
},
quality: {
averageErrors: successful.reduce((sum, r) => sum + (r.quality?.errors?.length || 0), 0) / successful.length,
averageWarnings: successful.reduce((sum, r) => sum + (r.quality?.warnings?.length || 0), 0) / successful.length
},
errors: failed.map(f => ({
file: f.filePath,
class: f.className,
error: f.error
}))
};
}
/**
* 提取转换模式
*/
extractConversionPatterns(original, final) {
const patterns = [];
// 提取变量转换模式
const variablePatterns = this.extractVariablePatterns(original, final);
patterns.push(...variablePatterns);
// 提取方法转换模式
const methodPatterns = this.extractMethodPatterns(original, final);
patterns.push(...methodPatterns);
// 提取类型转换模式
const typePatterns = this.extractTypePatterns(original, final);
patterns.push(...typePatterns);
return patterns;
}
/**
* 提取变量转换模式
*/
extractVariablePatterns(original, final) {
const patterns = [];
// 提取$this->variable模式
const thisMatches = original.match(/\$this->(\w+)/g);
if (thisMatches) {
thisMatches.forEach(match => {
const variableMatch = match.match(/\$this->(\w+)/);
if (variableMatch) {
const variable = variableMatch[1];
if (final.includes(`this.${variable}`)) {
patterns.push({
type: 'variable',
pattern: `$this->${variable}`,
replacement: `this.${variable}`,
confidence: 1.0
});
}
}
});
}
return patterns;
}
/**
* 提取方法转换模式
*/
extractMethodPatterns(original, final) {
const patterns = [];
// 提取方法调用模式
const methodMatches = original.match(/\$this->(\w+)\(/g);
if (methodMatches) {
methodMatches.forEach(match => {
const method = match.match(/\$this->(\w+)\(/)[1];
if (final.includes(`this.${method}(`)) {
patterns.push({
type: 'method',
pattern: `$this->${method}(`,
replacement: `this.${method}(`,
confidence: 1.0
});
}
});
}
return patterns;
}
/**
* 提取类型转换模式
*/
extractTypePatterns(original, final) {
const patterns = [];
// 提取类型声明模式
const typeMatches = original.match(/(string|int|array|bool)\s+\$(\w+)/g);
if (typeMatches) {
typeMatches.forEach(match => {
const typeMatch = match.match(/(string|int|array|bool)\s+\$(\w+)/);
const type = typeMatch[1];
const variable = typeMatch[2];
let tsType = type;
if (type === 'int') tsType = 'number';
if (type === 'array') tsType = 'any[]';
if (type === 'bool') tsType = 'boolean';
if (final.includes(`${variable}: ${tsType}`)) {
patterns.push({
type: 'type',
pattern: `${type} $${variable}`,
replacement: `${variable}: ${tsType}`,
confidence: 1.0
});
}
});
}
return patterns;
}
/**
* 分析质量指标
*/
analyzeQualityMetrics(quality) {
return {
overall: quality.overall,
errorCount: quality.errors.length,
warningCount: quality.warnings.length,
complexity: quality.metrics.complexity,
maintainability: quality.metrics.maintainability,
testability: quality.metrics.testability,
performance: quality.metrics.performance
};
}
/**
* 从学习数据更新规则
*/
updateRulesFromLearning(learningData) {
// 分析学习数据,提取新的转换规则
const newRules = this.analyzeLearningData(learningData);
// 更新转换规则数据库
newRules.forEach(rule => {
this.rulesDB.addRule(rule.category, rule);
});
console.log(`📚 更新了${newRules.length}个转换规则`);
}
/**
* 分析学习数据
*/
analyzeLearningData(learningData) {
const newRules = [];
// 分析转换模式
learningData.forEach(data => {
data.patterns.forEach(pattern => {
// 检查是否是新模式
if (this.isNewPattern(pattern)) {
newRules.push({
category: pattern.type,
pattern: new RegExp(pattern.pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'),
replacement: pattern.replacement,
description: `从学习数据中提取的${pattern.type}转换规则`,
confidence: pattern.confidence
});
}
});
});
return newRules;
}
/**
* 检查是否是新模式
*/
isNewPattern(pattern) {
// 检查规则数据库中是否已存在类似规则
const existingRules = this.rulesDB.getRules(pattern.type);
return !existingRules.some(rule =>
rule.pattern.toString() === pattern.pattern &&
rule.replacement === pattern.replacement
);
}
}
module.exports = EnhancedBusinessLogicConverter;

View File

@@ -1,184 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
/**
* 基础生成器类
* 提供通用的 dry-run、文件操作、日志等功能
*/
class BaseGenerator {
constructor(generatorName = 'Generator') {
this.generatorName = generatorName;
// 从环境变量或参数读取配置
this.dryRun = process.env.DRY_RUN === 'true' || process.argv.includes('--dry-run');
this.verbose = process.env.VERBOSE === 'true' || process.argv.includes('--verbose');
this.stats = {
filesCreated: 0,
filesUpdated: 0,
filesSkipped: 0,
errors: 0
};
}
/**
* 安全写入文件(支持 dry-run
*/
writeFile(filePath, content, description = '') {
try {
if (this.dryRun) {
console.log(` [DRY-RUN] Would create/update: ${filePath}`);
if (this.verbose && description) {
console.log(` Description: ${description}`);
}
this.stats.filesCreated++;
return true;
}
// 确保目录存在
this.ensureDir(path.dirname(filePath));
// 写入文件
fs.writeFileSync(filePath, content, 'utf8');
const action = fs.existsSync(filePath) ? 'Updated' : 'Created';
console.log(`${action}: ${filePath}`);
if (action === 'Created') {
this.stats.filesCreated++;
} else {
this.stats.filesUpdated++;
}
return true;
} catch (error) {
console.error(` ❌ Failed to write ${filePath}:`, error.message);
this.stats.errors++;
return false;
}
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (this.dryRun) {
return;
}
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 读取文件(安全)
*/
readFile(filePath) {
try {
if (!fs.existsSync(filePath)) {
return null;
}
return fs.readFileSync(filePath, 'utf8');
} catch (error) {
console.error(` ❌ Failed to read ${filePath}:`, error.message);
return null;
}
}
/**
* 检查文件是否存在
*/
fileExists(filePath) {
return fs.existsSync(filePath);
}
/**
* 日志输出
*/
log(message, level = 'info') {
const prefix = {
'info': ' ',
'success': ' ✅',
'warning': ' ⚠️ ',
'error': ' ❌',
'debug': ' 🔍'
};
if (level === 'debug' && !this.verbose) {
return;
}
console.log(`${prefix[level] || ' '}${message}`);
}
/**
* 输出统计信息
*/
printStats(additionalStats = {}) {
console.log('\n📊 Generation Statistics');
console.log('==================================================');
if (this.dryRun) {
console.log(' 🔍 DRY-RUN MODE - No files were actually modified');
}
console.log(` 📁 Files Created: ${this.stats.filesCreated}`);
console.log(` 🔄 Files Updated: ${this.stats.filesUpdated}`);
console.log(` ⏭️ Files Skipped: ${this.stats.filesSkipped}`);
console.log(` ❌ Errors: ${this.stats.errors}`);
// 输出额外的统计信息
for (const [key, value] of Object.entries(additionalStats)) {
console.log(` 📈 ${key}: ${value}`);
}
const total = this.stats.filesCreated + this.stats.filesUpdated;
const successRate = total > 0
? ((total / (total + this.stats.errors)) * 100).toFixed(2)
: '0.00';
console.log(` 📊 Success Rate: ${successRate}%`);
console.log('==================================================');
}
/**
* kebab-case 转换
*/
toKebabCase(str) {
return String(str)
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/_/g, '-')
.toLowerCase();
}
/**
* PascalCase 转换
*/
toPascalCase(str) {
return String(str)
.split(/[-_]/)
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join('');
}
/**
* camelCase 转换
*/
toCamelCase(str) {
const pascal = this.toPascalCase(str);
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
}
/**
* snake_case 转换
*/
toSnakeCase(str) {
return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
}
}
module.exports = BaseGenerator;

View File

@@ -1,809 +0,0 @@
const fs = require('fs');
const path = require('path');
/**
* 业务逻辑转换器
* 基于真实PHP代码的转换规则禁止TODO、假设、自创
*/
class BusinessLogicConverter {
constructor() {
// 混合模块智能分类规则
this.hybridClassificationRules = {
// 需要抽取到Core层的业务逻辑文件
coreBusinessLogic: [
// 支付相关
/pay/i,
/payment/i,
/transfer/i,
/refund/i,
// 会员相关
/member/i,
/user.*profile/i,
/account/i,
// 业务配置
/config.*pay/i,
/config.*member/i,
/config.*order/i,
// 订单相关
/order/i,
/goods/i,
/product/i,
// 认证业务逻辑
/login.*business/i,
/auth.*business/i,
/register/i,
// DIY业务
/diy/i,
/custom/i,
// 营销业务
/promotion/i,
/coupon/i,
/discount/i
],
// 应该使用Common基础服务的文件
useCommonInfrastructure: [
// 基础服务接口
/BaseController/,
/BaseService/,
/BaseModel/,
// 通用工具
/upload/i,
/export/i,
/attachment/i,
/sys.*config/i,
/system.*info/i,
/cache/i,
/redis/i,
// 基础认证
/jwt/i,
/token/i,
/guard/i,
/middleware/i
]
};
this.phpRegexPatterns = [
// PHP类型转换
{ pattern: /\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1' },
{ pattern: /\->/g, replacement: '.' },
{ pattern: /public function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/g, replacement: 'async $1($2)' },
{ pattern: /private function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/g, replacement: 'private async $1($2)' },
{ pattern: /protected function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/g, replacement: 'protected async $1($2)' },
// PHP参数类型转换
{ pattern: /string\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: string' },
{ pattern: /int\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: number' },
{ pattern: /array\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: any[]' },
{ pattern: /bool\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: boolean' },
// PHP语法转换
{ pattern: /this\s*\->\s*model/g, replacement: 'this.model' },
{ pattern: /new\s+([A-Z][a-zA-Z0-9_]*)\(\)/g, replacement: 'this.$1Repository' },
{ pattern: /parent::__construct\(\)/g, replacement: 'super()' },
// PHP函数转换
{ pattern: /empty\s*\(\s*([^)]+)\s*\)/g, replacement: '!$1' },
{ pattern: /isset\s*\(\s*([^)]+)\s*\)/g, replacement: '$1 !== undefined' },
{ pattern: /is_null\s*\(\s*([^)]+)\s*\)/g, replacement: '$1 === null' },
{ pattern: /is_array\s*\(\s*([^)]+)\s*\)/g, replacement: 'Array.isArray($1)' },
{ pattern: /is_string\s*\(\s*([^)]+)\s*\)/g, replacement: 'typeof $1 === "string"' },
{ pattern: /is_numeric\s*\(\s*([^)]+)\s*\)/g, replacement: '!isNaN($1)' },
// 字符串拼接
{ pattern: /\.\s*=/g, replacement: '+=' },
{ pattern: /\.(\s*['""])/g, replacement: ' + $1' },
// 数组语法
{ pattern: /array\(\)/g, replacement: '[]' },
{ pattern: /array\(([^)]+)\)/g, replacement: '[$1]' },
];
}
/**
* 智能分类判断文件应该迁移到Core层还是使用Common基础设施
*/
classifyFile(filePath, className, content) {
const fileName = path.basename(filePath, '.php');
const fullContext = `${fileName} ${className} ${content}`.toLowerCase();
// 检查是否应该使用Common基础设施
for (const pattern of this.hybridClassificationRules.useCommonInfrastructure) {
if (pattern.test(fileName) || pattern.test(className) || pattern.test(content)) {
return 'INFRASTRUCTURE';
}
}
// 检查是否应该迁移到Core层
for (const pattern of this.hybridClassificationRules.coreBusinessLogic) {
if (pattern.test(fileName) || pattern.test(className) || pattern.test(content)) {
return 'CORE_BUSINESS';
}
}
// 默认根据模块名判断
const moduleName = this.extractModuleName(filePath);
if (['sys', 'upload', 'config', 'export'].includes(moduleName)) {
return 'INFRASTRUCTURE'; // 基础服务
}
return 'CORE_BUSINESS'; // 默认为业务逻辑
}
/**
* 从文件路径提取模块名
*/
extractModuleName(filePath) {
const match = filePath.match(/\/([^\/]+)\/.+\.php$/);
return match ? match[1] : 'unknown';
}
/**
* 替换PHP基础设施调用为NestJS基础设施调用
*/
replaceInfrastructureCalls(tsCode) {
let convertedCode = tsCode;
// 替换PHP基础类为NestJS Common层
const infrastructureReplacements = [
// 按 v1 boot 实现进行映射
{ from: /core\\cache\\RedisCacheService/g, to: '@wwjCommon/cache/cache.service' },
{ from: /CoreRequestService/g, to: '@wwjCommon/http/request-context.service' },
// 旧的 BaseService/BaseController/BaseApiService 在 v1 中不再使用,避免误替换
// 日志统一使用 Nest Logger 或拦截器,不再映射到自定义 LoggingService
];
infrastructureReplacements.forEach(({ from, to }) => {
convertedCode = convertedCode.replace(from, to);
});
return convertedCode;
}
/**
* 转换PHP业务逻辑到TypeScript
*/
convertBusinessLogic(content, methodName, phpCode) {
try {
console.log(`🔄 转换方法: ${methodName}`);
let convertedCode = phpCode;
// 1. 先转换PHP语法到TypeScript
convertedCode = convertedCode
// 变量转换 - 移除$符号 (必须在->转换之前)
.replace(/\$this->([a-zA-Z_][a-zA-Z0-9_]*)/g, 'this.$1')
.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1')
// PHP数组语法 => 转换为对象属性 :
.replace(/'([a-zA-Z_][a-zA-Z0-9_]*)'\s*=>/g, '$1:')
.replace(/"([a-zA-Z_][a-zA-Z0-9_]*)"\s*=>/g, '$1:')
// PHP空值合并 ?? 转换为 ||
.replace(/\?\?/g, '||')
// PHP对象访问 -> 转换为 . (必须在$转换之后)
.replace(/->/g, '.')
// PHP静态访问 :: 转换为 .
.replace(/::/g, '.')
// PHP new对象转换 - 修复转换逻辑避免重复Service后缀
.replace(/\(new\s+([A-Z][a-zA-Z0-9_]*)\(\)\)/g, (match, serviceName) => {
if (serviceName.endsWith('Service')) {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}`;
} else {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}Service`;
}
})
.replace(/new\s+([A-Z][a-zA-Z0-9_]*)\(\)/g, (match, serviceName) => {
if (serviceName.endsWith('Service')) {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}`;
} else {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}Service`;
}
})
// PHP类型声明转换为TypeScript
.replace(/array\s+/g, '')
.replace(/:\s*array/g, ': any[]')
// 变量声明添加const/let
.replace(/^(\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*=/gm, '$1const $2 =')
// 修复数组访问
.replace(/\['([^']+)'\]/g, '.$1')
.replace(/\["([^"]+)"\]/g, '.$1')
// 修复PHP函数调用
.replace(/array_merge\s*\(/g, 'Object.assign(')
.replace(/strpos\s*\(/g, 'String.prototype.indexOf.call(')
.replace(/throw\s+new\s+([A-Z][a-zA-Z0-9_]*)\s*\(/g, 'throw new $1(')
// 修复PHP条件语句
.replace(/if\s*\(\s*([^)]+)\s*\)\s*\{/g, 'if ($1) {')
.replace(/else\s*\{/g, '} else {')
// 修复PHP静态变量访问
.replace(/self::\$([a-zA-Z_][a-zA-Z0-9_]*)/g, 'self.$1')
.replace(/static::\$([a-zA-Z_][a-zA-Z0-9_]*)/g, 'static.$1')
// 修复PHP is_null函数
.replace(/is_null\s*\(\s*([^)]+)\s*\)/g, '$1 === null')
// 修复PHP new static调用
.replace(/new\s+static\s*\(([^)]*)\)/g, 'new this.constructor($1)')
// 修复PHP数组语法错误
.replace(/\[\s*\]/g, '[]')
.replace(/\(\s*\)/g, '()')
// 修复PHP变量赋值错误
.replace(/=\s*=\s*=/g, '===')
.replace(/=\s*=\s*null/g, '=== null')
// 修复重复的等号
.replace(/====/g, '===')
.replace(/=====/g, '===')
// 修复方括号错误 - 修复函数调用中的方括号(排除数组语法)
.replace(/\(([^)]+)\]/g, '($1)')
// 移除错误的替换规则,避免破坏数组语法
// .replace(/(\w+)\]/g, (match, word) => {
// // 排除数组元素的情况,避免将 [ 'key', 'value' ] 转换为 [ 'key', 'value' )
// // 检查是否在数组上下文中
// const beforeMatch = code.substring(0, code.indexOf(match));
// const lastBracket = beforeMatch.lastIndexOf('[');
// const lastParen = beforeMatch.lastIndexOf('(');
//
// // 如果最近的符号是 [ 而不是 (,说明在数组上下文中,不应该替换
// if (lastBracket > lastParen) {
// return match;
// }
//
// return word + ')';
// })
// 修复数组语法中的方括号错误 - 直接修复(处理单引号和双引号)
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*\"\"\s*\)\s*\)/g, '["$1", ""]')
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*0\s*\)\s*\)/g, '["$1", 0]')
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/\]\s*;/g, ');')
// .replace(/\]\s*\)/g, '))')
// .replace(/\]\s*\{/g, ') {')
// .replace(/\]\s*,/g, '),')
// 修复数组语法中的方括号错误 - 更精确的匹配
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
// 修复数组语法中的方括号错误
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\]/g, '[$1]')
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\)/g, '[$1]')
// 修复数组元素中的方括号错误
.replace(/\[\s*\(\s*'([^']+)',\s*'([^']+)'\s*\)\s*\)/g, "['$1', '$2']")
.replace(/\[\s*\(\s*'([^']+)',\s*(\d+)\s*\)\s*\)/g, "['$1', $2]")
.replace(/\[\s*\(\s*'([^']+)',\s*""\s*\)\s*\)/g, "['$1', '']")
// 修复特定的方括号错误模式 - 只修复函数调用中的方括号,不修复数组语法
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/(\w+_id)\]/g, '$1)')
// .replace(/(\w+_key)\]/g, '$1)')
// .replace(/(\w+_type)\]/g, '$1)')
// .replace(/(\w+_name)\]/g, '$1)')
// .replace(/(\w+_code)\]/g, '$1)')
// .replace(/(\w+_value)\]/g, '$1)')
// 修复函数调用中的方括号错误 - 只修复函数调用中的方括号,不修复数组语法
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/(\w+)\(([^)]+)\]/g, '$1($2)')
// .replace(/(\w+)\.(\w+)\(([^)]+)\]/g, '$1.$2($3)')
// 修复PHP方法声明
.replace(/public\s+function\s+/g, 'async ')
.replace(/private\s+function\s+/g, 'private async ')
.replace(/protected\s+function\s+/g, 'protected async ')
// 修复PHP返回语句
.replace(/return\s+this;/g, 'return this;')
// 修复PHP异常处理
.replace(/CommonException/g, 'BadRequestException')
.replace(/(?<!BadRequest)Exception/g, 'BadRequestException')
// 修复重复的Business前缀
.replace(/BusinessBusinessException/g, 'BusinessException');
// 2. 使用新的清理和验证功能
convertedCode = this.cleanAndValidateTypeScriptCode(convertedCode);
return convertedCode;
} catch (error) {
console.error('❌ 业务逻辑转换失败:', error.message);
return content;
}
}
/**
* 从PHP源码中提取方法信息 (基于真实PHP服务代码分析)
*/
extractPHPMethods(phpContent) {
try {
const methods = [];
const methodNames = new Set(); // 防止重复方法
// 匹配public方法包括static和返回类型
const publicMethodsRegex = /public\s+(?:static\s+)?function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*(?::\s*[^{]+)?\s*\{/g;
let match;
while ((match = publicMethodsRegex.exec(phpContent)) !== null) {
const methodName = match[1];
const parameters = match[2] || '';
// 跳过构造函数和重复方法
if (methodName === '__construct' || methodNames.has(methodName)) continue;
// 找到方法体的结束位置
const startPos = match.index + match[0].length;
const methodBody = this.extractMethodBody(phpContent, startPos);
// 检查方法体是否有效(不是空方法或只有注释)
const cleanBody = methodBody.trim().replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '');
if (cleanBody.length < 10) continue; // 跳过空方法
methodNames.add(methodName);
methods.push({
name: methodName,
parameters: this.parsePHPParameters(parameters),
logic: methodBody.trim(),
type: 'public'
});
}
// 匹配private方法包括static和返回类型
const privateMethodsRegex = /private\s+(?:static\s+)?function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*(?::\s*[^{]+)?\s*\{/g;
while ((match = privateMethodsRegex.exec(phpContent)) !== null) {
const methodName = match[1];
const parameters = match[2] || '';
// 跳过构造函数和重复方法
if (methodName === '__construct' || methodNames.has(methodName)) continue;
// 找到方法体的结束位置
const startPos = match.index + match[0].length;
const methodBody = this.extractMethodBody(phpContent, startPos);
// 检查方法体是否有效
const cleanBody = methodBody.trim().replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '');
if (cleanBody.length < 10) continue; // 跳过空方法
methodNames.add(methodName);
methods.push({
name: methodName,
parameters: this.parsePHPParameters(parameters),
logic: methodBody.trim(),
type: 'private'
});
}
return methods;
} catch (error) {
console.error('❌ 提取PHP方法失败:', error.message);
return [];
}
}
/**
* 解析PHP方法参数
*/
parsePHPParameters(parameterString) {
if (!parameterString.trim()) return [];
const params = [];
// 修复正则表达式,正确匹配参数名
const paramPattern = /(?:int|string|array|bool)?\s*\$([a-zA-Z_][a-zA-Z0-9_]*)(?:\s*=\s*([^,\)]*?))?/g;
let match;
while ((match = paramPattern.exec(parameterString)) !== null) {
const paramName = match[1];
const defaultValue = match[2];
// 确保参数名不包含方括号,并处理保留字
const cleanParamName = paramName.replace(/\[\]/g, '');
const finalParamName = this.handleReservedWords(cleanParamName);
params.push({
name: finalParamName,
defaultValue: defaultValue ? defaultValue.trim() : undefined,
type: this.inferParameterType(parameterString, match[0])
});
}
return params;
}
/**
* 处理TypeScript保留字
*/
handleReservedWords(paramName) {
const reservedWords = [
'function', 'class', 'interface', 'enum', 'namespace', 'module',
'import', 'export', 'default', 'extends', 'implements', 'public',
'private', 'protected', 'static', 'abstract', 'readonly', 'async',
'await', 'return', 'if', 'else', 'for', 'while', 'do', 'switch',
'case', 'break', 'continue', 'try', 'catch', 'finally', 'throw',
'new', 'this', 'super', 'typeof', 'instanceof', 'in', 'of',
'var', 'let', 'const', 'true', 'false', 'null', 'undefined',
'any', 'string', 'number', 'boolean', 'object', 'void', 'never'
];
if (reservedWords.includes(paramName)) {
return `${paramName}Param`;
}
return paramName;
}
/**
* 推断参数类型
*/
inferParameterType(parameterString, fullMatch) {
// 简单的类型推断逻辑
if (parameterString.includes('[]') || parameterString.includes('array')) {
return 'any[]';
}
if (parameterString.includes('int') || parameterString.includes('float') || parameterString.includes('number')) {
return 'number';
}
if (parameterString.includes('string') || parameterString.includes('str')) {
return 'string';
}
if (parameterString.includes('bool')) {
return 'boolean';
}
if (parameterString.includes('object') || parameterString.includes('array')) {
return 'any';
}
// 默认返回 any
return 'any';
}
/**
* 提取方法体(处理嵌套大括号)
*/
extractMethodBody(content, startPos) {
let braceCount = 0;
let inString = false;
let stringChar = '';
let i = startPos;
let foundFirstBrace = false;
while (i < content.length) {
const char = content[i];
// 处理字符串
if (!inString && (char === '"' || char === "'")) {
inString = true;
stringChar = char;
} else if (inString && char === stringChar) {
// 检查是否是转义字符
if (i > 0 && content[i-1] !== '\\') {
inString = false;
stringChar = '';
}
}
// 只在非字符串状态下计算大括号
if (!inString) {
if (char === '{') {
if (!foundFirstBrace) {
foundFirstBrace = true;
i++;
continue;
}
braceCount++;
} else if (char === '}') {
if (foundFirstBrace && braceCount === 0) {
return content.substring(startPos, i);
}
braceCount--;
}
}
i++;
}
return content.substring(startPos);
}
/**
* 生成服务层参数定义
*/
generateServiceParameters(parameters) {
if (!parameters || parameters.length === 0) return '';
return parameters.map(param => {
const defaultValue = param.defaultValue ? ` = ${param.defaultValue.replace(/'/g, '"').replace(/^"([^"]*)"$/, '"$1"')}` : '';
return `${param.name}: ${param.type}${defaultValue}`;
}).join(', ');
}
/**
* 清理和验证生成的TypeScript代码
*/
cleanAndValidateTypeScriptCode(code) {
let cleanedCode = code;
// 移除PHP语法残留
cleanedCode = cleanedCode
// 移除PHP注释语法
.replace(/\/\*\*\s*\*\s*@param\s+\$[a-zA-Z_][a-zA-Z0-9_]*\s+[^\n]*\n/g, '')
.replace(/\/\*\*\s*\*\s*@return\s+[^\n]*\n/g, '')
.replace(/\/\*\*\s*\*\s*@throws\s+[^\n]*\n/g, '')
// 修复PHP方法声明残留
.replace(/public\s+function\s+/g, 'async ')
.replace(/private\s+function\s+/g, 'private async ')
.replace(/protected\s+function\s+/g, 'protected async ')
// 修复PHP变量声明
.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)\s*=/g, 'const $1 =')
// 修复PHP数组语法
.replace(/array\s*\(\s*\)/g, '[]')
.replace(/array\s*\(/g, '[')
.replace(/\)\s*;/g, '];')
// 修复PHP字符串拼接
.replace(/\.\s*=/g, ' += ')
.replace(/\.\s*['"]/g, ' + \'')
// 修复PHP条件语句
.replace(/if\s*\(\s*([^)]+)\s*\)\s*\{/g, 'if ($1) {')
.replace(/else\s*\{/g, '} else {')
// 修复PHP异常处理
.replace(/throw\s+new\s+CommonException\s*\(/g, 'throw new BadRequestException(')
.replace(/throw\s+new\s+Exception\s*\(/g, 'throw new BadRequestException(')
// 修复PHP函数调用
.replace(/array_merge\s*\(/g, 'Object.assign(')
.replace(/strpos\s*\(/g, 'String.prototype.indexOf.call(')
.replace(/empty\s*\(/g, '!')
.replace(/isset\s*\(/g, 'typeof ')
.replace(/is_null\s*\(/g, '=== null')
// 修复方括号错误 - 只修复函数调用中的方括号,不修复数组语法
.replace(/\(([^)]+)\]/g, '($1)')
// 移除错误的替换规则,避免破坏数组语法
// .replace(/(\w+)\]/g, '$1)') // 这个规则会破坏数组语法
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/\]\s*;/g, ');')
// .replace(/\]\s*\)/g, '))')
// .replace(/\]\s*\{/g, ') {')
// .replace(/\]\s*,/g, '),')
// 修复数组语法中的方括号错误
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\]/g, '[$1]')
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\)/g, '[$1]')
// 修复数组元素中的方括号错误
.replace(/\[\s*\(\s*'([^']+)',\s*'([^']+)'\s*\)\s*\)/g, "['$1', '$2']")
.replace(/\[\s*\(\s*'([^']+)',\s*(\d+)\s*\)\s*\)/g, "['$1', $2]")
.replace(/\[\s*\(\s*'([^']+)',\s*""\s*\)\s*\)/g, "['$1', '']")
// 修复数组元素中的圆括号错误 - 更精确的匹配
.replace(/\[\s*\(\s*'([^']+)',\s*'([^']+)'\s*\)\s*\)/g, "['$1', '$2']")
.replace(/\[\s*\(\s*'([^']+)',\s*(\d+)\s*\)\s*\)/g, "['$1', $2]")
.replace(/\[\s*\(\s*'([^']+)',\s*""\s*\)\s*\)/g, "['$1', '']")
// 修复数组元素中的圆括号错误 - 处理空字符串(单引号和双引号)
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*\"\"\s*\)\s*\)/g, '["$1", ""]')
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*0\s*\)\s*\)/g, '["$1", 0]')
// 修复数组语法中的方括号错误 - 直接修复
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
// 修复数组语法中的方括号错误 - 处理所有情况
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
// 修复数组语法中的方括号错误 - 最终修复
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
.replace(/is_array\s*\(/g, 'Array.isArray(')
.replace(/is_string\s*\(/g, 'typeof ')
.replace(/is_numeric\s*\(/g, '!isNaN(')
// 修复PHP对象访问
.replace(/->/g, '.')
.replace(/::/g, '.')
// 修复PHP空值合并
.replace(/\?\?/g, '||')
// 修复PHP数组访问
.replace(/\['([^']+)'\]/g, '.$1')
.replace(/\["([^"]+)"\]/g, '.$1')
// 修复PHP类型声明
.replace(/:\s*array/g, ': any[]')
.replace(/:\s*string/g, ': string')
.replace(/:\s*int/g, ': number')
.replace(/:\s*float/g, ': number')
.replace(/:\s*bool/g, ': boolean')
// 移除PHP语法残留
.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1')
// 修复方法体格式
.replace(/\{\s*\}/g, '{\n // 待实现\n }')
.replace(/\{\s*return\s+this;\s*\}/g, '{\n return this;\n }');
// 修复严重的语法错误
cleanedCode = this.fixCriticalSyntaxErrors(cleanedCode);
// 验证TypeScript语法
const validationErrors = this.validateTypeScriptSyntax(cleanedCode);
if (validationErrors.length > 0) {
console.warn('⚠️ TypeScript语法警告:', validationErrors);
}
return cleanedCode;
}
/**
* 修复严重的语法错误
*/
fixCriticalSyntaxErrors(code) {
return code
// 修复不完整的类结构
.replace(/export class \w+ \{[^}]*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的构造函数
.replace(/constructor\([^)]*\)\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*super\([^)]*\)\s*;\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*super\([^)]*\)\s*;\s*\}\s*$/, ' super(repository);\n }');
})
// 修复不完整的方法体
.replace(/async \w+\([^)]*\)\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*try\s*\{/gm, (match) => {
return match.replace(/\}\s*\}\s*try\s*\{/, ' {\n try {');
})
// 修复不完整的try-catch块
.replace(/try\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*catch\s*\([^)]*\)\s*\{/gm, (match) => {
return match.replace(/\}\s*\}\s*catch\s*\([^)]*\)\s*\{/, ' // 待实现\n } catch (error) {');
})
// 修复不完整的异常处理
.replace(/throw new BusinessException\('[^']*',\s*error\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/error\]\s*;\s*\}\s*\}\s*$/, 'error);\n }\n }');
})
// 修复不完整的import语句
.replace(/import\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*from/gm, (match) => {
return match.replace(/\{\s*\/\/ 待实现\s*\}\s*\}\s*from/, '{\n } from');
})
// 修复不完整的装饰器
.replace(/@\w+\([^)]*\)\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的数组语法
.replace(/\[\s*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的对象语法
.replace(/\{\s*\}\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的字符串
.replace(/'[^']*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\]\s*;\s*\}\s*\}\s*$/, ';\n }');
})
// 修复不完整的括号
.replace(/\(\s*\)\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的方括号
.replace(/\[\s*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的尖括号
.replace(/<\s*>\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的注释
.replace(/\/\/[^\n]*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\]\s*;\s*\}\s*\}\s*$/, ';\n }');
})
// 修复不完整的多行注释
.replace(/\/\*[\s\S]*?\*\/\s*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\]\s*;\s*\}\s*\}\s*$/, ';\n }');
});
}
/**
* 验证TypeScript语法
*/
validateTypeScriptSyntax(code) {
const errors = [];
// 检查常见语法错误
if (code.includes('=>')) {
errors.push('发现PHP数组语法 => 未转换');
}
if (code.includes('??')) {
errors.push('发现PHP空值合并 ?? 未转换');
}
if (code.includes('::')) {
errors.push('发现PHP静态访问 :: 未转换');
}
if (code.includes('->')) {
errors.push('发现PHP对象访问 -> 未转换');
}
if (code.includes('$')) {
errors.push('发现PHP变量 $ 未转换');
}
if (code.includes('array(')) {
errors.push('发现PHP数组语法 array() 未转换');
}
if (code.includes('public function') || code.includes('private function') || code.includes('protected function')) {
errors.push('发现PHP方法声明未转换');
}
// 检查严重的语法错误
if (code.includes(']') && !code.includes('[')) {
errors.push('发现不完整的方括号 ]');
}
if (code.includes('}') && !code.includes('{')) {
errors.push('发现不完整的大括号 }');
}
// 检查括号匹配
const openBraces = (code.match(/\{/g) || []).length;
const closeBraces = (code.match(/\}/g) || []).length;
if (openBraces !== closeBraces) {
errors.push(`大括号不匹配: 开括号${openBraces}个, 闭括号${closeBraces}`);
}
const openBrackets = (code.match(/\[/g) || []).length;
const closeBrackets = (code.match(/\]/g) || []).length;
if (openBrackets !== closeBrackets) {
errors.push(`方括号不匹配: 开括号${openBrackets}个, 闭括号${closeBrackets}`);
}
if (code.includes('// 待实现')) {
errors.push('发现未实现的方法体');
}
return errors;
}
}
module.exports = BusinessLogicConverter;

View File

@@ -1,270 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const BaseGenerator = require('./base-generator');
/**
* 📚 字典生成器 (参考Java架构)
*/
class DictGenerator extends BaseGenerator {
constructor(config = null) {
super('DictGenerator');
if (config) {
this.config = config;
} else {
const projectRoot = path.resolve(__dirname, '../../../../..');
this.config = {
javaBasePath: path.join(projectRoot, 'niucloud-java/niucloud-core/src/main/java'),
phpBasePath: path.join(projectRoot, 'niucloud-php/niucloud'),
nestjsBasePath: path.join(projectRoot, 'wwjcloud-nest-v1/libs/wwjcloud-core/src'),
discoveryResultPath: path.join(__dirname, '../java-discovery-result.json')
};
}
this.discoveryData = null;
this.dictStats = { dictsCreated: 0, dictsSkipped: 0 };
}
/**
* 运行字典生成
*/
async run() {
try {
console.log('📚 启动字典生成器...');
console.log('目标生成NestJS字典/枚举文件\n');
// 加载Java架构发现结果含PHP业务逻辑
await this.loadDiscoveryData();
// 生成字典
await this.generateDicts();
// 输出统计报告
this.printStats();
} catch (error) {
console.error('❌ 字典生成失败:', error);
this.stats.errors++;
}
}
/**
* 加载Java架构发现结果含PHP业务逻辑
*/
async loadDiscoveryData() {
try {
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8');
this.discoveryData = JSON.parse(data);
console.log(' ✅ 成功加载Java架构发现结果含PHP业务逻辑');
} catch (error) {
console.error('❌ 加载发现结果失败:', error);
throw error;
}
}
/**
* 生成字典
*/
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} 个字典`);
}
/**
* 创建字典
*/
async createDict(moduleName, dictName, dictInfo) {
// 使用 kebab-case 文件名,避免重叠名问题
// 例如: dict → dict.enum.ts (而不是 DictDict.ts)
const kebabName = this.toKebabCase(dictName);
const dictPath = path.join(
this.config.nestjsBasePath,
moduleName,
'enums',
`${kebabName}.enum.ts` // ✅ kebab-case + .enum.ts 后缀
);
const content = this.generateDictContent(moduleName, dictName);
const success = this.writeFile(dictPath, content, `Enum for ${moduleName}/${dictName}`);
if (success) {
this.dictStats.dictsCreated++;
} else {
this.dictStats.dictsSkipped++;
}
}
/**
* 生成字典内容
*/
generateDictContent(moduleName, dictName) {
// 避免重叠名: Dict → DictEnum (而不是 DictDict)
const pascalName = this.toPascalCase(dictName);
const className = `${pascalName}Enum`; // ✅ 例如: DictEnum, MemberEnum
const dictVarName = `${this.toCamelCase(dictName)}Dict`; // ✅ 例如: dictDict, memberDict
const content = `/**
* ${dictName} 枚举
* 定义相关的常量值
*/
export enum ${className} {
// 状态枚举
STATUS_ACTIVE = 'active',
STATUS_INACTIVE = 'inactive',
STATUS_PENDING = 'pending',
STATUS_DELETED = 'deleted',
// 类型枚举
TYPE_NORMAL = 'normal',
TYPE_PREMIUM = 'premium',
TYPE_VIP = 'vip',
// 级别枚举
LEVEL_LOW = 1,
LEVEL_MEDIUM = 2,
LEVEL_HIGH = 3,
LEVEL_CRITICAL = 4,
}
/**
* ${dictName} 字典映射
*/
export const ${dictVarName} = {
// 状态映射
status: {
[${className}.STATUS_ACTIVE]: '激活',
[${className}.STATUS_INACTIVE]: '未激活',
[${className}.STATUS_PENDING]: '待处理',
[${className}.STATUS_DELETED]: '已删除',
},
// 类型映射
type: {
[${className}.TYPE_NORMAL]: '普通',
[${className}.TYPE_PREMIUM]: '高级',
[${className}.TYPE_VIP]: 'VIP',
},
// 级别映射
level: {
[${className}.LEVEL_LOW]: '低',
[${className}.LEVEL_MEDIUM]: '中',
[${className}.LEVEL_HIGH]: '高',
[${className}.LEVEL_CRITICAL]: '紧急',
},
} as const;
/**
* ${dictName} 工具类
*/
export class ${className}Util {
/**
* 获取状态文本
*/
static getStatusText(status: ${className}): string {
return (${dictVarName}.status as any)[status] || '未知';
}
/**
* 获取类型文本
*/
static getTypeText(type: ${className}): string {
return (${dictVarName}.type as any)[type] || '未知';
}
/**
* 获取级别文本
*/
static getLevelText(level: ${className}): string {
return (${dictVarName}.level as any)[level] || '未知';
}
/**
* 获取所有状态选项
*/
static getStatusOptions(): Array<{ value: string; label: string }> {
return Object.entries(${dictVarName}.status).map(([value, label]) => ({
value,
label: label as string,
}));
}
/**
* 获取所有类型选项
*/
static getTypeOptions(): Array<{ value: string; label: string }> {
return Object.entries(${dictVarName}.type).map(([value, label]) => ({
value,
label: label as string,
}));
}
/**
* 获取所有级别选项
*/
static getLevelOptions(): Array<{ value: number; label: string }> {
return Object.entries(${dictVarName}.level).map(([value, label]) => ({
value: Number(value),
label: label as string,
}));
}
/**
* 验证状态值
*/
static isValidStatus(status: string): boolean {
return Object.values(${className}).includes(status as ${className});
}
/**
* 验证类型值
*/
static isValidType(type: string): boolean {
return Object.values(${className}).includes(type as ${className});
}
/**
* 验证级别值
*/
static isValidLevel(level: number): boolean {
return Object.values(${className}).includes(level as ${className});
}
}
/**
* ${dictName} 类型定义
*/
export type ${className}Status = keyof typeof ${dictVarName}.status;
export type ${className}Type = keyof typeof ${dictVarName}.type;
export type ${className}Level = keyof typeof ${dictVarName}.level;`;
return content;
}
/**
* 输出统计报告
*/
printStats() {
super.printStats({
'Dicts Created': this.dictStats.dictsCreated,
'Dicts Skipped': this.dictStats.dictsSkipped
});
}
}
// 如果直接运行此文件
if (require.main === module) {
const generator = new DictGenerator();
generator.run().catch(console.error);
}
module.exports = DictGenerator;

View File

@@ -1,290 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const BaseGenerator = require('./base-generator');
/**
* 🏗️ 实体生成器
* 专门负责生成NestJS实体文件 (参考Java架构)
*/
class EntityGenerator extends BaseGenerator {
constructor(config = null) {
super('EntityGenerator');
// 使用传入的配置或默认配置
if (config) {
this.config = config;
} else {
// 动态路径配置 - 确保指向正确的项目根目录
// __dirname从generators目录开始需要回到wwjcloud-nsetjs根目录
const projectRoot = path.resolve(__dirname, '../../..');
this.config = {
javaBasePath: path.join(projectRoot, 'niucloud-java/niucloud-core/src/main/java'),
nestjsBasePath: path.join(projectRoot, 'wwjcloud-nest-v1/libs/wwjcloud-core/src'),
discoveryResultPath: path.join(__dirname, '../java-discovery-result.json')
};
}
this.discoveryData = null;
this.entityStats = {
entitiesCreated: 0,
entitiesSkipped: 0
};
}
/**
* 运行实体生成
*/
async run() {
try {
console.log('🏗️ 启动实体生成器...');
console.log('目标生成NestJS实体文件\n');
// 加载Java架构发现结果
await this.loadDiscoveryData();
// 生成实体
await this.generateEntities();
// 输出统计报告
this.printStats();
} catch (error) {
console.error('❌ 实体生成失败:', error);
this.stats.errors++;
}
}
/**
* 加载Java架构发现结果
*/
async loadDiscoveryData() {
try {
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8');
this.discoveryData = JSON.parse(data);
console.log(' ✅ 成功加载Java架构发现结果');
} catch (error) {
console.error('❌ 加载发现结果失败:', error);
throw error;
}
}
/**
* 生成实体
*/
async generateEntities() {
console.log(' 🔨 生成实体...');
// 检查是否有模型数据
if (!this.discoveryData.models || Object.keys(this.discoveryData.models).length === 0) {
console.log(' ⚠️ 未发现Java实体跳过生成');
return;
}
for (const [moduleName, models] of Object.entries(this.discoveryData.models)) {
// 基于Java架构生成实体
console.log(` 📁 处理模块 ${moduleName}: ${Object.keys(models).length} 个实体`);
for (const [modelName, modelInfo] of Object.entries(models)) {
await this.createEntity(moduleName, modelName, modelInfo);
this.stats.entitiesCreated++;
}
}
console.log(` ✅ 生成了 ${this.stats.entitiesCreated} 个实体`);
}
/**
* 创建实体
*/
async createEntity(moduleName, modelName, modelInfo) {
const entityPath = path.join(
this.config.nestjsBasePath,
moduleName,
'entity',
`${this.toKebabCase(modelName)}.entity.ts`
);
// 基于Java实体生成
const content = await this.generateEntityFromJava(moduleName, modelName, modelInfo);
if (content) {
this.writeFile(entityPath, content, `Entity for ${moduleName}/${modelName}`);
this.entityStats.entitiesCreated++;
} else {
this.log(`跳过实体生成: ${moduleName}/${this.toKebabCase(modelName)}.entity.ts (无Java源码)`, 'warning');
this.entityStats.entitiesSkipped++;
this.stats.filesSkipped++;
}
}
toKebabCase(str) {
return String(str)
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/_/g, '-')
.toLowerCase();
}
/**
* 基于Java实体生成100%匹配的NestJS实体
*/
async generateEntityFromJava(moduleName, modelName, modelInfo) {
try {
// 查找对应的Java实体文件
const possibleJavaPaths = [
path.join(this.config.javaBasePath, 'com/niu/core/entity', moduleName, `${modelName}.java`),
path.join(this.config.javaBasePath, 'com/niu/core/entity', 'sys', `${modelName}.java`),
path.join(this.config.javaBasePath, 'com/niu/core/entity', `${modelName}.java`)
];
let javaFilePath = null;
for (const javaPath of possibleJavaPaths) {
if (fs.existsSync(javaPath)) {
javaFilePath = javaPath;
break;
}
}
if (!javaFilePath) {
return null;
}
const javaContent = fs.readFileSync(javaFilePath, 'utf-8');
const className = modelName; // Java类名直接作为NestJS类名
// 解析Java实体字段
const entityInfo = this.parseJavaEntity(javaContent, className);
if (!entityInfo) {
return null;
}
console.log(` 📖 基于Java实体生成: ${javaFilePath}`);
return `import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
/**
* ${className} - 对应Java实体
*/
@Entity('${entityInfo.tableName}')
export class ${className} {
${entityInfo.fields}
}`;
} catch (error) {
console.log(` ❌ 生成Java实体失败: ${error.message}`);
return null;
}
}
/**
* 解析Java实体内容
*/
parseJavaEntity(javaContent, className) {
// 提取表名注解
const tableMatch = javaContent.match(/@Table\([^)]*name\s*=\s*["']([^"']+)["']/);
const tableName = tableMatch ? tableMatch[1] : `${className.toLowerCase()}`;
// 提取字段定义
const fields = [];
const lines = javaContent.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// 查找字段定义 (private开头的字段)
if (line.match(/private\s+(\w+)\s+(\w+);/)) {
const fieldMatch = line.match(/private\s+(\w+)\s+(\w+);/);
if (fieldMatch) {
const javaType = fieldMatch[1];
const fieldName = fieldMatch[2];
// 查找字段注解
let columnDef = '';
let annotation = '';
// 向前查找注解定义
for (let j = Math.max(0, i - 5); j < i; j++) {
const annotationLine = lines[j].trim();
if (annotationLine.includes('@Id')) {
annotation = '@PrimaryGeneratedColumn()';
} else if (annotationLine.includes('@TableId')) {
annotation = '@PrimaryGeneratedColumn()';
} else if (annotationLine.includes('@Column')) {
// 解析@Column注解
const columnMatch = annotationLine.match(/@Column[^}]*name\s*=\s*["']([^"']+)["']/);
if (columnMatch) {
columnDef = `{ name: '${columnMatch[1]}' }`;
}
}
}
// 转换Java类型到TypeScript类型
const tsType = this.convertJavaTypeToTS(javaType);
// 生成字段定义
const fieldDef = annotation ?
` ${annotation}\n ${fieldName}: ${tsType};` :
columnDef ?
` @Column(${columnDef})\n ${fieldName}: ${tsType};` :
` @Column()\n ${fieldName}: ${tsType};`;
fields.push(fieldDef);
}
}
}
if (fields.length === 0) {
return null;
}
return {
tableName,
fields: fields.join('\n\n')
};
}
/**
* 转换Java类型到TypeScript类型
*/
convertJavaTypeToTS(javaType) {
const typeMap = {
'Integer': 'number',
'Long': 'number',
'String': 'string',
'Boolean': 'boolean',
'Date': 'Date',
'BigDecimal': 'number'
};
return typeMap[javaType] || 'any';
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 输出统计报告
*/
printStats() {
super.printStats({
'Entities Created': this.entityStats.entitiesCreated,
'Entities Skipped': this.entityStats.entitiesSkipped
});
}
}
// 如果直接运行此文件
if (require.main === module) {
const generator = new EntityGenerator();
generator.run().catch(console.error);
}
module.exports = EntityGenerator;

View File

@@ -1,273 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const BaseGenerator = require('./base-generator');
/**
* ⚡ 任务生成器
* 专门负责生成NestJS任务/队列文件 (参考Java架构)
*/
class JobGenerator extends BaseGenerator {
constructor(config = null) {
super('JobGenerator');
if (config) {
this.config = config;
} else {
const projectRoot = path.resolve(__dirname, '../../../../..');
this.config = {
javaBasePath: path.join(projectRoot, 'niucloud-java/niucloud-core/src/main/java'),
phpBasePath: path.join(projectRoot, 'niucloud-php/niucloud'),
nestjsBasePath: path.join(projectRoot, 'wwjcloud-nest-v1/libs/wwjcloud-core/src'),
discoveryResultPath: path.join(__dirname, '../java-discovery-result.json')
};
}
this.discoveryData = null;
this.jobStats = {
jobsCreated: 0,
jobsSkipped: 0
};
}
/**
* 运行任务生成
*/
async run() {
try {
console.log('⚡ 启动任务生成器...');
console.log('目标生成NestJS任务/队列文件\n');
// 加载Java架构发现结果含PHP业务逻辑
await this.loadDiscoveryData();
// 生成任务
await this.generateJobs();
// 输出统计报告
this.printStats();
} catch (error) {
console.error('❌ 任务生成失败:', error);
this.stats.errors++;
}
}
/**
* 加载Java架构发现结果含PHP业务逻辑
*/
async loadDiscoveryData() {
try {
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8');
this.discoveryData = JSON.parse(data);
console.log(' ✅ 成功加载Java架构发现结果含PHP业务逻辑');
} catch (error) {
console.error('❌ 加载发现结果失败:', error);
throw error;
}
}
/**
* 生成任务
*/
async generateJobs() {
console.log(' 🔨 生成任务...');
// 检查是否有任务数据
if (!this.discoveryData.jobs || Object.keys(this.discoveryData.jobs).length === 0) {
console.log(' ⚠️ 未发现PHP任务跳过生成');
return;
}
for (const [moduleName, jobs] of Object.entries(this.discoveryData.jobs)) {
// 检查Java架构是否有对应的任务目录
if (!this.hasPHPJobs(moduleName)) {
console.log(` ⚠️ 模块 ${moduleName} 在Java架构中无对应且PHP项目中也无任务跳过`);
continue;
}
for (const [jobName, jobInfo] of Object.entries(jobs)) {
await this.createJob(moduleName, jobName, jobInfo);
this.stats.jobsCreated++;
}
}
console.log(` ✅ 生成了 ${this.stats.jobsCreated} 个任务`);
}
/**
* 创建任务
*/
async createJob(moduleName, jobName, jobInfo) {
const jobDir = path.join(this.config.nestjsBasePath, moduleName, 'jobs');
this.ensureDir(jobDir);
const normalizedBase = jobName.replace(/Job$/i, '');
const jobPath = path.join(
jobDir,
`${this.toPascalCase(normalizedBase)}Job.ts`
);
// 检查是否有对应的PHP任务文件
const phpJobPath = path.join(this.config.phpBasePath, 'app/job', moduleName, `${jobName}.php`);
if (!fs.existsSync(phpJobPath)) {
console.log(` ❌ 未找到PHP任务文件跳过生成: ${phpJobPath}`);
return;
}
const content = this.generateJobContent(moduleName, jobName);
this.writeFile(jobPath, content, `Job for ${moduleName}/${jobName}`);
this.jobStats.jobsCreated++;
}
/**
* 生成任务内容
*/
generateJobContent(moduleName, jobName) {
const baseName = jobName.replace(/Job$/i, '');
const className = `${this.toPascalCase(baseName)}Job`;
return `import { Injectable, Logger } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';
import { BadRequestException } from '@nestjs/common';
/**
* ${className} - 基于NestJS BullMQ
* 参考: https://docs.nestjs.com/techniques/queues
* 对应 Java: @Async + RabbitMQ
* 对应 PHP: think\queue
*/
@Injectable()
export class ${className} {
private readonly logger = new Logger(${className}.name);
constructor(
@InjectQueue('${moduleName}') private readonly queue: Queue
) {}
/**
* 添加任务到队列 - 使用BullMQ标准API
* 参考: https://docs.nestjs.com/techniques/queues#producers
*/
async addJob(data: any, options?: any) {
try {
const job = await this.queue.add('${baseName}', data, options);
this.logger.log(\`${baseName} job added to queue: \${job.id}\`, data);
return job;
} catch (error) {
this.logger.error('Failed to add ${baseName} job to queue:', error);
throw new BadRequestException('${baseName}任务添加失败');
}
}
/**
* 处理队列任务
* 使用Core层基础设施统一队列服务、异常处理、日志服务
*/
async processJob(data: any) {
this.logger.log('${baseName} job processing:', data);
try {
// 任务逻辑
await this.executeJob(data);
this.logger.log('${baseName} job completed successfully');
} catch (error) {
this.logger.error('${baseName} job failed:', error);
// 使用Core层异常处理
throw new BadRequestException('${baseName}任务处理失败', error);
}
}
/**
* 执行任务
* 使用Core层基础设施日志服务、异常处理
*/
private async executeJob(data: any) {
// 实现具体的任务逻辑
// 例如:
// - 数据清理
// - 报表生成
// - 邮件发送
// - 数据同步
// - 备份操作
this.logger.log('Executing ${baseName} job logic with data:', data);
// 模拟异步操作
await new Promise(resolve => setTimeout(resolve, 1000));
this.logger.log('${baseName} job logic completed');
}
/**
* 手动触发任务
* 使用Core层基础设施日志服务、异常处理
*/
async triggerJob(data?: any) {
this.logger.log('Manually triggering ${baseName} job...');
try {
await this.executeJob(data || {});
} catch (error) {
this.logger.error('Failed to trigger ${baseName} job:', error);
// 使用Core层异常处理
throw new BadRequestException('${baseName}任务触发失败', error);
}
}
}`;
}
/**
* 转换为PascalCase
*/
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 转换为camelCase
*/
toCamelCase(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
}
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 检查模块是否有PHP任务
*/
hasPHPJobs(moduleName) {
const phpProjectPath = path.join(__dirname, '../../niucloud-php/niucloud');
const jobPath = path.join(phpProjectPath, 'app/job', moduleName);
return fs.existsSync(jobPath);
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 输出统计报告
*/
printStats() {
super.printStats({
'Jobs Created': this.jobStats.jobsCreated,
'Jobs Skipped': this.jobStats.jobsSkipped
});
}
}
// 如果直接运行此文件
if (require.main === module) {
const generator = new JobGenerator();
generator.run().catch(console.error);
}
module.exports = JobGenerator;

View File

@@ -1,297 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const BaseGenerator = require('./base-generator');
/**
* 👂 监听器生成器
* 专门负责生成NestJS事件监听器文件 (参考Java架构)
*/
class ListenerGenerator extends BaseGenerator {
constructor(config = null) {
super('ListenerGenerator');
if (config) {
this.config = config;
} else {
const projectRoot = path.resolve(__dirname, '../../../../..');
this.config = {
javaBasePath: path.join(projectRoot, 'niucloud-java/niucloud-core/src/main/java'),
phpBasePath: path.join(projectRoot, 'niucloud-php/niucloud'),
nestjsBasePath: path.join(projectRoot, 'wwjcloud-nest-v1/libs/wwjcloud-core/src'),
discoveryResultPath: path.join(__dirname, '../java-discovery-result.json')
};
}
this.discoveryData = null;
this.listenerStats = {
listenersCreated: 0,
listenersSkipped: 0
};
}
/**
* 运行监听器生成
*/
async run() {
try {
console.log('👂 启动监听器生成器...');
console.log('目标生成NestJS事件监听器文件\n');
// 加载Java架构发现结果含PHP业务逻辑
await this.loadDiscoveryData();
// 生成监听器
await this.generateListeners();
// 输出统计报告
this.printStats();
} catch (error) {
console.error('❌ 监听器生成失败:', error);
this.stats.errors++;
}
}
/**
* 加载Java架构发现结果含PHP业务逻辑
*/
async loadDiscoveryData() {
try {
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8');
this.discoveryData = JSON.parse(data);
console.log(' ✅ 成功加载Java架构发现结果含PHP业务逻辑');
} catch (error) {
console.error('❌ 加载发现结果失败:', error);
throw error;
}
}
/**
* 生成监听器
*/
async generateListeners() {
console.log(' 🔨 生成监听器...');
// 检查是否有监听器数据
if (!this.discoveryData.listeners || Object.keys(this.discoveryData.listeners).length === 0) {
console.log(' ⚠️ 未发现PHP监听器跳过生成');
return;
}
for (const [moduleName, listeners] of Object.entries(this.discoveryData.listeners)) {
// 检查Java架构是否有对应的监听器目录
if (!this.hasPHPListeners(moduleName)) {
console.log(` ⚠️ 模块 ${moduleName} 在Java架构中无对应且PHP项目中也无监听器跳过`);
continue;
}
for (const [listenerName, listenerInfo] of Object.entries(listeners)) {
await this.createListener(moduleName, listenerName, listenerInfo);
this.stats.listenersCreated++;
}
}
console.log(` ✅ 生成了 ${this.stats.listenersCreated} 个监听器`);
}
/**
* 创建监听器
*/
async createListener(moduleName, listenerName, listenerInfo) {
const listenerDir = path.join(this.config.nestjsBasePath, moduleName, 'listeners');
this.ensureDir(listenerDir);
const listenerPath = path.join(
listenerDir,
`${this.toPascalCase(listenerName)}Listener.ts`
);
// 检查是否有对应的PHP监听器文件
const phpListenerPath = path.join(this.config.phpBasePath, 'app/listener', moduleName, `${listenerName}.php`);
if (!fs.existsSync(phpListenerPath)) {
console.log(` ❌ 未找到PHP监听器文件跳过生成: ${phpListenerPath}`);
return;
}
const content = this.generateListenerContent(moduleName, listenerName);
this.writeFile(listenerPath, content, `Listener for ${moduleName}/${listenerName}`);
this.listenerStats.listenersCreated++;
}
/**
* 生成监听器内容
*/
generateListenerContent(moduleName, listenerName) {
// 移除可能存在的Listener后缀避免重复
const baseName = listenerName.replace(/Listener$/i, '');
const className = `${this.toPascalCase(baseName)}Listener`;
// 解析PHP监听器的真实内容
const phpListenerPath = path.join(__dirname, '../../niucloud-php/niucloud/app/listener', moduleName, `${listenerName}.php`);
const phpContent = this.parsePHPListener(phpListenerPath);
return `import { Injectable, Logger } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { BadRequestException } from '@nestjs/common';
/**
* ${className} - 基于NestJS EventEmitter
* 参考: https://docs.nestjs.com/techniques/events
* 对应 Java: @EventListener + ApplicationEventPublisher
* 对应 PHP: think\\facade\\Event
*/
@Injectable()
export class ${className} {
private readonly logger = new Logger(${className}.name);
/**
* 处理事件 - 基于PHP真实实现
* 使用 @OnEvent 装饰器监听事件
*/
@OnEvent('${baseName.toLowerCase()}.handle')
async handle(payload: any) {
this.logger.log('${baseName} listener: Event received', payload);
try {
// TODO: 实现${baseName}事件处理逻辑
// 原始PHP逻辑已解析需要手动转换为TypeScript
this.logger.log('Processing ${baseName} event with payload:', payload);
// 示例:处理事件数据
// const { type, data } = payload;
// if (type === 'weapp') {
// const siteId = data.site_id;
// // 处理逻辑...
// }
this.logger.log('${baseName} event processed successfully');
} catch (error) {
this.logger.error('Error processing ${baseName} event:', error);
throw new BadRequestException('${baseName}事件处理失败');
}
}
}`;
}
/**
* 解析PHP监听器文件
*/
parsePHPListener(phpFilePath) {
try {
if (!fs.existsSync(phpFilePath)) {
return {
methodBody: '// PHP文件不存在请手动实现业务逻辑'
};
}
const phpContent = fs.readFileSync(phpFilePath, 'utf8');
// 提取handle方法的内容
const handleMethodMatch = phpContent.match(/public function handle\([^)]*\)\s*\{([\s\S]*?)\n\s*\}/);
if (!handleMethodMatch) {
return {
methodBody: '// 无法解析PHP handle方法请手动实现业务逻辑'
};
}
const methodBody = handleMethodMatch[1]
.trim()
.split('\n')
.map(line => {
// 移除PHP注释
line = line.replace(/\/\/.*$/, '');
// 移除PHP变量符号
line = line.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1');
// 移除PHP数组语法
line = line.replace(/\[([^\]]*)\]/g, '[$1]');
// 移除PHP字符串连接
line = line.replace(/\./g, '+');
// 移除PHP分号
line = line.replace(/;$/g, '');
return line.trim();
})
.filter(line => line.length > 0)
.map(line => ` ${line}`)
.join('\n');
return {
methodBody: methodBody || '// 请根据PHP实现添加业务逻辑'
};
} catch (error) {
console.error(`解析PHP监听器失败: ${phpFilePath}`, error);
return {
methodBody: '// 解析PHP文件失败请手动实现业务逻辑'
};
}
}
/**
* 转换为PascalCase
*/
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 转换为camelCase
*/
toCamelCase(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
}
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 检查模块是否有PHP监听器
*/
hasPHPListeners(moduleName) {
const phpProjectPath = path.join(__dirname, '../../niucloud-php/niucloud');
const listenerPath = path.join(phpProjectPath, 'app/listener', moduleName);
// 检查目录是否存在
if (!fs.existsSync(listenerPath)) {
return false;
}
// 检查目录中是否有PHP文件
try {
const files = fs.readdirSync(listenerPath);
return files.some(file => file.endsWith('.php'));
} catch (error) {
return false;
}
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 输出统计报告
*/
printStats() {
super.printStats({
'Listeners Created': this.listenerStats.listenersCreated,
'Listeners Skipped': this.listenerStats.listenersSkipped
});
}
}
// 如果直接运行此文件
if (require.main === module) {
const generator = new ListenerGenerator();
generator.run().catch(console.error);
}
module.exports = ListenerGenerator;

View File

@@ -1,554 +0,0 @@
const fs = require('fs');
const path = require('path');
/**
* NestJS模块生成器 (参考Java架构)
* 为每个模块创建对应的.module.ts文件并正确引用所有组件
*/
class ModuleGenerator {
constructor() {
this.config = {
javaBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-java/niucloud-core/src/main/java',
nestjsBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/libs/wwjcloud-core/src',
discoveryResultPath: './java-discovery-result.json',
whitelistModules: [], // 空数组=全部业务模块,结合黑名单过滤
blacklistModules: ['job','queue','workerman','lang','menu','system'],
includeTypeOrmFeature: true
};
this.discoveryData = null;
this.stats = {
createdModules: 0,
updatedModules: 0,
errors: 0
};
}
/**
* 运行模块生成
*/
async run() {
try {
console.log('🚀 启动NestJS模块生成器...');
console.log('目标:为每个模块创建.module.ts文件并正确引用所有组件\n');
// 第1阶段加载Java架构发现结果含PHP业务逻辑
console.log('📊 第1阶段加载Java架构发现结果含PHP业务逻辑...');
await this.loadDiscoveryData();
console.log(' ✅ 成功加载Java架构发现结果含PHP业务逻辑');
// 第2阶段扫描现有文件结构
console.log('\n📊 第2阶段扫描现有文件结构...');
const moduleStructure = await this.scanModuleStructure();
console.log(` ✅ 扫描了 ${Object.keys(moduleStructure).length} 个模块`);
// 第3阶段生成模块文件
console.log('\n📊 第3阶段生成模块文件...');
await this.generateModules(moduleStructure);
console.log(` ✅ 生成了 ${this.stats.createdModules} 个模块文件`);
// 第4阶段生成统计报告
console.log('\n📊 第4阶段生成统计报告...');
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, 'utf8');
this.discoveryData = JSON.parse(data);
} catch (error) {
console.log(` ⚠️ 未找到发现结果文件,跳过加载: ${error.message}`);
this.discoveryData = {};
}
}
/**
* 扫描模块结构
*/
async scanModuleStructure() {
const moduleStructure = {};
const commonPath = this.config.nestjsBasePath;
if (!fs.existsSync(commonPath)) {
console.log(' ⚠️ common目录不存在');
return moduleStructure;
}
const modules = fs.readdirSync(commonPath, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
for (const moduleName of modules) {
if (this.shouldSkipModule(moduleName)) {
console.log(` ⏭️ 跳过非业务模块: ${moduleName}`);
continue;
}
const modulePath = path.join(commonPath, moduleName);
moduleStructure[moduleName] = {
controllers: this.scanControllers(modulePath),
services: this.scanServices(modulePath),
entities: this.scanEntities(modulePath),
validators: this.scanValidators(modulePath),
middlewares: this.scanMiddlewares(modulePath),
jobs: this.scanJobs(modulePath),
listeners: this.scanListeners(modulePath),
commands: this.scanCommands(modulePath),
dicts: this.scanDicts(modulePath)
};
}
return moduleStructure;
}
/**
* 读取实际文件中的类名
*/
getActualClassName(filePath) {
try {
if (!fs.existsSync(filePath)) {
return null;
}
const content = fs.readFileSync(filePath, 'utf8');
const match = content.match(/export\s+(?:class|interface|enum)\s+(\w+)/);
return match ? match[1] : null;
} catch (error) {
console.error(`读取文件 ${filePath} 时出错:`, error.message);
return null;
}
}
/**
* 扫描控制器
*/
scanControllers(modulePath) {
const controllers = [];
const controllersPath = path.join(modulePath, 'controllers');
if (fs.existsSync(controllersPath)) {
const layers = ['adminapi', 'api'];
for (const layer of layers) {
const layerPath = path.join(controllersPath, layer);
if (fs.existsSync(layerPath)) {
const allFiles = fs.readdirSync(layerPath);
const controllerFiles = allFiles.filter(file => file.endsWith('.controller.ts'));
if (controllerFiles.length > 0) {
console.log(` 发现 ${layer} 层控制器: ${controllerFiles.join(', ')}`);
}
const files = controllerFiles.map(file => {
const filePath = path.join(layerPath, file);
const actualClassName = this.getActualClassName(filePath);
return {
name: actualClassName || this.guessControllerClassName(file),
path: `./controllers/${layer}/${file}`,
layer: layer
};
});
controllers.push(...files);
}
}
}
return controllers;
}
/**
* 扫描服务
*/
scanServices(modulePath) {
const services = [];
const servicesPath = path.join(modulePath, 'services');
if (fs.existsSync(servicesPath)) {
const layers = ['admin', 'api', 'core'];
for (const layer of layers) {
const layerPath = path.join(servicesPath, layer);
if (fs.existsSync(layerPath)) {
const files = fs.readdirSync(layerPath)
.filter(file => file.endsWith('.service.ts'))
.map(file => {
const filePath = path.join(layerPath, file);
const actualClassName = this.getActualClassName(filePath);
return {
name: actualClassName || this.guessServiceClassName(file, layer),
path: `./services/${layer}/${file}`,
layer: layer
};
});
services.push(...files);
}
}
}
return services;
}
/**
* 扫描实体
*/
scanEntities(modulePath) {
const entities = [];
const entitiesPath = path.join(modulePath, 'entity');
if (fs.existsSync(entitiesPath)) {
const files = fs.readdirSync(entitiesPath)
.filter(file => file.endsWith('.entity.ts'))
.map(file => ({
name: this.getActualClassName(path.join(entitiesPath, file)) || this.guessEntityClassName(file),
path: `./entity/${file}`
}));
entities.push(...files);
}
return entities;
}
/**
* 扫描验证器
*/
scanValidators(modulePath) {
const validators = [];
const validatorsPath = path.join(modulePath, 'dto');
if (fs.existsSync(validatorsPath)) {
const files = fs.readdirSync(validatorsPath, { recursive: true })
.filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts'))
.map(file => ({
name: file.replace('.ts', ''),
path: `./dto/${file}`
}));
validators.push(...files);
}
return validators;
}
/**
* 扫描中间件
*/
scanMiddlewares(modulePath) {
const middlewares = [];
const middlewaresPath = path.join(modulePath, 'guards');
if (fs.existsSync(middlewaresPath)) {
const files = fs.readdirSync(middlewaresPath)
.filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts'))
.map(file => ({
name: file.replace('.ts', ''),
path: `./guards/${file}`
}));
middlewares.push(...files);
}
return middlewares;
}
/**
* 扫描任务
*/
scanJobs(modulePath) {
const jobs = [];
const jobsPath = path.join(modulePath, 'jobs');
if (fs.existsSync(jobsPath)) {
const files = fs.readdirSync(jobsPath)
.filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts'))
.map(file => ({
name: file.replace('.ts', ''),
path: `./jobs/${file}`
}));
jobs.push(...files);
}
return jobs;
}
/**
* 扫描监听器
*/
scanListeners(modulePath) {
const listeners = [];
const listenersPath = path.join(modulePath, 'listeners');
if (fs.existsSync(listenersPath)) {
const files = fs.readdirSync(listenersPath)
.filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts'))
.map(file => ({
name: file.replace('.ts', ''),
path: `./listeners/${file}`
}));
listeners.push(...files);
}
return listeners;
}
/**
* 扫描命令
*/
scanCommands(modulePath) {
const commands = [];
const commandsPath = path.join(modulePath, 'commands');
if (fs.existsSync(commandsPath)) {
const files = fs.readdirSync(commandsPath)
.filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts'))
.map(file => ({
name: file.replace('.ts', ''),
path: `./commands/${file}`
}));
commands.push(...files);
}
return commands;
}
/**
* 扫描字典
*/
scanDicts(modulePath) {
const dicts = [];
const dictsPath = path.join(modulePath, 'dicts');
if (fs.existsSync(dictsPath)) {
const files = fs.readdirSync(dictsPath)
.filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts'))
.map(file => ({
name: file.replace('.ts', ''),
path: `./dicts/${file}`
}));
dicts.push(...files);
}
return dicts;
}
/**
* 生成模块文件
*/
async generateModules(moduleStructure) {
console.log(' 🔨 生成模块文件...');
for (const [moduleName, components] of Object.entries(moduleStructure)) {
try {
await this.generateModuleFile(moduleName, components);
this.stats.createdModules++;
} catch (error) {
console.error(` ❌ 生成模块 ${moduleName} 失败:`, error.message);
this.stats.errors++;
}
}
}
/**
* 生成单个模块文件
*/
async generateModuleFile(moduleName, components) {
const modulePath = path.join(this.config.nestjsBasePath, moduleName, `${moduleName}.module.ts`);
// 生成模块内容
const moduleContent = this.generateModuleContent(moduleName, components);
// 确保目录存在
this.ensureDir(path.dirname(modulePath));
// 写入文件
fs.writeFileSync(modulePath, moduleContent);
console.log(` ✅ 创建模块: ${moduleName}/${moduleName}.module.ts`);
}
/**
* 生成模块内容
*/
generateModuleContent(moduleName, components) {
const className = this.toPascalCase(moduleName) + 'Module';
let imports = [];
let controllers = [];
let providers = [];
let exports = [];
let importSet = new Set(); // 用于去重
// TypeORM feature (可选)
const entityClassNames = components.entities.map(e => e.name).filter(Boolean);
if (this.config.includeTypeOrmFeature && entityClassNames.length > 0) {
importSet.add(`import { TypeOrmModule } from '@nestjs/typeorm';`);
imports.push(`TypeOrmModule.forFeature([${entityClassNames.join(', ')}])`);
}
// 导入控制器并注册
for (const controller of components.controllers) {
importSet.add(`import { ${controller.name} } from '${controller.path}';`);
controllers.push(controller.name);
}
// 导入服务并注册
for (const service of components.services) {
if (!importSet.has(`import { ${service.name} } from '${service.path}';`)) {
importSet.add(`import { ${service.name} } from '${service.path}';`);
providers.push(`${service.name}`);
}
}
// 导入实体(如果需要)
for (const entity of components.entities) {
if (!importSet.has(`import { ${entity.name} } from '${entity.path}';`)) {
importSet.add(`import { ${entity.name} } from '${entity.path}';`);
}
}
// 组合最终内容
const moduleContent = `${Array.from(importSet).join('\n')}
import { Module } from '@nestjs/common';
@Module({
imports: [${imports.join(', ')}],
controllers: [${controllers.join(', ')}],
providers: [${providers.join(', ')}],
exports: [${exports.join(', ')}],
})
export class ${className} {}
`;
return moduleContent;
}
/**
* 从文件内容获取导出的类名
*/
getActualClassName(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
const content = fs.readFileSync(filePath, 'utf8');
const match = content.match(/export\s+class\s+(\w+)/);
return match ? match[1] : null;
} catch (error) {
return null;
}
}
/**
* 由 kebab-case 实体文件名推测类名
* 例如: member.entity.ts -> MemberEntity
*/
guessEntityClassName(fileName) {
const base = fileName.replace(/\.entity\.ts$/i, '');
return this.kebabToPascal(base) + 'Entity';
}
/**
* 由 kebab-case 控制器文件名推测类名
* 例如: member-level.controller.ts -> MemberLevelController
*/
guessControllerClassName(fileName) {
const base = fileName.replace(/\.controller\.ts$/i, '');
return this.kebabToPascal(base) + 'Controller';
}
/**
* 由 kebab-case 服务文件名推测类名
* 例如: member-level.service.ts -> MemberLevelService
*/
guessServiceClassName(fileName, layer) {
const base = fileName.replace(/\.service\.ts$/i, '');
return this.kebabToPascal(base) + 'Service';
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 转换为PascalCase
*/
toPascalCase(str) {
return str.replace(/(^|_)([a-z])/g, (match, p1, p2) => p2.toUpperCase());
}
/**
* kebab-case 转 PascalCase
*/
kebabToPascal(str) {
return str
.split('-')
.filter(Boolean)
.map(s => s.charAt(0).toUpperCase() + s.slice(1))
.join('');
}
shouldSkipModule(moduleName) {
if (this.config.whitelistModules && this.config.whitelistModules.length > 0) {
if (!this.config.whitelistModules.includes(moduleName)) return true;
}
if (this.config.blacklistModules && this.config.blacklistModules.includes(moduleName)) {
return true;
}
return false;
}
/**
* 获取层前缀
*/
getLayerPrefix(layer, serviceName) {
// 如果服务名已经包含Core前缀则不需要再添加
if (layer === 'core' && serviceName.toLowerCase().startsWith('core')) {
return '';
}
const layerMap = {
'admin': 'Admin',
'api': 'Api',
'core': 'Core'
};
return layerMap[layer] || '';
}
/**
* 检查是否需要别名
*/
needsAlias(layer, serviceName) {
// 如果服务名已经包含层前缀,则不需要别名
if (layer === 'core' && serviceName.toLowerCase().startsWith('core')) {
return false;
}
return true;
}
/**
* 生成统计报告
*/
generateStatsReport() {
console.log('\n📊 NestJS模块生成统计报告:');
console.log('============================================================');
console.log(` 📁 创建模块: ${this.stats.createdModules}`);
console.log(` 🔄 更新模块: ${this.stats.updatedModules}`);
console.log(` ❌ 错误数量: ${this.stats.errors}`);
console.log('============================================================');
console.log('\n✅ 🎉 NestJS模块生成完成');
}
}
// 运行模块生成器
if (require.main === module) {
const generator = new ModuleGenerator();
generator.run().catch(console.error);
}
module.exports = ModuleGenerator;

View File

@@ -1,276 +0,0 @@
#!/usr/bin/env node
const { execSync } = require('child_process');
const path = require('path');
const fs = require('fs');
/**
* Quality Gate - 质量门禁工具
* 执行 TypeScript 编译检查和 ESLint 检查
*/
class QualityGate {
constructor(nestjsBasePath) {
this.nestjsBasePath = nestjsBasePath || '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1';
// Resolve project root for npm commands
this.projectRoot = this.findProjectRoot(this.nestjsBasePath) || this.nestjsBasePath;
// Resolve core directory to check (prefer libs/wwjcloud-core/src)
const libCore = path.join(this.projectRoot, 'libs', 'wwjcloud-core', 'src');
this.coreDir = libCore;
if (!fs.existsSync(this.coreDir)) {
console.warn(`⚠️ 核心目录不存在,预期为: ${this.coreDir}`);
}
this.stats = {
tsErrors: 0,
eslintErrors: 0,
eslintWarnings: 0,
filesChecked: 0
};
}
// Find nearest directory containing package.json, starting from provided path
findProjectRoot(startDir) {
let dir = startDir;
for (let i = 0; i < 4; i++) {
if (fs.existsSync(path.join(dir, 'package.json'))) return dir;
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
}
return null;
}
/**
* 运行所有质量检查
*/
async run() {
console.log('🚦 启动 Quality Gate 检查...\n');
let passed = true;
// TypeScript 编译检查
console.log('📝 第1阶段TypeScript 编译检查...');
const tsResult = await this.checkTypeScript();
if (!tsResult) {
passed = false;
console.log(' ❌ TypeScript 编译检查失败\n');
} else {
console.log(' ✅ TypeScript 编译检查通过\n');
}
// ESLint 检查
console.log('📝 第2阶段ESLint 代码规范检查...');
const eslintResult = await this.checkESLint();
if (!eslintResult) {
passed = false;
console.log(' ❌ ESLint 检查失败\n');
} else {
console.log(' ✅ ESLint 检查通过\n');
}
// 输出统计报告
this.printStats();
return passed;
}
/**
* TypeScript 编译检查
*/
async checkTypeScript() {
try {
console.log(' 🔍 检查 TypeScript 类型...');
const result = execSync('npm run type-check', {
cwd: this.projectRoot,
encoding: 'utf8',
stdio: 'pipe'
});
console.log(' ✅ TypeScript 类型检查通过');
return true;
} catch (error) {
this.stats.tsErrors++;
if (error.stdout) {
console.error(' ❌ TypeScript 错误:');
console.error(error.stdout);
}
if (error.stderr) {
console.error(error.stderr);
}
return false;
}
}
/**
* ESLint 检查
*/
async checkESLint() {
try {
console.log(' 🔍 检查代码规范...');
const result = execSync('npm run lint', {
cwd: this.projectRoot,
encoding: 'utf8',
stdio: 'pipe'
});
console.log(' ✅ ESLint 检查通过');
return true;
} catch (error) {
// ESLint 返回非零退出码表示有错误或警告
if (error.stdout) {
const output = error.stdout;
// 解析错误和警告数量
const errorMatch = output.match(/(\d+)\s+errors?/);
const warningMatch = output.match(/(\d+)\s+warnings?/);
if (errorMatch) {
this.stats.eslintErrors = parseInt(errorMatch[1]);
}
if (warningMatch) {
this.stats.eslintWarnings = parseInt(warningMatch[1]);
}
console.error(' ❌ ESLint 发现问题:');
console.error(output);
// 如果只有警告,不算失败
return this.stats.eslintErrors === 0;
}
return false;
}
}
/**
* 检查单个文件
*/
async checkFile(filePath) {
console.log(` 🔍 检查文件: ${filePath}`);
try {
execSync(`npx tsc --noEmit ${filePath}`, {
cwd: this.projectRoot,
encoding: 'utf8',
stdio: 'pipe'
});
execSync(`npx eslint ${filePath}`, {
cwd: this.projectRoot,
encoding: 'utf8',
stdio: 'pipe'
});
this.stats.filesChecked++;
return true;
} catch (error) {
console.error(` ❌ 文件检查失败: ${filePath}`);
if (error.stdout) {
console.error(error.stdout);
}
return false;
}
}
/**
* 快速检查(只检查核心层)
*/
async quickCheck() {
console.log('🚀 快速质量检查(仅核心层)...\n');
const coreFiles = this.getGeneratedFiles();
console.log(` 📁 发现 ${coreFiles.length} 个生成的文件\n`);
let passed = 0;
let failed = 0;
for (const file of coreFiles) {
const result = await this.checkFile(file);
if (result) {
passed++;
} else {
failed++;
}
}
console.log(`\n📊 快速检查结果:`);
console.log(` ✅ 通过: ${passed}`);
console.log(` ❌ 失败: ${failed}`);
return failed === 0;
}
/**
* 获取所有生成的文件
*/
getGeneratedFiles() {
const coreDir = this.coreDir;
const files = [];
const scanDir = (dir) => {
if (!fs.existsSync(dir)) return;
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
scanDir(fullPath);
} else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) {
files.push(fullPath);
}
}
};
scanDir(coreDir);
return files;
}
/**
* 输出统计报告
*/
printStats() {
console.log('📊 Quality Gate 统计报告');
console.log('==================================================');
console.log(` 📝 TypeScript 错误: ${this.stats.tsErrors}`);
console.log(` 📝 ESLint 错误: ${this.stats.eslintErrors}`);
console.log(` ⚠️ ESLint 警告: ${this.stats.eslintWarnings}`);
console.log(` 📁 检查文件数: ${this.stats.filesChecked}`);
console.log('==================================================');
const passed = this.stats.tsErrors === 0 && this.stats.eslintErrors === 0;
if (passed) {
console.log('\n✅ 🎉 所有质量检查通过!');
} else {
console.log('\n❌ 质量检查失败,请修复上述问题');
console.log('提示: 运行 "npm run lint:fix" 自动修复部分问题');
}
return passed;
}
}
// 如果直接运行此文件
if (require.main === module) {
const args = process.argv.slice(2);
const mode = args[0] || 'full';
const gate = new QualityGate();
if (mode === 'quick') {
gate.quickCheck().then(passed => {
process.exit(passed ? 0 : 1);
});
} else {
gate.run().then(passed => {
process.exit(passed ? 0 : 1);
});
}
}
module.exports = QualityGate;

View File

@@ -1,145 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
/**
* 🛣️ 路由生成器
* 专门负责生成NestJS路由文件 (参考Java架构)
*/
class RouteGenerator {
constructor(config = null) {
if (config) {
this.config = config;
} else {
const projectRoot = path.resolve(__dirname, '../../../../..');
this.config = {
javaBasePath: path.join(projectRoot, 'niucloud-java/niucloud-core/src/main/java'),
phpBasePath: path.join(projectRoot, 'niucloud-php/niucloud'),
nestjsBasePath: path.join(projectRoot, 'wwjcloud-nest-v1/libs/wwjcloud-core/src'),
discoveryResultPath: path.join(__dirname, '../java-discovery-result.json')
};
}
this.discoveryData = null;
this.stats = {
routesCreated: 0,
errors: 0
};
}
/**
* 运行路由生成
*/
async run() {
try {
console.log('🛣️ 启动路由生成器...');
console.log('目标生成NestJS路由文件\n');
// 加载Java架构发现结果含PHP业务逻辑
await this.loadDiscoveryData();
// 生成路由
await this.generateRoutes();
// 输出统计报告
this.printStats();
} catch (error) {
console.error('❌ 路由生成失败:', error);
this.stats.errors++;
}
}
/**
* 加载Java架构发现结果含PHP业务逻辑
*/
async loadDiscoveryData() {
try {
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8');
this.discoveryData = JSON.parse(data);
console.log(' ✅ 成功加载Java架构发现结果含PHP业务逻辑');
} catch (error) {
console.error('❌ 加载发现结果失败:', error);
throw error;
}
}
/**
* 生成路由
*/
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} 个路由`);
}
/**
* 创建路由 - NestJS不需要独立路由文件
*/
async createRoute(layerName, routeName, routeInfo) {
// NestJS不需要独立的路由文件
// 路由在控制器中定义模块路由在app.module.ts中配置
console.log(` ⏭️ 跳过路由: ${layerName}/${this.toCamelCase(routeName)}.route.ts (NestJS不需要独立路由文件)`);
return;
}
/**
* 生成路由内容 - NestJS不需要独立的路由文件
* 路由在控制器中定义,这里生成模块路由配置
*/
generateRouteContent(layerName, routeName) {
// NestJS不需要独立的路由文件
// 路由应该在控制器中定义模块路由在app.module.ts中配置
return null;
}
/**
* 转换为PascalCase
*/
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 转换为camelCase
*/
toCamelCase(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
}
/**
* 确保目录存在
*/
ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 输出统计报告
*/
printStats() {
console.log('\n📊 路由生成统计报告');
console.log('==================================================');
console.log(`✅ 创建路由数量: ${this.stats.routesCreated}`);
console.log(`❌ 错误数量: ${this.stats.errors}`);
console.log(`📈 成功率: ${this.stats.routesCreated > 0 ? '100.00%' : '0.00%'}`);
}
}
// 如果直接运行此文件
if (require.main === module) {
const generator = new RouteGenerator();
generator.run().catch(console.error);
}
module.exports = RouteGenerator;

View File

@@ -1,380 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
/**
* 📝 验证器生成器
* 专门负责生成NestJS验证器/DTO文件 (参考Java架构)
*/
class ValidatorGenerator {
constructor(config = null) {
// 使用传入的配置或默认配置
if (config) {
this.config = config;
} else {
// 动态路径配置
const projectRoot = path.resolve(__dirname, '../../../../..');
this.config = {
javaBasePath: path.join(projectRoot, 'niucloud-java/niucloud-core/src/main/java'),
phpBasePath: path.join(projectRoot, 'niucloud-php/niucloud'),
nestjsBasePath: path.join(projectRoot, 'wwjcloud-nest-v1/libs/wwjcloud-core/src'),
discoveryResultPath: path.join(__dirname, '../java-discovery-result.json')
};
}
this.discoveryData = null;
this.stats = {
validatorsCreated: 0,
errors: 0
};
}
/**
* 运行验证器生成
*/
async run() {
try {
console.log('📝 启动验证器生成器...');
console.log('目标生成NestJS验证器/DTO文件\n');
// 加载Java架构发现结果含PHP业务逻辑
await this.loadDiscoveryData();
// 生成验证器
await this.generateValidators();
// 输出统计报告
this.printStats();
} catch (error) {
console.error('❌ 验证器生成失败:', error);
this.stats.errors++;
}
}
/**
* 加载Java架构发现结果含PHP业务逻辑
*/
async loadDiscoveryData() {
try {
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8');
this.discoveryData = JSON.parse(data);
console.log(' ✅ 成功加载Java架构发现结果含PHP业务逻辑');
} catch (error) {
console.error('❌ 加载发现结果失败:', error);
throw error;
}
}
/**
* 生成验证器
*/
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 createValidator(moduleName, validateName, validateInfo) {
const validatorDir = path.join(this.config.nestjsBasePath, moduleName, 'dto');
this.ensureDir(validatorDir);
const validatorPath = path.join(
validatorDir,
`${this.toPascalCase(validateName)}Dto.ts`
);
const content = this.generateValidatorContent(moduleName, validateName);
if (content) {
fs.writeFileSync(validatorPath, content);
console.log(` ✅ 创建验证器: ${moduleName}/${this.toPascalCase(validateName)}Dto.ts`);
} else {
console.log(` ⚠️ 跳过验证器生成: ${moduleName}/${this.toPascalCase(validateName)}Dto.ts (无PHP源码)`);
}
}
/**
* 生成验证器内容 - 基于真实PHP验证器
*/
generateValidatorContent(moduleName, validateName) {
const className = `${this.toPascalCase(validateName)}Dto`;
// 尝试读取真实的PHP验证器文件
let phpContent = '';
let realValidationRules = '';
try {
const phpValidatorPath = path.join(this.config.phpBasePath, 'app/validate', moduleName, `${validateName}.php`);
if (fs.existsSync(phpValidatorPath)) {
phpContent = fs.readFileSync(phpValidatorPath, 'utf-8');
realValidationRules = this.extractValidationRulesFromPHP(phpContent, validateName);
console.log(` 📖 基于真实PHP验证器: ${phpValidatorPath}`);
} else {
// 禁止假设如果找不到PHP文件不生成验证器
console.log(` ❌ 未找到PHP验证器文件跳过生成: ${phpValidatorPath}`);
return null;
}
} catch (error) {
// 禁止假设,如果读取失败,不生成验证器
console.log(` ❌ 读取PHP验证器文件失败跳过生成: ${error.message}`);
return null;
}
const content = `import { IsString, IsNumber, IsOptional, IsNotEmpty, IsEmail, IsUrl, IsArray, IsObject, validateSync } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
/**
* ${className} - 数据传输对象
* 基于真实PHP验证器规则生成禁止假设字段
* 使用Core层基础设施class-validator + Swagger文档
*/
export class ${className} {
${realValidationRules}
}
/**
* ${className} 验证器类
* 使用 class-validator 进行同步验证
*/
export class ${className}Validator {
/**
* 验证数据
* 使用 class-validator 统一验证
*/
static validate(data: ${className}): void {
const instance = Object.assign(new ${className}(), data);
const errors = validateSync(instance, { whitelist: true });
if (errors && errors.length > 0) {
const messages = errors.map(e => Object.values(e.constraints || {}).join(';')).filter(Boolean);
throw new Error(messages.join('\n'));
}
}
/**
* 验证场景 - 基于真实PHP的$scene
*/
static validateAdd(data: ${className}): void {
// 基于真实PHP add场景验证规则
this.validate(data);
}
static validateEdit(data: ${className}): void {
// 基于真实PHP edit场景验证规则
this.validate(data);
}
}
export class Create${this.toPascalCase(validateName)}Dto {
// 字段定义需要基于真实PHP验证器解析
// 禁止假设字段
// 使用Core层基础设施class-validator装饰器、Swagger文档
}
export class Update${this.toPascalCase(validateName)}Dto {
// 字段定义需要基于真实PHP验证器解析
// 禁止假设字段
// 使用Core层基础设施class-validator装饰器、Swagger文档
}
export class Query${this.toPascalCase(validateName)}Dto {
// 字段定义需要基于真实PHP验证器解析
// 禁止假设字段
// 使用Core层基础设施class-validator装饰器、Swagger文档
}
`;
return content;
}
/**
* 从PHP验证器内容中提取验证规则
*/
extractValidationRulesFromPHP(phpContent, validateName) {
// 提取验证规则
const ruleMatch = phpContent.match(/protected\s+\$rule\s*=\s*\[([\s\S]*?)\];/);
const messageMatch = phpContent.match(/protected\s+\$message\s*=\s*\[([\s\S]*?)\];/);
const sceneMatch = phpContent.match(/protected\s+\$scene\s*=\s*\[([\s\S]*?)\];/);
if (ruleMatch) {
console.log(` 📖 找到PHP验证规则: ${validateName}`);
// 解析规则内容
return this.parsePHPValidationRules(ruleMatch[1], messageMatch ? messageMatch[1] : '', sceneMatch ? sceneMatch[1] : '');
}
return '';
}
/**
* 解析PHP验证规则
*/
parsePHPValidationRules(rulesContent, messagesContent, scenesContent) {
const fields = [];
// 解析规则
const ruleMatches = rulesContent.match(/(['"][^'"]*['"])\s*=>\s*(['"][^'"]*['"])/g);
if (ruleMatches) {
ruleMatches.forEach(match => {
const fieldMatch = match.match(/(['"][^'"]*['"])\s*=>\s*(['"][^'"]*['"])/);
if (fieldMatch) {
const fieldName = fieldMatch[1].replace(/['"]/g, '');
const fieldRules = fieldMatch[2].replace(/['"]/g, '');
// 解析规则类型
const fieldType = this.parseFieldType(fieldRules);
const validators = this.parseValidators(fieldRules);
fields.push({
name: fieldName,
type: fieldType,
validators: validators,
rules: fieldRules
});
}
});
}
// 生成DTO字段
const dtoFields = fields.map(field => {
const validatorsStr = field.validators.map(v => `@${v}()`).join('\n ');
return ` @ApiProperty({ description: ${JSON.stringify(field.name)} })
${validatorsStr}
${this.toCamelCase(field.name)}: ${field.type};`;
}).join('\n\n');
return dtoFields;
}
/**
* 解析字段类型
*/
parseFieldType(rules) {
if (rules.includes('number') || rules.includes('integer')) {
return 'number';
} else if (rules.includes('email')) {
return 'string';
} else if (rules.includes('url')) {
return 'string';
} else if (rules.includes('array')) {
return 'any[]';
} else if (rules.includes('object')) {
return 'object';
} else {
return 'string';
}
}
/**
* 解析验证器
*/
parseValidators(rules) {
const validators = [];
if (rules.includes('require')) {
validators.push('IsNotEmpty');
}
if (rules.includes('number') || rules.includes('integer')) {
validators.push('IsNumber');
} else if (rules.includes('email')) {
validators.push('IsEmail');
} else if (rules.includes('url')) {
validators.push('IsUrl');
} else if (rules.includes('array')) {
validators.push('IsArray');
} else if (rules.includes('object')) {
validators.push('IsObject');
} else {
validators.push('IsString');
}
return validators;
}
/**
* 转换为PascalCase - 处理连字符
*/
toPascalCase(str) {
return str.replace(/(^|-)([a-z])/g, (match, p1, p2) => p2.toUpperCase());
}
/**
* 转换为camelCase
*/
toCamelCase(str) {
return str.charAt(0).toLowerCase() + str.slice(1);
}
toPascalCase(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
/**
* 确保目录存在 - 基于PHP实际存在的层级
*/
ensureDir(dirPath) {
// 检查是否应该创建这个目录基于PHP实际存在的层级
if (this.shouldCreateDir(dirPath)) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
}
/**
* 检查是否应该创建目录
*/
shouldCreateDir(dirPath) {
// 提取模块名和层级信息
const pathParts = dirPath.split('/');
const moduleIndex = pathParts.indexOf('common') + 1;
if (moduleIndex < pathParts.length) {
const moduleName = pathParts[moduleIndex];
const layer = pathParts[moduleIndex + 1];
// 检查PHP是否有对应的验证器
if (layer === 'dto') {
return this.hasPHPValidators(moduleName);
}
}
return true; // 默认创建
}
/**
* 检查模块是否有PHP验证器
*/
hasPHPValidators(moduleName) {
const phpProjectPath = path.join(__dirname, '../../niucloud-php/niucloud');
const validatePath = path.join(phpProjectPath, 'app/validate', moduleName);
return fs.existsSync(validatePath);
}
/**
* 输出统计报告
*/
printStats() {
console.log('\n📊 验证器生成统计报告');
console.log('==================================================');
console.log(`✅ 创建验证器数量: ${this.stats.validatorsCreated}`);
console.log(`❌ 错误数量: ${this.stats.errors}`);
console.log(`📈 成功率: ${this.stats.validatorsCreated > 0 ? '100.00%' : '0.00%'}`);
}
}
// 如果直接运行此文件
if (require.main === module) {
const generator = new ValidatorGenerator();
generator.run().catch(console.error);
}
module.exports = ValidatorGenerator;

View File

@@ -1,186 +0,0 @@
#!/usr/bin/env node
const IncrementalUpdater = require('./incremental-updater');
/**
* 🔄 增量更新命令行工具
* 提供独立的增量更新功能入口
*/
function showHelp() {
console.log(`
🔄 增量更新工具 - WWJCloud PHP to NestJS
用法:
node incremental-update-cli.js [选项]
选项:
--help, -h 显示帮助信息
--dry-run 干运行模式,不实际修改文件
--verbose, -v 详细输出模式
--force 强制更新,忽略冲突警告
--backup 创建备份(默认启用)
--no-backup 不创建备份
环境变量:
DRY_RUN=true 启用干运行模式
VERBOSE=true 启用详细输出
FORCE=true 启用强制模式
示例:
# 基本增量更新
node incremental-update-cli.js
# 干运行模式(查看将要进行的更改)
node incremental-update-cli.js --dry-run
# 详细输出模式
node incremental-update-cli.js --verbose
# 强制更新模式
node incremental-update-cli.js --force
# 使用环境变量
DRY_RUN=true node incremental-update-cli.js
功能特性:
✅ 智能变更检测 - 基于文件哈希和时间戳
✅ 用户代码保护 - 自动检测和保护用户自定义代码
✅ 三路合并算法 - 智能合并PHP变更和用户修改
✅ 冲突处理机制 - 自动标记和处理合并冲突
✅ 备份恢复功能 - 自动创建备份,支持快速恢复
✅ 增量状态跟踪 - 记录更新历史和文件状态
✅ 详细更新报告 - 提供完整的更新统计和结果
注意事项:
- 首次运行将建立基线状态
- 建议在重要更新前手动备份
- 冲突文件需要手动解决
- 支持回滚到任意历史版本
`);
}
async function main() {
const args = process.argv.slice(2);
// 处理帮助选项
if (args.includes('--help') || args.includes('-h')) {
showHelp();
return;
}
// 解析命令行参数
const options = {
dryRun: args.includes('--dry-run') || process.env.DRY_RUN === 'true',
verbose: args.includes('--verbose') || args.includes('-v') || process.env.VERBOSE === 'true',
force: args.includes('--force') || process.env.FORCE === 'true',
backup: !args.includes('--no-backup')
};
console.log('🔄 WWJCloud 增量更新工具');
console.log('==================================================');
if (options.dryRun) {
console.log('🔍 运行模式: 干运行 (不会实际修改文件)');
}
if (options.verbose) {
console.log('📝 输出模式: 详细输出');
}
if (options.force) {
console.log('⚡ 更新模式: 强制更新');
}
if (!options.backup) {
console.log('⚠️ 备份模式: 已禁用备份');
}
console.log('==================================================\n');
try {
// 设置环境变量
if (options.dryRun) {
process.env.DRY_RUN = 'true';
}
if (options.verbose) {
process.env.VERBOSE = 'true';
}
if (options.force) {
process.env.FORCE = 'true';
}
if (!options.backup) {
process.env.NO_BACKUP = 'true';
}
// 创建并运行增量更新器
const updater = new IncrementalUpdater();
const success = await updater.run();
if (success) {
console.log('\n✅ 增量更新成功完成!');
if (options.dryRun) {
console.log('\n💡 提示: 这是干运行模式,没有实际修改文件');
console.log(' 要执行实际更新,请移除 --dry-run 参数');
}
process.exit(0);
} else {
console.log('\n❌ 增量更新失败');
process.exit(1);
}
} catch (error) {
console.error('\n💥 增量更新过程中发生错误:');
console.error(error.message);
if (options.verbose) {
console.error('\n📋 详细错误信息:');
console.error(error.stack);
}
console.log('\n🔧 故障排除建议:');
console.log('1. 检查PHP项目路径是否正确');
console.log('2. 检查NestJS项目路径是否正确');
console.log('3. 确保有足够的文件系统权限');
console.log('4. 尝试使用 --dry-run 模式查看详细信息');
console.log('5. 查看备份目录是否有可恢复的版本');
process.exit(1);
}
}
// 处理未捕获的异常
process.on('unhandledRejection', (reason, promise) => {
console.error('💥 未处理的Promise拒绝:', reason);
process.exit(1);
});
process.on('uncaughtException', (error) => {
console.error('💥 未捕获的异常:', error);
process.exit(1);
});
// 处理中断信号
process.on('SIGINT', () => {
console.log('\n\n⏹ 用户中断操作');
console.log('增量更新已停止');
process.exit(0);
});
process.on('SIGTERM', () => {
console.log('\n\n⏹ 收到终止信号');
console.log('增量更新已停止');
process.exit(0);
});
// 运行主程序
if (require.main === module) {
main();
}
module.exports = { main, showHelp };

View File

@@ -1,774 +0,0 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { execSync } = require('child_process');
/**
* 🔄 增量更新器
* 智能检测Java项目变更实现增量迁移到NestJS (参考Java架构)
*/
class IncrementalUpdater {
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',
stateFilePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/tools-v1/java-tools/.incremental-state.json',
backupPath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/tools-v1/java-tools/backups',
dryRun: process.env.DRY_RUN === 'true'
};
this.state = {
lastUpdate: null,
fileHashes: {},
migrationHistory: [],
userModifications: {},
conflicts: []
};
this.stats = {
filesChanged: 0,
filesAdded: 0,
filesDeleted: 0,
conflictsDetected: 0,
autoMerged: 0,
manualMergeRequired: 0
};
}
/**
* 🚀 执行增量更新
*/
async run() {
console.log('🔄 启动增量更新器...');
console.log(`📁 Java架构参考: ${this.config.javaBasePath}`);
console.log(`📁 PHP业务逻辑源: ${this.config.phpBasePath}`);
console.log(`📁 NestJS项目: ${this.config.nestjsBasePath}`);
console.log(`🔍 Dry-run模式: ${this.config.dryRun ? '是' : '否'}\n`);
try {
// 1. 加载上次更新状态
await this.loadState();
// 2. 检测Java架构变更参考Java提取PHP业务逻辑
const changes = await this.detectChanges();
if (changes.length === 0) {
console.log('✅ 没有检测到变更,无需更新');
return;
}
console.log(`📊 检测到 ${changes.length} 个变更文件`);
// 3. 分析变更类型
const changeAnalysis = await this.analyzeChanges(changes);
// 4. 检测用户自定义修改
await this.detectUserModifications();
// 5. 执行智能合并
const mergeResults = await this.performSmartMerge(changeAnalysis);
// 6. 生成更新报告
this.generateUpdateReport(mergeResults);
// 7. 保存新状态
if (!this.config.dryRun) {
await this.saveState();
}
} catch (error) {
console.error('❌ 增量更新失败:', error.message);
throw error;
}
}
/**
* 📂 加载上次更新状态
*/
async loadState() {
try {
if (fs.existsSync(this.config.stateFilePath)) {
const data = fs.readFileSync(this.config.stateFilePath, 'utf8');
this.state = { ...this.state, ...JSON.parse(data) };
console.log(`📋 加载状态: 上次更新时间 ${this.state.lastUpdate || '从未更新'}`);
} else {
console.log('📋 首次运行,创建新状态');
}
} catch (error) {
console.log(`⚠️ 加载状态失败,使用默认状态: ${error.message}`);
}
}
/**
* 🔍 检测Java架构变更 (参考Java架构提取PHP业务逻辑)
*/
async detectChanges() {
console.log('🔍 检测Java架构变更 (参考Java架构)...');
const changes = [];
const phpFiles = this.getAllPHPFiles();
for (const filePath of phpFiles) {
const relativePath = path.relative(this.config.phpBasePath, filePath);
const currentHash = this.calculateFileHash(filePath);
const lastHash = this.state.fileHashes[relativePath];
if (!lastHash) {
// 新文件
changes.push({
type: 'added',
path: relativePath,
fullPath: filePath,
hash: currentHash
});
this.stats.filesAdded++;
} else if (currentHash !== lastHash) {
// 修改的文件
changes.push({
type: 'modified',
path: relativePath,
fullPath: filePath,
hash: currentHash,
oldHash: lastHash
});
this.stats.filesChanged++;
}
// 更新哈希
this.state.fileHashes[relativePath] = currentHash;
}
// 检测删除的文件
for (const [relativePath, hash] of Object.entries(this.state.fileHashes)) {
const fullPath = path.join(this.config.phpBasePath, relativePath);
if (!fs.existsSync(fullPath)) {
changes.push({
type: 'deleted',
path: relativePath,
fullPath: fullPath,
hash: hash
});
this.stats.filesDeleted++;
delete this.state.fileHashes[relativePath];
}
}
return changes;
}
/**
* 📊 分析变更类型
*/
async analyzeChanges(changes) {
console.log('📊 分析变更类型...');
const analysis = {
controllers: [],
services: [],
models: [],
validators: [],
others: []
};
for (const change of changes) {
const category = this.categorizeFile(change.path);
analysis[category].push(change);
console.log(` ${this.getChangeIcon(change.type)} ${change.type.toUpperCase()}: ${change.path} (${category})`);
}
return analysis;
}
/**
* 🔍 检测用户自定义修改
*/
async detectUserModifications() {
console.log('🔍 检测用户自定义修改...');
const nestjsFiles = this.getAllNestJSFiles();
for (const filePath of nestjsFiles) {
const relativePath = path.relative(this.config.nestjsBasePath, filePath);
const content = fs.readFileSync(filePath, 'utf8');
// 检测用户自定义标记
const userModifications = this.detectUserCode(content);
if (userModifications.length > 0) {
this.state.userModifications[relativePath] = userModifications;
console.log(` 🔧 检测到用户修改: ${relativePath} (${userModifications.length}处)`);
}
}
}
/**
* 🤖 执行智能合并
*/
async performSmartMerge(changeAnalysis) {
console.log('🤖 执行智能合并...');
const mergeResults = {
autoMerged: [],
conflicts: [],
skipped: []
};
// 创建备份
if (!this.config.dryRun) {
await this.createBackup();
}
// 处理各类变更
for (const [category, changes] of Object.entries(changeAnalysis)) {
if (changes.length === 0) continue;
console.log(`\n📋 处理 ${category} 变更 (${changes.length}个文件):`);
for (const change of changes) {
const result = await this.mergeFile(change, category);
mergeResults[result.status].push(result);
console.log(` ${this.getMergeIcon(result.status)} ${change.path}: ${result.message}`);
}
}
return mergeResults;
}
/**
* 🔀 合并单个文件
*/
async mergeFile(change, category) {
const nestjsPath = this.mapPHPToNestJS(change.path, category);
if (!nestjsPath) {
return {
status: 'skipped',
change: change,
message: '无对应的NestJS文件映射'
};
}
const nestjsFullPath = path.join(this.config.nestjsBasePath, nestjsPath);
// 检查是否存在用户修改
const hasUserModifications = this.state.userModifications[nestjsPath];
if (change.type === 'deleted') {
return await this.handleDeletedFile(change, nestjsFullPath, hasUserModifications);
}
if (change.type === 'added') {
return await this.handleAddedFile(change, nestjsFullPath, category);
}
if (change.type === 'modified') {
return await this.handleModifiedFile(change, nestjsFullPath, hasUserModifications, category);
}
}
/**
* 处理新增文件
*/
async handleAddedFile(change, nestjsPath, category) {
if (fs.existsSync(nestjsPath)) {
return {
status: 'conflicts',
change: change,
message: 'NestJS文件已存在需要手动处理'
};
}
if (this.config.dryRun) {
return {
status: 'autoMerged',
change: change,
message: '[DRY-RUN] 将生成新的NestJS文件'
};
}
// 生成NestJS文件
const success = await this.generateNestJSFile(change.fullPath, nestjsPath, category);
if (success) {
this.stats.autoMerged++;
return {
status: 'autoMerged',
change: change,
message: '成功生成新的NestJS文件'
};
} else {
return {
status: 'conflicts',
change: change,
message: '生成NestJS文件失败'
};
}
}
/**
* ✏️ 处理修改文件
*/
async handleModifiedFile(change, nestjsPath, hasUserModifications, category) {
if (!fs.existsSync(nestjsPath)) {
// NestJS文件不存在直接生成
return await this.handleAddedFile(change, nestjsPath, category);
}
if (hasUserModifications) {
// 存在用户修改,需要智能合并
return await this.performIntelligentMerge(change, nestjsPath, category);
}
if (this.config.dryRun) {
return {
status: 'autoMerged',
change: change,
message: '[DRY-RUN] 将重新生成NestJS文件'
};
}
// 没有用户修改,直接重新生成
const success = await this.generateNestJSFile(change.fullPath, nestjsPath, category);
if (success) {
this.stats.autoMerged++;
return {
status: 'autoMerged',
change: change,
message: '成功重新生成NestJS文件'
};
} else {
return {
status: 'conflicts',
change: change,
message: '重新生成NestJS文件失败'
};
}
}
/**
* 🗑️ 处理删除文件
*/
async handleDeletedFile(change, nestjsPath, hasUserModifications) {
if (!fs.existsSync(nestjsPath)) {
return {
status: 'autoMerged',
change: change,
message: 'NestJS文件已不存在'
};
}
if (hasUserModifications) {
return {
status: 'conflicts',
change: change,
message: '文件包含用户修改,需要手动决定是否删除'
};
}
if (this.config.dryRun) {
return {
status: 'autoMerged',
change: change,
message: '[DRY-RUN] 将删除对应的NestJS文件'
};
}
// 删除NestJS文件
fs.unlinkSync(nestjsPath);
this.stats.autoMerged++;
return {
status: 'autoMerged',
change: change,
message: '成功删除对应的NestJS文件'
};
}
/**
* 🧠 执行智能合并
*/
async performIntelligentMerge(change, nestjsPath, category) {
console.log(` 🧠 智能合并: ${change.path}`);
// 读取现有NestJS文件
const existingContent = fs.readFileSync(nestjsPath, 'utf8');
// 生成新的NestJS内容
const newContent = await this.generateNestJSContent(change.fullPath, category);
if (!newContent) {
return {
status: 'conflicts',
change: change,
message: '无法生成新的NestJS内容'
};
}
// 执行三路合并
const mergeResult = this.performThreeWayMerge(existingContent, newContent, change);
if (mergeResult.hasConflicts) {
this.stats.conflictsDetected++;
// 保存冲突文件
const conflictPath = `${nestjsPath}.conflict`;
if (!this.config.dryRun) {
fs.writeFileSync(conflictPath, mergeResult.conflictContent);
}
return {
status: 'conflicts',
change: change,
message: `存在合并冲突,冲突文件保存为: ${conflictPath}`
};
}
if (this.config.dryRun) {
return {
status: 'autoMerged',
change: change,
message: '[DRY-RUN] 将执行智能合并'
};
}
// 保存合并结果
fs.writeFileSync(nestjsPath, mergeResult.mergedContent);
this.stats.autoMerged++;
return {
status: 'autoMerged',
change: change,
message: '成功执行智能合并'
};
}
/**
* 🔀 执行三路合并
*/
performThreeWayMerge(existingContent, newContent, change) {
// 简化的三路合并实现
// 在实际项目中,可以使用更复杂的合并算法
const userSections = this.extractUserSections(existingContent);
const generatedSections = this.extractGeneratedSections(newContent);
let mergedContent = newContent;
let hasConflicts = false;
let conflictContent = '';
// 尝试保留用户自定义部分
for (const userSection of userSections) {
const insertPosition = this.findInsertPosition(mergedContent, userSection);
if (insertPosition !== -1) {
// 可以安全插入
mergedContent = this.insertUserSection(mergedContent, userSection, insertPosition);
} else {
// 存在冲突
hasConflicts = true;
conflictContent += `\n<<<<<<< 用户修改\n${userSection.content}\n=======\n`;
conflictContent += `${this.getConflictingSection(newContent, userSection)}\n>>>>>>> 新生成\n`;
}
}
return {
mergedContent,
hasConflicts,
conflictContent: hasConflicts ? existingContent + '\n\n' + conflictContent : ''
};
}
/**
* 🏷️ 检测用户代码
*/
detectUserCode(content) {
const userModifications = [];
// 检测用户自定义注释
const userCommentRegex = /\/\*\s*USER_CUSTOM_START\s*\*\/([\s\S]*?)\/\*\s*USER_CUSTOM_END\s*\*\//g;
let match;
while ((match = userCommentRegex.exec(content)) !== null) {
userModifications.push({
type: 'custom_block',
content: match[1].trim(),
start: match.index,
end: match.index + match[0].length
});
}
// 检测手动添加的方法
const methodRegex = /\/\*\s*@user-added\s*\*\/\s*([\s\S]*?)(?=\/\*|$)/g;
while ((match = methodRegex.exec(content)) !== null) {
userModifications.push({
type: 'user_method',
content: match[1].trim(),
start: match.index,
end: match.index + match[0].length
});
}
return userModifications;
}
/**
* 🗂️ 文件分类
*/
categorizeFile(filePath) {
if (filePath.includes('/controller/')) return 'controllers';
if (filePath.includes('/service/')) return 'services';
if (filePath.includes('/model/')) return 'models';
if (filePath.includes('/validate/')) return 'validators';
return 'others';
}
/**
* 🗺️ PHP到NestJS文件映射
*/
mapPHPToNestJS(phpPath, category) {
// 简化的映射逻辑,实际项目中需要更复杂的映射规则
const baseName = path.basename(phpPath, '.php');
const dirName = path.dirname(phpPath);
switch (category) {
case 'controllers':
return `${dirName}/${baseName.toLowerCase()}.controller.ts`;
case 'services':
return `${dirName}/${baseName.toLowerCase()}.service.ts`;
case 'models':
return `${dirName}/entity/${baseName.toLowerCase()}.entity.ts`;
case 'validators':
return `${dirName}/${baseName.toLowerCase()}.validator.ts`;
default:
return null;
}
}
/**
* 📁 获取所有PHP文件
*/
getAllPHPFiles() {
const files = [];
const scanDir = (dir) => {
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
scanDir(fullPath);
} else if (item.endsWith('.php')) {
files.push(fullPath);
}
}
};
scanDir(this.config.phpBasePath);
return files;
}
/**
* 📁 获取所有NestJS文件
*/
getAllNestJSFiles() {
const files = [];
const scanDir = (dir) => {
if (!fs.existsSync(dir)) return;
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
scanDir(fullPath);
} else if (item.endsWith('.ts')) {
files.push(fullPath);
}
}
};
scanDir(this.config.nestjsBasePath);
return files;
}
/**
* 🔐 计算文件哈希
*/
calculateFileHash(filePath) {
const content = fs.readFileSync(filePath);
return crypto.createHash('md5').update(content).digest('hex');
}
/**
* 💾 创建备份
*/
async createBackup() {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupDir = path.join(this.config.backupPath, timestamp);
if (!fs.existsSync(this.config.backupPath)) {
fs.mkdirSync(this.config.backupPath, { recursive: true });
}
fs.mkdirSync(backupDir, { recursive: true });
// 复制NestJS项目到备份目录
this.copyDirectory(this.config.nestjsBasePath, backupDir);
console.log(`💾 创建备份: ${backupDir}`);
}
/**
* 📋 复制目录
*/
copyDirectory(src, dest) {
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest, { recursive: true });
}
const items = fs.readdirSync(src);
for (const item of items) {
const srcPath = path.join(src, item);
const destPath = path.join(dest, item);
const stat = fs.statSync(srcPath);
if (stat.isDirectory()) {
this.copyDirectory(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
}
/**
* 🏗️ 生成NestJS文件
*/
async generateNestJSFile(phpPath, nestjsPath, category) {
// 这里应该调用相应的生成器
// 为了简化,这里只是创建一个占位符
const content = await this.generateNestJSContent(phpPath, category);
if (!content) return false;
// 确保目录存在
const dir = path.dirname(nestjsPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(nestjsPath, content);
return true;
}
/**
* 📝 生成NestJS内容
*/
async generateNestJSContent(phpPath, category) {
// 这里应该调用相应的转换器
// 为了简化,返回一个基本模板
const className = path.basename(phpPath, '.php');
switch (category) {
case 'controllers':
return `import { Controller } from '@nestjs/common';\n\n@Controller()\nexport class ${className}Controller {\n // Generated from ${phpPath}\n}\n`;
case 'services':
return `import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class ${className}Service {\n // Generated from ${phpPath}\n}\n`;
case 'models':
return `import { Entity } from 'typeorm';\n\n@Entity()\nexport class ${className} {\n // Generated from ${phpPath}\n}\n`;
default:
return `// Generated from ${phpPath}\nexport class ${className} {\n}\n`;
}
}
/**
* 📊 生成更新报告
*/
generateUpdateReport(mergeResults) {
console.log('\n📊 增量更新报告');
console.log('==================================================');
console.log(`📁 文件变更统计:`);
console.log(` 新增: ${this.stats.filesAdded}`);
console.log(` ✏️ 修改: ${this.stats.filesChanged}`);
console.log(` 🗑️ 删除: ${this.stats.filesDeleted}`);
console.log(`\n🔀 合并结果统计:`);
console.log(` ✅ 自动合并: ${mergeResults.autoMerged.length}`);
console.log(` ⚠️ 冲突需处理: ${mergeResults.conflicts.length}`);
console.log(` ⏭️ 跳过: ${mergeResults.skipped.length}`);
if (mergeResults.conflicts.length > 0) {
console.log(`\n⚠️ 需要手动处理的冲突:`);
for (const conflict of mergeResults.conflicts) {
console.log(` - ${conflict.change.path}: ${conflict.message}`);
}
}
console.log('==================================================');
}
/**
* 💾 保存状态
*/
async saveState() {
this.state.lastUpdate = new Date().toISOString();
this.state.migrationHistory.push({
timestamp: this.state.lastUpdate,
stats: { ...this.stats }
});
fs.writeFileSync(this.config.stateFilePath, JSON.stringify(this.state, null, 2));
console.log(`💾 状态已保存: ${this.config.stateFilePath}`);
}
/**
* 🎨 获取变更图标
*/
getChangeIcon(type) {
const icons = {
added: '',
modified: '✏️',
deleted: '🗑️'
};
return icons[type] || '❓';
}
/**
* 🎨 获取合并图标
*/
getMergeIcon(status) {
const icons = {
autoMerged: '✅',
conflicts: '⚠️',
skipped: '⏭️'
};
return icons[status] || '❓';
}
// 辅助方法(简化实现)
extractUserSections(content) { return []; }
extractGeneratedSections(content) { return []; }
findInsertPosition(content, section) { return -1; }
insertUserSection(content, section, position) { return content; }
getConflictingSection(content, section) { return ''; }
}
// 命令行执行
if (require.main === module) {
const updater = new IncrementalUpdater();
updater.run().catch(console.error);
}
module.exports = IncrementalUpdater;

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# tools-v1/apps-api 开发快速启动脚本
# 用法bash tools-v1/scripts/dev-start.sh [ENV_FILE]
# 默认为 tools-v1/env/apps-api.development.example
ENV_FILE=${1:-tools-v1/env/apps-api.development.example}
if [ ! -f "$ENV_FILE" ]; then
echo "[ERROR] ENV file not found: $ENV_FILE" >&2
exit 1
fi
# shellcheck disable=SC1090
set -a
source "$ENV_FILE"
set +a
echo "[INFO] Starting apps/api with ENV: $ENV_FILE"
# 注意:在 wwjcloud-nest-v1 目录下启动 apps/api
bash -lc 'NODE_ENV=${NODE_ENV:-development} JWT_SECRET=${JWT_SECRET:-dev-secret} AI_ENABLED=${AI_ENABLED:-true} AUTH_ENABLED=${AUTH_ENABLED:-true} RBAC_ENABLED=${RBAC_ENABLED:-false} GLOBAL_PREFIX=${GLOBAL_PREFIX:-api} QUEUE_ENABLED=${QUEUE_ENABLED:-false} PORT=${PORT:-3001} npm run start -- api'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,595 +0,0 @@
/**
* 质量保证系统
* 为AI自动生成打下基石
*/
class QualityAssurance {
constructor() {
this.validators = {
syntax: this.validateSyntax.bind(this),
types: this.validateTypes.bind(this),
imports: this.validateImports.bind(this),
business: this.validateBusinessLogic.bind(this),
performance: this.validatePerformance.bind(this),
security: this.validateSecurity.bind(this)
};
this.fixers = {
syntax: this.fixSyntaxErrors.bind(this),
types: this.fixTypeErrors.bind(this),
imports: this.fixImportErrors.bind(this),
business: this.fixBusinessLogicErrors.bind(this)
};
this.metrics = {
complexity: this.calculateComplexity.bind(this),
maintainability: this.calculateMaintainability.bind(this),
testability: this.calculateTestability.bind(this),
performance: this.calculatePerformance.bind(this)
};
}
/**
* 执行完整的质量检查
*/
async performQualityCheck(code, context = {}) {
const results = {
overall: 'pass',
validations: {},
fixes: {},
metrics: {},
recommendations: [],
errors: [],
warnings: []
};
console.log('🛡️ 开始质量检查...');
// 执行所有验证
for (const [type, validator] of Object.entries(this.validators)) {
try {
console.log(` 🔍 执行${type}验证...`);
const validation = await validator(code, context);
results.validations[type] = validation;
if (validation.errors.length > 0) {
results.errors.push(...validation.errors);
results.overall = 'fail';
}
if (validation.warnings.length > 0) {
results.warnings.push(...validation.warnings);
}
console.log(`${type}验证完成: ${validation.errors.length}个错误, ${validation.warnings.length}个警告`);
} catch (error) {
console.error(`${type}验证失败:`, error.message);
results.errors.push({
type,
message: error.message,
stack: error.stack
});
results.overall = 'fail';
}
}
// 计算质量指标
for (const [type, calculator] of Object.entries(this.metrics)) {
try {
results.metrics[type] = calculator(code, context);
} catch (error) {
console.error(`${type}指标计算失败:`, error.message);
}
}
// 生成建议
results.recommendations = this.generateRecommendations(results);
console.log(`🎯 质量检查完成: ${results.overall.toUpperCase()}`);
return results;
}
/**
* 自动修复代码问题
*/
async autoFix(code, qualityResults) {
let fixedCode = code;
const fixes = [];
console.log('🔧 开始自动修复...');
// 修复语法错误
if (qualityResults.validations.syntax?.errors.length > 0) {
const syntaxFixes = await this.fixers.syntax(fixedCode, qualityResults.validations.syntax);
fixedCode = syntaxFixes.code;
fixes.push(...syntaxFixes.fixes);
}
// 修复类型错误
if (qualityResults.validations.types?.errors.length > 0) {
const typeFixes = await this.fixers.types(fixedCode, qualityResults.validations.types);
fixedCode = typeFixes.code;
fixes.push(...typeFixes.fixes);
}
// 修复导入错误
if (qualityResults.validations.imports?.errors.length > 0) {
const importFixes = await this.fixers.imports(fixedCode, qualityResults.validations.imports);
fixedCode = importFixes.code;
fixes.push(...importFixes.fixes);
}
// 修复业务逻辑错误
if (qualityResults.validations.business?.errors.length > 0) {
const businessFixes = await this.fixers.business(fixedCode, qualityResults.validations.business);
fixedCode = businessFixes.code;
fixes.push(...businessFixes.fixes);
}
console.log(`✅ 自动修复完成: ${fixes.length}个修复`);
return {
code: fixedCode,
fixes,
summary: {
totalFixes: fixes.length,
fixedTypes: [...new Set(fixes.map(f => f.type))]
}
};
}
/**
* 验证语法
*/
async validateSyntax(code, context) {
const errors = [];
const warnings = [];
// 检查方括号错误
const bracketErrors = this.findBracketErrors(code);
errors.push(...bracketErrors);
// 检查重复前缀
const prefixErrors = this.findPrefixErrors(code);
errors.push(...prefixErrors);
// 检查语法错误
const syntaxErrors = this.findSyntaxErrors(code);
errors.push(...syntaxErrors);
// 检查代码风格
const styleWarnings = this.findStyleWarnings(code);
warnings.push(...styleWarnings);
return { errors, warnings };
}
/**
* 验证类型
*/
async validateTypes(code, context) {
const errors = [];
const warnings = [];
// 检查类型声明
const typeErrors = this.findTypeErrors(code);
errors.push(...typeErrors);
// 检查类型使用
const usageWarnings = this.findTypeUsageWarnings(code);
warnings.push(...usageWarnings);
return { errors, warnings };
}
/**
* 验证导入
*/
async validateImports(code, context) {
const errors = [];
const warnings = [];
// 检查缺失的导入
const missingImports = this.findMissingImports(code);
errors.push(...missingImports);
// 检查未使用的导入
const unusedImports = this.findUnusedImports(code);
warnings.push(...unusedImports);
return { errors, warnings };
}
/**
* 验证业务逻辑
*/
async validateBusinessLogic(code, context) {
const errors = [];
const warnings = [];
// 检查业务逻辑完整性
const businessErrors = this.findBusinessLogicErrors(code);
errors.push(...businessErrors);
// 检查业务规则
const ruleWarnings = this.findBusinessRuleWarnings(code);
warnings.push(...ruleWarnings);
return { errors, warnings };
}
/**
* 验证性能
*/
async validatePerformance(code, context) {
const errors = [];
const warnings = [];
// 检查性能问题
const performanceIssues = this.findPerformanceIssues(code);
warnings.push(...performanceIssues);
return { errors, warnings };
}
/**
* 验证安全性
*/
async validateSecurity(code, context) {
const errors = [];
const warnings = [];
// 检查安全问题
const securityIssues = this.findSecurityIssues(code);
errors.push(...securityIssues);
return { errors, warnings };
}
// 错误检测方法
findBracketErrors(code) {
const errors = [];
const lines = code.split('\n');
lines.forEach((line, index) => {
if (line.includes(']') && !line.includes('[')) {
// 检查是否是函数调用中的方括号错误
if (line.match(/\w+\]/)) {
errors.push({
type: 'syntax',
message: '方括号错误: 应该是圆括号',
line: index + 1,
code: line.trim(),
severity: 'error'
});
}
}
});
return errors;
}
findPrefixErrors(code) {
const errors = [];
const lines = code.split('\n');
lines.forEach((line, index) => {
if (line.includes('BusinessBusinessException')) {
errors.push({
type: 'syntax',
message: '重复的Business前缀',
line: index + 1,
code: line.trim(),
severity: 'error'
});
}
});
return errors;
}
findSyntaxErrors(code) {
const errors = [];
const lines = code.split('\n');
lines.forEach((line, index) => {
// 检查等号错误
if (line.includes('====')) {
errors.push({
type: 'syntax',
message: '重复的等号',
line: index + 1,
code: line.trim(),
severity: 'error'
});
}
// 检查括号不匹配
const openParens = (line.match(/\(/g) || []).length;
const closeParens = (line.match(/\)/g) || []).length;
const openBrackets = (line.match(/\[/g) || []).length;
const closeBrackets = (line.match(/\]/g) || []).length;
if (openParens !== closeParens) {
errors.push({
type: 'syntax',
message: '括号不匹配',
line: index + 1,
code: line.trim(),
severity: 'error'
});
}
if (openBrackets !== closeBrackets) {
errors.push({
type: 'syntax',
message: '方括号不匹配',
line: index + 1,
code: line.trim(),
severity: 'error'
});
}
});
return errors;
}
findStyleWarnings(code) {
const warnings = [];
const lines = code.split('\n');
lines.forEach((line, index) => {
// 检查行长度
if (line.length > 120) {
warnings.push({
type: 'style',
message: '行长度超过120字符',
line: index + 1,
code: line.trim(),
severity: 'warning'
});
}
// 检查尾随空格
if (line.endsWith(' ')) {
warnings.push({
type: 'style',
message: '尾随空格',
line: index + 1,
code: line.trim(),
severity: 'warning'
});
}
});
return warnings;
}
findTypeErrors(code) {
const errors = [];
// 类型错误检测逻辑
return errors;
}
findTypeUsageWarnings(code) {
const warnings = [];
// 类型使用警告检测逻辑
return warnings;
}
findMissingImports(code) {
const errors = [];
const lines = code.split('\n');
// 检查使用的类是否已导入
const usedClasses = this.extractUsedClasses(code);
const importedClasses = this.extractImportedClasses(code);
usedClasses.forEach(className => {
if (!importedClasses.includes(className)) {
errors.push({
type: 'import',
message: `缺失导入: ${className}`,
line: -1,
code: '',
severity: 'error'
});
}
});
return errors;
}
findUnusedImports(code) {
const warnings = [];
// 未使用导入检测逻辑
return warnings;
}
findBusinessLogicErrors(code) {
const errors = [];
// 业务逻辑错误检测逻辑
return errors;
}
findBusinessRuleWarnings(code) {
const warnings = [];
// 业务规则警告检测逻辑
return warnings;
}
findPerformanceIssues(code) {
const warnings = [];
// 性能问题检测逻辑
return warnings;
}
findSecurityIssues(code) {
const errors = [];
// 安全问题检测逻辑
return errors;
}
// 修复方法
async fixSyntaxErrors(code, validation) {
let fixedCode = code;
const fixes = [];
validation.errors.forEach(error => {
if (error.message.includes('方括号错误')) {
fixedCode = fixedCode.replace(/(\w+)\]/g, '$1)');
fixes.push({
type: 'syntax',
description: '修复方括号错误',
line: error.line
});
}
if (error.message.includes('重复的Business前缀')) {
fixedCode = fixedCode.replace(/BusinessBusinessException/g, 'BusinessException');
fixes.push({
type: 'syntax',
description: '修复重复的Business前缀',
line: error.line
});
}
if (error.message.includes('重复的等号')) {
fixedCode = fixedCode.replace(/====/g, '===');
fixes.push({
type: 'syntax',
description: '修复重复的等号',
line: error.line
});
}
});
return { code: fixedCode, fixes };
}
async fixTypeErrors(code, validation) {
let fixedCode = code;
const fixes = [];
// 类型错误修复逻辑
return { code: fixedCode, fixes };
}
async fixImportErrors(code, validation) {
let fixedCode = code;
const fixes = [];
// 导入错误修复逻辑
return { code: fixedCode, fixes };
}
async fixBusinessLogicErrors(code, validation) {
let fixedCode = code;
const fixes = [];
// 业务逻辑错误修复逻辑
return { code: fixedCode, fixes };
}
// 指标计算方法
calculateComplexity(code, context) {
const lines = code.split('\n');
const methods = (code.match(/function\s+\w+/g) || []).length;
const conditions = (code.match(/if\s*\(|else\s*if\s*\(|switch\s*\(/g) || []).length;
const loops = (code.match(/for\s*\(|while\s*\(|foreach\s*\(/g) || []).length;
return {
lines: lines.length,
methods,
conditions,
loops,
cyclomatic: methods + conditions + loops + 1
};
}
calculateMaintainability(code, context) {
const complexity = this.calculateComplexity(code, context);
const maintainabilityIndex = Math.max(0, 171 - 5.2 * Math.log(complexity.lines) - 0.23 * complexity.cyclomatic);
return {
index: maintainabilityIndex,
rating: maintainabilityIndex > 80 ? 'A' : maintainabilityIndex > 60 ? 'B' : maintainabilityIndex > 40 ? 'C' : 'D'
};
}
calculateTestability(code, context) {
const methods = (code.match(/function\s+\w+/g) || []).length;
const dependencies = (code.match(/this\.\w+Service/g) || []).length;
return {
methods,
dependencies,
testabilityScore: Math.max(0, 100 - dependencies * 10)
};
}
calculatePerformance(code, context) {
const loops = (code.match(/for\s*\(|while\s*\(|foreach\s*\(/g) || []).length;
const asyncCalls = (code.match(/await\s+/g) || []).length;
return {
loops,
asyncCalls,
performanceScore: Math.max(0, 100 - loops * 5 - asyncCalls * 2)
};
}
// 辅助方法
extractUsedClasses(code) {
const classes = [];
const matches = code.match(/([A-Z][a-zA-Z0-9_]*)/g);
if (matches) {
classes.push(...matches);
}
return [...new Set(classes)];
}
extractImportedClasses(code) {
const imports = [];
const matches = code.match(/import\s*\{\s*([^}]+)\s*\}\s*from/g);
if (matches) {
matches.forEach(match => {
const importMatch = match.match(/import\s*\{\s*([^}]+)\s*\}\s*from/);
if (importMatch) {
const classNames = importMatch[1].split(',').map(name => name.trim());
imports.push(...classNames);
}
});
}
return imports;
}
generateRecommendations(results) {
const recommendations = [];
if (results.errors.length > 0) {
recommendations.push({
type: 'error',
message: '修复所有语法错误以提高代码质量',
priority: 'high'
});
}
if (results.warnings.length > 10) {
recommendations.push({
type: 'warning',
message: '减少警告数量以提高代码质量',
priority: 'medium'
});
}
if (results.metrics.complexity?.cyclomatic > 10) {
recommendations.push({
type: 'complexity',
message: '降低代码复杂度以提高可维护性',
priority: 'medium'
});
}
return recommendations;
}
}
module.exports = QualityAssurance;

View File

@@ -1,175 +0,0 @@
#!/usr/bin/env node
/**
* 测试 dict-generator 修复
* 验证文件命名和重叠名问题
*/
const DictGenerator = require('./generators/dict-generator');
class DictFixTester {
constructor() {
this.errors = [];
this.passed = [];
}
async run() {
console.log('🧪 测试 dict-generator 修复...\n');
// 测试1: 继承 BaseGenerator
this.testInheritance();
// 测试2: 文件命名规范
this.testFileNaming();
// 测试3: 避免重叠名
this.testNoOverlappingNames();
// 输出结果
this.printResults();
}
testInheritance() {
console.log('📝 测试1: 继承 BaseGenerator');
const generator = new DictGenerator();
if (typeof generator.writeFile === 'function') {
this.passed.push('DictGenerator 继承了 BaseGenerator.writeFile');
console.log(' ✅ 继承了 BaseGenerator.writeFile');
} else {
this.errors.push('DictGenerator 未继承 BaseGenerator.writeFile');
console.log(' ❌ 未继承 BaseGenerator.writeFile');
}
if (typeof generator.printStats === 'function') {
this.passed.push('DictGenerator 继承了 BaseGenerator.printStats');
console.log(' ✅ 继承了 BaseGenerator.printStats');
} else {
this.errors.push('DictGenerator 未继承 BaseGenerator.printStats');
console.log(' ❌ 未继承 BaseGenerator.printStats');
}
if (generator.dryRun !== undefined) {
this.passed.push('DictGenerator 支持 dry-run 模式');
console.log(' ✅ 支持 dry-run 模式');
} else {
this.errors.push('DictGenerator 不支持 dry-run 模式');
console.log(' ❌ 不支持 dry-run 模式');
}
}
testFileNaming() {
console.log('\n📝 测试2: 文件命名规范kebab-case');
const generator = new DictGenerator();
// 模拟生成内容并检查
const testCases = [
{ input: 'Dict', expected: 'dict.enum.ts' },
{ input: 'MemberLevel', expected: 'member-level.enum.ts' },
{ input: 'PayChannel', expected: 'pay-channel.enum.ts' },
{ input: 'dict_service', expected: 'dict-service.enum.ts' }
];
for (const testCase of testCases) {
const kebabName = generator.toKebabCase(testCase.input);
const fileName = `${kebabName}.enum.ts`;
if (fileName === testCase.expected) {
this.passed.push(`文件命名正确: ${testCase.input}${fileName}`);
console.log(`${testCase.input}${fileName}`);
} else {
this.errors.push(`文件命名错误: ${testCase.input} 应为 ${testCase.expected},实际为 ${fileName}`);
console.log(`${testCase.input} 应为 ${testCase.expected},实际为 ${fileName}`);
}
}
}
testNoOverlappingNames() {
console.log('\n📝 测试3: 避免重叠名问题');
const generator = new DictGenerator();
const content = generator.generateDictContent('test', 'Dict');
// 检查1: 应该生成 DictEnum 而不是 DictDict
if (content.includes('export enum DictEnum')) {
this.passed.push('使用 DictEnum 而不是 DictDict');
console.log(' ✅ 使用 DictEnum避免重叠名');
} else if (content.includes('export enum DictDict')) {
this.errors.push('错误使用了 DictDict重叠名');
console.log(' ❌ 错误使用了 DictDict重叠名');
} else {
this.errors.push('未找到枚举定义');
console.log(' ❌ 未找到枚举定义');
}
// 检查2: dictDict 变量名是合理的
if (content.includes('export const dictDict')) {
this.passed.push('dictDict 变量名符合预期');
console.log(' ✅ dictDict 变量名符合预期');
} else {
this.errors.push('dictDict 变量名不正确');
console.log(' ❌ dictDict 变量名不正确');
}
// 检查3: 工具类命名
if (content.includes('export class DictEnumUtil')) {
this.passed.push('工具类使用 DictEnumUtil');
console.log(' ✅ 工具类使用 DictEnumUtil');
} else {
this.errors.push('工具类命名不正确');
console.log(' ❌ 工具类命名不正确');
}
// 检查4: 文件名建议
console.log('\n 💡 推荐文件名模式:');
console.log(' - dict.enum.ts (kebab-case + .enum.ts 后缀)');
console.log(' - member-level.enum.ts');
console.log(' - pay-channel.enum.ts');
console.log('\n ❌ 禁止的文件名:');
console.log(' - DictDict.ts (PascalCase + 重叠名)');
console.log(' - Dict.ts (无后缀)');
}
printResults() {
console.log('\n\n📊 测试结果汇总');
console.log('='.repeat(60));
console.log(`\n✅ 通过项 (${this.passed.length}):`);
this.passed.forEach(item => console.log(` - ${item}`));
if (this.errors.length > 0) {
console.log(`\n❌ 错误项 (${this.errors.length}):`);
this.errors.forEach(item => console.log(` - ${item}`));
}
console.log('\n' + '='.repeat(60));
const totalChecks = this.passed.length + this.errors.length;
const successRate = totalChecks > 0
? ((this.passed.length / totalChecks) * 100).toFixed(2)
: '0.00';
console.log(`📈 成功率: ${successRate}% (${this.passed.length}/${totalChecks})`);
if (this.errors.length === 0) {
console.log('\n🎉 dict-generator 修复验证通过!');
return true;
} else {
console.log(`\n💔 发现 ${this.errors.length} 个错误,需要修复`);
return false;
}
}
}
// 运行测试
if (require.main === module) {
const tester = new DictFixTester();
tester.run().then(passed => {
process.exit(passed ? 0 : 1);
});
}
module.exports = DictFixTester;

View File

@@ -1,319 +0,0 @@
#!/usr/bin/env node
/**
* 测试修复脚本
* 验证所有修复是否正确
*/
const fs = require('fs');
const path = require('path');
class FixValidator {
constructor() {
this.errors = [];
this.warnings = [];
this.passed = [];
}
/**
* 运行所有验证
*/
async run() {
console.log('🧪 开始验证修复...\n');
// 验证1: command-generator.js 导入路径
console.log('📝 验证1: command-generator.js 导入路径修复');
this.validateCommandGeneratorImport();
// 验证2: BaseGenerator 存在性
console.log('\n📝 验证2: BaseGenerator 基类存在性');
this.validateBaseGenerator();
// 验证3: entity-generator.js 继承 BaseGenerator
console.log('\n📝 验证3: entity-generator.js 继承 BaseGenerator');
this.validateEntityGeneratorInheritance();
// 验证4: command-generator.js 继承 BaseGenerator
console.log('\n📝 验证4: command-generator.js 继承 BaseGenerator');
this.validateCommandGeneratorInheritance();
// 验证5: Quality Gate 工具存在
console.log('\n📝 验证5: Quality Gate 工具存在');
this.validateQualityGate();
// 验证6: migration-coordinator.js 集成 Quality Gate
console.log('\n📝 验证6: migration-coordinator.js 集成 Quality Gate');
this.validateCoordinatorQualityGate();
// 验证7: README.md 文档更新
console.log('\n📝 验证7: README.md 文档更新');
this.validateReadmeUpdate();
// 输出验证结果
this.printResults();
}
/**
* 验证 command-generator.js 导入路径
*/
validateCommandGeneratorImport() {
const filePath = path.join(__dirname, 'generators/command-generator.js');
const content = fs.readFileSync(filePath, 'utf8');
// 检查错误的导入
if (content.includes("@wwjCore/exceptions/Customexceptions")) {
this.errors.push('command-generator.js 仍使用错误的导入路径 @wwjCore/exceptions/Customexceptions');
console.log(' ❌ 仍使用错误的导入路径');
} else if (content.includes("@wwjCommon/exceptions/business.exception")) {
this.passed.push('command-generator.js 使用正确的导入路径');
console.log(' ✅ 使用正确的导入路径 @wwjCommon/exceptions/business.exception');
} else {
this.warnings.push('command-generator.js 未找到 BusinessException 导入');
console.log(' ⚠️ 未找到 BusinessException 导入');
}
}
/**
* 验证 BaseGenerator 存在
*/
validateBaseGenerator() {
const filePath = path.join(__dirname, 'generators/base-generator.js');
if (!fs.existsSync(filePath)) {
this.errors.push('base-generator.js 不存在');
console.log(' ❌ base-generator.js 不存在');
return;
}
const content = fs.readFileSync(filePath, 'utf8');
// 检查关键方法
const requiredMethods = ['writeFile', 'ensureDir', 'readFile', 'printStats'];
let allMethodsPresent = true;
for (const method of requiredMethods) {
if (!content.includes(`${method}(`)) {
this.errors.push(`base-generator.js 缺少方法: ${method}`);
allMethodsPresent = false;
}
}
if (allMethodsPresent) {
this.passed.push('BaseGenerator 包含所有必需方法');
console.log(' ✅ 包含所有必需方法');
} else {
console.log(' ❌ 缺少部分方法');
}
// 检查 dry-run 支持
if (content.includes('this.dryRun')) {
this.passed.push('BaseGenerator 支持 dry-run 模式');
console.log(' ✅ 支持 dry-run 模式');
} else {
this.errors.push('BaseGenerator 不支持 dry-run 模式');
console.log(' ❌ 不支持 dry-run 模式');
}
}
/**
* 验证 entity-generator.js 继承
*/
validateEntityGeneratorInheritance() {
const filePath = path.join(__dirname, 'generators/entity-generator.js');
const content = fs.readFileSync(filePath, 'utf8');
if (content.includes("extends BaseGenerator")) {
this.passed.push('entity-generator.js 继承 BaseGenerator');
console.log(' ✅ 继承 BaseGenerator');
} else {
this.errors.push('entity-generator.js 未继承 BaseGenerator');
console.log(' ❌ 未继承 BaseGenerator');
}
if (content.includes("require('./base-generator')")) {
this.passed.push('entity-generator.js 导入 BaseGenerator');
console.log(' ✅ 导入 BaseGenerator');
} else {
this.errors.push('entity-generator.js 未导入 BaseGenerator');
console.log(' ❌ 未导入 BaseGenerator');
}
if (content.includes("this.writeFile(")) {
this.passed.push('entity-generator.js 使用 BaseGenerator.writeFile');
console.log(' ✅ 使用 BaseGenerator.writeFile');
} else {
this.warnings.push('entity-generator.js 可能未使用 BaseGenerator.writeFile');
console.log(' ⚠️ 可能未使用 BaseGenerator.writeFile');
}
}
/**
* 验证 command-generator.js 继承
*/
validateCommandGeneratorInheritance() {
const filePath = path.join(__dirname, 'generators/command-generator.js');
const content = fs.readFileSync(filePath, 'utf8');
if (content.includes("extends BaseGenerator")) {
this.passed.push('command-generator.js 继承 BaseGenerator');
console.log(' ✅ 继承 BaseGenerator');
} else {
this.errors.push('command-generator.js 未继承 BaseGenerator');
console.log(' ❌ 未继承 BaseGenerator');
}
if (content.includes("this.writeFile(")) {
this.passed.push('command-generator.js 使用 BaseGenerator.writeFile');
console.log(' ✅ 使用 BaseGenerator.writeFile');
} else {
this.warnings.push('command-generator.js 可能未使用 BaseGenerator.writeFile');
console.log(' ⚠️ 可能未使用 BaseGenerator.writeFile');
}
}
/**
* 验证 Quality Gate 工具
*/
validateQualityGate() {
const filePath = path.join(__dirname, 'generators/quality-gate.js');
if (!fs.existsSync(filePath)) {
this.errors.push('quality-gate.js 不存在');
console.log(' ❌ quality-gate.js 不存在');
return;
}
const content = fs.readFileSync(filePath, 'utf8');
// 检查关键方法
const requiredMethods = ['checkTypeScript', 'checkESLint', 'run', 'printStats'];
let allMethodsPresent = true;
for (const method of requiredMethods) {
if (!content.includes(`${method}(`)) {
this.errors.push(`quality-gate.js 缺少方法: ${method}`);
allMethodsPresent = false;
}
}
if (allMethodsPresent) {
this.passed.push('Quality Gate 包含所有必需方法');
console.log(' ✅ 包含所有必需方法');
} else {
console.log(' ❌ 缺少部分方法');
}
}
/**
* 验证 migration-coordinator.js 集成
*/
validateCoordinatorQualityGate() {
const filePath = path.join(__dirname, 'migration-coordinator.js');
const content = fs.readFileSync(filePath, 'utf8');
if (content.includes("require('./generators/quality-gate')")) {
this.passed.push('migration-coordinator.js 导入 QualityGate');
console.log(' ✅ 导入 QualityGate');
} else {
this.errors.push('migration-coordinator.js 未导入 QualityGate');
console.log(' ❌ 未导入 QualityGate');
}
if (content.includes("runQualityGate")) {
this.passed.push('migration-coordinator.js 包含 runQualityGate 方法');
console.log(' ✅ 包含 runQualityGate 方法');
} else {
this.errors.push('migration-coordinator.js 未包含 runQualityGate 方法');
console.log(' ❌ 未包含 runQualityGate 方法');
}
if (content.includes("await this.runQualityGate()")) {
this.passed.push('migration-coordinator.js 调用 runQualityGate');
console.log(' ✅ 在流程中调用 runQualityGate');
} else {
this.errors.push('migration-coordinator.js 未在流程中调用 runQualityGate');
console.log(' ❌ 未在流程中调用 runQualityGate');
}
}
/**
* 验证 README.md 更新
*/
validateReadmeUpdate() {
const filePath = path.join(__dirname, 'README.md');
const content = fs.readFileSync(filePath, 'utf8');
if (content.includes('dry-run') || content.includes('DRY_RUN')) {
this.passed.push('README.md 包含 dry-run 使用说明');
console.log(' ✅ 包含 dry-run 使用说明');
} else {
this.warnings.push('README.md 缺少 dry-run 使用说明');
console.log(' ⚠️ 缺少 dry-run 使用说明');
}
if (content.includes('quality-gate') || content.includes('Quality Gate')) {
this.passed.push('README.md 包含 Quality Gate 说明');
console.log(' ✅ 包含 Quality Gate 说明');
} else {
this.warnings.push('README.md 缺少 Quality Gate 说明');
console.log(' ⚠️ 缺少 Quality Gate 说明');
}
if (content.includes('base-generator')) {
this.passed.push('README.md 包含 BaseGenerator 说明');
console.log(' ✅ 包含 BaseGenerator 说明');
} else {
this.warnings.push('README.md 缺少 BaseGenerator 说明');
console.log(' ⚠️ 缺少 BaseGenerator 说明');
}
}
/**
* 输出验证结果
*/
printResults() {
console.log('\n\n📊 验证结果汇总');
console.log('='.repeat(60));
console.log(`\n✅ 通过项 (${this.passed.length}):`);
this.passed.forEach(item => console.log(` - ${item}`));
if (this.warnings.length > 0) {
console.log(`\n⚠️ 警告项 (${this.warnings.length}):`);
this.warnings.forEach(item => console.log(` - ${item}`));
}
if (this.errors.length > 0) {
console.log(`\n❌ 错误项 (${this.errors.length}):`);
this.errors.forEach(item => console.log(` - ${item}`));
}
console.log('\n' + '='.repeat(60));
const totalChecks = this.passed.length + this.warnings.length + this.errors.length;
const successRate = totalChecks > 0
? ((this.passed.length / totalChecks) * 100).toFixed(2)
: '0.00';
console.log(`📈 成功率: ${successRate}% (${this.passed.length}/${totalChecks})`);
if (this.errors.length === 0) {
console.log('\n🎉 所有必需检查已通过!');
return true;
} else {
console.log(`\n💔 发现 ${this.errors.length} 个错误,需要修复`);
return false;
}
}
}
// 运行验证
if (require.main === module) {
const validator = new FixValidator();
validator.run().then(passed => {
process.exit(passed ? 0 : 1);
});
}
module.exports = FixValidator;

View File

@@ -1,62 +0,0 @@
#!/usr/bin/env node
const IncrementalUpdater = require('./incremental-updater');
/**
* 🧪 增量更新功能测试
*/
async function testIncrementalUpdate() {
console.log('🧪 开始测试增量更新功能...\n');
try {
// 设置测试环境
process.env.DRY_RUN = 'true';
console.log('📋 测试配置:');
console.log('- 干运行模式: 启用');
console.log('- 详细输出: 启用');
console.log('- 测试环境: 开发环境\n');
// 创建增量更新器实例
const updater = new IncrementalUpdater();
console.log('🔧 增量更新器配置:');
console.log(`- PHP项目路径: ${updater.config.phpBasePath}`);
console.log(`- NestJS项目路径: ${updater.config.nestjsBasePath}`);
console.log(`- 状态文件路径: ${updater.config.stateFilePath}`);
console.log(`- 备份路径: ${updater.config.backupPath}`);
console.log(`- 干运行模式: ${updater.config.dryRun}\n`);
// 执行增量更新
console.log('🚀 执行增量更新...');
const result = await updater.run();
if (result !== false) {
console.log('\n✅ 增量更新测试成功完成!');
console.log('📊 测试结果: 所有功能正常工作');
} else {
console.log('\n❌ 增量更新测试失败');
console.log('📊 测试结果: 存在功能问题');
}
} catch (error) {
console.error('\n💥 测试过程中发生错误:');
console.error('错误信息:', error.message);
console.error('错误堆栈:', error.stack);
console.log('\n🔧 可能的原因:');
console.log('1. PHP项目路径不存在或无法访问');
console.log('2. NestJS项目路径不存在或无法访问');
console.log('3. 文件权限不足');
console.log('4. 依赖模块缺失');
process.exit(1);
}
}
// 运行测试
if (require.main === module) {
testIncrementalUpdate();
}
module.exports = { testIncrementalUpdate };

View File

@@ -1,19 +0,0 @@
{
"extends": "./tsconfig.json",
"include": [
"apps/api/src/**/*",
"libs/**/*"
],
"exclude": [
"node_modules",
"test",
"dist",
"**/*.spec.ts",
"admin",
"admin/**/*",
"admin-vben",
"admin-vben/**/*",
"niucloud-*",
"niucloud-*/**/*"
]
}

View File

@@ -1,53 +0,0 @@
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"resolvePackageJsonExports": true,
"esModuleInterop": true,
"isolatedModules": true,
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "ES2023",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"noImplicitAny": false,
"strictBindCallApply": false,
"noFallthroughCasesInSwitch": false,
"paths": {
"@wwjBoot": ["libs/wwjcloud-boot/src"],
"@wwjBoot/*": ["libs/wwjcloud-boot/src/*"],
"@wwjCommon": ["libs/wwjcloud-boot/src/infra"],
"@wwjCommon/*": ["libs/wwjcloud-boot/src/infra/*"],
"@wwjVendor": ["libs/wwjcloud-boot/src/vendor"],
"@wwjVendor/*": ["libs/wwjcloud-boot/src/vendor/*"],
"@wwjCore": ["libs/wwjcloud-core/src"],
"@wwjCore/*": ["libs/wwjcloud-core/src/*"],
"@wwjAi": ["libs/wwjcloud-ai/src"],
"@wwjAi/*": ["libs/wwjcloud-ai/src/*"],
"@wwjAddon": ["libs/wwjcloud-addon/src"],
"@wwjAddon/*": ["libs/wwjcloud-addon/src/*"]
}
},
"include": [
"src/**/*",
"apps/api/src/**/*",
"libs/wwjcloud-boot/src/**/*",
"libs/wwjcloud-ai/src/**/*"
],
"exclude": [
"admin",
"scripts",
"test",
"tmp-dist",
"dist",
"**/*.spec.ts"
]
}

View File

@@ -0,0 +1,66 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { AddonServiceService } from '../services/addonservice.service';
/**
* AddonControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: AddonController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('AddonController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/api/addon') // ⚠️ 路由前缀与Java一致
export class AddonControllerController {
constructor(
private readonly logger: WinstonService,
private readonly addonService: AddonService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getaddon() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getaddon() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,110 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { AddonDevelopServiceService } from '../services/addondevelopservice.service';
/**
* AddonDevelopControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: AddonDevelopController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('AddonDevelopController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/addon_develop') // ⚠️ 路由前缀与Java一致
export class AddonDevelopControllerController {
constructor(
private readonly logger: WinstonService,
private readonly addonDevelopService: AddonDevelopService
) {}
@Get()
@Roles('admin', 'user') // V1框架角色守卫
@ApiOperation({ summary: '获取addondevelop列表' })
@ApiResponseWrapper({ type: Array, description: '列表数据' })
async findAll(@Query() query: any) {
this.logger.info('获取列表', { query });
try {
const result = await this.addondevelopService.findAll();
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取列表失败', { error: error.message });
throw error;
}
}
@Get(':id')
@Roles('admin', 'user')
@ApiOperation({ summary: '根据ID获取addondevelop' })
@ApiResponseWrapper({ description: '详情数据' })
async findById(@Param('id') id: number) {
this.logger.info('获取详情', { id });
try {
const result = await this.addondevelopService.findById(id);
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取详情失败', { error: error.message, id });
throw error;
}
}
@Post()
@ApiOperation({ summary: '创建addondevelop' })
@ApiResponse({ status: 201, description: '创建成功' })
async create(@Body() createDto: any) {
this.logger.log('create called', createDto);
try {
return await this.addondevelopService.create(createDto);
} catch (error) {
this.logger.error('create failed', error);
throw error;
}
}
@Put(':id')
@ApiOperation({ summary: '更新addondevelop' })
@ApiResponse({ status: 200, description: '更新成功' })
async update(@Param('id') id: number, @Body() updateDto: any) {
this.logger.log(`update called with id: ${id}`, updateDto);
try {
return await this.addondevelopService.update(id, updateDto);
} catch (error) {
this.logger.error('update failed', error);
throw error;
}
}
@Delete(':id')
@ApiOperation({ summary: '删除addondevelop' })
@ApiResponse({ status: 200, description: '删除成功' })
async delete(@Param('id') id: number) {
this.logger.log(`delete called with id: ${id}`);
try {
await this.addondevelopService.delete(id);
return { success: true };
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,92 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { AddonLogServiceService } from '../services/addonlogservice.service';
/**
* AddonLogControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: AddonLogController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('AddonLogController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/api/addon_log') // ⚠️ 路由前缀与Java一致
export class AddonLogControllerController {
constructor(
private readonly logger: WinstonService,
private readonly addonLogService: AddonLogService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getaddonlog() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getaddonlog() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postaddonlog() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postaddonlog() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,53 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { AgreementServiceService } from '../services/agreementservice.service';
/**
* AgreementControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: AgreementController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('AgreementController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/api/agreement') // ⚠️ 路由前缀与Java一致
export class AgreementControllerController {
constructor(
private readonly logger: WinstonService,
private readonly agreementService: AgreementService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getagreement() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,110 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { AppServiceService } from '../services/appservice.service';
/**
* AppControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: AppController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('AppController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi') // ⚠️ 路由前缀与Java一致
export class AppControllerController {
constructor(
private readonly logger: WinstonService,
private readonly appService: AppService
) {}
@Get()
@Roles('admin', 'user') // V1框架角色守卫
@ApiOperation({ summary: '获取app列表' })
@ApiResponseWrapper({ type: Array, description: '列表数据' })
async findAll(@Query() query: any) {
this.logger.info('获取列表', { query });
try {
const result = await this.appService.findAll();
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取列表失败', { error: error.message });
throw error;
}
}
@Get(':id')
@Roles('admin', 'user')
@ApiOperation({ summary: '根据ID获取app' })
@ApiResponseWrapper({ description: '详情数据' })
async findById(@Param('id') id: number) {
this.logger.info('获取详情', { id });
try {
const result = await this.appService.findById(id);
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取详情失败', { error: error.message, id });
throw error;
}
}
@Post()
@ApiOperation({ summary: '创建app' })
@ApiResponse({ status: 201, description: '创建成功' })
async create(@Body() createDto: any) {
this.logger.log('create called', createDto);
try {
return await this.appService.create(createDto);
} catch (error) {
this.logger.error('create failed', error);
throw error;
}
}
@Put(':id')
@ApiOperation({ summary: '更新app' })
@ApiResponse({ status: 200, description: '更新成功' })
async update(@Param('id') id: number, @Body() updateDto: any) {
this.logger.log(`update called with id: ${id}`, updateDto);
try {
return await this.appService.update(id, updateDto);
} catch (error) {
this.logger.error('update failed', error);
throw error;
}
}
@Delete(':id')
@ApiOperation({ summary: '删除app' })
@ApiResponse({ status: 200, description: '删除成功' })
async delete(@Param('id') id: number) {
this.logger.log(`delete called with id: ${id}`);
try {
await this.appService.delete(id);
return { success: true };
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,118 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { AuthServiceService } from '../services/authservice.service';
/**
* AuthControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: AuthController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('AuthController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/auth') // ⚠️ 路由前缀与Java一致
export class AuthControllerController {
constructor(
private readonly logger: WinstonService,
private readonly authService: AuthService
) {}
@Get('addon')
@ApiOperation({ summary: 'get操作' })
async getauth() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getauth() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getauth() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getauth() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async putauth() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async putauth() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,157 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { BackupServiceService } from '../services/backupservice.service';
/**
* BackupControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: BackupController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('BackupController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/backup') // ⚠️ 路由前缀与Java一致
export class BackupControllerController {
constructor(
private readonly logger: WinstonService,
private readonly backupService: BackupService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getbackup() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postbackup() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async putbackup() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postbackup() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postbackup() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getbackup() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getbackup() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postbackup() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postbackup() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,66 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { CaptchaServiceService } from '../services/captchaservice.service';
/**
* CaptchaControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: CaptchaController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('CaptchaController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/api') // ⚠️ 路由前缀与Java一致
export class CaptchaControllerController {
constructor(
private readonly logger: WinstonService,
private readonly captchaService: CaptchaService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcaptcha() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcaptcha() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,144 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { CloudServiceService } from '../services/cloudservice.service';
/**
* CloudControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: CloudController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('CloudController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/niucloud') // ⚠️ 路由前缀与Java一致
export class CloudControllerController {
constructor(
private readonly logger: WinstonService,
private readonly cloudService: CloudService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcloud() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postcloud() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcloud() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postcloud() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcloud() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcloud() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postcloud() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postcloud() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,110 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { ConfigServiceService } from '../services/configservice.service';
/**
* ConfigControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: ConfigController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('ConfigController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('adminapi/wxoplatform') // ⚠️ 路由前缀与Java一致
export class ConfigControllerController {
constructor(
private readonly logger: WinstonService,
private readonly configService: ConfigService
) {}
@Get()
@Roles('admin', 'user') // V1框架角色守卫
@ApiOperation({ summary: '获取config列表' })
@ApiResponseWrapper({ type: Array, description: '列表数据' })
async findAll(@Query() query: any) {
this.logger.info('获取列表', { query });
try {
const result = await this.configService.findAll();
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取列表失败', { error: error.message });
throw error;
}
}
@Get(':id')
@Roles('admin', 'user')
@ApiOperation({ summary: '根据ID获取config' })
@ApiResponseWrapper({ description: '详情数据' })
async findById(@Param('id') id: number) {
this.logger.info('获取详情', { id });
try {
const result = await this.configService.findById(id);
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取详情失败', { error: error.message, id });
throw error;
}
}
@Post()
@ApiOperation({ summary: '创建config' })
@ApiResponse({ status: 201, description: '创建成功' })
async create(@Body() createDto: any) {
this.logger.log('create called', createDto);
try {
return await this.configService.create(createDto);
} catch (error) {
this.logger.error('create failed', error);
throw error;
}
}
@Put(':id')
@ApiOperation({ summary: '更新config' })
@ApiResponse({ status: 200, description: '更新成功' })
async update(@Param('id') id: number, @Body() updateDto: any) {
this.logger.log(`update called with id: ${id}`, updateDto);
try {
return await this.configService.update(id, updateDto);
} catch (error) {
this.logger.error('update failed', error);
throw error;
}
}
@Delete(':id')
@ApiOperation({ summary: '删除config' })
@ApiResponse({ status: 200, description: '删除成功' })
async delete(@Param('id') id: number) {
this.logger.log(`delete called with id: ${id}`);
try {
await this.configService.delete(id);
return { success: true };
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,105 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { CoreAddonServiceService } from '../services/coreaddonservice.service';
/**
* CoreAddonControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: CoreAddonController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('CoreAddonController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/core/addon') // ⚠️ 路由前缀与Java一致
export class CoreAddonControllerController {
constructor(
private readonly logger: WinstonService,
private readonly coreAddonService: CoreAddonService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreaddon() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreaddon() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreaddon() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreaddon() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreaddon() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,79 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { CoreAsyncTaskServiceService } from '../services/coreasynctaskservice.service';
/**
* CoreAsyncTaskControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: CoreAsyncTaskController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('CoreAsyncTaskController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/core/task') // ⚠️ 路由前缀与Java一致
export class CoreAsyncTaskControllerController {
constructor(
private readonly logger: WinstonService,
private readonly coreAsyncTaskService: CoreAsyncTaskService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreasynctask() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreasynctask() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcoreasynctask() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,66 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { CoreQueueControlServiceService } from '../services/corequeuecontrolservice.service';
/**
* CoreQueueControlControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: CoreQueueControlController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('CoreQueueControlController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/core/queue') // ⚠️ 路由前缀与Java一致
export class CoreQueueControlControllerController {
constructor(
private readonly logger: WinstonService,
private readonly coreQueueControlService: CoreQueueControlService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcorequeuecontrol() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getcorequeuecontrol() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,110 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { DictServiceService } from '../services/dictservice.service';
/**
* DictControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: DictController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('DictController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/dict') // ⚠️ 路由前缀与Java一致
export class DictControllerController {
constructor(
private readonly logger: WinstonService,
private readonly dictService: DictService
) {}
@Get()
@Roles('admin', 'user') // V1框架角色守卫
@ApiOperation({ summary: '获取dict列表' })
@ApiResponseWrapper({ type: Array, description: '列表数据' })
async findAll(@Query() query: any) {
this.logger.info('获取列表', { query });
try {
const result = await this.dictService.findAll();
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取列表失败', { error: error.message });
throw error;
}
}
@Get(':id')
@Roles('admin', 'user')
@ApiOperation({ summary: '根据ID获取dict' })
@ApiResponseWrapper({ description: '详情数据' })
async findById(@Param('id') id: number) {
this.logger.info('获取详情', { id });
try {
const result = await this.dictService.findById(id);
return { code: 0, msg: '获取成功', data: result };
} catch (error) {
this.logger.error('获取详情失败', { error: error.message, id });
throw error;
}
}
@Post()
@ApiOperation({ summary: '创建dict' })
@ApiResponse({ status: 201, description: '创建成功' })
async create(@Body() createDto: any) {
this.logger.log('create called', createDto);
try {
return await this.dictService.create(createDto);
} catch (error) {
this.logger.error('create failed', error);
throw error;
}
}
@Put(':id')
@ApiOperation({ summary: '更新dict' })
@ApiResponse({ status: 200, description: '更新成功' })
async update(@Param('id') id: number, @Body() updateDto: any) {
this.logger.log(`update called with id: ${id}`, updateDto);
try {
return await this.dictService.update(id, updateDto);
} catch (error) {
this.logger.error('update failed', error);
throw error;
}
}
@Delete(':id')
@ApiOperation({ summary: '删除dict' })
@ApiResponse({ status: 200, description: '删除成功' })
async delete(@Param('id') id: number) {
this.logger.log(`delete called with id: ${id}`);
try {
await this.dictService.delete(id);
return { success: true };
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,92 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { DiyServiceService } from '../services/diyservice.service';
/**
* DiyControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: DiyController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('DiyController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/api/diy') // ⚠️ 路由前缀与Java一致
export class DiyControllerController {
constructor(
private readonly logger: WinstonService,
private readonly diyService: DiyService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiy() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiy() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiy() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiy() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,118 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { DiyFormServiceService } from '../services/diyformservice.service';
/**
* DiyFormControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: DiyFormController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('DiyFormController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/api/diy/form') // ⚠️ 路由前缀与Java一致
export class DiyFormControllerController {
constructor(
private readonly logger: WinstonService,
private readonly diyFormService: DiyFormService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiyform() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiyform() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiyform() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postdiyform() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async putdiyform() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiyform() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,92 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { DiyRouteServiceService } from '../services/diyrouteservice.service';
/**
* DiyRouteControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: DiyRouteController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('DiyRouteController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/diy/route') // ⚠️ 路由前缀与Java一致
export class DiyRouteControllerController {
constructor(
private readonly logger: WinstonService,
private readonly diyRouteService: DiyRouteService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiyroute() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiyroute() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiyroute() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async putdiyroute() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,118 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { DiyThemeServiceService } from '../services/diythemeservice.service';
/**
* DiyThemeControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: DiyThemeController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('DiyThemeController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/diy/theme') // ⚠️ 路由前缀与Java一致
export class DiyThemeControllerController {
constructor(
private readonly logger: WinstonService,
private readonly diyThemeService: DiyThemeService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiytheme() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postdiytheme() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getdiytheme() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postdiytheme() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async putdiytheme() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
@Delete('/')
@ApiOperation({ summary: 'delete操作' })
async deletediytheme() {
this.logger.log('delete called');
try {
// TODO: 实现delete逻辑
return { success: true };
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,209 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { GenerateServiceService } from '../services/generateservice.service';
/**
* GenerateControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: GenerateController
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('GenerateController')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('adminapi/generator') // ⚠️ 路由前缀与Java一致
export class GenerateControllerController {
constructor(
private readonly logger: WinstonService,
private readonly generateService: GenerateService
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postgenerate() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async putgenerate() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
@Delete('/')
@ApiOperation({ summary: 'delete操作' })
async deletegenerate() {
this.logger.log('delete called');
try {
// TODO: 实现delete逻辑
return { success: true };
} catch (error) {
this.logger.error('delete failed', error);
throw error;
}
}
@Post('/')
@ApiOperation({ summary: 'post操作' })
async postgenerate() {
this.logger.log('post called');
try {
// TODO: 实现post逻辑
return { success: true };
} catch (error) {
this.logger.error('post failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async getgenerate() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
}

View File

@@ -0,0 +1,66 @@
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// V1框架基础设施
import { JwtAuthGuard } from '@wwjcloud-boot/infra/auth/guards/jwt-auth.guard';
import { RolesGuard } from '@wwjcloud-boot/infra/auth/guards/roles.guard';
import { Roles } from '@wwjcloud-boot/infra/auth/decorators/roles.decorator';
import { Public } from '@wwjcloud-boot/infra/auth/decorators/public.decorator';
import { ApiResponseWrapper } from '@wwjcloud-boot/infra/response/decorators/api-response.decorator';
import { WinstonService } from '@wwjcloud-boot/infra/logging/winston.service';
import { H5ServiceService } from '../services/h5service.service';
/**
* H5ControllerController - 基于Java控制器转换使用NestJS v11和V1框架特性
*
* ⚠️ 重要与Java共享Admin管理面板API必须保持一致
* 对应Java控制器: H5Controller
*
* 一致性要求:
* 1. 路由路径必须与Java完全一致
* 2. 请求参数字段名必须一致(包括大小写)
* 3. 响应格式必须一致:{ code: 0, msg: '', data: {} }
* 4. HTTP方法GET/POST/PUT/DELETE必须一致
*
* V1框架能力
* - JwtAuthGuard: JWT认证守卫
* - RolesGuard: 角色权限守卫
* - ApiResponseWrapper: 统一响应包装
* - WinstonService: 结构化日志
*/
@ApiTags('H5Controller')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller('/adminapi/channel/h5') // ⚠️ 路由前缀与Java一致
export class H5ControllerController {
constructor(
private readonly logger: WinstonService,
private readonly h5Service: H5Service
) {}
@Get('/')
@ApiOperation({ summary: 'get操作' })
async geth5() {
this.logger.log('get called');
try {
// TODO: 实现get逻辑
return { success: true };
} catch (error) {
this.logger.error('get failed', error);
throw error;
}
}
@Put('/')
@ApiOperation({ summary: 'put操作' })
async puth5() {
this.logger.log('put called');
try {
// TODO: 实现put逻辑
return { success: true };
} catch (error) {
this.logger.error('put failed', error);
throw error;
}
}
}

Some files were not shown because too many files have changed in this diff Show More