From 9bad25475bbce5df53284605d7330d0545ca11b1 Mon Sep 17 00:00:00 2001 From: delicacylee Date: Mon, 31 Jul 2023 23:29:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=95=86=E5=93=81=E3=80=81?= =?UTF-8?q?=E5=95=86=E5=93=81=E8=A7=84=E6=A0=BC/=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E3=80=81=E5=BA=93=E5=AD=98=E3=80=81=E8=B4=AD=E7=89=A9=E8=BD=A6?= =?UTF-8?q?=E7=AD=89=E6=8E=A5=E5=8F=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 2 + hiver-admin/test-output/test-report.html | 16 +- .../core/common/constant/MallConstant.java | 10 + .../hiver/mall/common/AttributeTypeEnum.java | 30 ++ .../mall/controller/GoodsCartController.java | 74 +++- .../mall/controller/GoodsController.java | 24 +- .../converter/GoodsAttributeConverter.java | 15 + .../hiver/mall/converter/GoodsConverter.java | 19 + .../cc/hiver/mall/dao/mapper/GoodsMapper.java | 15 +- .../main/java/cc/hiver/mall/entity/Goods.java | 2 +- .../cc/hiver/mall/pojo/dto/CartItemDTO.java | 36 ++ .../mall/pojo/form/GoodsAttributeForm.java | 22 ++ .../cc/hiver/mall/pojo/form/GoodsForm.java | 5 +- .../hiver/mall/pojo/vo/GoodsCategoryVO.java | 3 - .../cc/hiver/mall/pojo/vo/GoodsDetailVO.java | 4 - .../cc/hiver/mall/pojo/vo/GoodsPageVO.java | 4 - .../hiver/mall/pojo/vo/MallGoodsDetailVO.java | 113 ++++++ .../hiver/mall/pojo/vo/MallGoodsPageVO.java | 32 ++ .../cc/hiver/mall/service/CartService.java | 21 ++ .../mall/service/mybatis/GoodsService.java | 18 + .../mall/serviceimpl/CartServiceImpl.java | 135 +++++++ .../serviceimpl/mybatis/GoodsServiceImpl.java | 332 +++++++++++++++++- .../src/main/resources/mapper/GoodsMapper.xml | 33 +- 23 files changed, 924 insertions(+), 41 deletions(-) create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/common/AttributeTypeEnum.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsAttributeConverter.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsConverter.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CartItemDTO.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsAttributeForm.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsDetailVO.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsPageVO.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/CartService.java create mode 100644 hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/CartServiceImpl.java diff --git a/hiver-admin/src/main/resources/application.yml b/hiver-admin/src/main/resources/application.yml index 89141df5..3a2cccec 100644 --- a/hiver-admin/src/main/resources/application.yml +++ b/hiver-admin/src/main/resources/application.yml @@ -283,6 +283,8 @@ ignored: - /hiver/iot/sensorHelper/** - /hiver/goview/visual/** - /hiver/license/verifyLicense + # 临时增加 + - /hiver/app/** # 限流及黑名单不拦截的路径 limitUrls: - /**/*.js diff --git a/hiver-admin/test-output/test-report.html b/hiver-admin/test-output/test-report.html index ddf3c480..79f23440 100644 --- a/hiver-admin/test-output/test-report.html +++ b/hiver-admin/test-output/test-report.html @@ -35,7 +35,7 @@ Hiver
  • - 31, 2023 09:25:02 + 31, 2023 23:25:57
  • @@ -84,7 +84,7 @@

    passTest

    -

    09:25:03 / 0.022 secs

    +

    23:25:57 / 0.01 secs

    @@ -92,9 +92,9 @@
    #test-id=1
    passTest
    -07.31.2023 09:25:03 -07.31.2023 09:25:03 -0.022 secs +07.31.2023 23:25:57 +07.31.2023 23:25:57 +0.01 secs
    @@ -104,7 +104,7 @@ Pass - 9:25:03 + 23:25:57 Test passed @@ -128,13 +128,13 @@

    Started

    -

    31, 2023 09:25:02

    +

    31, 2023 23:25:57

    Ended

    -

    31, 2023 09:25:03

    +

    31, 2023 23:25:57

    diff --git a/hiver-core/src/main/java/cc/hiver/core/common/constant/MallConstant.java b/hiver-core/src/main/java/cc/hiver/core/common/constant/MallConstant.java index 32bc85e4..7fd4524b 100644 --- a/hiver-core/src/main/java/cc/hiver/core/common/constant/MallConstant.java +++ b/hiver-core/src/main/java/cc/hiver/core/common/constant/MallConstant.java @@ -35,4 +35,14 @@ public interface MallConstant { * 商品分布式锁key前缀 */ String SKU_LOCK_PREFIX = "product:stock:lock:"; + + /** + * 临时规格ID前缀 + */ + String SPEC_TEMP_ID_PREFIX = "tid_"; + + /** + * 会员购物车缓存KEY前缀 + */ + String MEMBER_CART_PREFIX = "MEMBER:CART:"; } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/common/AttributeTypeEnum.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/common/AttributeTypeEnum.java new file mode 100644 index 00000000..fd9c9b96 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/common/AttributeTypeEnum.java @@ -0,0 +1,30 @@ +package cc.hiver.mall.common; + +import lombok.Getter; + +public enum AttributeTypeEnum { + SPEC(1, "规格"), + ATTR(2, "属性"); + + AttributeTypeEnum(int value, String name) { + this.value = value; + this.name = name; + } + + @Getter + private Integer value; + + @Getter + private String name; + + public static AttributeTypeEnum getByValue(Integer value) { + AttributeTypeEnum attributeTypeEnum = null; + + for (AttributeTypeEnum item : values()) { + if (item.getValue().equals(value)) { + attributeTypeEnum = item; + } + } + return attributeTypeEnum; + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsCartController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsCartController.java index 2ee2f67e..31a0d48b 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsCartController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsCartController.java @@ -15,15 +15,23 @@ limitations under the License. */ package cc.hiver.mall.controller; -import cc.hiver.mall.service.SalesOrderItemService; -import cc.hiver.mall.service.SalesOrderService; +import cc.hiver.core.common.utils.ResultUtil; +import cc.hiver.core.common.utils.SecurityUtil; +import cc.hiver.core.common.vo.Result; +import cc.hiver.mall.pojo.dto.CartItemDTO; +import cc.hiver.mall.service.CartService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** * @author Yazhi Li */ @@ -34,8 +42,66 @@ import org.springframework.web.bind.annotation.RestController; @Transactional public class GoodsCartController { @Autowired - private SalesOrderService salesOrderService; + private CartService cartService; @Autowired - private SalesOrderItemService salesOrderItemService; + private SecurityUtil securityUtil; + + @RequestMapping(value = "/get", method = RequestMethod.GET) + @ApiOperation(value = "查询购物车") + public Result> getCart() { + List result = cartService.listCartItems(securityUtil.getCurrUser().getId()); + return new ResultUtil>().setData(result); + } + + @RequestMapping(value = "/delete", method = RequestMethod.POST) + @ApiOperation(value = "删除购物车") + public Result deleteCart() { + boolean result = cartService.deleteCart(securityUtil.getCurrUser().getId()); + if(result) { + return ResultUtil.success("删除成功"); + } else { + return ResultUtil.error("删除失败"); + } + } + + @RequestMapping(value = "/add", method = RequestMethod.POST) + @ApiOperation(value = "添加购物车商品") + public Result addCartItem(String skuId) { + cartService.addCartItem(skuId, securityUtil.getCurrUser().getId()); + return ResultUtil.success(); + } + + @RequestMapping(value = "/edit", method = RequestMethod.POST) + @ApiOperation(value = "更新购物车商品") + public Result updateCartItem(CartItemDTO cartItem) { + boolean result = cartService.updateCartItem(cartItem, securityUtil.getCurrUser().getId()); + if(result) { + return ResultUtil.success("更新成功"); + } else { + return ResultUtil.error("更新失败"); + } + } + + @RequestMapping(value = "/item/delete", method = RequestMethod.POST) + @ApiOperation(value = "删除购物车商品") + public Result removeCartItem(String goodsStockId) { + boolean result = cartService.removeCartItem(goodsStockId, securityUtil.getCurrUser().getId()); + if(result) { + return ResultUtil.success("删除成功"); + } else { + return ResultUtil.error("删除失败"); + } + } + + @RequestMapping(value = "/_check", method = RequestMethod.POST) + @ApiOperation(value = "全选/全不选购物车商品") + public Result check(@ApiParam("全选/全不选") boolean checked) { + boolean result = cartService.checkAll(checked, securityUtil.getCurrUser().getId()); + if(result) { + return ResultUtil.success("设置成功"); + } else { + return ResultUtil.error("设置失败"); + } + } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsController.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsController.java index 7fb302f6..c70dfce0 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsController.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsController.java @@ -6,6 +6,8 @@ import cc.hiver.mall.pojo.form.GoodsForm; import cc.hiver.mall.pojo.query.GoodsPageQuery; import cc.hiver.mall.pojo.vo.GoodsDetailVO; import cc.hiver.mall.pojo.vo.GoodsPageVO; +import cc.hiver.mall.pojo.vo.MallGoodsDetailVO; +import cc.hiver.mall.pojo.vo.MallGoodsPageVO; import cc.hiver.mall.service.mybatis.GoodsService; import com.baomidou.mybatisplus.core.metadata.IPage; import io.swagger.annotations.Api; @@ -25,16 +27,16 @@ public class GoodsController { @Autowired private GoodsService goodsService; - @RequestMapping(value = "/getByCondition", method = RequestMethod.POST) + @RequestMapping(value = "/listGoodsPages", method = RequestMethod.POST) @ApiOperation(value = "商品分页列表") - public Result> listPmsSpuPages(GoodsPageQuery queryParams) { + public Result> listGoodsPages(GoodsPageQuery queryParams) { IPage result = goodsService.listGoodsPages(queryParams); return new ResultUtil>().setData(result); } - @RequestMapping(value = "/get/{id}", method = RequestMethod.GET) + @RequestMapping(value = "/getGoodsDetail/{id}", method = RequestMethod.GET) @ApiOperation(value = "商品详情") - public Result detail(@ApiParam("商品ID") @PathVariable String id) { + public Result getGoodsDetail(@ApiParam("商品ID") @PathVariable String id) { GoodsDetailVO goodsDetailVO = goodsService.getGoodsDetail(id); return new ResultUtil().setData(goodsDetailVO); } @@ -71,4 +73,18 @@ public class GoodsController { return ResultUtil.error("删除失败"); } } + + @RequestMapping(value = "/listMallGoodsPages", method = RequestMethod.POST) + @ApiOperation(value = "商品分页列表") + public Result listMallGoodsPages(GoodsPageQuery queryParams) { + IPage result = goodsService.listMallGoodsPages(queryParams); + return new ResultUtil>().setData(result); + } + + @RequestMapping(value = "/getMallGoodsDetail/{id}", method = RequestMethod.GET) + @ApiOperation(value = "获取商品详情") + public Result getMallGoodsDetail(@ApiParam("商品ID") @PathVariable String id) { + MallGoodsDetailVO mallGoodsDetailVO = goodsService.getMallGoodsDetail(id); + return new ResultUtil().setData(mallGoodsDetailVO); + } } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsAttributeConverter.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsAttributeConverter.java new file mode 100644 index 00000000..dd42b9da --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsAttributeConverter.java @@ -0,0 +1,15 @@ +package cc.hiver.mall.converter; + +import cc.hiver.mall.entity.GoodsAttribute; +import cc.hiver.mall.pojo.form.GoodsAttributeForm; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; + +@Mapper(componentModel = "spring") +public interface GoodsAttributeConverter { + @Mappings({ + @Mapping(target = "id",ignore = true) + }) + GoodsAttribute form2Entity(GoodsAttributeForm form); +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsConverter.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsConverter.java new file mode 100644 index 00000000..accf6792 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsConverter.java @@ -0,0 +1,19 @@ +package cc.hiver.mall.converter; + +import cc.hiver.mall.entity.Goods; +import cc.hiver.mall.pojo.form.GoodsForm; +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; + +@Mapper(componentModel = "spring") +public interface GoodsConverter { + @Mappings({ + @Mapping(target = "album", source = "subPicUrls") + }) + Goods form2Entity(GoodsForm form); + + @InheritInverseConfiguration(name="form2Entity") + GoodsForm entity2Form(Goods entity); +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/GoodsMapper.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/GoodsMapper.java index ce2af98e..b08e3456 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/GoodsMapper.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/GoodsMapper.java @@ -18,9 +18,11 @@ package cc.hiver.mall.dao.mapper; import cc.hiver.mall.entity.Goods; import cc.hiver.mall.pojo.query.GoodsPageQuery; import cc.hiver.mall.pojo.vo.GoodsPageVO; +import cc.hiver.mall.pojo.vo.MallGoodsPageVO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -30,11 +32,20 @@ import java.util.List; @Mapper public interface GoodsMapper extends BaseMapper { /** - * 商品分页列表 + * 商品分页列表(管理用) * * @param page * @param queryParams * @return */ - List listGoodsPages(Page page, GoodsPageQuery queryParams); + List listGoodsPages(Page page, @Param("queryParams") GoodsPageQuery queryParams); + + /** + * 商品分页列表(商铺用) + * + * @param page + * @param queryParams + * @return + */ + List listMallGoodsPages(Page page, @Param("queryParams") GoodsPageQuery queryParams); } diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Goods.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Goods.java index 8b354e82..35eeb459 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Goods.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Goods.java @@ -55,7 +55,7 @@ public class Goods extends HiverBaseMallEntity { private String videoUrl; @ApiModelProperty(value = "商品图册") - private String album; + private String[] album; @ApiModelProperty(value = "单位") private String unit; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CartItemDTO.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CartItemDTO.java new file mode 100644 index 00000000..0f116608 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CartItemDTO.java @@ -0,0 +1,36 @@ +package cc.hiver.mall.pojo.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class CartItemDTO implements Serializable { + @ApiModelProperty(value = "商品库存ID") + private String goodsStockId; + + @ApiModelProperty(value = "商品库存名称") + private String goodsStockName; + + @ApiModelProperty(value = "商品编码") + private String goodsStockSN; + + @ApiModelProperty(value = "商品图片") + private String picUrl; + + @ApiModelProperty(value = "商品数量") + private Integer count; + + @ApiModelProperty(value = "加入购物车时价格,因会变动,不能作为订单计算因子,订单提交时需验价") + private Long price; + + @ApiModelProperty(value = "是否选中") + private Boolean checked; + + @ApiModelProperty(value = "商品库存数量,页面控制能选择最大数量") + private Integer stock; + + @ApiModelProperty(value = "商品名称") + private String goodsName; +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsAttributeForm.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsAttributeForm.java new file mode 100644 index 00000000..e649f8b2 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsAttributeForm.java @@ -0,0 +1,22 @@ +package cc.hiver.mall.pojo.form; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class GoodsAttributeForm { + @ApiModelProperty(value = "序号") + private String id; + + @ApiModelProperty(value = "属性ID") + private Long attributeId; + + @ApiModelProperty(value = "商品属性名") + private String name; + + @ApiModelProperty(value = "商品属性值") + private String value; + + @ApiModelProperty(value = "商品图片") + private String picUrl; +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsForm.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsForm.java index cf10d18d..d23a2a6f 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsForm.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsForm.java @@ -15,7 +15,6 @@ limitations under the License. */ package cc.hiver.mall.pojo.form; -import cc.hiver.mall.entity.GoodsAttribute; import cc.hiver.mall.entity.GoodsStock; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -72,10 +71,10 @@ public class GoodsForm { private Integer status; @ApiModelProperty(value = "属性列表") - private List attrList; + private List attrList; @ApiModelProperty(value = "规格列表") - private List specList; + private List specList; @ApiModelProperty(value = "库存列表") private List goodsStockList; diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsCategoryVO.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsCategoryVO.java index f6fc6a09..7c3d0c70 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsCategoryVO.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsCategoryVO.java @@ -18,7 +18,6 @@ package cc.hiver.mall.pojo.vo; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.persistence.Column; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -35,7 +34,6 @@ public class GoodsCategoryVO { private String name; @ApiModelProperty(value = "父级ID") - @Column(nullable = false) private String parentId; @ApiModelProperty(value = "层级") @@ -45,7 +43,6 @@ public class GoodsCategoryVO { private String iconUrl; @ApiModelProperty(value = "排序值") - @Column(precision = 10, scale = 2) private BigDecimal sortOrder; @ApiModelProperty(value = "是否启用 0启用 -1禁用") diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsDetailVO.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsDetailVO.java index 9fdf7b0c..a0bacc20 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsDetailVO.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsDetailVO.java @@ -21,7 +21,6 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.persistence.Column; import java.math.BigDecimal; import java.util.List; @@ -44,15 +43,12 @@ public class GoodsDetailVO { private String brandId; @ApiModelProperty(value = "采购价") - @Column(precision = 10, scale = 2) private BigDecimal purchasePrice; @ApiModelProperty(value = "市场价") - @Column(precision = 10, scale = 2) private BigDecimal price; @ApiModelProperty(value = "批发价") - @Column(precision = 10, scale = 2) private BigDecimal wholesalePrice; @ApiModelProperty(value = "商品主图") diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsPageVO.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsPageVO.java index 481c85ec..22a7fb62 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsPageVO.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsPageVO.java @@ -20,7 +20,6 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.experimental.Accessors; -import javax.persistence.Column; import java.math.BigDecimal; import java.util.List; @@ -43,15 +42,12 @@ public class GoodsPageVO { private String brandId; @ApiModelProperty(value = "采购价") - @Column(precision = 10, scale = 2) private BigDecimal purchasePrice; @ApiModelProperty(value = "市场价") - @Column(precision = 10, scale = 2) private BigDecimal price; @ApiModelProperty(value = "批发价") - @Column(precision = 10, scale = 2) private BigDecimal wholesalePrice; @ApiModelProperty(value = "销量") diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsDetailVO.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsDetailVO.java new file mode 100644 index 00000000..a8b771a4 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsDetailVO.java @@ -0,0 +1,113 @@ +package cc.hiver.mall.pojo.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@ApiModel("商品详情") +public class MallGoodsDetailVO { + @ApiModelProperty("商品基本信息") + private GoodsInfo goodsInfo; + + @ApiModelProperty("商品属性列表") + private List attributeList; + + @ApiModelProperty("商品规格列表") + private List specList; + + @ApiModelProperty("商品库存单元列表") + private List skuList; + + @Data + @ApiModel("商品信息") + public static class GoodsInfo { + @ApiModelProperty("商品ID") + private String id; + + @ApiModelProperty("商品名称") + private String name; + + @ApiModelProperty(value = "采购价") + private BigDecimal purchasePrice; + + @ApiModelProperty(value = "市场价") + private BigDecimal price; + + @ApiModelProperty(value = "批发价") + private BigDecimal wholesalePrice; + + @ApiModelProperty("销量") + private Integer sales; + + @ApiModelProperty("商品图册") + private List album; + + @ApiModelProperty("商品详情") + private String detail; + } + + @Data + @ApiModel("属性信息") + public static class Attribute { + @ApiModelProperty("属性ID") + private String id; + + @ApiModelProperty("属性名称") + private String name; + + @ApiModelProperty("属性值") + private String value; + } + + @Data + @ApiModel("规格信息") + public static class Specification { + @ApiModelProperty(value = "规格名称", example = "颜色") + private String name; + + @ApiModelProperty(value = "规格项列表", example = "黑,白") + private List values; + + @Data + @ApiModel("规格项") + public static class Value { + @ApiModelProperty("规格项ID") + private String id; + + @ApiModelProperty("规格项值") + private String value; + } + } + + @Data + @ApiModel("商品库存单元") + public static class Sku { + @ApiModelProperty("库存单元ID") + private String id; + + @ApiModelProperty("库存单元名称") + private String name; + + @ApiModelProperty("库存单元规格值ID集合,以英文逗号拼接") + private String specIds; + + @ApiModelProperty(value = "采购价") + private BigDecimal purchasePrice; + + @ApiModelProperty(value = "市场价") + private BigDecimal price; + + @ApiModelProperty(value = "批发价") + private BigDecimal wholesalePrice; + + @ApiModelProperty("库存") + private Integer stockNum; + + @ApiModelProperty("商品图片URL") + private String picUrl; + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsPageVO.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsPageVO.java new file mode 100644 index 00000000..b6dc0225 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsPageVO.java @@ -0,0 +1,32 @@ +package cc.hiver.mall.pojo.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +@ApiModel("商品分页对象") +@Data +public class MallGoodsPageVO { + @ApiModelProperty("商品ID") + private Long id; + + @ApiModelProperty("商品名称") + private String name; + + @ApiModelProperty(value = "采购价") + private BigDecimal purchasePrice; + + @ApiModelProperty(value = "市场价") + private BigDecimal price; + + @ApiModelProperty(value = "批发价") + private BigDecimal wholesalePrice; + + @ApiModelProperty("销量") + private Integer sales; + + @ApiModelProperty("图片地址") + private String picUrl; +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/CartService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/CartService.java new file mode 100644 index 00000000..0f0ae9bf --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/CartService.java @@ -0,0 +1,21 @@ +package cc.hiver.mall.service; + +import cc.hiver.mall.pojo.dto.CartItemDTO; + +import java.util.List; + +public interface CartService { + List listCartItems(String memberId); + + boolean deleteCart(String memberId); + + boolean addCartItem(String goodsStockId, String memberId); + + boolean updateCartItem(CartItemDTO cartItem, String memberId); + + boolean removeCartItem(String goodsStockId, String memberId); + + boolean removeCheckedItem(String memberId); + + boolean checkAll(boolean checked, String memberId); +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/GoodsService.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/GoodsService.java index 68cd803f..c29b445a 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/GoodsService.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/GoodsService.java @@ -20,6 +20,8 @@ import cc.hiver.mall.pojo.form.GoodsForm; import cc.hiver.mall.pojo.query.GoodsPageQuery; import cc.hiver.mall.pojo.vo.GoodsDetailVO; import cc.hiver.mall.pojo.vo.GoodsPageVO; +import cc.hiver.mall.pojo.vo.MallGoodsDetailVO; +import cc.hiver.mall.pojo.vo.MallGoodsPageVO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; @@ -35,6 +37,14 @@ public interface GoodsService extends IService { */ IPage listGoodsPages(GoodsPageQuery queryParams); + /** + * 「商铺端」商品分页列表 + * + * @param queryParams + * @return + */ + IPage listMallGoodsPages(GoodsPageQuery queryParams); + /** * 「管理端」获取商品详情 * @@ -43,6 +53,14 @@ public interface GoodsService extends IService { */ GoodsDetailVO getGoodsDetail(String id); + /** + * 「商铺端」获取商品详情 + * + * @param id + * @return + */ + MallGoodsDetailVO getMallGoodsDetail(String id); + /** * 新增商品 * diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/CartServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/CartServiceImpl.java new file mode 100644 index 00000000..b9794938 --- /dev/null +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/CartServiceImpl.java @@ -0,0 +1,135 @@ +package cc.hiver.mall.serviceimpl; + +import cc.hiver.core.common.constant.MallConstant; +import cc.hiver.mall.pojo.dto.CartItemDTO; +import cc.hiver.mall.pojo.dto.GoodsStockDto; +import cc.hiver.mall.service.CartService; +import cc.hiver.mall.service.mybatis.GoodsStockService; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Assert; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.BoundHashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Service +@Slf4j +@AllArgsConstructor +public class CartServiceImpl implements CartService { + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private GoodsStockService goodsStockService; + + @Override + public List listCartItems(String memberId) { + if (memberId != null) { + BoundHashOperations cartHashOperations = getCartHashOperations(memberId); + List cartItems = cartHashOperations.values(); + return cartItems; + } + return Collections.EMPTY_LIST; + } + + @Override + public boolean deleteCart(String memberId) { + String key = MallConstant.MEMBER_CART_PREFIX + memberId; + redisTemplate.delete(key); + return true; + } + + @Override + public boolean addCartItem(String goodsStockId, String memberId) { + BoundHashOperations cartHashOperations = getCartHashOperations(memberId); + String hKey = goodsStockId + ""; + CartItemDTO cartItem; + // 购物车已存在该商品,更新商品数量 + if (cartHashOperations.get(hKey) != null) { + cartItem = (CartItemDTO) cartHashOperations.get(hKey); + cartItem.setCount(cartItem.getCount() + 1); // 点击一次“加入购物车”,数量+1 + cartItem.setChecked(true); + cartHashOperations.put(hKey, cartItem); + return true; + } + // 购物车不存在该商品,添加商品至购物车 + cartItem = new CartItemDTO(); + CompletableFuture cartItemCompletableFuture = CompletableFuture.runAsync(() -> { + GoodsStockDto goodsStockDto = goodsStockService.getStockInfo(goodsStockId); + if (goodsStockDto != null) { + BeanUtil.copyProperties(goodsStockDto, cartItem); + cartItem.setStock(goodsStockDto.getStock()); + cartItem.setCount(1); + cartItem.setChecked(true); + } + }); + CompletableFuture.allOf(cartItemCompletableFuture).join(); + Assert.isTrue(cartItem.getGoodsStockId() != null, "商品不存在"); + cartHashOperations.put(hKey, cartItem); + return true; + } + + @Override + public boolean updateCartItem(CartItemDTO cartItem, String memberId) { + BoundHashOperations cartHashOperations = getCartHashOperations(memberId); + String hKey = cartItem.getGoodsStockId() + ""; + if (cartHashOperations.get(hKey) != null) { + CartItemDTO cacheCartItem = (CartItemDTO) cartHashOperations.get(hKey); + if (cartItem.getChecked() != null) { + cacheCartItem.setChecked(cartItem.getChecked()); + } + if (cartItem.getCount() != null) { + cacheCartItem.setCount(cartItem.getCount()); + } + cartHashOperations.put(hKey, cacheCartItem); + } + return true; + } + + @Override + public boolean removeCartItem(String goodsStockId, String memberId) { + BoundHashOperations cartHashOperations = getCartHashOperations(memberId); + String hKey = goodsStockId + ""; + cartHashOperations.delete(hKey); + return true; + } + + @Override + public boolean removeCheckedItem(String memberId) { + BoundHashOperations cartHashOperations = getCartHashOperations(memberId); + for (Object value : cartHashOperations.values()) { + CartItemDTO cartItem = (CartItemDTO) value; + if (cartItem.getChecked()) { + cartHashOperations.delete(cartItem.getGoodsStockId() + ""); + } + } + return true; + } + + @Override + public boolean checkAll(boolean checked, String memberId) { + BoundHashOperations cartHashOperations = getCartHashOperations(memberId); + for (Object value : cartHashOperations.values()) { + CartItemDTO cartItem = (CartItemDTO) value; + cartItem.setChecked(checked); + String hKey = cartItem.getGoodsStockId() + ""; + cartHashOperations.put(hKey, cartItem); + } + return true; + } + + /** + * 获取第一层,即某个用户的购物车 + */ + private BoundHashOperations getCartHashOperations(String memberId) { + String cartKey = MallConstant.MEMBER_CART_PREFIX + memberId; + BoundHashOperations operations = redisTemplate.boundHashOps(cartKey); + return operations; + } +} diff --git a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/GoodsServiceImpl.java b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/GoodsServiceImpl.java index 3810acec..04b0f99d 100644 --- a/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/GoodsServiceImpl.java +++ b/hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/GoodsServiceImpl.java @@ -15,25 +15,61 @@ limitations under the License. */ package cc.hiver.mall.serviceimpl.mybatis; +import cc.hiver.core.common.constant.MallConstant; +import cc.hiver.mall.common.AttributeTypeEnum; +import cc.hiver.mall.converter.GoodsAttributeConverter; +import cc.hiver.mall.converter.GoodsConverter; import cc.hiver.mall.dao.mapper.GoodsMapper; import cc.hiver.mall.entity.Goods; +import cc.hiver.mall.entity.GoodsAttribute; +import cc.hiver.mall.entity.GoodsStock; +import cc.hiver.mall.pojo.form.GoodsAttributeForm; import cc.hiver.mall.pojo.form.GoodsForm; import cc.hiver.mall.pojo.query.GoodsPageQuery; import cc.hiver.mall.pojo.vo.GoodsDetailVO; import cc.hiver.mall.pojo.vo.GoodsPageVO; +import cc.hiver.mall.pojo.vo.MallGoodsDetailVO; +import cc.hiver.mall.pojo.vo.MallGoodsPageVO; +import cc.hiver.mall.service.mybatis.GoodsAttributeService; import cc.hiver.mall.service.mybatis.GoodsService; +import cc.hiver.mall.service.mybatis.GoodsStockService; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; +import javax.transaction.Transactional; +import java.util.*; +import java.util.stream.Collectors; /** * @author Yazhi Li */ @Service +@RequiredArgsConstructor public class GoodsServiceImpl extends ServiceImpl implements GoodsService { + @Autowired + private GoodsMapper goodsMapper; + + @Autowired + private GoodsStockService goodsStockService; + + @Autowired + private GoodsAttributeService goodsAttributeService; + + @Autowired + private GoodsConverter goodsConverter; + + @Autowired + private GoodsAttributeConverter goodsAttributeConverter; + @Override public IPage listGoodsPages(GoodsPageQuery queryParams) { Page page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); @@ -42,23 +78,309 @@ public class GoodsServiceImpl extends ServiceImpl implements return page; } + @Override + public IPage listMallGoodsPages(GoodsPageQuery queryParams) { + Page page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); + List list = this.baseMapper.listMallGoodsPages(page, queryParams); + page.setRecords(list); + return page; + } + @Override public GoodsDetailVO getGoodsDetail(String id) { - return null; + GoodsDetailVO goodsDetailVO = new GoodsDetailVO(); + + Goods entity = this.getById(id); + Assert.isTrue(entity != null, "商品不存在"); + + BeanUtil.copyProperties(entity, goodsDetailVO, "album"); + goodsDetailVO.setSubPicUrls(entity.getAlbum()); + + // 商品属性列表 + List attrList = goodsAttributeService.list(new LambdaQueryWrapper() + .eq(GoodsAttribute::getId, id) + .eq(GoodsAttribute::getType, AttributeTypeEnum.ATTR.getValue())); + goodsDetailVO.setAttrList(attrList); + + // 商品规格列表 + List specList = goodsAttributeService.list(new LambdaQueryWrapper() + .eq(GoodsAttribute::getId, id) + .eq(GoodsAttribute::getType, AttributeTypeEnum.SPEC.getValue())); + goodsDetailVO.setSpecList(specList); + + // 商品库存列表 + List goodsStockList = goodsStockService.list(new LambdaQueryWrapper().eq(GoodsStock::getGoodsId, id)); + goodsDetailVO.setGoodsStockList(goodsStockList); + return goodsDetailVO; + } + + @Override + public MallGoodsDetailVO getMallGoodsDetail(String id) { + Goods pmsSpu = this.getById(id); + Assert.isTrue(pmsSpu != null, "商品不存在"); + + MallGoodsDetailVO mallGoodsDetailVO = new MallGoodsDetailVO(); + + // 商品基本信息 + MallGoodsDetailVO.GoodsInfo goodsInfo = new MallGoodsDetailVO.GoodsInfo(); + BeanUtil.copyProperties(pmsSpu, goodsInfo, "album"); + + List album = new ArrayList<>(); + + if (StrUtil.isNotBlank(pmsSpu.getPicUrl())) { + album.add(pmsSpu.getPicUrl()); + } + if (pmsSpu.getAlbum() != null && pmsSpu.getAlbum().length > 0) { + album.addAll(Arrays.asList(pmsSpu.getAlbum())); + goodsInfo.setAlbum(album); + } + mallGoodsDetailVO.setGoodsInfo(goodsInfo); + + // 商品属性列表 + List attributeList = goodsAttributeService.list(new LambdaQueryWrapper() + .eq(GoodsAttribute::getType, AttributeTypeEnum.ATTR.getValue()).eq(GoodsAttribute::getGoodsId, id) + .select(GoodsAttribute::getId, GoodsAttribute::getName, GoodsAttribute::getValue)).stream(). + map(item -> { + MallGoodsDetailVO.Attribute attribute = new MallGoodsDetailVO.Attribute(); + BeanUtil.copyProperties(item, attribute); + return attribute; + }).collect(Collectors.toList()); + mallGoodsDetailVO.setAttributeList(attributeList); + + + // 商品规格列表 + List specSourceList = goodsAttributeService.list(new LambdaQueryWrapper() + .eq(GoodsAttribute::getType, AttributeTypeEnum.SPEC.getValue()) + .eq(GoodsAttribute::getGoodsId, id) + .select(GoodsAttribute::getId, GoodsAttribute::getName, GoodsAttribute::getValue)); + + List specList = new ArrayList<>(); + // 规格Map [key:"颜色",value:[{id:1,value:"黑"},{id:2,value:"白"}]] + Map> specValueMap = specSourceList.stream().collect(Collectors.groupingBy(GoodsAttribute::getName)); + + for (Map.Entry> entry : specValueMap.entrySet()) { + String specName = entry.getKey(); + List specValueSourceList = entry.getValue(); + + // 规格映射处理 + MallGoodsDetailVO.Specification spec = new MallGoodsDetailVO.Specification(); + spec.setName(specName); + if (CollectionUtil.isNotEmpty(specValueSourceList)) { + List specValueList = specValueSourceList.stream().map(item -> { + MallGoodsDetailVO.Specification.Value specValue = new MallGoodsDetailVO.Specification.Value(); + specValue.setId(item.getId()); + specValue.setValue(item.getValue()); + return specValue; + }).collect(Collectors.toList()); + spec.setValues(specValueList); + specList.add(spec); + } + } + mallGoodsDetailVO.setSpecList(specList); + + // 商品库存列表 + List skuSourceList = goodsStockService.list(new LambdaQueryWrapper().eq(GoodsStock::getGoodsId, id)); + if (CollectionUtil.isNotEmpty(skuSourceList)) { + List skuList = skuSourceList.stream().map(item -> { + MallGoodsDetailVO.Sku sku = new MallGoodsDetailVO.Sku(); + BeanUtil.copyProperties(item, sku); + return sku; + }).collect(Collectors.toList()); + mallGoodsDetailVO.setSkuList(skuList); + } + + return mallGoodsDetailVO; } @Override + @Transactional public boolean addGoods(GoodsForm formData) { - return false; + Goods entity = goodsConverter.form2Entity(formData); + boolean result = this.save(entity); + if (result) { + String goodsId = entity.getId(); + // 保存属性 + List attrList = formData.getAttrList(); + this.saveSpuAttrs(goodsId, attrList); + // 保存规格 + List specList = formData.getSpecList(); + Map tempWithNewSpecIdMap = this.saveSpuSpecs(goodsId, specList); + // 保存SKU + List skuList = formData.getGoodsStockList(); + this.saveSku(goodsId, skuList, tempWithNewSpecIdMap); + } + // 无异常返回true + return result; } @Override + @Transactional public boolean updateGoods(GoodsForm formData) { - return false; + Goods entity = goodsConverter.form2Entity(formData); + boolean result = this.updateById(entity); + if (result) { + // 属性保存 + List attrList = formData.getAttrList(); + this.saveSpuAttrs(entity.getId(), attrList); + + // 保存商品规格值 + List specList = formData.getSpecList(); + Map specTempIdIdMap = this.saveSpuSpecs(entity.getId(), specList); + + // SKU保存 + List skuList = formData.getGoodsStockList(); + this.saveSku(entity.getId(), skuList, specTempIdIdMap); + } + return result; } @Override + @Transactional public boolean removeByGoodsIds(String[] ids) { - return false; + for (String id : ids) { + goodsStockService.remove(new LambdaQueryWrapper().eq(GoodsStock::getGoodsId, id)); + // 规格 + goodsAttributeService.remove(new LambdaQueryWrapper().eq(GoodsAttribute::getGoodsId, id)); + // 属性 + goodsAttributeService.remove(new LambdaQueryWrapper().eq(GoodsAttribute::getGoodsId, id)); + // SPU + this.removeById(id); + } + // 无异常直接返回true + return true; + } + + /** + * 保存SKU,需要替换提交表单中的临时规格ID + * + * @param goodsId + * @param skuList + * @param specTempIdIdMap + * @return + */ + private boolean saveSku(String goodsId, List skuList, Map specTempIdIdMap) { + // 删除SKU + List formSkuIds = skuList.stream().map(GoodsStock::getId).collect(Collectors.toList()); + List dbSkuIds = goodsStockService.list(new LambdaQueryWrapper().eq(GoodsStock::getGoodsId, goodsId) + .select(GoodsStock::getId)).stream().map(GoodsStock::getId) + .collect(Collectors.toList()); + List removeSkuIds = dbSkuIds.stream().filter(dbSkuId -> !formSkuIds.contains(dbSkuId)).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(removeSkuIds)) { + goodsStockService.removeByIds(removeSkuIds); + } + // 新增/修改SKU + List pmsSkuList = skuList.stream().map(sku -> { + // 临时规格ID转换 + String specIds = Arrays.stream(sku.getSpecIds().split("\\|")) + .map(specId -> specId.startsWith(MallConstant.SPEC_TEMP_ID_PREFIX) ? specTempIdIdMap.get(specId) + "" : specId) + .collect(Collectors.joining("_")); + sku.setSpecIds(specIds); + sku.setGoodsId(goodsId); + return sku; + }).collect(Collectors.toList()); + return goodsStockService.saveOrUpdateBatch(pmsSkuList); + } + + /** + * 保存商品属性 + * + * @param goodsId 商品ID + * @param attrList 商品属性集合 + * @return + */ + private boolean saveSpuAttrs(String goodsId, List attrList) { + // 1. 【删除】此次提交移除的商品规格 + // 1.1 此次提交保留的商品属性ID + List retainAttrIds = attrList.stream() + .filter(item -> item.getId() != null) + .map(item -> item.getId()) + .collect(Collectors.toList()); + // 1.2 获取原商品属性ID集合 + List originAttrIds = goodsAttributeService.list(new LambdaQueryWrapper() + .eq(GoodsAttribute::getGoodsId, goodsId).eq(GoodsAttribute::getType, AttributeTypeEnum.ATTR.getValue()) + .select(GoodsAttribute::getId)) + .stream() + .map(GoodsAttribute::getId) + .collect(Collectors.toList()); + // 1.3 需要删除的商品属性:原商品属性-此次提交保留的属性 + List removeAttrValIds = originAttrIds.stream() + .filter(id -> !retainAttrIds.contains(id)) + .collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(removeAttrValIds)) { + goodsStockService.removeByIds(removeAttrValIds); + } + // 新增或修改商品属性 + List entities = attrList.stream().map(item -> { + GoodsAttribute entity = goodsAttributeConverter.form2Entity(item); + entity.setId(item.getId()); + entity.setGoodsId(goodsId); + entity.setType(AttributeTypeEnum.ATTR.getValue()); + return entity; + }).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(entities)) { + return goodsAttributeService.saveOrUpdateBatch(entities); + } + return true; + } + + /** + * 保存商品规格 + *

    + * 新增的规格需要返回临时ID和持久化到数据库的ID的映射关系,替换SKU中的规格ID集合 + * + * @param goodsId 商品ID + * @param specList 规格列表 + * @return Map: key-临时ID;value-持久化返回ID + */ + private Map saveSpuSpecs(String goodsId, List specList) { + // 1. 【删除】此次提交移除的商品规格 + // 1.1 此次提交保留的规格 + List retainSpuSpecIds = specList.stream() + .filter(item -> !item.getId().startsWith(MallConstant.SPEC_TEMP_ID_PREFIX)) + .map(item -> item.getId()) + .collect(Collectors.toList()); + // 1.2 原商品规格 + List originSpuSpecIds = goodsAttributeService.list(new LambdaQueryWrapper() + .eq(GoodsAttribute::getGoodsId, goodsId) + .eq(GoodsAttribute::getType, AttributeTypeEnum.SPEC.getValue()) + .select(GoodsAttribute::getId)) + .stream().map(GoodsAttribute::getId) + .collect(Collectors.toList()); + // 1.3 需要删除的商品规格:原商品规格-此次提交保留的规格 + List removeSpuSpecIds = originSpuSpecIds.stream().filter(id -> !retainSpuSpecIds.contains(id)) + .collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(removeSpuSpecIds)) { + // 删除商品的规格 + goodsAttributeService.removeByIds(removeSpuSpecIds); + } + // 2. 【新增】此次提交的新加的商品规格 + // 临时规格ID和持久化数据库得到的规格ID的映射,用于替换SKU临时的规格ID + Map tempWithNewSpecIdMap = new HashMap<>(); + List newSpecList = specList.stream() + .filter(item -> item.getId().startsWith(MallConstant.SPEC_TEMP_ID_PREFIX)) + .collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(newSpecList)) { + newSpecList.forEach(item -> { + GoodsAttribute entity = goodsAttributeConverter.form2Entity(item); + entity.setGoodsId(goodsId); + entity.setType(AttributeTypeEnum.SPEC.getValue()); + goodsAttributeService.save(entity); + tempWithNewSpecIdMap.put(item.getId(), entity.getId()); + }); + } + // 3. 【修改】此次提交的需要修改的商品规格 + List pmsSpuAttributeList = specList.stream() + .filter(item -> !item.getId().startsWith(MallConstant.SPEC_TEMP_ID_PREFIX)) + .map(item -> { + GoodsAttribute entity = goodsAttributeConverter.form2Entity(item); + entity.setId(item.getId()); + entity.setGoodsId(goodsId); + entity.setType(AttributeTypeEnum.SPEC.getValue()); + return entity; + }).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(pmsSpuAttributeList)) { + goodsAttributeService.updateBatchById(pmsSpuAttributeList); + } + return tempWithNewSpecIdMap; } } diff --git a/hiver-modules/hiver-mall/src/main/resources/mapper/GoodsMapper.xml b/hiver-modules/hiver-mall/src/main/resources/mapper/GoodsMapper.xml index ce03f92a..fc31aa88 100644 --- a/hiver-modules/hiver-mall/src/main/resources/mapper/GoodsMapper.xml +++ b/hiver-modules/hiver-mall/src/main/resources/mapper/GoodsMapper.xml @@ -21,7 +21,7 @@ - + @@ -33,14 +33,15 @@ - + + +