From e1e55dc841df7b6ceead7f3a2ae05799050c7f95 Mon Sep 17 00:00:00 2001
From: luowenfeng <1092164058@qq.com>
Date: Wed, 14 Sep 2022 11:57:30 +0800
Subject: [PATCH] =?UTF-8?q?feature(=E5=95=86=E5=93=81=E6=B7=BB=E5=8A=A0):?=
 =?UTF-8?q?=20=E8=A7=84=E6=A0=BC=E8=B0=83=E6=95=B4=E8=BF=9E=E5=B8=A6?=
 =?UTF-8?q?=E5=95=86=E5=93=81=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../property/ProductPropertyController.java   |  27 +++-
 .../ProductPropertyValueController.java       |  70 ++++++++
 .../vo/property/ProductPropertyBaseVO.java    |  16 +-
 .../property/ProductPropertyCreateReqVO.java  |  14 +-
 .../vo/property/ProductPropertyListReqVO.java |  19 +++
 .../vo/property/ProductPropertyRespVO.java    |  24 +++
 .../property/ProductPropertyUpdateReqVO.java  |   4 -
 .../vo/value/ProductPropertyValueBaseVO.java  |   4 +-
 .../value/ProductPropertyValuePageReqVO.java  |  31 ++++
 .../admin/spu/ProductSpuController.java       |  14 +-
 .../admin/spu/vo/ProductSpuBaseVO.java        |   8 +
 .../admin/spu/vo/ProductSpuDetailRespVO.java  |   7 +
 .../admin/spu/vo/ProductSpuPageReqVO.java     |  27 +---
 .../admin/spu/vo/ProductSpuRespVO.java        |  18 ---
 .../property/ProductPropertyConvert.java      |   8 +-
 .../convert/sku/ProductSkuConvert.java        |   3 +
 .../property/ProductPropertyDO.java           |   4 +
 .../property/ProductPropertyValueDO.java      |   5 +
 .../property/ProductPropertyValueMapper.java  |  14 +-
 .../dal/mysql/spu/ProductSpuMapper.java       |   3 -
 .../property/ProductPropertyService.java      |  34 ++--
 .../property/ProductPropertyServiceImpl.java  |  88 +++++-----
 .../property/ProductPropertyValueService.java |  65 ++++++++
 .../ProductPropertyValueServiceImpl.java      |  66 ++++++++
 .../service/sku/ProductSkuServiceImpl.java    |  17 +-
 .../service/spu/ProductSpuService.java        |  13 +-
 .../service/spu/ProductSpuServiceImpl.java    |  54 ++++---
 .../src/api/mall/product/property.js          |  65 ++++++++
 yudao-ui-admin/src/api/mall/product/spu.js    |   8 +
 yudao-ui-admin/src/router/index.js            |  11 ++
 .../src/views/mall/product/property/index.vue |  79 +++------
 .../src/views/mall/product/spu/index.vue      | 151 +++++++++++-------
 .../src/views/mall/product/spu/save.vue       |  71 ++++----
 33 files changed, 705 insertions(+), 337 deletions(-)
 create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java
 create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java
 create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java
 create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java
 create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java
 create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java

diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
index 7401ec744..72a8bf603 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
@@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.product.controller.admin.property;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*;
 import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -17,6 +14,8 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 
+import java.util.List;
+
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
 @Api(tags = "管理后台 - 规格名称")
@@ -56,15 +55,29 @@ public class ProductPropertyController {
     @ApiOperation("获得规格名称")
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
     @PreAuthorize("@ss.hasPermission('product:property:query')")
-    public CommonResult<ProductPropertyAndValueRespVO> getProperty(@RequestParam("id") Long id) {
+    public CommonResult<ProductPropertyRespVO> getProperty(@RequestParam("id") Long id) {
         return success(productPropertyService.getPropertyResp(id));
     }
 
+    @GetMapping("/list")
+    @ApiOperation("获得规格名称列表")
+    @PreAuthorize("@ss.hasPermission('product:property:query')")
+    public CommonResult<List<ProductPropertyRespVO>> getPropertyList(@Valid ProductPropertyListReqVO listReqVO) {
+        return success(productPropertyService.getPropertyList(listReqVO));
+    }
+
     @GetMapping("/page")
     @ApiOperation("获得规格名称分页")
     @PreAuthorize("@ss.hasPermission('product:property:query')")
-    public CommonResult<PageResult<ProductPropertyAndValueRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
-        return success(productPropertyService.getPropertyListPage(pageVO));
+    public CommonResult<PageResult<ProductPropertyRespVO>> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) {
+        return success(productPropertyService.getPropertyPage(pageVO));
+    }
+
+    @GetMapping("/listAndValue")
+    @ApiOperation("获得规格名称列表")
+    @PreAuthorize("@ss.hasPermission('product:property:query')")
+    public CommonResult<List<ProductPropertyAndValueRespVO>> getPropertyAndValueList(@Valid ProductPropertyListReqVO listReqVO) {
+        return success(productPropertyService.getPropertyAndValueList(listReqVO));
     }
 
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java
new file mode 100644
index 000000000..e88c91415
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java
@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.module.product.controller.admin.property;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
+import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Api(tags = "管理后台 - 规格值名称")
+@RestController
+@RequestMapping("/product/property/value")
+@Validated
+public class ProductPropertyValueController {
+
+    @Resource
+    private ProductPropertyValueService productPropertyValueService;
+
+    @PostMapping("/create")
+    @ApiOperation("创建规格名称")
+    @PreAuthorize("@ss.hasPermission('product:property:create')")
+    public CommonResult<Long> createProperty(@Valid @RequestBody ProductPropertyValueCreateReqVO createReqVO) {
+        return success(productPropertyValueService.createPropertyValue(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @ApiOperation("更新规格名称")
+    @PreAuthorize("@ss.hasPermission('product:property:update')")
+    public CommonResult<Boolean> updateProperty(@Valid @RequestBody ProductPropertyValueUpdateReqVO updateReqVO) {
+        productPropertyValueService.updatePropertyValue(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @ApiOperation("删除规格名称")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('product:property:delete')")
+    public CommonResult<Boolean> deleteProperty(@RequestParam("id") Long id) {
+        productPropertyValueService.deletePropertyValue(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @ApiOperation("获得规格名称")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('product:property:query')")
+    public CommonResult<ProductPropertyValueRespVO> getProperty(@RequestParam("id") Long id) {
+        return success(productPropertyValueService.getPropertyValue(id));
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("获得规格名称分页")
+    @PreAuthorize("@ss.hasPermission('product:property:query')")
+    public CommonResult<PageResult<ProductPropertyValueRespVO>> getPropertyValuePage(@Valid ProductPropertyValuePageReqVO pageVO) {
+        return success(productPropertyValueService.getPropertyValueListPage(pageVO));
+    }
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java
index c900a727b..25fc4c01a 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java
@@ -3,21 +3,25 @@ package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
-import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 
 /**
-* 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用
-* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
-*/
+ * 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
 @Data
 public class ProductPropertyBaseVO {
 
     @ApiModelProperty(value = "规格名称", required = true, example = "颜色")
-    @NotEmpty(message = "规格名称不能为空")
+    @NotBlank(message = "规格名称不能为空")
     private String name;
 
+    @ApiModelProperty(value = "备注", example = "颜色")
+    private String remark;
+
     @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
-    @NotEmpty(message = "状态不能为空")
+    @NotNull(message = "状态不能为空")
     private Integer status;
 
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java
index c0e6b9da2..8dfd58a5d 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java
@@ -1,11 +1,9 @@
 package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
 
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
-import lombok.*;
-import io.swagger.annotations.*;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
 
 @ApiModel("管理后台 - 规格名称创建 Request VO")
 @Data
@@ -13,9 +11,5 @@ import java.util.List;
 @ToString(callSuper = true)
 public class ProductPropertyCreateReqVO extends ProductPropertyBaseVO {
 
-    // TODO @Luowenfeng:规格值的 CRUD 可以单独;前端 + 后端,改成类似字典类型、字典数据的这种交互;在加一个 ProductPropertyValueController
-    @ApiModelProperty(value = "属性值")
-    @NotNull(message = "属性值不能为空")
-    List<ProductPropertyValueCreateReqVO> propertyValueList;
 
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java
new file mode 100644
index 000000000..314288ffb
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.ToString;
+
+@ApiModel("管理后台 - 规格名称 List Request VO")
+@Data
+@ToString(callSuper = true)
+public class ProductPropertyListReqVO {
+
+    @ApiModelProperty(value = "规格名称", example = "颜色")
+    private String name;
+
+    @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
+    private Integer status;
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java
new file mode 100644
index 000000000..e42cfaba0
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.product.controller.admin.property.vo.property;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.Date;
+
+@ApiModel("管理后台 - 规格 + 规格值 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ProductPropertyRespVO extends ProductPropertyBaseVO {
+
+    @ApiModelProperty(value = "规格的编号", required = true, example = "1024")
+    private Long id;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java
index f4b9d695a..f4630d874 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java
@@ -16,8 +16,4 @@ public class ProductPropertyUpdateReqVO extends ProductPropertyBaseVO {
     @NotNull(message = "主键不能为空")
     private Long id;
 
-    @ApiModelProperty(value = "属性值")
-    @NotNull(message = "属性值不能为空")
-    List<ProductPropertyValueCreateReqVO> propertyValueList;
-
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java
index 1e0708009..c289e7c61 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java
@@ -22,7 +22,9 @@ public class ProductPropertyValueBaseVO {
     private String name;
 
     @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
-    @NotEmpty(message = "状态不能为空")
+    @NotNull(message = "状态不能为空")
     private Integer status;
 
+    @ApiModelProperty(value = "备注", example = "颜色")
+    private String remark;
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java
new file mode 100644
index 000000000..ae77d822b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.product.controller.admin.property.vo.value;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.Date;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("管理后台 - 规格名称值分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ProductPropertyValuePageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "规格id", example = "1024")
+    private String propertyId;
+
+    @ApiModelProperty(value = "规格值", example = "红色")
+    private String name;
+
+    @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举")
+    private Integer status;
+
+}
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 ddae45dc2..0e5f57ec6 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
@@ -2,10 +2,7 @@ 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.ProductSpuCreateReqVO;
-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.admin.spu.vo.ProductSpuPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
@@ -56,6 +53,14 @@ public class ProductSpuController {
         return success(true);
     }
 
+    @GetMapping("/get/detail")
+    @ApiOperation("获得商品 SPU")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('product:spu:query')")
+    public CommonResult<ProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) {
+        return success(spuService.getSpuDetail(id));
+    }
+
     @GetMapping("/get")
     @ApiOperation("获得商品 SPU")
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@@ -64,7 +69,6 @@ public class ProductSpuController {
         return success(spuService.getSpu(id));
     }
 
-    // TODO @luowenfeng:新增 get-detail,返回 SpuDetailRespVO
 
     @GetMapping("/list")
     @ApiOperation("获得商品 SPU 列表")
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
index ec58bab76..826cdd6c4 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
 
 import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
 import io.swagger.annotations.ApiModelProperty;
@@ -67,6 +68,9 @@ public class ProductSpuBaseVO {
     @ApiModelProperty(value = "库存", required = true, example = "true")
     private Integer totalStock;
 
+    @ApiModelProperty(value = "市场价", example = "1024")
+    private Integer marketPrice;
+
     @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024")
     private Integer minPrice;
 
@@ -75,10 +79,14 @@ public class ProductSpuBaseVO {
 
     // ========== 统计相关字段 =========
 
+    @ApiModelProperty(value = "商品销量", example = "1024")
+    private Integer salesCount;
+
     @ApiModelProperty(value = "虚拟销量", required = true, example = "1024")
     @NotNull(message = "虚拟销量不能为空")
     private Integer virtualSalesCount;
 
     @ApiModelProperty(value = "点击量", example = "1024")
     private Integer clickCount;
+
 }
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 dafb0a680..8986a93c8 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,5 +1,6 @@
 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.sku.vo.ProductSkuBaseVO;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -54,4 +55,10 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO {
 
     }
 
+    @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]")
+    private List<Long> categoryIds;
+
+    @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<ProductPropertyViewRespVO> productPropertyViews;
+
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
index 36a37541b..2f0dd57e0 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
@@ -17,35 +17,16 @@ public class ProductSpuPageReqVO extends PageParam {
     @ApiModelProperty(value = "商品名称")
     private String name;
 
-    @ApiModelProperty(value = "卖点")
-    private String sellPoint;
-
-    @ApiModelProperty(value = "描述")
-    private String description;
+    @ApiModelProperty(value = "商品编码", example = "yudaoyuanma")
+    private String code;
 
     @ApiModelProperty(value = "分类id")
     private Long categoryId;
 
-    @ApiModelProperty(value = "商品主图地址,* 数组,以逗号分隔,最多上传15张")
-    private String picUrls;
-
-    @ApiModelProperty(value = "排序字段")
-    private Integer sort;
-
-    @ApiModelProperty(value = "点赞初始人数")
-    private Integer likeCount;
-
-    @ApiModelProperty(value = "价格 单位使用:分")
-    private Integer price;
-
-    @ApiModelProperty(value = "库存数量")
-    private Integer quantity;
+    @ApiModelProperty(value = "商品品牌编号", example = "1")
+    private Long brandId;
 
     @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)")
     private Integer status;
 
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    @ApiModelProperty(value = "创建时间")
-    private Date[] createTime;
-
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
index 9db319fdc..222288770 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
@@ -1,7 +1,5 @@
 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.sku.vo.ProductSkuRespVO;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -9,9 +7,7 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
 import java.util.Date;
-import java.util.List;
 
-// TODO @Luowenfeng:这个类只返回 SPU 相关的信息,删除 skus、categoryIds、productPropertyViews;明细使用 SpuDetailRespVO 替代
 @ApiModel("管理后台 - 商品 SPU Response VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -24,18 +20,4 @@ public class ProductSpuRespVO extends ProductSpuBaseVO {
     @ApiModelProperty(value = "创建时间")
     private Date createTime;
 
-    /**
-     * SKU 数组
-     */
-    @ApiModelProperty(value = "sku 数组", example = "[{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":10}],\"price\":12,\"originalPrice\":32,\"costPrice\":22,\"barCode\":\"765670123123\",\"picUrl\":\"http://test.yudao.iocoder.cn/72938088f1ca8438837c3b51394aea43.jpg\",\"status\":0,\"id\":7,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":11}],\"price\":13,\"originalPrice\":33,\"costPrice\":23,\"barCode\":\"888788770999\",\"picUrl\":\"http://test.yudao.iocoder.cn/6b902c700e5d32e862b6fd9af2e1c0e4.jpg\",\"status\":0,\"id\":8,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":10}],\"price\":14,\"originalPrice\":34,\"costPrice\":24,\"barCode\":\"9999981212\",\"picUrl\":\"http://test.yudao.iocoder.cn/eddf3c79b1917160d94d05244e1f47da.jpg\",\"status\":0,\"id\":9,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":11}],\"price\":15,\"originalPrice\":35,\"costPrice\":25,\"barCode\":\"4444121212\",\"picUrl\":\"http://test.yudao.iocoder.cn/88ac3eb068ea9cfac4726879b2776ccf.jpg\",\"status\":0,\"id\":10,\"createTime\":1656683270000}]")
-    private List<ProductSkuRespVO> skus;
-
-    @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]")
-    private List<Long> categoryIds;
-
-    // TODO @芋艿:再琢磨下 这个 VO 类,其实变成 SpuRespVO 内嵌的 VO 类会更好一点;然后把 SpuRespVO 改成 SpuDetailSpuVO
-
-    @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<ProductPropertyViewRespVO> productPropertyViews;
-
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
index 52b82a2ea..9f7c46745 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.product.convert.property;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
 import org.mapstruct.Mapper;
@@ -24,10 +24,10 @@ public interface ProductPropertyConvert {
 
     ProductPropertyDO convert(ProductPropertyUpdateReqVO bean);
 
-    ProductPropertyAndValueRespVO convert(ProductPropertyDO bean);
+    ProductPropertyRespVO convert(ProductPropertyDO bean);
 
-    List<ProductPropertyAndValueRespVO> convertList(List<ProductPropertyDO> list);
+    List<ProductPropertyRespVO> convertList(List<ProductPropertyDO> list);
 
-    PageResult<ProductPropertyAndValueRespVO> convertPage(PageResult<ProductPropertyDO> page);
+    PageResult<ProductPropertyRespVO> convertPage(PageResult<ProductPropertyDO> page);
 
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
index 7450da653..bbb7e3d2c 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.product.convert.sku;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 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.ProductSpuDetailRespVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
@@ -31,4 +32,6 @@ public interface ProductSkuConvert {
 
     List<ProductSkuRespDTO> convertList02(List<ProductSkuDO> list);
 
+    List<ProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> list);
+
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
index 608b248fe..b3831491e 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
@@ -37,6 +37,10 @@ public class ProductPropertyDO extends BaseDO {
      * 枚举 {@link CommonStatusEnum}
      */
     private Integer status;
+    /**
+     * 备注
+     */
+    private String remark;
 
     // TODO 芋艿:rule;规格属性 (发布商品时,和 SKU 关联);规格参数(搜索商品时,与 Category 关联搜索)
 
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
index 007b95a4f..b75f0d592 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
@@ -44,5 +44,10 @@ public class ProductPropertyValueDO extends BaseDO {
      * 枚举 {@link CommonStatusEnum}
      */
     private Integer status;
+    /**
+     * 备注
+     *
+     */
+    private String remark;
 
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java
index 6c5fc7570..bef38d37a 100644
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java
@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.module.product.dal.mysql.property;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -16,17 +18,25 @@ import java.util.List;
 public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyValueDO> {
 
     // TODO @franky:方法名,selectListByXXX。mapper 的操作都是 crud
-    default List<ProductPropertyValueDO> getPropertyValueListByPropertyId(List<Long> propertyIds){
+    default List<ProductPropertyValueDO> getPropertyValueListByPropertyId(List<Long> propertyIds) {
         // TODO @franky:调用父类的 selectList
         return selectList(new LambdaQueryWrapperX<ProductPropertyValueDO>()
                 .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds));
     }
 
-    default void deletePropertyValueByPropertyId(Long propertyId){
+    default void deletePropertyValueByPropertyId(Long propertyId) {
         // TODO @franky:delete(new ) 即可
         LambdaQueryWrapperX<ProductPropertyValueDO> queryWrapperX = new LambdaQueryWrapperX<>();
         queryWrapperX.eq(ProductPropertyValueDO::getPropertyId, propertyId)
                 .eq(ProductPropertyValueDO::getDeleted, false);
         delete(queryWrapperX);
     }
+
+    default PageResult<ProductPropertyValueDO> selectPage(ProductPropertyValuePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<ProductPropertyValueDO>()
+                .eqIfPresent(ProductPropertyValueDO::getPropertyId, reqVO.getPropertyId())
+                .likeIfPresent(ProductPropertyValueDO::getName, reqVO.getName())
+                .eqIfPresent(ProductPropertyValueDO::getStatus, reqVO.getStatus())
+                .orderByDesc(ProductPropertyValueDO::getId));
+    }
 }
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
index 1755695cb..49243c8d4 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
@@ -18,11 +18,8 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
     default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<ProductSpuDO>()
                 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
-                .eqIfPresent(ProductSpuDO::getSellPoint, reqVO.getSellPoint())
                 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
-                .eqIfPresent(ProductSpuDO::getPicUrls, reqVO.getPicUrls())
                 .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
-                .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(ProductSpuDO::getSort));
     }
 
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 a87e15d70..03c200d64 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
@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.product.service.property;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*;
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
 
@@ -48,35 +48,35 @@ public interface ProductPropertyService {
 
     /**
      * 获得规格名称列表
-     *
-     * @param ids 编号
-     * @return 规格名称列表
+     * @param listReqVO 集合查询
+     * @return 规格名称集合
      */
-    List<ProductPropertyDO> getPropertyList(Collection<Long> ids);
-
-    /**
-     * 获得规格名称分页
-     *
-     * @param pageReqVO 分页查询
-     * @return 规格名称分页
-     */
-    PageResult<ProductPropertyDO> getPropertyPage(ProductPropertyPageReqVO pageReqVO);
+    List<ProductPropertyRespVO> getPropertyList(ProductPropertyListReqVO listReqVO);
 
     /**
      * 获取属性及属性值列表 分页
      * @param pageReqVO
      * @return
      */
-    PageResult<ProductPropertyAndValueRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO);
+    PageResult<ProductPropertyRespVO> getPropertyPage(ProductPropertyPageReqVO pageReqVO);
 
-    ProductPropertyAndValueRespVO getPropertyResp(Long id);
+
+    ProductPropertyRespVO getPropertyResp(Long id);
 
     /**
      * 根据规格属性编号的集合,获得对应的规格 + 规格值的集合
      *
      * @param ids 规格编号的集合
-     * @return 对应的规格 + 规格值的集合
+     * @return 对应的规格
      */
-    List<ProductPropertyAndValueRespVO> getPropertyAndValueList(Collection<Long> ids);
+    List<ProductPropertyRespVO> getPropertyList(Collection<Long> ids);
+
+
+    /**
+     * 获得规格名称列表
+     * @param listReqVO 集合查询
+     * @return 规格名称集合
+     */
+    List<ProductPropertyAndValueRespVO> getPropertyAndValueList(ProductPropertyListReqVO listReqVO);
 
 }
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 d48c8b1ff..9cce0d0b3 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
@@ -1,7 +1,10 @@
 package cn.iocoder.yudao.module.product.service.property;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
@@ -46,12 +49,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
         // 插入
         ProductPropertyDO property = ProductPropertyConvert.INSTANCE.convert(createReqVO);
         productPropertyMapper.insert(property);
-
-        //插入属性值
-        List<ProductPropertyValueCreateReqVO> propertyValueList = createReqVO.getPropertyValueList();
-        List<ProductPropertyValueDO> productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
-        productPropertyValueDOList.forEach(x-> x.setPropertyId(property.getId()));
-        productPropertyValueMapper.insertBatch(productPropertyValueDOList);
         // 返回
         return property.getId();
     }
@@ -64,12 +61,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
         // 更新
         ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO);
         productPropertyMapper.updateById(updateObj);
-        //更新属性值,先删后加
-        productPropertyValueMapper.deletePropertyValueByPropertyId(updateReqVO.getId());
-        List<ProductPropertyValueCreateReqVO> propertyValueList = updateReqVO.getPropertyValueList();
-        List<ProductPropertyValueDO> productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
-        productPropertyValueDOList.forEach(x-> x.setPropertyId(updateReqVO.getId()));
-        productPropertyValueMapper.insertBatch(productPropertyValueDOList);
     }
 
     @Override
@@ -94,31 +85,28 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     }
 
     @Override
-    public List<ProductPropertyDO> getPropertyList(Collection<Long> ids) {
-        return productPropertyMapper.selectBatchIds(ids);
+    public List<ProductPropertyRespVO> getPropertyList(ProductPropertyListReqVO listReqVO) {
+        return ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectList(new LambdaQueryWrapperX<ProductPropertyDO>()
+                .likeIfPresent(ProductPropertyDO::getName, listReqVO.getName())
+                .eqIfPresent(ProductPropertyDO::getStatus, listReqVO.getStatus())));
     }
 
     @Override
-    public PageResult<ProductPropertyDO> getPropertyPage(ProductPropertyPageReqVO pageReqVO) {
-        return productPropertyMapper.selectPage(pageReqVO);
-    }
-
-    @Override
-    public PageResult<ProductPropertyAndValueRespVO> getPropertyListPage(ProductPropertyPageReqVO pageReqVO) {
+    public PageResult<ProductPropertyRespVO> getPropertyPage(ProductPropertyPageReqVO pageReqVO) {
         //获取属性列表
         PageResult<ProductPropertyDO> pageResult = productPropertyMapper.selectPage(pageReqVO);
-        PageResult<ProductPropertyAndValueRespVO> propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
-        List<Long> propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyAndValueRespVO::getId).collect(Collectors.toList());
-
-        //获取属性值列表
-        List<ProductPropertyValueDO> productPropertyValueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
-        List<ProductPropertyValueRespVO> propertyValueRespVOList = ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueDOList);
-        //组装一对多
-        propertyRespVOPageResult.getList().forEach(x->{
-            Long propertyId = x.getId();
-            List<ProductPropertyValueRespVO> valueDOList = propertyValueRespVOList.stream().filter(v -> v.getPropertyId().equals(propertyId)).collect(Collectors.toList());
-            x.setValues(valueDOList);
-        });
+        PageResult<ProductPropertyRespVO> propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
+//        List<Long> propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyAndValueRespVO::getId).collect(Collectors.toList());
+//
+//        //获取属性值列表
+//        List<ProductPropertyValueDO> productPropertyValueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
+//        List<ProductPropertyValueRespVO> propertyValueRespVOList = ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueDOList);
+//        //组装一对多
+//        propertyRespVOPageResult.getList().forEach(x->{
+//            Long propertyId = x.getId();
+//            List<ProductPropertyValueRespVO> valueDOList = propertyValueRespVOList.stream().filter(v -> v.getPropertyId().equals(propertyId)).collect(Collectors.toList());
+//            x.setValues(valueDOList);
+//        });
         return propertyRespVOPageResult;
     }
 
@@ -127,25 +115,31 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     }
 
     @Override
-    public ProductPropertyAndValueRespVO getPropertyResp(Long id) {
+    public ProductPropertyRespVO getPropertyResp(Long id) {
         //查询规格
         ProductPropertyDO property = getProperty(id);
-        ProductPropertyAndValueRespVO propertyRespVO = ProductPropertyConvert.INSTANCE.convert(property);
-        //查询属性值
-        List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(Arrays.asList(id));
-        List<ProductPropertyValueRespVO> propertyValueRespVOS = ProductPropertyValueConvert.INSTANCE.convertList(valueDOList);
-        //组装
-        propertyRespVO.setValues(propertyValueRespVOS);
-        return propertyRespVO;
+        return ProductPropertyConvert.INSTANCE.convert(property);
     }
 
     @Override
-    public List<ProductPropertyAndValueRespVO> getPropertyAndValueList(Collection<Long> ids) {
-        List<ProductPropertyAndValueRespVO> productPropertyRespVO = ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids));
+    public List<ProductPropertyRespVO> getPropertyList(Collection<Long> ids) {
+        return ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids));
+    }
+
+    @Override
+    public List<ProductPropertyAndValueRespVO> getPropertyAndValueList(ProductPropertyListReqVO listReqVO) {
+        List<ProductPropertyRespVO> propertyList = getPropertyList(listReqVO);
+
         //查询属性值
-        List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.selectBatchIds(ids);
-        Map<Long, List<ProductPropertyValueDO>> propertyValuesMap = valueDOList.stream().collect(Collectors.groupingBy(ProductPropertyValueDO::getPropertyId));
-        productPropertyRespVO.forEach(p -> p.setValues(ProductPropertyValueConvert.INSTANCE.convertList(propertyValuesMap.get(p.getId()))));
-        return productPropertyRespVO;
+        List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId));
+        Map<Long, List<ProductPropertyValueRespVO>> valueDOMap = valueDOList.stream()
+                .map(ProductPropertyValueConvert.INSTANCE::convert)
+                .collect(Collectors.groupingBy(ProductPropertyValueRespVO::getPropertyId));
+        //组装
+        return propertyList.stream().map(m -> {
+            ProductPropertyAndValueRespVO productPropertyAndValueRespVO = BeanUtil.copyProperties(m, ProductPropertyAndValueRespVO.class);
+            productPropertyAndValueRespVO.setValues(valueDOMap.get(m.getId()));
+            return productPropertyAndValueRespVO;
+        }).collect(Collectors.toList());
     }
 }
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
new file mode 100644
index 000000000..4d2f27ee2
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java
@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.product.service.property;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author LuoWenFeng
+ */
+public interface ProductPropertyValueService {
+
+    /**
+     * 创建规格值
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO);
+
+    /**
+     * 更新规格值
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO);
+
+    /**
+     * 删除规格值
+     *
+     * @param id 编号
+     */
+    void deletePropertyValue(Long id);
+
+    /**
+     * 获得规格值
+     *
+     * @param id 编号
+     * @return 规格名称
+     */
+    ProductPropertyValueRespVO getPropertyValue(Long id);
+
+    /**
+     * 获得规格值
+     *
+     * @param id 编号
+     * @return 规格名称
+     */
+    List<ProductPropertyValueRespVO> getPropertyValueListByPropertyId(List<Long> id);
+
+    /**
+     * 获取规格值 分页
+     *
+     * @param pageReqVO 查询条件
+     * @return
+     */
+    PageResult<ProductPropertyValueRespVO> getPropertyValueListPage(ProductPropertyValuePageReqVO pageReqVO);
+}
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
new file mode 100644
index 000000000..e62270e8b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java
@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.product.service.property;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO;
+import cn.iocoder.yudao.module.product.convert.propertyvalue.ProductPropertyValueConvert;
+import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
+import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyValueMapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author LuoWenFeng
+ */
+@Service
+@Validated
+public class ProductPropertyValueServiceImpl implements ProductPropertyValueService {
+
+    @Resource
+    private ProductPropertyValueMapper productPropertyValueMapper;
+
+    @Override
+    public Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO) {
+        ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(createReqVO);
+        productPropertyValueMapper.insert(convert);
+        return convert.getId();
+    }
+
+    @Override
+    public void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO) {
+        ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO);
+        productPropertyValueMapper.updateById(convert);
+    }
+
+    @Override
+    public void deletePropertyValue(Long id) {
+        productPropertyValueMapper.deleteById(id);
+    }
+
+    @Override
+    public ProductPropertyValueRespVO getPropertyValue(Long id) {
+        ProductPropertyValueDO productPropertyValueDO = productPropertyValueMapper.selectOne(new LambdaQueryWrapper<ProductPropertyValueDO>()
+                .eq(ProductPropertyValueDO::getId, id));
+        return ProductPropertyValueConvert.INSTANCE.convert(productPropertyValueDO);
+    }
+
+    @Override
+    public List<ProductPropertyValueRespVO> getPropertyValueListByPropertyId(List<Long> id) {
+        return ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueMapper.selectList("property_id", id));
+    }
+
+    @Override
+    public PageResult<ProductPropertyValueRespVO> getPropertyValueListPage(ProductPropertyValuePageReqVO pageReqVO) {
+        return ProductPropertyValueConvert.INSTANCE.convertPage(productPropertyValueMapper.selectPage(pageReqVO));
+    }
+}
diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
index bf8dab778..96cea6171 100755
--- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
+++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.product.service.sku;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO;
+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.ProductSkuBaseVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
@@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
 import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
 import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
+import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -39,6 +40,9 @@ public class ProductSkuServiceImpl implements ProductSkuService {
     @Resource
     private ProductPropertyService productPropertyService;
 
+    @Resource
+    private ProductPropertyValueService productPropertyValueService;
+
     @Override
     public void deleteSku(Long id) {
         // 校验存在
@@ -71,17 +75,15 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         }
 
         // 1、校验规格属性存在
-        // TODO @Luowenfeng:stream 的写法;不用改哈,就是说下可以酱紫写;
         Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null).flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性
                 .map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toSet()); // 将每个 Property 转换成对应的 propertyId,最后形成集合
-        List<ProductPropertyAndValueRespVO> propertyAndValueList = productPropertyService.getPropertyAndValueList(propertyIds);
-        if (propertyAndValueList.size() == propertyIds.size()) {
+        List<ProductPropertyRespVO> propertyList = productPropertyService.getPropertyList(propertyIds);
+        if (propertyList.size() != propertyIds.size()) {
             throw exception(PROPERTY_NOT_EXISTS);
         }
 
         // 2. 校验,一个 SKU 下,没有重复的规格。校验方式是,遍历每个 SKU ,看看是否有重复的规格 propertyId
-        Map<Long, ProductPropertyValueRespVO> propertyValueMap = propertyAndValueList.stream().filter(p -> p.getValues() != null).flatMap(p -> p.getValues().stream())
-                .collect(Collectors.toMap(ProductPropertyValueRespVO::getId, value -> value)); // KEY:规格属性值的编号
+        Map<Long, ProductPropertyValueRespVO> propertyValueMap = CollectionUtils.convertMap(productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(propertyIds)), ProductPropertyValueRespVO::getId);
         skus.forEach(sku -> {
             Set<Long> skuPropertyIds = CollectionUtils.convertSet(sku.getProperties(), propertyItem -> propertyValueMap.get(propertyItem.getValueId()).getPropertyId());
             if (skuPropertyIds.size() != sku.getProperties().size()) {
@@ -100,8 +102,7 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         // 4. 最后校验,每个 Sku 之间不是重复的
         Set<Set<Long>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
         for (ProductSkuCreateOrUpdateReqVO sku : skus) {
-            // TODO @Luowenfeng:可以使用 CollectionUtils.convertSet(),简化下面的 stream 操作
-            if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复
+            if (!skuAttrValues.add(CollectionUtils.convertSet(sku.getProperties(), ProductSkuBaseVO.Property::getValueId))) { // 添加失败,说明重复
                 throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
             }
         }
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 e5affa8d2..6a12dcb52 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
@@ -1,10 +1,7 @@
 package cn.iocoder.yudao.module.product.service.spu;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;
-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.admin.spu.vo.ProductSpuPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
@@ -42,6 +39,14 @@ public interface ProductSpuService {
      */
     void deleteSpu(Long id);
 
+    /**
+     * 获得商品spu详情
+     *
+     * @param id 编号
+     * @return 商品spu
+     */
+    ProductSpuDetailRespVO getSpuDetail(Long id);
+
     /**
      * 获得商品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 847301ba8..9fb13411b 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,17 +1,15 @@
 package cn.iocoder.yudao.module.product.service.spu;
 
+import cn.hutool.core.bean.BeanUtil;
 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.property.ProductPropertyAndValueRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
 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.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.admin.spu.vo.*;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
@@ -22,6 +20,7 @@ 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.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -55,6 +54,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
     @Resource
     private ProductPropertyService productPropertyService;
 
+    @Resource
+    private ProductPropertyValueService productPropertyValueService;
+
     @Resource
     private ProductBrandService brandService;
 
@@ -125,28 +127,31 @@ public class ProductSpuServiceImpl implements ProductSpuService {
 
     @Override
     // TODO @芋艿:需要再 review 下
-    public ProductSpuRespVO getSpu(Long id) {
+    public ProductSpuDetailRespVO getSpuDetail(Long id) {
         ProductSpuDO spu = ProductSpuMapper.selectById(id);
-        ProductSpuRespVO spuVO = ProductSpuConvert.INSTANCE.convert(spu);
-        if (null != spuVO) {
-            List<ProductSkuRespVO> skuReqs = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuId(id));
-            spuVO.setSkus(skuReqs);
-            List<ProductSkuRespVO.Property> properties = new ArrayList<>();
+        ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class);
+        if (null != spu) {
+            List<ProductSpuDetailRespVO.Sku> skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id));
+            respVO.setSkus(skuReqs);
             // 组合 sku 规格属性
             if(spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
-                for (ProductSkuRespVO productSkuRespVO : skuReqs) {
+                List<ProductSkuRespVO.Property> properties = new ArrayList<>();
+                for (ProductSpuDetailRespVO.Sku productSkuRespVO : skuReqs) {
                     properties.addAll(productSkuRespVO.getProperties());
                 }
                 Map<Long, List<ProductSkuBaseVO.Property>> propertyMaps = properties.stream().collect(Collectors.groupingBy(ProductSkuBaseVO.Property::getPropertyId));
-                List<ProductPropertyAndValueRespVO> propertyAndValueList = productPropertyService.getPropertyAndValueList(new ArrayList<>(propertyMaps.keySet()));
+
+                List<ProductPropertyValueRespVO> propertyValueList = productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(propertyMaps.keySet()));
+                List<ProductPropertyRespVO> propertyList = productPropertyService.getPropertyList(new ArrayList<>(propertyMaps.keySet()));
                 // 装载组装过后的属性
                 List<ProductPropertyViewRespVO> productPropertyViews = new ArrayList<>();
-                propertyAndValueList.forEach(p -> {
+                propertyList.forEach(p -> {
                     ProductPropertyViewRespVO productPropertyViewRespVO = new ProductPropertyViewRespVO();
                     productPropertyViewRespVO.setPropertyId(p.getId());
                     productPropertyViewRespVO.setName(p.getName());
                     List<ProductPropertyViewRespVO.Tuple2> propertyValues = new ArrayList<>();
-                    Map<Long, ProductPropertyValueRespVO> propertyValueMaps = p.getValues().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv));
+                    // 转换成map是为了能快速获取
+                    Map<Long, ProductPropertyValueRespVO> propertyValueMaps = CollectionUtils.convertMap(propertyValueList, ProductPropertyValueRespVO::getId);
                     propertyMaps.get(p.getId()).forEach(pv -> {
                         ProductPropertyViewRespVO.Tuple2 tuple2 = new ProductPropertyViewRespVO.Tuple2(pv.getValueId(), propertyValueMaps.get(pv.getValueId()).getName());
                         propertyValues.add(tuple2);
@@ -154,12 +159,12 @@ public class ProductSpuServiceImpl implements ProductSpuService {
                     productPropertyViewRespVO.setPropertyValues(propertyValues.stream().distinct().collect(Collectors.toList()));
                     productPropertyViews.add(productPropertyViewRespVO);
                 });
-                spuVO.setProductPropertyViews(productPropertyViews);
+                respVO.setProductPropertyViews(productPropertyViews);
             }
             // 组合分类
-            if (null != spuVO.getCategoryId()) {
+            if (null != respVO.getCategoryId()) {
                 LinkedList<Long> categoryArray = new LinkedList<>();
-                Long parentId = spuVO.getCategoryId();
+                Long parentId = respVO.getCategoryId();
                 categoryArray.addFirst(parentId);
                 while (parentId != 0) {
                     parentId = categoryService.getCategory(parentId).getParentId();
@@ -167,10 +172,15 @@ public class ProductSpuServiceImpl implements ProductSpuService {
                         categoryArray.addFirst(parentId);
                     }
                 }
-                spuVO.setCategoryIds(categoryArray);
+                respVO.setCategoryIds(categoryArray);
             }
         }
-        return spuVO;
+        return respVO;
+    }
+
+    @Override
+    public ProductSpuRespVO getSpu(Long id) {
+        return ProductSpuConvert.INSTANCE.convert(ProductSpuMapper.selectById(id));
     }
 
     @Override
@@ -182,8 +192,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
     public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
         PageResult<ProductSpuRespVO> spuVOs = ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO));
         // 查询 sku 的信息
-        List<Long> spuIds = spuVOs.getList().stream().map(ProductSpuRespVO::getId).collect(Collectors.toList());
-        List<ProductSkuRespVO> skus = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuIds(spuIds));
+//        List<Long> spuIds = spuVOs.getList().stream().map(ProductSpuRespVO::getId).collect(Collectors.toList());
+//        List<ProductSkuRespVO> skus = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuIds(spuIds));
         // TODO @franky:使用 CollUtil 里的方法替代哈
         // TODO 芋艿:临时注释
 //        Map<Long, List<ProductSkuRespVO>> skuMap = skus.stream().collect(Collectors.groupingBy(ProductSkuRespVO::getSpuId));
diff --git a/yudao-ui-admin/src/api/mall/product/property.js b/yudao-ui-admin/src/api/mall/product/property.js
index 58ae320f6..5046b9233 100644
--- a/yudao-ui-admin/src/api/mall/product/property.js
+++ b/yudao-ui-admin/src/api/mall/product/property.js
@@ -43,6 +43,25 @@ export function getPropertyPage(query) {
   })
 }
 
+// 获得规格名称列表
+export function getPropertyList(query) {
+  return request({
+    url: '/product/property/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 获得规格名称列表
+export function getPropertyListAndValue(query) {
+  return request({
+    url: '/product/property/listAndValue',
+    method: 'get',
+    params: query
+  })
+}
+
+
 // 导出规格名称 Excel
 export function exportPropertyExcel(query) {
   return request({
@@ -52,3 +71,49 @@ export function exportPropertyExcel(query) {
     responseType: 'blob'
   })
 }
+
+// ------------------------ 规格名称值 -------------------
+
+// 获得规格名称值分页
+export function getPropertyValuePage(query) {
+  return request({
+    url: '/product/property/value/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 获得规格名称值
+export function getPropertyValue(id) {
+  return request({
+    url: '/product/property/value/get?id=' + id,
+    method: 'get'
+  })
+}
+
+
+// 创建规格名称值
+export function createPropertyValue(data) {
+  return request({
+    url: '/product/property/value/create',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新规格名称值
+export function updatePropertyValue(data) {
+  return request({
+    url: '/product/property/value/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除规格名称
+export function deletePropertyValue(id) {
+  return request({
+    url: '/product/property/value/delete?id=' + id,
+    method: 'delete'
+  })
+}
diff --git a/yudao-ui-admin/src/api/mall/product/spu.js b/yudao-ui-admin/src/api/mall/product/spu.js
index fc4a545f2..662f1ab61 100644
--- a/yudao-ui-admin/src/api/mall/product/spu.js
+++ b/yudao-ui-admin/src/api/mall/product/spu.js
@@ -34,6 +34,14 @@ export function getSpu(id) {
   })
 }
 
+// 获得商品spu详情
+export function getSpuDetail(id) {
+  return request({
+    url: '/product/spu/get/detail?id=' + id,
+    method: 'get'
+  })
+}
+
 // 获得商品spu分页
 export function getSpuPage(query) {
   return request({
diff --git a/yudao-ui-admin/src/router/index.js b/yudao-ui-admin/src/router/index.js
index 7446a2f2b..3f488e5de 100644
--- a/yudao-ui-admin/src/router/index.js
+++ b/yudao-ui-admin/src/router/index.js
@@ -96,6 +96,17 @@ export const constantRoutes = [
         meta: {title: '字典数据', icon: '', activeMenu: '/system/dict'}
       }
     ]
+  }, {
+    path: '/property',
+    component: Layout,
+    hidden: true,
+    children: [{
+        path: 'value/:propertyId(\\d+)',
+        component: (resolve) => require(['@/views/mall/product/property/value'], resolve),
+        name: 'PropertyValue',
+        meta: {title: '规格数据', icon: '', activeMenu: '/mall/property'}
+      }
+    ]
   }, {
     path: '/job',
     component: Layout,
diff --git a/yudao-ui-admin/src/views/mall/product/property/index.vue b/yudao-ui-admin/src/views/mall/product/property/index.vue
index 0768ba207..36c1ab011 100644
--- a/yudao-ui-admin/src/views/mall/product/property/index.vue
+++ b/yudao-ui-admin/src/views/mall/product/property/index.vue
@@ -6,7 +6,7 @@
       <el-form-item label="规格名称" prop="name">
         <el-input v-model="queryParams.name" placeholder="请输入规格名称" clearable @keyup.enter.native="handleQuery"/>
       </el-form-item>
-      <el-form-item label="开启状态" prop="status">
+      <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable size="small">
           <el-option v-for="dict in this.getDictDatas(DICT_TYPE.COMMON_STATUS)"
                      :key="dict.value" :label="dict.label" :value="dict.value"/>
@@ -33,12 +33,14 @@
 
     <!-- 列表 -->
     <el-table v-loading="loading" :data="list">
-      <el-table-column label="规格名称" align="center" prop="name" />
-       <el-table-column label="规格名称" align="center" prop="propertyValueList">
+      <el-table-column label="规格id" align="center" prop="id" />
+      <el-table-column label="规格名称" align="center" :show-overflow-tooltip="true">
         <template slot-scope="scope">
-          <span>{{formatList(scope.row.propertyValueList)}}</span>
+          <router-link :to="'/property/value/' + scope.row.id" class="link-type">
+            <span>{{ scope.row.name }}</span>
+          </router-link>
         </template>
-       </el-table-column>
+      </el-table-column>
       <el-table-column label="开启状态" align="center" prop="status">
         <template slot-scope="scope">
           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
@@ -49,6 +51,7 @@
           <span>{{ parseTime(scope.row.createTime) }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="备注" align="center" prop="left" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
@@ -65,6 +68,9 @@
     <!-- 对话框(添加 / 修改) -->
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="规格id" prop="id" v-if="form.id != null">
+          <el-input v-model="form.id" disabled />
+        </el-form-item>
         <el-form-item label="规格名称" prop="name">
           <el-input v-model="form.name" placeholder="请输入规格名称" />
         </el-form-item>
@@ -75,26 +81,9 @@
             </el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="属性值">
-          <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="addPropertyValue()">添加</el-button>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="备注" />
         </el-form-item>
-        <el-form-item
-            v-for="(domain, index) in form.propertyValueList"
-            :key="domain.key"
-            :prop="'propertyValueList.' + index + '.name'"
-            :rules="{
-              required: true, message: '属性值不能为空', trigger: 'blur'
-            }"
-          >
-            <el-row>
-              <el-col :span="18">
-                <el-input v-model="domain.name" size="mini"></el-input>
-              </el-col>
-              <el-col :span="6">
-                <el-button style="margin-left: 20px;" size="mini" @click.prevent="removePropertyValue(domain)">删除</el-button>
-              </el-col>
-            </el-row>
-          </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -139,12 +128,17 @@ export default {
       form: {
         name:'',
         status:'',
-        propertyValueList: [{
-          name: ''
-        }],
+        remark:"",
+        id: null,
       },
       // 表单校验
       rules: {
+        name: [
+          { required: true, message: "规格不能为空", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "blur" }
+        ]
       }
     };
   },
@@ -170,12 +164,10 @@ export default {
     /** 表单重置 */
     reset() {
       this.form = {
-        id: undefined,
-        name: undefined,
-        status: undefined,
-        propertyValueList: [{
-          name: ''
-        }]
+        name:'',
+        status:'',
+        remark:"",
+        id: null,
       };
       this.resetForm("form");
     },
@@ -253,27 +245,6 @@ export default {
           this.exportLoading = false;
         }).catch(() => {});
     },
-    removePropertyValue(item) {
-      var index = this.form.propertyValueList.indexOf(item)
-      if (index !== -1) {
-        this.form.propertyValueList.splice(index, 1)
-      }
-    },
-    addPropertyValue() {
-      this.form.propertyValueList.push({
-        name: ''
-      });
-    },
-    formatList(list) {
-      let str = ''
-      for (var i = 0; i < list.length; i++) {
-        str += list[i].name;
-        if(i != list.length-1){
-          str+="/";
-        }
-      }
-      return str
-    }
   }
 };
 </script>
diff --git a/yudao-ui-admin/src/views/mall/product/spu/index.vue b/yudao-ui-admin/src/views/mall/product/spu/index.vue
index 5817a8cfb..02f430d9c 100644
--- a/yudao-ui-admin/src/views/mall/product/spu/index.vue
+++ b/yudao-ui-admin/src/views/mall/product/spu/index.vue
@@ -9,20 +9,22 @@
       <el-form-item label="商品名称" prop="name">
         <el-input v-model="queryParams.name" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
       </el-form-item>
-      <el-form-item label="分类id" prop="categoryId">
-        <el-input v-model="queryParams.categoryId" placeholder="请输入分类id" clearable @keyup.enter.native="handleQuery"/>
+
+      <el-form-item label="商品编码" prop="code">
+        <el-input v-model="queryParams.code" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
       </el-form-item>
-      <el-form-item label="状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择上下架状态" clearable size="small">
-          <el-option label="请选择字典生成" value="" />
-          <el-option label="上架" value="0" />
-          <el-option label="下架" value="1" />
+
+      <el-form-item label="商品分类" prop="categoryId">
+        <el-cascader v-model="queryParams.categoryIds" placeholder="请输入商品分类"
+                         :options="categoryList" :props="propName" clearable ref="category" />
+      </el-form-item>
+
+      <el-form-item label="商品品牌" prop="brandId">
+        <el-select v-model="queryParams.brandId" placeholder="请输入商品品牌" clearable @keyup.enter.native="handleQuery">
+          <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
         </el-select>
       </el-form-item>
-      <el-form-item label="创建时间">
-        <el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
-          range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"/>
-      </el-form-item>
+
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
@@ -46,33 +48,35 @@
        1. 字段:商品信息、价格、库存、销量、排序、创建时间、状态、操作;
        2. tab 分成全部、销售中、仓库中、预警中
        -->
-      <el-table-column label="主键" align="center" prop="id" />
-      <el-table-column label="商品名称" align="center" prop="name" />
-      <el-table-column label="分类id" align="center" prop="categoryId" />
-      <el-table-column label="商品主图地址" align="center" prop="picUrls">
-        <template slot-scope="scope">
-          <img
-            v-if="scope.row.picUrls"
-            :src="scope.row.picUrls[0]"
-            alt="分类图片"
-            class="img-height"
-          />
-        </template>
-      </el-table-column>
-      <el-table-column label="排序字段" align="center" prop="sort" />
-      <el-table-column label="点击量" align="center" prop="clickCount" />
-      <el-table-column label="价格区间" align="center" prop="price" />
-      <el-table-column label="总库存" align="center" prop="totalStock" />
-      <el-table-column label="状态" align="center" prop="status">
-        <template slot-scope="scope">
-          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
+      <el-table-column label="商品信息" align="center" width="260">
+
+        <template slot-scope="scope" >
+          <div class="product-info">
+            <img
+              v-if="scope.row.picUrls"
+              :src="scope.row.picUrls[0]"
+              alt="分类图片"
+              class="img-height"
+            />
+            <div class="message">{{scope.row.name}}</div>
+          </div>
         </template>
       </el-table-column>
+      <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
+      <el-table-column label="库存" align="center" prop="totalStock" />
+      <el-table-column label="销量" align="center" prop="salesCount" />
+      <el-table-column label="排序" align="center" prop="sort" />
       <el-table-column label="创建时间" align="center" prop="createTime" width="180">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.createTime) }}</span>
         </template>
       </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
@@ -87,7 +91,7 @@
                 @pagination="getList"/>
 
     <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body destroy-on-close :close-on-click-modal="false" >
-      <save @closeDialog="closeDialog" :type="dialogType" :obj="dialogObj" v-if="open" />
+      <save @closeDialog="closeDialog" :obj="dialogObj" v-if="open" />
     </el-dialog>
   </div>
 </template>
@@ -97,7 +101,8 @@ import {
   deleteSpu,
   getSpuPage,
 } from "@/api/mall/product/spu";
-
+import {getProductCategoryList} from "@/api/mall/product/category";
+import {getBrandList} from "@/api/mall/product/brand";
 import Editor from "@/components/Editor";
 import ImageUpload from "@/components/ImageUpload";
 import save  from "./save";
@@ -114,20 +119,12 @@ export default {
   },
   data() {
     return {
-      tableLeftTitles: [],
-      dbTagValues: [],
-      allhistoryTags: [],
-      unUseTags: [],
-      propertyPageList: [],
-      isShowTagInput: false,
-      addTagInput: {
-        name: "",
-        propertyId: "",
-        selectValues: [],
-        selectValueIds: [],
-        selectObect: [],
+      propName: {
+        checkStrictly: true,
+        label: "name",
+        value: "id",
       },
-      skuTags: [],
+      brandList: [],
       categoryList: [],
       // 遮罩层
       loading: true,
@@ -143,8 +140,6 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
-      // 弹出层类型
-      dialogType: "add",
       // 弹出层参数
       dialogObj:{},
       dateRangeCreateTime: [],
@@ -153,14 +148,10 @@ export default {
         pageNo: 1,
         pageSize: 10,
         name: null,
-        sellPoint: null,
-        description: null,
+        code: null,
+        categoryIds: [],
         categoryId: null,
-        picUrls: null,
-        sort: null,
-        likeCount: null,
-        price: null,
-        quantity: null,
+        brandId: null,
         status: null,
       },
       tagIndex: 0,
@@ -168,13 +159,30 @@ export default {
   },
   created() {
     this.getList();
+    this.getListCategory()
+    this.getListBrand()
   },
   methods: {
+    /** 查询分类列表 */
+    getListCategory() {
+      // 执行查询
+      getProductCategoryList().then((response) => {
+        this.categoryList = this.handleTree(response.data, "id", "parentId");
+      });
+    },
+    /** 查询品牌列表 */
+    getListBrand() {
+      // 执行查询
+      getBrandList().then((response) => {
+        this.brandList = response.data;
+      });
+    },
     /** 查询列表 */
     getList() {
       this.loading = true;
       // 处理查询参数
       let params = { ...this.queryParams };
+      params.categoryId =  this.queryParams.categoryIds[ this.queryParams.categoryIds.length - 1];
       this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime");
       // 执行查询
       getSpuPage(params).then((response) => {
@@ -200,27 +208,26 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.dateRangeCreateTime = [];
+      this.$refs.category.$refs.panel.checkedValue = [];//也可以是指定的值,默认返回值是数组,也可以返回单个值
+    this.$refs.category.$refs.panel.activePath = [];
+    this.$refs.category.$refs.panel.syncActivePath();
+      this.queryParams.categoryIds = [];
       this.resetForm("queryForm");
       this.handleQuery();
     },
     /** 新增按钮操作 */
     handleAdd() {
-      this.dialogType = "add";
       this.dialogObj={};
       this.open = true;
       this.title = "添加商品spu";
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-      this.dialogType = "upd";
       this.dialogObj.id = row.id;
       this.open = true;
-      console.log("修改")
       this.title = "修改商品spu";
     },
     closeDialog(){
-      console.log("关闭")
-      this.dialogType = "add";
       this.dialogObj={};
       this.open = false;
       this.getList()
@@ -238,6 +245,9 @@ export default {
           this.$modal.msgSuccess("删除成功");
         })
         .catch(() => {});
+    },
+    unitConversion(row, column, cellValue){
+      return this.divide(cellValue, 100);
     }
   },
 };
@@ -262,8 +272,25 @@ export default {
     vertical-align: bottom;
   }
 
-  .img-height {
-    height: 65px;
+  .product-info{
+    display: flex;
+    .img-height {
+      height: 50px;
+      width: 50px;
+    }
+    .message{
+      margin-left: 10px;
+      text-overflow: ellipsis;
+      display: -webkit-box;
+      -webkit-line-clamp: 2;
+      word-break: break-all;
+      -webkit-box-orient: vertical;
+      white-space: normal;
+      overflow: hidden;
+      height: 50px;
+      line-height: 25px;
+    }
   }
+
 }
 </style>
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 c0972777e..b32a1e12f 100644
--- a/yudao-ui-admin/src/views/mall/product/spu/save.vue
+++ b/yudao-ui-admin/src/views/mall/product/spu/save.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="container">
-    <el-tabs v-model="activeName" class="tabs"  :before-leave="confirmLeave">
+    <el-tabs v-model="activeName" class="tabs"  >
       <!-- 基础设置 -->
       <el-tab-pane label="基础设置" name="base">
         <el-form ref="base" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
@@ -12,7 +12,7 @@
           </el-form-item>
           <!-- TODO @Luowenfeng:商品主图,80 x 80 即可 -->
           <el-form-item label="商品主图" prop="picUrls">
-            <ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10"/>
+            <ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10" />
           </el-form-item>
           <!-- TODO @Luowenfeng:商品视频 -->
           <el-form-item label="商品品牌" prop="brandId">
@@ -38,10 +38,7 @@
         <el-form ref="rates" :model="ratesForm" :rules="rules">
           <el-form-item label="启用多规格">
             <!-- TODO @Luowenfeng:改成开关的按钮;关闭,单规格;开启,多规格 -->
-            <el-radio-group v-model="ratesForm.spec" @change="changeRadio">
-              <el-radio :label="1">单规格</el-radio>
-              <el-radio :label="2">多规格</el-radio>
-            </el-radio-group>
+            <el-switch v-model="activeSwitch" @change="changeRadio"></el-switch>
           </el-form-item>
 
           <!-- 动态添加规格属性 -->
@@ -67,7 +64,7 @@
           <!-- 规格明细 -->
           <el-form-item label="规格明细">
             <el-table :data="ratesForm.rates" border style="width: 100%" ref="ratesTable">
-              <template v-if="ratesForm.spec == 2">
+              <template v-if="this.activeSwitch">
                 <el-table-column :key="index" v-for="(item, index) in dynamicSpec.filter(v => v.specName !== undefined)"
                                  :label="item.specName">
                   <template slot-scope="scope">
@@ -81,7 +78,7 @@
                                style="width: 100px; height: 50px"/>
                 </template>
               </el-table-column>
-              <template v-if="ratesForm.spec === 2">
+              <template v-if="this.activeSwitch">
                <el-table-column label="sku名称" :render-header="addRedStar" key="91">
                   <template slot-scope="scope">
                     <el-form-item :prop="'rates.'+ scope.$index + '.name'" :rules="[{required: true, trigger: 'change'}]">
@@ -142,7 +139,7 @@
                   <el-input v-model="scope.row.barCode"></el-input>
                 </template>
               </el-table-column>
-               <template v-if="ratesForm.spec === 2">
+               <template v-if="this.activeSwitch">
                 <el-table-column fixed="right" label="操作" width="50" key="100">
                   <template slot-scope="scope">
                     <el-button @click="scope.row.status = 1" type="text" size="small" v-show="scope.row.status == undefined || scope.row.status == 0 ">禁用</el-button>
@@ -153,7 +150,6 @@
             </el-table>
           </el-form-item>
           <el-form-item label="虚拟销量" prop="virtualSalesCount">
-            <!-- TODO @Luowenfeng:使用 input 类型即可 -->
             <el-input v-model="baseForm.virtualSalesCount" placeholder="请输入虚拟销量" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
           </el-form-item>
         </el-form>
@@ -196,8 +192,8 @@
 
 import {getBrandList} from "@/api/mall/product/brand";
 import {getProductCategoryList} from "@/api/mall/product/category";
-import {createSpu, updateSpu, getSpu} from "@/api/mall/product/spu";
-import {getPropertyPage,} from "@/api/mall/product/property";
+import {createSpu, updateSpu, getSpuDetail} from "@/api/mall/product/spu";
+import {getPropertyListAndValue,} from "@/api/mall/product/property";
 import Editor from "@/components/Editor";
 import ImageUpload from "@/components/ImageUpload";
 
@@ -206,16 +202,13 @@ export default {
     Editor,
     ImageUpload
   },
-  props:{//props列表
-    type:{
-      type:String,
-      default:"add" //定义参数默认值
-    },
+  props:{
     obj: Object
   },
   data() {
     return {
-      activeName: "base", // TODO @Luowenfeng:切换时,不需要校验通过
+      activeSwitch: false,
+      activeName: "base",
       propName: {
         checkStrictly: true,
         label: "name",
@@ -271,7 +264,7 @@ export default {
     this.getListBrand();
     this.getListCategory();
     this.getPropertyPageList();
-    if(this.type == 'upd'){
+    if(this.obj.id != null){
       this.updateType(this.obj.id)
     }
   },
@@ -280,14 +273,6 @@ export default {
         this.dynamicSpec.splice(index, 1);
         this.changeRadio()
     },
-    async confirmLeave(active, old){
-      await this.$refs[old].validate((valid) => {
-        console.log(valid)
-        if (!valid) {
-          return reject();
-        }
-      });
-    },
     // 必选标识
     addRedStar(h, { column }) {
       return [
@@ -296,13 +281,13 @@ export default {
       ];
     },
     changeRadio() {
+      this.activeSwitch ? this.ratesForm.spec = 2:  this.ratesForm.spec = 1;
       this.$refs.ratesTable.doLayout();
       if (this.ratesForm.spec == 1) {
         this.ratesForm.rates = [{}]
       } else {
         this.ratesForm.rates = []
         if (this.dynamicSpec.length > 0) {
-          console.log( this.dynamicSpec)
           this.buildRatesFormRates()
         }
       }
@@ -316,6 +301,7 @@ export default {
           last.forEach(par1 => {
             current.forEach(par2 => {
               let v
+              // 当两个对象合并时,需使用[1,2]方式生成数组,而当数组和对象合并时,需使用concat
               if (par1 instanceof Array) {
                 v = par1.concat(par2)
               } else {
@@ -327,7 +313,12 @@ export default {
           return array;
         })
         .forEach(v => {
-          rates.push({spec: v, status: 0, name: Array.of(v).join()})
+          let spec = v;
+          // 当v为单个规格项时,会变成字符串。造成表格只截取第一个字符串,而不是数组的第一个元素
+          if (typeof v == 'string') {
+            spec = Array.of(v)
+          }
+          rates.push({spec: spec, status: 0, name: Array.of(v).join()})
         });
       this.ratesForm.rates = rates
     },
@@ -363,7 +354,7 @@ export default {
       })
 
       // 动态规格调整字段
-      if (this.ratesForm.spec == 2) {
+      if (this.activeSwitch) {
         rates.forEach(r => {
           let properties = []
             Array.of(r.spec).forEach(s => {
@@ -396,43 +387,42 @@ export default {
       }else{
         form.picUrls = Array.of(form.picUrls)
       }
-      console.log(rates)
       form.skus = rates;
       form.specType = this.ratesForm.spec;
       form.categoryId = form.categoryIds[this.baseForm.categoryIds.length - 1];
 
-
       if(form.id == null){
         createSpu(form).then((response) => {
           this.$modal.msgSuccess("新增成功");
+          this.$emit("closeDialog");
         })
       }else{
         updateSpu(form).then((response) => {
           this.$modal.msgSuccess("修改成功");
+          this.$emit("closeDialog");
         })
       }
       });
-      this.$emit("closeDialog");
+
     },
     /** 查询规格 */
     getPropertyPageList() {
       // 执行查询
-      getPropertyPage().then((response) => {
-        this.propertyPageList = response.data.list;
+      getPropertyListAndValue().then((response) => {
+        this.propertyPageList = response.data;
       });
     },
+    // 添加规格项目
     changeSpec(val) {
       let obj = this.propertyPageList.find(o => o.id == val);
-      let dynamicSpec = this.dynamicSpec;
-      let spec = dynamicSpec.find(o => o.specId == val)
+      let spec = this.dynamicSpec.find(o => o.specId == val)
       spec.specId = obj.id;
       spec.specName = obj.name;
-      spec.specValue = obj.propertyValueList;
-      this.dynamicSpec = dynamicSpec;
+      spec.specValue = obj.values;
       this.buildRatesFormRates();
     },
     updateType(id){
-        getSpu(id).then((response) =>{
+      getSpuDetail(id).then((response) =>{
             let data = response.data;
             this.baseForm.id=data.id;
             this.baseForm.name=data.name;
@@ -452,6 +442,7 @@ export default {
               r.costPrice = this.divide(r.costPrice, 100)
             })
             if(this.ratesForm.spec == 2){
+              this.activeSwitch = true;
               data.productPropertyViews.forEach(p=>{
                 let obj = {};
                 obj.specId = p.propertyId;