diff --git a/src/modules/content/controllers/post.controller.ts b/src/modules/content/controllers/post.controller.ts index 46b95a7..efd2284 100644 --- a/src/modules/content/controllers/post.controller.ts +++ b/src/modules/content/controllers/post.controller.ts @@ -8,17 +8,22 @@ import { Patch, Post, Query, + SerializeOptions, + UseInterceptors, ValidationPipe, } from '@nestjs/common'; import { CreatePostDto, QueryPostDto, UpdatePostDto } from '@/modules/content/dtos/post.dto'; import { PostService } from '@/modules/content/services/post.service'; +import { AppInterceptor } from '@/modules/core/providers/app.interceptor'; +@UseInterceptors(AppInterceptor) @Controller('posts') export class PostController { constructor(private postService: PostService) {} @Get() + @SerializeOptions({ groups: ['post-list'] }) async list( @Query( new ValidationPipe({ @@ -35,11 +40,13 @@ export class PostController { } @Get(':id') + @SerializeOptions({ groups: ['post-detail'] }) async show(@Param('id', new ParseUUIDPipe()) id: string) { return this.postService.detail(id); } @Post() + @SerializeOptions({ groups: ['post-detail'] }) async store( @Body( new ValidationPipe({ @@ -57,6 +64,7 @@ export class PostController { } @Patch() + @SerializeOptions({ groups: ['post-detail'] }) async update( @Body( new ValidationPipe({ @@ -74,6 +82,7 @@ export class PostController { } @Delete(':id') + @SerializeOptions({ groups: ['post-detail'] }) async delete(@Param('id', new ParseUUIDPipe()) id: string) { return this.postService.delete(id); } diff --git a/src/modules/content/entities/post.entity.ts b/src/modules/content/entities/post.entity.ts index 601502c..1a2b95f 100644 --- a/src/modules/content/entities/post.entity.ts +++ b/src/modules/content/entities/post.entity.ts @@ -1,4 +1,4 @@ -import { Expose } from 'class-transformer'; +import { Exclude, Expose, Type } from 'class-transformer'; import { BaseEntity, Column, @@ -10,36 +10,49 @@ import { import { PostBodyType } from '@/modules/content/constants'; +@Exclude() @Entity('content_posts') export class PostEntity extends BaseEntity { + @Expose() @PrimaryColumn({ type: 'varchar', generated: 'uuid', length: 36 }) id: string; + @Expose() @Column({ comment: '文章标题' }) title: string; + @Expose({ groups: ['post-detail'] }) @Column({ comment: '文章内容', type: 'text' }) body: string; + @Expose() @Column({ comment: '文章描述', nullable: true }) summary?: string; + @Expose() @Expose() @Column({ comment: '关键字', type: 'simple-array', nullable: true }) keywords?: string[]; + @Expose() @Column({ comment: '文章类型', type: 'enum', enum: PostBodyType, default: PostBodyType.HTML }) type: PostBodyType; + @Expose() @Column({ comment: '发布时间', type: 'varchar', nullable: true }) publishedAt?: Date | null; + @Expose() @Column({ comment: '自定义文章排序', default: 0 }) customOrder: number; + @Expose() + @Type(() => Date) @CreateDateColumn({ comment: '创建时间' }) createdAt?: Date; + @Expose() + @Type(() => Date) @UpdateDateColumn({ comment: '更新时间', nullable: true }) updatedAt?: Date; } diff --git a/src/modules/core/providers/app.interceptor.ts b/src/modules/core/providers/app.interceptor.ts new file mode 100644 index 0000000..6b2ae23 --- /dev/null +++ b/src/modules/core/providers/app.interceptor.ts @@ -0,0 +1,35 @@ +import { + ClassSerializerContextOptions, + ClassSerializerInterceptor, + PlainLiteralObject, + StreamableFile, +} from '@nestjs/common'; +import { isArray, isNil, isObject } from 'lodash'; + +export class AppInterceptor extends ClassSerializerInterceptor { + serialize( + response: PlainLiteralObject | Array, + options: ClassSerializerContextOptions, + ): PlainLiteralObject | Array { + if ((!isObject(response) && !isArray(response)) || response instanceof StreamableFile) { + return response; + } + + if (isArray(response)) { + return (response as PlainLiteralObject[]).map((item) => { + return !isObject(item) ? item : this.transformToPlain(item, options); + }); + } + + if ('meta' in response && 'items' in response) { + const items = !isNil(response.items) && isArray(response.items) ? response.items : []; + return { + ...response, + items: (items as PlainLiteralObject[]).map((item) => { + return isObject(item) ? this.transformToPlain(item, options) : item; + }), + }; + } + return super.transformToPlain(response, options); + } +}