Merge remote-tracking branch 'origin/master'

This commit is contained in:
sin 2019-03-06 22:04:24 +08:00
commit 22cc477bf9
34 changed files with 1023 additions and 82 deletions

View File

@ -113,7 +113,7 @@ public class AdminController {
@ApiImplicitParam(name = "id", value = "管理员编号", required = true, example = "1"),
@ApiImplicitParam(name = "username", value = "账号", required = true, example = "15601691300"),
@ApiImplicitParam(name = "nickname", value = "昵称", required = true, example = "小王"),
@ApiImplicitParam(name = "password", value = "密码", required = true, example = "buzhidao"),
@ApiImplicitParam(name = "password", value = "密码", example = "buzhidao"),
})
public CommonResult<Boolean> update(@RequestParam("id") Integer id,
@RequestParam("username") String username,

View File

@ -6,15 +6,19 @@ import cn.iocoder.mall.admin.api.bo.DataDictBO;
import cn.iocoder.mall.admin.api.dto.DataDictAddDTO;
import cn.iocoder.mall.admin.api.dto.DataDictUpdateDTO;
import cn.iocoder.mall.admin.application.convert.DataDictConvert;
import cn.iocoder.mall.admin.application.vo.DataDictEnumVO;
import cn.iocoder.mall.admin.application.vo.DataDictVO;
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
import com.alibaba.dubbo.config.annotation.Reference;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@ -32,6 +36,26 @@ public class DataDictController {
return DataDictConvert.INSTANCE.convert(result);
}
@GetMapping("/tree")
@ApiOperation(value = "数据字典树结构", notes = "该接口返回的信息更为精简。一般用于前端缓存数据字典到本地。")
public CommonResult<List<DataDictEnumVO>> tree() {
// 查询数据字典全列表
CommonResult<List<DataDictBO>> result = dataDictService.selectDataDictList();
if (result.isError()) {
return CommonResult.error(result);
}
// 构建基于 enumValue 聚合的 Multimap
ImmutableListMultimap<String, DataDictBO> dataDictMap = Multimaps.index(result.getData(), DataDictBO::getEnumValue); // KEY enumValue VALUE DataDictBO 数组
// 构建返回结果
List<DataDictEnumVO> dataDictEnumVOs = new ArrayList<>(dataDictMap.size());
dataDictMap.keys().forEach(enumValue -> {
DataDictEnumVO dataDictEnumVO = new DataDictEnumVO().setEnumValue(enumValue)
.setValues(DataDictConvert.INSTANCE.convert2(dataDictMap.get(enumValue)));
dataDictEnumVOs.add(dataDictEnumVO);
});
return CommonResult.success(dataDictEnumVOs);
}
@PostMapping("/add")
@ApiOperation(value = "创建数据字典")
@ApiImplicitParams({

View File

@ -3,6 +3,7 @@ package cn.iocoder.mall.admin.application.convert;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.admin.api.bo.DataDictBO;
import cn.iocoder.mall.admin.application.vo.DataDictVO;
import cn.iocoder.mall.admin.application.vo.DataDictValueVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@ -26,4 +27,7 @@ public interface DataDictConvert {
@Mappings({})
CommonResult<DataDictVO> convert2(CommonResult<DataDictBO> result);
@Mappings({})
List<DataDictValueVO> convert2(List<DataDictBO> dataDictBOs);
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.mall.admin.application.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel("数据字典枚举 VO")
public class DataDictEnumVO {
@ApiModelProperty(value = "大类枚举值", required = true, example = "gender")
private String enumValue;
@ApiModelProperty(value = "小类数值数组", required = true)
private List<DataDictValueVO> values;
public String getEnumValue() {
return enumValue;
}
public DataDictEnumVO setEnumValue(String enumValue) {
this.enumValue = enumValue;
return this;
}
public List<DataDictValueVO> getValues() {
return values;
}
public DataDictEnumVO setValues(List<DataDictValueVO> values) {
this.values = values;
return this;
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.mall.admin.application.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel("数据字典枚举值 VO")
public class DataDictValueVO {
@ApiModelProperty(value = "小类数值", required = true, example = "1")
private String value;
@ApiModelProperty(value = "展示名", required = true, example = "")
private String displayName;
public String getValue() {
return value;
}
public DataDictValueVO setValue(String value) {
this.value = value;
return this;
}
public String getDisplayName() {
return displayName;
}
public DataDictValueVO setDisplayName(String displayName) {
this.displayName = displayName;
return this;
}
}

View File

@ -0,0 +1,74 @@
package cn.iocoder.mall.product.application.controller.admins;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.product.api.ProductAttrService;
import cn.iocoder.mall.product.api.bo.ProductAttrPageBO;
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
import cn.iocoder.mall.product.api.dto.ProductAttrPageDTO;
import cn.iocoder.mall.product.application.convert.ProductAttrConvert;
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrPageVO;
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrSimpleVO;
import com.alibaba.dubbo.config.annotation.Reference;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("admins")
@Api("商品规格")
public class AdminsProductAttrController {
@Reference(validation = "true")
private ProductAttrService productAttrService;
@GetMapping("/attr/page")
public CommonResult<AdminsProductAttrPageVO> attrPage(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
// 创建 ProductAttrPageDTO 对象
ProductAttrPageDTO productAttrPageDTO = new ProductAttrPageDTO().setName(name).setPageNo(pageNo).setPageSize(pageSize);
// 查询分页
CommonResult<ProductAttrPageBO> result = productAttrService.getProductAttrPage(productAttrPageDTO);
// 返回结果
return ProductAttrConvert.INSTANCE.convert2(result);
}
@GetMapping("/attr/tree")
public CommonResult<List<AdminsProductAttrSimpleVO>> tree() {
// 查询全列表
CommonResult<List<ProductAttrSimpleBO>> result = productAttrService.getProductAttrList();
// 返回结果
return ProductAttrConvert.INSTANCE.convert(result);
}
@PostMapping("/attr/add")
public CommonResult addAttr() {
return null;
}
public CommonResult<Boolean> updateAttr() {
return null;
}
public CommonResult<Boolean> updateAttrStatus() {
return null;
}
// TODO 芋艿 暂时不考虑 delete Attr 因为关联逻辑比较多
public CommonResult addAttrValue() {
return null;
}
public CommonResult<Boolean> updateAttrValue() {
return null;
}
public CommonResult<Boolean> updateAttrValueStr() {
return null;
}
// TODO 芋艿 暂时不考虑 delete Attr Value 因为关联逻辑比较多
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.mall.product.application.convert;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.product.api.bo.ProductAttrPageBO;
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrPageVO;
import cn.iocoder.mall.product.application.vo.admins.AdminsProductAttrSimpleVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface ProductAttrConvert {
ProductAttrConvert INSTANCE = Mappers.getMapper(ProductAttrConvert.class);
@Mappings({})
CommonResult<AdminsProductAttrPageVO> convert2(CommonResult<ProductAttrPageBO> result);
@Mappings({})
CommonResult<List<AdminsProductAttrSimpleVO>> convert(CommonResult<List<ProductAttrSimpleBO>> result);
}

View File

@ -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 AdminsProductAttrAndValuePairVO {
@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 AdminsProductAttrAndValuePairVO setAttrId(Integer attrId) {
this.attrId = attrId;
return this;
}
public String getAttrName() {
return attrName;
}
public AdminsProductAttrAndValuePairVO setAttrName(String attrName) {
this.attrName = attrName;
return this;
}
public Integer getAttrValueId() {
return attrValueId;
}
public AdminsProductAttrAndValuePairVO setAttrValueId(Integer attrValueId) {
this.attrValueId = attrValueId;
return this;
}
public String getAttrValueName() {
return attrValueName;
}
public AdminsProductAttrAndValuePairVO setAttrValueName(String attrValueName) {
this.attrValueName = attrValueName;
return this;
}
}

View File

@ -3,51 +3,65 @@ package cn.iocoder.mall.product.application.vo.admins;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "商品规格 VO")
import java.util.Date;
import java.util.List;
@ApiModel(value = "商品规格明细 VO", description = "带有规格值数组")
public class AdminsProductAttrDetailVO {
@ApiModelProperty(value = "规格编号", required = true, example = "1")
private Integer attrId;
private Integer id;
@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;
private String name;
@ApiModelProperty(value = "状态", required = true, example = "1")
private Integer status;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳")
private Date createTime;
@ApiModelProperty(value = "规格值数组", required = true)
private List<AdminsProductAttrValueDetailVO> values;
public Integer getAttrId() {
return attrId;
public Integer getId() {
return id;
}
public AdminsProductAttrDetailVO setAttrId(Integer attrId) {
this.attrId = attrId;
public AdminsProductAttrDetailVO setId(Integer id) {
this.id = id;
return this;
}
public String getAttrName() {
return attrName;
public String getName() {
return name;
}
public AdminsProductAttrDetailVO setAttrName(String attrName) {
this.attrName = attrName;
public AdminsProductAttrDetailVO setName(String name) {
this.name = name;
return this;
}
public Integer getAttrValueId() {
return attrValueId;
public Integer getStatus() {
return status;
}
public AdminsProductAttrDetailVO setAttrValueId(Integer attrValueId) {
this.attrValueId = attrValueId;
public AdminsProductAttrDetailVO setStatus(Integer status) {
this.status = status;
return this;
}
public String getAttrValueName() {
return attrValueName;
public Date getCreateTime() {
return createTime;
}
public AdminsProductAttrDetailVO setAttrValueName(String attrValueName) {
this.attrValueName = attrValueName;
public AdminsProductAttrDetailVO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
public List<AdminsProductAttrValueDetailVO> getValues() {
return values;
}
public AdminsProductAttrDetailVO setValues(List<AdminsProductAttrValueDetailVO> values) {
this.values = values;
return this;
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.mall.product.application.vo.admins;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "商品规格明细分页 VO")
public class AdminsProductAttrPageVO {
@ApiModelProperty(value = "规格数组", required = true)
private List<AdminsProductAttrDetailVO> attrs;
@ApiModelProperty(value = "总数", required = true)
private Integer count;
public List<AdminsProductAttrDetailVO> getAttrs() {
return attrs;
}
public AdminsProductAttrPageVO setAttrs(List<AdminsProductAttrDetailVO> attrs) {
this.attrs = attrs;
return this;
}
public Integer getCount() {
return count;
}
public AdminsProductAttrPageVO setCount(Integer count) {
this.count = count;
return this;
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.mall.product.application.vo.admins;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "商品规格精简 VO", description = "带有规格值数组")
public class AdminsProductAttrSimpleVO {
@ApiModelProperty(value = "规格编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "规格名", required = true, example = "颜色")
private String name;
@ApiModelProperty(value = "规格值数组", required = true)
private List<AdminsProductAttrValueSimpleVO> values;
public Integer getId() {
return id;
}
public AdminsProductAttrSimpleVO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public AdminsProductAttrSimpleVO setName(String name) {
this.name = name;
return this;
}
public List<AdminsProductAttrValueSimpleVO> getValues() {
return values;
}
public AdminsProductAttrSimpleVO setValues(List<AdminsProductAttrValueSimpleVO> values) {
this.values = values;
return this;
}
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.mall.product.application.vo.admins;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
@ApiModel(value = "商品规格 VO", description = "不带有规格值数组")
public class AdminsProductAttrVO {
@ApiModelProperty(value = "规格编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "规格名", required = true, example = "颜色")
private String name;
@ApiModelProperty(value = "状态", required = true, example = "1")
private Integer status;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳")
private Date createTime;
}

View File

@ -0,0 +1,56 @@
package cn.iocoder.mall.product.application.vo.admins;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
@ApiModel(value = "商品规格值 VO")
public class AdminsProductAttrValueDetailVO {
@ApiModelProperty(value = "规格值编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "规格值名", required = true, example = "颜色")
private String name;
@ApiModelProperty(value = "状态", required = true, example = "1")
private Integer status;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳")
private Date createTime;
public Integer getId() {
return id;
}
public AdminsProductAttrValueDetailVO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public AdminsProductAttrValueDetailVO setName(String name) {
this.name = name;
return this;
}
public Integer getStatus() {
return status;
}
public AdminsProductAttrValueDetailVO setStatus(Integer status) {
this.status = status;
return this;
}
public Date getCreateTime() {
return createTime;
}
public AdminsProductAttrValueDetailVO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.mall.product.application.vo.admins;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "商品规格值精简 VO")
public class AdminsProductAttrValueSimpleVO {
@ApiModelProperty(value = "规格值编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "规格值名", required = true, example = "颜色")
private String name;
public Integer getId() {
return id;
}
public AdminsProductAttrValueSimpleVO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public AdminsProductAttrValueSimpleVO setName(String name) {
this.name = name;
return this;
}
}

View File

@ -16,7 +16,7 @@ public class AdminsProductSkuDetailVO {
@ApiModelProperty(value = "图片地址", required = true, example = "http://www.iocoder.cn")
private String picURL;
@ApiModelProperty(value = "规格值数组", required = true)
private List<AdminsProductAttrDetailVO> attrs;
private List<AdminsProductAttrAndValuePairVO> attrs;
@ApiModelProperty(value = "价格,单位:分", required = true, example = "100")
private Integer price;
@ApiModelProperty(value = "库存数量", required = true, example = "100")
@ -68,11 +68,11 @@ public class AdminsProductSkuDetailVO {
return this;
}
public List<AdminsProductAttrDetailVO> getAttrs() {
public List<AdminsProductAttrAndValuePairVO> getAttrs() {
return attrs;
}
public AdminsProductSkuDetailVO setAttrs(List<AdminsProductAttrDetailVO> attrs) {
public AdminsProductSkuDetailVO setAttrs(List<AdminsProductAttrAndValuePairVO> attrs) {
this.attrs = attrs;
return this;
}

View File

@ -1,19 +1,16 @@
package cn.iocoder.mall.product.application.vo.admins;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel("商品 SPU 分页 VO")
public class AdminsProductSpuPageVO {
/**
* spu 数组
*/
@ApiModelProperty(value = "spu 数组", required = true)
private List<AdminsProductSpuVO> spus;
/**
* 总数
*/
@ApiModelProperty(value = "总数", required = true)
private Integer count;
public List<AdminsProductSpuVO> getSpus() {

View File

@ -0,0 +1,23 @@
package cn.iocoder.mall.product.api;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.product.api.bo.ProductAttrPageBO;
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
import cn.iocoder.mall.product.api.dto.ProductAttrPageDTO;
import java.util.List;
public interface ProductAttrService {
CommonResult<ProductAttrPageBO> getProductAttrPage(ProductAttrPageDTO productAttrPageDTO);
/**
* 获得规格属性数组
*
* 注意该方法过滤了禁用的规格
*
* @return 规格属性数组
*/
CommonResult<List<ProductAttrSimpleBO>> getProductAttrList();
}

View File

@ -0,0 +1,61 @@
package cn.iocoder.mall.product.api.bo;
/**
* 商品规格明细 BO
*/
public class ProductAttrAndValuePairBO {
/**
* 规格编号
*/
private Integer attrId;
/**
* 规格名
*/
private String attrName;
/**
* 规格值
*/
private Integer attrValueId;
/**
* 规格值名
*/
private String attrValueName;
public Integer getAttrId() {
return attrId;
}
public ProductAttrAndValuePairBO setAttrId(Integer attrId) {
this.attrId = attrId;
return this;
}
public String getAttrName() {
return attrName;
}
public ProductAttrAndValuePairBO setAttrName(String attrName) {
this.attrName = attrName;
return this;
}
public Integer getAttrValueId() {
return attrValueId;
}
public ProductAttrAndValuePairBO setAttrValueId(Integer attrValueId) {
this.attrValueId = attrValueId;
return this;
}
public String getAttrValueName() {
return attrValueName;
}
public ProductAttrAndValuePairBO setAttrValueName(String attrValueName) {
this.attrValueName = attrValueName;
return this;
}
}

View File

@ -1,61 +1,76 @@
package cn.iocoder.mall.product.api.bo;
import java.util.Date;
import java.util.List;
/**
* 商品规格明细 BO
* 商品规格明细 VO
*/
public class ProductAttrDetailBO {
/**
* 规格编号
*/
private Integer attrId;
private Integer id;
/**
* 规格名
*/
private String attrName;
private String name;
/**
* 规格值
* 状态
*/
private Integer attrValueId;
private Integer status;
/**
* 规格值名
* 创建时间
*/
private String attrValueName;
private Date createTime;
/**
* 规格值数组
*/
private List<ProductAttrValueDetailBO> values;
public Integer getAttrId() {
return attrId;
public Integer getId() {
return id;
}
public ProductAttrDetailBO setAttrId(Integer attrId) {
this.attrId = attrId;
public ProductAttrDetailBO setId(Integer id) {
this.id = id;
return this;
}
public String getAttrName() {
return attrName;
public String getName() {
return name;
}
public ProductAttrDetailBO setAttrName(String attrName) {
this.attrName = attrName;
public ProductAttrDetailBO setName(String name) {
this.name = name;
return this;
}
public Integer getAttrValueId() {
return attrValueId;
public Integer getStatus() {
return status;
}
public ProductAttrDetailBO setAttrValueId(Integer attrValueId) {
this.attrValueId = attrValueId;
public ProductAttrDetailBO setStatus(Integer status) {
this.status = status;
return this;
}
public String getAttrValueName() {
return attrValueName;
public Date getCreateTime() {
return createTime;
}
public ProductAttrDetailBO setAttrValueName(String attrValueName) {
this.attrValueName = attrValueName;
public ProductAttrDetailBO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
public List<ProductAttrValueDetailBO> getValues() {
return values;
}
public ProductAttrDetailBO setValues(List<ProductAttrValueDetailBO> values) {
this.values = values;
return this;
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.mall.product.api.bo;
import java.util.List;
/**
* 商品规格明细分页 BO
*/
public class ProductAttrPageBO {
/**
* 规格数组
*/
private List<ProductAttrDetailBO> attrs;
/**
* 总数
*/
private Integer count;
public List<ProductAttrDetailBO> getAttrs() {
return attrs;
}
public ProductAttrPageBO setAttrs(List<ProductAttrDetailBO> attrs) {
this.attrs = attrs;
return this;
}
public Integer getCount() {
return count;
}
public ProductAttrPageBO setCount(Integer count) {
this.count = count;
return this;
}
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.mall.product.api.bo;
import java.util.List;
/**
* 商品规格精简 VO
*/
public class ProductAttrSimpleBO {
/**
* 规格编号
*/
private Integer id;
/**
* 规格名
*/
private String name;
/**
* 规格值数组
*/
private List<ProductAttrValueSimpleBO> values;
public Integer getId() {
return id;
}
public ProductAttrSimpleBO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public ProductAttrSimpleBO setName(String name) {
this.name = name;
return this;
}
public List<ProductAttrValueSimpleBO> getValues() {
return values;
}
public ProductAttrSimpleBO setValues(List<ProductAttrValueSimpleBO> values) {
this.values = values;
return this;
}
}

View File

@ -0,0 +1,62 @@
package cn.iocoder.mall.product.api.bo;
import java.util.Date;
/**
* 商品规格值 VO
*/
public class ProductAttrValueDetailBO {
/**
* 规格值编号
*/
private Integer id;
/**
* 规格值名
*/
private String name;
/**
* 状态
*/
private Integer status;
/**
* 创建时间
*/
private Date createTime;
public Integer getId() {
return id;
}
public ProductAttrValueDetailBO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public ProductAttrValueDetailBO setName(String name) {
this.name = name;
return this;
}
public Integer getStatus() {
return status;
}
public ProductAttrValueDetailBO setStatus(Integer status) {
this.status = status;
return this;
}
public Date getCreateTime() {
return createTime;
}
public ProductAttrValueDetailBO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.mall.product.api.bo;
/**
* 商品规格值 VO
*/
public class ProductAttrValueSimpleBO {
/**
* 规格值编号
*/
private Integer id;
/**
* 规格值名
*/
private String name;
public Integer getId() {
return id;
}
public ProductAttrValueSimpleBO setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public ProductAttrValueSimpleBO setName(String name) {
this.name = name;
return this;
}
}

View File

@ -22,7 +22,7 @@ public class ProductSkuDetailBO {
/**
* 规格值数组
*/
private List<ProductAttrDetailBO> attrs;
private List<ProductAttrAndValuePairBO> attrs;
/**
* 价格单位
*/
@ -60,11 +60,11 @@ public class ProductSkuDetailBO {
return this;
}
public List<ProductAttrDetailBO> getAttrs() {
public List<ProductAttrAndValuePairBO> getAttrs() {
return attrs;
}
public ProductSkuDetailBO setAttrs(List<ProductAttrDetailBO> attrs) {
public ProductSkuDetailBO setAttrs(List<ProductAttrAndValuePairBO> attrs) {
this.attrs = attrs;
return this;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.mall.product.api.dto;
import javax.validation.constraints.NotNull;
/**
* 商品规格分页 DTO
*/
public class ProductAttrPageDTO {
private String name;
@NotNull(message = "页码不能为空")
private Integer pageNo;
@NotNull(message = "每页条数不能为空")
private Integer pageSize;
public String getName() {
return name;
}
public ProductAttrPageDTO setName(String name) {
this.name = name;
return this;
}
public Integer getPageNo() {
return pageNo;
}
public ProductAttrPageDTO setPageNo(Integer pageNo) {
this.pageNo = pageNo;
return this;
}
public Integer getPageSize() {
return pageSize;
}
public ProductAttrPageDTO setPageSize(Integer pageSize) {
this.pageSize = pageSize;
return this;
}
}

View File

@ -2,6 +2,9 @@ package cn.iocoder.mall.product.api.dto;
import javax.validation.constraints.NotNull;
/**
* 商品 Spu 分页 DTO
*/
public class ProductSpuPageDTO {
private String name;

View File

@ -0,0 +1,38 @@
package cn.iocoder.mall.product.convert;
import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
import cn.iocoder.mall.product.api.bo.ProductAttrValueDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrValueSimpleBO;
import cn.iocoder.mall.product.dataobject.ProductAttrDO;
import cn.iocoder.mall.product.dataobject.ProductAttrValueDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface ProductAttrConvert {
ProductAttrConvert INSTANCE = Mappers.getMapper(ProductAttrConvert.class);
@Mappings({})
List<ProductAttrDetailBO> convert(List<ProductAttrDO> attrs);
@Mappings({})
ProductAttrValueDetailBO convert(ProductAttrValueDO value);
@Mappings({})
List<ProductAttrValueDetailBO> convert2(List<ProductAttrValueDO> values);
@Mappings({})
List<ProductAttrSimpleBO> convert3(List<ProductAttrDO> attrs);
// @Mappings({})
// ProductAttrValueSimpleBO convert3(ProductAttrValueDO value);
//
@Mappings({})
List<ProductAttrValueSimpleBO> convert4(List<ProductAttrValueDO> values);
}

View File

@ -1,7 +1,7 @@
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.ProductAttrAndValuePairBO;
import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO;
import cn.iocoder.mall.product.api.bo.ProductSpuBO;
import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO;
@ -63,13 +63,13 @@ public interface ProductSpuConvert {
})
ProductSkuDetailBO convert2(ProductSkuDO sku);
@Mappings({})
default ProductSpuDetailBO convert2(ProductSpuDO spu, List<ProductSkuDO> skus, List<ProductAttrDetailBO> productAttrDetailBOs) {
@Mappings({}) // TODO 芋艿后续细看下 mapstruct API 优化这块
default ProductSpuDetailBO convert2(ProductSpuDO spu, List<ProductSkuDO> skus, List<ProductAttrAndValuePairBO> productAttrDetailBOs) {
// 创建并转换 ProductSpuDetailBO 对象
ProductSpuDetailBO spuDetail = this.convert2(spu).setPicUrls(StringUtil.split(spu.getPicUrls(), ","));
// 创建 ProductAttrDetailBO 的映射其中KEY ProductAttrDetailBO.attrValueId 即规格值的编号
Map<Integer, ProductAttrDetailBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrDetailBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
Map<Integer, ProductAttrAndValuePairBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrAndValuePairBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
// 创建并转换 ProductSpuDetailBO 数组
spuDetail.setSkus(new ArrayList<>());
skus.forEach(sku -> {

View File

@ -14,4 +14,12 @@ public interface ProductAttrMapper {
List<ProductAttrDO> selectListByIds(@Param("ids") Collection<Integer> ids);
List<ProductAttrDO> selectListByStatus(@Param("status") Integer status);
List<ProductAttrDO> selectListByNameLike(@Param("name") String name,
@Param("offset") Integer offset,
@Param("limit") Integer limit);
Integer selectCountByNameLike(@Param("name") String name);
}

View File

@ -14,4 +14,8 @@ public interface ProductAttrValueMapper {
List<ProductAttrValueDO> selectListByIds(@Param("ids") Collection<Integer> ids);
List<ProductAttrValueDO> selectListByStatus(@Param("status") Integer status);
List<ProductAttrValueDO> selectListByAttrIds(@Param("attrIds") Collection<Integer> attrIds);
}

View File

@ -2,16 +2,25 @@ 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.ProductAttrService;
import cn.iocoder.mall.product.api.bo.ProductAttrAndValuePairBO;
import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrPageBO;
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
import cn.iocoder.mall.product.api.constant.ProductAttrConstants;
import cn.iocoder.mall.product.api.constant.ProductErrorCodeEnum;
import cn.iocoder.mall.product.api.dto.ProductAttrPageDTO;
import cn.iocoder.mall.product.convert.ProductAttrConvert;
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 com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -24,22 +33,25 @@ import java.util.stream.Collectors;
* @see cn.iocoder.mall.product.dataobject.ProductAttrValueDO
*/
@Service
public class ProductAttrServiceImpl {
@com.alibaba.dubbo.config.annotation.Service(validation = "true")
public class ProductAttrServiceImpl implements ProductAttrService {
@Autowired
private ProductAttrMapper productAttrMapper;
@Autowired
private ProductAttrValueMapper productValueMapper;
private ProductAttrValueMapper productAttrValueMapper;
public CommonResult<List<ProductAttrDetailBO>> validProductAttrAndValue(Set<Integer> productAttrValueIds) {
public CommonResult<List<ProductAttrAndValuePairBO>> validProductAttrAndValue(Set<Integer> productAttrValueIds, boolean validStatus) {
// 首先校验规格值
List<ProductAttrValueDO> attrValues = productValueMapper.selectListByIds(productAttrValueIds);
List<ProductAttrValueDO> attrValues = productAttrValueMapper.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());
if (validStatus) {
for (ProductAttrValueDO attrValue : attrValues) { // 同时校验下状态
if (ProductAttrConstants.ATTR_STATUS_DISABLE.equals(attrValue.getStatus())) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
}
}
}
// 然后校验规格
@ -48,17 +60,58 @@ public class ProductAttrServiceImpl {
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());
if (validStatus) {
for (ProductAttrDO attr : attrs) { // 同时校验下状态
if (ProductAttrConstants.ATTR_VALUE_STATUS_DISABLE.equals(attr.getStatus())) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
}
}
}
// 返回成功
Map<Integer, ProductAttrDO> attrMap = attrs.stream().collect(Collectors.toMap(ProductAttrDO::getId, productAttrDO -> productAttrDO)); // ProductAttrDO 的映射方便查找
List<ProductAttrDetailBO> result = attrValues.stream().map(productAttrValueDO -> new ProductAttrDetailBO()
List<ProductAttrAndValuePairBO> result = attrValues.stream().map(productAttrValueDO -> new ProductAttrAndValuePairBO()
.setAttrId(productAttrValueDO.getAttrId()).setAttrName(attrMap.get(productAttrValueDO.getAttrId()).getName())
.setAttrValueId(productAttrValueDO.getId()).setAttrValueName(productAttrValueDO.getName())).collect(Collectors.toList());
return CommonResult.success(result);
}
@Override
public CommonResult<ProductAttrPageBO> getProductAttrPage(ProductAttrPageDTO productAttrPageDTO) {
ProductAttrPageBO productAttrPageBO = new ProductAttrPageBO();
// 查询分页数据
int offset = productAttrPageDTO.getPageNo() * productAttrPageDTO.getPageSize();
productAttrPageBO.setAttrs(ProductAttrConvert.INSTANCE.convert(productAttrMapper.selectListByNameLike(productAttrPageDTO.getName(),
offset, productAttrPageDTO.getPageSize())));
// 查询分页总数
productAttrPageBO.setCount(productAttrMapper.selectCountByNameLike(productAttrPageDTO.getName()));
// 将规格值拼接上去
if (!productAttrPageBO.getAttrs().isEmpty()) {
Set<Integer> attrIds = productAttrPageBO.getAttrs().stream().map(ProductAttrDetailBO::getId).collect(Collectors.toSet());
List<ProductAttrValueDO> attrValues = productAttrValueMapper.selectListByAttrIds(attrIds);
ImmutableListMultimap<Integer, ProductAttrValueDO> attrValueMap = Multimaps.index(attrValues, ProductAttrValueDO::getAttrId); // KEY attrId VALUE ProductAttrValueDO 数组
for (ProductAttrDetailBO productAttrDetailBO : productAttrPageBO.getAttrs()) {
productAttrDetailBO.setValues(ProductAttrConvert.INSTANCE.convert2(((attrValueMap).get(productAttrDetailBO.getId()))));
}
}
// 返回结果
return CommonResult.success(productAttrPageBO);
}
@Override
public CommonResult<List<ProductAttrSimpleBO>> getProductAttrList() {
// 查询所有开启的规格数组
List<ProductAttrSimpleBO> attrs = ProductAttrConvert.INSTANCE.convert3(productAttrMapper.selectListByStatus(ProductAttrConstants.ATTR_STATUS_ENABLE));
// 如果为空则返回空
if (attrs.isEmpty()) {
return CommonResult.success(Collections.emptyList());
}
// 将规格值拼接上去
List<ProductAttrValueDO> attrValues = productAttrValueMapper.selectListByStatus(ProductAttrConstants.ATTR_VALUE_STATUS_ENABLE);
ImmutableListMultimap<Integer, ProductAttrValueDO> attrValueMap = Multimaps.index(attrValues, ProductAttrValueDO::getAttrId); // KEY attrId VALUE ProductAttrValueDO 数组
for (ProductAttrSimpleBO productAttrSimpleBO : attrs) {
productAttrSimpleBO.setValues(ProductAttrConvert.INSTANCE.convert4(((attrValueMap).get(productAttrSimpleBO.getId()))));
}
return CommonResult.success(attrs);
}
}

View File

@ -6,7 +6,7 @@ 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.ProductAttrAndValuePairBO;
import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO;
import cn.iocoder.mall.product.api.bo.ProductSpuPageBO;
import cn.iocoder.mall.product.api.constant.ProductErrorCodeEnum;
@ -61,7 +61,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 获得规格
Set<Integer> productAttrValueIds = new HashSet<>();
skus.forEach(sku -> productAttrValueIds.addAll(StringUtil.splitToInt(sku.getAttrs(), ",")));
CommonResult<List<ProductAttrDetailBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds);
CommonResult<List<ProductAttrAndValuePairBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds,
false); // 读取规格时不考虑规格是否被禁用
if (validAttrResult.isError()) {
return CommonResult.error(validAttrResult);
}
@ -81,7 +82,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 校验规格是否存在
Set<Integer> productAttrValueIds = new HashSet<>();
productSpuAddDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs()));
CommonResult<List<ProductAttrDetailBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds);
CommonResult<List<ProductAttrAndValuePairBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds
, true); // 读取规格时需要考虑规格是否被禁用
if (validAttrResult.isError()) {
return CommonResult.error(validAttrResult);
}
@ -126,7 +128,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 校验规格是否存在
Set<Integer> productAttrValueIds = new HashSet<>();
productSpuUpdateDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs()));
CommonResult<List<ProductAttrDetailBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds);
CommonResult<List<ProductAttrAndValuePairBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds,
true); // 读取规格时需要考虑规格是否被禁用
if (validAttrResult.isError()) {
return CommonResult.error(validAttrResult);
}
@ -203,10 +206,10 @@ public class ProductSpuServiceImpl implements ProductSpuService {
return CommonResult.success(productSpuPage);
}
private CommonResult<Boolean> validProductSku(List<ProductSkuAddOrUpdateDTO> productSkuAddDTOs, List<ProductAttrDetailBO> productAttrDetailBOs) {
private CommonResult<Boolean> validProductSku(List<ProductSkuAddOrUpdateDTO> productSkuAddDTOs, List<ProductAttrAndValuePairBO> productAttrDetailBOs) {
// 创建 ProductAttrDetailBO 的映射其中KEY ProductAttrDetailBO.attrValueId 即规格值的编号
Map<Integer, ProductAttrDetailBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrDetailBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
Map<Integer, ProductAttrAndValuePairBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrAndValuePairBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
// 1. 先校验一个 Sku 没有重复的规格校验方式是遍历每个 Sku 看看是否有重复的规格 attrId
for (ProductSkuAddOrUpdateDTO sku : productSkuAddDTOs) {
Set<Integer> attrIds = sku.getAttrs().stream().map(attrValueId -> productAttrDetailBOMap.get(attrValueId).getAttrId()).collect(Collectors.toSet());

View File

@ -70,4 +70,41 @@
AND deleted = 0
</select>
<select id="selectListByNameLike" resultType="ProductAttrDO">
SELECT
<include refid="FIELDS" />
FROM product_attr
<where>
<if test="name != null">
name LIKE "%"#{name}"%"
</if>
AND deleted = 0
</where>
LIMIT #{offset}, #{limit}
</select>
<select id="selectCountByNameLike" resultType="Integer">
SELECT
COUNT(1)
FROM product_attr
<where>
<if test="name != null">
name LIKE "%"#{name}"%"
</if>
AND deleted = 0
</where>
</select>
<select id="selectListByStatus" parameterType="Integer" resultType="ProductAttrDO">
SELECT
<include refid="FIELDS" />
FROM product_attr
<where>
<if test="status != null">
status = #{status}
</if>
AND deleted = 0
</where>
</select>
</mapper>

View File

@ -70,4 +70,27 @@
AND deleted = 0
</select>
<select id="selectListByAttrIds" resultType="ProductAttrValueDO">
SELECT
<include refid="FIELDS" />
FROM product_attr_value
WHERE attr_id IN
<foreach item="attrId" collection="attrIds" separator="," open="(" close=")" index="">
#{attrId}
</foreach>
AND deleted = 0
</select>
<select id="selectListByStatus" resultType="ProductAttrValueDO">
SELECT
<include refid="FIELDS" />
FROM product_attr_value
<where>
<if test="status != null">
status = #{status}
</if>
AND deleted = 0
</where>
</select>
</mapper>