Prechádzať zdrojové kódy

feat: 产品编辑、获取、分页、删除接口

IlhamTahir 1 rok pred
rodič
commit
fce8ada51e

+ 2 - 2
src/article/controller/carousal.controller.ts

@@ -13,8 +13,8 @@ import { CreateCarousalRequest } from '../dto/create-carousal.request';
 import { ApiBearerAuth, ApiOkResponse, getSchemaPath } from '@nestjs/swagger';
 import { CarousalVo } from '../vo/carousal.vo';
 import { CarousalMapper } from '../mapper/carousal.mapper';
-import { PageResult } from '../../core/vo/page-result';
-import { PageResultMapper } from '../../core/mapper/page-result.mapper';
+import { PageResult } from '@/core/vo/page-result';
+import { PageResultMapper } from '@/core/mapper/page-result.mapper';
 import { SearchCarousalFilter } from '../dto/search-carousal.filter';
 import { UpdateCarousalRequest } from '../dto/update-carousal.request';
 

+ 67 - 2
src/pet-feeder/controller/product.controller.ts

@@ -1,9 +1,22 @@
-import { Body, Controller, Post } from '@nestjs/common';
+import {
+  Body,
+  Controller,
+  Delete,
+  Get,
+  Param,
+  Post,
+  Put,
+  Query,
+} 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';
+import { ApiBearerAuth, ApiOkResponse, getSchemaPath } from '@nestjs/swagger';
+import { UpdateProductRequest } from '@/pet-feeder/dto/update-product.request';
+import { PageResultMapper } from '@/core/mapper/page-result.mapper';
+import { SearchProductFilter } from '@/pet-feeder/dto/search-product.filter';
+import { PageResult } from '@/core/vo/page-result';
 
 @Controller('products')
 export class ProductController {
@@ -24,4 +37,56 @@ export class ProductController {
       await this.productService.create(createProductRequest),
     );
   }
+
+  @Put(':id')
+  @ApiOkResponse({
+    type: ProductVo,
+  })
+  @ApiBearerAuth()
+  async update(
+    @Param('id') id: string,
+    @Body() updateProductRequest: UpdateProductRequest,
+  ): Promise<ProductVo> {
+    return this.productMapper.toVo(
+      await this.productService.update(id, updateProductRequest),
+    );
+  }
+  @Get(':id')
+  async get(@Param('id') id: string): Promise<ProductVo> {
+    return this.productMapper.toVo(await this.productService.get(id));
+  }
+
+  @Get()
+  @ApiOkResponse({
+    description: '产品分页列表',
+    schema: {
+      allOf: [
+        { $ref: getSchemaPath(PageResult) }, // 引用 PageResult 模型
+        {
+          properties: {
+            data: {
+              type: 'array',
+              items: { $ref: getSchemaPath(ProductVo) }, // 泛型内容具体化
+            },
+          },
+        },
+      ],
+    },
+  })
+  @ApiBearerAuth()
+  async search(@Query() searchProductFilter: SearchProductFilter) {
+    const [data, total] = await this.productService.search(searchProductFilter);
+    return PageResultMapper.toPageResult<ProductVo>(
+      this.productMapper.toVos(data),
+      searchProductFilter.getPage(),
+      searchProductFilter.getSize(),
+      total,
+    );
+  }
+
+  @Delete(':id')
+  @ApiBearerAuth()
+  async delete(@Param('id') id: string): Promise<void> {
+    await this.productService.delete(id);
+  }
 }

+ 3 - 0
src/pet-feeder/dto/search-product.filter.ts

@@ -0,0 +1,3 @@
+import { BaseFilter } from '@/core/dto/base.filter';
+
+export class SearchProductFilter extends BaseFilter {}

+ 3 - 0
src/pet-feeder/dto/update-product.request.ts

@@ -0,0 +1,3 @@
+import { CreateProductRequest } from '@/pet-feeder/dto/create-product.request';
+
+export class UpdateProductRequest extends CreateProductRequest {}

+ 6 - 0
src/pet-feeder/error/product.error.ts

@@ -0,0 +1,6 @@
+import { ErrorResponse } from '@/core/error/error.response';
+
+export const PRODUCT_NOT_FOUND: ErrorResponse = {
+  code: 5001,
+  message: 'Product not found',
+};

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

@@ -3,6 +3,10 @@ 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';
+import { UpdateProductRequest } from '@/pet-feeder/dto/update-product.request';
+import { BizException } from '@/core/exception/biz.exception';
+import { PRODUCT_NOT_FOUND } from '@/pet-feeder/error/product.error';
+import { SearchProductFilter } from '@/pet-feeder/dto/search-product.filter';
 
 @Injectable()
 export class ProductService {
@@ -17,4 +21,39 @@ export class ProductService {
     });
     return this.productRepository.save(product);
   }
+
+  async update(
+    id: string,
+    updateProductRequest: UpdateProductRequest,
+  ): Promise<Product> {
+    const product = await this.get(id);
+    product.name = updateProductRequest.name;
+    product.tags = updateProductRequest.tags;
+    product.photo = updateProductRequest.photo;
+    product.totalCalories = updateProductRequest.totalCalories;
+    product.totalWeight = updateProductRequest.totalWeight;
+    return this.productRepository.save(product);
+  }
+
+  async get(id: string): Promise<Product> {
+    const product = await this.productRepository.findOneBy({ id });
+    if (!product) {
+      throw new BizException(PRODUCT_NOT_FOUND);
+    }
+    return product;
+  }
+
+  async search(searchProductFilter: SearchProductFilter) {
+    return this.productRepository.findAndCount({
+      where: searchProductFilter.getConditions(),
+      skip: searchProductFilter.getSkip(),
+      take: searchProductFilter.getSize(),
+      order: searchProductFilter.getOrderBy(),
+    });
+  }
+
+  async delete(id: string) {
+    const product = await this.get(id);
+    await this.productRepository.remove(product);
+  }
 }