From 3ced6a3240022dcdaadd1c9807495ab3378c5b8f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 26 Apr 2023 20:13:12 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=AE=8C=E5=96=84=20App=20=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=90=9C=E7=B4=A2=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/spu/AppProductSpuController.http | 12 ++++++- .../app/spu/AppProductSpuController.java | 4 +-- .../spu/vo/AppProductSpuPageItemRespVO.java | 20 +++++++----- .../app/spu/vo/AppProductSpuPageReqVO.java | 7 +++- .../convert/spu/ProductSpuConvert.java | 13 ++++++-- .../dal/mysql/spu/ProductSpuMapper.java | 32 ++++++++++++++----- .../service/spu/ProductSpuService.java | 7 ++-- .../service/spu/ProductSpuServiceImpl.java | 24 ++++++++++---- 8 files changed, 87 insertions(+), 32 deletions(-) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http index 04df7bfec..0de7583ae 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http @@ -1,8 +1,18 @@ -### 获得订单交易的分页 TODO +### 获得订单交易的分页(默认) GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10 Authorization: Bearer {{appToken}} tenant-id: {{appTenentId}} +### 获得订单交易的分页(价格) +GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10&sortField=price&sortAsc=true +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + +### 获得订单交易的分页(销售) +GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10&sortField=salesCount&sortAsc=true +Authorization: Bearer {{appToken}} +tenant-id: {{appTenentId}} + ### 获得商品 SPU 明细 GET {{appApi}}/product/spu/get-detail?id=4 tenant-id: {{appTenentId}} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java index d9ab87c72..783b85780 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java @@ -49,8 +49,8 @@ public class AppProductSpuController { @GetMapping("/page") @Operation(summary = "获得商品 SPU 分页") public CommonResult> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { - PageResult pageResult = productSpuService.getSpuPage(pageVO, ProductSpuStatusEnum.ENABLE.getStatus()); - return success(ProductSpuConvert.INSTANCE.convertPage02(pageResult)); + PageResult pageResult = productSpuService.getSpuPage(pageVO); + return success(ProductSpuConvert.INSTANCE.convertPageForGetSpuPage(pageResult)); } @GetMapping("/get-detail") diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java index d826900a6..27d577976 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.product.controller.app.spu.vo; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -15,21 +16,24 @@ public class AppProductSpuPageItemRespVO { private Long id; @Schema(description = "商品名称", required = true, example = "芋道") - @NotEmpty(message = "商品名称不能为空") private String name; @Schema(description = "分类编号", required = true) - @NotNull(message = "分类编号不能为空") private Long categoryId; - @Schema(description = "商品图片的数组", required = true) - private List picUrls; + @Schema(description = "商品封面图", required = true) + private String picUrl; - @Schema(description = " 最小价格,单位使用:分", required = true, example = "1024") - private Integer minPrice; + @Schema(description = "商品轮播图", required = true) + private List sliderPicUrls; - @Schema(description = "最大价格,单位使用:分", required = true, example = "1024") - private Integer maxPrice; + @Schema(description = "商品价格,单位使用:分", required = true, example = "1024") + private Integer price; + + // ========== SKU 相关字段 ========= + + @Schema(description = "库存", required = true, example = "666") + private Integer stock; // ========== 统计相关字段 ========= diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java index dcbd1e190..5050561d6 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageReqVO.java @@ -19,18 +19,23 @@ public class AppProductSpuPageReqVO extends PageParam { public static final String SORT_FIELD_PRICE = "price"; public static final String SORT_FIELD_SALES_COUNT = "salesCount"; + public static final String RECOMMEND_TYPE_HOT = "hot"; + @Schema(description = "分类编号", example = "1") private Long categoryId; @Schema(description = "关键字", example = "好看") private String keyword; - @Schema(description = "排序字段", example = "price") // 参见 AppSpuPageReqVO.SORT_FIELD_XXX 常量 + @Schema(description = "排序字段", example = "price") // 参见 AppProductSpuPageReqVO.SORT_FIELD_XXX 常量 private String sortField; @Schema(description = "排序方式", example = "true") private Boolean sortAsc; + @Schema(description = "推荐类型", example = "hot") // 参见 AppProductSpuPageReqVO.RECOMMEND_TYPE_XXX 常亮 + private String recommendType; + @AssertTrue(message = "排序字段不合法") @JsonIgnore public boolean isSortFieldValid() { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java index fcf6d6436..cddd742f0 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; import org.mapstruct.Mapper; +import org.mapstruct.Named; import org.mapstruct.factory.Mappers; import java.util.ArrayList; @@ -75,8 +76,6 @@ public interface ProductSpuConvert { List convertList03(List skus); AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue); - PageResult convertPage02(PageResult page); - default ProductSpuDetailRespVO convert03(ProductSpuDO spu, List skus, List propertyValues) { ProductSpuDetailRespVO spuVO = convert03(spu); @@ -105,4 +104,14 @@ public interface ProductSpuConvert { List convertList04(List skus); ProductPropertyValueDetailRespVO convert04(ProductPropertyValueDetailRespBO propertyValue); + // ========== 用户 App 相关 ========== + + default PageResult convertPageForGetSpuPage(PageResult page) { + // 累加虚拟销量 + page.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); + // 然后进行转换 + return convertPageForGetSpuPage0(page); + } + PageResult convertPageForGetSpuPage0(PageResult page); + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java index 256bc43f1..ee0922208 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java @@ -1,11 +1,15 @@ package cn.iocoder.yudao.module.product.dal.mysql.spu; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @@ -46,16 +50,28 @@ public interface ProductSpuMapper extends BaseMapperX { .orderByDesc(ProductSpuDO::getSort)); } - default PageResult selectPage(AppProductSpuPageReqVO pageReqVO, Integer status) { + /** + * 获得商品 SPU 分页,提供给用户 App 使用 + */ + default PageResult selectPage(AppProductSpuPageReqVO pageReqVO, Set categoryIds) { LambdaQueryWrapperX query = new LambdaQueryWrapperX() - .eqIfPresent(ProductSpuDO::getCategoryId, pageReqVO.getCategoryId()) - .eqIfPresent(ProductSpuDO::getStatus, status); + .likeIfPresent(ProductSpuDO::getName, pageReqVO.getKeyword()) // 关键字匹配,目前只匹配商品名 + .inIfPresent(ProductSpuDO::getCategoryId, categoryIds); // 分类 + query.eq(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()) // 上架状态 + .gt(ProductSpuDO::getStock, 0); // 有库存 + // 推荐类型的过滤条件 + if (ObjUtil.equal(pageReqVO.getRecommendType(), AppProductSpuPageReqVO.RECOMMEND_TYPE_HOT)) { + query.eq(ProductSpuDO::getRecommendHot, true); + } // 排序逻辑 - if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) { - // TODO ProductSpuDO 已经没有maxPrice 属性 - //query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getMaxPrice); - } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) { - query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getSalesCount); + if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) { + query.last(String.format(" ORDER BY (sales_count + virtual_sales_count) %s, sort DESC, id DESC", + pageReqVO.getSortAsc() ? "ASC" : "DESC")); + } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) { + query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getPrice) + .orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId); + } else { + query.orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId); } return selectPage(pageReqVO, query); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java index 0ae7359eb..dd8f77c12 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java @@ -75,7 +75,7 @@ public interface ProductSpuService { List getSpuList(); /** - * 获得商品 SPU 分页 + * 获得商品 SPU 分页,提供给挂你兰后台使用 * * @param pageReqVO 分页查询 * @return 商品spu分页 @@ -83,13 +83,12 @@ public interface ProductSpuService { PageResult getSpuPage(ProductSpuPageReqVO pageReqVO); /** - * 获得商品 SPU 分页 + * 获得商品 SPU 分页,提供给用户 App 使用 * * @param pageReqVO 分页查询 - * @param status 状态 * @return 商品 SPU 分页 */ - PageResult getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status); + PageResult getSpuPage(AppProductSpuPageReqVO pageReqVO); /** * 更新商品 SPU 库存(增量) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 352c8b341..79a6949a5 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -1,14 +1,20 @@ package cn.iocoder.yudao.module.product.service.spu; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; @@ -21,10 +27,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @@ -168,8 +171,17 @@ public class ProductSpuServiceImpl implements ProductSpuService { } @Override - public PageResult getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status) { - return productSpuMapper.selectPage(pageReqVO, status); + public PageResult getSpuPage(AppProductSpuPageReqVO pageReqVO) { + // 查找时,如果查找某个分类编号,则包含它的子分类。因为顶级分类不包含商品 + Set categoryIds = new HashSet<>(); + if (pageReqVO.getCategoryId() != null && pageReqVO.getCategoryId() > 0) { + categoryIds.add(pageReqVO.getCategoryId()); + List categoryChildren = categoryService.getEnableCategoryList(new ProductCategoryListReqVO() + .setParentId(pageReqVO.getCategoryId()).setStatus(CommonStatusEnum.ENABLE.getStatus())); + categoryIds.addAll(CollectionUtils.convertList(categoryChildren, ProductCategoryDO::getId)); + } + // 分页查询 + return productSpuMapper.selectPage(pageReqVO, categoryIds); } @Override From 2113e825d7b085478e8a352e077146f1c4e2581f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 27 Apr 2023 22:43:37 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=AE=8C=E5=96=84=20App=20=E5=95=86?= =?UTF-8?q?=E5=93=81=E8=AF=A6=E6=83=85=E9=80=BB=E8=BE=91=E7=9A=84=2010%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/spu/AppProductSpuController.http | 2 +- .../app/spu/AppProductSpuController.java | 2 +- .../app/spu/vo/AppProductSpuDetailRespVO.java | 24 +++---- .../spu/vo/AppProductSpuPageItemRespVO.java | 9 +-- .../convert/spu/ProductSpuConvert.java | 64 +++++++++---------- .../service/spu/ProductSpuServiceImpl.java | 7 +- 6 files changed, 50 insertions(+), 58 deletions(-) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http index 0de7583ae..c391b5873 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.http @@ -14,5 +14,5 @@ Authorization: Bearer {{appToken}} tenant-id: {{appTenentId}} ### 获得商品 SPU 明细 -GET {{appApi}}/product/spu/get-detail?id=4 +GET {{appApi}}/product/spu/get-detail?id=102 tenant-id: {{appTenentId}} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java index 783b85780..fe1a8ee87 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java @@ -73,7 +73,7 @@ public class AppProductSpuController { List propertyValues = productPropertyValueService .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus)); // 拼接 - return success(ProductSpuConvert.INSTANCE.convert(spu, skus, propertyValues)); + return success(ProductSpuConvert.INSTANCE.convertForGetSpuDetail(spu, skus, propertyValues)); } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java index 424843bc7..6992d83b7 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java @@ -18,17 +18,17 @@ public class AppProductSpuDetailRespVO { @Schema(description = "商品名称", required = true, example = "芋道") private String name; - @Schema(description = "促销语", example = "好吃!") - private String sellPoint; - @Schema(description = "商品详情", required = true, example = "我是商品描述") private String description; @Schema(description = "商品分类编号", required = true, example = "1") private Long categoryId; - @Schema(description = "商品图片的数组", required = true) - private List picUrls; + @Schema(description = "商品封面图", required = true) + private String picUrl; + + @Schema(description = "商品轮播图", required = true) + private List sliderPicUrls; @Schema(description = "商品视频", required = true) private String videoUrl; @@ -38,14 +38,14 @@ public class AppProductSpuDetailRespVO { @Schema(description = "规格类型", required = true, example = "true") private Boolean specType; - @Schema(description = "是否展示库存", required = true, example = "true") - private Boolean showStock; + @Schema(description = "商品价格,单位使用:分", required = true, example = "1024") + private Integer price; - @Schema(description = " 最小价格,单位使用:分", required = true, example = "1024") - private Integer minPrice; + @Schema(description = "市场价,单位使用:分", required = true, example = "1024") + private Integer marketPrice; - @Schema(description = "最大价格,单位使用:分", required = true, example = "1024") - private Integer maxPrice; + @Schema(description = "库存", required = true, example = "666") + private Integer stock; /** * SKU 数组 @@ -72,7 +72,7 @@ public class AppProductSpuDetailRespVO { @Schema(description = "销售价格,单位:分", required = true, example = "1024") private Integer price; - @Schema(description = "市场价", example = "1024") + @Schema(description = "市场价,单位使用:分", required = true, example = "1024") private Integer marketPrice; @Schema(description = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png") diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java index 27d577976..97513c3bc 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java @@ -1,11 +1,8 @@ package cn.iocoder.yudao.module.product.controller.app.spu.vo; -import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; import java.util.List; @Schema(description = "用户 App - 商品 SPU 分页项 Response VO") @@ -27,17 +24,17 @@ public class AppProductSpuPageItemRespVO { @Schema(description = "商品轮播图", required = true) private List sliderPicUrls; + // ========== SKU 相关字段 ========= + @Schema(description = "商品价格,单位使用:分", required = true, example = "1024") private Integer price; - // ========== SKU 相关字段 ========= - @Schema(description = "库存", required = true, example = "666") private Integer stock; // ========== 统计相关字段 ========= - @Schema(description = "商品销量", example = "1024") + @Schema(description = "商品销量", required = true, example = "1024") private Integer salesCount; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java index cddd742f0..1aa3a4bef 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java @@ -13,7 +13,6 @@ import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; import org.mapstruct.Mapper; -import org.mapstruct.Named; import org.mapstruct.factory.Mappers; import java.util.ArrayList; @@ -33,48 +32,18 @@ public interface ProductSpuConvert { ProductSpuConvert INSTANCE = Mappers.getMapper(ProductSpuConvert.class); - ProductSpuDO convert(ProductSpuCreateReqVO bean); + ProductSpuDO convertForGetSpuDetail(ProductSpuCreateReqVO bean); - ProductSpuDO convert(ProductSpuUpdateReqVO bean); + ProductSpuDO convertForGetSpuDetail(ProductSpuUpdateReqVO bean); List convertList(List list); PageResult convertPage(PageResult page); - ProductSpuPageReqVO convert(AppProductSpuPageReqVO bean); - List convertList2(List list); List convertList02(List list); - default AppProductSpuDetailRespVO convert(ProductSpuDO spu, List skus, - List propertyValues) { - AppProductSpuDetailRespVO spuVO = convert02(spu) - .setSalesCount(spu.getSalesCount() + defaultIfNull(spu.getVirtualSalesCount(), 0)); - spuVO.setSkus(convertList03(skus)); - // 处理商品属性 - Map propertyValueMap = convertMap(propertyValues, ProductPropertyValueDetailRespBO::getValueId); - for (int i = 0; i < skus.size(); i++) { - List properties = skus.get(i).getProperties(); - if (CollUtil.isEmpty(properties)) { - continue; - } - AppProductSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); - sku.setProperties(new ArrayList<>(properties.size())); - // 遍历每个 properties,设置到 AppSpuDetailRespVO.Sku 中 - properties.forEach(property -> { - ProductPropertyValueDetailRespBO propertyValue = propertyValueMap.get(property.getValueId()); - if (propertyValue == null) { - return; - } - sku.getProperties().add(convert03(propertyValue)); - }); - } - return spuVO; - } - AppProductSpuDetailRespVO convert02(ProductSpuDO spu); - List convertList03(List skus); - AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue); default ProductSpuDetailRespVO convert03(ProductSpuDO spu, List skus, List propertyValues) { @@ -114,4 +83,33 @@ public interface ProductSpuConvert { } PageResult convertPageForGetSpuPage0(PageResult page); + default AppProductSpuDetailRespVO convertForGetSpuDetail(ProductSpuDO spu, List skus, + List propertyValues) { + AppProductSpuDetailRespVO spuVO = convertForGetSpuDetail(spu) + .setSalesCount(spu.getSalesCount() + defaultIfNull(spu.getVirtualSalesCount(), 0)); + spuVO.setSkus(convertListForGetSpuDetail(skus)); + // 处理商品属性 + Map propertyValueMap = convertMap(propertyValues, ProductPropertyValueDetailRespBO::getValueId); + for (int i = 0; i < skus.size(); i++) { + List properties = skus.get(i).getProperties(); + if (CollUtil.isEmpty(properties)) { + continue; + } + AppProductSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); + sku.setProperties(new ArrayList<>(properties.size())); + // 遍历每个 properties,设置到 AppSpuDetailRespVO.Sku 中 + properties.forEach(property -> { + ProductPropertyValueDetailRespBO propertyValue = propertyValueMap.get(property.getValueId()); + if (propertyValue == null) { + return; + } + sku.getProperties().add(convertForGetSpuDetail(propertyValue)); + }); + } + return spuVO; + } + AppProductSpuDetailRespVO convertForGetSpuDetail(ProductSpuDO spu); + List convertListForGetSpuDetail(List skus); + AppProductPropertyValueDetailRespVO convertForGetSpuDetail(ProductPropertyValueDetailRespBO propertyValue); + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 79a6949a5..22b643ef5 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -1,12 +1,9 @@ package cn.iocoder.yudao.module.product.service.spu; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.NumberUtil; -import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; @@ -66,7 +63,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType()); // 插入 SPU - ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO); + ProductSpuDO spu = ProductSpuConvert.INSTANCE.convertForGetSpuDetail(createReqVO); initSpuFromSkus(spu, skuSaveReqList); productSpuMapper.insert(spu); // 插入 SKU @@ -89,7 +86,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType()); // 更新 SPU - ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO); + ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convertForGetSpuDetail(updateReqVO); initSpuFromSkus(updateObj, skuSaveReqList); productSpuMapper.updateById(updateObj); // 批量更新 SKU From da162853ec245d4261a2a6a3c9536dca81ba1b24 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 30 Apr 2023 20:32:01 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=95=86=E5=9F=8E=EF=BC=9A=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E8=B4=AD=E7=89=A9=E8=BD=A6=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/core/mapper/BaseMapperX.java | 12 ++ .../api/sku/dto/ProductSkuRespDTO.java | 12 +- .../api/spu/dto/ProductSpuRespDTO.java | 55 +++---- .../product/api/sku/ProductSkuApiImpl.java | 7 +- .../spu/vo/AppProductSpuPageItemRespVO.java | 3 + .../dal/dataobject/sku/ProductSkuDO.java | 21 ++- .../property/ProductPropertyServiceImpl.java | 1 + .../ProductPropertyValueServiceImpl.java | 1 + .../service/sku/ProductSkuServiceTest.java | 6 +- .../app/base/spu/AppProductSpuBaseRespVO.java | 2 +- .../app/cart/TradeCartController.http | 30 ++-- .../app/cart/TradeCartController.java | 47 +++--- ...ntReqVO.java => AppTradeCartAddReqVO.java} | 6 +- .../app/cart/vo/AppTradeCartDetailRespVO.java | 117 -------------- .../app/cart/vo/AppTradeCartListRespVO.java | 45 ++++++ ...eqVO.java => AppTradeCartUpdateReqVO.java} | 10 +- .../trade/convert/cart/TradeCartConvert.java | 65 ++++---- ...{TradeCartItemDO.java => TradeCartDO.java} | 52 +++--- .../dal/mysql/cart/TradeCartItemMapper.java | 47 ------ .../trade/dal/mysql/cart/TradeCartMapper.java | 56 +++++++ .../trade/service/cart/TradeCartService.java | 32 ++-- .../service/cart/TradeCartServiceImpl.java | 152 +++++++----------- 22 files changed, 349 insertions(+), 430 deletions(-) rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/{AppTradeCartItemAddCountReqVO.java => AppTradeCartAddReqVO.java} (75%) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/{AppTradeCartItemUpdateCountReqVO.java => AppTradeCartUpdateReqVO.java} (60%) rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/{TradeCartItemDO.java => TradeCartDO.java} (61%) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java index 9819bf551..87cf0dddc 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java @@ -46,6 +46,18 @@ public interface BaseMapperX extends MPJBaseMapper { return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2)); } + default T selectOne(SFunction field1, Object value1, SFunction field2, Object value2, + SFunction field3, Object value3) { + return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2) + .eq(field3, value3)); + } + + default T selectOne(SFunction field1, Object value1, SFunction field2, Object value2, + SFunction field3, Object value3, SFunction field4, Object value4) { + return selectOne(new LambdaQueryWrapper().eq(field1, value1).eq(field2, value2) + .eq(field3, value3).eq(field4, value4)); + } + default Long selectCount() { return selectCount(new QueryWrapper()); } diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java index aaaf767f2..9197c6147 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java @@ -28,7 +28,7 @@ public class ProductSkuRespDTO { private String spuName; /** - * 属性数组,JSON 格式 + * 属性数组 */ private List properties; /** @@ -84,12 +84,20 @@ public class ProductSkuRespDTO { * 属性编号 */ private Long propertyId; + /** + * 属性名字 + */ + private String propertyName; + /** * 属性值编号 */ private Long valueId; + /** + * 属性值名字 + */ + private String valueName; } - } diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java index 5c4ee9bb7..acce738a7 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java @@ -29,17 +29,23 @@ public class ProductSpuRespDTO { */ private String name; /** - * 商品编码 + * 关键字 */ - private String code; + private String keyword; /** - * 促销语 + * 商品简介 */ - private String sellPoint; + private String introduction; /** * 商品详情 */ private String description; + // TODO @芋艿:是不是要删除 + /** + * 商品条码(一维码) + */ + private String barCode; + /** * 商品分类编号 */ @@ -49,13 +55,13 @@ public class ProductSpuRespDTO { */ private Long brandId; /** - * 商品图片的数组 - *

- * 1. 第一张图片将作为商品主图,支持同时上传多张图; - * 2. 建议使用尺寸 800x800 像素以上、大小不超过 1M 的正方形图片; - * 3. 至少 1 张,最多上传 10 张 + * 商品封面图 */ - private List picUrls; + private String picUrl; + /** + * 商品轮播图 + */ + private List sliderPicUrls; /** * 商品视频 */ @@ -76,38 +82,27 @@ public class ProductSpuRespDTO { /** * 规格类型 - *

- * 枚举 {@link ProductSpuSpecTypeEnum} + * + * false - 单规格 + * true - 多规格 */ private Boolean specType; /** - * 最小价格,单位使用:分 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最小值 + * 商品价格,单位使用:分 */ - private Integer minPrice; - /** - * 最大价格,单位使用:分 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最大值 - */ - private Integer maxPrice; + private Integer price; /** * 市场价,单位使用:分 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getMarketPrice()} 最大值 */ private Integer marketPrice; /** - * 总库存 - *

- * 基于其对应的 {@link ProductSkuRespDTO#getStock()} 求和 + * 成本价,单位使用:分 */ - private Integer totalStock; + private Integer costPrice; /** - * 是否展示库存 + * 库存 */ - private Boolean showStock; + private Integer stock; // ========== 统计相关字段 ========= diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java index 89913c70e..6bec2a74c 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java @@ -15,7 +15,8 @@ import java.util.Collections; import java.util.List; /** - * TODO LeeYan9: 类注释; + * 商品 SKU API 实现类 + * * @author LeeYan9 * @since 2022-09-06 */ @@ -28,8 +29,8 @@ public class ProductSkuApiImpl implements ProductSkuApi { @Override public ProductSkuRespDTO getSku(Long id) { - // TODO TODO LeeYan9: 需要实现 - return null; + ProductSkuDO sku = productSkuService.getSku(id); + return ProductSkuConvert.INSTANCE.convert02(sku); } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java index 97513c3bc..68812b754 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java @@ -26,6 +26,9 @@ public class AppProductSpuPageItemRespVO { // ========== SKU 相关字段 ========= + @Schema(description = "规格类型", required = true, example = "true") + private Boolean specType; + @Schema(description = "商品价格,单位使用:分", required = true, example = "1024") private Integer price; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java index a9488563a..b759ae5ee 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java @@ -109,12 +109,29 @@ public class ProductSkuDO extends BaseDO { * 关联 {@link ProductPropertyDO#getId()} */ private Long propertyId; + /** + * 属性名字 + * + * 冗余 {@link ProductPropertyDO#getName()} + * + * 注意:每次属性名字发生变化时,需要更新该冗余 + */ + private String propertyName; + /** * 属性值编号 * * 关联 {@link ProductPropertyValueDO#getId()} */ private Long valueId; + /** + * 属性值名字 + * + * 冗余 {@link ProductPropertyValueDO#getName()} + * + * 注意:每次属性值名字发生变化时,需要更新该冗余 + */ + private String valueName; } @@ -139,9 +156,5 @@ public class ProductSkuDO extends BaseDO { // TODO 芋艿:pinkStock from y // TODO 芋艿:seckillStock from y - // TODO 芋艿:quota from c - // TODO 芋艿:quotaShow from c - // TODO 芋艿:attrValue from c - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java index 328c343d6..3468f2d60 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java @@ -67,6 +67,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { // 更新 ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO); productPropertyMapper.updateById(updateObj); + // TODO 芋艿:更新时,需要看看 sku 表 } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java index e5bc6874b..231b79b68 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java @@ -68,6 +68,7 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ // 更新 ProductPropertyValueDO updateObj = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO); productPropertyValueMapper.updateById(updateObj); + // TODO 芋艿:更新时,需要看看 sku 表 } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java index ec088cfdd..2e8ade7fc 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java +++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java @@ -54,12 +54,14 @@ public class ProductSkuServiceTest extends BaseDbUnitTest { // mock 数据 ProductSkuDO sku01 = randomPojo(ProductSkuDO.class, o -> { // 测试更新 o.setSpuId(1L); - o.setProperties(singletonList(new ProductSkuDO.Property(10L, 20L))); + o.setProperties(singletonList(new ProductSkuDO.Property( + 10L, "颜色", 20L, "红色"))); }); productSkuMapper.insert(sku01); ProductSkuDO sku02 = randomPojo(ProductSkuDO.class, o -> { // 测试删除 o.setSpuId(1L); - o.setProperties(singletonList(new ProductSkuDO.Property(10L, 30L))); + o.setProperties(singletonList(new ProductSkuDO.Property( + 10L, "颜色", 30L, "蓝色"))); }); productSkuMapper.insert(sku02); // 准备参数 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java index b73be6e0c..04359c810 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java @@ -20,6 +20,6 @@ public class AppProductSpuBaseRespVO { private String name; @Schema(description = "商品主图地址", example = "https://www.iocoder.cn/xx.png") - private List picUrls; + private String picUrl; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http index 3ce8797fc..ead0fa72f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http @@ -1,38 +1,28 @@ -### 请求 /trade/cart/add-count 接口 => 成功 -POST {{appApi}}/trade/cart/add-count +### 请求 /trade/cart/add 接口 => 成功 +POST {{appApi}}/trade/cart/add tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} Content-Type: application/json { "skuId": 1, - "count": 1 + "count": 10, + "addStatus": true } -### 请求 /trade/cart/update-count 接口 => 成功 -PUT {{appApi}}/trade/cart/update-count +### 请求 /trade/cart/update 接口 => 成功 +PUT {{appApi}}/trade/cart/update tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} Content-Type: application/json { - "skuId": 1, + "id": 35, "count": 5 } -### 请求 /trade/cart/update-selected 接口 => 成功 -PUT {{appApi}}/trade/cart/update-selected -tenant-id: {{appTenentId}} -Authorization: Bearer {{appToken}} -Content-Type: application/json - -{ - "skuIds": [1], - "selected": false -} - ### 请求 /trade/cart/delete 接口 => 成功 -DELETE {{appApi}}/trade/cart/delete?skuIds=1 +DELETE {{appApi}}/trade/cart/delete?ids=1 tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} @@ -41,7 +31,7 @@ GET {{appApi}}/trade/cart/get-count tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} -### 请求 /trade/cart/get-detail 接口 => 成功 -GET {{appApi}}/trade/cart/get-detail +### 请求 /trade/cart/list 接口 => 成功 +GET {{appApi}}/trade/cart/list tenant-id: {{appTenentId}} Authorization: Bearer {{appToken}} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java index 46512a959..d00c2b0f3 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java @@ -2,10 +2,9 @@ package cn.iocoder.yudao.module.trade.controller.app.cart; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -33,37 +32,27 @@ public class TradeCartController { @Resource private TradeCartService cartService; - @PostMapping("/add-count") - @Operation(summary = "添加商品到购物车") + @PostMapping("/add") + @Operation(summary = "添加购物车商品") @PreAuthenticated - public CommonResult addCartItemCount(@Valid @RequestBody AppTradeCartItemAddCountReqVO addCountReqVO) { - cartService.addCartItemCount(getLoginUserId(), addCountReqVO); - return success(true); + public CommonResult addCart(@Valid @RequestBody AppTradeCartAddReqVO addCountReqVO) { + return success(cartService.addCart(getLoginUserId(), addCountReqVO)); } - @PutMapping("update-count") - @Operation(summary = "更新购物车商品数量") + @PutMapping("/update") + @Operation(summary = "更新购物车商品") @PreAuthenticated - public CommonResult updateCartItemQuantity(@Valid @RequestBody AppTradeCartItemUpdateCountReqVO updateCountReqVO) { - cartService.updateCartItemCount(getLoginUserId(), updateCountReqVO); - return success(true); - } - - @PutMapping("update-selected") - @Operation(summary = "更新购物车商品是否选中") - @PreAuthenticated - public CommonResult updateCartItemSelected(@Valid @RequestBody AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { - cartService.updateCartItemSelected(getLoginUserId(), updateSelectedReqVO); - // 获得目前购物车明细 + public CommonResult updateCartItemQuantity(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) { + cartService.updateCart(getLoginUserId(), updateReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "删除购物车商品") - @Parameter(name = "skuIds", description = "商品 SKU 编号的数组", required = true, example = "1024,2048") + @Parameter(name = "ids", description = "购物车商品编号", required = true, example = "1024,2048") @PreAuthenticated - public CommonResult deleteCartItem(@RequestParam("skuIds") List skuIds) { - cartService.deleteCartItems(getLoginUserId(), skuIds); + public CommonResult deleteCart(@RequestParam("ids") List ids) { + cartService.deleteCart(getLoginUserId(), ids); return success(true); } @@ -74,11 +63,11 @@ public class TradeCartController { return success(cartService.getCartCount(getLoginUserId())); } - @GetMapping("/get-detail") - @Operation(summary = "查询用户的购物车的详情") + @GetMapping("/list") + @Operation(summary = "查询用户的购物车列表") @PreAuthenticated - public CommonResult getCartDetail() { - return success(cartService.getCartDetail(getLoginUserId())); + public CommonResult getCartList() { + return success(cartService.getCartList(getLoginUserId())); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java similarity index 75% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java index 9b4ba6929..c1e3ebd2f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java @@ -8,7 +8,7 @@ import javax.validation.constraints.NotNull; @Schema(description = "用户 App - 购物车添加购物项 Request VO") @Data -public class AppTradeCartItemAddCountReqVO { +public class AppTradeCartAddReqVO { @Schema(description = "商品 SKU 编号", required = true,example = "1024") @NotNull(message = "商品 SKU 编号不能为空") @@ -19,4 +19,8 @@ public class AppTradeCartItemAddCountReqVO { @Min(message = "数量必须大于 0", value = 1L) private Integer count; + @Schema(description = "是否添加到购物车", required = true, example = "true") + @NotNull(message = "是否添加购物车不能为空") + private Boolean addStatus; + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java deleted file mode 100644 index 769418528..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java +++ /dev/null @@ -1,117 +0,0 @@ -package cn.iocoder.yudao.module.trade.controller.app.cart.vo; - -import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.util.List; - -@Schema(description = "用户 App - 用户的购物车明细 Response VO") -@Data -public class AppTradeCartDetailRespVO { - - /** - * 商品分组数组 - */ - private List itemGroups; - - /** - * 费用 - */ - private Order order; - - @Schema(description = "商品分组") // 多个商品,参加同一个活动,从而形成分组 - @Data - public static class ItemGroup { - - /** - * 商品数组 - */ - private List items; - /** - * 营销活动,订单级别 - */ - private Promotion promotion; - - } - - @Schema(description = "商品 SKU") - @Data - public static class Sku extends AppProductSkuBaseRespVO { - - /** - * SPU 信息 - */ - private AppProductSkuBaseRespVO spu; - - // ========== 购物车相关的字段 ========== - - @Schema(description = "商品数量", required = true, example = "1") - private Integer count; - @Schema(description = "是否选中", required = true, example = "true") - private Boolean selected; - - // ========== 价格相关的字段,对应 PriceCalculateRespDTO.OrderItem 的属性 ========== - - // TODO 芋艿:后续可以去除一些无用的字段 - - @Schema(description = "商品原价(单)", required = true, example = "100") - private Integer originalPrice; - @Schema(description = "商品原价(总)", required = true, example = "200") - private Integer totalOriginalPrice; - @Schema(description = "商品级优惠(总)", required = true, example = "300") - private Integer totalPromotionPrice; - @Schema(description = "最终购买金额(总)", required = true, example = "400") - private Integer totalPresentPrice; - @Schema(description = "最终购买金额(单)", required = true, example = "500") - private Integer presentPrice; - @Schema(description = "应付金额(总)", required = true, example = "600") - private Integer totalPayPrice; - - // ========== 营销相关的字段 ========== - /** - * 营销活动,商品级别 - */ - private Promotion promotion; - - } - - @Schema(description = "订单") // 对应 PriceCalculateRespDTO.Order 类,用于费用(合计) - @Data - public static class Order { - - // TODO 芋艿:后续可以去除一些无用的字段 - - @Schema(description = "商品原价(总)", required = true, example = "100") - private Integer skuOriginalPrice; - @Schema(description = "商品优惠(总)", required = true, example = "200") - private Integer skuPromotionPrice; - @Schema(description = "订单优惠(总)", required = true, example = "300") - private Integer orderPromotionPrice; - @Schema(description = "运费金额", required = true, example = "400") - private Integer deliveryPrice; - @Schema(description = "应付金额(总)", required = true, example = "500") - private Integer payPrice; - - } - - @Schema(description = "营销活动") // 对应 PriceCalculateRespDTO.Promotion 类的属性 - @Data - public static class Promotion { - - @Schema(description = "营销编号", required = true, example = "1024") // 营销活动的编号、优惠劵的编号 - private Long id; - @Schema(description = "营销名字", required = true, example = "xx 活动") - private String name; - @Schema(description = "营销类型", required = true, example = "1") - private Integer type; - - // ========== 匹配情况 ========== - @Schema(description = "是否满足优惠条件", required = true, example = "true") - private Boolean meet; - @Schema(description = "满足条件的提示", required = true, example = "圣诞价:省 150.00 元") - private String meetTip; - - } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java new file mode 100644 index 000000000..5f33ece55 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartListRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.base.spu.AppProductSpuBaseRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "用户 App - 用户的购物列表 Response VO") +@Data +public class AppTradeCartListRespVO { + + /** + * 有效的购物项数组 + */ + private List validList; + + /** + * 无效的购物项数组 + */ + private List invalidList; + + @Schema(description = "购物项") + @Data + public static class Cart { + + @Schema(description = "购物项的编号", required = true, example = "1024") + private Long id; + + @Schema(description = "商品数量", required = true, example = "1") + private Integer count; + + /** + * 商品 SPU + */ + private AppProductSpuBaseRespVO spu; + /** + * 商品 SKU + */ + private AppProductSkuBaseRespVO sku; + + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartUpdateReqVO.java similarity index 60% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartUpdateReqVO.java index d3d12487e..4cf72bbf1 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartUpdateReqVO.java @@ -6,13 +6,13 @@ import lombok.Data; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; -@Schema(description = "用户 App - 购物车更新数量 Request VO") +@Schema(description = "用户 App - 购物车更新 Request VO") @Data -public class AppTradeCartItemUpdateCountReqVO { +public class AppTradeCartUpdateReqVO { - @Schema(description = "商品 SKU 编号", required = true, example = "1024") - @NotNull(message = "商品 SKU 编号不能为空") - private Long skuId; + @Schema(description = "编号", required = true, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; @Schema(description = "商品数量", required = true, example = "1") @NotNull(message = "数量不能为空") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java index eb696ae30..c40ce377f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java @@ -1,45 +1,52 @@ package cn.iocoder.yudao.module.trade.convert.cart; -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.base.spu.AppProductSpuBaseRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; +import java.util.Map; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @Mapper public interface TradeCartConvert { TradeCartConvert INSTANCE = Mappers.getMapper(TradeCartConvert.class); - default AppTradeCartDetailRespVO buildEmptyAppTradeCartDetailRespVO() { - return new AppTradeCartDetailRespVO().setItemGroups(Collections.emptyList()) - .setOrder(new AppTradeCartDetailRespVO.Order().setSkuOriginalPrice(0).setSkuPromotionPrice(0) - .setOrderPromotionPrice(0).setDeliveryPrice(0).setPayPrice(0)); + default AppTradeCartListRespVO convertList(List carts, + List spus, List skus) { + Map spuMap = convertMap(spus, ProductSpuRespDTO::getId); + Map skuMap = convertMap(skus, ProductSkuRespDTO::getId); + // 遍历,开始转换 + List validList = new ArrayList<>(carts.size()); + List invalidList = new ArrayList<>(); + carts.forEach(cart -> { + AppTradeCartListRespVO.Cart cartVO = new AppTradeCartListRespVO.Cart(); + cartVO.setId(cart.getId()).setCount(cart.getCount()); + ProductSpuRespDTO spu = spuMap.get(cart.getSpuId()); + ProductSkuRespDTO sku = skuMap.get(cart.getSkuId()); + cartVO.setSpu(convert(spu)).setSku(convert(sku)); + // 如果 spu 或 sku 不存在,或者 spu 被禁用,说明是非法的,或者 sku 库存不足 + if (spu == null + || sku == null + || !ProductSpuStatusEnum.isEnable(spu.getStatus()) + || sku.getStock() <= 0) { + invalidList.add(cartVO); + } else { + validList.add(cartVO); + } + }); + return new AppTradeCartListRespVO().setValidList(validList).setValidList(invalidList); } - - default PriceCalculateReqDTO convert(Long userId, List cartItems) { - return new PriceCalculateReqDTO().setUserId(userId) - .setItems(convertList(cartItems, cartItem -> new PriceCalculateReqDTO.Item().setSkuId(cartItem.getSkuId()) - .setCount(cartItem.getSelected() ? cartItem.getCount() : 0))); - } - - // ========== AppTradeCartDetailRespVO 相关 ========== - - AppTradeCartDetailRespVO.Promotion convert(PriceCalculateRespDTO.Promotion bean); - - @Mappings({ - @Mapping(source = "cartItem.count", target = "count") - }) - AppTradeCartDetailRespVO.Sku convert(PriceCalculateRespDTO.OrderItem orderItem, TradeCartItemDO cartItem); - - AppTradeCartDetailRespVO.Order convert(PriceCalculateRespDTO.Order bean); + AppProductSpuBaseRespVO convert(ProductSpuRespDTO spu); + AppProductSkuBaseRespVO convert(ProductSkuRespDTO sku); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartDO.java similarity index 61% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartDO.java index 05fbb801d..d9d9697ae 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartDO.java @@ -9,13 +9,15 @@ import lombok.experimental.Accessors; /** * 购物车的商品信息 DO * + * 每个商品,对应一条记录,通过 {@link #spuId} 和 {@link #skuId} 关联 + * * @author 芋道源码 */ -@TableName("trade_cart_item") +@TableName("trade_cart") @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) -public class TradeCartItemDO extends BaseDO { +public class TradeCartDO extends BaseDO { // ========= 基础字段 BEGIN ========= @@ -23,14 +25,6 @@ public class TradeCartItemDO extends BaseDO { * 编号,唯一自增 */ private Long id; - /** - * 是否选中 - */ - private Boolean selected; - - // ========= 基础字段 END ========= - - // ========= 买家信息 BEGIN ========= /** * 用户编号 @@ -39,7 +33,25 @@ public class TradeCartItemDO extends BaseDO { */ private Long userId; - // ========= 买家信息 END ========= + /** + * 是否添加到购物车 + * + * false - 未添加:用户点击【立即购买】 + * true - 已添加:用户点击【添加购物车】 + * + * 为什么要设计这个字段? + * 配合 orderStatus 字段,可以知道有多少商品,用户点击了【立即购买】,最终多少【确认下单】 + */ + private Boolean addStatus; + /** + * 是否提交订单 + * + * false - 未下单:立即购买,或者添加到购物车,此时设置为 false + * true - 已下单:确认下单,此时设置为 true + */ + private Boolean orderStatus; + + // ========= 基础字段 END ========= // ========= 商品信息 BEGIN ========= @@ -64,27 +76,11 @@ public class TradeCartItemDO extends BaseDO { // ========= 优惠信息 BEGIN ========= -// /** -// * 商品营销活动编号 -// */ -// private Long activityId; // discount_id -// /** -// * 商品营销活动类型 -// */ -// private Integer activityType; // TODO 芋艿:combination_id 拼团 ID // TODO 芋艿:seckill_id 秒杀产品 ID // TODO 芋艿:bargain_id 砍价 ID + // TODO 芋艿:pinkId 团长拼团 ID // ========= 优惠信息 END ========= - // TODO 待确定字段:mf - // TODO 芋艿:distribution_card_no 推广员 - // TODO 芋艿:is_pay 未购买、已购买 - // TODO 芋艿:is_new 是否立即购买 - - // TODO 待确定字段: yv - // TODO isPay: 是否购买 - // TODO isNew:是否立即购买 - } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java deleted file mode 100644 index fa6adbf41..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.yudao.module.trade.dal.mysql.cart; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -@Mapper -public interface TradeCartItemMapper extends BaseMapperX { - - default TradeCartItemDO selectByUserIdAndSkuId(Long userId, Long skuId) { - return selectOne(TradeCartItemDO::getUserId, userId, - TradeCartItemDO::getSkuId, skuId); - } - - default List selectListByUserIdAndSkuIds(Long userId, Collection skuIds) { - return selectList(new LambdaQueryWrapper().eq(TradeCartItemDO::getUserId, userId) - .in(TradeCartItemDO::getSkuId, skuIds)); - } - - default void updateByIds(Collection ids, TradeCartItemDO updateObject) { - update(updateObject, new LambdaQueryWrapper().in(TradeCartItemDO::getId, ids)); - } - - default Integer selectSumByUserId(Long userId) { - // SQL sum 查询 - List> result = selectMaps(new QueryWrapper() - .select("SUM(count) AS sumCount") - .eq("user_id", userId)); - // 获得数量 - return CollUtil.isNotEmpty(result) ? MapUtil.getInt(result.get(0), "sumCount") : 0; - } - - default List selectListByUserId(Long userId, Boolean selected) { - return selectList(new LambdaQueryWrapperX().eq(TradeCartItemDO::getUserId, userId) - .eqIfPresent(TradeCartItemDO::getSelected, selected)); - } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java new file mode 100644 index 000000000..b1a834c38 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.cart; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Mapper +public interface TradeCartMapper extends BaseMapperX { + + default TradeCartDO selectByUserIdAndSkuId(Long userId, Long skuId, + Boolean addStatus, Boolean orderStatus) { + return selectOne(TradeCartDO::getUserId, userId, + TradeCartDO::getSkuId, skuId, + TradeCartDO::getAddStatus, addStatus, + TradeCartDO::getOrderStatus, orderStatus); + } + + default Integer selectSumByUserId(Long userId) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .eq("user_id", userId) + .eq("add_status", true) // 只计算添加到购物车中的 + .eq("order_status", false)); // 必须未下单 + // 获得数量 + return CollUtil.getFirst(result) != null ? MapUtil.getInt(result.get(0), "sumCount") : 0; + } + + default TradeCartDO selectById(Long id, Long userId) { + return selectOne(TradeCartDO::getId, id, + TradeCartDO::getUserId, userId); + } + + default List selectListByIds(Collection ids, Long userId) { + return selectList(new LambdaQueryWrapper() + .in(TradeCartDO::getId, ids) + .eq(TradeCartDO::getUserId, userId)); + } + + default List selectListByUserId(Long userId) { + return selectList(TradeCartDO::getUserId, userId); + } + + default void updateByIds(Collection ids, TradeCartDO updateObject) { + update(updateObject, new LambdaQueryWrapper().in(TradeCartDO::getId, ids)); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java index 3f46f5102..bb06374b6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java @@ -1,9 +1,8 @@ package cn.iocoder.yudao.module.trade.service.cart; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import javax.validation.Valid; import java.util.Collection; @@ -19,9 +18,10 @@ public interface TradeCartService { * 添加商品到购物车 * * @param userId 用户编号 - * @param addCountReqVO 添加信息 + * @param addReqVO 添加信息 + * @return 购物项的编号 */ - void addCartItemCount(Long userId, @Valid AppTradeCartItemAddCountReqVO addCountReqVO); + Long addCart(Long userId, @Valid AppTradeCartAddReqVO addReqVO); /** * 更新购物车商品数量 @@ -29,23 +29,15 @@ public interface TradeCartService { * @param userId 用户编号 * @param updateCountReqVO 更新信息 */ - void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO); - - /** - * 更新购物车商品是否选中 - * - * @param userId 用户编号 - * @param updateSelectedReqVO 更新信息 - */ - void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO); + void updateCart(Long userId, AppTradeCartUpdateReqVO updateCountReqVO); /** * 删除购物车商品 * * @param userId 用户编号 - * @param skuIds SKU 编号的数组 + * @param ids 购物项的编号 */ - void deleteCartItems(Long userId, Collection skuIds); + void deleteCart(Long userId, Collection ids); /** * 查询用户在购物车中的商品数量 @@ -56,11 +48,11 @@ public interface TradeCartService { Integer getCartCount(Long userId); /** - * 查询用户的购物车详情 + * 查询用户的购物车列表 * * @param userId 用户编号 - * @return 购物车详情 + * @return 购物车列表 */ - AppTradeCartDetailRespVO getCartDetail(Long userId); + AppTradeCartListRespVO getCartList(Long userId); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java index ae0301e83..9539a19c5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java @@ -1,39 +1,38 @@ package cn.iocoder.yudao.module.trade.service.cart; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.promotion.api.price.PriceApi; -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import cn.iocoder.yudao.module.trade.convert.cart.TradeCartConvert; -import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; -import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartItemMapper; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; +import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartMapper; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.List; -import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.CARD_ITEM_NOT_FOUND; +import static java.util.Collections.emptyList; /** * 购物车 Service 实现类 * + * // TODO 芋艿:秒杀、拼团、砍价对购物车的影响 + * // TODO 芋艿:未来优化:购物车的价格计算,支持营销信息 + * * @author 芋道源码 */ @Service @@ -41,123 +40,92 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.CARD_ITEM_N public class TradeCartServiceImpl implements TradeCartService { @Resource - private TradeCartItemMapper cartItemMapper; + private TradeCartMapper cartMapper; + @Resource + private ProductSpuApi productSpuApi; @Resource private ProductSkuApi productSkuApi; - @Resource - private PriceApi priceApi; @Override - public void addCartItemCount(Long userId, AppTradeCartItemAddCountReqVO addCountReqVO) { - Long skuId = addCountReqVO.getSkuId(); - Integer count = addCountReqVO.getCount(); - // 查询 CartItemDO - TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, addCountReqVO.getSkuId()); + public Long addCart(Long userId, AppTradeCartAddReqVO addReqVO) { + // 查询 TradeCartDO + TradeCartDO cart = cartMapper.selectByUserIdAndSkuId(userId, addReqVO.getSkuId(), + addReqVO.getAddStatus(), false); + // 校验 SKU + Integer count = cart != null && addReqVO.getAddStatus() ? + cart.getCount() + addReqVO.getCount() : addReqVO.getCount(); + ProductSkuRespDTO sku = checkProductSku(addReqVO.getSkuId(), count); - // 存在,则进行数量更新 - if (tradeItem != null) { - checkProductSku(skuId, tradeItem.getCount() + count); - cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()) - .setSelected(true).setCount(tradeItem.getCount() + count)); - return; + // 情况一:存在,则进行数量更新 + if (cart != null) { + cartMapper.updateById(new TradeCartDO().setId(cart.getId()).setCount(count)); + return cart.getId(); + // 情况二:不存在,则进行插入 + } else { + cart = new TradeCartDO().setUserId(userId) + .setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count) + .setAddStatus(addReqVO.getAddStatus()).setOrderStatus(false); + cartMapper.insert(cart); } - - // 不存在,则进行插入 - ProductSkuRespDTO sku = checkProductSku(skuId, count); - cartItemMapper.insert(new TradeCartItemDO().setUserId(userId).setSpuId(sku.getSpuId()).setSkuId(sku.getId()) - .setSelected(true).setCount(count)); + return cart.getId(); } @Override - public void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO) { - // 校验 TradeCartItemDO 存在 - TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, updateCountReqVO.getSkuId()); - if (tradeItem == null) { + public void updateCart(Long userId, AppTradeCartUpdateReqVO updateReqVO) { + // 校验 TradeCartDO 存在 + TradeCartDO cart = cartMapper.selectById(updateReqVO.getId(), userId); + if (cart == null) { throw exception(CARD_ITEM_NOT_FOUND); } // 校验商品 SKU - checkProductSku(updateCountReqVO.getSkuId(), updateCountReqVO.getCount()); + checkProductSku(cart.getSkuId(), updateReqVO.getCount()); // 更新数量 - cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()).setCount(updateCountReqVO.getCount())); - } - - @Override - public void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { - // 查询 CartItemDO 列表 - List cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, updateSelectedReqVO.getSkuIds()); - if (CollUtil.isEmpty(cartItems)) { - return; - } - - // 更新选中 - cartItemMapper.updateByIds(CollectionUtils.convertList(cartItems, TradeCartItemDO::getId), - new TradeCartItemDO().setSelected(updateSelectedReqVO.getSelected())); + cartMapper.updateById(new TradeCartDO().setId(cart.getId()) + .setCount(updateReqVO.getCount())); } /** * 购物车删除商品 * * @param userId 用户编号 - * @param skuIds 商品 SKU 编号的数组 + * @param ids 商品 SKU 编号的数组 */ @Override - public void deleteCartItems(Long userId, Collection skuIds) { - // 查询 CartItemDO 列表 - List cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, skuIds); - if (CollUtil.isEmpty(cartItems)) { + public void deleteCart(Long userId, Collection ids) { + // 查询 TradeCartDO 列表 + List carts = cartMapper.selectListByIds(ids, userId); + if (CollUtil.isEmpty(carts)) { return; } // 批量标记删除 - cartItemMapper.deleteBatchIds(CollectionUtils.convertSet(cartItems, TradeCartItemDO::getId)); + cartMapper.deleteBatchIds(ids); } @Override public Integer getCartCount(Long userId) { - return cartItemMapper.selectSumByUserId(userId); + return cartMapper.selectSumByUserId(userId); } @Override - public AppTradeCartDetailRespVO getCartDetail(Long userId) { + public AppTradeCartListRespVO getCartList(Long userId) { // 获得购物车的商品 - List cartItems = cartItemMapper.selectListByUserId(userId, null); + List carts = cartMapper.selectListByUserId(userId); + carts.sort(Comparator.comparing(TradeCartDO::getId).reversed()); // 如果未空,则返回空结果 - if (CollUtil.isEmpty(cartItems)) { - return TradeCartConvert.INSTANCE.buildEmptyAppTradeCartDetailRespVO(); + if (CollUtil.isEmpty(carts)) { + return new AppTradeCartListRespVO().setValidList(emptyList()) + .setInvalidList(emptyList()); } - // 调用价格服务,计算价格 - PriceCalculateRespDTO priceCalculate = priceApi.calculatePrice(TradeCartConvert.INSTANCE.convert(userId, cartItems)); + // 查询 SPU、SKU 列表 + List spus = productSpuApi.getSpuList(convertSet(carts, TradeCartDO::getSpuId)); + List skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSpuId)); - // 转换返回 - Map cartItemMap = convertMap(cartItems, TradeCartItemDO::getSkuId); - Map orderItemMap = convertMap(priceCalculate.getOrder().getItems(), - PriceCalculateRespDTO.OrderItem::getSkuId); - List itemGroups = new ArrayList<>(cartItems.size()); - // ① 场景一,营销活动,订单级别 TODO 芋艿:待测试 - priceCalculate.getPromotions().stream().filter(promotion -> PromotionLevelEnum.ORDER.getLevel().equals(promotion.getLevel())) - .forEach(promotion -> { - AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>()) - .setPromotion(TradeCartConvert.INSTANCE.convert(promotion)); - itemGroups.add(itemGroup); - promotion.getItems().forEach(promotionItem -> { - PriceCalculateRespDTO.OrderItem orderItem = orderItemMap.remove(promotionItem.getSkuId()); - Assert.notNull(orderItem, "商品 SKU({}) 对应的订单项不能为空", promotionItem.getSkuId()); - TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); - itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu - }); - }); - // ② 场景二,营销活动,商品级别 - orderItemMap.values().forEach(orderItem -> { - AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>(1)).setPromotion(null); - itemGroups.add(itemGroup); - TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); - itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu - }); - return new AppTradeCartDetailRespVO().setItemGroups(itemGroups) - .setOrder(TradeCartConvert.INSTANCE.convert(priceCalculate.getOrder())); + // 拼接数据 + return TradeCartConvert.INSTANCE.convertList(carts, spus, skus); } /** From f7fe9ad7b0c19f2c2fc12bc518b34ee991ac5283 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 1 May 2023 16:00:37 +0800 Subject: [PATCH 4/5] =?UTF-8?q?1.=20=E5=95=86=E5=9F=8E=EF=BC=9A=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E8=B4=AD=E7=89=A9=E8=BD=A6=E7=9A=84=E5=A4=B1=E6=95=88?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=AE=9E=E7=8E=B0=EF=BC=8C=E5=9F=BA=E4=BA=8E?= =?UTF-8?q?=20SPU=20=E6=98=AF=E5=90=A6=E4=B8=8B=E6=9E=B6=202.=20=E5=95=86?= =?UTF-8?q?=E5=9F=8E=EF=BC=9A=E5=A2=9E=E5=8A=A0=E8=B4=AD=E7=89=A9=E8=BD=A6?= =?UTF-8?q?=E5=A4=B1=E6=95=88=E7=9A=84=E9=87=8D=E9=80=89=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/sku/dto/ProductSkuRespDTO.java | 11 ----- .../trade/enums/ErrorCodeConstants.java | 1 - .../app/base/sku/AppProductSkuBaseRespVO.java | 6 +-- .../app/cart/TradeCartController.java | 11 ++++- .../AppTradeCartItemUpdateSelectedReqVO.java | 21 --------- .../app/cart/vo/AppTradeCartResetReqVO.java | 26 ++++++++++ .../trade/convert/cart/TradeCartConvert.java | 8 ++-- .../trade/dal/mysql/cart/TradeCartMapper.java | 7 ++- .../trade/service/cart/TradeCartService.java | 13 ++++- .../service/cart/TradeCartServiceImpl.java | 47 +++++++++++++++++-- .../service/order/TradeOrderServiceImpl.java | 8 +--- 11 files changed, 103 insertions(+), 56 deletions(-) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartResetReqVO.java diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java index 9197c6147..7f5e7aed8 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.product.api.sku.dto; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import lombok.Data; import java.util.List; @@ -22,10 +21,6 @@ public class ProductSkuRespDTO { * SPU 编号 */ private Long spuId; - /** - * SPU 名字 - */ - private String spuName; /** * 属性数组 @@ -51,12 +46,6 @@ public class ProductSkuRespDTO { * 图片地址 */ private String picUrl; - /** - * SKU 状态 - *

- * 枚举 {@link CommonStatusEnum} - */ - private Integer status; /** * 库存 */ diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index af387ab85..d6c314147 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -14,7 +14,6 @@ public interface ErrorCodeConstants { // ========== Order 模块 1-011-000-000 ========== ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品 SKU 不存在"); ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1011000002, "商品 SPU 不可售卖"); - ErrorCode ORDER_CREATE_SKU_NOT_SALE = new ErrorCode(1011000003, "商品 SKU 不可售卖"); ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品 SKU 库存不足"); ErrorCode ORDER_CREATE_SPU_NOT_FOUND = new ErrorCode(1011000005, "商品 SPU 不可售卖"); ErrorCode ORDER_CREATE_ADDRESS_NOT_FOUND = new ErrorCode(1011000006, "收货地址不存在"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java index 053e329b4..bb2c60482 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java @@ -17,12 +17,12 @@ public class AppProductSkuBaseRespVO { @Schema(description = "主键", required = true, example = "1024") private Long id; - @Schema(description = "商品 SKU 名字", required = true, example = "芋道") - private String name; - @Schema(description = "图片地址", example = "https://www.iocoder.cn/xx.png") private String picUrl; + @Schema(description = "销售价格,单位:分", required = true, example = "100") + private Integer price; + @Schema(description = "库存", required = true, example = "1") private Integer stock; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java index d00c2b0f3..79105ced6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; import io.swagger.v3.oas.annotations.Operation; @@ -42,11 +43,19 @@ public class TradeCartController { @PutMapping("/update") @Operation(summary = "更新购物车商品") @PreAuthenticated - public CommonResult updateCartItemQuantity(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) { + public CommonResult updateCart(@Valid @RequestBody AppTradeCartUpdateReqVO updateReqVO) { cartService.updateCart(getLoginUserId(), updateReqVO); return success(true); } + @PutMapping("/reset") + @Operation(summary = "重置购物车商品") + @PreAuthenticated + public CommonResult resetCart(@Valid @RequestBody AppTradeCartResetReqVO updateReqVO) { + cartService.resetCart(getLoginUserId(), updateReqVO); + return success(true); + } + @DeleteMapping("/delete") @Operation(summary = "删除购物车商品") @Parameter(name = "ids", description = "购物车商品编号", required = true, example = "1024,2048") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java deleted file mode 100644 index 62327f320..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.trade.controller.app.cart.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import javax.validation.constraints.NotNull; -import java.util.Collection; - -@Schema(description = "用户 App - 购物车更新是否选中 Request VO") -@Data -public class AppTradeCartItemUpdateSelectedReqVO { - - @Schema(description = "商品 SKU 编号列表", required = true, example = "1024,2048") - @NotNull(message = "商品 SKU 编号列表不能为空") - private Collection skuIds; - - @Schema(description = "是否选中", required = true, example = "true") - @NotNull(message = "是否选中不能为空") - private Boolean selected; - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartResetReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartResetReqVO.java new file mode 100644 index 000000000..eb8a81c80 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartResetReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@Schema(description = "用户 App - 购物车重置 Request VO") +@Data +public class AppTradeCartResetReqVO { + + @Schema(description = "编号", required = true, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "商品 SKU 编号", required = true,example = "1024") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @Schema(description = "商品数量", required = true, example = "1") + @NotNull(message = "数量不能为空") + @Min(message = "数量必须大于 0", value = 1L) + private Integer count; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java index c40ce377f..519b82fc9 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java @@ -34,17 +34,17 @@ public interface TradeCartConvert { ProductSpuRespDTO spu = spuMap.get(cart.getSpuId()); ProductSkuRespDTO sku = skuMap.get(cart.getSkuId()); cartVO.setSpu(convert(spu)).setSku(convert(sku)); - // 如果 spu 或 sku 不存在,或者 spu 被禁用,说明是非法的,或者 sku 库存不足 + // 如果 SPU 不存在,或者下架,或者库存不足,说明是无效的 if (spu == null - || sku == null || !ProductSpuStatusEnum.isEnable(spu.getStatus()) - || sku.getStock() <= 0) { + || spu.getStock() <= 0) { invalidList.add(cartVO); } else { + // 虽然 SKU 可能也会不存在,但是可以通过购物车重新选择 validList.add(cartVO); } }); - return new AppTradeCartListRespVO().setValidList(validList).setValidList(invalidList); + return new AppTradeCartListRespVO().setValidList(validList).setInvalidList(invalidList); } AppProductSpuBaseRespVO convert(ProductSpuRespDTO spu); AppProductSkuBaseRespVO convert(ProductSkuRespDTO sku); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java index b1a834c38..6c44dc279 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java @@ -45,8 +45,11 @@ public interface TradeCartMapper extends BaseMapperX { .eq(TradeCartDO::getUserId, userId)); } - default List selectListByUserId(Long userId) { - return selectList(TradeCartDO::getUserId, userId); + default List selectListByUserId(Long userId, Boolean addStatus, Boolean orderStatus) { + return selectList(new LambdaQueryWrapper() + .eq(TradeCartDO::getUserId, userId) + .eq(TradeCartDO::getAddStatus, addStatus) + .eq(TradeCartDO::getOrderStatus, orderStatus)); } default void updateByIds(Collection ids, TradeCartDO updateObject) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java index bb06374b6..9b87762c9 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java @@ -1,7 +1,8 @@ package cn.iocoder.yudao.module.trade.service.cart; -import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import javax.validation.Valid; @@ -31,6 +32,16 @@ public interface TradeCartService { */ void updateCart(Long userId, AppTradeCartUpdateReqVO updateCountReqVO); + /** + * 重置购物车商品 + * + * 使用场景:在一个购物车项对应的商品失效(例如说 SPU 被下架),可以重新选择对应的 SKU + * + * @param userId 用户编号 + * @param updateReqVO 重置信息 + */ + void resetCart(Long userId, AppTradeCartResetReqVO updateReqVO); + /** * 删除购物车商品 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java index 9539a19c5..ffd75a07a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java @@ -1,18 +1,19 @@ package cn.iocoder.yudao.module.trade.service.cart; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO; import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; import cn.iocoder.yudao.module.trade.convert.cart.TradeCartConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartMapper; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; @@ -86,6 +87,28 @@ public class TradeCartServiceImpl implements TradeCartService { .setCount(updateReqVO.getCount())); } + @Override + @Transactional(rollbackFor = Exception.class) + public void resetCart(Long userId, AppTradeCartResetReqVO resetReqVO) { + // 第一步:删除原本的购物项 + TradeCartDO oldCart = cartMapper.selectById(resetReqVO.getId(), userId); + if (oldCart == null) { + throw exception(CARD_ITEM_NOT_FOUND); + } + cartMapper.deleteById(oldCart.getId()); + + // 第二步:添加新的购物项 + TradeCartDO newCart = cartMapper.selectByUserIdAndSkuId(userId, resetReqVO.getSkuId(), + true, false); + if (newCart != null) { + updateCart(userId, new AppTradeCartUpdateReqVO() + .setId(newCart.getId()).setCount(resetReqVO.getCount())); + } else { + addCart(userId, new AppTradeCartAddReqVO().setAddStatus(true) + .setSkuId(resetReqVO.getSkuId()).setCount(resetReqVO.getCount())); + } + } + /** * 购物车删除商品 * @@ -111,8 +134,8 @@ public class TradeCartServiceImpl implements TradeCartService { @Override public AppTradeCartListRespVO getCartList(Long userId) { - // 获得购物车的商品 - List carts = cartMapper.selectListByUserId(userId); + // 获得购物车的商品,只查询未下单的 + List carts = cartMapper.selectListByUserId(userId, true, false); carts.sort(Comparator.comparing(TradeCartDO::getId).reversed()); // 如果未空,则返回空结果 if (CollUtil.isEmpty(carts)) { @@ -122,12 +145,26 @@ public class TradeCartServiceImpl implements TradeCartService { // 查询 SPU、SKU 列表 List spus = productSpuApi.getSpuList(convertSet(carts, TradeCartDO::getSpuId)); - List skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSpuId)); + List skus = productSkuApi.getSkuList(convertSet(carts, TradeCartDO::getSkuId)); + + // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除 + deleteCartIfSpuDeleted(carts, spus); // 拼接数据 return TradeCartConvert.INSTANCE.convertList(carts, spus, skus); } + private void deleteCartIfSpuDeleted(List carts, List spus) { + // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除 + carts.removeIf(cart -> { + if (spus.stream().noneMatch(spu -> spu.getId().equals(cart.getSpuId()))) { + cartMapper.deleteById(cart.getId()); + return true; + } + return false; + }); + } + /** * 校验商品 SKU 是否合法 * 1. 是否存在 @@ -140,7 +177,7 @@ public class TradeCartServiceImpl implements TradeCartService { */ private ProductSkuRespDTO checkProductSku(Long skuId, Integer count) { ProductSkuRespDTO sku = productSkuApi.getSku(skuId); - if (sku == null || CommonStatusEnum.DISABLE.getStatus().equals(sku.getStatus())) { + if (sku == null) { throw exception(SKU_NOT_EXISTS); } if (count > sku.getStock()) { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 86d84c415..464cb86a7 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -5,7 +5,6 @@ import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.TerminalEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -125,15 +124,10 @@ public class TradeOrderServiceImpl implements TradeOrderService { if (items.size() != skus.size()) { throw exception(ORDER_CREATE_SKU_NOT_FOUND); } - // 校验是否禁用 or 库存不足 + // 校验库存不足 Map skuMap = convertMap(skus, ProductSkuRespDTO::getId); items.forEach(item -> { ProductSkuRespDTO sku = skuMap.get(item.getSkuId()); - // SKU 禁用 - if (ObjectUtil.notEqual(CommonStatusEnum.ENABLE.getStatus(), sku.getStatus())) { - throw exception(ORDER_CREATE_SKU_NOT_SALE); - } - // SKU 库存不足 if (item.getCount() > sku.getStock()) { throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_STOCK_NOT_ENOUGH); } From 9980b12551e9cd5ce59b5e497b6754cf8209654f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 3 May 2023 00:30:02 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=B4=AD=E7=89=A9?= =?UTF-8?q?=E8=BD=A6=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=94=AF=E6=8C=81=20add=20?= =?UTF-8?q?=E5=95=86=E5=93=81=E6=97=B6=EF=BC=8C=E9=80=82=E9=85=8D=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E5=8F=AF=E8=83=BD=E8=A6=81=E5=88=A0=E9=99=A4=E7=9A=84?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/app/cart/vo/AppTradeCartAddReqVO.java | 2 -- .../module/trade/service/cart/TradeCartServiceImpl.java | 8 +++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java index c1e3ebd2f..1018ec9a2 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartAddReqVO.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.cart.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; @Schema(description = "用户 App - 购物车添加购物项 Request VO") @@ -16,7 +15,6 @@ public class AppTradeCartAddReqVO { @Schema(description = "新增商品数量", required = true, example = "1") @NotNull(message = "数量不能为空") - @Min(message = "数量必须大于 0", value = 1L) private Integer count; @Schema(description = "是否添加到购物车", required = true, example = "true") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java index ffd75a07a..f92068644 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java @@ -58,9 +58,15 @@ public class TradeCartServiceImpl implements TradeCartService { cart.getCount() + addReqVO.getCount() : addReqVO.getCount(); ProductSkuRespDTO sku = checkProductSku(addReqVO.getSkuId(), count); + // 情况零:特殊,count 小于等于 0,说明前端项目删除 // 情况一:存在,则进行数量更新 if (cart != null) { - cartMapper.updateById(new TradeCartDO().setId(cart.getId()).setCount(count)); + // 特殊情况,如果 count 小于等于 0,说明前端想要删除 + if (count <= 0) { + cartMapper.deleteById(cart.getId()); + } else { + cartMapper.updateById(new TradeCartDO().setId(cart.getId()).setCount(count)); + } return cart.getId(); // 情况二:不存在,则进行插入 } else {