Browse Source

增加商品、商品规格/属性、库存、购物车等接口。

cangku
delicacylee 3 years ago
parent
commit
9bad25475b
  1. 2
      hiver-admin/src/main/resources/application.yml
  2. 16
      hiver-admin/test-output/test-report.html
  3. 10
      hiver-core/src/main/java/cc/hiver/core/common/constant/MallConstant.java
  4. 30
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/common/AttributeTypeEnum.java
  5. 74
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsCartController.java
  6. 24
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/GoodsController.java
  7. 15
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsAttributeConverter.java
  8. 19
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/converter/GoodsConverter.java
  9. 15
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/GoodsMapper.java
  10. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Goods.java
  11. 36
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CartItemDTO.java
  12. 22
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsAttributeForm.java
  13. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/form/GoodsForm.java
  14. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsCategoryVO.java
  15. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsDetailVO.java
  16. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/GoodsPageVO.java
  17. 113
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsDetailVO.java
  18. 32
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/MallGoodsPageVO.java
  19. 21
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/CartService.java
  20. 18
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/GoodsService.java
  21. 135
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/CartServiceImpl.java
  22. 332
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/GoodsServiceImpl.java
  23. 33
      hiver-modules/hiver-mall/src/main/resources/mapper/GoodsMapper.xml

2
hiver-admin/src/main/resources/application.yml

@ -283,6 +283,8 @@ ignored:
- /hiver/iot/sensorHelper/** - /hiver/iot/sensorHelper/**
- /hiver/goview/visual/** - /hiver/goview/visual/**
- /hiver/license/verifyLicense - /hiver/license/verifyLicense
# 临时增加
- /hiver/app/**
# 限流及黑名单不拦截的路径 # 限流及黑名单不拦截的路径
limitUrls: limitUrls:
- /**/*.js - /**/*.js

16
hiver-admin/test-output/test-report.html

@ -35,7 +35,7 @@
<a href="#"><span class="badge badge-primary">Hiver</span></a> <a href="#"><span class="badge badge-primary">Hiver</span></a>
</li> </li>
<li class="m-r-10"> <li class="m-r-10">
<a href="#"><span class="badge badge-primary">七月 31, 2023 09:25:02</span></a> <a href="#"><span class="badge badge-primary">七月 31, 2023 23:25:57</span></a>
</li> </li>
</ul> </ul>
</div> </div>
@ -84,7 +84,7 @@
<div class="test-detail"> <div class="test-detail">
<span class="meta text-white badge badge-sm"></span> <span class="meta text-white badge badge-sm"></span>
<p class="name">passTest</p> <p class="name">passTest</p>
<p class="text-sm"><span>09:25:03 上</span> / <span>0.022 secs</span></p> <p class="text-sm"><span>23:25:57 下</span> / <span>0.01 secs</span></p>
</div> </div>
<div class="test-contents d-none"> <div class="test-contents d-none">
<div class="detail-head"> <div class="detail-head">
@ -92,9 +92,9 @@
<div class="info"> <div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div> <div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5> <h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>07.31.2023 09:25:03</span> <span class='badge badge-success'>07.31.2023 23:25:57</span>
<span class='badge badge-danger'>07.31.2023 09:25:03</span> <span class='badge badge-danger'>07.31.2023 23:25:57</span>
<span class='badge badge-default'>0.022 secs</span> <span class='badge badge-default'>0.01 secs</span>
</div> </div>
<div class="m-t-10 m-l-5"></div> <div class="m-t-10 m-l-5"></div>
</div> </div>
@ -104,7 +104,7 @@
<tbody> <tbody>
<tr class="event-row"> <tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td> <td><span class="badge log pass-bg">Pass</span></td>
<td>9:25:03</td> <td>23:25:57</td>
<td> <td>
Test passed Test passed
</td> </td>
@ -128,13 +128,13 @@
<div class="col-md-3"> <div class="col-md-3">
<div class="card"><div class="card-body"> <div class="card"><div class="card-body">
<p class="m-b-0">Started</p> <p class="m-b-0">Started</p>
<h3>七月 31, 2023 09:25:02</h3> <h3>七月 31, 2023 23:25:57</h3>
</div></div> </div></div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="card"><div class="card-body"> <div class="card"><div class="card-body">
<p class="m-b-0">Ended</p> <p class="m-b-0">Ended</p>
<h3>七月 31, 2023 09:25:03</h3> <h3>七月 31, 2023 23:25:57</h3>
</div></div> </div></div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">

10
hiver-core/src/main/java/cc/hiver/core/common/constant/MallConstant.java

@ -35,4 +35,14 @@ public interface MallConstant {
* 商品分布式锁key前缀 * 商品分布式锁key前缀
*/ */
String SKU_LOCK_PREFIX = "product:stock:lock:"; String SKU_LOCK_PREFIX = "product:stock:lock:";
/**
* 临时规格ID前缀
*/
String SPEC_TEMP_ID_PREFIX = "tid_";
/**
* 会员购物车缓存KEY前缀
*/
String MEMBER_CART_PREFIX = "MEMBER:CART:";
} }

30
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;
}
}

74
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; package cc.hiver.mall.controller;
import cc.hiver.mall.service.SalesOrderItemService; import cc.hiver.core.common.utils.ResultUtil;
import cc.hiver.mall.service.SalesOrderService; 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.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* @author Yazhi Li * @author Yazhi Li
*/ */
@ -34,8 +42,66 @@ import org.springframework.web.bind.annotation.RestController;
@Transactional @Transactional
public class GoodsCartController { public class GoodsCartController {
@Autowired @Autowired
private SalesOrderService salesOrderService; private CartService cartService;
@Autowired @Autowired
private SalesOrderItemService salesOrderItemService; private SecurityUtil securityUtil;
@RequestMapping(value = "/get", method = RequestMethod.GET)
@ApiOperation(value = "查询购物车")
public Result<List<CartItemDTO>> getCart() {
List<CartItemDTO> result = cartService.listCartItems(securityUtil.getCurrUser().getId());
return new ResultUtil<List<CartItemDTO>>().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 <T> Result<T> 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("设置失败");
}
}
} }

24
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.query.GoodsPageQuery;
import cc.hiver.mall.pojo.vo.GoodsDetailVO; import cc.hiver.mall.pojo.vo.GoodsDetailVO;
import cc.hiver.mall.pojo.vo.GoodsPageVO; 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 cc.hiver.mall.service.mybatis.GoodsService;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
@ -25,16 +27,16 @@ public class GoodsController {
@Autowired @Autowired
private GoodsService goodsService; private GoodsService goodsService;
@RequestMapping(value = "/getByCondition", method = RequestMethod.POST) @RequestMapping(value = "/listGoodsPages", method = RequestMethod.POST)
@ApiOperation(value = "商品分页列表") @ApiOperation(value = "商品分页列表")
public Result<IPage<GoodsPageVO>> listPmsSpuPages(GoodsPageQuery queryParams) { public Result<IPage<GoodsPageVO>> listGoodsPages(GoodsPageQuery queryParams) {
IPage<GoodsPageVO> result = goodsService.listGoodsPages(queryParams); IPage<GoodsPageVO> result = goodsService.listGoodsPages(queryParams);
return new ResultUtil<IPage<GoodsPageVO>>().setData(result); return new ResultUtil<IPage<GoodsPageVO>>().setData(result);
} }
@RequestMapping(value = "/get/{id}", method = RequestMethod.GET) @RequestMapping(value = "/getGoodsDetail/{id}", method = RequestMethod.GET)
@ApiOperation(value = "商品详情") @ApiOperation(value = "商品详情")
public Result<GoodsDetailVO> detail(@ApiParam("商品ID") @PathVariable String id) { public Result<GoodsDetailVO> getGoodsDetail(@ApiParam("商品ID") @PathVariable String id) {
GoodsDetailVO goodsDetailVO = goodsService.getGoodsDetail(id); GoodsDetailVO goodsDetailVO = goodsService.getGoodsDetail(id);
return new ResultUtil<GoodsDetailVO>().setData(goodsDetailVO); return new ResultUtil<GoodsDetailVO>().setData(goodsDetailVO);
} }
@ -71,4 +73,18 @@ public class GoodsController {
return ResultUtil.error("删除失败"); return ResultUtil.error("删除失败");
} }
} }
@RequestMapping(value = "/listMallGoodsPages", method = RequestMethod.POST)
@ApiOperation(value = "商品分页列表")
public Result listMallGoodsPages(GoodsPageQuery queryParams) {
IPage<MallGoodsPageVO> result = goodsService.listMallGoodsPages(queryParams);
return new ResultUtil<IPage<MallGoodsPageVO>>().setData(result);
}
@RequestMapping(value = "/getMallGoodsDetail/{id}", method = RequestMethod.GET)
@ApiOperation(value = "获取商品详情")
public Result<MallGoodsDetailVO> getMallGoodsDetail(@ApiParam("商品ID") @PathVariable String id) {
MallGoodsDetailVO mallGoodsDetailVO = goodsService.getMallGoodsDetail(id);
return new ResultUtil<MallGoodsDetailVO>().setData(mallGoodsDetailVO);
}
} }

15
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);
}

19
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);
}

15
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.entity.Goods;
import cc.hiver.mall.pojo.query.GoodsPageQuery; import cc.hiver.mall.pojo.query.GoodsPageQuery;
import cc.hiver.mall.pojo.vo.GoodsPageVO; 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.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -30,11 +32,20 @@ import java.util.List;
@Mapper @Mapper
public interface GoodsMapper extends BaseMapper<Goods> { public interface GoodsMapper extends BaseMapper<Goods> {
/** /**
* 商品分页列表 * 商品分页列表管理用
* *
* @param page * @param page
* @param queryParams * @param queryParams
* @return * @return
*/ */
List<GoodsPageVO> listGoodsPages(Page<GoodsPageVO> page, GoodsPageQuery queryParams); List<GoodsPageVO> listGoodsPages(Page<GoodsPageVO> page, @Param("queryParams") GoodsPageQuery queryParams);
/**
* 商品分页列表商铺用
*
* @param page
* @param queryParams
* @return
*/
List<MallGoodsPageVO> listMallGoodsPages(Page<MallGoodsPageVO> page, @Param("queryParams") GoodsPageQuery queryParams);
} }

2
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; private String videoUrl;
@ApiModelProperty(value = "商品图册") @ApiModelProperty(value = "商品图册")
private String album; private String[] album;
@ApiModelProperty(value = "单位") @ApiModelProperty(value = "单位")
private String unit; private String unit;

36
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;
}

22
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;
}

5
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; package cc.hiver.mall.pojo.form;
import cc.hiver.mall.entity.GoodsAttribute;
import cc.hiver.mall.entity.GoodsStock; import cc.hiver.mall.entity.GoodsStock;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -72,10 +71,10 @@ public class GoodsForm {
private Integer status; private Integer status;
@ApiModelProperty(value = "属性列表") @ApiModelProperty(value = "属性列表")
private List<GoodsAttribute> attrList; private List<GoodsAttributeForm> attrList;
@ApiModelProperty(value = "规格列表") @ApiModelProperty(value = "规格列表")
private List<GoodsAttribute> specList; private List<GoodsAttributeForm> specList;
@ApiModelProperty(value = "库存列表") @ApiModelProperty(value = "库存列表")
private List<GoodsStock> goodsStockList; private List<GoodsStock> goodsStockList;

3
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 io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.persistence.Column;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -35,7 +34,6 @@ public class GoodsCategoryVO {
private String name; private String name;
@ApiModelProperty(value = "父级ID") @ApiModelProperty(value = "父级ID")
@Column(nullable = false)
private String parentId; private String parentId;
@ApiModelProperty(value = "层级") @ApiModelProperty(value = "层级")
@ -45,7 +43,6 @@ public class GoodsCategoryVO {
private String iconUrl; private String iconUrl;
@ApiModelProperty(value = "排序值") @ApiModelProperty(value = "排序值")
@Column(precision = 10, scale = 2)
private BigDecimal sortOrder; private BigDecimal sortOrder;
@ApiModelProperty(value = "是否启用 0启用 -1禁用") @ApiModelProperty(value = "是否启用 0启用 -1禁用")

4
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 io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.persistence.Column;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
@ -44,15 +43,12 @@ public class GoodsDetailVO {
private String brandId; private String brandId;
@ApiModelProperty(value = "采购价") @ApiModelProperty(value = "采购价")
@Column(precision = 10, scale = 2)
private BigDecimal purchasePrice; private BigDecimal purchasePrice;
@ApiModelProperty(value = "市场价") @ApiModelProperty(value = "市场价")
@Column(precision = 10, scale = 2)
private BigDecimal price; private BigDecimal price;
@ApiModelProperty(value = "批发价") @ApiModelProperty(value = "批发价")
@Column(precision = 10, scale = 2)
private BigDecimal wholesalePrice; private BigDecimal wholesalePrice;
@ApiModelProperty(value = "商品主图") @ApiModelProperty(value = "商品主图")

4
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.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.persistence.Column;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
@ -43,15 +42,12 @@ public class GoodsPageVO {
private String brandId; private String brandId;
@ApiModelProperty(value = "采购价") @ApiModelProperty(value = "采购价")
@Column(precision = 10, scale = 2)
private BigDecimal purchasePrice; private BigDecimal purchasePrice;
@ApiModelProperty(value = "市场价") @ApiModelProperty(value = "市场价")
@Column(precision = 10, scale = 2)
private BigDecimal price; private BigDecimal price;
@ApiModelProperty(value = "批发价") @ApiModelProperty(value = "批发价")
@Column(precision = 10, scale = 2)
private BigDecimal wholesalePrice; private BigDecimal wholesalePrice;
@ApiModelProperty(value = "销量") @ApiModelProperty(value = "销量")

113
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<Attribute> attributeList;
@ApiModelProperty("商品规格列表")
private List<Specification> specList;
@ApiModelProperty("商品库存单元列表")
private List<Sku> 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<String> 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<Value> 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;
}
}

32
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;
}

21
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<CartItemDTO> 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);
}

18
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.query.GoodsPageQuery;
import cc.hiver.mall.pojo.vo.GoodsDetailVO; import cc.hiver.mall.pojo.vo.GoodsDetailVO;
import cc.hiver.mall.pojo.vo.GoodsPageVO; 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.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
@ -35,6 +37,14 @@ public interface GoodsService extends IService<Goods> {
*/ */
IPage<GoodsPageVO> listGoodsPages(GoodsPageQuery queryParams); IPage<GoodsPageVO> listGoodsPages(GoodsPageQuery queryParams);
/**
* 商铺端商品分页列表
*
* @param queryParams
* @return
*/
IPage<MallGoodsPageVO> listMallGoodsPages(GoodsPageQuery queryParams);
/** /**
* 管理端获取商品详情 * 管理端获取商品详情
* *
@ -43,6 +53,14 @@ public interface GoodsService extends IService<Goods> {
*/ */
GoodsDetailVO getGoodsDetail(String id); GoodsDetailVO getGoodsDetail(String id);
/**
* 商铺端获取商品详情
*
* @param id
* @return
*/
MallGoodsDetailVO getMallGoodsDetail(String id);
/** /**
* 新增商品 * 新增商品
* *

135
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<CartItemDTO> listCartItems(String memberId) {
if (memberId != null) {
BoundHashOperations cartHashOperations = getCartHashOperations(memberId);
List<CartItemDTO> 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<Void> 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;
}
}

332
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; 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.dao.mapper.GoodsMapper;
import cc.hiver.mall.entity.Goods; 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.form.GoodsForm;
import cc.hiver.mall.pojo.query.GoodsPageQuery; import cc.hiver.mall.pojo.query.GoodsPageQuery;
import cc.hiver.mall.pojo.vo.GoodsDetailVO; import cc.hiver.mall.pojo.vo.GoodsDetailVO;
import cc.hiver.mall.pojo.vo.GoodsPageVO; 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.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.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/** /**
* @author Yazhi Li * @author Yazhi Li
*/ */
@Service @Service
@RequiredArgsConstructor
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService { public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
@Autowired
private GoodsMapper goodsMapper;
@Autowired
private GoodsStockService goodsStockService;
@Autowired
private GoodsAttributeService goodsAttributeService;
@Autowired
private GoodsConverter goodsConverter;
@Autowired
private GoodsAttributeConverter goodsAttributeConverter;
@Override @Override
public IPage<GoodsPageVO> listGoodsPages(GoodsPageQuery queryParams) { public IPage<GoodsPageVO> listGoodsPages(GoodsPageQuery queryParams) {
Page<GoodsPageVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize()); Page<GoodsPageVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
@ -42,23 +78,309 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
return page; return page;
} }
@Override
public IPage<MallGoodsPageVO> listMallGoodsPages(GoodsPageQuery queryParams) {
Page<MallGoodsPageVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
List<MallGoodsPageVO> list = this.baseMapper.listMallGoodsPages(page, queryParams);
page.setRecords(list);
return page;
}
@Override @Override
public GoodsDetailVO getGoodsDetail(String id) { 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<GoodsAttribute> attrList = goodsAttributeService.list(new LambdaQueryWrapper<GoodsAttribute>()
.eq(GoodsAttribute::getId, id)
.eq(GoodsAttribute::getType, AttributeTypeEnum.ATTR.getValue()));
goodsDetailVO.setAttrList(attrList);
// 商品规格列表
List<GoodsAttribute> specList = goodsAttributeService.list(new LambdaQueryWrapper<GoodsAttribute>()
.eq(GoodsAttribute::getId, id)
.eq(GoodsAttribute::getType, AttributeTypeEnum.SPEC.getValue()));
goodsDetailVO.setSpecList(specList);
// 商品库存列表
List<GoodsStock> goodsStockList = goodsStockService.list(new LambdaQueryWrapper<GoodsStock>().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<String> 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<MallGoodsDetailVO.Attribute> attributeList = goodsAttributeService.list(new LambdaQueryWrapper<GoodsAttribute>()
.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<GoodsAttribute> specSourceList = goodsAttributeService.list(new LambdaQueryWrapper<GoodsAttribute>()
.eq(GoodsAttribute::getType, AttributeTypeEnum.SPEC.getValue())
.eq(GoodsAttribute::getGoodsId, id)
.select(GoodsAttribute::getId, GoodsAttribute::getName, GoodsAttribute::getValue));
List<MallGoodsDetailVO.Specification> specList = new ArrayList<>();
// 规格Map [key:"颜色",value:[{id:1,value:"黑"},{id:2,value:"白"}]]
Map<String, List<GoodsAttribute>> specValueMap = specSourceList.stream().collect(Collectors.groupingBy(GoodsAttribute::getName));
for (Map.Entry<String, List<GoodsAttribute>> entry : specValueMap.entrySet()) {
String specName = entry.getKey();
List<GoodsAttribute> specValueSourceList = entry.getValue();
// 规格映射处理
MallGoodsDetailVO.Specification spec = new MallGoodsDetailVO.Specification();
spec.setName(specName);
if (CollectionUtil.isNotEmpty(specValueSourceList)) {
List<MallGoodsDetailVO.Specification.Value> 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<GoodsStock> skuSourceList = goodsStockService.list(new LambdaQueryWrapper<GoodsStock>().eq(GoodsStock::getGoodsId, id));
if (CollectionUtil.isNotEmpty(skuSourceList)) {
List<MallGoodsDetailVO.Sku> 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 @Override
@Transactional
public boolean addGoods(GoodsForm formData) { public boolean addGoods(GoodsForm formData) {
return false; Goods entity = goodsConverter.form2Entity(formData);
boolean result = this.save(entity);
if (result) {
String goodsId = entity.getId();
// 保存属性
List<GoodsAttributeForm> attrList = formData.getAttrList();
this.saveSpuAttrs(goodsId, attrList);
// 保存规格
List<GoodsAttributeForm> specList = formData.getSpecList();
Map<String, String> tempWithNewSpecIdMap = this.saveSpuSpecs(goodsId, specList);
// 保存SKU
List<GoodsStock> skuList = formData.getGoodsStockList();
this.saveSku(goodsId, skuList, tempWithNewSpecIdMap);
}
// 无异常返回true
return result;
} }
@Override @Override
@Transactional
public boolean updateGoods(GoodsForm formData) { public boolean updateGoods(GoodsForm formData) {
return false; Goods entity = goodsConverter.form2Entity(formData);
boolean result = this.updateById(entity);
if (result) {
// 属性保存
List<GoodsAttributeForm> attrList = formData.getAttrList();
this.saveSpuAttrs(entity.getId(), attrList);
// 保存商品规格值
List<GoodsAttributeForm> specList = formData.getSpecList();
Map<String, String> specTempIdIdMap = this.saveSpuSpecs(entity.getId(), specList);
// SKU保存
List<GoodsStock> skuList = formData.getGoodsStockList();
this.saveSku(entity.getId(), skuList, specTempIdIdMap);
}
return result;
} }
@Override @Override
@Transactional
public boolean removeByGoodsIds(String[] ids) { public boolean removeByGoodsIds(String[] ids) {
return false; for (String id : ids) {
goodsStockService.remove(new LambdaQueryWrapper<GoodsStock>().eq(GoodsStock::getGoodsId, id));
// 规格
goodsAttributeService.remove(new LambdaQueryWrapper<GoodsAttribute>().eq(GoodsAttribute::getGoodsId, id));
// 属性
goodsAttributeService.remove(new LambdaQueryWrapper<GoodsAttribute>().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<GoodsStock> skuList, Map<String, String> specTempIdIdMap) {
// 删除SKU
List<String> formSkuIds = skuList.stream().map(GoodsStock::getId).collect(Collectors.toList());
List<String> dbSkuIds = goodsStockService.list(new LambdaQueryWrapper<GoodsStock>().eq(GoodsStock::getGoodsId, goodsId)
.select(GoodsStock::getId)).stream().map(GoodsStock::getId)
.collect(Collectors.toList());
List<String> removeSkuIds = dbSkuIds.stream().filter(dbSkuId -> !formSkuIds.contains(dbSkuId)).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(removeSkuIds)) {
goodsStockService.removeByIds(removeSkuIds);
}
// 新增/修改SKU
List<GoodsStock> 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<GoodsAttributeForm> attrList) {
// 1. 【删除】此次提交移除的商品规格
// 1.1 此次提交保留的商品属性ID
List<String> retainAttrIds = attrList.stream()
.filter(item -> item.getId() != null)
.map(item -> item.getId())
.collect(Collectors.toList());
// 1.2 获取原商品属性ID集合
List<String> originAttrIds = goodsAttributeService.list(new LambdaQueryWrapper<GoodsAttribute>()
.eq(GoodsAttribute::getGoodsId, goodsId).eq(GoodsAttribute::getType, AttributeTypeEnum.ATTR.getValue())
.select(GoodsAttribute::getId))
.stream()
.map(GoodsAttribute::getId)
.collect(Collectors.toList());
// 1.3 需要删除的商品属性:原商品属性-此次提交保留的属性
List<String> removeAttrValIds = originAttrIds.stream()
.filter(id -> !retainAttrIds.contains(id))
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(removeAttrValIds)) {
goodsStockService.removeByIds(removeAttrValIds);
}
// 新增或修改商品属性
List<GoodsAttribute> 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;
}
/**
* 保存商品规格
* <p>
* 新增的规格需要返回临时ID和持久化到数据库的ID的映射关系替换SKU中的规格ID集合
*
* @param goodsId 商品ID
* @param specList 规格列表
* @return Map: key-临时IDvalue-持久化返回ID
*/
private Map<String, String> saveSpuSpecs(String goodsId, List<GoodsAttributeForm> specList) {
// 1. 【删除】此次提交移除的商品规格
// 1.1 此次提交保留的规格
List<String> retainSpuSpecIds = specList.stream()
.filter(item -> !item.getId().startsWith(MallConstant.SPEC_TEMP_ID_PREFIX))
.map(item -> item.getId())
.collect(Collectors.toList());
// 1.2 原商品规格
List<String> originSpuSpecIds = goodsAttributeService.list(new LambdaQueryWrapper<GoodsAttribute>()
.eq(GoodsAttribute::getGoodsId, goodsId)
.eq(GoodsAttribute::getType, AttributeTypeEnum.SPEC.getValue())
.select(GoodsAttribute::getId))
.stream().map(GoodsAttribute::getId)
.collect(Collectors.toList());
// 1.3 需要删除的商品规格:原商品规格-此次提交保留的规格
List<String> removeSpuSpecIds = originSpuSpecIds.stream().filter(id -> !retainSpuSpecIds.contains(id))
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(removeSpuSpecIds)) {
// 删除商品的规格
goodsAttributeService.removeByIds(removeSpuSpecIds);
}
// 2. 【新增】此次提交的新加的商品规格
// 临时规格ID和持久化数据库得到的规格ID的映射,用于替换SKU临时的规格ID
Map<String, String> tempWithNewSpecIdMap = new HashMap<>();
List<GoodsAttributeForm> 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<GoodsAttribute> 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;
} }
} }

33
hiver-modules/hiver-mall/src/main/resources/mapper/GoodsMapper.xml

@ -21,7 +21,7 @@
<result property="status" column="status" jdbcType="TINYINT"/> <result property="status" column="status" jdbcType="TINYINT"/>
<result property="categoryName" column="categoryName" jdbcType="VARCHAR"/> <result property="categoryName" column="categoryName" jdbcType="VARCHAR"/>
<result property="brandName" column="brandName" jdbcType="VARCHAR"/> <result property="brandName" column="brandName" jdbcType="VARCHAR"/>
<collection property="goodsStockList" column="id" select="cc.hiver.mall.dao.mapper.listGoodsByGoodsId"> <collection property="goodsStockList" column="id" select="cc.hiver.mall.dao.mapper.GoodsStockMapper.getStockInfo">
<id property="id" column="id" jdbcType="BIGINT"/> <id property="id" column="id" jdbcType="BIGINT"/>
<result property="name" column="name" jdbcType="VARCHAR"/> <result property="name" column="name" jdbcType="VARCHAR"/>
<result property="sn" column="sn" jdbcType="VARCHAR"/> <result property="sn" column="sn" jdbcType="VARCHAR"/>
@ -33,14 +33,15 @@
</collection> </collection>
</resultMap> </resultMap>
<!--商品分页列表--> <!--管理商品分页列表-->
<select id="listGoodsPages" resultMap="BaseResultMap"> <select id="listGoodsPages" resultMap="BaseResultMap">
SELECT SELECT
t1.id, t1.id,
t1.name, t1.name,
t1.pic_url, t1.pic_url,
t1.origin_price, t1.purchase_price,
t1.price, t1.price,
t1.wholesale_price,
t1.sales, t1.sales,
t1.unit, t1.unit,
t1.detail, t1.detail,
@ -63,4 +64,30 @@
t1.update_time DESC, t1.update_time DESC,
t1.create_time DESC t1.create_time DESC
</select> </select>
<select id="listMallGoodsPages" resultType="cc.hiver.mall.pojo.vo.MallGoodsDetailVO">
SELECT
id,
NAME,
pic_url,
purchase_price,
price,
wholesale_price,
sales
FROM
`t_goods`
<where>
<if test='queryParams.keywords!=null and queryParams.keywords.trim() neq ""'>
AND name like concat('%',#{queryParams.keywords},'%')
</if>
<if test='queryParams.categoryId!=null'>
AND category_id like concat('%',#{queryParams.categoryId},'%')
</if>
</where>
ORDER BY
<if test='queryParams.sortField!=null and queryParams.sortField.trim() neq "" and queryParams.sortField !=null and queryParams.sort.trim() neq ""'>
#{queryParams.sortField} #{queryParams.sort} ,
</if>
create_time desc
</select>
</mapper> </mapper>

Loading…
Cancel
Save