fix:修复 mall review @puhui999

This commit is contained in:
puhui999 2023-07-10 16:35:49 +08:00
parent 9cbd0fec1c
commit e7d8643665
38 changed files with 207 additions and 244 deletions

View File

@ -4,6 +4,7 @@ import cn.hutool.core.date.LocalDateTimeUtil;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime;
/** /**
* 时间工具类用于 {@link java.time.LocalDateTime} * 时间工具类用于 {@link java.time.LocalDateTime}
@ -50,7 +51,7 @@ public class LocalDateTimeUtils {
* 判断当前时间是否在该时间范围内 * 判断当前时间是否在该时间范围内
* *
* @param startTime 开始时间 * @param startTime 开始时间
* @param endTime 结束时间 * @param endTime 结束时间
* @return 是否 * @return 是否
*/ */
public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) { public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
@ -60,4 +61,23 @@ public class LocalDateTimeUtils {
return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime); return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
} }
/**
* 检查时间重叠 不包含日期
*
* @param startTime1 需要校验的开始时间
* @param endTime1 需要校验的结束时间
* @param startTime2 校验所需的开始时间
* @param endTime2 校验所需的结束时间
* @return 是否重叠
*/
public static boolean checkTimeOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
// 判断时间是否重叠
// 开始时间在已配置时段的结束时间之前 结束时间在已配置时段的开始时间之后 []
return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的开始时间之前 结束时间在已配置时段的开始时间之后 (] ()
|| startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的结束时间之前 结束时间在已配值时段的结束时间之后 [) ()
|| startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
}
} }

View File

@ -46,7 +46,7 @@ public interface ErrorCodeConstants {
// ========== 商品 评价 1008007000 ========== // ========== 商品 评价 1008007000 ==========
ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1008007000, "商品 评价 不存在"); ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1008007000, "商品 评价 不存在");
ErrorCode ORDER_SPU_COMMENT_EXISTS = new ErrorCode(1008007001, "订单 商品评价 已存在"); ErrorCode ORDER_SKU_COMMENT_EXISTS = new ErrorCode(1008007001, "订单 商品评价 已存在");
ErrorCode COMMENT_ERROR_OPT = new ErrorCode(1008007002, "商品评价非法操作"); ErrorCode COMMENT_ERROR_OPT = new ErrorCode(1008007002, "商品评价非法操作");
ErrorCode COMMENT_ADDITIONAL_EXISTS = new ErrorCode(1008007003, "商品追加评价已存在"); ErrorCode COMMENT_ADDITIONAL_EXISTS = new ErrorCode(1008007003, "商品追加评价已存在");

View File

@ -26,23 +26,10 @@ public class ProductCommentBaseVO {
@NotNull(message = "评价人头像不能为空") @NotNull(message = "评价人头像不能为空")
private String userAvatar; private String userAvatar;
// TODO @puhuispuIdspuName 是不是只有 ProductCommentRespVO 有呀
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖")
@NotNull(message = "商品 SPU 编号不能为空")
private Long spuId;
@Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
@NotNull(message = "商品 SPU 名称不能为空")
private String spuName;
@Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "商品 SKU 编号不能为空") @NotNull(message = "商品 SKU 编号不能为空")
private Long skuId; private Long skuId;
@Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
@NotNull(message = "评分星级不能为空")
private Integer scores;
@Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
@NotNull(message = "描述星级不能为空") @NotNull(message = "描述星级不能为空")
private Integer descriptionScores; private Integer descriptionScores;

View File

@ -35,9 +35,8 @@ public class ProductCommentPageReqVO extends PageParam {
@InEnum(ProductCommentScoresEnum.class) @InEnum(ProductCommentScoresEnum.class)
private Integer scores; private Integer scores;
// TODO @puhui999replyStatus
@Schema(description = "商家是否回复", example = "true") @Schema(description = "商家是否回复", example = "true")
private Boolean replied; private Boolean replyStatus;
@Schema(description = "创建时间") @Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

View File

@ -5,6 +5,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Schema(description = "管理后台 - 商品评价 Response VO") @Schema(description = "管理后台 - 商品评价 Response VO")
@ -40,4 +41,15 @@ public class ProductCommentRespVO extends ProductCommentBaseVO {
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
private Integer scores;
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖")
@NotNull(message = "商品 SPU 编号不能为空")
private Long spuId;
@Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
@NotNull(message = "商品 SPU 名称不能为空")
private String spuName;
} }

View File

@ -30,11 +30,6 @@ 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.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
/**
* 商品 SPU 相关接口
*
* @author HUIHUI
*/
@Tag(name = "管理后台 - 商品 SPU") @Tag(name = "管理后台 - 商品 SPU")
@RestController @RestController
@RequestMapping("/product/spu") @RequestMapping("/product/spu")

View File

@ -9,11 +9,6 @@ import lombok.ToString;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.util.List;
/**
* 商品 SPU 创建 Request VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品 SPU 创建 Request VO") @Schema(description = "管理后台 - 商品 SPU 创建 Request VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -8,12 +8,6 @@ import lombok.ToString;
import java.util.List; import java.util.List;
/**
* 商品 SPU 详细 Response VO
* 包括关联的 SKU 等信息
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品 SPU 详细 Response VO") @Schema(description = "管理后台 - 商品 SPU 详细 Response VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -10,11 +10,6 @@ import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的") @Schema(description = "管理后台 - 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的")
@Data @Data
@NoArgsConstructor @NoArgsConstructor

View File

@ -11,11 +11,6 @@ import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 商品 SPU 分页 Request VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品 SPU 分页 Request VO") @Schema(description = "管理后台 - 商品 SPU 分页 Request VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -7,11 +7,6 @@ import lombok.ToString;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/**
* 商品 SPU Response VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品 SPU Response VO") @Schema(description = "管理后台 - 商品 SPU Response VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -4,11 +4,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.ToString; import lombok.ToString;
/**
* 商品 SPU 精简 Response VO
* TODO 商品 SPU 精简 VO 暂时没有使用到用到的时候再按需添加\修改属性
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品 SPU 精简 Response VO") @Schema(description = "管理后台 - 商品 SPU 精简 Response VO")
@Data @Data
@ToString(callSuper = true) @ToString(callSuper = true)

View File

@ -12,11 +12,6 @@ import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
/**
* 商品 SPU 更新 Request VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品 SPU 更新 Request VO") @Schema(description = "管理后台 - 商品 SPU 更新 Request VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -7,11 +7,6 @@ import lombok.Data;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
/**
* 商品 SPU Status 更新 Request VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 商品 SPU Status 更新 Request VO") @Schema(description = "管理后台 - 商品 SPU Status 更新 Request VO")
@Data @Data
public class ProductSpuUpdateStatusReqVO{ public class ProductSpuUpdateStatusReqVO{

View File

@ -1,18 +1,18 @@
package cn.iocoder.yudao.module.product.controller.app.comment; package cn.iocoder.yudao.module.product.controller.app.comment;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
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.controller.app.comment.vo.AppCommentStatisticsRespVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert; import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
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.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.service.comment.ProductCommentService; import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
import com.google.common.collect.Maps;
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;
import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.Parameters;
@ -26,11 +26,9 @@ 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.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -61,26 +59,14 @@ public class AppProductCommentController {
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得商品评价分页") @Operation(summary = "获得商品评价分页")
public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) { public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
PageResult<AppProductCommentRespVO> page = productCommentService.getCommentPage(pageVO, Boolean.TRUE); PageResult<ProductCommentDO> commentDOPage = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
// TODO @puhui CollUtils 有简化 convertmap list 的方法 Set<Long> skuIds = CollectionUtils.convertSet(commentDOPage.getList(), ProductCommentDO::getSkuId);
Set<Long> skuIds = page.getList().stream().map(AppProductCommentRespVO::getSkuId).collect(Collectors.toSet());
List<ProductSkuDO> skuList = productSkuService.getSkuList(skuIds); List<ProductSkuDO> skuList = productSkuService.getSkuList(skuIds);
Map<Long, ProductSkuDO> skuDOMap = new HashMap<>(skuIds.size()); Map<Long, ProductSkuDO> skuDOMap = Maps.newLinkedHashMapWithExpectedSize(skuIds.size());
if (CollUtil.isNotEmpty(skuList)) { if (CollUtil.isNotEmpty(skuList)) {
skuDOMap.putAll(skuList.stream().collect(Collectors.toMap(ProductSkuDO::getId, c -> c))); skuDOMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId, c -> c));
} }
// TODO @puihui999下面也可以放到 convert 里哈 PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, skuDOMap);
page.getList().forEach(item -> {
// 判断用户是否选择匿名
if (ObjectUtil.equal(item.getAnonymous(), true)) {
item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
}
ProductSkuDO productSkuDO = skuDOMap.get(item.getSkuId());
if (productSkuDO != null) {
List<AppProductPropertyValueDetailRespVO> skuProperties = ProductCommentConvert.INSTANCE.convertList01(productSkuDO.getProperties());
item.setSkuProperties(skuProperties);
}
});
return success(page); return success(page);
} }

View File

@ -10,11 +10,6 @@ import javax.validation.constraints.Size;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/**
* 用户 App - 商品评价详情 Response VO
*
* @author HUIHUI
*/
@Schema(description = "用户 App - 商品评价详情 Response VO") @Schema(description = "用户 App - 商品评价详情 Response VO")
@Data @Data
@ToString(callSuper = true) @ToString(callSuper = true)

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.product.convert.comment; package cn.iocoder.yudao.module.product.convert.comment;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
@ -19,6 +20,7 @@ import org.mapstruct.factory.Mappers;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 商品评价 Convert * 商品评价 Convert
@ -32,10 +34,12 @@ public interface ProductCommentConvert {
ProductCommentRespVO convert(ProductCommentDO bean); ProductCommentRespVO convert(ProductCommentDO bean);
// TODO @puhui999这里貌似字段对上就不用 mapping 可以测试下看看哈 @Named("calculateOverallScore")
@Mapping(target = "goodCount", source = "goodCount") default double calculateOverallScore(long goodCount, long mediocreCount, long negativeCount) {
@Mapping(target = "mediocreCount", source = "mediocreCount") return (goodCount * 5 + mediocreCount * 3 + negativeCount) / (double) (goodCount + mediocreCount + negativeCount);
@Mapping(target = "negativeCount", source = "negativeCount") }
@Mapping(target = "scores", expression = "java(calculateOverallScore(goodCount, mediocreCount, negativeCount))")
AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount); AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount);
List<ProductCommentRespVO> convertList(List<ProductCommentDO> list); List<ProductCommentRespVO> convertList(List<ProductCommentDO> list);
@ -44,7 +48,23 @@ public interface ProductCommentConvert {
PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> page); PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> page);
PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult); PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult);
default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult, Map<Long, ProductSkuDO> skuDOMap) {
PageResult<AppProductCommentRespVO> page = convertPage01(pageResult);
page.getList().forEach(item -> {
// 判断用户是否选择匿名
if (ObjectUtil.equal(item.getAnonymous(), true)) {
item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
}
ProductSkuDO productSkuDO = skuDOMap.get(item.getSkuId());
if (productSkuDO != null) {
List<AppProductPropertyValueDetailRespVO> skuProperties = ProductCommentConvert.INSTANCE.convertList01(productSkuDO.getProperties());
item.setSkuProperties(skuProperties);
}
});
return page;
}
/** /**
* 计算综合评分 * 计算综合评分

View File

@ -51,11 +51,11 @@ public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
return selectPage(reqVO, queryWrapper); return selectPage(reqVO, queryWrapper);
} }
default ProductCommentDO selectByUserIdAndOrderItemIdAndSpuId(Long userId, Long orderItemId, Long spuId) { default ProductCommentDO selectByUserIdAndOrderItemIdAndSpuId(Long userId, Long orderItemId, Long skuId) {
return selectOne(new LambdaQueryWrapperX<ProductCommentDO>() return selectOne(new LambdaQueryWrapperX<ProductCommentDO>()
.eq(ProductCommentDO::getUserId, userId) .eq(ProductCommentDO::getUserId, userId)
.eq(ProductCommentDO::getOrderItemId, orderItemId) .eq(ProductCommentDO::getOrderItemId, orderItemId)
.eq(ProductCommentDO::getSpuId, spuId)); .eq(ProductCommentDO::getSpuId, skuId));
} }
default Long selectCountBySpuId(Long spuId, Boolean visible, Integer type) { default Long selectCountBySpuId(Long spuId, Boolean visible, Integer type) {

View File

@ -54,7 +54,7 @@ public interface ProductCommentService {
* @param visible 是否可见 * @param visible 是否可见
* @return 商品评价分页 * @return 商品评价分页
*/ */
PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible); PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
/** /**
* 创建商品评论 * 创建商品评论

View File

@ -81,7 +81,7 @@ public class ProductCommentServiceImpl implements ProductCommentService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void createComment(ProductCommentCreateReqVO createReqVO) { public void createComment(ProductCommentCreateReqVO createReqVO) {
// 校验评论 // 校验评论
validateComment(createReqVO.getSpuId(), createReqVO.getUserId(), createReqVO.getOrderItemId()); validateComment(createReqVO.getSkuId(), createReqVO.getUserId(), createReqVO.getOrderItemId());
ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqVO); ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqVO);
productCommentMapper.insert(commentDO); productCommentMapper.insert(commentDO);
@ -108,11 +108,11 @@ public class ProductCommentServiceImpl implements ProductCommentService {
return commentDO.getId(); return commentDO.getId();
} }
private void validateComment(Long spuId, Long userId, Long orderItemId) { private void validateComment(Long skuId, Long userId, Long orderItemId) {
// 判断当前订单的当前商品用户是否评价过 // 判断当前订单的当前商品用户是否评价过
ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemIdAndSpuId(userId, orderItemId, spuId); ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemIdAndSpuId(userId, orderItemId, skuId);
if (null != exist) { if (null != exist) {
throw exception(ORDER_SPU_COMMENT_EXISTS); throw exception(ORDER_SKU_COMMENT_EXISTS);
} }
} }
@ -141,23 +141,17 @@ public class ProductCommentServiceImpl implements ProductCommentService {
productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT), productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT),
// 查询商品 id = spuId 的所有差评数量 // 查询商品 id = spuId 的所有差评数量
productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT) productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT)
).setScores(3.0); // TODO @puhui999这里要实现下 );
} }
@Override @Override
public List<AppProductCommentRespVO> getCommentList(Long spuId, Integer count) { public List<AppProductCommentRespVO> getCommentList(Long spuId, Integer count) {
// 校验商品 spu 是否存在 return ProductCommentConvert.INSTANCE.convertList02(productCommentMapper.selectCommentList(spuId, count).getList());
// TODO @puhui 这里校验可以去掉哈
ProductSpuDO spuDO = validateSpu(spuId);
return ProductCommentConvert.INSTANCE.convertList02(productCommentMapper.selectCommentList(spuDO.getId(), count).getList());
} }
// TODO @puhui 可以放到 controller convert
@Override @Override
public PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) { public PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) {
// TODO @puhui 可以放到 controller convert return productCommentMapper.selectPage(pageVO, visible);
return ProductCommentConvert.INSTANCE.convertPage02(
productCommentMapper.selectPage(pageVO, visible));
} }
@Override @Override

View File

@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommen
import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO;
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.controller.app.comment.vo.AppCommentStatisticsRespVO; import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert; import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
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.mysql.comment.ProductCommentMapper; import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper;
@ -128,7 +127,7 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
productCommentPageReqVO.setSpuId(spuId); productCommentPageReqVO.setSpuId(spuId);
productCommentPageReqVO.setSpuName("感冒药"); productCommentPageReqVO.setSpuName("感冒药");
productCommentPageReqVO.setScores(ProductCommentScoresEnum.FOUR.getScores()); productCommentPageReqVO.setScores(ProductCommentScoresEnum.FOUR.getScores());
productCommentPageReqVO.setReplied(Boolean.TRUE); productCommentPageReqVO.setReplyStatus(Boolean.TRUE);
PageResult<ProductCommentDO> commentPage = productCommentService.getCommentPage(productCommentPageReqVO); PageResult<ProductCommentDO> commentPage = productCommentService.getCommentPage(productCommentPageReqVO);
PageResult<ProductCommentRespVO> result = ProductCommentConvert.INSTANCE.convertPage(productCommentMapper.selectPage(productCommentPageReqVO)); PageResult<ProductCommentRespVO> result = ProductCommentConvert.INSTANCE.convertPage(productCommentMapper.selectPage(productCommentPageReqVO));
@ -138,15 +137,15 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
assertEquals(8, all.getTotal()); assertEquals(8, all.getTotal());
// 测试获取所有商品分页评论数据 // 测试获取所有商品分页评论数据
PageResult<AppProductCommentRespVO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE); PageResult<ProductCommentDO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE);
assertEquals(7, result1.getTotal()); assertEquals(7, result1.getTotal());
// 测试获取所有商品分页中评数据 // 测试获取所有商品分页中评数据
PageResult<AppProductCommentRespVO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); PageResult<ProductCommentDO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
assertEquals(2, result2.getTotal()); assertEquals(2, result2.getTotal());
// 测试获取指定 spuId 商品分页中评数据 // 测试获取指定 spuId 商品分页中评数据
PageResult<AppProductCommentRespVO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); PageResult<ProductCommentDO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
assertEquals(2, result3.getTotal()); assertEquals(2, result3.getTotal());
// 测试分页 tab count // 测试分页 tab count

View File

@ -19,11 +19,6 @@ import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* 管理后台 - 秒杀时段相关接口
*
* @author HUIHUI
*/
@Tag(name = "管理后台 - 秒杀时段") @Tag(name = "管理后台 - 秒杀时段")
@RestController @RestController
@RequestMapping("/promotion/seckill-config") @RequestMapping("/promotion/seckill-config")

View File

@ -9,11 +9,6 @@ import lombok.ToString;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/**
* 管理后台 - 秒杀活动 Response VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 秒杀活动 Response VO") @Schema(description = "管理后台 - 秒杀活动 Response VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -1,9 +1,13 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config; package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.time.LocalTime;
import java.util.List;
/** /**
* 秒杀时段 Base VO提供给添加修改详细的子 VO 使用 * 秒杀时段 Base VO提供给添加修改详细的子 VO 使用
@ -26,12 +30,24 @@ public class SeckillConfigBaseVO {
@NotNull(message = "结束时间点不能为空") @NotNull(message = "结束时间点不能为空")
private String endTime; private String endTime;
@Schema(description = "秒杀", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") @Schema(description = "秒杀轮播", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]")
@NotNull(message = "秒杀图不能为空") @NotNull(message = "秒杀轮播图不能为空")
private String picUrl; private List<String> sliderPicUrls;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "状态不能为空") @NotNull(message = "状态不能为空")
private Integer status; private Integer status;
@AssertTrue(message = "秒杀时段开始时间和结束时间不能相等")
@JsonIgnore
public boolean isValidStartTimeValid() {
return !LocalTime.parse(startTime).equals(LocalTime.parse(endTime));
}
@AssertTrue(message = "秒杀时段开始时间不能在结束时间之后")
@JsonIgnore
public boolean isValidEndTimeValid() {
return !LocalTime.parse(startTime).isAfter(LocalTime.parse(endTime));
}
} }

View File

@ -6,12 +6,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
// TODO @puhuiVO 上不写注释已经有注解啦
/**
* 管理后台 - 秒杀时段分页 Request VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 秒杀时段分页 Request VO") @Schema(description = "管理后台 - 秒杀时段分页 Request VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -1,16 +1,9 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.*; import lombok.Data;
import lombok.EqualsAndHashCode;
/** import lombok.ToString;
* 管理后台 - 秒杀参与商品创建 Request VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 秒杀参与商品创建 Request VO") @Schema(description = "管理后台 - 秒杀参与商品创建 Request VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -1,14 +1,12 @@
package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/**
* 管理后台 - 秒杀参与商品 Response VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 秒杀参与商品 Response VO") @Schema(description = "管理后台 - 秒杀参与商品 Response VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -5,11 +5,6 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
/**
* 管理后台 - 秒杀参与商品更新 Request VO
*
* @author HUIHUI
*/
@Schema(description = "管理后台 - 秒杀参与商品更新 Request VO") @Schema(description = "管理后台 - 秒杀参与商品更新 Request VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -3,22 +3,27 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.EqualsAndHashCode; import lombok.*;
import lombok.ToString;
import java.util.List;
/** /**
* 秒杀时段 DO * 秒杀时段 DO
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@TableName("promotion_seckill_config") @TableName(value = "promotion_seckill_config", autoResultMap = true)
@KeySequence("promotion_seckill_config_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写 @KeySequence("promotion_seckill_config_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SeckillConfigDO extends BaseDO { public class SeckillConfigDO extends BaseDO {
/** /**
@ -38,14 +43,14 @@ public class SeckillConfigDO extends BaseDO {
* 结束时间点 * 结束时间点
*/ */
private String endTime; private String endTime;
// TODO puhui999应该是轮播图 private List<String> sliderPicUrls;
/** /**
* 秒杀 * 秒杀轮播
*/ */
private String picUrl; @TableField(typeHandler = JacksonTypeHandler.class)
private List<String> sliderPicUrls;
/** /**
* 状态 * 状态
* * <p>
* 枚举 {@link CommonStatusEnum 对应的类} * 枚举 {@link CommonStatusEnum 对应的类}
*/ */
private Integer status; private Integer status;

View File

@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper @Mapper
public interface SeckillConfigMapper extends BaseMapperX<SeckillConfigDO> { public interface SeckillConfigMapper extends BaseMapperX<SeckillConfigDO> {
@ -17,4 +19,9 @@ public interface SeckillConfigMapper extends BaseMapperX<SeckillConfigDO> {
.orderByDesc(SeckillConfigDO::getId)); .orderByDesc(SeckillConfigDO::getId));
} }
default List<SeckillConfigDO> selectListByStatus(Integer status) {
return selectList(SeckillConfigDO::getStatus, status);
}
} }

View File

@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
@ -12,14 +13,13 @@ import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillCo
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
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.promotion.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@ -37,9 +37,10 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
private SeckillConfigMapper seckillConfigMapper; private SeckillConfigMapper seckillConfigMapper;
@Override @Override
@Transactional(rollbackFor = Exception.class)
public Long createSeckillConfig(SeckillConfigCreateReqVO createReqVO) { public Long createSeckillConfig(SeckillConfigCreateReqVO createReqVO) {
// 校验时间段是否冲突 // 校验时间段是否冲突
validateSeckillConfigConflict(createReqVO.getStartTime(), createReqVO.getEndTime()); validateSeckillConfigConflict(createReqVO.getStartTime(), createReqVO.getEndTime(), null);
// 插入 // 插入
SeckillConfigDO seckillConfig = SeckillConfigConvert.INSTANCE.convert(createReqVO); SeckillConfigDO seckillConfig = SeckillConfigConvert.INSTANCE.convert(createReqVO);
@ -49,18 +50,30 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateSeckillConfig(SeckillConfigUpdateReqVO updateReqVO) { public void updateSeckillConfig(SeckillConfigUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
validateSeckillConfigExists(updateReqVO.getId()); validateSeckillConfigExists(updateReqVO.getId());
// 校验时间段是否冲突 // 校验时间段是否冲突
validateSeckillConfigConflict(updateReqVO.getStartTime(), updateReqVO.getEndTime()); validateSeckillConfigConflict(updateReqVO.getStartTime(), updateReqVO.getEndTime(), updateReqVO.getId());
// 更新 // 更新
SeckillConfigDO updateObj = SeckillConfigConvert.INSTANCE.convert(updateReqVO); SeckillConfigDO updateObj = SeckillConfigConvert.INSTANCE.convert(updateReqVO);
seckillConfigMapper.updateById(updateObj); seckillConfigMapper.updateById(updateObj);
} }
// TODO @puhui999: 这个要不合并到更新操作里? 不单独有个操作咧; 更新状态不用那么多必须的参数更新的时候需要校验时间段
@Override @Override
public void updateSeckillConfigStatus(Long id, Integer status) {
// 校验秒杀时段是否存在
validateSeckillConfigExists(id);
// 更新状态
seckillConfigMapper.updateById(new SeckillConfigDO().setId(id).setStatus(status));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteSeckillConfig(Long id) { public void deleteSeckillConfig(Long id) {
// 校验存在 // 校验存在
validateSeckillConfigExists(id); validateSeckillConfigExists(id);
@ -81,39 +94,29 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
* @param startTime 开始时间 * @param startTime 开始时间
* @param endTime 结束时间 * @param endTime 结束时间
*/ */
private void validateSeckillConfigConflict(String startTime, String endTime) { private void validateSeckillConfigConflict(String startTime, String endTime, Long seckillConfigId) {
LocalTime startTime1 = LocalTime.parse(startTime); LocalTime startTime1 = LocalTime.parse(startTime);
LocalTime endTime1 = LocalTime.parse(endTime); LocalTime endTime1 = LocalTime.parse(endTime);
// TODO @puhui999 这个可以用 validator 里的 assertTrue 去做哈
// 检查选择的时间是否相等
if (startTime1.equals(endTime1)) {
throw exception(SECKILL_TIME_EQUAL);
}
// 检查开始时间是否在结束时间之前
if (startTime1.isAfter(endTime1)) {
throw exception(SECKILL_START_TIME_BEFORE_END_TIME);
}
// 查询出所有的时段配置 // 查询出所有的时段配置
List<SeckillConfigDO> configDOs = seckillConfigMapper.selectList(); List<SeckillConfigDO> configDOs = seckillConfigMapper.selectList();
// 更新时排除自己
if (seckillConfigId != null) {
configDOs.removeIf(item -> ObjectUtil.equal(item.getId(), seckillConfigId));
}
// 过滤出重叠的时段 ids // 过滤出重叠的时段 ids
// TODO @puhui999感觉 findOne 就可以了 boolean hasConflict = configDOs.stream().anyMatch(config -> {
Set<Long> ids = configDOs.stream().filter((config) -> {
LocalTime startTime2 = LocalTime.parse(config.getStartTime()); LocalTime startTime2 = LocalTime.parse(config.getStartTime());
LocalTime endTime2 = LocalTime.parse(config.getEndTime()); LocalTime endTime2 = LocalTime.parse(config.getEndTime());
// 判断时间是否重叠 // 判断时间是否重叠
// 开始时间在已配置时段的结束时间之前 结束时间在已配置时段的开始时间之后 [] return LocalDateTimeUtils.checkTimeOverlap(startTime1, endTime1, startTime2, endTime2);
// todo @puhui999LocalDateUtils 可以写个工具类是否是有重叠的时间感觉别的场景可能也会有需要 });
return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的开始时间之前 结束时间在已配置时段的开始时间之后 (] () if (hasConflict) {
|| startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
// 开始时间在已配置时段的结束时间之前 结束时间在已配值时段的结束时间之后 [) ()
|| startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
}).map(SeckillConfigDO::getId).collect(Collectors.toSet());
if (CollUtil.isNotEmpty(ids)) {
throw exception(SECKILL_TIME_CONFLICTS); throw exception(SECKILL_TIME_CONFLICTS);
} }
} }
@Override @Override
public SeckillConfigDO getSeckillConfig(Long id) { public SeckillConfigDO getSeckillConfig(Long id) {
return seckillConfigMapper.selectById(id); return seckillConfigMapper.selectById(id);
@ -148,23 +151,9 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
return seckillConfigMapper.selectPage(pageVO); return seckillConfigMapper.selectPage(pageVO);
} }
// TODO @puhui999:写个查询状态的; 尽可能通用哈
@Override @Override
public List<SeckillConfigDO> getListAllSimple() { public List<SeckillConfigDO> getListAllSimple() {
return seckillConfigMapper.selectList(SeckillConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); return seckillConfigMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
}
// TODO @puhui999: 这个要不合并到更新操作里? 不单独有个操作咧;
@Override
public void updateSeckillConfigStatus(Long id, Integer status) {
// 校验秒杀时段是否存在
validateSeckillConfigExists(id);
SeckillConfigDO seckillConfigDO = new SeckillConfigDO();
seckillConfigDO.setId(id);
seckillConfigDO.setStatus(status);
// 更新状态
seckillConfigMapper.updateById(seckillConfigDO);
} }
} }

View File

@ -27,6 +27,8 @@ public interface ErrorCodeConstants {
ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1011000016, "交易订单更新支付状态失败,支付单金额不匹配"); ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1011000016, "交易订单更新支付状态失败,支付单金额不匹配");
ErrorCode ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED = new ErrorCode(1011000017, "交易订单发货失败,订单不是【待发货】状态"); ErrorCode ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED = new ErrorCode(1011000017, "交易订单发货失败,订单不是【待发货】状态");
ErrorCode ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED = new ErrorCode(1011000018, "交易订单收货失败,订单不是【待收货】状态"); ErrorCode ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED = new ErrorCode(1011000018, "交易订单收货失败,订单不是【待收货】状态");
ErrorCode ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED = new ErrorCode(1011000019, "创建交易订单项的评价失败,订单不是【已完成】状态");
ErrorCode ORDER_COMMENT_STATUS_NOT_FALSE = new ErrorCode(1011000019, "创建交易订单项的评价失败,订单已评价");
// ========== After Sale 模块 1011000100 ========== // ========== After Sale 模块 1011000100 ==========
ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");

View File

@ -4,8 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
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.trade.controller.app.order.vo.*; import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
@ -30,13 +28,10 @@ import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Map; 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.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
@Tag(name = "用户 App - 交易订单") @Tag(name = "用户 App - 交易订单")
@RestController @RestController
@ -47,12 +42,8 @@ public class AppTradeOrderController {
@Resource @Resource
private TradeOrderService tradeOrderService; private TradeOrderService tradeOrderService;
@Resource @Resource
private ProductPropertyValueApi productPropertyValueApi; private ProductPropertyValueApi productPropertyValueApi;
@Resource
private ProductCommentApi productCommentApi;
@Resource @Resource
private TradeOrderProperties tradeOrderProperties; private TradeOrderProperties tradeOrderProperties;
@ -121,7 +112,7 @@ public class AppTradeOrderController {
// 待发货 // 待发货
orderCount.put("undeliveredCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.UNDELIVERED.getStatus(), null)); orderCount.put("undeliveredCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.UNDELIVERED.getStatus(), null));
// 待收货 // 待收货
orderCount.put("deliveredCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.DELIVERED.getStatus(), null)); orderCount.put("deliveredCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.DELIVERED.getStatus(), null));
// 待评价 // 待评价
orderCount.put("uncommentedCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.COMPLETED.getStatus(), false)); orderCount.put("uncommentedCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.COMPLETED.getStatus(), false));
return success(orderCount); return success(orderCount);
@ -164,22 +155,7 @@ public class AppTradeOrderController {
@PostMapping("/item/create-comment") @PostMapping("/item/create-comment")
@Operation(summary = "创建交易订单项的评价") @Operation(summary = "创建交易订单项的评价")
public CommonResult<Long> createOrderItemComment(@RequestBody AppTradeOrderItemCommentCreateReqVO createReqVO) { public CommonResult<Long> createOrderItemComment(@RequestBody AppTradeOrderItemCommentCreateReqVO createReqVO) {
// TODO @puhui999这个逻辑最好写到 service return success(tradeOrderService.createOrderItemComment(createReqVO));
Long loginUserId = getLoginUserId();
// 先通过订单项 ID 查询订单项是否存在
TradeOrderItemDO orderItemDO = tradeOrderService.getOrderItemByIdAndUserId(createReqVO.getOrderItemId(), loginUserId);
if (orderItemDO == null) {
throw exception(ORDER_ITEM_NOT_FOUND);
}
// 校验订单
TradeOrderDO orderDO = tradeOrderService.getOrderByIdAndUserId(orderItemDO.getOrderId(), loginUserId);
if (orderDO == null) {
throw exception(ORDER_NOT_FOUND);
}
// TODO @puhui999要校验订单已完成但是未评价
ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItemDO);
return success(productCommentApi.createComment(productCommentCreateReqDTO));
} }
} }

View File

@ -19,11 +19,6 @@ public class AppTradeOrderItemCommentCreateReqVO {
@NotNull(message = "交易订单项编号不能为空") @NotNull(message = "交易订单项编号不能为空")
private Long orderItemId; private Long orderItemId;
// TODO @puhui999貌似不用这个字段哈
@Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
@NotNull(message = "评分星级 1-5 分不能为空")
private Integer scores;
@Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
@NotNull(message = "描述星级 1-5 分不能为空") @NotNull(message = "描述星级 1-5 分不能为空")
private Integer descriptionScores; private Integer descriptionScores;

View File

@ -270,7 +270,6 @@ public interface TradeOrderConvert {
@Mapping(target = "skuId", source = "tradeOrderItemDO.skuId") @Mapping(target = "skuId", source = "tradeOrderItemDO.skuId")
@Mapping(target = "orderId", source = "tradeOrderItemDO.orderId") @Mapping(target = "orderId", source = "tradeOrderItemDO.orderId")
@Mapping(target = "orderItemId", source = "tradeOrderItemDO.id") @Mapping(target = "orderItemId", source = "tradeOrderItemDO.id")
@Mapping(target = "scores", source = "createReqVO.scores")
@Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores") @Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores")
@Mapping(target = "benefitScores", source = "createReqVO.benefitScores") @Mapping(target = "benefitScores", source = "createReqVO.benefitScores")
@Mapping(target = "content", source = "createReqVO.content") @Mapping(target = "content", source = "createReqVO.content")

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
@ -177,4 +178,14 @@ public interface TradeOrderService {
* @return 得到订单 * @return 得到订单
*/ */
TradeOrderDO getOrderByIdAndUserId(Long orderId, Long loginUserId); TradeOrderDO getOrderByIdAndUserId(Long orderId, Long loginUserId);
/**
* 创建订单项评论
* 创建交易订单项的评价
*
* @param createReqVO 创建请求
* @return 得到评价 id
*/
Long createOrderItemComment(AppTradeOrderItemCommentCreateReqVO createReqVO);
} }

View File

@ -17,19 +17,21 @@ import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
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.coupon.CouponApi; import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
@ -57,6 +59,7 @@ import java.util.*;
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.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@ -93,7 +96,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
@Resource @Resource
private MemberUserApi memberUserApi; private MemberUserApi memberUserApi;
@Resource @Resource
private AdminUserApi adminUserApi; private ProductCommentApi productCommentApi;
@Resource @Resource
private NotifyMessageSendApi notifyMessageSendApi; private NotifyMessageSendApi notifyMessageSendApi;
@ -556,6 +559,30 @@ public class TradeOrderServiceImpl implements TradeOrderService {
return tradeOrderMapper.selectOrderByIdAndUserId(orderId, loginUserId); return tradeOrderMapper.selectOrderByIdAndUserId(orderId, loginUserId);
} }
@Override
public Long createOrderItemComment(AppTradeOrderItemCommentCreateReqVO createReqVO) {
Long loginUserId = getLoginUserId();
// 先通过订单项 ID 查询订单项是否存在
TradeOrderItemDO orderItemDO = getOrderItemByIdAndUserId(createReqVO.getOrderItemId(), loginUserId);
if (orderItemDO == null) {
throw exception(ORDER_ITEM_NOT_FOUND);
}
// 校验订单
TradeOrderDO orderDO = getOrderByIdAndUserId(orderItemDO.getOrderId(), loginUserId);
if (orderDO == null) {
throw exception(ORDER_NOT_FOUND);
}
if (ObjectUtil.notEqual(orderDO.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) {
throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED);
}
if (ObjectUtil.notEqual(orderDO.getCommentStatus(), Boolean.FALSE)) {
throw exception(ORDER_COMMENT_STATUS_NOT_FALSE);
}
ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItemDO);
return productCommentApi.createComment(productCommentCreateReqDTO);
}
/** /**
* 判断指定订单的所有订单项是不是都售后成功 * 判断指定订单的所有订单项是不是都售后成功
* *

View File

@ -19,10 +19,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
/** /**
* {@link AddressServiceImpl} 的单元测试类 * {@link AddressServiceImpl} 的单元测试类
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@Import(AddressServiceImpl.class) @Import(AddressServiceImpl.class)
public class AddressServiceImplTest extends BaseDbUnitTest { public class AddressServiceImplTest extends BaseDbUnitTest {
@ -82,8 +82,8 @@ public class AddressServiceImplTest extends BaseDbUnitTest {
// 调用 // 调用
addressService.deleteAddress(dbAddress.getUserId(), id); addressService.deleteAddress(dbAddress.getUserId(), id);
// 校验数据不存在了 // 校验数据不存在了
assertNull(addressMapper.selectById(id)); assertNull(addressMapper.selectById(id));
} }
@Test @Test