2
0

2 Revīzijas 089cacee78 ... 7c34f8b986

Autors SHA1 Ziņojums Datums
  IlhamTahir 7c34f8b986 feat: 创建宠物接口 1 gadu atpakaļ
  IlhamTahir 5939e959d9 feat: 宠物及喂养计划模型设计 1 gadu atpakaļ

+ 2 - 1
src/app.module.ts

@@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
 import { CoreModule } from './core/core.module';
 import { ArticleModule } from './article/article.module';
 import { WeChatModule } from './we-chat/we-chat.module';
+import { PetFeederModule } from './pet-feeder/pet-feeder.module';
 
 @Module({
-  imports: [CoreModule, ArticleModule, WeChatModule],
+  imports: [CoreModule, ArticleModule, WeChatModule, PetFeederModule],
   controllers: [],
   providers: [],
 })

+ 18 - 0
src/pet-feeder/controller/pet.controller.ts

@@ -0,0 +1,18 @@
+import { Controller, 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';
+
+@Controller('pets')
+export class PetController {
+  constructor(
+    private readonly petService: PetService,
+    private readonly petMapper: PetMapper,
+  ) {}
+
+  @Post()
+  async create(createPetRequest: CreatePetRequest): Promise<PetVo> {
+    return this.petMapper.toVo(await this.petService.create(createPetRequest));
+  }
+}

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

@@ -0,0 +1,73 @@
+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 { ApiProperty } from '@nestjs/swagger';
+
+export class CreatePetRequest {
+  @IsNotEmpty({
+    message: '宠物名称不能为空',
+  })
+  @ApiProperty()
+  name: string;
+
+  @IsNotEmpty({
+    message: '请选择宠物类型',
+  })
+  @ApiProperty()
+  type: PetType;
+
+  @IsNotEmpty({
+    message: '请选择性别',
+  })
+  @ApiProperty()
+  gender: Gender;
+
+  @IsNotEmpty({
+    message: '生日不能为空',
+  })
+  @ApiProperty()
+  birthday: string;
+
+  @IsNotEmpty({
+    message: '体重不能为空',
+  })
+  @ApiProperty()
+  weight: number;
+
+  @IsNotEmpty({
+    message: '照片不能为空',
+  })
+  @ApiProperty()
+  photo: string;
+
+  @IsNotEmpty({
+    message: '是否活跃不能为空',
+  })
+  @ApiProperty()
+  isActive: boolean;
+
+  @IsNotEmpty({
+    message: '是否怀孕不能为空',
+  })
+  @ApiProperty()
+  isPregnant: boolean;
+
+  @IsNotEmpty({
+    message: '是否绝育不能为空',
+  })
+  @ApiProperty()
+  isSterilization: boolean;
+
+  @IsNotEmpty({
+    message: '是否在哺乳不能为空',
+  })
+  @ApiProperty()
+  isLactation: boolean;
+
+  @IsNotEmpty({
+    message: '请选择体型',
+  })
+  @ApiProperty()
+  bodyType: PetBodyType;
+}

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

@@ -0,0 +1,17 @@
+import { BaseEntity } from '@/core/entity/base.entity';
+import { Column, Entity, OneToOne } from 'typeorm';
+import { Pet } from '@/pet-feeder/entity/pet.entity';
+import { FeedingGoal } from '@/pet-feeder/enum/feeding-goal';
+
+@Entity()
+export class FeedingPlan extends BaseEntity {
+  @Column()
+  targetWeight: number;
+
+  @Column()
+  feedingGoal: FeedingGoal;
+
+  // 反向一对一关系
+  @OneToOne(() => Pet, (pet) => pet.feedingPlan)
+  pet: Pet;
+}

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

@@ -0,0 +1,64 @@
+import { TraceableEntity } from '@/core/entity/traceable.entity';
+import { PetType } from '@/pet-feeder/enum/pet-type';
+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';
+
+@Entity()
+export class Pet extends TraceableEntity {
+  @Column()
+  name: string;
+
+  @Column({
+    type: 'enum',
+    enum: PetType,
+    default: PetType.CAT,
+  })
+  type: PetType;
+
+  @Column({
+    type: 'enum',
+    enum: PetType,
+    default: PetType.CAT,
+  })
+  gender: Gender;
+
+  @Column()
+  birthday: Date;
+
+  @Column()
+  weight: number;
+
+  @Column()
+  photo: string;
+
+  @Column()
+  isActive: boolean;
+
+  @Column()
+  isPregnant: boolean;
+
+  // 是否绝育
+  @Column()
+  isSterilization: boolean;
+
+  // 是否在哺乳
+  @Column()
+  isLactation: boolean;
+
+  // 体型
+  @Column({
+    type: 'enum',
+    enum: PetBodyType,
+    default: PetBodyType.IDEAL,
+  })
+  bodyType: PetBodyType;
+
+  // 一对一喂养计划
+  @OneToOne(() => FeedingPlan, (feedingPlan) => feedingPlan.pet, {
+    cascade: true,
+  })
+  @JoinColumn() // 用于指定外键关系
+  feedingPlan: FeedingPlan;
+}

+ 5 - 0
src/pet-feeder/enum/feeding-goal.ts

@@ -0,0 +1,5 @@
+export enum FeedingGoal {
+  GAIN = 'gain',
+  LOSE = 'lose',
+  MAINTAIN = 'maintain',
+}

+ 18 - 0
src/pet-feeder/enum/pet-body-type.ts

@@ -0,0 +1,18 @@
+export enum PetBodyType {
+  // 极度消瘦
+  EXTREMELY_THIN = 'extremely-thin',
+  // 非常瘦
+  VERY_THIN = 'very-thin',
+  // 消瘦
+  THIN = 'thin',
+  // 偏轻
+  UNDERWEIGHT = 'underweight',
+  // 理想体重
+  IDEAL = 'ideal',
+  // 偏重
+  OVERWEIGHT = 'overweight',
+  // 肥胖
+  OBESE = 'obese',
+  // 极度肥胖
+  EXTREMELY_OBESE = 'extremely-obese',
+}

+ 4 - 0
src/pet-feeder/enum/pet-type.ts

@@ -0,0 +1,4 @@
+export enum PetType {
+  CAT = 'cat',
+  DOG = 'dog',
+}

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

@@ -0,0 +1,24 @@
+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';
+
+@Injectable()
+export class PetMapper extends BaseMapper<Pet, PetVo> {
+  toVo(entity: Pet): PetVo {
+    return {
+      ...super.toVo(entity),
+      name: entity.name,
+      type: entity.type,
+      gender: entity.gender,
+      birthday: entity.birthday.toISOString(),
+      weight: entity.weight,
+      photo: entity.photo,
+      isActive: entity.isActive,
+      isPregnant: entity.isPregnant,
+      isSterilization: entity.isSterilization,
+      isLactation: entity.isLactation,
+      bodyType: entity.bodyType,
+    };
+  }
+}

+ 14 - 0
src/pet-feeder/pet-feeder.module.ts

@@ -0,0 +1,14 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+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';
+
+@Module({
+  imports: [TypeOrmModule.forFeature([Pet, FeedingPlan])],
+  controllers: [],
+  providers: [PetService, PetMapper],
+  exports: [],
+})
+export class PetFeederModule {}

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

@@ -0,0 +1,30 @@
+import { Injectable } from '@nestjs/common';
+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';
+
+@Injectable()
+export class PetService {
+  constructor(
+    @InjectRepository(Pet)
+    private readonly petRepository: Repository<Pet>,
+  ) {}
+
+  async create(createPetRequest: CreatePetRequest): Promise<Pet> {
+    const pet = this.petRepository.create({
+      name: createPetRequest.name,
+      type: createPetRequest.type,
+      gender: createPetRequest.gender,
+      birthday: createPetRequest.birthday,
+      weight: createPetRequest.weight,
+      photo: createPetRequest.photo,
+      isActive: createPetRequest.isActive,
+      isPregnant: createPetRequest.isPregnant,
+      isSterilization: createPetRequest.isSterilization,
+      isLactation: createPetRequest.isLactation,
+      bodyType: createPetRequest.bodyType,
+    });
+    return this.petRepository.save(pet);
+  }
+}

+ 35 - 0
src/pet-feeder/vo/pet.vo.ts

@@ -0,0 +1,35 @@
+import { TraceableVo } from '@/core/vo/traceable.vo';
+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';
+
+@ApiSchema({
+  name: 'Pet',
+})
+export class PetVo extends TraceableVo {
+  @ApiProperty()
+  name: string;
+  @ApiProperty()
+  type: PetType;
+  @ApiProperty()
+  gender: Gender;
+  @ApiProperty()
+  birthday: string;
+  @ApiProperty()
+  weight: number;
+  @ApiProperty()
+  photo: string;
+  @ApiProperty()
+  isActive: boolean;
+  @ApiProperty()
+  isPregnant: boolean;
+  // 是否绝育
+  @ApiProperty()
+  isSterilization: boolean;
+  // 是否在哺乳
+  @ApiProperty()
+  isLactation: boolean;
+  @ApiProperty()
+  bodyType: PetBodyType;
+}

+ 3 - 0
tsconfig.json

@@ -10,6 +10,9 @@
     "sourceMap": true,
     "outDir": "./dist",
     "baseUrl": "./",
+    "paths": {
+      "@/*": ["src/*"]
+    },
     "incremental": true,
     "skipLibCheck": true,
     "strictNullChecks": false,