diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/util/StringUtil.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/StringUtil.java new file mode 100644 index 000000000..05292a919 --- /dev/null +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/util/StringUtil.java @@ -0,0 +1,20 @@ +package cn.iocoder.common.framework.util; + +import org.springframework.util.StringUtils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class StringUtil { + + public static String join(Collection coll, String delim) { + return StringUtils.collectionToDelimitedString(coll, delim); + } + + public static List split(String toSplit, String delim) { + String[] stringArray = StringUtils.tokenizeToStringArray(toSplit, delim); + return Arrays.asList(stringArray); + } + +} \ No newline at end of file diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java index e13957856..215ff3771 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductCategoryController.java @@ -8,7 +8,7 @@ import cn.iocoder.mall.product.api.constant.ProductCategoryConstants; import cn.iocoder.mall.product.api.dto.ProductCategoryAddDTO; import cn.iocoder.mall.product.api.dto.ProductCategoryUpdateDTO; import cn.iocoder.mall.product.application.convert.ProductCategoryConvert; -import cn.iocoder.mall.product.application.vo.admins.AdminProductCategoryTreeNodeVO; +import cn.iocoder.mall.product.application.vo.admins.AdminsProductCategoryTreeNodeVO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductCategoryVO; import com.alibaba.dubbo.config.annotation.Reference; import io.swagger.annotations.Api; @@ -33,16 +33,16 @@ public class AdminsProductCategoryController { @GetMapping("/tree") @ApiOperation("获得分类树结构") - public CommonResult> tree() { + public CommonResult> tree() { List productCategories = productCategoryService.getAll().getData(); // 创建 ProductCategoryTreeNodeVO Map - Map treeNodeMap = productCategories.stream().collect(Collectors.toMap(ProductCategoryBO::getId, ProductCategoryConvert.INSTANCE::convert)); + Map treeNodeMap = productCategories.stream().collect(Collectors.toMap(ProductCategoryBO::getId, ProductCategoryConvert.INSTANCE::convert)); // 处理父子关系 treeNodeMap.values().stream() .filter(node -> !node.getPid().equals(ProductCategoryConstants.PID_ROOT)) .forEach((childNode) -> { // 获得父节点 - AdminProductCategoryTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid()); + AdminsProductCategoryTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid()); if (parentNode.getChildren() == null) { // 初始化 children 数组 parentNode.setChildren(new ArrayList<>()); } @@ -50,9 +50,9 @@ public class AdminsProductCategoryController { parentNode.getChildren().add(childNode); }); // 获得到所有的根节点 - List rootNodes = treeNodeMap.values().stream() + List rootNodes = treeNodeMap.values().stream() .filter(node -> node.getPid().equals(ProductCategoryConstants.PID_ROOT)) - .sorted(Comparator.comparing(AdminProductCategoryTreeNodeVO::getSort)) + .sorted(Comparator.comparing(AdminsProductCategoryTreeNodeVO::getSort)) .collect(Collectors.toList()); return CommonResult.success(rootNodes); } diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java index 4308f0698..a6eba1d27 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/controller/admins/AdminsProductSpuController.java @@ -15,6 +15,8 @@ import com.alibaba.dubbo.config.annotation.Reference; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -35,6 +37,16 @@ public class AdminsProductSpuController { @PostMapping("/spu/add") @ApiOperation("创建商品") + @ApiImplicitParams({ + @ApiImplicitParam(name = "name", value = "SPU 名字", required = true, example = "厮大牛逼"), + @ApiImplicitParam(name = "sellPoint", value = "卖点", required = true, example = "各种 MQ 骚操作"), + @ApiImplicitParam(name = "description", value = "描述", required = true, example = "你就说强不强 MQ 骚操作"), + @ApiImplicitParam(name = "cid", value = "分类编号", required = true, example = "反正我是信了"), + @ApiImplicitParam(name = "picUrls", value = "商品主图地址的数组", required = true, example = "http://www.iocoder.cn"), + @ApiImplicitParam(name = "visible", value = "是否上架商品(是否可见)", required = true, example = "true"), + @ApiImplicitParam(name = "skuStr", value = "SKU 字符串", required = true, example = "[{\"attrs\": [1,3 ], \"price\": 1, \"quantity\": 100, \"picUrl\": \"http://www.iocoder.cn\"}]"), + + }) public CommonResult add(@RequestParam("name") String name, @RequestParam("sellPoint") String sellPoint, @RequestParam("description") String description, @@ -54,6 +66,17 @@ public class AdminsProductSpuController { @PostMapping("/spu/update") @ApiOperation("更新商品") + @ApiImplicitParams({ + @ApiImplicitParam(name = "id", value = "SPU 编号", required = true, example = "100"), + @ApiImplicitParam(name = "name", value = "SPU 名字", required = true, example = "厮大牛逼"), + @ApiImplicitParam(name = "sellPoint", value = "卖点", required = true, example = "各种 MQ 骚操作"), + @ApiImplicitParam(name = "description", value = "描述", required = true, example = "你就说强不强 MQ 骚操作"), + @ApiImplicitParam(name = "cid", value = "分类编号", required = true, example = "反正我是信了"), + @ApiImplicitParam(name = "picUrls", value = "商品主图地址的数组", required = true, example = "http://www.iocoder.cn"), + @ApiImplicitParam(name = "visible", value = "是否上架商品(是否可见)", required = true, example = "true"), + @ApiImplicitParam(name = "skuStr", value = "SKU 字符串", required = true, example = "[{\"attrs\": [1,3 ], \"price\": 1, \"quantity\": 100, \"picUrl\": \"http://www.iocoder.cn\"}]"), + + }) public CommonResult update(@RequestParam("id") Integer id, @RequestParam("name") String name, @RequestParam("sellPoint") String sellPoint, diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductCategoryConvert.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductCategoryConvert.java index f0602a9f9..31be87556 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductCategoryConvert.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/convert/ProductCategoryConvert.java @@ -3,7 +3,7 @@ package cn.iocoder.mall.product.application.convert; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.product.api.bo.ProductCategoryBO; import cn.iocoder.mall.product.application.vo.users.UsersProductCategoryVO; -import cn.iocoder.mall.product.application.vo.admins.AdminProductCategoryTreeNodeVO; +import cn.iocoder.mall.product.application.vo.admins.AdminsProductCategoryTreeNodeVO; import cn.iocoder.mall.product.application.vo.admins.AdminsProductCategoryVO; import org.mapstruct.Mapper; import org.mapstruct.Mappings; @@ -21,7 +21,7 @@ public interface ProductCategoryConvert { List convertToVO(List categoryList); - AdminProductCategoryTreeNodeVO convert(ProductCategoryBO category); + AdminsProductCategoryTreeNodeVO convert(ProductCategoryBO category); CommonResult convert(CommonResult result); diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductAttrDetailVO.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductAttrDetailVO.java new file mode 100644 index 000000000..5d4a0b9be --- /dev/null +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductAttrDetailVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.mall.product.application.vo.admins; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "商品规格 VO") +public class AdminsProductAttrDetailVO { + + @ApiModelProperty(value = "规格编号", required = true, example = "1") + private Integer attrId; + @ApiModelProperty(value = "规格名", required = true, example = "颜色") + private String attrName; + @ApiModelProperty(value = "规格值", required = true, example = "10") + private Integer attrValueId; + @ApiModelProperty(value = "规格值名", required = true, example = "红色") + private String attrValueName; + + public Integer getAttrId() { + return attrId; + } + + public AdminsProductAttrDetailVO setAttrId(Integer attrId) { + this.attrId = attrId; + return this; + } + + public String getAttrName() { + return attrName; + } + + public AdminsProductAttrDetailVO setAttrName(String attrName) { + this.attrName = attrName; + return this; + } + + public Integer getAttrValueId() { + return attrValueId; + } + + public AdminsProductAttrDetailVO setAttrValueId(Integer attrValueId) { + this.attrValueId = attrValueId; + return this; + } + + public String getAttrValueName() { + return attrValueName; + } + + public AdminsProductAttrDetailVO setAttrValueName(String attrValueName) { + this.attrValueName = attrValueName; + return this; + } + +} \ No newline at end of file diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminProductCategoryTreeNodeVO.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductCategoryTreeNodeVO.java similarity index 73% rename from product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminProductCategoryTreeNodeVO.java rename to product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductCategoryTreeNodeVO.java index 15807ae1f..526db8268 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminProductCategoryTreeNodeVO.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductCategoryTreeNodeVO.java @@ -7,7 +7,7 @@ import java.util.Date; import java.util.List; @ApiModel("产品分类树节点 VO") -public class AdminProductCategoryTreeNodeVO { +public class AdminsProductCategoryTreeNodeVO { @ApiModelProperty(value = "分类编号", required = true, example = "1") private Integer id; @@ -26,13 +26,13 @@ public class AdminProductCategoryTreeNodeVO { @ApiModelProperty(value = "创建时间", required = true, example = "时间戳") private Date createTime; @ApiModelProperty(value = "子节点数组") - private List children; + private List children; public Integer getId() { return id; } - public AdminProductCategoryTreeNodeVO setId(Integer id) { + public AdminsProductCategoryTreeNodeVO setId(Integer id) { this.id = id; return this; } @@ -41,7 +41,7 @@ public class AdminProductCategoryTreeNodeVO { return pid; } - public AdminProductCategoryTreeNodeVO setPid(Integer pid) { + public AdminsProductCategoryTreeNodeVO setPid(Integer pid) { this.pid = pid; return this; } @@ -50,7 +50,7 @@ public class AdminProductCategoryTreeNodeVO { return name; } - public AdminProductCategoryTreeNodeVO setName(String name) { + public AdminsProductCategoryTreeNodeVO setName(String name) { this.name = name; return this; } @@ -59,7 +59,7 @@ public class AdminProductCategoryTreeNodeVO { return description; } - public AdminProductCategoryTreeNodeVO setDescription(String description) { + public AdminsProductCategoryTreeNodeVO setDescription(String description) { this.description = description; return this; } @@ -68,7 +68,7 @@ public class AdminProductCategoryTreeNodeVO { return picUrl; } - public AdminProductCategoryTreeNodeVO setPicUrl(String picUrl) { + public AdminsProductCategoryTreeNodeVO setPicUrl(String picUrl) { this.picUrl = picUrl; return this; } @@ -77,7 +77,7 @@ public class AdminProductCategoryTreeNodeVO { return sort; } - public AdminProductCategoryTreeNodeVO setSort(Integer sort) { + public AdminsProductCategoryTreeNodeVO setSort(Integer sort) { this.sort = sort; return this; } @@ -86,7 +86,7 @@ public class AdminProductCategoryTreeNodeVO { return status; } - public AdminProductCategoryTreeNodeVO setStatus(Integer status) { + public AdminsProductCategoryTreeNodeVO setStatus(Integer status) { this.status = status; return this; } @@ -95,16 +95,16 @@ public class AdminProductCategoryTreeNodeVO { return createTime; } - public AdminProductCategoryTreeNodeVO setCreateTime(Date createTime) { + public AdminsProductCategoryTreeNodeVO setCreateTime(Date createTime) { this.createTime = createTime; return this; } - public List getChildren() { + public List getChildren() { return children; } - public AdminProductCategoryTreeNodeVO setChildren(List children) { + public AdminsProductCategoryTreeNodeVO setChildren(List children) { this.children = children; return this; } diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductSkuDetailVO.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductSkuDetailVO.java new file mode 100644 index 000000000..46348fecb --- /dev/null +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductSkuDetailVO.java @@ -0,0 +1,80 @@ +package cn.iocoder.mall.product.application.vo.admins; + +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +/** + * 商品 Sku 明细 BO + */ +public class AdminsProductSkuDetailVO { + + @ApiModelProperty(value = "sku 编号", required = true, example = "1") + private Integer id; + @ApiModelProperty(value = "SPU 编号", required = true, example = "1") + private Integer spuId; + @ApiModelProperty(value = "图片地址", required = true, example = "http://www.iocoder.cn") + private String picURL; + @ApiModelProperty(value = "规格值数组", required = true) + private List attrs; + @ApiModelProperty(value = "价格,单位:分", required = true, example = "100") + private Integer price; + @ApiModelProperty(value = "库存数量", required = true, example = "100") + private Integer quantity; + + + public Integer getId() { + return id; + } + + public AdminsProductSkuDetailVO setId(Integer id) { + this.id = id; + return this; + } + + public Integer getSpuId() { + return spuId; + } + + public AdminsProductSkuDetailVO setSpuId(Integer spuId) { + this.spuId = spuId; + return this; + } + + public String getPicURL() { + return picURL; + } + + public AdminsProductSkuDetailVO setPicURL(String picURL) { + this.picURL = picURL; + return this; + } + + public Integer getPrice() { + return price; + } + + public AdminsProductSkuDetailVO setPrice(Integer price) { + this.price = price; + return this; + } + + public Integer getQuantity() { + return quantity; + } + + public AdminsProductSkuDetailVO setQuantity(Integer quantity) { + this.quantity = quantity; + return this; + } + + public List getAttrs() { + return attrs; + } + + public AdminsProductSkuDetailVO setAttrs(List attrs) { + this.attrs = attrs; + return this; + } + +} \ No newline at end of file diff --git a/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductSpuDetailVO.java b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductSpuDetailVO.java index aebbbcc23..2b5d0d5d5 100644 --- a/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductSpuDetailVO.java +++ b/product/product-application/src/main/java/cn/iocoder/mall/product/application/vo/admins/AdminsProductSpuDetailVO.java @@ -1,10 +1,120 @@ package cn.iocoder.mall.product.application.vo.admins; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; @ApiModel(value = "商品 SPU 详细 VO", description = "包括 SKU 信息 VO") public class AdminsProductSpuDetailVO { + @ApiModelProperty(value = "SPU 编号", required = true, example = "1") + private Integer id; + // ========== 基本信息 ========= + @ApiModelProperty(value = "SPU 名字", required = true, example = "厮大牛逼") + private String name; + @ApiModelProperty(value = "卖点", required = true, example = "各种 MQ 骚操作") + private String sellPoint; + @ApiModelProperty(value = "描述", required = true, example = "你就说强不强") + private String description; + @ApiModelProperty(value = "分类编号", required = true, example = "反正我是信了") + private Integer cid; + @ApiModelProperty(value = "商品主图地址的数组", required = true, example = "http://www.iocoder.cn") + private List picUrls; -} + // ========== 其他信息 ========= + @ApiModelProperty(value = "是否上架商品(是否可见)", required = true, example = "true") + private Boolean visible; + @ApiModelProperty(value = "排序字段", required = true, example = "10") + private Integer sort; + + // ========== SKU ========= + + /** + * SKU 数组 + */ + private List skus; + + public Integer getId() { + return id; + } + + public AdminsProductSpuDetailVO setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public AdminsProductSpuDetailVO setName(String name) { + this.name = name; + return this; + } + + public String getSellPoint() { + return sellPoint; + } + + public AdminsProductSpuDetailVO setSellPoint(String sellPoint) { + this.sellPoint = sellPoint; + return this; + } + + public String getDescription() { + return description; + } + + public AdminsProductSpuDetailVO setDescription(String description) { + this.description = description; + return this; + } + + public Integer getCid() { + return cid; + } + + public AdminsProductSpuDetailVO setCid(Integer cid) { + this.cid = cid; + return this; + } + + public List getPicUrls() { + return picUrls; + } + + public AdminsProductSpuDetailVO setPicUrls(List picUrls) { + this.picUrls = picUrls; + return this; + } + + public Boolean getVisible() { + return visible; + } + + public AdminsProductSpuDetailVO setVisible(Boolean visible) { + this.visible = visible; + return this; + } + + public Integer getSort() { + return sort; + } + + public AdminsProductSpuDetailVO setSort(Integer sort) { + this.sort = sort; + return this; + } + + public List getSkus() { + return skus; + } + + public AdminsProductSpuDetailVO setSkus(List skus) { + this.skus = skus; + return this; + } + +} \ No newline at end of file diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrBO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrDetailBO.java similarity index 72% rename from product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrBO.java rename to product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrDetailBO.java index 766c44006..0ba4506de 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrBO.java +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductAttrDetailBO.java @@ -1,9 +1,9 @@ package cn.iocoder.mall.product.api.bo; /** - * 商品规格 BO + * 商品规格明细 BO */ -public class ProductAttrBO { +public class ProductAttrDetailBO { /** * 规格编号 @@ -26,7 +26,7 @@ public class ProductAttrBO { return attrId; } - public ProductAttrBO setAttrId(Integer attrId) { + public ProductAttrDetailBO setAttrId(Integer attrId) { this.attrId = attrId; return this; } @@ -35,7 +35,7 @@ public class ProductAttrBO { return attrName; } - public ProductAttrBO setAttrName(String attrName) { + public ProductAttrDetailBO setAttrName(String attrName) { this.attrName = attrName; return this; } @@ -44,7 +44,7 @@ public class ProductAttrBO { return attrValueId; } - public ProductAttrBO setAttrValueId(Integer attrValueId) { + public ProductAttrDetailBO setAttrValueId(Integer attrValueId) { this.attrValueId = attrValueId; return this; } @@ -53,7 +53,7 @@ public class ProductAttrBO { return attrValueName; } - public ProductAttrBO setAttrValueName(String attrValueName) { + public ProductAttrDetailBO setAttrValueName(String attrValueName) { this.attrValueName = attrValueName; return this; } diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSkuDetailBO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSkuDetailBO.java index 806320c2c..67fe8eaa0 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSkuDetailBO.java +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSkuDetailBO.java @@ -14,17 +14,7 @@ public class ProductSkuDetailBO { /** * 商品编号 */ - private Integer itemId; - - // TODO 店铺编号 - - /** - * 状态 - * - * 1-正常 - * 2-禁用 - */ - private Integer status; + private Integer spuId; /** * 图片地址 */ @@ -32,7 +22,7 @@ public class ProductSkuDetailBO { /** * 规格值数组 */ - private List attrs; + private List attrs; /** * 价格,单位:分 */ @@ -42,4 +32,59 @@ public class ProductSkuDetailBO { */ private Integer quantity; + + public Integer getId() { + return id; + } + + public ProductSkuDetailBO setId(Integer id) { + this.id = id; + return this; + } + + public Integer getSpuId() { + return spuId; + } + + public ProductSkuDetailBO setSpuId(Integer spuId) { + this.spuId = spuId; + return this; + } + + public String getPicURL() { + return picURL; + } + + public ProductSkuDetailBO setPicURL(String picURL) { + this.picURL = picURL; + return this; + } + + public List getAttrs() { + return attrs; + } + + public ProductSkuDetailBO setAttrs(List attrs) { + this.attrs = attrs; + return this; + } + + public Integer getPrice() { + return price; + } + + public ProductSkuDetailBO setPrice(Integer price) { + this.price = price; + return this; + } + + public Integer getQuantity() { + return quantity; + } + + public ProductSkuDetailBO setQuantity(Integer quantity) { + this.quantity = quantity; + return this; + } + } \ No newline at end of file diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuDetailBO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuDetailBO.java index 22631318d..0b068aad3 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuDetailBO.java +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/bo/ProductSpuDetailBO.java @@ -1,7 +1,5 @@ package cn.iocoder.mall.product.api.bo; -import cn.iocoder.mall.product.api.dto.ProductSkuAddDTO; - import java.util.List; /** @@ -51,15 +49,94 @@ public class ProductSpuDetailBO { /** * 排序字段 */ - private Integer order; - - // + private Integer sort; // ========== SKU ========= /** * SKU 数组 */ - private List skus; + private List skus; + + public Integer getId() { + return id; + } + + public ProductSpuDetailBO setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public ProductSpuDetailBO setName(String name) { + this.name = name; + return this; + } + + public String getSellPoint() { + return sellPoint; + } + + public ProductSpuDetailBO setSellPoint(String sellPoint) { + this.sellPoint = sellPoint; + return this; + } + + public String getDescription() { + return description; + } + + public ProductSpuDetailBO setDescription(String description) { + this.description = description; + return this; + } + + public Integer getCid() { + return cid; + } + + public ProductSpuDetailBO setCid(Integer cid) { + this.cid = cid; + return this; + } + + public List getPicUrls() { + return picUrls; + } + + public ProductSpuDetailBO setPicUrls(List picUrls) { + this.picUrls = picUrls; + return this; + } + + public Boolean getVisible() { + return visible; + } + + public ProductSpuDetailBO setVisible(Boolean visible) { + this.visible = visible; + return this; + } + + public Integer getSort() { + return sort; + } + + public ProductSpuDetailBO setSort(Integer sort) { + this.sort = sort; + return this; + } + + public List getSkus() { + return skus; + } + + public ProductSpuDetailBO setSkus(List skus) { + this.skus = skus; + return this; + } } \ No newline at end of file diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductAttrConstants.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductAttrConstants.java new file mode 100644 index 000000000..d454b800a --- /dev/null +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductAttrConstants.java @@ -0,0 +1,23 @@ +package cn.iocoder.mall.product.api.constant; + +public class ProductAttrConstants { + + /** + * ATTR 状态 - 开启 + */ + public static final Integer ATTR_STATUS_ENABLE = 1; + /** + * ATTR 状态 - 关闭 + */ + public static final Integer ATTR_STATUS_DISABLE = 2; + + /** + * ATTR_VALUE 状态 - 开启 + */ + public static final Integer ATTR_VALUE_STATUS_ENABLE = 1; + /** + * ATTR_VALUE 状态 - 关闭 + */ + public static final Integer ATTR_VALUE_STATUS_DISABLE = 2; + +} diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductErrorCodeEnum.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductErrorCodeEnum.java index cf84493dc..4808658a3 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductErrorCodeEnum.java +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductErrorCodeEnum.java @@ -11,8 +11,20 @@ public enum ProductErrorCodeEnum { PRODUCT_CATEGORY_PARENT_NOT_EXISTS(1003001000, "父分类不存在"), PRODUCT_CATEGORY_NOT_EXISTS(1003001001, "商品分类不存在"), PRODUCT_CATEGORY_PARENT_NOT_SELF(1003001002, "不能设置自己为父分类"), - PRODUCT_CATEGORY_STATUS_EQUALS(1002002003, "商品分类已经是该状态"), - PRODUCT_CATEGORY_DELETE_ONLY_DISABLE(1002002004, "只有关闭的商品分类才可以删除"), + PRODUCT_CATEGORY_STATUS_EQUALS(1002001003, "商品分类已经是该状态"), + PRODUCT_CATEGORY_DELETE_ONLY_DISABLE(1002001004, "只有关闭的商品分类才可以删除"), + PRODUCT_CATEGORY_MUST_ENABLE(1002001005, "只有开启的商品分类,才可以使用"), + + // ========== PRODUCT SPU + SKU 模块 ========== + PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE(1003002000, "一个 Sku 下,不能有重复的规格"), + PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS(1003002001, "一个 Spu 下的每个 Sku ,其规格数必须一致"), + PRODUCT_SPU_SKU__NOT_DUPLICATE(1003002002, "一个 Spu 下的每个 Sku ,必须不重复"), + + + // ========== PRODUCT ATTR + ATTR_VALUE 模块 ========== + PRODUCT_ATTR_VALUE_NOT_EXIST(1003003000, "商品属性值不存在"), + + PRODUCT_ATTR_NOT_EXIST(1003003001, "商品属性值不存在"), ; diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductSpuConstants.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductSpuConstants.java new file mode 100644 index 000000000..686157097 --- /dev/null +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/constant/ProductSpuConstants.java @@ -0,0 +1,14 @@ +package cn.iocoder.mall.product.api.constant; + +public class ProductSpuConstants { + + /** + * 状态 - 开启 + */ + public static final Integer SKU_STATUS_ENABLE = 1; + /** + * 状态 - 关闭 + */ + public static final Integer SKU_STATUS_DISABLE = 2; + +} diff --git a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java index a2e25fc22..948c60a02 100644 --- a/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java +++ b/product/product-service-api/src/main/java/cn/iocoder/mall/product/api/dto/ProductSpuAddDTO.java @@ -28,7 +28,7 @@ public class ProductSpuAddDTO { /** * 分类编号 */ - @NotEmpty(message = "分类不能为空") + @NotNull(message = "分类不能为空") private Integer cid; /** * 商品主图地址 diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/convert/ProductSpuConvert.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/convert/ProductSpuConvert.java index 4390597b2..a016b3444 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/convert/ProductSpuConvert.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/convert/ProductSpuConvert.java @@ -1,11 +1,26 @@ package cn.iocoder.mall.product.convert; +import cn.iocoder.common.framework.util.StringUtil; +import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO; +import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO; import cn.iocoder.mall.product.api.bo.ProductSpuBO; +import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO; +import cn.iocoder.mall.product.api.dto.ProductSkuAddDTO; +import cn.iocoder.mall.product.api.dto.ProductSkuUpdateDTO; +import cn.iocoder.mall.product.api.dto.ProductSpuAddDTO; +import cn.iocoder.mall.product.api.dto.ProductSpuUpdateDTO; +import cn.iocoder.mall.product.dataobject.ProductSkuDO; import cn.iocoder.mall.product.dataobject.ProductSpuDO; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + @Mapper public interface ProductSpuConvert { @@ -14,4 +29,60 @@ public interface ProductSpuConvert { @Mappings({}) ProductSpuBO convert(ProductSpuDO spu); + @Mappings({ + @Mapping(source = "picUrls", target = "picUrls", ignore = true) + }) + ProductSpuDO convert(ProductSpuAddDTO productSpuAddDTO); + + @Mappings({ + @Mapping(source = "attrs", target = "attrs", ignore = true) + }) + ProductSkuDO convert(ProductSkuAddDTO productSkuAddDTO); + + + @Mappings({ + @Mapping(source = "picUrls", target = "picUrls", ignore = true) + }) + ProductSpuDO convert(ProductSpuUpdateDTO productSpuUpdateDTO); + + @Mappings({ + @Mapping(source = "attrs", target = "attrs", ignore = true) + }) + ProductSkuDO convert(ProductSkuUpdateDTO productSkuUpdateDTO); + + @Mappings({}) + ProductSpuDetailBO convert(ProductSpuBO spu); + + @Mappings({ + @Mapping(source = "picUrls", target = "picUrls", ignore = true) + }) + ProductSpuDetailBO convert2(ProductSpuDO spu); + + @Mappings({ + @Mapping(source = "attrs", target = "attrs", ignore = true) + }) + ProductSkuDetailBO convert2(ProductSkuDO sku); + + @Mappings({}) + default ProductSpuDetailBO convert2(ProductSpuDO spu, List skus, List productAttrDetailBOs) { + // 创建并转换 ProductSpuDetailBO 对象 + ProductSpuDetailBO spuDetail = this.convert2(spu).setPicUrls(StringUtil.split(spu.getPicUrls(), ",")); + // 创建 ProductAttrDetailBO 的映射。其中,KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号 + Map productAttrDetailBOMap = productAttrDetailBOs.stream().collect( + Collectors.toMap(ProductAttrDetailBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO)); + // 创建并转换 ProductSpuDetailBO 数组 + spuDetail.setSkus(new ArrayList<>()); + skus.forEach(sku -> { + // 创建 ProductSpuDetailBO 对象 + ProductSkuDetailBO skuDetail = ProductSpuConvert.this.convert2(sku) + .setAttrs(new ArrayList<>()); + spuDetail.getSkus().add(skuDetail); + // 设置 ProductSpuDetailBO 的 attrs 规格属性 + List attrs = StringUtil.split(sku.getAttrs(), ","); + attrs.forEach(attr -> skuDetail.getAttrs().add(productAttrDetailBOMap.get(Integer.valueOf(attr)))); + }); + // 返回 + return spuDetail; + } + } \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductAttrMapper.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductAttrMapper.java new file mode 100644 index 000000000..a89830fca --- /dev/null +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductAttrMapper.java @@ -0,0 +1,17 @@ +package cn.iocoder.mall.product.dao; + +import cn.iocoder.mall.product.dataobject.ProductAttrDO; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; + +@Repository +public interface ProductAttrMapper { + + ProductAttrDO selectById(@Param("id") Integer id); + + List selectListByIds(@Param("ids") Collection ids); + +} \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductAttrValueMapper.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductAttrValueMapper.java new file mode 100644 index 000000000..f73a37fa3 --- /dev/null +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductAttrValueMapper.java @@ -0,0 +1,17 @@ +package cn.iocoder.mall.product.dao; + +import cn.iocoder.mall.product.dataobject.ProductAttrValueDO; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; + +@Repository +public interface ProductAttrValueMapper { + + ProductAttrValueDO selectById(@Param("id") Integer id); + + List selectListByIds(@Param("ids") Collection ids); + +} \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSkuMapper.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSkuMapper.java new file mode 100644 index 000000000..936161507 --- /dev/null +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSkuMapper.java @@ -0,0 +1,16 @@ +package cn.iocoder.mall.product.dao; + +import cn.iocoder.mall.product.dataobject.ProductSkuDO; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ProductSkuMapper { + + ProductSkuDO selectById(Integer id); + + void insertList(@Param("productSkuDOs") List productSkuDOs); + +} \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java index a7a814868..b5c5d02dd 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dao/ProductSpuMapper.java @@ -8,4 +8,8 @@ public interface ProductSpuMapper { ProductSpuDO selectById(Integer id); + void insert(ProductSpuDO productSpuDO); + + void update(ProductSpuDO productSpuDO); + } \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrDO.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrDO.java index 450e8e075..b5007912b 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrDO.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrDO.java @@ -1,11 +1,11 @@ package cn.iocoder.mall.product.dataobject; -import java.util.Date; +import cn.iocoder.common.framework.dataobject.BaseDO; /** * Product 规格 */ -public class ProductAttrDO { +public class ProductAttrDO extends BaseDO { /** * 规格编号 @@ -15,20 +15,39 @@ public class ProductAttrDO { * 名称 */ private String name; - /** - * 创建时间 - */ - private Date createTime; - /** - * 最后更新时间 - */ - private Date updateTime; /** * 状态 * - * 1-正常 - * 2-删除 + * 1-开启 + * 2-禁用 */ private Integer status; + public Integer getId() { + return id; + } + + public ProductAttrDO setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public ProductAttrDO setName(String name) { + this.name = name; + return this; + } + + public Integer getStatus() { + return status; + } + + public ProductAttrDO setStatus(Integer status) { + this.status = status; + return this; + } + } \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrValueDO.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrValueDO.java index 9ebdb6672..a9a2576c7 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrValueDO.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductAttrValueDO.java @@ -1,11 +1,11 @@ package cn.iocoder.mall.product.dataobject; -import java.util.Date; +import cn.iocoder.common.framework.dataobject.BaseDO; /** * Product 规格值 */ -public class ProductAttrValueDO { +public class ProductAttrValueDO extends BaseDO { /** * 规格值编号 @@ -19,20 +19,48 @@ public class ProductAttrValueDO { * 规格值 */ private String name; - /** - * 创建时间 - */ - private Date createTime; - /** - * 最后更新时间 - */ - private Date updateTime; /** * 状态 * * 1-正常 - * 2-删除 + * 2-禁用 */ private Integer status; + public Integer getId() { + return id; + } + + public ProductAttrValueDO setId(Integer id) { + this.id = id; + return this; + } + + public Integer getAttrId() { + return attrId; + } + + public ProductAttrValueDO setAttrId(Integer attrId) { + this.attrId = attrId; + return this; + } + + public String getName() { + return name; + } + + public ProductAttrValueDO setName(String name) { + this.name = name; + return this; + } + + public Integer getStatus() { + return status; + } + + public ProductAttrValueDO setStatus(Integer status) { + this.status = status; + return this; + } + } \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductCategoryDO.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductCategoryDO.java index 1152ab5e2..65c022816 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductCategoryDO.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductCategoryDO.java @@ -7,9 +7,6 @@ import cn.iocoder.common.framework.dataobject.BaseDO; */ public class ProductCategoryDO extends BaseDO { - @Deprecated - public static final Integer STATUS_ENABLE = 1; - /** * 分类编号 */ diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSkuDO.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSkuDO.java index a3f3b4f09..6ee66af63 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSkuDO.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSkuDO.java @@ -14,7 +14,7 @@ public class ProductSkuDO extends BaseDO { /** * 商品编号 */ - private Integer itemId; + private Integer spuId; // TODO 店铺编号 @@ -28,7 +28,7 @@ public class ProductSkuDO extends BaseDO { /** * 图片地址 */ - private String picURL; + private String picUrl; /** * 规格值({@link ProductAttrDO})数组 * @@ -52,4 +52,68 @@ public class ProductSkuDO extends BaseDO { // */ // private Integer soldNum; + + public Integer getId() { + return id; + } + + public ProductSkuDO setId(Integer id) { + this.id = id; + return this; + } + + public Integer getSpuId() { + return spuId; + } + + public ProductSkuDO setSpuId(Integer spuId) { + this.spuId = spuId; + return this; + } + + public Integer getStatus() { + return status; + } + + public ProductSkuDO setStatus(Integer status) { + this.status = status; + return this; + } + + public String getPicUrl() { + return picUrl; + } + + public ProductSkuDO setPicUrl(String picUrl) { + this.picUrl = picUrl; + return this; + } + + public String getAttrs() { + return attrs; + } + + public ProductSkuDO setAttrs(String attrs) { + this.attrs = attrs; + return this; + } + + public Integer getPrice() { + return price; + } + + public ProductSkuDO setPrice(Integer price) { + this.price = price; + return this; + } + + public Integer getQuantity() { + return quantity; + } + + public ProductSkuDO setQuantity(Integer quantity) { + this.quantity = quantity; + return this; + } + } \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSpuDO.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSpuDO.java index 621baaf59..e64d9949f 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSpuDO.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/dataobject/ProductSpuDO.java @@ -55,7 +55,7 @@ public class ProductSpuDO extends BaseDO { /** * 排序字段 */ - private Integer order; + private Integer sort; public Integer getId() { return id; @@ -119,12 +119,15 @@ public class ProductSpuDO extends BaseDO { return this; } - public Integer getOrder() { - return order; + public Integer getSort() { + return sort; } - public ProductSpuDO setOrder(Integer order) { - this.order = order; + public ProductSpuDO setSort(Integer sort) { + this.sort = sort; return this; } + + + } \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java new file mode 100644 index 000000000..b823845b8 --- /dev/null +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductAttrServiceImpl.java @@ -0,0 +1,64 @@ +package cn.iocoder.mall.product.service; + +import cn.iocoder.common.framework.util.ServiceExceptionUtil; +import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO; +import cn.iocoder.mall.product.api.constant.ProductAttrConstants; +import cn.iocoder.mall.product.api.constant.ProductErrorCodeEnum; +import cn.iocoder.mall.product.dao.ProductAttrMapper; +import cn.iocoder.mall.product.dao.ProductAttrValueMapper; +import cn.iocoder.mall.product.dataobject.ProductAttrDO; +import cn.iocoder.mall.product.dataobject.ProductAttrValueDO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 商品规格 Service 实现类 + * + * @see cn.iocoder.mall.product.dataobject.ProductAttrDO + * @see cn.iocoder.mall.product.dataobject.ProductAttrValueDO + */ +@Service +public class ProductAttrServiceImpl { + + @Autowired + private ProductAttrMapper productAttrMapper; + @Autowired + private ProductAttrValueMapper productValueMapper; + + public CommonResult> validProductAttrAndValue(Set productAttrValueIds) { + // 首先,校验规格值 + List attrValues = productValueMapper.selectListByIds(productAttrValueIds); + if (attrValues.size() != productAttrValueIds.size()) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode()); + } + for (ProductAttrValueDO attrValue : attrValues) { // 同时,校验下状态 + if (ProductAttrConstants.ATTR_STATUS_DISABLE.equals(attrValue.getStatus())) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode()); + } + } + // 然后,校验规格 + Set attrIds = attrValues.stream().map(ProductAttrValueDO::getAttrId).collect(Collectors.toSet()); + List attrs = productAttrMapper.selectListByIds(attrIds); + if (attrs.size() != attrIds.size()) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode()); + } + for (ProductAttrDO attr : attrs) { // 同时,校验下状态 + if (ProductAttrConstants.ATTR_VALUE_STATUS_DISABLE.equals(attr.getStatus())) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode()); + } + } + // 返回成功 + Map attrMap = attrs.stream().collect(Collectors.toMap(ProductAttrDO::getId, productAttrDO -> productAttrDO)); // ProductAttrDO 的映射,方便查找。 + List result = attrValues.stream().map(productAttrValueDO -> new ProductAttrDetailBO() + .setAttrId(productAttrValueDO.getAttrId()).setAttrName(attrMap.get(productAttrValueDO.getAttrId()).getName()) + .setAttrValueId(productAttrValueDO.getId()).setAttrValueName(productAttrValueDO.getName())).collect(Collectors.toList()); + return CommonResult.success(result); + } + +} \ No newline at end of file diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java index cebdae3f0..02019e8ef 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductCategoryServiceImpl.java @@ -28,7 +28,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService { @Override public List getListByPid(Integer pid) { - List categoryList = productCategoryMapper.selectListByPidAndStatusOrderBySort(pid, ProductCategoryDO.STATUS_ENABLE); + List categoryList = productCategoryMapper.selectListByPidAndStatusOrderBySort(pid, ProductCategoryConstants.STATUS_ENABLE); return ProductCategoryConvert.INSTANCE.convertToBO(categoryList); } @@ -111,6 +111,7 @@ public class ProductCategoryServiceImpl implements ProductCategoryService { return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_CATEGORY_DELETE_ONLY_DISABLE.getCode()); } // TODO 芋艿:考虑下,是否需要判断下该分类下是否有商品 + // TODO 芋艿,需要补充下,还有子分类 // 标记删除商品分类 ProductCategoryDO updateProductCategory = new ProductCategoryDO().setId(productCategoryId); updateProductCategory.setDeleted(BaseDO.DELETED_YES); @@ -119,6 +120,20 @@ public class ProductCategoryServiceImpl implements ProductCategoryService { return CommonResult.success(true); } + public CommonResult validProductCategory(Integer productCategoryId) { + // 校验分类是否存在 + ProductCategoryDO productCategory = productCategoryMapper.selectById(productCategoryId); + if (productCategory == null) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_CATEGORY_NOT_EXISTS.getCode()); + } + // 只有禁用的商品分类才可以删除 + if (ProductCategoryConstants.STATUS_DISABLE.equals(productCategory.getStatus())) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_CATEGORY_MUST_ENABLE.getCode()); + } + // 返回结果 + return CommonResult.success(productCategory); + } + private boolean isValidStatus(Integer status) { return ProductCategoryConstants.STATUS_ENABLE.equals(status) || ProductCategoryConstants.STATUS_DISABLE.equals(status); diff --git a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java index 21ec281a3..1892f8a04 100644 --- a/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java +++ b/product/product-service-impl/src/main/java/cn/iocoder/mall/product/service/ProductSpuServiceImpl.java @@ -1,39 +1,143 @@ package cn.iocoder.mall.product.service; +import cn.iocoder.common.framework.dataobject.BaseDO; +import cn.iocoder.common.framework.util.ServiceExceptionUtil; +import cn.iocoder.common.framework.util.StringUtil; import cn.iocoder.common.framework.vo.CommonResult; import cn.iocoder.mall.product.api.ProductSpuService; +import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO; import cn.iocoder.mall.product.api.bo.ProductSpuBO; import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO; +import cn.iocoder.mall.product.api.constant.ProductErrorCodeEnum; +import cn.iocoder.mall.product.api.constant.ProductSpuConstants; +import cn.iocoder.mall.product.api.dto.ProductSkuAddDTO; import cn.iocoder.mall.product.api.dto.ProductSpuAddDTO; import cn.iocoder.mall.product.api.dto.ProductSpuUpdateDTO; import cn.iocoder.mall.product.convert.ProductSpuConvert; +import cn.iocoder.mall.product.dao.ProductSkuMapper; import cn.iocoder.mall.product.dao.ProductSpuMapper; +import cn.iocoder.mall.product.dataobject.ProductCategoryDO; +import cn.iocoder.mall.product.dataobject.ProductSkuDO; import cn.iocoder.mall.product.dataobject.ProductSpuDO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; @Service // 实际上不用添加。添加的原因是,必须 Spring 报错提示 -@com.alibaba.dubbo.config.annotation.Service +@com.alibaba.dubbo.config.annotation.Service(validation = "true") public class ProductSpuServiceImpl implements ProductSpuService { @Autowired - private ProductSpuMapper productSpuDAO; + private ProductSpuMapper productSpuMapper; + @Autowired + private ProductSkuMapper productSkuMapper; + + @Autowired + private ProductCategoryServiceImpl productCategoryService; + @Autowired + private ProductAttrServiceImpl productAttrService; @Override public ProductSpuBO getProductSpu(Integer id) { - ProductSpuDO productSpuDO = productSpuDAO.selectById(id); + ProductSpuDO productSpuDO = productSpuMapper.selectById(id); // 转换成 BO return ProductSpuConvert.INSTANCE.convert(productSpuDO); } + @SuppressWarnings("Duplicates") @Override + @Transactional public CommonResult addProductSpu(Integer adminId, ProductSpuAddDTO productSpuAddDTO) { - return null; + // 校验商品分类分类存在 + CommonResult validCategoryResult = productCategoryService.validProductCategory(productSpuAddDTO.getCid()); + if (validCategoryResult.isError()) { + return CommonResult.error(validCategoryResult); + } + // 校验规格是否存在 + Set productAttrValueIds = new HashSet<>(); + productSpuAddDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs())); + CommonResult> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds); + if (validAttrResult.isError()) { + return CommonResult.error(validAttrResult); + } + // 保存 Spu + ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(productSpuAddDTO) + .setPicUrls(StringUtil.join(productSpuAddDTO.getPicUrls(), ",")) + .setSort(0); // 排序为 0 + spu.setCreateTime(new Date()).setDeleted(BaseDO.DELETED_NO); + productSpuMapper.insert(spu); + // 保存 Sku + List skus = productSpuAddDTO.getSkus().stream().map(productSkuAddDTO -> { + ProductSkuDO sku = ProductSpuConvert.INSTANCE.convert(productSkuAddDTO) + .setSpuId(spu.getId()) + .setStatus(ProductSpuConstants.SKU_STATUS_ENABLE) + .setAttrs(StringUtil.join(productSkuAddDTO.getAttrs(), ",")); + sku.setCreateTime(new Date()).setDeleted(BaseDO.DELETED_NO); + return sku; + }).collect(Collectors.toList()); + // 校验 Sku 规格 + CommonResult validProductSkuResult = validProductSku(productSpuAddDTO.getSkus(), validAttrResult.getData()); + if (validProductSkuResult.isError()) { + return CommonResult.error(validProductSkuResult); + } + productSkuMapper.insertList(skus); + // 返回成功 + return CommonResult.success(ProductSpuConvert.INSTANCE.convert2(spu, skus, validAttrResult.getData())); } + @SuppressWarnings("Duplicates") @Override public CommonResult updateProductSpu(Integer adminId, ProductSpuUpdateDTO productSpuUpdateDTO) { - return null; + // 校验商品分类分类存在 + CommonResult validCategoryResult = productCategoryService.validProductCategory(productSpuUpdateDTO.getCid()); + if (validCategoryResult.isError()) { + return CommonResult.error(validCategoryResult); + } + // 校验规格是否存在 + Set productAttrValueIds = new HashSet<>(); + productSpuUpdateDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs())); + CommonResult> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds); + if (validAttrResult.isError()) { + return CommonResult.error(validAttrResult); + } + // 更新 Spu + ProductSpuDO updateSpu = ProductSpuConvert.INSTANCE.convert(productSpuUpdateDTO) + .setPicUrls(StringUtil.join(productSpuUpdateDTO.getPicUrls(), ",")); + productSpuMapper.update(updateSpu); + // 校验 Sku 规格 + return CommonResult.success(true); + } + + private CommonResult validProductSku(List productSkuAddDTOs, List productAttrDetailBOs) { + // 创建 ProductAttrDetailBO 的映射。其中,KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号 + Map productAttrDetailBOMap = productAttrDetailBOs.stream().collect( + Collectors.toMap(ProductAttrDetailBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO)); + // 1. 先校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId + for (ProductSkuAddDTO sku : productSkuAddDTOs) { + Set attrIds = sku.getAttrs().stream().map(attrValueId -> productAttrDetailBOMap.get(attrValueId).getAttrId()).collect(Collectors.toSet()); + if (attrIds.size() != sku.getAttrs().size()) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE.getCode()); + } + } + // 2. 再校验,每个 Sku 的规格值的数量,是一致的。 + int attrSize = productSkuAddDTOs.get(0).getAttrs().size(); + for (int i = 1; i < productSkuAddDTOs.size(); i++) { + if (attrSize != productSkuAddDTOs.get(i).getAttrs().size()) { + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS.getCode()); + } + } + // 3. 最后校验,每个 Sku 之间不是重复的 + Set> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的. + for (ProductSkuAddDTO sku : productSkuAddDTOs) { + if (!skuAttrValues.add(new HashSet<>(sku.getAttrs()))) { // 添加失败,说明重复 + return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_SPU_SKU__NOT_DUPLICATE.getCode()); + } + } + // 校验通过 + return CommonResult.success(true); } } \ No newline at end of file diff --git a/product/product-service-impl/src/main/resources/mapper/ProductAttrMapper.xml b/product/product-service-impl/src/main/resources/mapper/ProductAttrMapper.xml new file mode 100644 index 000000000..0116915c0 --- /dev/null +++ b/product/product-service-impl/src/main/resources/mapper/ProductAttrMapper.xml @@ -0,0 +1,73 @@ + + + + + + id, name, status, create_time + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/product/product-service-impl/src/main/resources/mapper/ProductAttrValueMapper.xml b/product/product-service-impl/src/main/resources/mapper/ProductAttrValueMapper.xml new file mode 100644 index 000000000..4063869cc --- /dev/null +++ b/product/product-service-impl/src/main/resources/mapper/ProductAttrValueMapper.xml @@ -0,0 +1,73 @@ + + + + + + id, attr_id, name, status, create_time + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/product/product-service-impl/src/main/resources/mapper/ProductSkuMapper.xml b/product/product-service-impl/src/main/resources/mapper/ProductSkuMapper.xml index f3c090623..983835d57 100644 --- a/product/product-service-impl/src/main/resources/mapper/ProductSkuMapper.xml +++ b/product/product-service-impl/src/main/resources/mapper/ProductSkuMapper.xml @@ -1,12 +1,24 @@ - + - SELECT id - FROM product_spu + FROM product_sku WHERE id = #{id} + + INSERT INTO product_sku ( + spu_id, status, pic_url, attrs, price, + quantity, deleted, create_time + ) VALUES + + (#{productSkuDO.spuId}, #{productSkuDO.status}, #{productSkuDO.picUrl}, #{productSkuDO.attrs}, #{productSkuDO.price}, + #{productSkuDO.quantity}, #{productSkuDO.deleted}, #{productSkuDO.createTime} + ) + + + \ No newline at end of file diff --git a/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml b/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml new file mode 100644 index 000000000..bc2e16f5e --- /dev/null +++ b/product/product-service-impl/src/main/resources/mapper/ProductSpuMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + INSERT INTO product_spu ( + name, sell_point, description, cid, pic_urls, + visible, sort, deleted, create_time + ) VALUES ( + #{name}, #{sellPoint}, #{description}, #{cid}, #{picUrls}, + #{visible}, #{sort}, #{deleted}, #{createTime} + ) + + + + + + + \ No newline at end of file