max 5 giorni fa
parent
commit
9c1fa6490d

+ 16 - 0
LMS-NodeJs/README.md

@@ -34,6 +34,22 @@ NODE_ENV=development
 - `DB_PASSWORD`: 数据库密码
 - `DB_DATABASE`: 数据库名称
 
+## API 文档
+
+项目集成了 Swagger API 文档,启动服务后可以通过以下地址访问:
+
+**Swagger UI**: http://localhost:3000/api
+
+API 文档包含以下模块:
+- **books**: 图书相关接口
+- **authors**: 作者相关接口
+- **tags**: 标签相关接口
+- **chapters**: 章节相关接口
+- **hot**: 热门相关接口
+- **aide**: 助手相关接口
+- **line**: 线路相关接口
+- **file**: 文件相关接口
+
 ## 功能特性
 
 - **文件管理**: 支持文件上传、下载和去重

+ 2 - 0
LMS-NodeJs/package.json

@@ -25,6 +25,7 @@
     "@nestjs/core": "^11.0.1",
     "@nestjs/mapped-types": "*",
     "@nestjs/platform-express": "^11.0.1",
+    "@nestjs/swagger": "^11.2.0",
     "@nestjs/typeorm": "^11.0.0",
     "@types/multer": "^2.0.0",
     "@types/uuid": "^10.0.0",
@@ -34,6 +35,7 @@
     "mysql2": "^3.14.2",
     "reflect-metadata": "^0.2.2",
     "rxjs": "^7.8.1",
+    "swagger-ui-express": "^5.0.1",
     "typeorm": "^0.3.25"
   },
   "devDependencies": {

+ 73 - 0
LMS-NodeJs/pnpm-lock.yaml

@@ -23,6 +23,9 @@ importers:
       '@nestjs/platform-express':
         specifier: ^11.0.1
         version: 11.1.5(@nestjs/common@11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.5)
+      '@nestjs/swagger':
+        specifier: ^11.2.0
+        version: 11.2.0(@nestjs/common@11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.5)(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)
       '@nestjs/typeorm':
         specifier: ^11.0.0
         version: 11.0.0(@nestjs/common@11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.5)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.25(mysql2@3.14.2)(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.13.1)(@types/node@22.16.5)(typescript@5.8.3)))
@@ -50,6 +53,9 @@ importers:
       rxjs:
         specifier: ^7.8.1
         version: 7.8.2
+      swagger-ui-express:
+        specifier: ^5.0.1
+        version: 5.0.1(express@5.1.0)
       typeorm:
         specifier: ^0.3.25
         version: 0.3.25(mysql2@3.14.2)(reflect-metadata@0.2.2)(ts-node@10.9.2(@swc/core@1.13.1)(@types/node@22.16.5)(typescript@5.8.3))
@@ -637,6 +643,9 @@ packages:
     resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
     engines: {node: '>=8'}
 
+  '@microsoft/tsdoc@0.15.1':
+    resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==}
+
   '@napi-rs/nice-android-arm-eabi@1.0.4':
     resolution: {integrity: sha512-OZFMYUkih4g6HCKTjqJHhMUlgvPiDuSLZPbPBWHLjKmFTv74COzRlq/gwHtmEVaR39mJQ6ZyttDl2HNMUbLVoA==}
     engines: {node: '>= 10'}
@@ -811,6 +820,23 @@ packages:
     peerDependencies:
       typescript: '>=4.8.2'
 
+  '@nestjs/swagger@11.2.0':
+    resolution: {integrity: sha512-5wolt8GmpNcrQv34tIPUtPoV1EeFbCetm40Ij3+M0FNNnf2RJ3FyWfuQvI8SBlcJyfaounYVTKzKHreFXsUyOg==}
+    peerDependencies:
+      '@fastify/static': ^8.0.0
+      '@nestjs/common': ^11.0.1
+      '@nestjs/core': ^11.0.1
+      class-transformer: '*'
+      class-validator: '*'
+      reflect-metadata: ^0.1.12 || ^0.2.0
+    peerDependenciesMeta:
+      '@fastify/static':
+        optional: true
+      class-transformer:
+        optional: true
+      class-validator:
+        optional: true
+
   '@nestjs/testing@11.1.5':
     resolution: {integrity: sha512-ZYRYF750SefmuIo7ZqPlHDcin1OHh6My0OkOfGEFjrD9mJ0vMVIpwMTOOkpzCfCcpqUuxeHBuecpiIn+NLrQbQ==}
     peerDependencies:
@@ -865,6 +891,9 @@ packages:
     resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
     engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
 
+  '@scarf/scarf@1.4.0':
+    resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
+
   '@sec-ant/readable-stream@0.4.1':
     resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
 
@@ -3290,6 +3319,18 @@ packages:
     resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
     engines: {node: '>= 0.4'}
 
+  swagger-ui-dist@5.21.0:
+    resolution: {integrity: sha512-E0K3AB6HvQd8yQNSMR7eE5bk+323AUxjtCz/4ZNKiahOlPhPJxqn3UPIGs00cyY/dhrTDJ61L7C/a8u6zhGrZg==}
+
+  swagger-ui-dist@5.27.0:
+    resolution: {integrity: sha512-tS6LRyBhY6yAqxrfsA9IYpGWPUJOri6sclySa7TdC7XQfGLvTwDY531KLgfQwHEtQsn+sT4JlUspbeQDBVGWig==}
+
+  swagger-ui-express@5.0.1:
+    resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==}
+    engines: {node: '>= v0.10.32'}
+    peerDependencies:
+      express: '>=4.0.0 || >=5.0.0-beta'
+
   symbol-observable@4.0.0:
     resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
     engines: {node: '>=0.10'}
@@ -4340,6 +4381,8 @@ snapshots:
 
   '@lukeed/csprng@1.1.0': {}
 
+  '@microsoft/tsdoc@0.15.1': {}
+
   '@napi-rs/nice-android-arm-eabi@1.0.4':
     optional: true
 
@@ -4506,6 +4549,21 @@ snapshots:
     transitivePeerDependencies:
       - chokidar
 
+  '@nestjs/swagger@11.2.0(@nestjs/common@11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.5)(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)':
+    dependencies:
+      '@microsoft/tsdoc': 0.15.1
+      '@nestjs/common': 11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)
+      '@nestjs/core': 11.1.5(@nestjs/common@11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.5)(reflect-metadata@0.2.2)(rxjs@7.8.2)
+      '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)
+      js-yaml: 4.1.0
+      lodash: 4.17.21
+      path-to-regexp: 8.2.0
+      reflect-metadata: 0.2.2
+      swagger-ui-dist: 5.21.0
+    optionalDependencies:
+      class-transformer: 0.5.1
+      class-validator: 0.14.2
+
   '@nestjs/testing@11.1.5(@nestjs/common@11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.5)(@nestjs/platform-express@11.1.5)':
     dependencies:
       '@nestjs/common': 11.1.5(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)
@@ -4549,6 +4607,8 @@ snapshots:
 
   '@pkgr/core@0.2.9': {}
 
+  '@scarf/scarf@1.4.0': {}
+
   '@sec-ant/readable-stream@0.4.1': {}
 
   '@sinclair/typebox@0.27.8': {}
@@ -7234,6 +7294,19 @@ snapshots:
 
   supports-preserve-symlinks-flag@1.0.0: {}
 
+  swagger-ui-dist@5.21.0:
+    dependencies:
+      '@scarf/scarf': 1.4.0
+
+  swagger-ui-dist@5.27.0:
+    dependencies:
+      '@scarf/scarf': 1.4.0
+
+  swagger-ui-express@5.0.1(express@5.1.0):
+    dependencies:
+      express: 5.1.0
+      swagger-ui-dist: 5.27.0
+
   symbol-observable@4.0.0: {}
 
   synckit@0.11.11:

+ 22 - 0
LMS-NodeJs/src/aide/aide.controller.ts

@@ -10,32 +10,54 @@ import {
 import { AideService } from './aide.service';
 import { CreateAideDto } from './dto/create-aide.dto';
 import { UpdateAideDto } from './dto/update-aide.dto';
+import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
 
+@ApiTags('aide')
 @Controller('aide')
 export class AideController {
   constructor(private readonly aideService: AideService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建助手', description: '创建新的助手记录' })
+  @ApiResponse({ status: 201, description: '助手创建成功' })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createAideDto: CreateAideDto) {
     return this.aideService.create(createAideDto);
   }
 
   @Get()
+  @ApiOperation({ summary: '获取所有助手', description: '获取所有助手列表' })
+  @ApiResponse({ status: 200, description: '获取成功' })
   findAll() {
     return this.aideService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取助手',
+    description: '根据助手ID获取单个助手',
+  })
+  @ApiParam({ name: 'id', description: '助手ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功' })
+  @ApiResponse({ status: 404, description: '助手不存在' })
   findOne(@Param('id') id: string) {
     return this.aideService.findOne(+id);
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新助手', description: '根据ID更新助手信息' })
+  @ApiParam({ name: 'id', description: '助手ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功' })
+  @ApiResponse({ status: 404, description: '助手不存在' })
   update(@Param('id') id: string, @Body() updateAideDto: UpdateAideDto) {
     return this.aideService.update(+id, updateAideDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除助手', description: '根据ID删除助手' })
+  @ApiParam({ name: 'id', description: '助手ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '助手不存在' })
   remove(@Param('id') id: string) {
     return this.aideService.remove(+id);
   }

+ 22 - 0
LMS-NodeJs/src/author/author.controller.ts

@@ -10,32 +10,54 @@ import {
 import { AuthorService } from './author.service';
 import { CreateAuthorDto } from './dto/create-author.dto';
 import { UpdateAuthorDto } from './dto/update-author.dto';
+import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
 
+@ApiTags('authors')
 @Controller('author')
 export class AuthorController {
   constructor(private readonly authorService: AuthorService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建作者', description: '创建新的作者记录' })
+  @ApiResponse({ status: 201, description: '作者创建成功' })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createAuthorDto: CreateAuthorDto) {
     return this.authorService.create(createAuthorDto);
   }
 
   @Get()
+  @ApiOperation({ summary: '获取所有作者', description: '获取所有作者列表' })
+  @ApiResponse({ status: 200, description: '获取成功' })
   findAll() {
     return this.authorService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取作者',
+    description: '根据作者ID获取单个作者',
+  })
+  @ApiParam({ name: 'id', description: '作者ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功' })
+  @ApiResponse({ status: 404, description: '作者不存在' })
   findOne(@Param('id') id: string) {
     return this.authorService.findOne(+id);
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新作者', description: '根据ID更新作者信息' })
+  @ApiParam({ name: 'id', description: '作者ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功' })
+  @ApiResponse({ status: 404, description: '作者不存在' })
   update(@Param('id') id: string, @Body() updateAuthorDto: UpdateAuthorDto) {
     return this.authorService.update(+id, updateAuthorDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除作者', description: '根据ID删除作者' })
+  @ApiParam({ name: 'id', description: '作者ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '作者不存在' })
   remove(@Param('id') id: string) {
     return this.authorService.remove(+id);
   }

+ 23 - 0
LMS-NodeJs/src/book/book.controller.ts

@@ -10,32 +10,55 @@ import {
 import { BookService } from './book.service';
 import { CreateBookDto } from './dto/create-book.dto';
 import { UpdateBookDto } from './dto/update-book.dto';
+import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
+import { Book } from './entities/book.entity';
 
+@ApiTags('books')
 @Controller('book')
 export class BookController {
   constructor(private readonly bookService: BookService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建图书', description: '创建新的图书记录' })
+  @ApiResponse({ status: 201, description: '图书创建成功' })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createBookDto: CreateBookDto) {
     return this.bookService.create(createBookDto);
   }
 
   @Get()
+  @ApiOperation({ summary: '获取所有图书', description: '获取所有图书列表' })
+  @ApiResponse({ status: 200, description: '获取成功' })
   findAll() {
     return this.bookService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取图书',
+    description: '根据图书ID获取单个图书',
+  })
+  @ApiParam({ name: 'id', description: '图书ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功' })
+  @ApiResponse({ status: 404, description: '图书不存在' })
   findOne(@Param('id') id: string) {
     return this.bookService.findOne(+id);
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新图书', description: '根据ID更新图书信息' })
+  @ApiParam({ name: 'id', description: '图书ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功' })
+  @ApiResponse({ status: 404, description: '图书不存在' })
   update(@Param('id') id: string, @Body() updateBookDto: UpdateBookDto) {
     return this.bookService.update(+id, updateBookDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除图书', description: '根据ID删除图书' })
+  @ApiParam({ name: 'id', description: '图书ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '图书不存在' })
   remove(@Param('id') id: string) {
     return this.bookService.remove(+id);
   }

+ 22 - 0
LMS-NodeJs/src/chapter/chapter.controller.ts

@@ -10,32 +10,54 @@ import {
 import { ChapterService } from './chapter.service';
 import { CreateChapterDto } from './dto/create-chapter.dto';
 import { UpdateChapterDto } from './dto/update-chapter.dto';
+import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
 
+@ApiTags('chapters')
 @Controller('chapter')
 export class ChapterController {
   constructor(private readonly chapterService: ChapterService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建章节', description: '创建新的章节记录' })
+  @ApiResponse({ status: 201, description: '章节创建成功' })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createChapterDto: CreateChapterDto) {
     return this.chapterService.create(createChapterDto);
   }
 
   @Get()
+  @ApiOperation({ summary: '获取所有章节', description: '获取所有章节列表' })
+  @ApiResponse({ status: 200, description: '获取成功' })
   findAll() {
     return this.chapterService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取章节',
+    description: '根据章节ID获取单个章节',
+  })
+  @ApiParam({ name: 'id', description: '章节ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功' })
+  @ApiResponse({ status: 404, description: '章节不存在' })
   findOne(@Param('id') id: string) {
     return this.chapterService.findOne(+id);
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新章节', description: '根据ID更新章节信息' })
+  @ApiParam({ name: 'id', description: '章节ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功' })
+  @ApiResponse({ status: 404, description: '章节不存在' })
   update(@Param('id') id: string, @Body() updateChapterDto: UpdateChapterDto) {
     return this.chapterService.update(+id, updateChapterDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除章节', description: '根据ID删除章节' })
+  @ApiParam({ name: 'id', description: '章节ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '章节不存在' })
   remove(@Param('id') id: string) {
     return this.chapterService.remove(+id);
   }

+ 22 - 0
LMS-NodeJs/src/file/entities/file.entity.ts

@@ -5,12 +5,18 @@ import {
   CreateDateColumn,
   UpdateDateColumn,
 } from 'typeorm';
+import { ApiProperty } from '@nestjs/swagger';
 
 @Entity('files')
 export class File {
+  @ApiProperty({ description: '文件ID', example: 1 })
   @PrimaryGeneratedColumn()
   id: number;
 
+  @ApiProperty({
+    description: '文件唯一标识(基于hash生成的UUID)',
+    example: '550e8400-e29b-41d4-a716-446655440000',
+  })
   @Column({
     name: 'file_id',
     type: 'varchar',
@@ -20,6 +26,7 @@ export class File {
   })
   fileId: string;
 
+  @ApiProperty({ description: '文件名称', example: 'example.jpg' })
   @Column({
     name: 'file_name',
     type: 'varchar',
@@ -29,6 +36,7 @@ export class File {
   })
   fileName: string;
 
+  @ApiProperty({ description: '文件类型', example: 'image/jpeg' })
   @Column({
     name: 'file_type',
     type: 'varchar',
@@ -38,6 +46,10 @@ export class File {
   })
   fileType: string;
 
+  @ApiProperty({
+    description: '文件hash(唯一)',
+    example: 'a1b2c3d4e5f6789012345678901234567890abcdef',
+  })
   @Column({
     name: 'file_hash',
     type: 'varchar',
@@ -47,6 +59,7 @@ export class File {
   })
   fileHash: string;
 
+  @ApiProperty({ description: '文件大小(字节)', example: 1024000 })
   @Column({
     name: 'file_size',
     type: 'bigint',
@@ -55,6 +68,7 @@ export class File {
   })
   fileSize: number;
 
+  @ApiProperty({ description: 'MIME类型', example: 'image/jpeg' })
   @Column({
     name: 'mime_type',
     type: 'varchar',
@@ -64,6 +78,10 @@ export class File {
   })
   mimeType: string;
 
+  @ApiProperty({
+    description: '文件存储位置(相对路径)',
+    example: '/uploads/2024/01/example.jpg',
+  })
   @Column({
     name: 'storage_path',
     type: 'varchar',
@@ -73,6 +91,7 @@ export class File {
   })
   storagePath: string;
 
+  @ApiProperty({ description: '上传来源', example: 'web' })
   @Column({
     name: 'upload_source',
     type: 'varchar',
@@ -82,6 +101,7 @@ export class File {
   })
   uploadSource: string;
 
+  @ApiProperty({ description: '原始文件名', example: 'original-file-name.jpg' })
   @Column({
     name: 'original_name',
     type: 'varchar',
@@ -91,12 +111,14 @@ export class File {
   })
   originalName: string;
 
+  @ApiProperty({ description: '上传日期', example: '2024-01-01T00:00:00.000Z' })
   @CreateDateColumn({
     name: 'upload_date',
     comment: '上传日期',
   })
   uploadDate: Date;
 
+  @ApiProperty({ description: '更新时间', example: '2024-01-01T00:00:00.000Z' })
   @UpdateDateColumn({
     name: 'updated_at',
     comment: '更新时间',

+ 57 - 0
LMS-NodeJs/src/file/file.controller.ts

@@ -19,27 +19,60 @@ import { UpdateFileDto } from './dto/update-file.dto';
 import { FileInterceptor } from '@nestjs/platform-express';
 import * as fs from 'fs';
 import * as path from 'path';
+import {
+  ApiTags,
+  ApiOperation,
+  ApiResponse,
+  ApiParam,
+  ApiBody,
+  ApiConsumes,
+} from '@nestjs/swagger';
+import { File } from './entities/file.entity';
 
+@ApiTags('file')
 @Controller('file')
 export class FileController {
   constructor(private readonly fileService: FileService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建文件记录', description: '创建新的文件记录' })
+  @ApiResponse({ status: 201, description: '文件记录创建成功', type: File })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createFileDto: CreateFileDto) {
     return this.fileService.create(createFileDto);
   }
 
   @Get()
+  @ApiOperation({
+    summary: '获取所有文件',
+    description: '获取所有文件记录列表',
+  })
+  @ApiResponse({ status: 200, description: '获取成功', type: [File] })
   findAll() {
     return this.fileService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取文件',
+    description: '根据文件ID获取单个文件记录',
+  })
+  @ApiParam({ name: 'id', description: '文件ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功', type: File })
+  @ApiResponse({ status: 404, description: '文件不存在' })
   findOne(@Param('id') id: string) {
     return this.fileService.findOne(+id);
   }
 
   @Get('download/:fileId')
+  @ApiOperation({ summary: '下载文件', description: '根据文件ID下载文件' })
+  @ApiParam({
+    name: 'fileId',
+    description: '文件唯一标识',
+    example: '550e8400-e29b-41d4-a716-446655440000',
+  })
+  @ApiResponse({ status: 200, description: '文件下载成功' })
+  @ApiResponse({ status: 404, description: '文件不存在' })
   async getFileByFileId(@Param('fileId') fileId: string, @Res() res: Response) {
     try {
       const file = await this.fileService.findByFileId(fileId);
@@ -73,16 +106,40 @@ export class FileController {
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新文件记录', description: '根据ID更新文件记录' })
+  @ApiParam({ name: 'id', description: '文件ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功', type: File })
+  @ApiResponse({ status: 404, description: '文件不存在' })
   update(@Param('id') id: string, @Body() updateFileDto: UpdateFileDto) {
     return this.fileService.update(+id, updateFileDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除文件记录', description: '根据ID删除文件记录' })
+  @ApiParam({ name: 'id', description: '文件ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '文件不存在' })
   remove(@Param('id') id: string) {
     return this.fileService.remove(+id);
   }
 
   @Post('upload')
+  @ApiOperation({ summary: '上传文件', description: '上传文件到服务器' })
+  @ApiConsumes('multipart/form-data')
+  @ApiBody({
+    schema: {
+      type: 'object',
+      properties: {
+        file: {
+          type: 'string',
+          format: 'binary',
+          description: '要上传的文件',
+        },
+      },
+    },
+  })
+  @ApiResponse({ status: 201, description: '文件上传成功', type: File })
+  @ApiResponse({ status: 400, description: '文件上传失败' })
   @UseInterceptors(FileInterceptor('file'))
   async uploadFile(@UploadedFile() file: Express.Multer.File) {
     return await this.fileService.uploadFile(file);

+ 22 - 0
LMS-NodeJs/src/hot/hot.controller.ts

@@ -10,32 +10,54 @@ import {
 import { HotService } from './hot.service';
 import { CreateHotDto } from './dto/create-hot.dto';
 import { UpdateHotDto } from './dto/update-hot.dto';
+import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
 
+@ApiTags('hot')
 @Controller('hot')
 export class HotController {
   constructor(private readonly hotService: HotService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建热门记录', description: '创建新的热门记录' })
+  @ApiResponse({ status: 201, description: '热门记录创建成功' })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createHotDto: CreateHotDto) {
     return this.hotService.create(createHotDto);
   }
 
   @Get()
+  @ApiOperation({ summary: '获取所有热门', description: '获取所有热门列表' })
+  @ApiResponse({ status: 200, description: '获取成功' })
   findAll() {
     return this.hotService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取热门',
+    description: '根据热门ID获取单个热门记录',
+  })
+  @ApiParam({ name: 'id', description: '热门ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功' })
+  @ApiResponse({ status: 404, description: '热门记录不存在' })
   findOne(@Param('id') id: string) {
     return this.hotService.findOne(+id);
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新热门', description: '根据ID更新热门信息' })
+  @ApiParam({ name: 'id', description: '热门ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功' })
+  @ApiResponse({ status: 404, description: '热门记录不存在' })
   update(@Param('id') id: string, @Body() updateHotDto: UpdateHotDto) {
     return this.hotService.update(+id, updateHotDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除热门', description: '根据ID删除热门记录' })
+  @ApiParam({ name: 'id', description: '热门ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '热门记录不存在' })
   remove(@Param('id') id: string) {
     return this.hotService.remove(+id);
   }

+ 22 - 0
LMS-NodeJs/src/line/line.controller.ts

@@ -10,32 +10,54 @@ import {
 import { LineService } from './line.service';
 import { CreateLineDto } from './dto/create-line.dto';
 import { UpdateLineDto } from './dto/update-line.dto';
+import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
 
+@ApiTags('line')
 @Controller('line')
 export class LineController {
   constructor(private readonly lineService: LineService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建线路', description: '创建新的线路记录' })
+  @ApiResponse({ status: 201, description: '线路创建成功' })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createLineDto: CreateLineDto) {
     return this.lineService.create(createLineDto);
   }
 
   @Get()
+  @ApiOperation({ summary: '获取所有线路', description: '获取所有线路列表' })
+  @ApiResponse({ status: 200, description: '获取成功' })
   findAll() {
     return this.lineService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取线路',
+    description: '根据线路ID获取单个线路',
+  })
+  @ApiParam({ name: 'id', description: '线路ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功' })
+  @ApiResponse({ status: 404, description: '线路不存在' })
   findOne(@Param('id') id: string) {
     return this.lineService.findOne(+id);
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新线路', description: '根据ID更新线路信息' })
+  @ApiParam({ name: 'id', description: '线路ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功' })
+  @ApiResponse({ status: 404, description: '线路不存在' })
   update(@Param('id') id: string, @Body() updateLineDto: UpdateLineDto) {
     return this.lineService.update(+id, updateLineDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除线路', description: '根据ID删除线路' })
+  @ApiParam({ name: 'id', description: '线路ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '线路不存在' })
   remove(@Param('id') id: string) {
     return this.lineService.remove(+id);
   }

+ 20 - 0
LMS-NodeJs/src/main.ts

@@ -1,8 +1,28 @@
 import { NestFactory } from '@nestjs/core';
 import { AppModule } from './app.module';
+import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
 
 async function bootstrap() {
   const app = await NestFactory.create(AppModule, { cors: true });
+
+  // Swagger 配置
+  const config = new DocumentBuilder()
+    .setTitle('图书管理系统 API')
+    .setDescription('图书管理系统的 RESTful API 文档')
+    .setVersion('1.0')
+    .addTag('books', '图书相关接口')
+    .addTag('authors', '作者相关接口')
+    .addTag('tags', '标签相关接口')
+    .addTag('chapters', '章节相关接口')
+    .addTag('hot', '热门相关接口')
+    .addTag('aide', '助手相关接口')
+    .addTag('line', '线路相关接口')
+    .addTag('file', '文件相关接口')
+    .build();
+
+  const document = SwaggerModule.createDocument(app, config);
+  SwaggerModule.setup('api', app, document);
+
   await app.listen(process.env.PORT ?? 3000);
 }
 bootstrap();

+ 22 - 0
LMS-NodeJs/src/tag/tag.controller.ts

@@ -10,32 +10,54 @@ import {
 import { TagService } from './tag.service';
 import { CreateTagDto } from './dto/create-tag.dto';
 import { UpdateTagDto } from './dto/update-tag.dto';
+import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
 
+@ApiTags('tags')
 @Controller('tag')
 export class TagController {
   constructor(private readonly tagService: TagService) {}
 
   @Post()
+  @ApiOperation({ summary: '创建标签', description: '创建新的标签记录' })
+  @ApiResponse({ status: 201, description: '标签创建成功' })
+  @ApiResponse({ status: 400, description: '请求参数错误' })
   create(@Body() createTagDto: CreateTagDto) {
     return this.tagService.create(createTagDto);
   }
 
   @Get()
+  @ApiOperation({ summary: '获取所有标签', description: '获取所有标签列表' })
+  @ApiResponse({ status: 200, description: '获取成功' })
   findAll() {
     return this.tagService.findAll();
   }
 
   @Get(':id')
+  @ApiOperation({
+    summary: '根据ID获取标签',
+    description: '根据标签ID获取单个标签',
+  })
+  @ApiParam({ name: 'id', description: '标签ID', example: 1 })
+  @ApiResponse({ status: 200, description: '获取成功' })
+  @ApiResponse({ status: 404, description: '标签不存在' })
   findOne(@Param('id') id: string) {
     return this.tagService.findOne(+id);
   }
 
   @Patch(':id')
+  @ApiOperation({ summary: '更新标签', description: '根据ID更新标签信息' })
+  @ApiParam({ name: 'id', description: '标签ID', example: 1 })
+  @ApiResponse({ status: 200, description: '更新成功' })
+  @ApiResponse({ status: 404, description: '标签不存在' })
   update(@Param('id') id: string, @Body() updateTagDto: UpdateTagDto) {
     return this.tagService.update(+id, updateTagDto);
   }
 
   @Delete(':id')
+  @ApiOperation({ summary: '删除标签', description: '根据ID删除标签' })
+  @ApiParam({ name: 'id', description: '标签ID', example: 1 })
+  @ApiResponse({ status: 200, description: '删除成功' })
+  @ApiResponse({ status: 404, description: '标签不存在' })
   remove(@Param('id') id: string) {
     return this.tagService.remove(+id);
   }