From 36d03339f1eb3ac030e5569abc133f9942af0ac8 Mon Sep 17 00:00:00 2001 From: peng <peng.com> Date: 星期二, 30 九月 2025 17:08:20 +0800 Subject: [PATCH] 店铺扫码抽奖功能 --- framework/src/main/java/cn/lili/modules/lmk/mapper/ScanPrizeMapper.java | 4 framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeClaimRecord.java | 5 buyer-api/src/main/java/cn/lili/controller/lmk/StorePrizeClaimController.java | 35 +++++++ framework/src/main/java/cn/lili/modules/lmk/domain/vo/StorePrizeVO.java | 55 +++++++++++ framework/src/main/java/cn/lili/modules/lmk/service/PrizeClaimRecordService.java | 2 framework/src/main/java/cn/lili/modules/lmk/service/ScanPrizeService.java | 5 + framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java | 1 framework/src/main/java/cn/lili/modules/lmk/service/impl/ScanPrizeServiceImpl.java | 106 ++++++++++++++++++++ manager-api/src/main/java/cn/lili/controller/order/OrderComplaintManagerController.java | 15 ++ framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeClaimRecordServiceImpl.java | 20 +++ framework/src/main/resources/mapper/lmk/ScanPrizeMapper.xml | 32 ++++++ 11 files changed, 275 insertions(+), 5 deletions(-) diff --git a/buyer-api/src/main/java/cn/lili/controller/lmk/StorePrizeClaimController.java b/buyer-api/src/main/java/cn/lili/controller/lmk/StorePrizeClaimController.java new file mode 100644 index 0000000..546fce1 --- /dev/null +++ b/buyer-api/src/main/java/cn/lili/controller/lmk/StorePrizeClaimController.java @@ -0,0 +1,35 @@ +package cn.lili.controller.lmk; + +import cn.lili.base.Result; +import cn.lili.modules.lmk.service.PrizeClaimRecordService; +import cn.lili.modules.lmk.service.ScanPrizeService; +import cn.lili.modules.lmk.service.StoreCouponClaimRecordService; +import cn.lili.modules.lmk.service.StoreCouponService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +@Validated +@RequiredArgsConstructor +@Api(value = "鍟嗗绔壂鐮侀鍙栨娊濂栨満浼氭帴鍙�", tags = "鍟嗗绔壂鐮侀鍙栨娊濂栨満浼氭帴鍙�") +@RestController +@RequestMapping("/buyer/lmk/store/prize") +public class StorePrizeClaimController { + + private final PrizeClaimRecordService prizeClaimRecordService; + private final ScanPrizeService scanPrizeService; + + @PostMapping("/{id}") + @ApiOperation(value = "棰嗗彇鎶藉鏈轰細", notes = "棰嗗彇鎶藉鏈轰細") + public Result claimPrize(@PathVariable String id){ + return scanPrizeService.claimPrize(id); + } + + @GetMapping("/{id}") + @ApiOperation(value = "鏌ョ湅鎶藉鏈轰細淇℃伅", notes = "鏌ョ湅鎶藉鏈轰細淇℃伅") + public Result getStorePrize(@PathVariable String id){ + return scanPrizeService.getStorePrize(id); + } +} diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeClaimRecord.java b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeClaimRecord.java index 83b2e1e..b274f1a 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeClaimRecord.java +++ b/framework/src/main/java/cn/lili/modules/lmk/domain/entity/PrizeClaimRecord.java @@ -1,6 +1,7 @@ package cn.lili.modules.lmk.domain.entity; import cn.lili.modules.lmk.enums.general.MaterialStatusEnum; +import cn.lili.modules.order.order.entity.enums.ClaimStatusEnum; import cn.lili.mybatis.BaseEntity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; @@ -52,7 +53,9 @@ private String nickName; @TableField("claim_status") - /** 棰嗗彇鐘舵�� */ + /** 棰嗗彇鐘舵�� + * @see ClaimStatusEnum + * */ private String claimStatus; @TableField("material") diff --git a/framework/src/main/java/cn/lili/modules/lmk/domain/vo/StorePrizeVO.java b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/StorePrizeVO.java new file mode 100644 index 0000000..580ebfe --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/lmk/domain/vo/StorePrizeVO.java @@ -0,0 +1,55 @@ +package cn.lili.modules.lmk.domain.vo; + +import cn.lili.base.AbsVo; +import cn.lili.modules.lmk.domain.entity.ActionRecord; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.beans.BeanUtils; +import org.springframework.lang.NonNull; + +import java.util.Date; + +/** + * 鐢ㄦ埛琛屼负璁板綍灞曠ず + * + * @author peng + * @since 2025-09-08 + */ +@Data +@ApiModel(value = "鐢ㄦ埛琛屼负璁板綍鍝嶅簲鏁版嵁", description = "鐢ㄦ埛琛屼负璁板綍鍝嶅簲鏁版嵁") +public class StorePrizeVO { + + @ApiModelProperty("id") + private String id; + + @ApiModelProperty("缂栧彿") + private String no; + + @ApiModelProperty("闂ㄥ簵id") + private String storeId; + + @ApiModelProperty("闂ㄥ簵鍚嶇О") + private String storeName; + + @ApiModelProperty("娲诲姩鍚嶇О") + private String activityName; + + @ApiModelProperty("娲诲姩鎻忚堪") + private String activityDes; + + @ApiModelProperty("寮�濮嬫椂闂�") + private Date beginTime; + + @ApiModelProperty("缁撴潫鏃堕棿") + private Date endTime; + + @ApiModelProperty("娲诲姩灏侀潰") + private String activityCover; + + @ApiModelProperty("鍚敤鐘舵��") + private String enableStatus; + + @ApiModelProperty("寮圭獥鍐呭") + private Boolean popup; +} diff --git a/framework/src/main/java/cn/lili/modules/lmk/mapper/ScanPrizeMapper.java b/framework/src/main/java/cn/lili/modules/lmk/mapper/ScanPrizeMapper.java index e4e4169..c21d00f 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/mapper/ScanPrizeMapper.java +++ b/framework/src/main/java/cn/lili/modules/lmk/mapper/ScanPrizeMapper.java @@ -1,6 +1,8 @@ package cn.lili.modules.lmk.mapper; +import cn.lili.base.Result; import cn.lili.modules.lmk.domain.entity.ScanPrize; +import cn.lili.modules.lmk.domain.vo.StorePrizeVO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import cn.lili.modules.lmk.domain.vo.ScanPrizeVO; @@ -31,4 +33,6 @@ */ IPage getPage(IPage page, @Param("query") ScanPrizeQuery query); + StorePrizeVO getStorePrize(@Param("id") String id); + } diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeClaimRecordService.java b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeClaimRecordService.java index 179988f..e90fd83 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeClaimRecordService.java +++ b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeClaimRecordService.java @@ -5,6 +5,8 @@ import cn.lili.base.Result; import cn.lili.modules.lmk.domain.form.PrizeClaimRecordForm; import cn.lili.modules.lmk.domain.query.PrizeClaimRecordQuery; +import org.springframework.web.bind.annotation.PathVariable; + import java.util.List; /** diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java index a67ac86..b4e27da 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java +++ b/framework/src/main/java/cn/lili/modules/lmk/service/PrizeService.java @@ -18,4 +18,5 @@ Result addPrizeNum(AddPrizeNumForm addPrizeNumForm); + } diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/ScanPrizeService.java b/framework/src/main/java/cn/lili/modules/lmk/service/ScanPrizeService.java index 925e543..926b9bf 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/service/ScanPrizeService.java +++ b/framework/src/main/java/cn/lili/modules/lmk/service/ScanPrizeService.java @@ -66,4 +66,9 @@ Result changeStatus(String id); Result generateStorePrize(String id); + + Result claimPrize(String id); + + Result getStorePrize(String id); + } diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeClaimRecordServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeClaimRecordServiceImpl.java index eb80535..45bf2c7 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeClaimRecordServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/PrizeClaimRecordServiceImpl.java @@ -1,18 +1,36 @@ package cn.lili.modules.lmk.service.impl; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; +import cn.lili.modules.lmk.domain.entity.*; +import cn.lili.modules.lmk.domain.form.AddPrizeNumForm; +import cn.lili.modules.lmk.enums.general.PrizeUserActionEnum; +import cn.lili.modules.lmk.enums.general.StoreCouponStausEnum; +import cn.lili.modules.lmk.enums.general.StoreScanPrizeStausEnum; +import cn.lili.modules.lmk.service.PrizeService; +import cn.lili.modules.lmk.service.ScanPrizeService; +import cn.lili.modules.order.order.entity.enums.ClaimStatusEnum; +import cn.lili.modules.promotion.entity.dos.MemberCoupon; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; -import cn.lili.modules.lmk.domain.entity.PrizeClaimRecord; import cn.lili.modules.lmk.mapper.PrizeClaimRecordMapper; import cn.lili.modules.lmk.service.PrizeClaimRecordService; import cn.lili.base.Result; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import cn.lili.modules.lmk.domain.form.PrizeClaimRecordForm; import cn.lili.modules.lmk.domain.vo.PrizeClaimRecordVO; import cn.lili.modules.lmk.domain.query.PrizeClaimRecordQuery; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; import cn.lili.utils.PageUtil; import org.springframework.beans.BeanUtils; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; import java.util.List; diff --git a/framework/src/main/java/cn/lili/modules/lmk/service/impl/ScanPrizeServiceImpl.java b/framework/src/main/java/cn/lili/modules/lmk/service/impl/ScanPrizeServiceImpl.java index 0193259..cc7d618 100644 --- a/framework/src/main/java/cn/lili/modules/lmk/service/impl/ScanPrizeServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/lmk/service/impl/ScanPrizeServiceImpl.java @@ -1,13 +1,20 @@ package cn.lili.modules.lmk.service.impl; import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; import cn.lili.modules.lmk.domain.entity.PrizeClaimRecord; import cn.lili.modules.lmk.domain.entity.StoreCoupon; import cn.lili.modules.lmk.domain.entity.StoreCouponSingle; +import cn.lili.modules.lmk.domain.form.AddPrizeNumForm; +import cn.lili.modules.lmk.domain.vo.StorePrizeVO; import cn.lili.modules.lmk.enums.general.*; import cn.lili.modules.lmk.service.PrizeClaimRecordService; +import cn.lili.modules.lmk.service.PrizeService; import cn.lili.modules.order.order.entity.enums.ClaimStatusEnum; +import cn.lili.utils.COSUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import cn.lili.modules.lmk.domain.entity.ScanPrize; import cn.lili.modules.lmk.mapper.ScanPrizeMapper; @@ -49,7 +56,9 @@ private final RedissonClient redissonClient; private static final String STORE_PRIZE_GENERATE = "store_prize_generate:"; private final PrizeClaimRecordService prizeClaimRecordService; - + private static final String STORE_PRIZE_CLAIM = "store_prize_claim:"; + private final PrizeService prizeService; + private final COSUtil cosUtil; /** * 娣诲姞 * @param form @@ -164,7 +173,7 @@ } @Override - @Transactional + @Transactional(rollbackFor = Exception.class) public Result generateStorePrize(String id) { RLock redissonLock = redissonClient.getLock(STORE_PRIZE_GENERATE + id); @@ -224,4 +233,97 @@ prizeClaimRecord.setMaterial(MaterialStatusEnum.NOT_GENERATE.name()); return prizeClaimRecord; } + @Override + public Result claimPrize(String id) { + AuthUser currentUser = UserContext.getCurrentUser(); + if (currentUser == null) { + throw new ServiceException("褰撳墠鐢ㄦ埛娌℃湁鐧诲綍鏃犳硶棰嗗彇"); + } + String userId = currentUser.getId(); + String nickName = currentUser.getNickName(); + + //閿佷綇绀煎搧鐮乮d + RLock redissonLock = redissonClient.getLock(STORE_PRIZE_CLAIM + id); + try { + redissonLock.lock(); + LambdaQueryWrapper<PrizeClaimRecord> forUpdate = Wrappers.<PrizeClaimRecord>lambdaQuery() + .eq(PrizeClaimRecord::getId, id).last("FOR UPDATE"); + PrizeClaimRecord prizeClaimRecord = prizeClaimRecordService.getOne(forUpdate); + if (prizeClaimRecord == null) { + throw new ServiceException("褰撳墠棰嗗彇鎶藉鏈轰細浜岀淮鐮佷笉瀛樺湪"); + } + if (!ClaimStatusEnum.NOT_CLAIM.name().equals(prizeClaimRecord.getClaimStatus())) { + throw new ServiceException("褰撳墠棰嗗彇鎶藉鏈轰細鐘舵�佸紓甯�"); + } + //鏇存柊琚鍙栫殑璁板綍 + prizeClaimRecord.setClaimStatus(ClaimStatusEnum.CLAIM.name()); + prizeClaimRecord.setUserId(userId); + prizeClaimRecord.setNickName(nickName); + LambdaQueryWrapper<ScanPrize> storeCoupQuery = Wrappers.<ScanPrize>lambdaQuery() + .eq(ScanPrize::getId, prizeClaimRecord.getStorePrizeId()).last("FOR UPDATE"); + ScanPrize scanPrize = this.getOne(storeCoupQuery); + AddPrizeNumForm addPrizeNumForm = new AddPrizeNumForm(); + addPrizeNumForm.setUserId(userId); + addPrizeNumForm.setPrizeActivityId(prizeClaimRecord.getPrizeActivityId()); + addPrizeNumForm.setAddType(PrizeUserActionEnum.USER_SCAN_STORE.name()); + prizeService.addPrizeNum(addPrizeNumForm); + if (scanPrize == null) { + throw new ServiceException("褰撳墠搴楅摵鎶藉鍗蜂笉瀛樺湪"); + } + if (!StoreScanPrizeStausEnum.ENABLE.name().equals(scanPrize.getStatus())) { + throw new ServiceException("褰撳墠搴楅摵鎶藉鍗风姸鎬佸紓甯�"); + } + //棰嗗彇瀵瑰簲鐨勪紭鎯犲嵎鍐欏叆璁板綍 + prizeClaimRecordService.updateById(prizeClaimRecord); + LambdaUpdateWrapper<ScanPrize> updateStoreCoupon = Wrappers.<ScanPrize>lambdaUpdate() + .eq(ScanPrize::getId, scanPrize.getId()) + .set(ScanPrize::getClaimNum, scanPrize.getClaimNum() + 1) + .ge(ScanPrize::getGenerateNum, scanPrize.getClaimNum() + 1); + boolean update = this.update(updateStoreCoupon); + if (!update) { + throw new ServiceException("棰嗗彇澶辫触"); + } + return Result.ok().data(0); + + } finally { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + if (redissonLock.isHeldByCurrentThread()) { + redissonLock.unlock(); + } + } + + @Override + public void afterCompletion(int status) { + // 纭繚鍗充娇鍦ㄤ簨鍔″洖婊氱殑鎯呭喌涓嬩篃鑳介噴鏀鹃攣 + if (redissonLock.isHeldByCurrentThread()) { + redissonLock.unlock(); + } + } + + }); + + } + } + + @Override + public Result getStorePrize(String id) { + StorePrizeVO storePrize = baseMapper.getStorePrize(id); + if (storePrize == null) { + throw new ServiceException("褰撳墠娲诲姩涓嶅瓨鍦�"); + } + Boolean popup = storePrize.getPopup(); + if (!Boolean.TRUE.equals(popup)) { + throw new ServiceException("褰撳墠娲诲姩娌℃湁寮�鍚�"); + } + if (!PrizeActivityStatusEnum.ON.name().equals(storePrize.getEnableStatus())) { + throw new ServiceException("褰撳墠娲诲姩娌℃湁寮�鍚�"); + } + String activityCover = storePrize.getActivityCover(); + if (StringUtils.isNotBlank(activityCover)&&!activityCover.contains("http")) { + storePrize.setActivityCover(cosUtil.getPreviewUrl(activityCover)); + } + return Result.ok().data(storePrize); + } } diff --git a/framework/src/main/resources/mapper/lmk/ScanPrizeMapper.xml b/framework/src/main/resources/mapper/lmk/ScanPrizeMapper.xml index 1a489b4..cbe91b8 100644 --- a/framework/src/main/resources/mapper/lmk/ScanPrizeMapper.xml +++ b/framework/src/main/resources/mapper/lmk/ScanPrizeMapper.xml @@ -57,5 +57,37 @@ WHERE LSP.delete_flag = 0 </select> + <resultMap id="getStorePrizeMap" type="cn.lili.modules.lmk.domain.vo.StorePrizeVO"> + <id column="id" property="id"/> + <result property="no" column="no"/> + <result property="storeId" column="store_id"/> + <result property="storeName" column="store_name"/> + <result property="activityName" column="activity_name"/> + <result property="activityDes" column="activity_des"/> + <result property="beginTime" column="begin_time"/> + <result property="activityCover" column="activity_cover"/> + <result property="enableStatus" column="enable_status"/> + <result property="popup" column="popup"/> + </resultMap> + <select id="getStorePrize" resultMap="getStorePrizeMap"> + SELECT + pcr.id, + pcr.no, + pcr.store_id, + pcr.store_name, + lpa.activity_name, + lpa.activity_des, + lpa.begin_time, + lpa.end_time, + lpa.activity_cover, + lpa.enable_status, + lpa.popup + FROM + lmk_prize_claim_record pcr + JOIN lmk_prize_activity lpa ON pcr.prize_activity_id = lpa.id + AND pcr.delete_flag = 0 AND lpa.delete_flag = 0 + WHERE + pcr.id = #{id} + </select> </mapper> diff --git a/manager-api/src/main/java/cn/lili/controller/order/OrderComplaintManagerController.java b/manager-api/src/main/java/cn/lili/controller/order/OrderComplaintManagerController.java index 1610157..a134ef3 100644 --- a/manager-api/src/main/java/cn/lili/controller/order/OrderComplaintManagerController.java +++ b/manager-api/src/main/java/cn/lili/controller/order/OrderComplaintManagerController.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -64,12 +65,24 @@ orderComplainById.setGoodsImage(cosUtil.getPreviewUrl(goodsImage)); } String[] orderComplaintImages = orderComplainById.getOrderComplaintImages(); - List<String> orderComplaintImagesList = Arrays.asList(orderComplaintImages); + List<String> orderComplaintImagesList = new ArrayList<>(); for (String orderComplaintImage : orderComplaintImages) { if (StringUtils.isNotBlank(orderComplaintImage)&&!orderComplaintImage.contains("http")) { orderComplaintImagesList.add(cosUtil.getPreviewUrl(orderComplaintImage)); } } + String images = orderComplainById.getImages(); + String[] split = images.split(","); + ArrayList<String> imgs = new ArrayList<>(); + for (String s : split) { + if (StringUtils.isNotBlank(s)) { + if (StringUtils.isNotBlank(s)&&!s.contains("http")) { + imgs.add(cosUtil.getPreviewUrl(s)); + } + } + } + String join = String.join(",", imgs); + orderComplainById.setImages(join); orderComplainById.setOrderComplaintImages(orderComplaintImagesList.toArray(new String[0])); return ResultUtil.data(orderComplainById); } -- Gitblit v1.8.0