mall + product:review 评论接口

This commit is contained in:
YunaiV 2023-06-09 13:59:04 +08:00
parent 4126e37d91
commit f2d803c111
14 changed files with 92 additions and 119 deletions

View File

@ -6,7 +6,9 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
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;
@ -22,8 +24,10 @@ import java.io.IOException;
import java.util.List;
import java.util.Map;
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.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
/**
* 商品 SPU 相关接口
@ -38,6 +42,8 @@ public class ProductSpuController {
@Resource
private ProductSpuService productSpuService;
@Resource
private ProductSkuService productSkuService;
@PostMapping("/create")
@Operation(summary = "创建商品 SPU")
@ -58,7 +64,7 @@ public class ProductSpuController {
@Operation(summary = "更新商品 SPU Status")
@PreAuthorize("@ss.hasPermission('product:spu:update')")
public CommonResult<Boolean> updateStatus(@Valid @RequestBody ProductSpuUpdateStatusReqVO updateReqVO) {
productSpuService.updateStatus(updateReqVO);
productSpuService.updateSpuStatus(updateReqVO);
return success(true);
}
@ -76,7 +82,14 @@ public class ProductSpuController {
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('product:spu:query')")
public CommonResult<ProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) {
return success(productSpuService.getSpuDetail(id));
// 获得商品 SPU
ProductSpuDO spu = productSpuService.getSpu(id);
if (spu == null) {
throw exception(SPU_NOT_EXISTS);
}
// 查询商品 SKU
List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
return success(ProductSpuConvert.INSTANCE.convertForSpuDetailRespVO(spu, skus));
}
@GetMapping("/get-simple-list")

View File

@ -6,7 +6,11 @@ import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetail
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.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.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;
@ -19,8 +23,12 @@ 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
@ -30,6 +38,10 @@ public class AppProductSpuController {
@Resource
private ProductSpuService productSpuService;
@Resource
private ProductSkuService productSkuService;
@Resource
private ProductPropertyValueService productPropertyValueService;
@GetMapping("/page")
@Operation(summary = "获得商品 SPU 分页")
@ -38,12 +50,23 @@ public class AppProductSpuController {
return success(ProductSpuConvert.INSTANCE.convertPageForGetSpuPage(pageResult));
}
// TODO 芋艿等会看看
@GetMapping("/get-detail")
@Operation(summary = "获得商品 SPU 明细")
@Parameter(name = "id", description = "编号", required = true)
public CommonResult<AppProductSpuDetailRespVO> getSpuDetail(@RequestParam("id") Long id) {
return success(productSpuService.getAppProductSpuDetail(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());
// 拼接
return success(ProductSpuConvert.INSTANCE.convertForGetSpuDetail(spu, skus));
}
}

View File

@ -22,13 +22,13 @@ import lombok.*;
public class ProductPropertyDO extends BaseDO {
/**
* 默认属性id
* SPU 单规格时默认属性 id
*/
public static final Long PROPERTY_ID = 0L;
public static final Long ID_DEFAULT = 0L;
/**
* 默认属性名字
* SPU 单规格时默认属性名字
*/
public static final String PROPERTY_NAME = "默认";
public static final String NAME_DEFAULT = "默认";
/**
* 主键

View File

@ -23,13 +23,13 @@ import lombok.*;
public class ProductPropertyValueDO extends BaseDO {
/**
* 默认属性值id
* SPU 单规格时默认属性值 id
*/
public static final Long VALUE_ID = 0L;
public static final Long ID_DEFAULT = 0L;
/**
* 默认属性值名字
* SPU 单规格时默认属性值名字
*/
public static final String VALUE_NAME = "默认";
public static final String NAME_DEFAULT = "默认";
/**
* 主键

View File

@ -35,6 +35,7 @@ public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
.orderByDesc(ProductCommentDO::getId));
}
// TODO 芋艿在看看这块
static void appendTabQuery(LambdaQueryWrapperX<ProductCommentDO> queryWrapper, Integer type) {
// 构建好评查询语句
if (ObjectUtil.equal(type, AppCommentPageReqVO.FAVOURABLE_COMMENT)) {

View File

@ -68,8 +68,8 @@ public class ProductCategoryServiceImpl implements ProductCategoryService {
throw exception(CATEGORY_EXISTS_CHILDREN);
}
// 校验分类是否绑定了 SPU
Long count = productSpuService.getSpuCountByCategoryId(id);
if (0 != count) {
Long spuCount = productSpuService.getSpuCountByCategoryId(id);
if (spuCount > 0) {
throw exception(CATEGORY_HAVE_BIND_SPU);
}
// 删除

View File

@ -31,6 +31,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
// TODO @芋艿详细 review
/**
* 商品评论 Service 实现类
*
@ -73,13 +74,17 @@ public class ProductCommentServiceImpl implements ProductCommentService {
public Map<String, Long> getCommentPageTabsCount(Long spuId, Boolean visible) {
Map<String, Long> countMap = new HashMap<>(4);
// 查询商品 id = spuId 的所有评论数量
countMap.put(AppCommentPageReqVO.ALL_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.ALL));
countMap.put(AppCommentPageReqVO.ALL_COUNT,
productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.ALL));
// 查询商品 id = spuId 的所有好评数量
countMap.put(AppCommentPageReqVO.FAVOURABLE_COMMENT_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.FAVOURABLE_COMMENT));
countMap.put(AppCommentPageReqVO.FAVOURABLE_COMMENT_COUNT,
productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.FAVOURABLE_COMMENT));
// 查询商品 id = spuId 的所有中评数量
countMap.put(AppCommentPageReqVO.MEDIOCRE_COMMENT_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT));
countMap.put(AppCommentPageReqVO.MEDIOCRE_COMMENT_COUNT,
productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT));
// 查询商品 id = spuId 的所有差评数量
countMap.put(AppCommentPageReqVO.NEGATIVE_COMMENT_COUNT, productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT));
countMap.put(AppCommentPageReqVO.NEGATIVE_COMMENT_COUNT,
productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT));
return countMap;
}
@ -101,13 +106,14 @@ public class ProductCommentServiceImpl implements ProductCommentService {
@Override
public void createComment(ProductCommentDO productComment, Boolean system) {
// TODO @puhui999这里不区分是否为 system直接都校验
if (!system) {
// TODO 判断订单是否存在 fix
// TODO 判断订单是否存在 fix
// TODO @puhui999改成 order 那有个 comment 接口哪里校验下商品评论这里不校验订单是否存在哈
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);
@ -147,5 +153,4 @@ public class ProductCommentServiceImpl implements ProductCommentService {
return productComment;
}
}

View File

@ -83,21 +83,20 @@ public class ProductSkuServiceImpl implements ProductSkuService {
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);
property.setPropertyId(ProductPropertyDO.ID_DEFAULT);
property.setPropertyName(ProductPropertyDO.NAME_DEFAULT);
property.setValueId(ProductPropertyValueDO.ID_DEFAULT);
property.setValueName(ProductPropertyValueDO.NAME_DEFAULT);
properties.add(property);
skuVO.setProperties(properties);
// 单规格不需要后续的校验
return;
return; // 单规格不需要后续的校验
}
// 1校验属性项存在
Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null)
// 遍历多个 Property 属性

View File

@ -2,7 +2,6 @@ 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;
@ -107,40 +106,25 @@ public interface ProductSpuService {
void updateSpuStock(Map<Long, Integer> stockIncrCounts);
/**
* 得到spu详细
* 更新 SPU 状态
*
* @param id id
* @return {@link ProductSpuDetailRespVO}
* @param updateReqVO 更新请求
*/
ProductSpuDetailRespVO getSpuDetail(Long id);
void updateSpuStatus(ProductSpuUpdateStatusReqVO updateReqVO);
/**
* 更新状态
* 获取 SPU 列表标签对应的 Count 数量
*
* @param updateReqVO 更新请求签证官
*/
void updateStatus(ProductSpuUpdateStatusReqVO updateReqVO);
/**
* 获取spu列表标签对应的Count数量
*
* @return {@link Map}<{@link Integer}, {@link Integer}>
* @return Count 数量
*/
Map<Integer, Long> getTabsCount();
/**
* 通过分类 id 查询 spu 个数
* 通过分类 categoryId 查询 SPU 个数
*
* @param id 分类 id
* @return spu
* @param categoryId 分类 categoryId
* @return SPU 数量
*/
Long getSpuCountByCategoryId(Long id);
Long getSpuCountByCategoryId(Long categoryId);
/**
* 通过 spu id 获取商品 SPU 明细
*
* @param id id
* @return 用户 App - 商品 SPU 明细
*/
AppProductSpuDetailRespVO getAppProductSpuDetail(Long id);
}

View File

@ -7,21 +7,15 @@ 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 com.google.common.collect.Maps;
import org.springframework.context.annotation.Lazy;
@ -114,9 +108,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
spu.setPrice(getMinValue(skus, ProductSkuCreateOrUpdateReqVO::getPrice));
// sku 单价最低的商品的市场价格
spu.setMarketPrice(getMinValue(skus, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
// sku单价最低的商品的成本价格
// sku 单价最低的商品的成本价格
spu.setCostPrice(getMinValue(skus, ProductSkuCreateOrUpdateReqVO::getCostPrice));
// sku单价最低的商品的条形码
// sku 单价最低的商品的条形码
spu.setBarCode(getMinValue(skus, ProductSkuCreateOrUpdateReqVO::getBarCode));
// skus 库存总数
spu.setStock(getSumValue(skus, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
@ -213,21 +207,9 @@ public class ProductSpuServiceImpl implements ProductSpuService {
stockIncrCounts.forEach((id, incCount) -> productSpuMapper.updateStock(id, incCount));
}
@Override
public ProductSpuDetailRespVO getSpuDetail(Long id) {
// 获得商品 SPU
ProductSpuDO spu = getSpu(id);
if (spu == null) {
throw exception(SPU_NOT_EXISTS);
}
// 查询商品 SKU
List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
return ProductSpuConvert.INSTANCE.convertForSpuDetailRespVO(spu, skus);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateStatus(ProductSpuUpdateStatusReqVO updateReqVO) {
public void updateSpuStatus(ProductSpuUpdateStatusReqVO updateReqVO) {
// 校验存在
validateSpuExists(updateReqVO.getId());
@ -258,39 +240,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
}
@Override
public Long getSpuCountByCategoryId(Long 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);
public Long getSpuCountByCategoryId(Long categoryId) {
return productSpuMapper.selectCount(ProductSpuDO::getCategoryId, categoryId);
}
}

View File

@ -34,6 +34,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
// TODO 芋艿单测详细 review
/**
* {@link ProductCommentServiceImpl} 的单元测试类
*

View File

@ -23,26 +23,24 @@ 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;
/**
@ -55,7 +53,7 @@ public class TradeOrderRespDTO {
private String userRemark;
/**
* 订单状态
* <p>
*
* 枚举 {@link TradeOrderStatusEnum}
*/
private Integer status;
@ -73,7 +71,7 @@ public class TradeOrderRespDTO {
private LocalDateTime cancelTime;
/**
* 取消类型
* <p>
*
* 枚举 {@link TradeOrderCancelTypeEnum}
*/
private Integer cancelType;
@ -83,9 +81,6 @@ public class TradeOrderRespDTO {
private String remark;
/**
* 是否评价
* <p>
* true - 已评价
* false - 未评价
*/
private Boolean commentStatus;

View File

@ -70,7 +70,6 @@ public class DeliveryExpressTemplateController {
return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list));
}
// TODO @puhui999DeliveryExpressTemplateRespVO 搞个 simple 的哈 fix
@GetMapping("/list-all-simple")
@Operation(summary = "获取快递模版精简信息列表", description = "主要用于前端的下拉选项")
public CommonResult<List<DeliveryExpressTemplateSimpleRespVO>> getSimpleTemplateList() {

View File

@ -100,6 +100,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
private AdminUserApi adminUserApi;
@Resource
private NotifyMessageSendApi notifyMessageSendApi;
@Resource
private TradeOrderProperties tradeOrderProperties;
@ -356,6 +357,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// TODO 芋艿发送订单变化的消息
// TODO 芋艿发送站内信 fix
// TODO @puhui999使用 sendSingleMessageToMember 走模版不用判断模版是否存在哈
// 1获取模版编码为 order_delivery 的模版判断是否存在 存在放回 true
if (!notifyMessageSendApi.validateNotifyTemplate("order_delivery")) {
// 11 站内信模版不存在则创建模版