浏览代码

feat: implement pet variety management with CRUD operations and integrate into pet entity

IlhamTahir 5 月之前
父节点
当前提交
e99524a157

+ 64 - 0
src/pet-feeder/controller/pet-variety.controller.ts

@@ -0,0 +1,64 @@
+import {
+  Body,
+  Controller,
+  Delete,
+  Get,
+  Param,
+  Post,
+  Put,
+  Query,
+} from '@nestjs/common';
+import { PetVarietyVo } from '@/pet-feeder/vo/pet-variety.vo';
+import { PetVarietyService } from '@/pet-feeder/service/pet-variety.service';
+import { PetVarietyMapper } from '@/pet-feeder/mapper/pet-variety.mapper';
+import { PageResultMapper } from '@/core/mapper/page-result.mapper';
+import { SearchPetVarietyFilter } from '@/pet-feeder/dto/search-pet-variety.filter';
+
+@Controller('/pet-varieties')
+export class PetVarietyController {
+  constructor(
+    private readonly petVarietyService: PetVarietyService,
+    private readonly petVarietyMapper: PetVarietyMapper,
+  ) {}
+
+  @Post()
+  async create(@Body('name') name: string) {
+    return this.petVarietyMapper.toVo(
+      await this.petVarietyService.create(name),
+    );
+  }
+
+  @Get('/list')
+  async list() {
+    return this.petVarietyMapper.toVos(await this.petVarietyService.list());
+  }
+  @Get('/:id')
+  async get(@Param('id') id: string) {
+    return this.petVarietyMapper.toVo(await this.petVarietyService.get(id));
+  }
+
+  @Get()
+  async search(@Query() searchPetVarietyFilter: SearchPetVarietyFilter) {
+    const [data, total] = await this.petVarietyService.search(
+      searchPetVarietyFilter,
+    );
+    return PageResultMapper.toPageResult<PetVarietyVo>(
+      this.petVarietyMapper.toVos(data),
+      searchPetVarietyFilter.getPage(),
+      searchPetVarietyFilter.getSize(),
+      total,
+    );
+  }
+
+  @Delete('/:id')
+  async delete(@Param('id') id: string) {
+    await this.petVarietyService.delete(id);
+  }
+
+  @Put('/:id')
+  async update(@Param('id') id: string, @Body('name') name: string) {
+    return this.petVarietyMapper.toVo(
+      await this.petVarietyService.update(id, name),
+    );
+  }
+}

+ 6 - 0
src/pet-feeder/dto/create-pet.request.ts

@@ -17,6 +17,12 @@ export class CreatePetRequest {
   @ApiProperty()
   type: PetType;
 
+  @IsNotEmpty({
+    message: '请选择品种',
+  })
+  @ApiProperty()
+  varietyName: string;
+
   @IsNotEmpty({
     message: '请选择性别',
   })

+ 7 - 0
src/pet-feeder/dto/search-pet-variety.filter.ts

@@ -0,0 +1,7 @@
+import { BaseFilter } from '@/core/dto/base.filter';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class SearchPetVarietyFilter extends BaseFilter {
+  @ApiProperty()
+  order = ['-createdTime'];
+}

+ 8 - 0
src/pet-feeder/entity/pet-variety.entity.ts

@@ -0,0 +1,8 @@
+import { Column, Entity } from 'typeorm';
+import { BaseEntity } from '@/core/entity/base.entity';
+
+@Entity()
+export class PetVariety extends BaseEntity {
+  @Column()
+  name: string;
+}

+ 5 - 0
src/pet-feeder/entity/pet.entity.ts

@@ -4,6 +4,7 @@ import { Gender } from '@/core/enum/Gender';
 import { PetBodyType } from '@/pet-feeder/enum/pet-body-type';
 import { Column, Entity, JoinColumn, OneToOne } from 'typeorm';
 import { FeedingPlan } from '@/pet-feeder/entity/feeding-plan.entity';
+import { PetVariety } from '@/pet-feeder/entity/pet-variety.entity';
 
 @Entity()
 export class Pet extends TraceableEntity {
@@ -17,6 +18,10 @@ export class Pet extends TraceableEntity {
   })
   type: PetType;
 
+  @OneToOne(() => PetVariety, { eager: true })
+  @JoinColumn({ name: 'varietyId' })
+  variety: PetVariety;
+
   @Column({
     type: 'enum',
     enum: PetType,

+ 12 - 0
src/pet-feeder/mapper/pet-variety.mapper.ts

@@ -0,0 +1,12 @@
+import { BaseMapper } from '@/core/mapper/base.mapper';
+import { PetVariety } from '@/pet-feeder/entity/pet-variety.entity';
+import { PetVarietyVo } from '@/pet-feeder/vo/pet-variety.vo';
+
+export class PetVarietyMapper extends BaseMapper<PetVariety, PetVarietyVo> {
+  toVo(entity: PetVariety): PetVarietyVo {
+    return {
+      ...super.toVo(entity),
+      name: entity.name,
+    };
+  }
+}

+ 1 - 0
src/pet-feeder/mapper/pet.mapper.ts

@@ -16,6 +16,7 @@ export class PetMapper extends BaseMapper<Pet, PetVo> {
       ...super.toVo(entity),
       name: entity.name,
       type: entity.type,
+      varietyName: entity.variety ? entity.variety.name : '',
       gender: entity.gender,
       birthday: DateUtil.format(entity.birthday),
       weight: entity.weight,

+ 19 - 2
src/pet-feeder/pet-feeder.module.ts

@@ -14,12 +14,27 @@ import { FeedingPlanService } from '@/pet-feeder/service/feeding-plan.service';
 import { FeedingPlanMapper } from '@/pet-feeder/mapper/feeding-plan.mapper';
 import { FeedingPlanController } from '@/pet-feeder/controller/feeding-plan.controller';
 import { FeedingPlanProductMapper } from '@/pet-feeder/mapper/feeding-plan-product.mapper';
+import { PetVariety } from '@/pet-feeder/entity/pet-variety.entity';
+import { PetVarietyController } from '@/pet-feeder/controller/pet-variety.controller';
+import { PetVarietyService } from '@/pet-feeder/service/pet-variety.service';
+import { PetVarietyMapper } from '@/pet-feeder/mapper/pet-variety.mapper';
 
 @Module({
   imports: [
-    TypeOrmModule.forFeature([Pet, FeedingPlan, FeedingPlanProduct, Product]),
+    TypeOrmModule.forFeature([
+      Pet,
+      FeedingPlan,
+      FeedingPlanProduct,
+      Product,
+      PetVariety,
+    ]),
+  ],
+  controllers: [
+    PetController,
+    ProductController,
+    FeedingPlanController,
+    PetVarietyController,
   ],
-  controllers: [PetController, ProductController, FeedingPlanController],
   providers: [
     PetService,
     PetMapper,
@@ -28,6 +43,8 @@ import { FeedingPlanProductMapper } from '@/pet-feeder/mapper/feeding-plan-produ
     FeedingPlanService,
     FeedingPlanMapper,
     FeedingPlanProductMapper,
+    PetVarietyService,
+    PetVarietyMapper,
   ],
   exports: [],
 })

+ 60 - 0
src/pet-feeder/service/pet-variety.service.ts

@@ -0,0 +1,60 @@
+import { Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { PetVariety } from '@/pet-feeder/entity/pet-variety.entity';
+import { Repository } from 'typeorm';
+import { SearchPetVarietyFilter } from '@/pet-feeder/dto/search-pet-variety.filter';
+
+@Injectable()
+export class PetVarietyService {
+  constructor(
+    @InjectRepository(PetVariety)
+    private readonly petVarietyRepository: Repository<PetVariety>,
+  ) {}
+
+  async create(name: string): Promise<PetVariety> {
+    const petVariety = this.petVarietyRepository.create({
+      name,
+    });
+    return this.petVarietyRepository.save(petVariety);
+  }
+
+  async get(id: string): Promise<PetVariety> {
+    const petVariety = await this.petVarietyRepository.findOneBy({
+      id,
+    });
+    if (!petVariety) {
+      throw new Error('PetVariety not found');
+    }
+    return petVariety;
+  }
+
+  async search(searchPetVarietyFilter: SearchPetVarietyFilter) {
+    return this.petVarietyRepository.findAndCount({
+      where: searchPetVarietyFilter.getConditions(),
+      skip: searchPetVarietyFilter.getSkip(),
+      take: searchPetVarietyFilter.getSize(),
+      order: searchPetVarietyFilter.getOrderBy(),
+    });
+  }
+
+  async delete(id: string) {
+    const petVariety = await this.get(id);
+    return this.petVarietyRepository.remove(petVariety);
+  }
+
+  async update(id: string, name: string) {
+    const petVariety = await this.get(id);
+    petVariety.name = name;
+    return this.petVarietyRepository.save(petVariety);
+  }
+
+  async list() {
+    return this.petVarietyRepository.find();
+  }
+
+  getByName(name: string) {
+    return this.petVarietyRepository.findOneBy({
+      name,
+    });
+  }
+}

+ 7 - 0
src/pet-feeder/service/pet.service.ts

@@ -4,18 +4,25 @@ import { InjectRepository } from '@nestjs/typeorm';
 import { Pet } from '@/pet-feeder/entity/pet.entity';
 import { Repository } from 'typeorm';
 import { RequestContext } from 'nestjs-request-context';
+import { PetVariety } from '@/pet-feeder/entity/pet-variety.entity';
+import { PetVarietyService } from '@/pet-feeder/service/pet-variety.service';
 
 @Injectable()
 export class PetService {
   constructor(
     @InjectRepository(Pet)
     private readonly petRepository: Repository<Pet>,
+
+    private readonly petVarietyService: PetVarietyService,
   ) {}
 
   async create(createPetRequest: CreatePetRequest): Promise<Pet> {
     const pet = this.petRepository.create({
       name: createPetRequest.name,
       type: createPetRequest.type,
+      variety: createPetRequest.varietyName
+        ? await this.petVarietyService.getByName(createPetRequest.varietyName)
+        : null,
       gender: createPetRequest.gender,
       birthday: createPetRequest.birthday,
       weight: createPetRequest.weight,

+ 10 - 0
src/pet-feeder/vo/pet-variety.vo.ts

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

+ 2 - 1
src/pet-feeder/vo/pet.vo.ts

@@ -3,7 +3,6 @@ import { ApiProperty, ApiSchema } from '@nestjs/swagger';
 import { PetType } from '@/pet-feeder/enum/pet-type';
 import { Gender } from '@/core/enum/Gender';
 import { PetBodyType } from '@/pet-feeder/enum/pet-body-type';
-import { FeedingPlan } from '@/pet-feeder/entity/feeding-plan.entity';
 import { FeedingPlanVo } from '@/pet-feeder/vo/feeding-plan.vo';
 
 @ApiSchema({
@@ -17,6 +16,8 @@ export class PetVo extends TraceableVo {
   @ApiProperty()
   gender: Gender;
   @ApiProperty()
+  varietyName: string;
+  @ApiProperty()
   birthday: string;
   @ApiProperty()
   weight: number;