소스 검색

feat: 创建产品接口

IlhamTahir 1 년 전
부모
커밋
8d72401f74

+ 13 - 2
src/pet-feeder/controller/pet.controller.ts

@@ -1,8 +1,9 @@
-import { Controller, Post } from '@nestjs/common';
+import { Body, Controller, Get, Post } from '@nestjs/common';
 import { PetService } from '@/pet-feeder/service/pet.service';
 import { PetMapper } from '@/pet-feeder/mapper/pet.mapper';
 import { PetVo } from '@/pet-feeder/vo/pet.vo';
 import { CreatePetRequest } from '@/pet-feeder/dto/create-pet.request';
+import { ApiBearerAuth, ApiOkResponse } from '@nestjs/swagger';
 
 @Controller('pets')
 export class PetController {
@@ -12,7 +13,17 @@ export class PetController {
   ) {}
 
   @Post()
-  async create(createPetRequest: CreatePetRequest): Promise<PetVo> {
+  @ApiOkResponse({
+    type: PetVo,
+  })
+  @ApiBearerAuth()
+  async create(@Body() createPetRequest: CreatePetRequest): Promise<PetVo> {
     return this.petMapper.toVo(await this.petService.create(createPetRequest));
   }
+
+  @Get('own')
+  @ApiBearerAuth()
+  async ownPetList(): Promise<PetVo[]> {
+    return this.petMapper.toVos(await this.petService.ownPetList());
+  }
 }

+ 27 - 0
src/pet-feeder/controller/product.controller.ts

@@ -0,0 +1,27 @@
+import { Body, Controller, Post } from '@nestjs/common';
+import { CreateProductRequest } from '@/pet-feeder/dto/create-product.request';
+import { ProductService } from '@/pet-feeder/service/product.service';
+import { ProductVo } from '@/pet-feeder/vo/product.vo';
+import { ProductMapper } from '@/pet-feeder/mapper/product.mapper';
+import { ApiBearerAuth, ApiOkResponse } from '@nestjs/swagger';
+
+@Controller('products')
+export class ProductController {
+  constructor(
+    private readonly productService: ProductService,
+    private readonly productMapper: ProductMapper,
+  ) {}
+
+  @Post()
+  @ApiOkResponse({
+    type: ProductVo,
+  })
+  @ApiBearerAuth()
+  async create(
+    @Body() createProductRequest: CreateProductRequest,
+  ): Promise<ProductVo> {
+    return this.productMapper.toVo(
+      await this.productService.create(createProductRequest),
+    );
+  }
+}

+ 2 - 4
src/pet-feeder/dto/create-pet.request.ts

@@ -1,7 +1,7 @@
 import { PetType } from '@/pet-feeder/enum/pet-type';
 import { Gender } from '@/core/enum/Gender';
 import { PetBodyType } from '@/pet-feeder/enum/pet-body-type';
-import { IsNotEmpty } from 'class-validator';
+import { IsNotEmpty, IsOptional } from 'class-validator';
 import { ApiProperty } from '@nestjs/swagger';
 
 export class CreatePetRequest {
@@ -35,9 +35,7 @@ export class CreatePetRequest {
   @ApiProperty()
   weight: number;
 
-  @IsNotEmpty({
-    message: '照片不能为空',
-  })
+  @IsOptional()
   @ApiProperty()
   photo: string;
 

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

@@ -0,0 +1,32 @@
+import { IsNotEmpty, IsOptional } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class CreateProductRequest {
+  @IsNotEmpty({
+    message: '产品名称不能为空',
+  })
+  @ApiProperty()
+  name: string;
+
+  @IsNotEmpty({
+    message: '产品图片不能为空',
+  })
+  @ApiProperty()
+  photo: string;
+
+  @IsOptional()
+  @ApiProperty()
+  tags: string[] = [];
+
+  @IsNotEmpty({
+    message: '总卡路里不能为空',
+  })
+  @ApiProperty()
+  totalCalories: number;
+
+  @IsNotEmpty({
+    message: '总重量不能为空',
+  })
+  @ApiProperty()
+  totalWeight: number;
+}

+ 28 - 0
src/pet-feeder/entity/feeding-plan-product.entity.ts

@@ -0,0 +1,28 @@
+import { BaseEntity } from '@/core/entity/base.entity';
+import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
+import { FeedingPlan } from '@/pet-feeder/entity/feeding-plan.entity';
+import { Product } from '@/pet-feeder/entity/product.entity';
+
+@Entity()
+export class FeedingPlanProduct extends BaseEntity {
+  @Column()
+  dailyUsageWeight: number;
+
+  @ManyToOne(
+    () => FeedingPlan,
+    (feedingPlan) => feedingPlan.feedingPlanProducts,
+  )
+  @JoinColumn({
+    name: 'feedingPlanId',
+  })
+  feedingPlan: FeedingPlan;
+
+  @ManyToOne(() => Product, (product) => product.feedingPlanProducts, {
+    eager: true,
+    onDelete: 'CASCADE',
+  })
+  @JoinColumn({
+    name: 'productId',
+  })
+  product: Product;
+}

+ 8 - 1
src/pet-feeder/entity/feeding-plan.entity.ts

@@ -1,7 +1,8 @@
 import { BaseEntity } from '@/core/entity/base.entity';
-import { Column, Entity, OneToOne } from 'typeorm';
+import { Column, Entity, OneToMany, OneToOne } from 'typeorm';
 import { Pet } from '@/pet-feeder/entity/pet.entity';
 import { FeedingGoal } from '@/pet-feeder/enum/feeding-goal';
+import { FeedingPlanProduct } from '@/pet-feeder/entity/feeding-plan-product.entity';
 
 @Entity()
 export class FeedingPlan extends BaseEntity {
@@ -14,4 +15,10 @@ export class FeedingPlan extends BaseEntity {
   // 反向一对一关系
   @OneToOne(() => Pet, (pet) => pet.feedingPlan)
   pet: Pet;
+
+  @OneToMany(
+    () => FeedingPlanProduct,
+    (feedingPlanProduct) => feedingPlanProduct.product,
+  )
+  feedingPlanProducts: FeedingPlanProduct[];
 }

+ 30 - 0
src/pet-feeder/entity/product.entity.ts

@@ -0,0 +1,30 @@
+import { BaseEntity } from '@/core/entity/base.entity';
+import { Column, Entity, OneToMany } from 'typeorm';
+import { FeedingPlanProduct } from '@/pet-feeder/entity/feeding-plan-product.entity';
+
+@Entity()
+export class Product extends BaseEntity {
+  @Column()
+  name: string;
+
+  @Column()
+  photo: string;
+
+  @Column({
+    type: 'json',
+  })
+  tags: string[];
+
+  @Column()
+  totalCalories: number;
+
+  @Column()
+  totalWeight: number;
+
+  @OneToMany(
+    () => FeedingPlanProduct,
+    (feedingPlanProduct) => feedingPlanProduct.feedingPlan,
+    { cascade: true },
+  )
+  feedingPlanProducts: FeedingPlanProduct[];
+}

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

@@ -2,6 +2,7 @@ import { BaseMapper } from '@/core/mapper/base.mapper';
 import { Pet } from '@/pet-feeder/entity/pet.entity';
 import { PetVo } from '@/pet-feeder/vo/pet.vo';
 import { Injectable } from '@nestjs/common';
+import { DateUtil } from '@/core/util/date.util';
 
 @Injectable()
 export class PetMapper extends BaseMapper<Pet, PetVo> {
@@ -11,7 +12,7 @@ export class PetMapper extends BaseMapper<Pet, PetVo> {
       name: entity.name,
       type: entity.type,
       gender: entity.gender,
-      birthday: entity.birthday.toISOString(),
+      birthday: DateUtil.format(entity.birthday),
       weight: entity.weight,
       photo: entity.photo,
       isActive: entity.isActive,

+ 18 - 0
src/pet-feeder/mapper/product.mapper.ts

@@ -0,0 +1,18 @@
+import { BaseMapper } from '@/core/mapper/base.mapper';
+import { Product } from '@/pet-feeder/entity/product.entity';
+import { ProductVo } from '@/pet-feeder/vo/product.vo';
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class ProductMapper extends BaseMapper<Product, ProductVo> {
+  toVo(entity: Product): ProductVo {
+    return {
+      ...super.toVo(entity),
+      name: entity.name,
+      photo: entity.photo,
+      tags: entity.tags,
+      totalCalories: entity.totalCalories,
+      totalWeight: entity.totalWeight,
+    };
+  }
+}

+ 11 - 3
src/pet-feeder/pet-feeder.module.ts

@@ -4,11 +4,19 @@ import { Pet } from '@/pet-feeder/entity/pet.entity';
 import { FeedingPlan } from '@/pet-feeder/entity/feeding-plan.entity';
 import { PetService } from '@/pet-feeder/service/pet.service';
 import { PetMapper } from '@/pet-feeder/mapper/pet.mapper';
+import { PetController } from '@/pet-feeder/controller/pet.controller';
+import { FeedingPlanProduct } from '@/pet-feeder/entity/feeding-plan-product.entity';
+import { Product } from '@/pet-feeder/entity/product.entity';
+import { ProductService } from '@/pet-feeder/service/product.service';
+import { ProductMapper } from '@/pet-feeder/mapper/product.mapper';
+import { ProductController } from '@/pet-feeder/controller/product.controller';
 
 @Module({
-  imports: [TypeOrmModule.forFeature([Pet, FeedingPlan])],
-  controllers: [],
-  providers: [PetService, PetMapper],
+  imports: [
+    TypeOrmModule.forFeature([Pet, FeedingPlan, FeedingPlanProduct, Product]),
+  ],
+  controllers: [PetController, ProductController],
+  providers: [PetService, PetMapper, ProductService, ProductMapper],
   exports: [],
 })
 export class PetFeederModule {}

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

@@ -3,6 +3,7 @@ import { CreatePetRequest } from '@/pet-feeder/dto/create-pet.request';
 import { InjectRepository } from '@nestjs/typeorm';
 import { Pet } from '@/pet-feeder/entity/pet.entity';
 import { Repository } from 'typeorm';
+import { RequestContext } from 'nestjs-request-context';
 
 @Injectable()
 export class PetService {
@@ -27,4 +28,11 @@ export class PetService {
     });
     return this.petRepository.save(pet);
   }
+
+  async ownPetList(): Promise<Pet[]> {
+    const id = RequestContext.currentContext.req.user.id;
+    return this.petRepository.findBy({
+      createBy: { id },
+    });
+  }
 }

+ 20 - 0
src/pet-feeder/service/product.service.ts

@@ -0,0 +1,20 @@
+import { Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Product } from '@/pet-feeder/entity/product.entity';
+import { Repository } from 'typeorm';
+import { CreateProductRequest } from '@/pet-feeder/dto/create-product.request';
+
+@Injectable()
+export class ProductService {
+  constructor(
+    @InjectRepository(Product)
+    private readonly productRepository: Repository<Product>,
+  ) {}
+
+  async create(createProductRequest: CreateProductRequest): Promise<Product> {
+    const product = this.productRepository.create({
+      ...createProductRequest,
+    });
+    return this.productRepository.save(product);
+  }
+}

+ 18 - 0
src/pet-feeder/vo/product.vo.ts

@@ -0,0 +1,18 @@
+import { BaseVo } from '@/core/vo/base.vo';
+import { ApiProperty, ApiSchema } from '@nestjs/swagger';
+
+@ApiSchema({
+  name: 'Product',
+})
+export class ProductVo extends BaseVo {
+  @ApiProperty()
+  name: string;
+  @ApiProperty()
+  photo: string;
+  @ApiProperty()
+  tags: string[];
+  @ApiProperty()
+  totalCalories: number;
+  @ApiProperty()
+  totalWeight: number;
+}