diff --git a/src/admin/auth/admin-auth.controller.ts b/src/admin/auth/admin-auth.controller.ts index d57192a..7f21b01 100644 --- a/src/admin/auth/admin-auth.controller.ts +++ b/src/admin/auth/admin-auth.controller.ts @@ -17,7 +17,7 @@ import { AdminAuthService } from './admin-auth.service'; import { JwtAuthGuard } from './jwt-auth.guard'; import { WordpressService } from '@/wordpress/wordpress.service'; -@ApiTags('admin-auth') +@ApiTags('Admin - 认证') @Controller() @UseGuards(JwtAuthGuard) export class AdminAuthController { diff --git a/src/admin/component/component.controller.ts b/src/admin/component/component.controller.ts index 7e17682..739cda5 100644 --- a/src/admin/component/component.controller.ts +++ b/src/admin/component/component.controller.ts @@ -60,7 +60,7 @@ class CompPageDto } @Controller('component') -@ApiTags('component') +@ApiTags('Admin - 组件管理') @ApiExtraModels(PaginatedDto) @UseGuards(JwtAuthGuard) export class ComponentController { diff --git a/src/admin/dept/admin-dept.controller.ts b/src/admin/dept/admin-dept.controller.ts index 3fe3593..f5d713c 100644 --- a/src/admin/dept/admin-dept.controller.ts +++ b/src/admin/dept/admin-dept.controller.ts @@ -14,7 +14,7 @@ import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { AdminDept } from './admin-dept.entity'; import { AdminDeptService } from './admin-dept.service'; -@ApiTags('admin-dept') +@ApiTags('Admin - 部门管理') @Controller('system/dept') @UseGuards(JwtAuthGuard) export class AdminDeptController { diff --git a/src/admin/dict/dict.controller.ts b/src/admin/dict/dict.controller.ts index 80f4039..d507ab7 100644 --- a/src/admin/dict/dict.controller.ts +++ b/src/admin/dict/dict.controller.ts @@ -35,7 +35,7 @@ const chartDictExample = [ }, ]; -@ApiTags('dict') +@ApiTags('Admin - 字典管理') @Controller('dict') @UseGuards(JwtAuthGuard) export class DictController { diff --git a/src/admin/example/admin-example.controller.ts b/src/admin/example/admin-example.controller.ts index 568b0bc..9985596 100644 --- a/src/admin/example/admin-example.controller.ts +++ b/src/admin/example/admin-example.controller.ts @@ -66,7 +66,7 @@ const DEMO_ROWS: DemoTableRow[] = Array.from({ length: 100 }, (_, index) => { }; }); -@ApiTags('admin-example') +@ApiTags('Admin - 示例') @Controller() @UseGuards(JwtAuthGuard) export class AdminExampleController { diff --git a/src/admin/menu/admin-menu.controller.ts b/src/admin/menu/admin-menu.controller.ts index 2fd66b6..372d066 100644 --- a/src/admin/menu/admin-menu.controller.ts +++ b/src/admin/menu/admin-menu.controller.ts @@ -16,7 +16,7 @@ import { AdminUser } from '../user/admin-user.entity'; import { AdminMenu } from './admin-menu.entity'; import { AdminMenuService } from './admin-menu.service'; -@ApiTags('admin-menu') +@ApiTags('Admin - 菜单管理') @Controller() @UseGuards(JwtAuthGuard) export class AdminMenuController { diff --git a/src/admin/role/admin-role.controller.ts b/src/admin/role/admin-role.controller.ts index 4f887ee..5a99f46 100644 --- a/src/admin/role/admin-role.controller.ts +++ b/src/admin/role/admin-role.controller.ts @@ -14,7 +14,7 @@ import { vbenPage, vbenSuccess } from '@/common'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { AdminRoleService } from './admin-role.service'; -@ApiTags('admin-role') +@ApiTags('Admin - 角色管理') @Controller('system/role') @UseGuards(JwtAuthGuard) export class AdminRoleController { diff --git a/src/admin/timezone/admin-timezone.controller.ts b/src/admin/timezone/admin-timezone.controller.ts index 8376838..11efda2 100644 --- a/src/admin/timezone/admin-timezone.controller.ts +++ b/src/admin/timezone/admin-timezone.controller.ts @@ -13,7 +13,7 @@ const TIMEZONE_OPTIONS = [ { label: 'Asia/Seoul (GMT+9)', value: 'Asia/Seoul' }, ]; -@ApiTags('admin-timezone') +@ApiTags('Admin - 时区') @Controller('timezone') @UseGuards(JwtAuthGuard) export class AdminTimezoneController { diff --git a/src/admin/user/admin-user.controller.ts b/src/admin/user/admin-user.controller.ts index b473016..53c117c 100644 --- a/src/admin/user/admin-user.controller.ts +++ b/src/admin/user/admin-user.controller.ts @@ -5,7 +5,7 @@ import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { AdminUser } from './admin-user.entity'; import { AdminUserService } from './admin-user.service'; -@ApiTags('admin-user') +@ApiTags('Admin - 用户管理') @Controller('user') @UseGuards(JwtAuthGuard) export class AdminUserController { diff --git a/src/app.controller.ts b/src/app.controller.ts index b02cd1c..471d0f2 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,7 +1,12 @@ import { Controller, Get, Redirect } from '@nestjs/common'; -import { ApiMovedPermanentlyResponse, ApiOperation } from '@nestjs/swagger'; +import { + ApiMovedPermanentlyResponse, + ApiOperation, + ApiTags, +} from '@nestjs/swagger'; import { AppService } from './app.service'; +@ApiTags('基础能力 - 根入口') @Controller() export class AppController { constructor(private readonly appService: AppService) {} diff --git a/src/main.ts b/src/main.ts index 7a7bde8..7cc0d28 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,56 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; -import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import type { OpenAPIObject } from '@nestjs/swagger'; import { urlencoded, json } from 'express'; import { knife4jSetup } from 'nestjs-knife4j-plus'; +import type { Service } from 'nestjs-knife4j-plus'; + +type SwaggerPathMatcher = (path: string) => boolean; + +interface SwaggerDocumentGroup { + matcher: SwaggerPathMatcher; + name: string; + path: string; +} + +const adminSwaggerPathPrefixes = [ + '/auth', + '/component', + '/dict', + '/menu', + '/system', + '/timezone', + '/user', + '/demo', + '/status', + '/table', + '/test', + '/upload', +]; + +const swaggerGroups: SwaggerDocumentGroup[] = [ + { + matcher: (path) => matchPathPrefixes(path, adminSwaggerPathPrefixes), + name: 'Admin 后台管理', + path: 'api/admin', + }, + { + matcher: (path) => path.startsWith('/qqbot'), + name: 'QQBot 机器人', + path: 'api/qqbot', + }, + { + matcher: (path) => path.startsWith('/wordpress'), + name: 'WordPress 博客', + path: 'api/wordpress', + }, + { + matcher: (path) => path === '/' || path.startsWith('/minio'), + name: '基础能力', + path: 'api/basic', + }, +]; async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -15,15 +63,57 @@ async function bootstrap() { .build(); const document = SwaggerModule.createDocument(app, options); SwaggerModule.setup('api', app, document); + const services: Service[] = [ + { + name: '全量接口', + url: '/api-json', + }, + ]; + + swaggerGroups.forEach((group) => { + const groupDocument = filterSwaggerDocument(document, group.matcher); + SwaggerModule.setup(group.path, app, groupDocument); + services.push({ + name: group.name, + url: `/${group.path}-json`, + }); + }); // 启用knife4j增强(关键代码) - knife4jSetup(app, [ - { - name: '1.0', // 文档版本名称 - url: `/api-json`, // Swagger openapi JSON地址 - }, - ]); + knife4jSetup(app, services); await app.listen(48085); } + +function filterSwaggerDocument( + document: OpenAPIObject, + matcher: SwaggerPathMatcher, +): OpenAPIObject { + const paths = Object.fromEntries( + Object.entries(document.paths).filter(([path]) => matcher(path)), + ) as OpenAPIObject['paths']; + const usedTags = new Set(); + + Object.values(paths).forEach((pathItem) => { + Object.values(pathItem || {}).forEach((operation) => { + const tags = (operation as any)?.tags; + if (Array.isArray(tags)) { + tags.forEach((tag) => usedTags.add(tag)); + } + }); + }); + + return { + ...document, + paths, + tags: document.tags?.filter((tag) => usedTags.has(tag.name)), + }; +} + +function matchPathPrefixes(path: string, prefixes: string[]) { + return prefixes.some( + (prefix) => path === prefix || path.startsWith(`${prefix}/`), + ); +} + bootstrap(); diff --git a/src/minio/minio.controller.ts b/src/minio/minio.controller.ts index 4899bc4..49f72b2 100644 --- a/src/minio/minio.controller.ts +++ b/src/minio/minio.controller.ts @@ -50,7 +50,7 @@ const PROXY_RESOURCE_EXTENSION_RE = /\.(avif|bmp|css|eot|gif|ico|jpe?g|otf|png|svg|ttf|webp|woff2?)(?:[?#].*)?$/i; @Controller('minio') -@ApiTags('minio') +@ApiTags('基础能力 - MinIO') @UseGuards(JwtAuthGuard) export class MinioClientController { constructor( diff --git a/src/qqbot/account/qqbot-account.controller.ts b/src/qqbot/account/qqbot-account.controller.ts index 69caedc..5b95b00 100644 --- a/src/qqbot/account/qqbot-account.controller.ts +++ b/src/qqbot/account/qqbot-account.controller.ts @@ -21,7 +21,7 @@ import { QqbotAccountService } from './qqbot-account.service'; import { QqbotNapcatLoginService } from './qqbot-napcat-login.service'; import { QqbotReverseWsService } from '../connection/qqbot-reverse-ws.service'; -@ApiTags('qqbot-account') +@ApiTags('QQBot - 账号连接') @Controller('qqbot/account') @UseGuards(JwtAuthGuard) export class QqbotAccountController { diff --git a/src/qqbot/command/qqbot-command.controller.ts b/src/qqbot/command/qqbot-command.controller.ts index d9582bd..9fd333b 100644 --- a/src/qqbot/command/qqbot-command.controller.ts +++ b/src/qqbot/command/qqbot-command.controller.ts @@ -21,7 +21,7 @@ import { QqbotCommandEngineService } from './qqbot-command-engine.service'; import { QqbotCommandService } from './qqbot-command.service'; import { normalizeBoolean } from '../qqbot.utils'; -@ApiTags('qqbot-command') +@ApiTags('QQBot - 在线命令') @Controller('qqbot/command') @UseGuards(JwtAuthGuard) export class QqbotCommandController { diff --git a/src/qqbot/dashboard/qqbot-dashboard.controller.ts b/src/qqbot/dashboard/qqbot-dashboard.controller.ts index 95290c4..ce59a7e 100644 --- a/src/qqbot/dashboard/qqbot-dashboard.controller.ts +++ b/src/qqbot/dashboard/qqbot-dashboard.controller.ts @@ -4,7 +4,7 @@ import { JwtAuthGuard } from '@/admin/auth/jwt-auth.guard'; import { vbenSuccess } from '@/common'; import { QqbotDashboardService } from './qqbot-dashboard.service'; -@ApiTags('qqbot-dashboard') +@ApiTags('QQBot - 工作台') @Controller('qqbot/dashboard') @UseGuards(JwtAuthGuard) export class QqbotDashboardController { diff --git a/src/qqbot/message/qqbot-message.controller.ts b/src/qqbot/message/qqbot-message.controller.ts index 01adfd9..a33cb03 100644 --- a/src/qqbot/message/qqbot-message.controller.ts +++ b/src/qqbot/message/qqbot-message.controller.ts @@ -8,7 +8,7 @@ import { } from './qqbot-message.dto'; import { QqbotMessageService } from './qqbot-message.service'; -@ApiTags('qqbot-message') +@ApiTags('QQBot - 会话与消息') @Controller('qqbot') @UseGuards(JwtAuthGuard) export class QqbotMessageController { diff --git a/src/qqbot/permission/qqbot-permission.controller.ts b/src/qqbot/permission/qqbot-permission.controller.ts index ba182c7..be2f0f9 100644 --- a/src/qqbot/permission/qqbot-permission.controller.ts +++ b/src/qqbot/permission/qqbot-permission.controller.ts @@ -19,7 +19,7 @@ import { } from './qqbot-permission.dto'; import { QqbotPermissionService } from './qqbot-permission.service'; -@ApiTags('qqbot-permission') +@ApiTags('QQBot - 权限名单') @Controller('qqbot/permission') @UseGuards(JwtAuthGuard) export class QqbotPermissionController { diff --git a/src/qqbot/plugin/qqbot-plugin.controller.ts b/src/qqbot/plugin/qqbot-plugin.controller.ts index 631d1db..ecb160a 100644 --- a/src/qqbot/plugin/qqbot-plugin.controller.ts +++ b/src/qqbot/plugin/qqbot-plugin.controller.ts @@ -14,7 +14,7 @@ import { QqbotEventPluginRegistryService } from './qqbot-event-plugin-registry.s import { QqbotPluginRegistryService } from './qqbot-plugin-registry.service'; import type { QqbotPluginTriggerMode } from './qqbot-plugin.types'; -@ApiTags('qqbot-plugin') +@ApiTags('QQBot - 插件能力') @Controller('qqbot/plugin') @UseGuards(JwtAuthGuard) export class QqbotPluginController { diff --git a/src/qqbot/rule/qqbot-rule.controller.ts b/src/qqbot/rule/qqbot-rule.controller.ts index 20e3ff3..9cc950b 100644 --- a/src/qqbot/rule/qqbot-rule.controller.ts +++ b/src/qqbot/rule/qqbot-rule.controller.ts @@ -19,7 +19,7 @@ import { import { QqbotRuleService } from './qqbot-rule.service'; import { normalizeBoolean } from '../qqbot.utils'; -@ApiTags('qqbot-rule') +@ApiTags('QQBot - 自动回复规则') @Controller('qqbot/rule') @UseGuards(JwtAuthGuard) export class QqbotRuleController { diff --git a/src/qqbot/send/qqbot-send.controller.ts b/src/qqbot/send/qqbot-send.controller.ts index 3330997..91ff2ea 100644 --- a/src/qqbot/send/qqbot-send.controller.ts +++ b/src/qqbot/send/qqbot-send.controller.ts @@ -18,7 +18,7 @@ import { } from './qqbot-send.dto'; import { QqbotSendService } from './qqbot-send.service'; -@ApiTags('qqbot-send') +@ApiTags('QQBot - 发送日志') @Controller('qqbot/send') @UseGuards(JwtAuthGuard) export class QqbotSendController { diff --git a/src/wordpress/wordpress-article.controller.ts b/src/wordpress/wordpress-article.controller.ts index e9a8e2a..47168a4 100644 --- a/src/wordpress/wordpress-article.controller.ts +++ b/src/wordpress/wordpress-article.controller.ts @@ -21,7 +21,7 @@ import { } from './wordpress.dto'; import { WordpressService } from './wordpress.service'; -@ApiTags('wordpress-article') +@ApiTags('WordPress - 文章') @ApiHeader({ name: 'X-WordPress-Authorization', required: false, diff --git a/src/wordpress/wordpress-auth.controller.ts b/src/wordpress/wordpress-auth.controller.ts index 81fd4b5..6029de1 100644 --- a/src/wordpress/wordpress-auth.controller.ts +++ b/src/wordpress/wordpress-auth.controller.ts @@ -12,7 +12,7 @@ import { JwtAuthGuard } from '@/admin/auth/jwt-auth.guard'; import { Public, vbenSuccess } from '@/common'; import { WordpressService } from './wordpress.service'; -@ApiTags('wordpress-auth') +@ApiTags('WordPress - 认证') @ApiHeader({ name: 'X-WordPress-Authorization', required: false, diff --git a/src/wordpress/wordpress-category.controller.ts b/src/wordpress/wordpress-category.controller.ts index 0bea339..9a48690 100644 --- a/src/wordpress/wordpress-category.controller.ts +++ b/src/wordpress/wordpress-category.controller.ts @@ -21,7 +21,7 @@ import { } from './wordpress.dto'; import { WordpressService } from './wordpress.service'; -@ApiTags('wordpress-category') +@ApiTags('WordPress - 分类') @ApiHeader({ name: 'X-WordPress-Authorization', required: false, diff --git a/src/wordpress/wordpress-tag.controller.ts b/src/wordpress/wordpress-tag.controller.ts index f8546da..e1c2a56 100644 --- a/src/wordpress/wordpress-tag.controller.ts +++ b/src/wordpress/wordpress-tag.controller.ts @@ -21,7 +21,7 @@ import { } from './wordpress.dto'; import { WordpressService } from './wordpress.service'; -@ApiTags('wordpress-tag') +@ApiTags('WordPress - 标签') @ApiHeader({ name: 'X-WordPress-Authorization', required: false,