diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java index 102f858fc..1d0ea189f 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java @@ -34,8 +34,9 @@ public interface ErrorCodeConstants { // ========== 商品 SPU 1-008-005-000 ========== ErrorCode SPU_NOT_EXISTS = new ErrorCode(1_008_005_000, "商品 SPU 不存在"); ErrorCode SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR = new ErrorCode(1_008_005_001, "商品分类不正确,原因:必须使用第二级的商品分类及以下"); - ErrorCode SPU_NOT_ENABLE = new ErrorCode(1_008_005_002, "商品 SPU【{}】不处于上架状态"); - ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1_008_005_003, "商品 SPU 不处于回收站状态"); + ErrorCode SPU_SAVE_FAIL_COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1_008_005_002, "商品 SPU 保存失败,原因:优惠卷不存在"); + ErrorCode SPU_NOT_ENABLE = new ErrorCode(1_008_005_003, "商品 SPU【{}】不处于上架状态"); + ErrorCode SPU_NOT_RECYCLE = new ErrorCode(1_008_005_004, "商品 SPU 不处于回收站状态"); // ========== 商品 SKU 1-008-006-000 ========== ErrorCode SKU_NOT_EXISTS = new ErrorCode(1_008_006_000, "商品 SKU 不存在"); diff --git a/yudao-module-mall/yudao-module-product-biz/pom.xml b/yudao-module-mall/yudao-module-product-biz/pom.xml index f6190ceda..385b6690e 100644 --- a/yudao-module-mall/yudao-module-product-biz/pom.xml +++ b/yudao-module-mall/yudao-module-product-biz/pom.xml @@ -28,6 +28,11 @@ yudao-module-member-api ${revision} + + cn.iocoder.boot + yudao-module-promotion-api + ${revision} + diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java index 7f88dd8c6..f41138179 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java @@ -11,6 +11,8 @@ 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.sku.ProductSkuService; import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; +import cn.iocoder.yudao.module.promotion.api.coupon.CouponTemplateApi; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -43,6 +45,9 @@ public class ProductSpuController { @Resource private ProductSkuService productSkuService; + @Resource + private CouponTemplateApi couponTemplateApi; + @PostMapping("/create") @Operation(summary = "创建商品 SPU") @PreAuthorize("@ss.hasPermission('product:spu:create')") @@ -87,7 +92,10 @@ public class ProductSpuController { } // 查询商品 SKU List skus = productSkuService.getSkuListBySpuId(spu.getId()); - return success(ProductSpuConvert.INSTANCE.convertForSpuDetailRespVO(spu, skus)); + // 查询优惠卷 + List couponTemplateList = couponTemplateApi.getCouponTemplateListByIds( + spu.getGiveCouponTemplateIds()); + return success(ProductSpuConvert.INSTANCE.convertForSpuDetailRespVO(spu, skus, couponTemplateList)); } @GetMapping("/list-all-simple") diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java index 23c2467f8..7f2c22c95 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java @@ -96,19 +96,31 @@ public class ProductSpuBaseVO { @NotNull(message = "商品赠送积分不能为空") private Integer giveIntegral; - @Schema(description = "赠送的优惠劵编号的数组", example = "[1, 10]") // TODO 这块前端还未实现 - private List giveCouponTemplateIds; + @Schema(description = "赠送的优惠劵数组包含优惠券编号和名称") + private List giveCouponTemplates; @Schema(description = "分销类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") @NotNull(message = "商品分销类型不能为空") private Boolean subCommissionType; - @Schema(description = "活动展示顺序", example = "[1, 3, 2, 4, 5]") // TODO 这块前端还未实现 + @Schema(description = "活动展示顺序", example = "[1, 3, 2, 4, 5]") private List activityOrders; // ========== 统计相关字段 ========= - @Schema(description = "虚拟销量", example = "芋道") + @Schema(description = "虚拟销量", example = "66") private Integer virtualSalesCount; + @Schema(description = "管理后台 - 商品 SPU 赠送的优惠卷") + @Data + public static class GiveCouponTemplate { + + @Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送") + private String name; + + } + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java index e8e6a8bc1..0b83abe42 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; 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.DictTypeConstants; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Named; @@ -100,10 +101,14 @@ public interface ProductSpuConvert { List convertListForGetSpuDetail(List skus); - default ProductSpuDetailRespVO convertForSpuDetailRespVO(ProductSpuDO spu, List skus) { - ProductSpuDetailRespVO detailRespVO = convert03(spu); - detailRespVO.setSkus(ProductSkuConvert.INSTANCE.convertList(skus)); - return detailRespVO; + List convertList04(List couponTemplateList); + + default ProductSpuDetailRespVO convertForSpuDetailRespVO(ProductSpuDO spu, List skus, + List couponTemplateList) { + ProductSpuDetailRespVO respVO = convert03(spu); + respVO.setSkus(ProductSkuConvert.INSTANCE.convertList(skus)); + respVO.setGiveCouponTemplates(convertList04(couponTemplateList)); + return respVO; } default List convertForSpuDetailRespListVO(List spus, List skus) { diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java index 9e073fee7..9ce55a096 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java @@ -194,7 +194,7 @@ public class ProductSpuDO extends BaseDO { * 对应 PromotionTypeEnum 枚举 */ @TableField(typeHandler = JacksonTypeHandler.class) - private List activityOrders; + private List activityOrders; // TODO @芋艿: 活动顺序字段长度需要增加 // ========== 统计相关字段 ========= diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 521a5fefe..5f2fcbb04 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -16,8 +16,10 @@ 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.sku.ProductSkuService; +import cn.iocoder.yudao.module.promotion.api.coupon.CouponTemplateApi; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; import com.google.common.collect.Maps; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -26,10 +28,10 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMinValue; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO.CATEGORY_LEVEL; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; @@ -52,9 +54,10 @@ public class ProductSpuServiceImpl implements ProductSpuService { private ProductBrandService brandService; @Resource private ProductCategoryService categoryService; + @Resource - @Lazy // 循环依赖,避免报错 - private ProductPropertyValueService productPropertyValueService; + @Lazy + private CouponTemplateApi couponTemplateApi; @Override @Transactional(rollbackFor = Exception.class) @@ -62,6 +65,9 @@ public class ProductSpuServiceImpl implements ProductSpuService { // 校验分类、品牌 validateCategory(createReqVO.getCategoryId()); brandService.validateProductBrand(createReqVO.getBrandId()); + // 校验优惠券 + Set giveCouponTemplateIds = convertSet(createReqVO.getGiveCouponTemplates(), ProductSpuCreateReqVO.GiveCouponTemplate::getId); + validateCouponTemplate(giveCouponTemplateIds); // 校验 SKU List skuSaveReqList = createReqVO.getSkus(); productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType()); @@ -69,6 +75,8 @@ public class ProductSpuServiceImpl implements ProductSpuService { ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO); // 初始化 SPU 中 SKU 相关属性 initSpuFromSkus(spu, skuSaveReqList); + // 设置优惠券 + spu.setGiveCouponTemplateIds(CollUtil.newArrayList(giveCouponTemplateIds)); // 插入 SPU productSpuMapper.insert(spu); // 插入 SKU @@ -85,6 +93,9 @@ public class ProductSpuServiceImpl implements ProductSpuService { // 校验分类、品牌 validateCategory(updateReqVO.getCategoryId()); brandService.validateProductBrand(updateReqVO.getBrandId()); + // 校验优惠券 + Set giveCouponTemplateIds = convertSet(updateReqVO.getGiveCouponTemplates(), ProductSpuUpdateReqVO.GiveCouponTemplate::getId); + validateCouponTemplate(giveCouponTemplateIds); // 校验SKU List skuSaveReqList = updateReqVO.getSkus(); productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType()); @@ -92,6 +103,8 @@ public class ProductSpuServiceImpl implements ProductSpuService { // 更新 SPU ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO); initSpuFromSkus(updateObj, skuSaveReqList); + // 设置优惠券 + updateObj.setGiveCouponTemplateIds(CollUtil.newArrayList(giveCouponTemplateIds)); productSpuMapper.updateById(updateObj); // 批量更新 SKU productSkuService.updateSkuList(updateObj.getId(), updateReqVO.getSkus()); @@ -125,6 +138,10 @@ public class ProductSpuServiceImpl implements ProductSpuService { // 默认商品浏览量 spu.setBrowseCount(0); } + // 如果活动顺序为空则默认初始化 + if (CollUtil.isEmpty(spu.getActivityOrders())) { + spu.setActivityOrders(Arrays.stream(PromotionTypeEnum.ARRAYS).boxed().collect(Collectors.toList())); + } } /** @@ -140,6 +157,13 @@ public class ProductSpuServiceImpl implements ProductSpuService { } } + private void validateCouponTemplate(Collection ids) { + List couponTemplateList = couponTemplateApi.getCouponTemplateListByIds(ids); + if (couponTemplateList.size() != ids.size()) { + throw exception(SPU_SAVE_FAIL_COUPON_TEMPLATE_NOT_EXISTS); + } + } + @Override public List validateSpuList(Collection ids) { if (CollUtil.isEmpty(ids)) { diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponTemplateApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponTemplateApi.java new file mode 100644 index 000000000..d31e80ec1 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponTemplateApi.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.api.coupon; + +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO; + +import java.util.Collection; +import java.util.List; + +/** + * 优惠劵模版 API 接口 + * + * @author HUIHUI + */ +public interface CouponTemplateApi { + + /** + * 获得优惠券模版的精简信息列表 + * + * @param ids 优惠券模版编号 + * @return 优惠券模版的精简信息列表 + */ + List getCouponTemplateListByIds(Collection ids); + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponTemplateRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponTemplateRespDTO.java new file mode 100644 index 000000000..a54ccf2b0 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponTemplateRespDTO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.api.coupon.dto; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import lombok.Data; + +/** + * 优惠券模版 Response DTO + * + * @author HUIHUI + */ +@Data +public class CouponTemplateRespDTO { + /** + * 模板编号,自增唯一 + */ + + private Long id; + /** + * 优惠劵名 + */ + private String name; + + /** + * 状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/banner/BannerPositionEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/banner/BannerPositionEnum.java new file mode 100644 index 000000000..5d99fc1b4 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/banner/BannerPositionEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.promotion.enums.banner; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * Banner Position 枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum BannerPositionEnum implements IntArrayValuable { + + HOME_POSITION(1, "首页"), + SECKILL_POSITION(2, "秒杀活动页"), + COMBINATION_POSITION(3, "砍价活动页"), + DISCOUNT_POSITION(4, "限时折扣页"), + REWARD_POSITION(5, "满减送页"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BargainRecordStatusEnum::getStatus).toArray(); + /** + * 值 + */ + private final Integer position; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponTemplateApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponTemplateApiImpl.java new file mode 100644 index 000000000..8c4f443f5 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponTemplateApiImpl.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.promotion.api.coupon; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * 优惠劵模版 API 接口实现类 + * + * @author HUIHUI + */ +@Service +public class CouponTemplateApiImpl implements CouponTemplateApi { + + @Resource + private CouponTemplateService couponTemplateService; + + @Override + public List getCouponTemplateListByIds(Collection ids) { + if (CollUtil.isEmpty(ids)) { // 防御一下 + return Collections.emptyList(); + } + return CouponTemplateConvert.INSTANCE.convertList(couponTemplateService.getCouponTemplateListByIds(ids)); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerBaseVO.java index ff90cb7a0..f840254cc 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerBaseVO.java @@ -27,6 +27,10 @@ public class BannerBaseVO { @NotNull(message = "图片地址不能为空") private String picUrl; + @Schema(description = "position", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "position 不能为空") + private Integer position; + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "排序不能为空") private Integer sort; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerPageReqVO.java index b97008ccd..4aafb9f46 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerPageReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/banner/vo/BannerPageReqVO.java @@ -25,7 +25,6 @@ public class BannerPageReqVO extends PageParam { @Schema(description = "标题") private String title; - @Schema(description = "状态") @InEnum(CommonStatusEnum.class) private Integer status; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java index 534e82ff3..5acb43cfe 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java @@ -56,13 +56,11 @@ public class AppArticleController { return success(ArticleConvert.INSTANCE.convert01(articleService.getArticle(id))); } - // TODO @puhui999:add-browse-count 噢;前端 uniapp 也要接下;就是打开文章的时候,调用下这个接口; - @PutMapping("/add-browseCount") + @PutMapping("/add-browse-count") @Operation(summary = "增加文章浏览量") @Parameter(name = "id", description = "文章编号", example = "1024") public CommonResult addBrowseCount(@RequestParam("id") Long id) { - // TODO @puhui999:addArticleBrowseCount - articleService.addBrowseCount(id); + articleService.addArticleBrowseCount(id); return success(true); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/AppBannerController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/AppBannerController.java index 3a4ff8a78..4947e113c 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/AppBannerController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/AppBannerController.java @@ -2,18 +2,23 @@ package cn.iocoder.yudao.module.promotion.controller.app.banner; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.promotion.controller.app.banner.vo.AppBannerRespVO; +import cn.iocoder.yudao.module.promotion.convert.banner.BannerConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; +import cn.iocoder.yudao.module.promotion.service.banner.BannerService; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; +import javax.annotation.Resource; +import java.time.Duration; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; @RestController @RequestMapping("/promotion/banner") @@ -21,22 +26,39 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Validated public class AppBannerController { + @Resource + private BannerService bannerService; + /** + * {@link AppBannerRespVO} 缓存,通过它异步刷新 {@link #getBannerList0(Integer)} 所要的首页数据 + */ + private final LoadingCache> bannerListCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), + new CacheLoader>() { + + @Override + public List load(Integer position) { + return getBannerList0(position); + } + + }); + @GetMapping("/list") @Operation(summary = "获得 banner 列表") - // todo @芋艿:swagger 注解,待补全 - // TODO @芋艿:可以增加缓存,提升性能 - // TODO @芋艿:position = 1 时,首页;position = 10 时,拼团活动页 + @Parameter(name = "position", description = "Banner position", example = "1") public CommonResult> getBannerList(@RequestParam("position") Integer position) { - List bannerList = new ArrayList<>(); - AppBannerRespVO banner1 = new AppBannerRespVO(); - banner1.setUrl("https://www.example.com/link1"); - banner1.setPicUrl("https://api.java.crmeb.net/crmebimage/public/content/2022/08/04/0f78716213f64bfa83f191d51a832cbf73f6axavoy.jpg"); - bannerList.add(banner1); - AppBannerRespVO banner2 = new AppBannerRespVO(); - banner2.setUrl("https://www.example.com/link2"); - banner2.setPicUrl("https://api.java.crmeb.net/crmebimage/public/content/2023/01/11/be09e755268b43ee90b0db3a3e1b7132r7a6t2wvsm.jpg"); - bannerList.add(banner2); - return success(bannerList); + return success(bannerListCache.getUnchecked(position)); + } + + private List getBannerList0(Integer position) { + List bannerList = bannerService.getBannerListByPosition(position); + return BannerConvert.INSTANCE.convertList01(bannerList); + } + + @PutMapping("/add-browse-count") + @Operation(summary = "增加 Banner 点击量") + @Parameter(name = "id", description = "Banner 编号", example = "1024") + public CommonResult addBrowseCount(@RequestParam("id") Long id) { + bannerService.addBannerBrowseCount(id); + return success(true); } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/vo/AppBannerRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/vo/AppBannerRespVO.java index 7656a431d..cc36d87d4 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/vo/AppBannerRespVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/banner/vo/AppBannerRespVO.java @@ -9,6 +9,13 @@ import javax.validation.constraints.NotNull; @Data public class AppBannerRespVO { + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "标题不能为空") + private String title; + @Schema(description = "跳转链接", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "跳转链接不能为空") private String url; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/banner/BannerConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/banner/BannerConvert.java index 3e2afeb49..d2d75362e 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/banner/BannerConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/banner/BannerConvert.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.app.banner.vo.AppBannerRespVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -25,4 +26,6 @@ public interface BannerConvert { BannerDO convert(BannerUpdateReqVO updateReqVO); + List convertList01(List bannerList); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java index e09d0f013..8e1c57f5c 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.convert.coupon; import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponTemplateRespDTO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateRespVO; @@ -58,4 +59,6 @@ public interface CouponTemplateConvert { } } + List convertList(List list); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java index 585462b95..0a2065e77 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/banner/BannerDO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.banner; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.promotion.enums.banner.BannerPositionEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -40,14 +42,25 @@ public class BannerDO extends BaseDO { private Integer sort; /** - * 状态 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + * 状态 {@link CommonStatusEnum} */ private Integer status; + + /** + * 定位 {@link BannerPositionEnum} + */ + private Integer position; + /** * 备注 */ private String memo; - // TODO 芋艿 点击次数。&& 其他数据相关 + /** + * 点击次数 + */ + private Integer browseCount; + + // TODO 芋艿 其他数据相关 } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/banner/BannerMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/banner/BannerMapper.java index d98375365..74bd3c7da 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/banner/BannerMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/banner/BannerMapper.java @@ -5,8 +5,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.promotion.controller.admin.banner.vo.BannerPageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.banner.BannerDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * Banner Mapper * @@ -23,4 +26,14 @@ public interface BannerMapper extends BaseMapperX { .orderByDesc(BannerDO::getSort)); } + default void updateBrowseCount(Long id) { + update(null, new LambdaUpdateWrapper() + .eq(BannerDO::getId, id) + .setSql("browse_count = browse_count + 1")); + } + + default List selectBannerListByPosition(Integer position) { + return selectList(new LambdaQueryWrapperX().eq(BannerDO::getPosition, position)); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java index fd5466648..72d604e77 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java @@ -86,7 +86,6 @@ public interface BargainActivityMapper extends BaseMapperX { .last("LIMIT " + count)); } - // TODO @puhui999:是不是返回 BargainActivityDO 更干净哈?分组后返回 DO 的话需要联表查询 /** * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 * @@ -102,7 +101,6 @@ public interface BargainActivityMapper extends BaseMapperX { .groupBy("spu_id")); } - // TODO @puhui999:是不是只要 endTime 小于就可以啦; /** * 获取指定活动编号的活动列表且 * 开始时间和结束时间小于给定时间 dateTime 的活动列表 @@ -115,7 +113,7 @@ public interface BargainActivityMapper extends BaseMapperX { return selectList(new LambdaQueryWrapperX() .in(BargainActivityDO::getId, ids) .lt(BargainActivityDO::getStartTime, dateTime) - .lt(BargainActivityDO::getEndTime, dateTime) + .gt(BargainActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 .orderByDesc(BargainActivityDO::getCreateTime)); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java index 530478e69..55e975c45 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java @@ -71,7 +71,7 @@ public interface CombinationActivityMapper extends BaseMapperX() .in(CombinationActivityDO::getId, ids) .lt(CombinationActivityDO::getStartTime, dateTime) - .lt(CombinationActivityDO::getEndTime, dateTime) + .gt(CombinationActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 .orderByDesc(CombinationActivityDO::getCreateTime)); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java index f5715298d..ba5706a77 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java @@ -8,10 +8,11 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; import java.util.function.Consumer; @@ -39,7 +40,11 @@ public interface CouponTemplateMapper extends BaseMapperX { .orderByDesc(CouponTemplateDO::getId)); } - void updateTakeCount(@Param("id") Long id, @Param("incrCount") Integer incrCount); + default void updateTakeCount(Long id, Integer incrCount) { + update(null, new LambdaUpdateWrapper() + .eq(CouponTemplateDO::getId, id) + .setSql("take_count = take_count + " + incrCount)); + } default List selectListByTakeType(Integer takeType) { return selectList(CouponTemplateDO::getTakeType, takeType); @@ -70,4 +75,8 @@ public interface CouponTemplateMapper extends BaseMapperX { return canTakeConsumer; } + default List selectListByIds(Collection ids) { + return selectList(new LambdaQueryWrapperX().in(CouponTemplateDO::getId, ids)); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java index 82fbafecd..ca40e7602 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java @@ -103,7 +103,7 @@ public interface SeckillActivityMapper extends BaseMapperX { return selectList(new LambdaQueryWrapperX() .in(SeckillActivityDO::getId, ids) .lt(SeckillActivityDO::getStartTime, dateTime) - .lt(SeckillActivityDO::getEndTime, dateTime) + .gt(SeckillActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 .orderByDesc(SeckillActivityDO::getCreateTime)); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java index 81b463373..4188cc681 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java @@ -93,6 +93,6 @@ public interface ArticleService { * * @param id 文章编号 */ - void addBrowseCount(Long id); + void addArticleBrowseCount(Long id); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java index 47e614057..7a4e69a6e 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java @@ -111,7 +111,7 @@ public class ArticleServiceImpl implements ArticleService { } @Override - public void addBrowseCount(Long id) { + public void addArticleBrowseCount(Long id) { // 校验文章是否存在 validateArticleExists(id); // 增加浏览次数 diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerService.java index d541211be..404f7f5b2 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerService.java @@ -46,12 +46,6 @@ public interface BannerService { */ BannerDO getBanner(Long id); - /** - * 获得所有 Banner列表 - * @return Banner列表 - */ - List getBannerList(); - /** * 获得 Banner 分页 * @@ -60,4 +54,19 @@ public interface BannerService { */ PageResult getBannerPage(BannerPageReqVO pageReqVO); + /** + * 增加 Banner 点击量 + * + * @param id Banner编号 + */ + void addBannerBrowseCount(Long id); + + /** + * 获得 Banner 列表 + * + * @param position 定位 + * @return Banner 列表 + */ + List getBannerListByPosition(Integer position); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerServiceImpl.java index 013ae8992..46c22f0e2 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/banner/BannerServiceImpl.java @@ -65,14 +65,22 @@ public class BannerServiceImpl implements BannerService { return bannerMapper.selectById(id); } - @Override - public List getBannerList() { - return bannerMapper.selectList(); - } - @Override public PageResult getBannerPage(BannerPageReqVO pageReqVO) { return bannerMapper.selectPage(pageReqVO); } + @Override + public void addBannerBrowseCount(Long id) { + // 校验 Banner 是否存在 + validateBannerExists(id); + // 增加点击次数 + bannerMapper.updateBrowseCount(id); + } + + @Override + public List getBannerListByPosition(Integer position) { + return bannerMapper.selectBannerListByPosition(position); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java index db4197f52..f5b78ab13 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java @@ -369,8 +369,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { keyValue.setValue(keyValue.getValue() + 1); } } catch (Exception ignored) { // 处理异常继续循环 - // TODO @puhui999:拼团过期 or 虚拟成团 可以改成 expireCombinationRecord;因为找方法更容易一些; - log.error("[拼团过期 or 虚拟成团][record({}) 处理异常,请进行处理!record 数据是:{}]", + log.error("[expireCombinationRecord][record({}) 处理异常,请进行处理!record 数据是:{}]", record.getId(), JsonUtils.toJsonString(record)); } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java index db0fa6cb4..a47644a4c 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; import javax.validation.Valid; +import java.util.Collection; import java.util.List; /** @@ -91,4 +92,12 @@ public interface CouponTemplateService { List getCouponTemplateList(List canTakeTypes, Integer productScope, Long productScopeValue, Integer count); + /** + * 获得优惠券模版列表 + * + * @param ids 优惠券模版编号 + * @return 优惠券模版列表 + */ + List getCouponTemplateListByIds(Collection ids); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java index 2228df71a..8a7fbb8ba 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java @@ -16,6 +16,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.Collection; import java.util.List; import java.util.Objects; @@ -126,4 +127,9 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { return couponTemplateMapper.selectList(canTakeTypes, productScope, productScopeValue, count); } + @Override + public List getCouponTemplateListByIds(Collection ids) { + return couponTemplateMapper.selectListByIds(ids); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/coupon/CouponTemplateMapper.xml b/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/coupon/CouponTemplateMapper.xml deleted file mode 100644 index 987143534..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/coupon/CouponTemplateMapper.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - UPDATE promotion_coupon_template - SET take_count = take_count + #{incrCount} - WHERE id = #{id} - - - diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInController.java deleted file mode 100644 index ec5e0a4a8..000000000 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInController.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.member.controller.app.signin; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.member.service.signin.MemberSignInRecordService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -// TODO @xiaqing:sign-in -@Tag(name = "签到APP - 签到") -@RestController -@RequestMapping("/member/signin") -public class AppMemberSignInController { - - @Resource - private MemberSignInRecordService signInRecordService; - - // TODO @xiaqing:泛型: - // TODO @xiaqing:合并到 AppMemberSignInRecordController 的 getSignInRecordSummary 里哈。 - @Operation(summary = "个人签到信息") - @GetMapping("/get-summary") - public CommonResult getUserSummary() { - return success(signInRecordService.getSignInRecordSummary(getLoginUserId())); - } - -} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInRecordController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInRecordController.java index fa07d85ec..2f7afa042 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInRecordController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/AppMemberSignInRecordController.java @@ -31,22 +31,11 @@ public class AppMemberSignInRecordController { @Resource private MemberSignInRecordService signInRecordService; - // TODO 芋艿:临时 mock => UserSignController.getUserInfo @GetMapping("/get-summary") @Operation(summary = "获得个人签到统计") @PreAuthenticated public CommonResult getSignInRecordSummary() { - AppMemberSignInRecordSummaryRespVO respVO = new AppMemberSignInRecordSummaryRespVO(); - if (false) { - respVO.setTotalDay(100); - respVO.setContinuousDay(5); - respVO.setTodaySignIn(true); - } else { - respVO.setTotalDay(100); - respVO.setContinuousDay(10); - respVO.setTodaySignIn(false); - } - return success(respVO); + return success(signInRecordService.getSignInRecordSummary(getLoginUserId())); } @PostMapping("/create") diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInRecordRespVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInRecordRespVO.java deleted file mode 100644 index c31e365ec..000000000 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInRecordRespVO.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.member.controller.app.signin.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "用户签到积分 Response VO") -@Data -public class AppMemberSignInRecordRespVO { - - @Schema(description = "第几天签到", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer day; - - @Schema(description = "签到的积分", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private Integer point; - - @Schema(description = "签到的经验", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private Integer experience; - - @Schema(description = "签到时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - -} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInSummaryRespVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInSummaryRespVO.java deleted file mode 100644 index 55eaddbdd..000000000 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/signin/vo/AppMemberSignInSummaryRespVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.yudao.module.member.controller.app.signin.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "用户签到统计信息 Response VO") -@Data -public class AppMemberSignInSummaryRespVO { - - @Schema(description = "持续签到天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5") - private Integer continuousDay; - - @Schema(description = "总签到天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private Integer totalDay; - - @Schema(description = "当天是否签到", requiredMode = Schema.RequiredMode.REQUIRED,example = "true") - private Boolean todaySignIn ; - -} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java index edac5edae..6ad9794d8 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/signin/MemberSignInRecordConvert.java @@ -1,14 +1,19 @@ package cn.iocoder.yudao.module.member.convert.signin; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordRespVO; import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordRespVO; +import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; @@ -32,10 +37,37 @@ public interface MemberSignInRecordConvert { memberUserRespDTO -> record.setNickname(memberUserRespDTO.getNickname()))); return voPageResult; } + PageResult convertPage(PageResult pageResult); PageResult convertPage02(PageResult pageResult); AppMemberSignInRecordRespVO coverRecordToAppRecordVo(MemberSignInRecordDO memberSignInRecordDO); + default MemberSignInRecordDO convert(Long userId, MemberSignInRecordDO firstRecord, List signInConfigs) { + // 1. 计算今天是第几天签到 + long day = ChronoUnit.DAYS.between(firstRecord.getCreateTime(), LocalDateTime.now()); + // 2. 初始化签到信息 + MemberSignInRecordDO signInRecord = new MemberSignInRecordDO().setUserId(userId) + .setDay(Integer.parseInt(Long.toString(day))) // 设置签到天数 + .setPoint(0) // 设置签到积分默认为 0 + .setExperience(0); // 设置签到经验默认为 0 + + + // 3. 获取签到对应的积分数 + MemberSignInConfigDO lastConfig = signInConfigs.get(signInConfigs.size() - 1); // 最大签到天数 + if (day > lastConfig.getDay()) { // 超出范围按第一天的经验计算 + signInRecord.setPoint(signInConfigs.get(0).getPoint()); + signInRecord.setExperience(signInConfigs.get(0).getExperience()); + return signInRecord; + } + MemberSignInConfigDO signInConfig = CollUtil.findOne(signInConfigs, config -> ObjUtil.equal(config.getDay(), day)); + if (signInConfig == null) { + return signInRecord; + } + signInRecord.setPoint(signInConfig.getPoint()); + signInRecord.setExperience(signInConfig.getExperience()); + return signInRecord; + } + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java index 84e61a761..fcd4ae408 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/signin/MemberSignInRecordMapper.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -35,9 +36,45 @@ public interface MemberSignInRecordMapper extends BaseMapperX selectListByUserId(Long userId){ - return selectList(new LambdaQueryWrapperX () + /** + * 获取用户最近的签到记录信息,根据签到时间倒序 + * + * @param userId 用户编号 + * @return 签到记录列表 + */ + default MemberSignInRecordDO selectLastRecordByUserIdDesc(Long userId) { + return selectOne(new QueryWrapper() + .eq("user_id", userId) + .orderByDesc("create_time") + .last("limit 1")); + } + + /** + * 获取用户最早的签到记录信息,根据签到时间倒序 + * + * @param userId 用户编号 + * @return 签到记录列表 + */ + default MemberSignInRecordDO selectLastRecordByUserIdAsc(Long userId) { + return selectOne(new QueryWrapper() + .eq("user_id", userId) + .orderByAsc("create_time") + .last("limit 1")); + } + + default Long selectCountByUserId(Long userId) { + return selectCount(new LambdaQueryWrapperX() + .eq(MemberSignInRecordDO::getUserId, userId)); + } + + /** + * 获取用户的签到记录列表信息,根据签到时间倒序 + * + * @param userId 用户编号 + * @return 签到记录信息 + */ + default List selectListByUserId(Long userId) { + return selectList(new LambdaQueryWrapperX() .eq(MemberSignInRecordDO::getUserId, userId) .orderByDesc(MemberSignInRecordDO::getCreateTime)); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java index 4f1c365e0..b22ceed1a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.member.service.signin; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; -import cn.iocoder.yudao.module.member.controller.app.signin.vo.AppMemberSignInSummaryRespVO; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO; import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; /** @@ -24,7 +24,7 @@ public interface MemberSignInRecordService { /** * 【会员】获得签到记录分页 * - * @param userId 用户编号 + * @param userId 用户编号 * @param pageParam 分页查询 * @return 签到记录分页 */ @@ -44,7 +44,7 @@ public interface MemberSignInRecordService { * @param userId 用户编号 * @return 个人签到统计信息 */ - AppMemberSignInSummaryRespVO getSignInRecordSummary(Long userId); + AppMemberSignInRecordSummaryRespVO getSignInRecordSummary(Long userId); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java index dca079dc2..586e60ac4 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInRecordServiceImpl.java @@ -1,19 +1,20 @@ package cn.iocoder.yudao.module.member.service.signin; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.member.api.user.MemberUserApi; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.controller.admin.signin.vo.record.MemberSignInRecordPageReqVO; -import cn.iocoder.yudao.module.member.controller.app.signin.vo.AppMemberSignInSummaryRespVO; +import cn.iocoder.yudao.module.member.controller.app.signin.vo.record.AppMemberSignInRecordSummaryRespVO; +import cn.iocoder.yudao.module.member.convert.signin.MemberSignInRecordConvert; import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInConfigDO; import cn.iocoder.yudao.module.member.dal.dataobject.signin.MemberSignInRecordDO; -import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInConfigMapper; import cn.iocoder.yudao.module.member.dal.mysql.signin.MemberSignInRecordMapper; -import cn.iocoder.yudao.module.member.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum; import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; import cn.iocoder.yudao.module.member.service.level.MemberLevelService; @@ -21,17 +22,17 @@ import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.time.LocalDate; -import java.time.temporal.ChronoUnit; +import java.util.Comparator; import java.util.List; import java.util.Set; 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.module.member.enums.ErrorCodeConstants.SIGN_IN_RECORD_TODAY_EXISTS; /** * 签到记录 Service 实现类 @@ -45,7 +46,7 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService @Resource private MemberSignInRecordMapper signInRecordMapper; @Resource - private MemberSignInConfigMapper signInConfigMapper; + private MemberSignInConfigService signInConfigService; @Resource private MemberPointRecordService pointRecordService; @Resource @@ -55,50 +56,64 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService private MemberUserApi memberUserApi; @Override - public AppMemberSignInSummaryRespVO getSignInRecordSummary(Long userId) { - AppMemberSignInSummaryRespVO vo = new AppMemberSignInSummaryRespVO(); + public AppMemberSignInRecordSummaryRespVO getSignInRecordSummary(Long userId) { + // 1. 初始化默认返回信息 + AppMemberSignInRecordSummaryRespVO vo = new AppMemberSignInRecordSummaryRespVO(); vo.setTotalDay(0); vo.setContinuousDay(0); vo.setTodaySignIn(false); - //获取用户签到的记录,按照天数倒序获取 - List signInRecordDOList = signInRecordMapper.selectListByUserId(userId); - // TODO @xiaqing:if 空的时候,直接 return;这样括号少,逻辑更简洁; - if (!CollectionUtils.isEmpty(signInRecordDOList)) { - //设置总签到天数 - vo.setTotalDay(signInRecordDOList.size()); // TODO @xiaqing:是不是不用读取 signInRecordDOList 所有的,而是 count下,然后另外再读取一条最后一条; - //判断当天是否有签到复用校验方法 - // TODO @xiaqing:不要用异常实现逻辑;还是判断哈; - try { - validSignDay(signInRecordDOList.get(0)); - vo.setTodaySignIn(false); - } catch (Exception e) { - vo.setTodaySignIn(true); - } - //如果当天签到了则说明连续签到天数有意义,否则直接用默认值0 - if (vo.getTodaySignIn()) { - //下方计算连续签到从2天开始,此处直接设置一天连续签到 - vo.setContinuousDay(1); - //判断连续签到天数 - // TODO @xiaqing:这里逻辑,想想怎么在简化下,可读性可以在提升下哈; - for (int i = 1; i < signInRecordDOList.size(); i++) { - //前一天减1等于当前天数则说明连续,继续循环 - LocalDate cur = signInRecordDOList.get(i).getCreateTime().toLocalDate(); - LocalDate pre = signInRecordDOList.get(i - 1).getCreateTime().toLocalDate(); - if (1 == daysBetween(cur, pre)) { - vo.setContinuousDay(i + 1); - } else { - break; - } - } - } - + // 2. 获取用户签到的记录数 + Long signCount = signInRecordMapper.selectCountByUserId(userId); + if (ObjUtil.equal(signCount, 0L)) { + return vo; } + vo.setTotalDay(signCount.intValue()); // 设置总签到天数 + + // 3. 校验当天是否有签到 + MemberSignInRecordDO signInRecord = signInRecordMapper.selectLastRecordByUserIdDesc(userId); + if (signInRecord == null) { + return vo; + } + vo.setTodaySignIn(DateUtils.isToday(signInRecord.getCreateTime())); + + // 4. 校验今天是否签到,没有签到则直接返回 + if (!vo.getTodaySignIn()) { + return vo; + } + // 4.1. 判断连续签到天数 + List signInRecords = signInRecordMapper.selectListByUserId(userId); + vo.setContinuousDay(calculateConsecutiveDays(signInRecords)); return vo; } - private long daysBetween(LocalDate date1, LocalDate date2) { - return ChronoUnit.DAYS.between(date1, date2); + /** + * 计算连续签到天数 + * + * @param signInRecords 签到记录列表 + * @return int 连续签到天数 + */ + public int calculateConsecutiveDays(List signInRecords) { + int consecutiveDays = 1; // 初始连续天数为1 + LocalDate previousDate = null; + + for (MemberSignInRecordDO record : signInRecords) { + LocalDate currentDate = record.getCreateTime().toLocalDate(); + + if (previousDate != null) { + // 检查相邻两个日期是否连续 + if (currentDate.minusDays(1).isEqual(previousDate)) { + consecutiveDays++; + } else { + // 如果日期不连续,停止遍历 + break; + } + } + + previousDate = currentDate; + } + + return consecutiveDays; } @Override @@ -108,7 +123,7 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService if (StringUtils.isNotBlank(pageReqVO.getNickname())) { List users = memberUserApi.getUserListByNickname(pageReqVO.getNickname()); // 如果查询用户结果为空直接返回无需继续查询 - if (CollectionUtils.isEmpty(users)) { + if (CollUtil.isEmpty(users)) { return PageResult.empty(); } userIds = convertSet(users, MemberUserRespDTO::getId); @@ -125,73 +140,40 @@ public class MemberSignInRecordServiceImpl implements MemberSignInRecordService @Override @Transactional(rollbackFor = Exception.class) public MemberSignInRecordDO createSignRecord(Long userId) { - // 获取当前用户签到的最大天数 - // TODO @xiaqing:db 操作,dou封装到 mapper 中; - // TODO @xiaqing:maxSignDay,是不是变量叫 lastRecord 会更容易理解哈; - MemberSignInRecordDO maxSignDay = signInRecordMapper.selectOne(new LambdaQueryWrapperX() - .eq(MemberSignInRecordDO::getUserId, userId) - .orderByDesc(MemberSignInRecordDO::getDay) - .last("limit 1")); - // 判断是否重复签到 - validSignDay(maxSignDay); + // 1. 获取当前用户最近的签到 + MemberSignInRecordDO lastRecord = signInRecordMapper.selectLastRecordByUserIdDesc(userId); + // 1.1. 判断是否重复签到 + validateSigned(lastRecord); - // 1. 查询出当前签到的天数 - MemberSignInRecordDO sign = new MemberSignInRecordDO().setUserId(userId); // TODO @xiaqing:应该使用 record 变量,会更合适 - sign.setDay(1); // 设置签到初始化天数 - sign.setPoint(0); // 设置签到积分默认为 0 - sign.setExperience(0); // 设置签到经验默认为 0 - // 如果不为空则修改当前签到对应的天数 - // TODO @xiaqing:应该是要判断连续哈,就是昨天; - if (maxSignDay != null) { - sign.setDay(maxSignDay.getDay() + 1); - } - // 2. 获取签到对应的积分数 - // 获取所有的签到规则,按照天数排序,只获取启用的 TODO @xiaqing:不要使用 signInConfigMapper 直接查询,而是要通过 SigninConfigService; - List configDOList = signInConfigMapper.selectList(new LambdaQueryWrapperX() - .eq(MemberSignInConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .orderByAsc(MemberSignInConfigDO::getDay)); - // 如果签到的天数大于最大启用的规则天数,直接给最大签到的积分数 - // TODO @xiaqing:超过最大配置的天数,应该直接重置到第一天哈; - MemberSignInConfigDO lastConfig = configDOList.get(configDOList.size() - 1); - if (sign.getDay() > lastConfig.getDay()) { - sign.setPoint(lastConfig.getPoint()); - sign.setExperience(lastConfig.getExperience()); - } else { - configDOList.forEach(el -> { - // 循环匹配对应天数,设置对应积分数 - // TODO @xiaqing:使用 equals;另外,这种不应该去遍历比较,从可读性来说,应该 CollUtil.findOne() - if (el.getDay() == sign.getDay()) { - sign.setPoint(el.getPoint()); - sign.setExperience(el.getExperience()); - } - - }); - } + // 2. 获取当前用户最早的一次前端记录,用于计算今天是第几天签到 + MemberSignInRecordDO firstRecord = signInRecordMapper.selectLastRecordByUserIdAsc(userId); + // 2.1. 获取所有的签到规则 + List signInConfigs = signInConfigService.getSignInConfigList(CommonStatusEnum.ENABLE.getStatus()); + signInConfigs.sort(Comparator.comparing(MemberSignInConfigDO::getDay)); + // 2.2. 组合数据 + MemberSignInRecordDO record = MemberSignInRecordConvert.INSTANCE.convert(userId, firstRecord, signInConfigs); // 3. 插入签到记录 - signInRecordMapper.insert(sign); + signInRecordMapper.insert(record); // 4. 增加积分 - if (!ObjectUtils.equalsAny(sign.getPoint(), null, 0)) { - pointRecordService.createPointRecord(userId, sign.getPoint(), MemberPointBizTypeEnum.SIGN, String.valueOf(sign.getId())); + if (!ObjectUtils.equalsAny(record.getPoint(), null, 0)) { + pointRecordService.createPointRecord(userId, record.getPoint(), MemberPointBizTypeEnum.SIGN, String.valueOf(record.getId())); } // 5. 增加经验 - if (!ObjectUtils.equalsAny(sign.getPoint(), null, 0)) { - memberLevelService.addExperience(userId, sign.getExperience(), MemberExperienceBizTypeEnum.SIGN_IN, String.valueOf(sign.getId())); + if (!ObjectUtils.equalsAny(record.getExperience(), null, 0)) { + memberLevelService.addExperience(userId, record.getExperience(), MemberExperienceBizTypeEnum.SIGN_IN, String.valueOf(record.getId())); } - return sign; + return record; } - // TODO @xiaqing:校验使用 validate 动词哈;可以改成 validateSigned - private void validSignDay(MemberSignInRecordDO signInRecordDO) { - // TODO @xiaqing:代码格式:if () {} 要有括号哈 - if (signInRecordDO == null) + private void validateSigned(MemberSignInRecordDO signInRecordDO) { + if (signInRecordDO == null) { return; - // TODO @xiaqing:可以直接使用 DateUtils.isToday() - LocalDate today = LocalDate.now(); - if (today.equals(signInRecordDO.getCreateTime().toLocalDate())) { - throw exception(ErrorCodeConstants.SIGN_IN_RECORD_TODAY_EXISTS); + } + if (DateUtils.isToday(signInRecordDO.getCreateTime())) { + throw exception(SIGN_IN_RECORD_TODAY_EXISTS); } }