Browse Source

fix:完善 TODO 提到的问题

puhui999 1 year ago
parent
commit
db7e47faa2
22 changed files with 328 additions and 167 deletions
  1. 5 6
      yudao-module-mall/yudao-module-product-biz/pom.xml
  2. 1 30
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java
  3. 9 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java
  4. 9 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java
  5. 0 22
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/sku/ProductSkuMapper.java
  6. 4 9
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/category/ProductCategoryServiceImpl.java
  7. 20 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
  8. 2 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java
  9. 2 4
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java
  10. 6 6
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
  11. 45 67
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
  12. 8 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
  13. 45 15
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
  14. 20 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
  15. 92 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java
  16. 1 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java
  17. 28 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
  18. 1 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java
  19. 3 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java
  20. 21 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java
  21. 3 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java
  22. 3 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

+ 5 - 6
yudao-module-mall/yudao-module-product-biz/pom.xml

@@ -23,7 +23,11 @@
             <artifactId>yudao-module-product-api</artifactId>
             <version>${revision}</version>
         </dependency>
-
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-trade-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
         <dependency>
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-module-member-api</artifactId>
@@ -35,11 +39,6 @@
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
         </dependency>
-        <!-- TODO 芋艿:是不是可以去掉这个依赖呀? -->
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
-        </dependency>
 
         <!-- Web 相关 -->
         <dependency>

+ 1 - 30
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/AppProductSpuController.java

@@ -5,14 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
-import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
-import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
-import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
-import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
-import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
-import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
 import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -25,12 +19,8 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
-import java.util.List;
 
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_ENABLE;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 
 @Tag(name = "用户 APP - 商品 SPU")
 @RestController
@@ -40,10 +30,6 @@ public class AppProductSpuController {
 
     @Resource
     private ProductSpuService productSpuService;
-    @Resource
-    private ProductSkuService productSkuService;
-    @Resource
-    private ProductPropertyValueService productPropertyValueService;
 
     @GetMapping("/page")
     @Operation(summary = "获得商品 SPU 分页")
@@ -56,22 +42,7 @@ public class AppProductSpuController {
     @Operation(summary = "获得商品 SPU 明细")
     @Parameter(name = "id", description = "编号", required = true)
     public CommonResult<AppProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) {
-        // 获得商品 SPU
-        ProductSpuDO spu = productSpuService.getSpu(id);
-        if (spu == null) {
-            throw exception(SPU_NOT_EXISTS);
-        }
-        if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
-            throw exception(SPU_NOT_ENABLE);
-        }
-
-        // 查询商品 SKU
-        List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
-        // 查询商品属性
-        List<ProductPropertyValueDetailRespBO> propertyValues = productPropertyValueService
-                .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus));
-        // 拼接
-        return success(ProductSpuConvert.INSTANCE.convertForGetSpuDetail(spu, skus, propertyValues));
+        return success(productSpuService.getAppProductSpuDetail(id));
     }
 
 }

+ 9 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.product.dal.dataobject.property;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -22,6 +21,15 @@ import lombok.*;
 @AllArgsConstructor
 public class ProductPropertyDO extends BaseDO {
 
+    /**
+     * 默认属性id
+     */
+    public static final Long PROPERTY_ID = 0L;
+    /**
+     * 默认属性名字
+     */
+    public static final String PROPERTY_NAME = "默认";
+
     /**
      * 主键
      */

+ 9 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.product.dal.dataobject.property;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -23,6 +22,15 @@ import lombok.*;
 @AllArgsConstructor
 public class ProductPropertyValueDO extends BaseDO {
 
+    /**
+     * 默认属性值id
+     */
+    public static final Long VALUE_ID = 0L;
+    /**
+     * 默认属性值名字
+     */
+    public static final String VALUE_NAME = "默认";
+
     /**
      * 主键
      */

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

@@ -1,12 +1,9 @@
 package cn.iocoder.yudao.module.product.dal.mysql.sku;
 
 import cn.hutool.core.lang.Assert;
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-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.dal.dataobject.sku.ProductSkuDO;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -63,23 +60,4 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
         return selectList(new QueryWrapper<ProductSkuDO>().apply("stock <= warn_stock"));
     }
 
-    // TODO @puhui999:貌似 IN 不出来数据哈。直接全部查询出来,处理就好列;
-    /**
-     * 更新 sku 属性值时使用的分页查询
-     *
-     * @param pageParam 页面参数
-     * @return {@link PageResult}<{@link ProductSkuDO}>
-     */
-    default PageResult<ProductSkuDO> selectPage(PageParam pageParam) {
-        return selectPage(pageParam, new LambdaQueryWrapper<ProductSkuDO>().isNotNull(ProductSkuDO::getProperties));
-    }
-
-    /**
-     * 查询 sku properties 不等于 null 的数量
-     *
-     * @return {@link Long}
-     */
-    default Long selectCountByPropertyNotNull() {
-        return selectCount(new LambdaQueryWrapper<ProductSkuDO>().isNotNull(ProductSkuDO::getProperties));
-    }
 }

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

@@ -68,7 +68,10 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
             throw exception(CATEGORY_EXISTS_CHILDREN);
         }
         // 校验分类是否绑定了 SPU
-        validateProductCategoryIsHaveBindSpu(id);
+        Long count = productSpuService.getSpuCountByCategoryId(id);
+        if (0 != count) {
+            throw exception(CATEGORY_HAVE_BIND_SPU);
+        }
         // 删除
         productCategoryMapper.deleteById(id);
     }
@@ -96,14 +99,6 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
         }
     }
 
-    // TODO @puhui999:不用抽方法,因为不太会复用这个方法哈。
-    private void validateProductCategoryIsHaveBindSpu(Long id) {
-        Long count = productSpuService.getSpuCountByCategoryId(id);
-        if (0 != count) {
-            throw exception(CATEGORY_HAVE_BIND_SPU);
-        }
-    }
-
     @Override
     public ProductCategoryDO getCategory(Long id) {
         return productCategoryMapper.selectById(id);

+ 20 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java

@@ -8,7 +8,11 @@ import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommen
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentAdditionalReqVO;
 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
+import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper;
+import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
+import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
+import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 import org.springframework.validation.annotation.Validated;
@@ -18,6 +22,7 @@ import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
 
 /**
  * 商品评论 Service 实现类
@@ -30,6 +35,11 @@ public class ProductCommentServiceImpl implements ProductCommentService {
 
     @Resource
     private ProductCommentMapper productCommentMapper;
+    @Resource
+    private TradeOrderApi tradeOrderApi;
+
+    @Resource
+    private ProductSpuService productSpuService;
 
     @Override
     public PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO) {
@@ -60,6 +70,16 @@ public class ProductCommentServiceImpl implements ProductCommentService {
     @Override
     public void createComment(ProductCommentDO productComment, Boolean system) {
         if (!system) {
+            // TODO 判断订单是否存在 fix
+            TradeOrderRespDTO order = tradeOrderApi.getOrder(productComment.getOrderId());
+            if (null == order) {
+                throw exception(ORDER_NOT_FOUND);
+            }
+            // TODO 判断 SPU 是否存在 fix
+            ProductSpuDO spu = productSpuService.getSpu(productComment.getSpuId());
+            if (null == spu) {
+                throw exception(SPU_NOT_EXISTS);
+            }
             // 判断当前订单的当前商品用户是否评价过
             ProductCommentDO exist = productCommentMapper.findByUserIdAndOrderIdAndSpuId(productComment.getId(), productComment.getOrderId(), productComment.getSpuId());
             if (null != exist) {

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

@@ -71,8 +71,8 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
         // 更新
         ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO);
         productPropertyMapper.updateById(updateObj);
-        // TODO @puhui:是不是只要传递变量,不传递整个 updateObj 变量哈
-        productSkuService.updateSkuProperty(updateObj);
+        // 更新 sku 相关属性
+        productSkuService.updateSkuProperty(updateObj.getId(), updateObj.getName());
     }
 
     @Override

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

@@ -73,10 +73,8 @@ public class ProductPropertyValueServiceImpl implements ProductPropertyValueServ
         // 更新
         ProductPropertyValueDO updateObj = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO);
         productPropertyValueMapper.updateById(updateObj);
-
-        // TODO 芋艿:更新时,需要看看 sku 表 fix
-        // TODO @puhui:是不是只要传递变量,不传递整个 updateObj 变量哈
-        productSkuService.updateSkuPropertyValue(updateObj);
+        // 更新 sku 相关属性
+        productSkuService.updateSkuPropertyValue(updateObj.getId(), updateObj.getName());
     }
 
     @Override

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

@@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.product.service.sku;
 
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
-import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
-import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 
 import java.util.Collection;
@@ -111,16 +109,18 @@ public interface ProductSkuService {
     /**
      * 更新 sku 属性
      *
-     * @param updateObj 属性对象
+     * @param propertyId   属性 id
+     * @param propertyName 属性名
      * @return int 影响的行数
      */
-    int updateSkuProperty(ProductPropertyDO updateObj);
+    int updateSkuProperty(Long propertyId, String propertyName);
 
     /**
      * 更新 sku 属性值
      *
-     * @param updateObj 属性值对象
+     * @param propertyValueId   属性值 id
+     * @param propertyValueName 属性值名字
      * @return int 影响的行数
      */
-    int updateSkuPropertyValue(ProductPropertyValueDO updateObj);
+    int updateSkuPropertyValue(Long propertyValueId, String propertyValueName);
 }

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

@@ -2,9 +2,8 @@ package cn.iocoder.yudao.module.product.service.sku;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
+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.convert.sku.ProductSkuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
@@ -80,16 +79,25 @@ public class ProductSkuServiceImpl implements ProductSkuService {
 
     @Override
     public void validateSkuList(List<ProductSkuCreateOrUpdateReqVO> skus, Boolean specType) {
-        // 非多规格,不需要校验
-        if (ObjectUtil.notEqual(specType, true)) {
-            return;
-        }
-
         // 0、校验skus是否为空
         if (CollUtil.isEmpty(skus)) {
             throw exception(SKU_NOT_EXISTS);
         }
-
+        // 单规格处理
+        if (ObjectUtil.equal(specType, false)) {
+            ProductSkuCreateOrUpdateReqVO skuVO = skus.get(0);
+            // 赋予单规格默认属性
+            List<ProductSkuBaseVO.Property> properties = new ArrayList<>();
+            ProductSkuBaseVO.Property property = new ProductSkuBaseVO.Property();
+            property.setPropertyId(ProductPropertyDO.PROPERTY_ID);
+            property.setPropertyName(ProductPropertyDO.PROPERTY_NAME);
+            property.setValueId(ProductPropertyValueDO.VALUE_ID);
+            property.setValueName(ProductPropertyValueDO.VALUE_NAME);
+            properties.add(property);
+            skuVO.setProperties(properties);
+            // 单规格不需要后续的校验
+            return;
+        }
         // 1、校验属性项存在
         Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null)
                 // 遍历多个 Property 属性
@@ -156,81 +164,51 @@ public class ProductSkuServiceImpl implements ProductSkuService {
     }
 
     @Override
-    public int updateSkuProperty(ProductPropertyDO updateObj) {
-        // TODO 看了一下数据库有关于 json 字符串的处理,怕数据库出现兼容问题这里还是用数据库常规操作来实现
-        // TODO @puhui999:直接全部查询处理,批量处理就好列;一般项目的商品不会超过几十万的哈。
-        Long count = productSkuMapper.selectCountByPropertyNotNull();
-        int currentPage = 1;
+    public int updateSkuProperty(Long propertyId, String propertyName) {
+        // 获取所有的 sku
+        List<ProductSkuDO> skuDOList = productSkuMapper.selectList();
+        // 处理后需要更新的 sku
         List<ProductSkuDO> updateSkus = new ArrayList<>();
-        if (count == 0) {
+        if (CollUtil.isEmpty(skuDOList)) {
             return 0;
         }
-        int pageSize = 100;
-        for (int i = 0; i <= count / 100; i++) {
-            PageParam pageParam = new PageParam().setPageNo(currentPage + i).setPageSize(pageSize);
-            // 分页查找出 sku 属性不为 null 的
-            PageResult<ProductSkuDO> skuPage = productSkuMapper.selectPage(pageParam);
-            List<ProductSkuDO> records = skuPage.getList();
-            if (CollUtil.isEmpty(records)) {
-                break;
-            }
-            records.stream().filter(sku -> sku.getProperties() != null)
-                    .forEach(sku -> sku.getProperties().forEach(property -> {
-                        if (property.getPropertyId().equals(updateObj.getId())) {
-                            property.setPropertyName(updateObj.getName());
-                            updateSkus.add(sku);
-                        }
-                    }));
-        }
+        skuDOList.stream().filter(sku -> sku.getProperties() != null)
+                .forEach(sku -> sku.getProperties().forEach(property -> {
+                    if (property.getPropertyId().equals(propertyId)) {
+                        property.setPropertyName(propertyName);
+                        updateSkus.add(sku);
+                    }
+                }));
         if (CollUtil.isEmpty(updateSkus)) {
             return 0;
         }
-        // TODO @puhui999:貌似 updateBatch 自己会拆分批次,这里不用再拆分了
-        // 每批处理的大小
-        int batchSize = 1000;
-        for (int i = 0; i < updateSkus.size(); i += batchSize) {
-            List<ProductSkuDO> batchSkuDOs = updateSkus.subList(i, Math.min(i + batchSize, updateSkus.size()));
-            productSkuMapper.updateBatch(batchSkuDOs, batchSize);
-        }
+
+        productSkuMapper.updateBatch(updateSkus);
         return updateSkus.size();
     }
 
     @Override
-    public int updateSkuPropertyValue(ProductPropertyValueDO updateObj) {
-        // TODO 看了一下数据库有关于 json 字符串的处理,怕数据库出现兼容问题这里还是用数据库常规操作来实现
-        Long count = productSkuMapper.selectCountByPropertyNotNull();
-        int currentPage = 1;
+    public int updateSkuPropertyValue(Long propertyValueId, String propertyValueName) {
+        // 获取所有的 sku
+        List<ProductSkuDO> skuDOList = productSkuMapper.selectList();
+        // 处理后需要更新的 sku
         List<ProductSkuDO> updateSkus = new ArrayList<>();
-        if (count == 0) {
+        if (CollUtil.isEmpty(skuDOList)) {
             return 0;
         }
-        int pageSize = 100;
-        for (int i = 0; i <= count / 100; i++) {
-            PageParam pageParam = new PageParam().setPageNo(currentPage + i).setPageSize(pageSize);
-            // 分页查找出 sku 属性不为 null 的
-            PageResult<ProductSkuDO> skuPage = productSkuMapper.selectPage(pageParam);
-            List<ProductSkuDO> records = skuPage.getList();
-            if (CollUtil.isEmpty(records)) {
-                break;
-            }
-            records.stream()
-                    .filter(sku -> sku.getProperties() != null)
-                    .forEach(sku -> sku.getProperties().forEach(property -> {
-                        if (property.getValueId().equals(updateObj.getId())) {
-                            property.setValueName(updateObj.getName());
-                            updateSkus.add(sku);
-                        }
-                    }));
-        }
+        skuDOList.stream()
+                .filter(sku -> sku.getProperties() != null)
+                .forEach(sku -> sku.getProperties().forEach(property -> {
+                    if (property.getValueId().equals(propertyValueId)) {
+                        property.setValueName(propertyValueName);
+                        updateSkus.add(sku);
+                    }
+                }));
         if (CollUtil.isEmpty(updateSkus)) {
             return 0;
         }
-        // 每批处理的大小
-        int batchSize = 1000;
-        for (int i = 0; i < updateSkus.size(); i += batchSize) {
-            List<ProductSkuDO> batchSkuDOs = updateSkus.subList(i, Math.min(i + batchSize, updateSkus.size()));
-            productSkuMapper.updateBatch(batchSkuDOs, batchSize);
-        }
+
+        productSkuMapper.updateBatch(updateSkus);
         return updateSkus.size();
     }
 

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

@@ -2,6 +2,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.*;
+import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 
@@ -135,4 +136,11 @@ public interface ProductSpuService {
      */
     Long getSpuCountByCategoryId(Long id);
 
+    /**
+     * 通过 spu id 获取商品 SPU 明细
+     *
+     * @param id id
+     * @return 用户 App - 商品 SPU 明细
+     */
+    AppProductSpuDetailRespVO getAppProductSpuDetail(Long id);
 }

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

@@ -7,15 +7,21 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
+import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
 import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
+import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
+import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO;
+import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
 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.ProductPropertyValueService;
+import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -50,6 +56,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
     private ProductBrandService brandService;
     @Resource
     private ProductCategoryService categoryService;
+    @Resource
+    @Lazy // 循环依赖,避免报错
+    private ProductPropertyValueService productPropertyValueService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -140,7 +149,11 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         // 校验存在
         validateSpuExists(id);
         // 校验商品状态不是回收站不能删除
-        validateSpuStatus(id);
+        ProductSpuDO spuDO = productSpuMapper.selectById(id);
+        // 判断 SPU 状态是否为回收站
+        if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) {
+            throw exception(SPU_NOT_RECYCLE);
+        }
 
         // 删除 SPU
         productSpuMapper.deleteById(id);
@@ -154,20 +167,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         }
     }
 
-    /**
-     * 验证 SPU 状态是否为回收站
-     *
-     * @param id id
-     */
-    // TODO puhui999:感觉不用独立出来一个方法,直接在 deleteSpu 方法中校验即可
-    private void validateSpuStatus(Long id) {
-        ProductSpuDO spuDO = productSpuMapper.selectById(id);
-        // 判断 SPU 状态是否为回收站
-        if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) {
-            throw exception(SPU_NOT_RECYCLE);
-        }
-    }
-
     @Override
     public ProductSpuDO getSpu(Long id) {
         return productSpuMapper.selectById(id);
@@ -257,4 +256,35 @@ public class ProductSpuServiceImpl implements ProductSpuService {
         return productSpuMapper.selectCount(ProductSpuDO::getCategoryId, id);
     }
 
+    @Override
+    public AppProductSpuDetailRespVO getAppProductSpuDetail(Long id) {
+        // 获得商品 SPU
+        ProductSpuDO spu = getSpu(id);
+        if (spu == null) {
+            throw exception(SPU_NOT_EXISTS);
+        }
+        if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
+            throw exception(SPU_NOT_ENABLE);
+        }
+
+        // 查询商品 SKU
+        List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
+        List<ProductPropertyValueDetailRespBO> propertyValues = new ArrayList<>();
+        // 单规格商品 赋予默认属性值
+        if (ObjectUtil.equal(spu.getSpecType(), false)) {
+            ProductPropertyValueDetailRespBO respBO = new ProductPropertyValueDetailRespBO();
+            respBO.setPropertyId(ProductPropertyDO.PROPERTY_ID);
+            respBO.setPropertyName(ProductPropertyDO.PROPERTY_NAME);
+            respBO.setValueId(ProductPropertyValueDO.VALUE_ID);
+            respBO.setValueName(ProductPropertyValueDO.VALUE_NAME);
+            propertyValues.add(respBO);
+        } else {
+            // 多规格商品则查询商品属性
+            propertyValues = productPropertyValueService
+                    .getPropertyValueDetailList(ProductSkuConvert.INSTANCE.convertPropertyValueIds(skus));
+        }
+        // 拼接
+        return ProductSpuConvert.INSTANCE.convertForGetSpuDetail(spu, skus, propertyValues);
+    }
+
 }

+ 20 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.trade.api.order;
+
+import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
+
+/**
+ * 订单 API 接口
+ *
+ * @author HUIHUI
+ */
+public interface TradeOrderApi {
+
+    /**
+     * 获取订单通过订单 id
+     *
+     * @param id id
+     * @return 订单信息 Response DTO
+     */
+    TradeOrderRespDTO getOrder(Long id);
+
+}

+ 92 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/dto/TradeOrderRespDTO.java

@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.trade.api.order.dto;
+
+import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 订单信息 Response DTO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class TradeOrderRespDTO {
+
+    // ========== 订单基本信息 ==========
+    /**
+     * 订单编号,主键自增
+     */
+    private Long id;
+    /**
+     * 订单流水号
+     * <p>
+     * 例如说,1146347329394184195
+     */
+    private String no;
+    /**
+     * 订单类型
+     * <p>
+     * 枚举 {@link TradeOrderTypeEnum}
+     */
+    private Integer type;
+    /**
+     * 订单来源
+     * <p>
+     * 枚举 {@link TerminalEnum}
+     */
+    private Integer terminal;
+    /**
+     * 用户编号
+     * <p>
+     * 关联 MemberUserDO 的 id 编号
+     */
+    private Long userId;
+    /**
+     * 用户 IP
+     */
+    private String userIp;
+    /**
+     * 用户备注
+     */
+    private String userRemark;
+    /**
+     * 订单状态
+     * <p>
+     * 枚举 {@link TradeOrderStatusEnum}
+     */
+    private Integer status;
+    /**
+     * 购买的商品数量
+     */
+    private Integer productCount;
+    /**
+     * 订单完成时间
+     */
+    private LocalDateTime finishTime;
+    /**
+     * 订单取消时间
+     */
+    private LocalDateTime cancelTime;
+    /**
+     * 取消类型
+     * <p>
+     * 枚举 {@link TradeOrderCancelTypeEnum}
+     */
+    private Integer cancelType;
+    /**
+     * 商家备注
+     */
+    private String remark;
+    /**
+     * 是否评价
+     * <p>
+     * true - 已评价
+     * false - 未评价
+     */
+    private Boolean commentStatus;
+
+}

+ 1 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.trade.api;

+ 28 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.trade.api.order;
+
+import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
+import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+/**
+ * 订单 API 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+@Validated
+public class TradeOrderApiImpl implements TradeOrderApi {
+
+    @Resource
+    private TradeOrderService tradeOrderService;
+
+    @Override
+    public TradeOrderRespDTO getOrder(Long id) {
+        return TradeOrderConvert.INSTANCE.convert(tradeOrderService.getOrder(id));
+    }
+
+}

+ 1 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.trade.api;

+ 3 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java

@@ -70,14 +70,14 @@ public class DeliveryExpressTemplateController {
         return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list));
     }
 
-    // TODO @puhui999:DeliveryExpressTemplateRespVO 搞个 simple 的哈
+    // TODO @puhui999:DeliveryExpressTemplateRespVO 搞个 simple 的哈 fix
     @GetMapping("/list-all-simple")
     @Operation(summary = "获取快递模版精简信息列表", description = "主要用于前端的下拉选项")
-    public CommonResult<List<DeliveryExpressTemplateRespVO>> getSimpleTemplateList() {
+    public CommonResult<List<DeliveryExpressTemplateSimpleRespVO>> getSimpleTemplateList() {
         // 获取运费模版列表,只要开启状态的
         List<DeliveryExpressTemplateDO> list = deliveryExpressTemplateService.getDeliveryExpressTemplateList();
         // 排序后,返回给前端
-        return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list));
+        return success(DeliveryExpressTemplateConvert.INSTANCE.convertList1(list));
     }
 
     @GetMapping("/page")

+ 21 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+@Schema(description = "管理后台 - 模版精简信息 Response VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DeliveryExpressTemplateSimpleRespVO {
+
+    @Schema(description = "模版编号", required = true, example = "1024")
+    private Long id;
+
+    @Schema(description = "模板名称", required = true, example = "测试模版")
+    private String name;
+
+}

+ 3 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java

@@ -28,11 +28,13 @@ public interface DeliveryExpressTemplateConvert {
 
     List<DeliveryExpressTemplateRespVO> convertList(List<DeliveryExpressTemplateDO> list);
 
+    List<DeliveryExpressTemplateSimpleRespVO> convertList1(List<DeliveryExpressTemplateDO> list);
+
     PageResult<DeliveryExpressTemplateRespVO> convertPage(PageResult<DeliveryExpressTemplateDO> page);
 
     default DeliveryExpressTemplateDetailRespVO convert(DeliveryExpressTemplateDO bean,
                                                         List<DeliveryExpressTemplateChargeDO> chargeList,
-                                                        List<DeliveryExpressTemplateFreeDO> freeList){
+                                                        List<DeliveryExpressTemplateFreeDO> freeList) {
         DeliveryExpressTemplateDetailRespVO respVO = convert2(bean);
         respVO.setTemplateCharge(convertTemplateChargeList(chargeList));
         respVO.setTemplateFree(convertTemplateFreeList(freeList));

+ 3 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
+import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO;
@@ -62,6 +63,8 @@ public interface TradeOrderConvert {
     TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
                          TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address);
 
+    TradeOrderRespDTO convert(TradeOrderDO orderDO);
+
     default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {
         return CollectionUtils.convertList(calculateRespBO.getItems(), item -> {
             TradeOrderItemDO orderItem = convert(item);