luowenfeng 2 лет назад
Родитель
Сommit
31f5b27d01
18 измененных файлов с 142 добавлено и 158 удалено
  1. 2 0
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
  2. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java
  3. 1 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java
  4. 5 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java
  5. 7 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java
  6. 9 8
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java
  7. 6 9
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
  8. 6 9
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
  9. 6 10
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java
  10. 19 40
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java
  11. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java
  12. 11 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java
  13. 1 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
  14. 4 12
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
  15. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
  16. 19 19
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
  17. 19 19
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
  18. 24 22
      yudao-ui-admin/src/views/mall/product/spu/save.vue

+ 2 - 0
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java

@@ -24,9 +24,11 @@ public interface ErrorCodeConstants {
 
     // ========== 商品规格名称 1008003000 ==========
     ErrorCode PROPERTY_NOT_EXISTS = new ErrorCode(1008003000, "规格名称不存在");
+    ErrorCode PROPERTY_EXISTS = new ErrorCode(1008003001, "规格名称已存在");
 
     // ========== 规格值 1008004000 ==========
     ErrorCode PROPERTY_VALUE_NOT_EXISTS = new ErrorCode(1008004000, "规格值不存在");
+    ErrorCode PROPERTY_VALUE_EXISTS = new ErrorCode(1008004001, "规格值已存在");
 
     // ========== 商品 SPU 1008005000 ==========
     ErrorCode SPU_NOT_EXISTS = new ErrorCode(1008005000, "商品 SPU 不存在");

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java

@@ -56,7 +56,7 @@ public class ProductPropertyController {
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
     @PreAuthorize("@ss.hasPermission('product:property:query')")
     public CommonResult<ProductPropertyRespVO> getProperty(@RequestParam("id") Long id) {
-        return success(productPropertyService.getPropertyResp(id));
+        return success(productPropertyService.getProperty(id));
     }
 
     @GetMapping("/list")

+ 1 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java

@@ -55,9 +55,8 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO {
 
     }
 
-    // TODO @luowenfeng: 只返回 categoryId 可以么? 如果是为了前端修改时使用, 会拿到下拉列表, 自动选中合适的. 可以微信讨论下, 我也不完全确定哈;
     @ApiModelProperty(value = "分类 id 数组,一直递归到一级父节点", example = "[1,2,4]")
-    private List<Long> categoryIds;
+    private 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;

+ 5 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java

@@ -1,10 +1,13 @@
 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.controller.admin.property.vo.value.ProductPropertyValueRespVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
+import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
@@ -23,6 +26,8 @@ public interface ProductPropertyConvert {
     ProductPropertyDO convert(ProductPropertyCreateReqVO bean);
 
     ProductPropertyDO convert(ProductPropertyUpdateReqVO bean);
+    ProductPropertyAndValueRespVO convert(ProductPropertyRespVO bean);
+
 
     ProductPropertyRespVO convert(ProductPropertyDO bean);
 

+ 7 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyMapper.java

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.Pro
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * 规格名称 Mapper
  *
@@ -23,4 +25,9 @@ public interface ProductPropertyMapper extends BaseMapperX<ProductPropertyDO> {
                 .orderByDesc(ProductPropertyDO::getId));
     }
 
+    default ProductPropertyDO selectByName(String name) {
+        return selectOne(new LambdaQueryWrapperX<ProductPropertyDO>()
+                .likeIfPresent(ProductPropertyDO::getName, name));
+    }
+
 }

+ 9 - 8
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java

@@ -17,19 +17,20 @@ import java.util.List;
 @Mapper
 public interface ProductPropertyValueMapper extends BaseMapperX<ProductPropertyValueDO> {
 
-    // TODO @luowenfeng:方法名,selectListByXXX。mapper 的操作都是 crud
-    default List<ProductPropertyValueDO> getPropertyValueListByPropertyId(List<Long> propertyIds) {
-        // TODO @franky:调用父类的 selectList
+    default List<ProductPropertyValueDO> selectListByPropertyValueListByPropertyId(List<Long> propertyIds) {
         return selectList(new LambdaQueryWrapperX<ProductPropertyValueDO>()
                 .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds));
     }
 
+    default ProductPropertyValueDO selectByName(Long propertyId, String name) {
+        return selectOne(new LambdaQueryWrapperX<ProductPropertyValueDO>()
+                .eq(ProductPropertyValueDO::getPropertyId, propertyId)
+                .eq(ProductPropertyValueDO::getName, name));
+    }
+
     default void deletePropertyValueByPropertyId(Long propertyId) {
-        // TODO @luowenfeng:delete(new ) 即可
-        LambdaQueryWrapperX<ProductPropertyValueDO> queryWrapperX = new LambdaQueryWrapperX<>();
-        queryWrapperX.eq(ProductPropertyValueDO::getPropertyId, propertyId)
-                .eq(ProductPropertyValueDO::getDeleted, false);
-        delete(queryWrapperX);
+        delete(new LambdaQueryWrapperX<ProductPropertyValueDO>().eq(ProductPropertyValueDO::getPropertyId, propertyId)
+                .eq(ProductPropertyValueDO::getDeleted, false));
     }
 
     default PageResult<ProductPropertyValueDO> selectPage(ProductPropertyValuePageReqVO reqVO) {

+ 6 - 9
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -17,20 +18,13 @@ import java.util.List;
 @Mapper
 public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
 
-    // TODO @franky:方法名 selectList; 可以直接调用 selectList
-    default List<ProductSkuDO> selectListBySpuIds(List<Long> spuIds) {
-        return selectList(ProductSkuDO::getSpuId, spuIds);
-    }
-
     default List<ProductSkuDO> selectListBySpuId(Long spuId) {
         return selectList(ProductSkuDO::getSpuId, spuId);
     }
 
     default void deleteBySpuId(Long spuId) {
-        // TODO @franky:直接 delete(new XXX) 即可,更简洁一些
-        LambdaQueryWrapperX<ProductSkuDO> lambdaQueryWrapperX = new LambdaQueryWrapperX<ProductSkuDO>()
-                .eqIfPresent(ProductSkuDO::getSpuId, spuId);
-        delete(lambdaQueryWrapperX);
+        delete(new LambdaQueryWrapperX<ProductSkuDO>()
+                .eqIfPresent(ProductSkuDO::getSpuId, spuId));
     }
 
     default void decrementStockBatch(List<SkuDecrementStockBatchReqDTO.Item> items) {
@@ -45,4 +39,7 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
             this.update(null, lambdaUpdateWrapper);
         }
     }
+    default List<ProductSkuDO> selectRemindSpuIds(){
+       return selectList(new QueryWrapper<ProductSkuDO>().apply("stock <= warn_stock"));
+    }
 }

+ 6 - 9
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java

@@ -93,18 +93,15 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
     @Override
     public void validateCategoryLevel(Long id) {
         Long parentId = id;
-        for (int i = 0; i < 3; i++) { // TODO @luowenfeng: 建议还是先获得 level; 然后判断 level 是不是满足; 这样逻辑会更清晰一些;
-            if (Objects.equals(parentId, ProductCategoryDO.PARENT_ID_NULL)) {
-                throw exception(CATEGORY_LEVEL_ERROR);
-            }
+        int i = 2;
+        for (; i >= 0; --i) {
             ProductCategoryDO category = productCategoryMapper.selectById(parentId);
-            if (category == null) {
-                // TODO @luowenfeng: 应该抛出 CATEGORY_LEVEL_ERROR
-                throw exception(CATEGORY_NOT_EXISTS);
-            }
             parentId = category.getParentId();
+            if(Objects.equals(parentId, ProductCategoryDO.PARENT_ID_NULL)){
+                break;
+            }
         }
-        if (!Objects.equals(parentId, ProductCategoryDO.PARENT_ID_NULL)) {
+        if (!Objects.equals(parentId, ProductCategoryDO.PARENT_ID_NULL) || i != 0) {
             throw exception(CATEGORY_LEVEL_ERROR);
         }
     }

+ 6 - 10
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java

@@ -39,14 +39,6 @@ public interface ProductPropertyService {
     void deleteProperty(Long id);
 
     /**
-     * 获得规格名称
-     *
-     * @param id 编号
-     * @return 规格名称
-     */
-    ProductPropertyDO getProperty(Long id);
-
-    /**
      * 获得规格名称列表
      * @param listReqVO 集合查询
      * @return 规格名称集合
@@ -61,8 +53,12 @@ public interface ProductPropertyService {
      */
     PageResult<ProductPropertyRespVO> getPropertyPage(ProductPropertyPageReqVO pageReqVO);
 
-    // TODO luowenfeng: getProperty 就可以拉, 不用到 Resp
-    ProductPropertyRespVO getPropertyResp(Long id);
+    /**
+     *
+     * @param id 编号
+     * @return 规格名称
+     */
+    ProductPropertyRespVO getProperty(Long id);
 
     /**
      * 根据规格属性编号的集合,获得对应的规格 + 规格值的集合

+ 19 - 40
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java

@@ -1,13 +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.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 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;
 import cn.iocoder.yudao.module.product.convert.property.ProductPropertyConvert;
 import cn.iocoder.yudao.module.product.convert.propertyvalue.ProductPropertyValueConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
@@ -19,13 +16,12 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_EXISTS;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_NOT_EXISTS;
 
 /**
@@ -46,7 +42,10 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Long createProperty(ProductPropertyCreateReqVO createReqVO) {
-        // TODO @luowenfeng: 插入和更新的时候, 要校验 name 的唯一性;
+        // 校验存在
+        if(productPropertyMapper.selectByName(createReqVO.getName()) != null){
+            throw exception(PROPERTY_EXISTS);
+        }
         // 插入
         ProductPropertyDO property = ProductPropertyConvert.INSTANCE.convert(createReqVO);
         productPropertyMapper.insert(property);
@@ -59,6 +58,9 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     public void updateProperty(ProductPropertyUpdateReqVO updateReqVO) {
         // 校验存在
         this.validatePropertyExists(updateReqVO.getId());
+        if(productPropertyMapper.selectByName(updateReqVO.getName()) != null){
+            throw exception(PROPERTY_EXISTS);
+        }
         // 更新
         ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO);
         productPropertyMapper.updateById(updateObj);
@@ -81,11 +83,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     }
 
     @Override
-    public ProductPropertyDO getProperty(Long id) {
-        return productPropertyMapper.selectById(id);
-    }
-
-    @Override
     public List<ProductPropertyRespVO> getPropertyList(ProductPropertyListReqVO listReqVO) {
         return ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectList(new LambdaQueryWrapperX<ProductPropertyDO>()
                 .likeIfPresent(ProductPropertyDO::getName, listReqVO.getName())
@@ -96,29 +93,16 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
     public PageResult<ProductPropertyRespVO> getPropertyPage(ProductPropertyPageReqVO pageReqVO) {
         //获取属性列表
         PageResult<ProductPropertyDO> pageResult = productPropertyMapper.selectPage(pageReqVO);
-        PageResult<ProductPropertyRespVO> propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult);
-        // TODO @luofengwen: 下面的代码, 如果不要,可以删除哈; git 可以拿到记录的
-//        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;
+        return ProductPropertyConvert.INSTANCE.convertPage(pageResult);
     }
 
     private List<ProductPropertyValueDO> getPropertyValueListByPropertyId(List<Long> propertyIds) {
-        return productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds);
+        return productPropertyValueMapper.selectListByPropertyValueListByPropertyId(propertyIds);
     }
 
     @Override
-    public ProductPropertyRespVO getPropertyResp(Long id) {
-        ProductPropertyDO property = getProperty(id);
+    public ProductPropertyRespVO getProperty(Long id) {
+        ProductPropertyDO property = productPropertyMapper.selectById(id);
         return ProductPropertyConvert.INSTANCE.convert(property);
     }
 
@@ -132,17 +116,12 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
         List<ProductPropertyRespVO> propertyList = getPropertyList(listReqVO);
 
         // 查询属性值
-        List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId));
-//        CollectionUtils.convertMultiMap() // TODO @luofengwen: 可以使用这个方法哈
-        Map<Long, List<ProductPropertyValueRespVO>> valueDOMap = valueDOList.stream()
-                .map(ProductPropertyValueConvert.INSTANCE::convert)
-                .collect(Collectors.groupingBy(ProductPropertyValueRespVO::getPropertyId));
-        // 组装 TODO @luowenfeng: CollectionUtils 转换哈;
-        return propertyList.stream().map(m -> {
-            // TODO @luowenfeng: 使用 mapstruct convert 哈
-            ProductPropertyAndValueRespVO productPropertyAndValueRespVO = BeanUtil.copyProperties(m, ProductPropertyAndValueRespVO.class);
-            productPropertyAndValueRespVO.setValues(valueDOMap.get(m.getId()));
+        List<ProductPropertyValueDO> valueDOList = productPropertyValueMapper.selectListByPropertyValueListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId));
+        Map<Long, List<ProductPropertyValueDO>> valueDOMap = CollectionUtils.convertMultiMap(valueDOList, ProductPropertyValueDO::getPropertyId);
+        return CollectionUtils.convertList(propertyList, m -> {
+            ProductPropertyAndValueRespVO productPropertyAndValueRespVO = ProductPropertyConvert.INSTANCE.convert(m);
+            productPropertyAndValueRespVO.setValues(ProductPropertyValueConvert.INSTANCE.convertList(valueDOMap.get(m.getId())));
             return productPropertyAndValueRespVO;
-        }).collect(Collectors.toList());
+        });
     }
 }

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java

@@ -10,7 +10,7 @@ import java.util.List;
 
 /**
  * <p>
- *
+ * 规格值 Service 接口
  * </p>
  *
  * @author LuoWenFeng

+ 11 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java

@@ -15,9 +15,12 @@ import org.springframework.validation.annotation.Validated;
 import javax.annotation.Resource;
 import java.util.List;
 
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.PROPERTY_VALUE_EXISTS;
+
 /**
- * <p> TODO @luowenfeng: 类注释
- *
+ * <p>
+ *  规格值 Service 实现类
  * </p>
  *
  * @author LuoWenFeng
@@ -31,7 +34,9 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ
 
     @Override
     public Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO) {
-        // TODO @luowenfeng: 需要校验下在这个 propertyId, 新增和更新, name 都要唯一
+        if (productPropertyValueMapper.selectByName(createReqVO.getPropertyId(), createReqVO.getName()) != null) {
+            throw exception(PROPERTY_VALUE_EXISTS);
+        }
         ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(createReqVO);
         productPropertyValueMapper.insert(convert);
         return convert.getId();
@@ -39,6 +44,9 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ
 
     @Override
     public void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO) {
+        if (productPropertyValueMapper.selectByName(updateReqVO.getPropertyId(), updateReqVO.getName()) != null) {
+            throw exception(PROPERTY_VALUE_EXISTS);
+        }
         ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO);
         productPropertyValueMapper.updateById(convert);
     }

+ 1 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java

@@ -83,12 +83,11 @@ public interface ProductSkuService {
      */
     void deleteSkuBySpuId(Long spuId);
 
-    // TODO @luowenfeng: 可以改成返回 ProductSkuDO 列表; 然后, 上层业务在做处理;
     /**
      * 获得商品预警中的 SPU 集合
      *
      * @return 商品spuId集合
      */
-    List<Long> getRemindSpuIds();
+    List<ProductSkuDO> getRemindSpuIds();
 
 }

+ 4 - 12
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java

@@ -124,12 +124,12 @@ public class ProductSkuServiceImpl implements ProductSkuService {
 
     @Override
     public List<ProductSkuDO> getSkusBySpuId(Long spuId) {
-        return productSkuMapper.selectListBySpuIds(Collections.singletonList(spuId));
+        return productSkuMapper.selectList(ProductSkuDO::getSpuId, spuId);
     }
 
     @Override
     public List<ProductSkuDO> getSkusBySpuIds(List<Long> spuIds) {
-        return productSkuMapper.selectListBySpuIds(spuIds);
+        return productSkuMapper.selectList(ProductSkuDO::getSpuId, spuIds);
     }
 
     @Override
@@ -138,10 +138,8 @@ public class ProductSkuServiceImpl implements ProductSkuService {
     }
 
     @Override
-    public List<Long> getRemindSpuIds() {
-        // TODO @luowenfeng: mybatis plus 不能出现在 Service 哈; 把这个查询, 下沉一个方法到 mapper 里
-        List<ProductSkuDO> productSkuDOS = productSkuMapper.selectList(new QueryWrapper<ProductSkuDO>().apply("stock <= warn_stock"));
-        return productSkuDOS.stream().map(ProductSkuDO::getSpuId).distinct().collect(Collectors.toList());
+    public List<ProductSkuDO> getRemindSpuIds() {
+        return productSkuMapper.selectRemindSpuIds();
     }
 
     @Override
@@ -160,12 +158,6 @@ public class ProductSkuServiceImpl implements ProductSkuService {
                     return String.join("-", collect, String.valueOf(v.getId()));
                 })
                 .collect(Collectors.toMap(v -> v.split("-")[0], v -> Long.valueOf(v.split("-")[1])));
-//        Map<String, Long> existsSkuMap2 = CollectionUtils.convertMap(existsSkus, productSkuDO -> {
-//            if (CollUtil.isEmpty(productSkuDO.getProperties())) {
-//                return "";
-//            }
-//            return StrUtil.join("-", convertList(productSkuDO.getProperties(), ProductSkuDO.Property::getValueId));
-//        }, ProductSkuDO::getId);
 
         // 拆分三个集合,新插入的、需要更新的、需要删除的
         List<ProductSkuDO> insertSkus = new ArrayList<>();

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java

@@ -72,7 +72,7 @@ public interface ProductSpuService {
     PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO);
 
     /**
-     * 获得商品 SPU 分页 // TODO @luowenfeng: 中文和英文之间, 要有一个空格; 这样, 阅读起来会更清晰; 我已经都改啦
+     * 获得商品 SPU 分页
      *
      * @param pageReqVO 分页查询
      * @return 商品spu分页

+ 19 - 19
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java

@@ -14,6 +14,7 @@ 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;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
+import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
@@ -134,7 +135,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
             List<ProductSpuDetailRespVO.Sku> skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id));
             respVO.setSkus(skuReqs);
             // 组合 sku 规格属性
-            if(spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
+            if (spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) {
                 List<ProductSkuRespVO.Property> properties = new ArrayList<>();
                 for (ProductSpuDetailRespVO.Sku productSkuRespVO : skuReqs) {
                     properties.addAll(productSkuRespVO.getProperties());
@@ -162,18 +163,19 @@ public class ProductSpuServiceImpl implements ProductSpuService {
                 respVO.setProductPropertyViews(productPropertyViews);
             }
             // 组合分类
-            if (null != respVO.getCategoryId()) {
-                LinkedList<Long> categoryArray = new LinkedList<>();
-                Long parentId = respVO.getCategoryId();
-                categoryArray.addFirst(parentId);
-                while (parentId != 0) {
-                    parentId = categoryService.getCategory(parentId).getParentId();
-                    if (parentId > 0) {
-                        categoryArray.addFirst(parentId);
-                    }
-                }
-                respVO.setCategoryIds(categoryArray);
-            }
+//            if (null != respVO.getCategoryId()) {
+//                LinkedList<Long> categoryArray = new LinkedList<>();
+//                Long parentId = respVO.getCategoryId();
+//                categoryArray.addFirst(parentId);
+//                while (parentId != 0) {
+//                    parentId = categoryService.getCategory(parentId).getParentId();
+//                    if (parentId > 0) {
+//                        categoryArray.addFirst(parentId);
+//                    }
+//                }
+//
+//            }
+            respVO.setCategoryIds(respVO.getCategoryId());
         }
         return respVO;
     }
@@ -190,12 +192,10 @@ public class ProductSpuServiceImpl implements ProductSpuService {
 
     @Override
     public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
-        List<Long> remindSpuIds= null;
-        // todo @yunai 预警类型的判断应该可以优化,看下怎么处理
-        // TODO @luowenfeng: 先这么简单处理; 性能应该影响不大的;
-        if(pageReqVO.getTabStatus() != null && pageReqVO.getTabStatus() == 2){
-            remindSpuIds= productSkuService.getRemindSpuIds();
-            if(remindSpuIds.isEmpty()){
+        List<Long> remindSpuIds = null;
+        if (pageReqVO.getTabStatus() != null && pageReqVO.getTabStatus() == 2) {
+            remindSpuIds = productSkuService.getRemindSpuIds().stream().map(ProductSkuDO::getSpuId).distinct().collect(Collectors.toList());
+            if (remindSpuIds.isEmpty()) {
                 remindSpuIds.add(null);
             }
         }

+ 19 - 19
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java

@@ -1,19 +1,19 @@
-package cn.iocoder.yudao.module.pay.api.order;
-
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * @author LeeYan9
- * @since 2022-09-06
- */
-@Service
-public class PayOrderApiImpl implements PayOrderApi {
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) {
-        return null;
-    }
-
-}
+//package cn.iocoder.yudao.module.pay.api.order;
+//
+//import org.springframework.stereotype.Service;
+//import org.springframework.transaction.annotation.Transactional;
+//
+///**
+// * @author LeeYan9
+// * @since 2022-09-06
+// */
+//@Service
+//public class PayOrderApiImpl implements PayOrderApi {
+//
+//    @Override
+//    @Transactional(rollbackFor = Exception.class)
+//    public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) {
+//        return null;
+//    }
+//
+//}

+ 24 - 22
yudao-ui-admin/src/views/mall/product/spu/save.vue

@@ -39,8 +39,7 @@
       <el-tab-pane label="价格库存" name="rates" class="rates">
         <el-form ref="rates" :model="ratesForm" :rules="rules">
           <el-form-item label="启用多规格">
-            <!-- TODO @luowenfeng: 1) activeSwitch 可以考虑改成; specSwitch, 更清晰一点, activeSwitch 太通用了; changeRadio 改成 changeSpecSwitch  -->
-            <el-switch v-model="activeSwitch" @change="changeRadio"></el-switch>
+            <el-switch v-model="specSwitch" @change="changeSpecSwitch"></el-switch>
           </el-form-item>
 
           <!-- 动态添加规格属性 -->
@@ -67,7 +66,7 @@
           <!-- 规格明细 -->
           <el-form-item label="规格明细">
             <el-table :data="ratesForm.rates" border style="width: 100%" ref="ratesTable">
-              <template v-if="this.activeSwitch">
+              <template v-if="this.specSwitch">
                 <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 +80,7 @@
                                style="width: 100px; height: 50px"/>
                 </template>
               </el-table-column>
-              <template v-if="this.activeSwitch">
+              <template v-if="this.specSwitch">
                 <el-table-column label="sku名称" :render-header="addRedStar" key="91">
                   <template slot-scope="scope">
                     <el-form-item :prop="'rates.'+ scope.$index + '.name'"
@@ -148,13 +147,13 @@
                   <el-input v-model="scope.row.barCode"></el-input>
                 </template>
               </el-table-column>
-              <template v-if="this.activeSwitch">
+              <template v-if="this.specSwitch">
                 <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 ">禁用
+                               v-show="scope.row.status === undefined || scope.row.status === 0 ">禁用
                     </el-button>
-                    <el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status == 1">
+                    <el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status === 1">
                       启用
                     </el-button>
                   </template>
@@ -220,7 +219,7 @@ export default {
   },
   data() {
     return {
-      activeSwitch: false,
+      specSwitch: false,
       activeName: "base",
       propName: {
         checkStrictly: true,
@@ -287,7 +286,7 @@ export default {
   methods: {
     removeSpec(index) {
       this.dynamicSpec.splice(index, 1);
-      this.changeRadio()
+      this.changeSpecSwitch()
     },
     // 必选标识
     addRedStar(h, {column}) {
@@ -296,10 +295,10 @@ export default {
         h('span', ' ' + column.label)
       ];
     },
-    changeRadio() {
-      this.activeSwitch ? this.ratesForm.spec = 2 : this.ratesForm.spec = 1;
+    changeSpecSwitch() {
+      this.specSwitch ? this.ratesForm.spec = 2 : this.ratesForm.spec = 1;
       this.$refs.ratesTable.doLayout();
-      if (this.ratesForm.spec == 1) {
+      if (this.ratesForm.spec === 1) {
         this.ratesForm.rates = [{}]
       } else {
         this.ratesForm.rates = []
@@ -380,7 +379,7 @@ export default {
         })
 
         // 动态规格调整字段
-        if (this.activeSwitch) {
+        if (this.specSwitch) {
           rates.forEach(r => {
             let properties = []
             Array.of(r.spec).forEach(s => {
@@ -391,7 +390,7 @@ export default {
                 obj = Array.of(s);
               }
               obj.forEach((v, i) => {
-                let specValue = this.dynamicSpec[i].specValue.find(o => o.name == v);
+                let specValue = this.dynamicSpec[i].specValue.find(o => o.name === v);
                 let propertie = {};
                 propertie.propertyId = this.dynamicSpec[i].specId;
                 propertie.valueId = specValue.id;
@@ -414,17 +413,20 @@ export default {
         }
         form.skus = rates;
         form.specType = this.ratesForm.spec;
-        form.categoryId = form.categoryIds[this.baseForm.categoryIds.length - 1];
+
+        let category = form.categoryIds instanceof Array ? form.categoryIds: Array.of(form.categoryIds)
+        console.log(category)
+        form.categoryId = category[category.length - 1];
 
         if (form.id == null) {
-          createSpu(form).then((response) => {
+          createSpu(form).then(() => {
             this.$modal.msgSuccess("新增成功");
           })
           .then(()=>{
             this.cancel();
           })
         } else {
-          updateSpu(form).then((response) => {
+          updateSpu(form).then(() => {
             this.$modal.msgSuccess("修改成功");
           })
           .then(()=>{
@@ -443,8 +445,8 @@ export default {
     },
     // 添加规格项目
     changeSpec(val) {
-      let obj = this.propertyPageList.find(o => o.id == val);
-      let spec = this.dynamicSpec.find(o => o.specId == val)
+      let obj = this.propertyPageList.find(o => o.id === val);
+      let spec = this.dynamicSpec.find(o => o.specId === val)
       spec.specId = obj.id;
       spec.specName = obj.name;
       spec.specValue = obj.values;
@@ -471,8 +473,8 @@ export default {
           r.price = this.divide(r.price, 100)
           r.costPrice = this.divide(r.costPrice, 100)
         })
-        if (this.ratesForm.spec == 2) {
-          this.activeSwitch = true;
+        if (this.ratesForm.spec === 2) {
+          this.specSwitch = true;
           data.productPropertyViews.forEach(p => {
             let obj = {};
             obj.specId = p.propertyId;
@@ -483,7 +485,7 @@ export default {
           data.skus.forEach(s => {
             s.spec = [];
             s.properties.forEach(sp => {
-              let spec = data.productPropertyViews.find(o => o.propertyId == sp.propertyId).propertyValues.find(v => v.id == sp.valueId).name;
+              let spec = data.productPropertyViews.find(o => o.propertyId === sp.propertyId).propertyValues.find(v => v.id === sp.valueId).name;
               s.spec.push(spec)
             })
           })