Explorar o código

feat: 推荐检索列表

IlhamTahir hai 1 ano
pai
achega
79bf751a30

+ 9 - 1
src/article/article.module.ts

@@ -10,6 +10,8 @@ import { CarousalController } from './controller/carousal.controller';
 import { CarousalService } from './service/carousal.service';
 import { Carousal } from './entity/carousal.entity';
 import { ArticleSearchRecord } from './entity/article-search-record.entity';
+import { ArticleSearchRecommend } from './entity/article-search-recommend.entity';
+import { ArticleSearchRecommendMapper } from './mapper/article-search-recommend.mapper';
 
 @Module({
   controllers: [CategoryController, ArticleController, CarousalController],
@@ -19,8 +21,14 @@ import { ArticleSearchRecord } from './entity/article-search-record.entity';
       Article,
       Carousal,
       ArticleSearchRecord,
+      ArticleSearchRecommend,
     ]),
   ],
-  providers: [CategoryService, ArticleService, CarousalService],
+  providers: [
+    CategoryService,
+    ArticleService,
+    CarousalService,
+    ArticleSearchRecommendMapper,
+  ],
 })
 export class ArticleModule {}

+ 39 - 3
src/article/controller/article.controller.ts

@@ -18,10 +18,16 @@ import { PageResult } from '../../core/vo/page-result';
 import { PageResultMapper } from '../../core/mapper/page-result.mapper';
 import { ArticleSearchRecordMapper } from '../mapper/article-search-record.mapper';
 import { ArticleSearchRecordVo } from '../vo/article-search-record.vo';
+import { ArticleSearchRecommendMapper } from '../mapper/article-search-recommend.mapper';
+import { ArticleSearchRecommendVo } from '../vo/article-search-recommend.vo';
+import { CreateArticleSearchRecommendRequest } from '../dto/create-article-search-recommend.request';
 
 @Controller('articles')
 export class ArticleController {
-  constructor(private readonly articleService: ArticleService) {}
+  constructor(
+    private readonly articleService: ArticleService,
+    private readonly articleSearchRecommendMapper: ArticleSearchRecommendMapper,
+  ) {}
   @Post()
   @ApiBearerAuth()
   @ApiOkResponse({
@@ -65,12 +71,12 @@ export class ArticleController {
   @Get('search-records')
   @ApiBearerAuth()
   @ApiOkResponse({
-    description: '查询列表',
+    description: '历史关键词列表',
     schema: {
       allOf: [
         {
           type: 'array',
-          items: { $ref: getSchemaPath(ArticleVo) }, // 泛型内容具体化
+          items: { $ref: getSchemaPath(ArticleSearchRecordVo) }, // 泛型内容具体化
         },
       ],
     },
@@ -81,6 +87,36 @@ export class ArticleController {
     );
   }
 
+  @Get('active-search-recommends')
+  @ApiBearerAuth()
+  @ApiOkResponse({
+    description: '推荐关键词',
+    type: ArticleSearchRecommendVo, // 单个对象
+    isArray: true, // 指定返回值是数组
+  })
+  async activeArticleSearchRecommends() {
+    return this.articleSearchRecommendMapper.toVos(
+      await this.articleService.activeArticleSearchRecommends(),
+    );
+  }
+
+  @Post('search-recommends')
+  @ApiBearerAuth()
+  @ApiOkResponse({
+    description: '创建推荐关键词',
+    type: ArticleSearchRecommendVo,
+  })
+  async createArticleSearchRecommend(
+    @Body()
+    createArticleSearchRecommendRequest: CreateArticleSearchRecommendRequest,
+  ) {
+    return this.articleSearchRecommendMapper.toVo(
+      await this.articleService.createArticleSearchRecommend(
+        createArticleSearchRecommendRequest,
+      ),
+    );
+  }
+
   @Get(':id')
   @ApiBearerAuth()
   @ApiOkResponse({

+ 10 - 0
src/article/dto/create-article-search-recommend.request.ts

@@ -0,0 +1,10 @@
+import { IsNotEmpty } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class CreateArticleSearchRecommendRequest {
+  @IsNotEmpty({
+    message: '关键词不能为空',
+  })
+  @ApiProperty()
+  keyword: string;
+}

+ 11 - 0
src/article/entity/article-search-recommend.entity.ts

@@ -0,0 +1,11 @@
+import { TraceableEntity } from '../../core/entity/traceable.entity';
+import { Column, Entity } from 'typeorm';
+
+@Entity()
+export class ArticleSearchRecommend extends TraceableEntity {
+  @Column()
+  keyword: string;
+
+  @Column()
+  enabled: boolean = true;
+}

+ 17 - 0
src/article/mapper/article-search-recommend.mapper.ts

@@ -0,0 +1,17 @@
+import { BaseMapper } from '../../core/mapper/base.mapper';
+import { ArticleSearchRecommend } from '../entity/article-search-recommend.entity';
+import { ArticleSearchRecommendVo } from '../vo/article-search-recommend.vo';
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class ArticleSearchRecommendMapper extends BaseMapper<
+  ArticleSearchRecommend,
+  ArticleSearchRecommendVo
+> {
+  toVo(entity: ArticleSearchRecommend): ArticleSearchRecommendVo {
+    return {
+      ...super.toVo(entity),
+      keyword: entity.keyword,
+    };
+  }
+}

+ 22 - 0
src/article/service/article.service.ts

@@ -11,6 +11,8 @@ import { ArticleStatus } from '../enum/article.status';
 import { ArticleSearchRecord } from '../entity/article-search-record.entity';
 import { RequestContext } from 'nestjs-request-context';
 import { User } from '../../core/entity/user.entity';
+import { ArticleSearchRecommend } from '../entity/article-search-recommend.entity';
+import { CreateArticleSearchRecommendRequest } from '../dto/create-article-search-recommend.request';
 
 @Injectable()
 export class ArticleService {
@@ -21,6 +23,9 @@ export class ArticleService {
     private readonly categoryService: CategoryService,
     @InjectRepository(ArticleSearchRecord)
     private readonly articleSearchRecordRepository: Repository<ArticleSearchRecord>,
+
+    @InjectRepository(ArticleSearchRecommend)
+    private readonly articleSearchRecommendRepository: Repository<ArticleSearchRecommend>,
   ) {}
 
   async create(createArticleRequest: CreateArticleRequest) {
@@ -126,4 +131,21 @@ export class ArticleService {
       skip: 0,
     });
   }
+
+  async activeArticleSearchRecommends(): Promise<ArticleSearchRecommend[]> {
+    return this.articleSearchRecommendRepository.findBy({
+      enabled: true,
+    });
+  }
+
+  async createArticleSearchRecommend(
+    createArticleSearchRecommendRequest: CreateArticleSearchRecommendRequest,
+  ) {
+    const articleSearchRecommend = this.articleSearchRecommendRepository.create(
+      {
+        keyword: createArticleSearchRecommendRequest.keyword,
+      },
+    );
+    return this.articleSearchRecommendRepository.save(articleSearchRecommend);
+  }
 }

+ 10 - 0
src/article/vo/article-search-recommend.vo.ts

@@ -0,0 +1,10 @@
+import { BaseVo } from '../../core/vo/base.vo';
+import { ApiProperty, ApiSchema } from '@nestjs/swagger';
+
+@ApiSchema({
+  name: 'ArticleSearchRecommend',
+})
+export class ArticleSearchRecommendVo extends BaseVo {
+  @ApiProperty()
+  keyword: string;
+}

+ 18 - 0
src/core/mapper/base.mapper.ts

@@ -0,0 +1,18 @@
+import { BaseEntity } from '../entity/base.entity';
+import { BaseVo } from '../vo/base.vo';
+import { DateUtil } from '../util/date.util';
+
+export abstract class BaseMapper<Entity extends BaseEntity, Vo extends BaseVo> {
+  toVo(entity: Entity): Vo {
+    if (!entity) return null;
+    return {
+      id: entity.id,
+      createdTime: DateUtil.format(entity.createdTime),
+      updatedTime: DateUtil.format(entity.updatedTime),
+    } as Vo;
+  }
+
+  toVos(entities: Entity[]): Vo[] {
+    return entities.map((entity) => this.toVo(entity));
+  }
+}