fix:完善 TODO 提到的问题

This commit is contained in:
puhui999 2023-06-07 14:15:25 +08:00
parent 36c45bd44e
commit db7e47faa2
22 changed files with 328 additions and 167 deletions

View File

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

View File

@ -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.AppProductSpuDetailRespVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageItemRespVO; 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.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.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.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 cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@ -25,12 +19,8 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; 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.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") @Tag(name = "用户 APP - 商品 SPU")
@RestController @RestController
@ -40,10 +30,6 @@ public class AppProductSpuController {
@Resource @Resource
private ProductSpuService productSpuService; private ProductSpuService productSpuService;
@Resource
private ProductSkuService productSkuService;
@Resource
private ProductPropertyValueService productPropertyValueService;
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得商品 SPU 分页") @Operation(summary = "获得商品 SPU 分页")
@ -56,22 +42,7 @@ public class AppProductSpuController {
@Operation(summary = "获得商品 SPU 明细") @Operation(summary = "获得商品 SPU 明细")
@Parameter(name = "id", description = "编号", required = true) @Parameter(name = "id", description = "编号", required = true)
public CommonResult<AppProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) { public CommonResult<AppProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) {
// 获得商品 SPU return success(productSpuService.getAppProductSpuDetail(id));
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));
} }
} }

View File

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

View File

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

View File

@ -1,12 +1,9 @@
package cn.iocoder.yudao.module.product.dal.mysql.sku; package cn.iocoder.yudao.module.product.dal.mysql.sku;
import cn.hutool.core.lang.Assert; 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.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; 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.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; 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")); 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));
}
} }

View File

@ -68,7 +68,10 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
throw exception(CATEGORY_EXISTS_CHILDREN); throw exception(CATEGORY_EXISTS_CHILDREN);
} }
// 校验分类是否绑定了 SPU // 校验分类是否绑定了 SPU
validateProductCategoryIsHaveBindSpu(id); Long count = productSpuService.getSpuCountByCategoryId(id);
if (0 != count) {
throw exception(CATEGORY_HAVE_BIND_SPU);
}
// 删除 // 删除
productCategoryMapper.deleteById(id); 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 @Override
public ProductCategoryDO getCategory(Long id) { public ProductCategoryDO getCategory(Long id) {
return productCategoryMapper.selectById(id); return productCategoryMapper.selectById(id);

View File

@ -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.AppCommentAdditionalReqVO;
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; 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.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.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.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated; 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.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
/** /**
* 商品评论 Service 实现类 * 商品评论 Service 实现类
@ -30,6 +35,11 @@ public class ProductCommentServiceImpl implements ProductCommentService {
@Resource @Resource
private ProductCommentMapper productCommentMapper; private ProductCommentMapper productCommentMapper;
@Resource
private TradeOrderApi tradeOrderApi;
@Resource
private ProductSpuService productSpuService;
@Override @Override
public PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO) { public PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO) {
@ -60,6 +70,16 @@ public class ProductCommentServiceImpl implements ProductCommentService {
@Override @Override
public void createComment(ProductCommentDO productComment, Boolean system) { public void createComment(ProductCommentDO productComment, Boolean system) {
if (!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()); ProductCommentDO exist = productCommentMapper.findByUserIdAndOrderIdAndSpuId(productComment.getId(), productComment.getOrderId(), productComment.getSpuId());
if (null != exist) { if (null != exist) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.category.vo.ProductCategoryListReqVO;
import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.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.convert.spu.ProductSpuConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; 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.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; 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.dal.mysql.spu.ProductSpuMapper;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; 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.brand.ProductBrandService;
import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; 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 cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -50,6 +56,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
private ProductBrandService brandService; private ProductBrandService brandService;
@Resource @Resource
private ProductCategoryService categoryService; private ProductCategoryService categoryService;
@Resource
@Lazy // 循环依赖避免报错
private ProductPropertyValueService productPropertyValueService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -140,7 +149,11 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 校验存在 // 校验存在
validateSpuExists(id); validateSpuExists(id);
// 校验商品状态不是回收站不能删除 // 校验商品状态不是回收站不能删除
validateSpuStatus(id); ProductSpuDO spuDO = productSpuMapper.selectById(id);
// 判断 SPU 状态是否为回收站
if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) {
throw exception(SPU_NOT_RECYCLE);
}
// 删除 SPU // 删除 SPU
productSpuMapper.deleteById(id); 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 @Override
public ProductSpuDO getSpu(Long id) { public ProductSpuDO getSpu(Long id) {
return productSpuMapper.selectById(id); return productSpuMapper.selectById(id);
@ -257,4 +256,35 @@ public class ProductSpuServiceImpl implements ProductSpuService {
return productSpuMapper.selectCount(ProductSpuDO::getCategoryId, id); 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);
}
} }

View File

@ -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);
}

View File

@ -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;
}

View File

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

View File

@ -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));
}
}

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

@ -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.property.dto.ProductPropertyValueDetailRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; 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.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.member.user.MemberUserRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO; 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, TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO,
TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address); TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address);
TradeOrderRespDTO convert(TradeOrderDO orderDO);
default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) { default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) {
return CollectionUtils.convertList(calculateRespBO.getItems(), item -> { return CollectionUtils.convertList(calculateRespBO.getItems(), item -> {
TradeOrderItemDO orderItem = convert(item); TradeOrderItemDO orderItem = convert(item);