diff --git a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java index 9dd90026c..c77f8be30 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/utils/AreaUtils.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.framework.ip.core.utils; import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.lang.Assert; import cn.hutool.core.text.csv.CsvRow; import cn.hutool.core.text.csv.CsvUtil; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; @@ -50,6 +51,7 @@ public class AreaUtils { for (CsvRow row : rows) { Area area = areas.get(Integer.valueOf(row.get(0))); // 自己 Area parent = areas.get(Integer.valueOf(row.get(3))); // 父 + Assert.isTrue(area != parent, "{}:父子节点相同", area.getName()); area.setParent(parent); parent.getChildren().add(area); } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv index 99010471f..27e753c90 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv +++ b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/resources/area.csv @@ -2567,8 +2567,6 @@ id,name,type,parentId 441826,连南瑶族自治县,4,441800 441881,英德市,4,441800 441882,连州市,4,441800 -441900,东莞市,4,441900 -442000,中山市,4,442000 445102,湘桥区,4,445100 445103,潮安区,4,445100 445122,饶平县,4,445100 @@ -2704,7 +2702,6 @@ id,name,type,parentId 460321,西沙群岛,4,460300 460322,南沙群岛,4,460300 460323,中沙群岛的岛礁及其海域,4,460300 -460400,儋州市,4,460400 469001,五指山市,4,469000 469002,琼海市,4,469000 469005,文昌市,4,469000 diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java index c18bd248c..e98f4980f 100644 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java @@ -33,6 +33,10 @@ public class AssertUtils { public static void assertPojoEquals(Object expected, Object actual, String... ignoreFields) { Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); Arrays.stream(expectedFields).forEach(expectedField -> { + // 忽略 jacoco 自动生成的 $jacocoData 属性的情况 + if (expectedField.isSynthetic()) { + return; + } // 如果是忽略的属性,则不进行比对 if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { return; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyViewRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyViewRespVO.java deleted file mode 100644 index b97c04a80..000000000 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/ProductPropertyViewRespVO.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.product.controller.admin.property.vo; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.ToString; - -import java.util.List; - -// TODO 芋艿:看看怎么删除 -@ApiModel("管理后台 - 商品属性详情展示 Request VO") -@Data -@ToString(callSuper = true) -public class ProductPropertyViewRespVO { - - @ApiModelProperty(value = "属性项 id", example = "1") - public Long propertyId; - - @ApiModelProperty(value = "属性项的名字", example = "内存") - public String name; - - @ApiModelProperty(value = "属性值数组") - public List propertyValues; - - @Data - @ApiModel(value = "属性值元组") - public static class Tuple2 { - private final long id; - private final String name; - - public Tuple2(Long id, String name) { - this.id = id; - this.name = name; - } - - } - - -} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueDetailRespVO.java new file mode 100644 index 000000000..55bae16df --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueDetailRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel("管理后台 - 商品属性值的明细 Response VO") +@Data +public class ProductPropertyValueDetailRespVO { + + @ApiModelProperty(value = "属性的编号", required = true, example = "1") + private Long propertyId; + + @ApiModelProperty(value = "属性的名称", required = true, example = "颜色") + private String propertyName; + + @ApiModelProperty(value = "属性值的编号", required = true, example = "1024") + private Long valueId; + + @ApiModelProperty(value = "属性值的名称", required = true, example = "红色") + private String valueName; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.http b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.http new file mode 100644 index 000000000..4ab7b4f71 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.http @@ -0,0 +1,4 @@ +### 获得商品 SPU 明细 +GET {{baseUrl}}/product/spu/get-detail?id=4 +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java index 5d07403d7..f19fde594 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java @@ -3,8 +3,13 @@ package cn.iocoder.yudao.module.product.controller.admin.spu; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -15,10 +20,11 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; -import java.util.Collection; import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; @Api(tags = "管理后台 - 商品 SPU") @RestController @@ -28,6 +34,10 @@ public class ProductSpuController { @Resource private ProductSpuService productSpuService; + @Resource + private ProductSkuService productSkuService; + @Resource + private ProductPropertyValueService productPropertyValueService; @PostMapping("/create") @ApiOperation("创建商品 SPU") @@ -53,31 +63,24 @@ public class ProductSpuController { return success(true); } - // TODO 芋艿:修改接口 - @GetMapping("/get/detail") - @ApiOperation("获得商品 SPU") + @GetMapping("/get-detail") + @ApiOperation("获得商品 SPU 明细") @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) @PreAuthorize("@ss.hasPermission('product:spu:query')") public CommonResult getSpuDetail(@RequestParam("id") Long id) { - return success(productSpuService.getSpuDetail(id)); - } + // 获得商品 SPU + ProductSpuDO spu = productSpuService.getSpu(id); + if (spu == null) { + throw exception(SPU_NOT_EXISTS); + } - @GetMapping("/get") - @ApiOperation("获得商品 SPU") - @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) - @PreAuthorize("@ss.hasPermission('product:spu:query')") - public CommonResult getSpu(@RequestParam("id") Long id) { - return success(productSpuService.getSpu(id)); - } - - - @GetMapping("/list") - @ApiOperation("获得商品 SPU 列表") - @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class) - @PreAuthorize("@ss.hasPermission('product:spu:query')") - public CommonResult> getSpuList(@RequestParam("ids") Collection ids) { - List list = productSpuService.getSpuList(ids); - return success(ProductSpuConvert.INSTANCE.convertList(list)); + // 查询商品 SKU + List skus = productSkuService.getSkuListBySpuIdAndStatus(spu.getId(), null); + // 查询商品属性 + List propertyValues = productPropertyValueService + .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus)); + // 拼接 + return success(ProductSpuConvert.INSTANCE.convert03(spu, skus, propertyValues)); } @GetMapping("/get-simple-list") @@ -92,7 +95,7 @@ public class ProductSpuController { @ApiOperation("获得商品 SPU 分页") @PreAuthorize("@ss.hasPermission('product:spu:query')") public CommonResult> getSpuPage(@Valid ProductSpuPageReqVO pageVO) { - return success(productSpuService.getSpuPage(pageVO)); + return success(ProductSpuConvert.INSTANCE.convertPage(productSpuService.getSpuPage(pageVO))); } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java index 4782dcddb..65cdd22a2 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java @@ -1,52 +1,27 @@ package cn.iocoder.yudao.module.product.controller.admin.spu.vo; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import java.time.LocalDateTime; import java.util.List; @ApiModel(value = "管理后台 - 商品 SPU 详细 Response VO", description = "包括关联的 SKU 等信息") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class ProductSpuDetailRespVO extends ProductSpuBaseVO { - - @ApiModelProperty(value = "主键", required = true, example = "1") - private Long id; - - @ApiModelProperty(value = "创建时间") - private LocalDateTime createTime; +public class ProductSpuDetailRespVO extends ProductSpuRespVO { // ========== SKU 相关字段 ========= - @ApiModelProperty(value = "库存", required = true, example = "true") - private Integer totalStock; - - @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024") - private Integer minPrice; - - @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024") - private Integer maxPrice; - - @ApiModelProperty(value = "商品销量", example = "1024") - private Integer salesCount; - /** * SKU 数组 */ private List skus; - // ========== 统计相关字段 ========= - - @ApiModelProperty(value = "点击量", example = "1024") - private Integer clickCount; - @ApiModel(value = "管理后台 - 商品 SKU 详细 Response VO") @Data @EqualsAndHashCode(callSuper = true) @@ -56,29 +31,8 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO { /** * 属性数组 */ - private List properties; + private List properties; } - @ApiModel(value = "管理后台 - 商品属性的详细 Response VO") - @Data - @EqualsAndHashCode(callSuper = true) - @ToString(callSuper = true) - public static class Property extends ProductSkuBaseVO.Property { - - @ApiModelProperty(value = "属性项的名字", required = true, example = "颜色") - private String propertyName; - - @ApiModelProperty(value = "属性值的名称", required = true, example = "蓝色") - private String valueName; - - } - - @ApiModelProperty(value = "分类 id 数组,一直递归到一级父节点", example = "4") - private Long categoryId; - - // TODO @芋艿:在瞅瞅~ - @ApiModelProperty(value = "属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]") - private List productPropertyViews; - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java index 517140b49..9116f29cf 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java @@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuDetailRespVO; -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageItemRespVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO; import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; @@ -48,7 +48,7 @@ public class AppProductSpuController { @GetMapping("/page") @ApiOperation("获得商品 SPU 分页") - public CommonResult> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { + public CommonResult> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { PageResult pageResult = productSpuService.getSpuPage(pageVO, ProductSpuStatusEnum.ENABLE.getStatus()); return success(ProductSpuConvert.INSTANCE.convertPage02(pageResult)); } @@ -56,7 +56,7 @@ public class AppProductSpuController { @GetMapping("/get-detail") @ApiOperation("获得商品 SPU 明细") @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) - public CommonResult getSpuDetail(@RequestParam("id") Long id) { + public CommonResult getSpuDetail(@RequestParam("id") Long id) { // 获得商品 SPU ProductSpuDO spu = productSpuService.getSpu(id); if (spu == null) { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java similarity index 98% rename from yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuDetailRespVO.java rename to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java index 76aed7732..699ca1caa 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuDetailRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java @@ -9,7 +9,7 @@ import java.util.List; @ApiModel("用户 App - 商品 SPU 明细 Response VO") @Data -public class AppSpuDetailRespVO { +public class AppProductSpuDetailRespVO { @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1") private Long id; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageItemRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java similarity index 96% rename from yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageItemRespVO.java rename to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java index 0b58555f8..60fc9235e 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppSpuPageItemRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuPageItemRespVO.java @@ -10,7 +10,7 @@ import java.util.List; @ApiModel("用户 App - 商品 SPU 分页项 Response VO") @Data -public class AppSpuPageItemRespVO { +public class AppProductSpuPageItemRespVO { @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1") private Long id; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java index 9ed0c9b2c..fcf6d6436 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java @@ -3,11 +3,12 @@ package cn.iocoder.yudao.module.product.convert.spu; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuDetailRespVO; -import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageItemRespVO; +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; @@ -45,9 +46,9 @@ public interface ProductSpuConvert { List convertList02(List list); - default AppSpuDetailRespVO convert(ProductSpuDO spu, List skus, - List propertyValues) { - AppSpuDetailRespVO spuVO = convert02(spu) + default AppProductSpuDetailRespVO convert(ProductSpuDO spu, List skus, + List propertyValues) { + AppProductSpuDetailRespVO spuVO = convert02(spu) .setSalesCount(spu.getSalesCount() + defaultIfNull(spu.getVirtualSalesCount(), 0)); spuVO.setSkus(convertList03(skus)); // 处理商品属性 @@ -57,7 +58,7 @@ public interface ProductSpuConvert { if (CollUtil.isEmpty(properties)) { continue; } - AppSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); + AppProductSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); sku.setProperties(new ArrayList<>(properties.size())); // 遍历每个 properties,设置到 AppSpuDetailRespVO.Sku 中 properties.forEach(property -> { @@ -70,10 +71,38 @@ public interface ProductSpuConvert { } return spuVO; } - AppSpuDetailRespVO convert02(ProductSpuDO spu); - List convertList03(List skus); + AppProductSpuDetailRespVO convert02(ProductSpuDO spu); + List convertList03(List skus); AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue); - PageResult convertPage02(PageResult page); + PageResult convertPage02(PageResult page); + + default ProductSpuDetailRespVO convert03(ProductSpuDO spu, List skus, + List propertyValues) { + ProductSpuDetailRespVO spuVO = convert03(spu); + spuVO.setSkus(convertList04(skus)); + // 处理商品属性 + Map propertyValueMap = convertMap(propertyValues, ProductPropertyValueDetailRespBO::getValueId); + for (int i = 0; i < skus.size(); i++) { + List properties = skus.get(i).getProperties(); + if (CollUtil.isEmpty(properties)) { + continue; + } + ProductSpuDetailRespVO.Sku sku = spuVO.getSkus().get(i); + sku.setProperties(new ArrayList<>(properties.size())); + // 遍历每个 properties,设置到 AppSpuDetailRespVO.Sku 中 + properties.forEach(property -> { + ProductPropertyValueDetailRespBO propertyValue = propertyValueMap.get(property.getValueId()); + if (propertyValue == null) { + return; + } + sku.getProperties().add(convert04(propertyValue)); + }); + } + return spuVO; + } + ProductSpuDetailRespVO convert03(ProductSpuDO spu); + List convertList04(List skus); + ProductPropertyValueDetailRespVO convert04(ProductPropertyValueDetailRespBO propertyValue); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java index 195b50d13..26f8d5239 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java @@ -21,8 +21,7 @@ public interface ProductPropertyMapper extends BaseMapperX { } default ProductPropertyDO selectByName(String name) { - return selectOne(new LambdaQueryWrapperX() - .eqIfPresent(ProductPropertyDO::getName, name)); + return selectOne(ProductPropertyDO::getName, name); } default List selectList(ProductPropertyListReqVO listReqVO) { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java index 855d2f0f6..564bc82a9 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java @@ -17,6 +17,7 @@ public interface ProductPropertyService { /** * 创建属性项 + * 注意,如果已经存在该属性项,直接返回它的编号即可 * * @param createReqVO 创建信息 * @return 编号 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java index ba0704c72..328c343d6 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java @@ -40,9 +40,10 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { @Override @Transactional(rollbackFor = Exception.class) public Long createProperty(ProductPropertyCreateReqVO createReqVO) { - // 校验名字重复 - if (productPropertyMapper.selectByName(createReqVO.getName()) != null) { - throw exception(PROPERTY_EXISTS); + // 如果已经添加过该属性项,直接返回 + ProductPropertyDO dbProperty = productPropertyMapper.selectByName(createReqVO.getName()); + if (dbProperty != null) { + return dbProperty.getId(); } // 插入 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java index 605e40d93..553e2578d 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java @@ -19,6 +19,7 @@ public interface ProductPropertyValueService { /** * 创建属性值 + * 注意,如果已经存在该属性值,直接返回它的编号即可 * * @param createReqVO 创建信息 * @return 编号 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java index c58d74b95..e5bc6874b 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java @@ -42,9 +42,11 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ @Override public Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO) { - // 校验名字唯一 - if (productPropertyValueMapper.selectByName(createReqVO.getPropertyId(), createReqVO.getName()) != null) { - throw exception(PROPERTY_VALUE_EXISTS); + // 如果已经添加过该属性值,直接返回 + ProductPropertyValueDO dbValue = productPropertyValueMapper.selectByName( + createReqVO.getPropertyId(), createReqVO.getName()); + if (dbValue != null) { + return dbValue.getId(); } // 新增 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java index d8034bd1b..0ae7359eb 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java @@ -41,14 +41,6 @@ public interface ProductSpuService { */ void deleteSpu(Long id); - /** - * 获得商品 SPU 详情 - * - * @param id 编号 - * @return 商品 SPU - */ - ProductSpuDetailRespVO getSpuDetail(Long id); - /** * 获得商品 SPU * @@ -88,7 +80,7 @@ public interface ProductSpuService { * @param pageReqVO 分页查询 * @return 商品spu分页 */ - PageResult getSpuPage(ProductSpuPageReqVO pageReqVO); + PageResult getSpuPage(ProductSpuPageReqVO pageReqVO); /** * 获得商品 SPU 分页 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 72589fa7f..0dd9cdf55 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -1,27 +1,19 @@ package cn.iocoder.yudao.module.product.service.spu; -import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO; -import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; -import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; -import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; -import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; import cn.iocoder.yudao.module.product.service.brand.ProductBrandService; import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; -import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; -import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -29,8 +21,10 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.*; -import java.util.stream.Collectors; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @@ -49,18 +43,13 @@ public class ProductSpuServiceImpl implements ProductSpuService { @Resource private ProductSpuMapper productSpuMapper; - @Resource - private ProductCategoryService categoryService; - @Resource @Lazy // 循环依赖,避免报错 private ProductSkuService productSkuService; @Resource - private ProductPropertyService productPropertyService; - @Resource - private ProductPropertyValueService productPropertyValueService; - @Resource private ProductBrandService brandService; + @Resource + private ProductCategoryService categoryService; @Override @Transactional(rollbackFor = Exception.class) @@ -148,46 +137,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { } } - @Override - // TODO @芋艿:需要再 review 下 - public ProductSpuDetailRespVO getSpuDetail(Long id) { - ProductSpuDO spu = productSpuMapper.selectById(id); - ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class); - if (null != spu) { - List skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkuListBySpuId(id)); - respVO.setSkus(skuReqs); - // 组合 sku 属性 - if (spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) { - List properties = new ArrayList<>(); - for (ProductSpuDetailRespVO.Sku productSkuRespVO : skuReqs) { - properties.addAll(productSkuRespVO.getProperties()); - } - Map> propertyMaps = properties.stream().collect(Collectors.groupingBy(ProductSkuBaseVO.Property::getPropertyId)); - - List propertyValueList = productPropertyValueService.getPropertyValueListByPropertyId(propertyMaps.keySet()); - List propertyList = productPropertyService.getPropertyList(propertyMaps.keySet()); - // 装载组装过后的属性 - List productPropertyViews = new ArrayList<>(); - propertyList.forEach(p -> { - ProductPropertyViewRespVO productPropertyViewRespVO = new ProductPropertyViewRespVO(); - productPropertyViewRespVO.setPropertyId(p.getId()); - productPropertyViewRespVO.setName(p.getName()); - List propertyValues = new ArrayList<>(); - // 转换成map是为了能快速获取 - Map propertyValueMaps = convertMap(propertyValueList, ProductPropertyValueDO::getId); - propertyMaps.get(p.getId()).forEach(pv -> { - ProductPropertyViewRespVO.Tuple2 tuple2 = new ProductPropertyViewRespVO.Tuple2(pv.getValueId(), propertyValueMaps.get(pv.getValueId()).getName()); - propertyValues.add(tuple2); - }); - productPropertyViewRespVO.setPropertyValues(propertyValues.stream().distinct().collect(Collectors.toList())); - productPropertyViews.add(productPropertyViewRespVO); - }); - respVO.setProductPropertyViews(productPropertyViews); - } - } - return respVO; - } - @Override public ProductSpuDO getSpu(Long id) { return productSpuMapper.selectById(id); @@ -203,9 +152,8 @@ public class ProductSpuServiceImpl implements ProductSpuService { return productSpuMapper.selectList(); } - // TODO 芋艿:改成 DO 返回 @Override - public PageResult getSpuPage(ProductSpuPageReqVO pageReqVO) { + public PageResult getSpuPage(ProductSpuPageReqVO pageReqVO) { // 库存告警的 SPU 编号的集合 Set alarmStockSpuIds = null; if (Boolean.TRUE.equals(pageReqVO.getAlarmStock())) { @@ -215,7 +163,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { } } // 分页查询 - return ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds)); + return productSpuMapper.selectPage(pageReqVO, alarmStockSpuIds); } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java index 850d343c3..ec088cfdd 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java +++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceTest.java @@ -19,11 +19,12 @@ import java.util.Arrays; import java.util.List; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; import static java.util.Collections.singletonList; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.verify; @@ -145,4 +146,26 @@ public class ProductSkuServiceTest extends BaseDbUnitTest { SKU_STOCK_NOT_ENOUGH); } + @Test + public void testDeleteSku_success() { + // mock 数据 + ProductSkuDO dbSku = randomPojo(ProductSkuDO.class); + productSkuMapper.insert(dbSku);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSku.getId(); + + // 调用 + productSkuService.deleteSku(id); + // 校验数据不存在了 + assertNull(productSkuMapper.selectById(id)); + } + + @Test + public void testDeleteSku_notExists() { + // 准备参数 + Long id = 1L; + + // 调用, 并断言异常 + assertServiceException(() -> productSkuService.deleteSku(id), SKU_NOT_EXISTS); + } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/SkuServiceImplTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/SkuServiceImplTest.java deleted file mode 100755 index 1f04e9d35..000000000 --- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/sku/SkuServiceImplTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.product.service.sku; - -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; -import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Import; - -import javax.annotation.Resource; - -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; -import static org.junit.jupiter.api.Assertions.assertNull; - -// TODO 芋艿:整合到 {@link ProductSkuServiceTest} 中 -/** -* {@link ProductSkuServiceImpl} 的单元测试类 -* -* @author 芋道源码 -*/ -@Import(ProductSkuServiceImpl.class) -@Disabled // TODO 芋艿:临时去掉 -public class SkuServiceImplTest extends BaseDbUnitTest { - - @Resource - private ProductSkuServiceImpl ProductSkuService; - - @Resource - private ProductSkuMapper ProductSkuMapper; - - @Test - public void testDeleteSku_success() { - // mock 数据 - ProductSkuDO dbSku = randomPojo(ProductSkuDO.class); - ProductSkuMapper.insert(dbSku);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbSku.getId(); - - // 调用 - ProductSkuService.deleteSku(id); - // 校验数据不存在了 - assertNull(ProductSkuMapper.selectById(id)); - } - - @Test - public void testDeleteSku_notExists() { - // 准备参数 - Long id = 1L; - - // 调用, 并断言异常 - assertServiceException(() -> ProductSkuService.deleteSku(id), SKU_NOT_EXISTS); - } - -} diff --git a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java index 33cdf5f56..1e029570c 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java +++ b/yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java @@ -8,10 +8,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; @@ -148,53 +149,6 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { Assertions.assertNull(productSpuMapper.selectById(createReqVO.getId())); } - @Test - void getSpuDetail() { - // 准备spu参数 - ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o -> { - o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType()); - }); - productSpuMapper.insert(createReqVO); - - // 创建两个属性 - ArrayList productPropertyRespVOS = Lists.newArrayList( - randomPojo(ProductPropertyRespVO.class), - randomPojo(ProductPropertyRespVO.class)); - - // 所有属性值 - ArrayList productPropertyValueRespVO = new ArrayList<>(); - - // 每个属性创建属性值 - productPropertyRespVOS.forEach(v -> { - ProductPropertyValueRespVO productPropertyValueRespVO1 = randomPojo(ProductPropertyValueRespVO.class, o -> o.setPropertyId(v.getId())); - productPropertyValueRespVO.add(productPropertyValueRespVO1); - }); - - // 属性值建立笛卡尔积 - Map> collect = productPropertyValueRespVO.stream().collect(Collectors.groupingBy(ProductPropertyValueRespVO::getPropertyId)); - List> lists = cartesianProduct(Lists.newArrayList(collect.values())); - - // 准备sku参数 - ArrayList productSkuDOS = Lists.newArrayList(); - lists.forEach(pp -> { - List property = pp.stream().map(ppv -> new ProductSkuDO.Property(ppv.getPropertyId(), ppv.getId())).collect(Collectors.toList()); - ProductSkuDO productSkuDO = randomPojo(ProductSkuDO.class, o -> { - o.setProperties(property); - }); - productSkuDOS.add(productSkuDO); - - }); - - Mockito.when(productSkuService.getSkuListBySpuId(createReqVO.getId())).thenReturn(productSkuDOS); -// Mockito.when(productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyValueRespVO); -// Mockito.when(productPropertyService.getPropertyVOList(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyRespVOS); -// - // 调用 - ProductSpuDetailRespVO spuDetail = productSpuService.getSpuDetail(createReqVO.getId()); - - assertPojoEquals(createReqVO, spuDetail); - } - @Test void getSpu() { // 准备参数 @@ -222,7 +176,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); productSpuPageReqVO.setAlarmStock(true); - PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); PageResult result = PageResult.empty(); Assertions.assertIterableEquals(result.getList(), spuPage.getList()); @@ -271,7 +225,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { // 调用 ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO(); productSpuPageReqVO.setAlarmStock(true); - PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); PageResult result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, alarmStockSpuIds)); Assertions.assertIterableEquals(result.getList(), spuPage.getList()); @@ -323,7 +277,7 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest { productSpuPageReqVO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus()); productSpuPageReqVO.setCategoryId(categoryId); - PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); + PageResult spuPage = productSpuService.getSpuPage(productSpuPageReqVO); PageResult result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, (Set) null)); assertEquals(result, spuPage); diff --git a/yudao-module-system/yudao-module-system-biz/pom.xml b/yudao-module-system/yudao-module-system-biz/pom.xml index ecac34aa5..f1887ea90 100644 --- a/yudao-module-system/yudao-module-system-biz/pom.xml +++ b/yudao-module-system/yudao-module-system-biz/pom.xml @@ -54,6 +54,10 @@ cn.iocoder.boot yudao-spring-boot-starter-biz-tenant + + cn.iocoder.boot + yudao-spring-boot-starter-biz-ip + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.http new file mode 100644 index 000000000..f1b893d01 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.http @@ -0,0 +1,5 @@ +### 获得地区树 +GET {{baseUrl}}/system/area/tree +Authorization: Bearer {{token}} +tenant-id: {{adminTenentId}} + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java new file mode 100644 index 000000000..a7e4d3e03 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/AreaController.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.controller.admin.ip; + +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; +import cn.iocoder.yudao.framework.ip.core.utils.IPUtils; +import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO; +import cn.iocoder.yudao.module.system.convert.ip.AreaConvert; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 地区") +@RestController +@RequestMapping("/system/area") +@Validated +public class AreaController { + + @GetMapping("/tree") + @ApiOperation("获得地区树") + public CommonResult> getAreaTree() { + Area area = AreaUtils.getArea(Area.ID_CHINA); + Assert.notNull(area, "获取不到中国"); + return success(AreaConvert.INSTANCE.convertList(area.getChildren())); + } + + @GetMapping("/get-by-ip") + @ApiOperation("获得 IP 对应的地区名") + @ApiImplicitParam(name = "ip", value = "IP", required = true, dataTypeClass = String.class) + public CommonResult getAreaByIp(@RequestParam("ip") String ip) { + // 获得城市 + Area area = IPUtils.getArea(ip); + if (area == null) { + return success("未知"); + } + // 格式化返回 + return success(AreaUtils.format(area.getId())); + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/vo/AreaNodeRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/vo/AreaNodeRespVO.java new file mode 100644 index 000000000..a2416832d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/ip/vo/AreaNodeRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.system.controller.admin.ip.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@ApiModel("管理后台 - 地区节点 Response VO") +@Data +public class AreaNodeRespVO { + + @ApiModelProperty(value = "编号", required = true, example = "110000") + private Integer id; + + @ApiModelProperty(value = "名字", required = true, example = "北京") + private String name; + + /** + * 子节点 + */ + private List children; + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/ip/AreaConvert.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/ip/AreaConvert.java new file mode 100644 index 000000000..0cedf8785 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/ip/AreaConvert.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.system.convert.ip; + +import cn.iocoder.yudao.framework.ip.core.Area; +import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface AreaConvert { + + AreaConvert INSTANCE = Mappers.getMapper(AreaConvert.class); + + List convertList(List list); + +} diff --git a/yudao-ui-admin/src/api/mall/product/spu.js b/yudao-ui-admin/src/api/mall/product/spu.js index 7cce82f3b..a6d331239 100644 --- a/yudao-ui-admin/src/api/mall/product/spu.js +++ b/yudao-ui-admin/src/api/mall/product/spu.js @@ -26,18 +26,10 @@ export function deleteSpu(id) { }) } -// 获得商品spu -export function getSpu(id) { - return request({ - url: '/product/spu/get?id=' + id, - method: 'get' - }) -} - // 获得商品 SPU 详情 export function getSpuDetail(id) { return request({ - url: '/product/spu/get/detail?id=' + id, + url: '/product/spu/get-detail?id=' + id, method: 'get' }) } diff --git a/yudao-ui-admin/src/api/system/area.js b/yudao-ui-admin/src/api/system/area.js new file mode 100644 index 000000000..f67d9c64a --- /dev/null +++ b/yudao-ui-admin/src/api/system/area.js @@ -0,0 +1,17 @@ +import request from '@/utils/request' + +// 获得地区树 +export function getAreaTree() { + return request({ + url: '/system/area/tree', + method: 'get' + }) +} + +// 获得 IP 对应的地区名 +export function getAreaByIp(ip) { + return request({ + url: '/system/area/get-by-ip?ip=' + ip, + method: 'get' + }) +} diff --git a/yudao-ui-admin/src/views/mall/product/spu/save.vue b/yudao-ui-admin/src/views/mall/product/spu/save.vue index 5eee696d3..82e58d10a 100644 --- a/yudao-ui-admin/src/views/mall/product/spu/save.vue +++ b/yudao-ui-admin/src/views/mall/product/spu/save.vue @@ -4,9 +4,8 @@ - - - + + @@ -155,9 +154,8 @@ - - - + + @@ -165,9 +163,8 @@ - - - + + @@ -208,7 +205,7 @@ export default { data() { return { specSwitch: false, - activeName: "base", + activeName: "basic", propName: { checkStrictly: true, label: "name", diff --git a/yudao-ui-admin/src/views/system/area/index.vue b/yudao-ui-admin/src/views/system/area/index.vue new file mode 100644 index 000000000..6f9b77ce7 --- /dev/null +++ b/yudao-ui-admin/src/views/system/area/index.vue @@ -0,0 +1,114 @@ + + +