抽奖相关接口初步调通

This commit is contained in:
tianfeng 2025-10-20 10:10:33 +08:00
parent 0ee3f41c1b
commit 8976ce27df
68 changed files with 476 additions and 313 deletions

View File

@ -5,6 +5,7 @@ import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.inner.model.cmd.activity.LotteryActivityQryCmd; import com.red.circle.other.inner.model.cmd.activity.LotteryActivityQryCmd;
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO; import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
/** /**
@ -20,7 +21,7 @@ public interface LotteryActivityQueryClientApi {
/** /**
* 分页查询活动列表. * 分页查询活动列表.
*/ */
@GetMapping("/listActivities") @PostMapping("/listActivities")
ResultResponse<PageResult<LotteryActivityDTO>> listActivities(@RequestBody LotteryActivityQryCmd cmd); ResultResponse<PageResult<LotteryActivityDTO>> listActivities(@RequestBody LotteryActivityQryCmd cmd);
} }

View File

@ -26,7 +26,7 @@ public interface LotteryRecordClientApi {
@RequestParam("activityId") Long activityId, @RequestParam("activityId") Long activityId,
@RequestParam(value = "prizeId", required = false) Long prizeId, @RequestParam(value = "prizeId", required = false) Long prizeId,
@RequestParam(value = "prizeName", required = false) String prizeName, @RequestParam(value = "prizeName", required = false) String prizeName,
@RequestParam(value = "prizeType", required = false) Integer prizeType, @RequestParam(value = "prizeType", required = false) String prizeType,
@RequestParam("isWin") Integer isWin @RequestParam("isWin") Integer isWin
); );

View File

@ -22,7 +22,7 @@ public interface LotteryRecordManageClientApi {
/** /**
* 分页查询中奖记录. * 分页查询中奖记录.
*/ */
@GetMapping("/listRecords") @PostMapping("/listRecords")
ResultResponse<PageResult<LotteryRecordDTO>> listRecords(@RequestBody LotteryRecordQryCmd cmd); ResultResponse<PageResult<LotteryRecordDTO>> listRecords(@RequestBody LotteryRecordQryCmd cmd);
/** /**

View File

@ -1,13 +1,12 @@
package com.red.circle.other.inner.model.cmd.activity; package com.red.circle.other.inner.model.cmd.activity;
import com.red.circle.framework.dto.Command;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.sql.Timestamp;
/** /**
* 创建/更新活动命令. * 创建/更新活动命令.
* *
@ -16,7 +15,7 @@ import lombok.EqualsAndHashCode;
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class LotteryActivitySaveCmd extends Command { public class LotteryActivitySaveCmd {
/** /**
* 活动ID更新时需要. * 活动ID更新时需要.
@ -44,13 +43,13 @@ public class LotteryActivitySaveCmd extends Command {
* 开始时间. * 开始时间.
*/ */
@NotNull(message = "开始时间不能为空") @NotNull(message = "开始时间不能为空")
private LocalDateTime startTime; private Timestamp startTime;
/** /**
* 结束时间. * 结束时间.
*/ */
@NotNull(message = "结束时间不能为空") @NotNull(message = "结束时间不能为空")
private LocalDateTime endTime; private Timestamp endTime;
/** /**
* 抽奖次数限制. * 抽奖次数限制.

View File

@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class LotteryPrizeSaveCmd extends Command { public class LotteryPrizeSaveCmd {
/** /**
* 奖品ID更新时需要. * 奖品ID更新时需要.
@ -43,8 +43,8 @@ public class LotteryPrizeSaveCmd extends Command {
/** /**
* 奖品类型. * 奖品类型.
*/ */
@NotNull(message = "奖品类型不能为空") @NotBlank(message = "奖品类型不能为空")
private Integer prizeType; private String prizeType;
/** /**
* 奖品价值. * 奖品价值.

View File

@ -53,11 +53,11 @@ public class LotteryRecordQryCmd extends Command {
/** /**
* 页码. * 页码.
*/ */
private Integer pageNo; private Integer pageNo = 1;
/** /**
* 页大小. * 页大小.
*/ */
private Integer pageSize; private Integer pageSize = 20;
} }

View File

@ -2,7 +2,8 @@ package com.red.circle.other.inner.model.cmd.activity;
import com.red.circle.framework.dto.Command; import com.red.circle.framework.dto.Command;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -41,7 +42,7 @@ public class LotteryTicketGrantCmd extends Command {
/** /**
* 过期时间. * 过期时间.
*/ */
private LocalDateTime expireTime; private Timestamp expireTime;
/** /**
* 备注. * 备注.

View File

@ -3,7 +3,7 @@ package com.red.circle.other.inner.model.dto.activity;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
/** /**
@ -41,12 +41,12 @@ public class LotteryActivityDTO implements Serializable {
/** /**
* 开始时间. * 开始时间.
*/ */
private LocalDateTime startTime; private Timestamp startTime;
/** /**
* 结束时间. * 结束时间.
*/ */
private LocalDateTime endTime; private Timestamp endTime;
/** /**
* 状态. * 状态.
@ -91,11 +91,11 @@ public class LotteryActivityDTO implements Serializable {
/** /**
* 创建时间. * 创建时间.
*/ */
private LocalDateTime createdAt; private Timestamp createdAt;
/** /**
* 更新时间. * 更新时间.
*/ */
private LocalDateTime updatedAt; private Timestamp updatedAt;
} }

View File

@ -41,7 +41,7 @@ public class LotteryPrizeDTO implements Serializable {
/** /**
* 奖品类型. * 奖品类型.
*/ */
private Integer prizeType; private String prizeType;
/** /**
* 奖品价值. * 奖品价值.

View File

@ -48,7 +48,7 @@ public class LotteryActivityBackRestController extends BaseController {
* 更新活动. * 更新活动.
*/ */
@PutMapping("/update") @PutMapping("/update")
public void updateActivity(@RequestBody @Validated LotteryActivitySaveCmd cmd) { public void updateActivity(@RequestBody LotteryActivitySaveCmd cmd) {
lotteryActivityBackService.updateActivity(cmd); lotteryActivityBackService.updateActivity(cmd);
} }

View File

@ -1,6 +1,7 @@
package com.red.circle.console.app.service.app.activity; package com.red.circle.console.app.service.app.activity;
import com.red.circle.framework.dto.PageResult; import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.inner.endpoint.activity.LotteryActivityManageClient; import com.red.circle.other.inner.endpoint.activity.LotteryActivityManageClient;
import com.red.circle.other.inner.endpoint.activity.LotteryActivityQueryClient; import com.red.circle.other.inner.endpoint.activity.LotteryActivityQueryClient;
import com.red.circle.other.inner.endpoint.activity.LotteryPrizeManageClient; import com.red.circle.other.inner.endpoint.activity.LotteryPrizeManageClient;
@ -46,7 +47,8 @@ public class LotteryActivityBackServiceImpl implements LotteryActivityBackServic
@Override @Override
public PageResult<LotteryActivityDTO> listActivities(LotteryActivityQryCmd cmd) { public PageResult<LotteryActivityDTO> listActivities(LotteryActivityQryCmd cmd) {
return lotteryActivityQueryClient.listActivities(cmd).getBody(); ResultResponse<PageResult<LotteryActivityDTO>> response = lotteryActivityQueryClient.listActivities(cmd);
return response.getBody();
} }
@Override @Override

View File

@ -10,7 +10,8 @@ import com.red.circle.other.app.dto.clientobject.activity.LotteryRecordCO;
import com.red.circle.other.app.dto.clientobject.activity.LotteryTicketCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryTicketCO;
import com.red.circle.other.app.dto.cmd.activity.LotteryDrawCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryDrawCmd;
import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd; import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
import com.red.circle.other.app.service.activity.LotteryActivityService; import com.red.circle.other.app.service.activity.LotteryActivityRestService;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -40,7 +41,7 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor @RequiredArgsConstructor
public class LotteryActivityRestController extends BaseController { public class LotteryActivityRestController extends BaseController {
private final LotteryActivityService lotteryActivityService; private final LotteryActivityRestService lotteryActivityRestService;
/** /**
* 获取有效活动列表. * 获取有效活动列表.
@ -52,7 +53,7 @@ public class LotteryActivityRestController extends BaseController {
*/ */
@GetMapping("/list") @GetMapping("/list")
public List<LotteryActivityCO> listValidActivities(AppExtCommand cmd) { public List<LotteryActivityCO> listValidActivities(AppExtCommand cmd) {
return lotteryActivityService.listValidActivities(cmd); return lotteryActivityRestService.listValidActivities(cmd);
} }
/** /**
@ -65,7 +66,7 @@ public class LotteryActivityRestController extends BaseController {
*/ */
@GetMapping("/detail/{activityCode}") @GetMapping("/detail/{activityCode}")
public LotteryActivityDetailCO getActivityDetail(@PathVariable String activityCode, AppExtCommand cmd) { public LotteryActivityDetailCO getActivityDetail(@PathVariable String activityCode, AppExtCommand cmd) {
return lotteryActivityService.getActivityDetail(activityCode, cmd); return lotteryActivityRestService.getActivityDetail(activityCode, cmd);
} }
/** /**
@ -78,7 +79,7 @@ public class LotteryActivityRestController extends BaseController {
*/ */
@PostMapping("/draw") @PostMapping("/draw")
public LotteryDrawResultCO draw(@RequestBody @Validated LotteryDrawCmd cmd) { public LotteryDrawResultCO draw(@RequestBody @Validated LotteryDrawCmd cmd) {
return lotteryActivityService.draw(cmd); return lotteryActivityRestService.draw(cmd);
} }
/** /**
@ -91,33 +92,33 @@ public class LotteryActivityRestController extends BaseController {
*/ */
@GetMapping("/my-records") @GetMapping("/my-records")
public PageResult<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd) { public PageResult<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd) {
return lotteryActivityService.listMyRecords(cmd); return lotteryActivityRestService.listMyRecords(cmd);
} }
/** /**
* 查询我的抽奖券. * 查询我的抽奖券列表详细信息.
* *
* @eo.name 查询我的抽奖券. * @eo.name 查询我的抽奖券列表.
* @eo.url /my-tickets * @eo.url /my-tickets
* @eo.method get * @eo.method get
* @eo.request-type formdata * @eo.request-type formdata
*/ */
@GetMapping("/my-tickets") @GetMapping("/my-tickets")
public List<LotteryTicketCO> listMyTickets(AppExtCommand cmd) { public List<LotteryTicketCO> listMyTickets(AppExtCommand cmd) {
return lotteryActivityService.listMyTickets(cmd); return lotteryActivityRestService.listMyTickets(cmd);
} }
/** /**
* 获取抽奖券. * 获取我的剩余抽奖券数.
* *
* @eo.name 获取抽奖券. * @eo.name 获取我的剩余抽奖券数.
* @eo.url /ticket-count * @eo.url /my-ticket-count
* @eo.method get * @eo.method get
* @eo.request-type formdata * @eo.request-type formdata
*/ */
@GetMapping("/ticket-count") @GetMapping("/my-ticket-count")
public Integer getMyTicketCount(AppExtCommand cmd) { public Integer getMyTicketCount(AppExtCommand cmd) {
return lotteryActivityService.getMyTicketCount(cmd); return lotteryActivityRestService.getMyTicketCount(cmd);
} }
} }

View File

@ -13,6 +13,7 @@ import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityS
import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService; import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService;
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService; import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService;
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService; import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService;
import com.red.circle.other.inner.asserts.lottery.LotteryErrorCode;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@ -39,22 +40,22 @@ public class LotteryActivityDetailQryExe {
Long userId = cmd.requiredReqUserId(); Long userId = cmd.requiredReqUserId();
// 查询活动 // 查询活动
LotteryActivity activity = lotteryActivityService.lambdaQuery() LotteryActivity activity = lotteryActivityService.query()
.eq(LotteryActivity::getActivityCode, activityCode) .eq(LotteryActivity::getActivityCode, activityCode)
.one(); .getOne();
ResponseAssert.isTrue(activity != null, "活动不存在"); ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null);
// 查询奖品列表 // 查询奖品列表
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery() List<LotteryPrize> prizes = lotteryPrizeService.query()
.eq(LotteryPrize::getActivityId, activity.getId()) .eq(LotteryPrize::getActivityId, activity.getId())
.eq(LotteryPrize::getIsDisplay, 1) .eq(LotteryPrize::getIsDisplay, 1)
.orderByAsc(LotteryPrize::getSortOrder) .orderByAsc(LotteryPrize::getSortOrder)
.list(); .list();
// 查询用户抽奖券数量 // 查询用户抽奖券数量
Integer ticketCount = 0; int ticketCount = 0;
if (activity.getNeedTicket() == 1) { if (activity.getNeedTicket() == 1) {
ticketCount = lotteryTicketService.lambdaQuery() ticketCount = lotteryTicketService.query()
.eq(LotteryTicket::getUserId, userId) .eq(LotteryTicket::getUserId, userId)
.eq(LotteryTicket::getStatus, 1) .eq(LotteryTicket::getStatus, 1)
.gt(LotteryTicket::getRemainingCount, 0) .gt(LotteryTicket::getRemainingCount, 0)
@ -67,11 +68,11 @@ public class LotteryActivityDetailQryExe {
// 查询用户今日抽奖次数 // 查询用户今日抽奖次数
Integer usedCount = 0; Integer usedCount = 0;
if (activity.getDrawCountLimit() != null && activity.getDrawCountLimit() > 0) { if (activity.getDrawCountLimit() != null && activity.getDrawCountLimit() > 0) {
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery() LotteryUserCount userCount = lotteryUserCountService.query()
.eq(LotteryUserCount::getUserId, userId) .eq(LotteryUserCount::getUserId, userId)
.eq(LotteryUserCount::getActivityId, activity.getId()) .eq(LotteryUserCount::getActivityId, activity.getId())
.eq(LotteryUserCount::getDrawDate, LocalDate.now()) .eq(LotteryUserCount::getDrawDate, LocalDate.now())
.one(); .getOne();
if (userCount != null) { if (userCount != null) {
usedCount = userCount.getDrawCount(); usedCount = userCount.getDrawCount();
} }

View File

@ -6,11 +6,15 @@ import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount; import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService; import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService; import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService;
import java.sql.Timestamp;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.red.circle.tool.core.date.TimestampUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -29,10 +33,10 @@ public class LotteryActivityListQryExe {
public List<LotteryActivityCO> execute(AppExtCommand cmd) { public List<LotteryActivityCO> execute(AppExtCommand cmd) {
Long userId = cmd.requiredReqUserId(); Long userId = cmd.requiredReqUserId();
LocalDateTime now = LocalDateTime.now(); Timestamp now = TimestampUtils.now();
// 查询进行中的活动 // 查询进行中的活动
List<LotteryActivity> activities = lotteryActivityService.lambdaQuery() List<LotteryActivity> activities = lotteryActivityService.query()
.eq(LotteryActivity::getStatus, 1) .eq(LotteryActivity::getStatus, 1)
.le(LotteryActivity::getStartTime, now) .le(LotteryActivity::getStartTime, now)
.ge(LotteryActivity::getEndTime, now) .ge(LotteryActivity::getEndTime, now)
@ -48,7 +52,7 @@ public class LotteryActivityListQryExe {
.map(LotteryActivity::getId) .map(LotteryActivity::getId)
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<Long, Integer> userDrawCountMap = lotteryUserCountService.lambdaQuery() Map<Long, Integer> userDrawCountMap = lotteryUserCountService.query()
.eq(LotteryUserCount::getUserId, userId) .eq(LotteryUserCount::getUserId, userId)
.in(LotteryUserCount::getActivityId, activityIds) .in(LotteryUserCount::getActivityId, activityIds)
.eq(LotteryUserCount::getDrawDate, LocalDate.now()) .eq(LotteryUserCount::getDrawDate, LocalDate.now())

View File

@ -16,12 +16,16 @@ import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordSer
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketRecordService; import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketRecordService;
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService; import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService;
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService; import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService;
import com.red.circle.other.inner.asserts.lottery.LotteryErrorCode;
import com.red.circle.tool.core.date.TimestampUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -45,95 +49,99 @@ public class LotteryDrawExe {
private final LotteryTicketRecordService lotteryTicketRecordService; private final LotteryTicketRecordService lotteryTicketRecordService;
private final LotteryUserCountService lotteryUserCountService; private final LotteryUserCountService lotteryUserCountService;
private final Random random = new Random();
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public LotteryDrawResultCO execute(LotteryDrawCmd cmd) { public LotteryDrawResultCO execute(LotteryDrawCmd cmd) {
Long userId = cmd.requiredReqUserId(); Long userId = cmd.requiredReqUserId();
String activityCode = cmd.getActivityCode(); Long activityId = cmd.getActivityId();
Timestamp now = TimestampUtils.now();
// 1. 校验活动 // 1. 校验活动
LotteryActivity activity = lotteryActivityService.lambdaQuery() LotteryActivity activity = validateActivity(activityId, now);
.eq(LotteryActivity::getActivityCode, activityCode)
.one();
ResponseAssert.isTrue(activity != null, "活动不存在");
ResponseAssert.isTrue(activity.getStatus() == 1, "活动未开始或已结束");
LocalDateTime now = LocalDateTime.now(); // 2. 校验抽奖次数限制
ResponseAssert.isTrue(now.isAfter(activity.getStartTime()) && now.isBefore(activity.getEndTime()), validateDrawCount(userId, activityId, activity);
"不在活动时间内");
// 2. 校验抽奖次数 // 3. 校验并扣除抽奖券写死消耗1次
if (activity.getDrawCountLimit() != null && activity.getDrawCountLimit() > 0) { Integer needTicket = 1;
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery() deductTicket(userId, needTicket);
.eq(LotteryUserCount::getUserId, userId)
.eq(LotteryUserCount::getActivityId, activity.getId())
.eq(LotteryUserCount::getDrawDate, LocalDate.now())
.one();
int drawCount = userCount != null ? userCount.getDrawCount() : 0;
ResponseAssert.isTrue(drawCount < activity.getDrawCountLimit(), "今日抽奖次数已用完");
}
// 3. 校验并扣除抽奖券
if (activity.getNeedTicket() == 1) {
deductTicket(userId, activity.getTicketCost());
}
// 4. 执行抽奖算法 // 4. 执行抽奖算法
LotteryPrize prize = drawPrize(activity.getId()); LotteryPrize prize = drawPrize(activityId);
// 5. 保存抽奖记录
String recordNo = generateRecordNo();
LotteryRecord record = new LotteryRecord();
record.setRecordNo(recordNo);
record.setUserId(userId);
record.setActivityId(activity.getId());
record.setDrawTime(now);
// 5. 扣减奖品库存使用悲观锁防止超卖
if (prize != null) { if (prize != null) {
record.setPrizeId(prize.getId()); boolean deductSuccess = deductPrizeStock(prize.getId());
record.setPrizeName(prize.getPrizeName()); if (!deductSuccess) {
record.setPrizeType(prize.getPrizeType()); // 库存扣减失败视为未中奖
record.setIsWin(1); log.warn("Prize stock deduction failed, prizeId: {}", prize.getId());
record.setPrizeStatus(0); // 待发放 prize = null;
}
// 扣减库存
lotteryPrizeService.lambdaUpdate()
.eq(LotteryPrize::getId, prize.getId())
.gt(LotteryPrize::getRemainingStock, 0)
.setSql("remaining_stock = remaining_stock - 1")
.update();
} else {
record.setIsWin(0);
} }
lotteryRecordService.save(record); // 6. 保存抽奖记录
LotteryRecord record = saveDrawRecord(userId, activityId, prize, now);
// 6. 更新用户抽奖次数 // 7. 更新用户抽奖次数
updateUserDrawCount(userId, activity.getId()); updateUserDrawCount(userId, activityId);
// 7. 组装返回结果 // 8. 组装返回结果
return convertToResultCO(record, prize); return convertToResultCO(record, prize);
} }
/** /**
* 扣除抽奖券. * 校验活动状态和时间.
*/
private LotteryActivity validateActivity(Long activityId, Timestamp now) {
LotteryActivity activity = lotteryActivityService.getById(activityId);
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null);
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_CLOSED, activity.getStatus() == 1);
ResponseAssert.isTrue(LotteryErrorCode.NOT_IN_ACTIVITY_TIME,
now.after(activity.getStartTime()) && now.before(activity.getEndTime()));
return activity;
}
/**
* 校验抽奖次数限制.
*/
private void validateDrawCount(Long userId, Long activityId, LotteryActivity activity) {
if (activity.getDrawCountLimit() == null || activity.getDrawCountLimit() <= 0) {
return; // 无限制
}
LotteryUserCount userCount = lotteryUserCountService.query()
.eq(LotteryUserCount::getUserId, userId)
.eq(LotteryUserCount::getActivityId, activityId)
.eq(LotteryUserCount::getDrawDate, LocalDate.now())
.getOne();
int drawCount = userCount != null ? userCount.getDrawCount() : 0;
ResponseAssert.isTrue(LotteryErrorCode.DRAW_COUNT_EXHAUSTED,
drawCount < activity.getDrawCountLimit());
}
/**
* 扣除抽奖券优化使用批量处理减少数据库交互.
*/ */
private void deductTicket(Long userId, Integer ticketCost) { private void deductTicket(Long userId, Integer ticketCost) {
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery() // 查询可用抽奖券按过期时间排序先用快过期的
List<LotteryTicket> tickets = lotteryTicketService.query()
.eq(LotteryTicket::getUserId, userId) .eq(LotteryTicket::getUserId, userId)
.eq(LotteryTicket::getStatus, 1) .eq(LotteryTicket::getStatus, 1)
.gt(LotteryTicket::getRemainingCount, 0) .gt(LotteryTicket::getRemainingCount, 0)
.orderByAsc(LotteryTicket::getExpireTime) .orderByAsc(LotteryTicket::getExpireTime)
.list(); .list();
// 校验总数量
int totalRemaining = tickets.stream() int totalRemaining = tickets.stream()
.mapToInt(LotteryTicket::getRemainingCount) .mapToInt(LotteryTicket::getRemainingCount)
.sum(); .sum();
ResponseAssert.isTrue(totalRemaining >= ticketCost, "抽奖券不足"); ResponseAssert.isTrue(LotteryErrorCode.INSUFFICIENT_TICKETS, totalRemaining >= ticketCost);
// 批量扣减
List<LotteryTicketRecord> records = new ArrayList<>();
int remaining = ticketCost; int remaining = ticketCost;
for (LotteryTicket ticket : tickets) { for (LotteryTicket ticket : tickets) {
if (remaining <= 0) { if (remaining <= 0) {
break; break;
@ -141,33 +149,43 @@ public class LotteryDrawExe {
int deduct = Math.min(remaining, ticket.getRemainingCount()); int deduct = Math.min(remaining, ticket.getRemainingCount());
lotteryTicketService.lambdaUpdate() // 使用乐观锁更新防止并发问题
boolean updateSuccess = lotteryTicketService.update()
.eq(LotteryTicket::getId, ticket.getId()) .eq(LotteryTicket::getId, ticket.getId())
.eq(LotteryTicket::getRemainingCount, ticket.getRemainingCount()) // 乐观锁
.setSql("used_count = used_count + " + deduct) .setSql("used_count = used_count + " + deduct)
.setSql("remaining_count = remaining_count - " + deduct) .setSql("remaining_count = remaining_count - " + deduct)
.update(); .execute();
// 记录使用 ResponseAssert.isTrue(LotteryErrorCode.INSUFFICIENT_TICKETS, updateSuccess);
// 记录使用日志
LotteryTicketRecord ticketRecord = new LotteryTicketRecord(); LotteryTicketRecord ticketRecord = new LotteryTicketRecord();
ticketRecord.setUserId(userId); ticketRecord.setUserId(userId);
ticketRecord.setTicketId(ticket.getId()); ticketRecord.setTicketId(ticket.getId());
ticketRecord.setChangeCount(-deduct); ticketRecord.setChangeCount(-deduct);
ticketRecord.setChangeType(2); // 消耗 ticketRecord.setChangeType(2); // 消耗
ticketRecord.setRemark("抽奖消耗"); ticketRecord.setRemark("抽奖消耗");
lotteryTicketRecordService.save(ticketRecord); records.add(ticketRecord);
remaining -= deduct; remaining -= deduct;
} }
// 批量插入日志
if (!records.isEmpty()) {
lotteryTicketRecordService.saveBatch(records);
}
} }
/** /**
* 抽奖算法 - 权重随机. * 抽奖算法 - 权重随机优化使用ThreadLocalRandom.
*/ */
private LotteryPrize drawPrize(Long activityId) { private LotteryPrize drawPrize(Long activityId) {
// 查询所有可用奖品 // 查询所有可用奖品
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery() List<LotteryPrize> prizes = lotteryPrizeService.query()
.eq(LotteryPrize::getActivityId, activityId) .eq(LotteryPrize::getActivityId, activityId)
.gt(LotteryPrize::getRemainingStock, 0) .gt(LotteryPrize::getRemainingStock, 0)
.orderByAsc(LotteryPrize::getSortOrder)
.list(); .list();
if (prizes.isEmpty()) { if (prizes.isEmpty()) {
@ -179,8 +197,7 @@ public class LotteryDrawExe {
.map(LotteryPrize::getProbability) .map(LotteryPrize::getProbability)
.reduce(BigDecimal.ZERO, BigDecimal::add); .reduce(BigDecimal.ZERO, BigDecimal::add);
// 生成随机数 double randomValue = ThreadLocalRandom.current().nextDouble() * totalProbability.doubleValue();
double randomValue = random.nextDouble() * totalProbability.doubleValue();
double cumulative = 0.0; double cumulative = 0.0;
// 根据概率选择奖品 // 根据概率选择奖品
@ -195,35 +212,86 @@ public class LotteryDrawExe {
} }
/** /**
* 更新用户抽奖次数. * 扣减奖品库存使用悲观锁防止超卖.
*/
private boolean deductPrizeStock(Long prizeId) {
// 使用数据库级别的原子操作
int affected = lotteryPrizeService.update()
.eq(LotteryPrize::getId, prizeId)
.gt(LotteryPrize::getRemainingStock, 0) // 必须有库存
.setSql("remaining_stock = remaining_stock - 1")
.execute()
? 1 : 0;
return affected > 0;
}
/**
* 保存抽奖记录.
*/
private LotteryRecord saveDrawRecord(Long userId, Long activityId, LotteryPrize prize, Timestamp now) {
String recordNo = generateRecordNo();
LotteryRecord record = new LotteryRecord();
record.setRecordNo(recordNo);
record.setUserId(userId);
record.setActivityId(activityId);
record.setDrawTime(now);
if (prize != null) {
record.setPrizeId(prize.getId());
record.setPrizeName(prize.getPrizeName());
record.setPrizeType(prize.getPrizeType());
record.setIsWin(1);
record.setPrizeStatus(0); // 待发放
} else {
record.setIsWin(0);
}
lotteryRecordService.save(record);
return record;
}
/**
* 更新用户抽奖次数优化减少查询.
*/ */
private void updateUserDrawCount(Long userId, Long activityId) { private void updateUserDrawCount(Long userId, Long activityId) {
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery() LocalDate today = LocalDate.now();
// 先尝试直接更新
boolean updated = lotteryUserCountService.update()
.eq(LotteryUserCount::getUserId, userId) .eq(LotteryUserCount::getUserId, userId)
.eq(LotteryUserCount::getActivityId, activityId) .eq(LotteryUserCount::getActivityId, activityId)
.eq(LotteryUserCount::getDrawDate, LocalDate.now()) .eq(LotteryUserCount::getDrawDate, today)
.one(); .setSql("draw_count = draw_count + 1")
.execute();
if (userCount == null) { // 如果更新失败记录不存在则插入
userCount = new LotteryUserCount(); if (!updated) {
userCount.setUserId(userId); try {
userCount.setActivityId(activityId); LotteryUserCount userCount = new LotteryUserCount();
userCount.setDrawDate(LocalDate.now()); userCount.setUserId(userId);
userCount.setDrawCount(1); userCount.setActivityId(activityId);
lotteryUserCountService.save(userCount); userCount.setDrawDate(today);
} else { userCount.setDrawCount(1);
lotteryUserCountService.lambdaUpdate() lotteryUserCountService.save(userCount);
.eq(LotteryUserCount::getId, userCount.getId()) } catch (Exception e) {
.setSql("draw_count = draw_count + 1") // 并发情况下可能插入失败再次更新
.update(); lotteryUserCountService.update()
.eq(LotteryUserCount::getUserId, userId)
.eq(LotteryUserCount::getActivityId, activityId)
.eq(LotteryUserCount::getDrawDate, today)
.setSql("draw_count = draw_count + 1")
.execute();
}
} }
} }
/** /**
* 生成记录编号. * 生成记录编号优化使用更高效的方式.
*/ */
private String generateRecordNo() { private String generateRecordNo() {
return "LT" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8); return "LT" + System.currentTimeMillis() +
String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
} }
/** /**

View File

@ -1,5 +1,6 @@
package com.red.circle.other.app.command.activity; package com.red.circle.other.app.command.activity;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.red.circle.framework.dto.PageResult; import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.app.dto.clientobject.activity.LotteryPrizeCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryPrizeCO;
@ -37,14 +38,14 @@ public class LotteryRecordQryExe {
Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20; Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20;
// 构建查询条件 // 构建查询条件
Page<LotteryRecord> page = new Page<>(pageNo, pageSize); IPage<LotteryRecord> page = new Page<>(pageNo, pageSize);
var query = lotteryRecordService.lambdaQuery() var query = lotteryRecordService.query()
.eq(LotteryRecord::getUserId, userId); .eq(LotteryRecord::getUserId, userId);
if (cmd.getActivityCode() != null) { if (cmd.getActivityCode() != null) {
LotteryActivity activity = lotteryActivityService.lambdaQuery() LotteryActivity activity = lotteryActivityService.query()
.eq(LotteryActivity::getActivityCode, cmd.getActivityCode()) .eq(LotteryActivity::getActivityCode, cmd.getActivityCode())
.one(); .getOne();
if (activity != null) { if (activity != null) {
query.eq(LotteryRecord::getActivityId, activity.getId()); query.eq(LotteryRecord::getActivityId, activity.getId());
} }
@ -54,7 +55,7 @@ public class LotteryRecordQryExe {
query.eq(LotteryRecord::getIsWin, 1); query.eq(LotteryRecord::getIsWin, 1);
} }
Page<LotteryRecord> recordPage = query.orderByDesc(LotteryRecord::getDrawTime).page(page); IPage<LotteryRecord> recordPage = query.orderByDesc(LotteryRecord::getDrawTime).page(page);
// 查询关联数据 // 查询关联数据
List<Long> activityIds = recordPage.getRecords().stream() List<Long> activityIds = recordPage.getRecords().stream()
@ -68,13 +69,13 @@ public class LotteryRecordQryExe {
.distinct() .distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<Long, LotteryActivity> activityMap = lotteryActivityService.lambdaQuery() Map<Long, LotteryActivity> activityMap = lotteryActivityService.query()
.in(LotteryActivity::getId, activityIds) .in(LotteryActivity::getId, activityIds)
.list() .list()
.stream() .stream()
.collect(Collectors.toMap(LotteryActivity::getId, a -> a)); .collect(Collectors.toMap(LotteryActivity::getId, a -> a));
Map<Long, LotteryPrize> prizeMap = lotteryPrizeService.lambdaQuery() Map<Long, LotteryPrize> prizeMap = lotteryPrizeService.query()
.in(LotteryPrize::getId, prizeIds) .in(LotteryPrize::getId, prizeIds)
.list() .list()
.stream() .stream()
@ -85,7 +86,13 @@ public class LotteryRecordQryExe {
.map(record -> convertToCO(record, activityMap, prizeMap)) .map(record -> convertToCO(record, activityMap, prizeMap))
.collect(Collectors.toList()); .collect(Collectors.toList());
return PageResult.of(records, recordPage.getTotal(), pageNo, pageSize); PageResult<LotteryRecordCO> result = new PageResult<>();
result.setRecords(records);
result.setTotal(recordPage.getTotal());
result.setCurrent(recordPage.getCurrent());
result.setSize(recordPage.getSize());
return result;
} }
private LotteryRecordCO convertToCO(LotteryRecord record, private LotteryRecordCO convertToCO(LotteryRecord record,

View File

@ -22,7 +22,7 @@ public class LotteryTicketCountQryExe {
public Integer execute(AppExtCommand cmd) { public Integer execute(AppExtCommand cmd) {
Long userId = cmd.requiredReqUserId(); Long userId = cmd.requiredReqUserId();
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery() List<LotteryTicket> tickets = lotteryTicketService.query()
.eq(LotteryTicket::getUserId, userId) .eq(LotteryTicket::getUserId, userId)
.eq(LotteryTicket::getStatus, 1) .eq(LotteryTicket::getStatus, 1)
.gt(LotteryTicket::getRemainingCount, 0) .gt(LotteryTicket::getRemainingCount, 0)

View File

@ -7,10 +7,11 @@ import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketSer
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* 查询我的抽奖券. * 查询我的抽奖券列表.
* *
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
@ -24,7 +25,7 @@ public class LotteryTicketQryExe {
public List<LotteryTicketCO> execute(AppExtCommand cmd) { public List<LotteryTicketCO> execute(AppExtCommand cmd) {
Long userId = cmd.requiredReqUserId(); Long userId = cmd.requiredReqUserId();
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery() List<LotteryTicket> tickets = lotteryTicketService.query()
.eq(LotteryTicket::getUserId, userId) .eq(LotteryTicket::getUserId, userId)
.eq(LotteryTicket::getStatus, 1) .eq(LotteryTicket::getStatus, 1)
.gt(LotteryTicket::getRemainingCount, 0) .gt(LotteryTicket::getRemainingCount, 0)
@ -38,13 +39,7 @@ public class LotteryTicketQryExe {
private LotteryTicketCO convertToCO(LotteryTicket ticket) { private LotteryTicketCO convertToCO(LotteryTicket ticket) {
LotteryTicketCO co = new LotteryTicketCO(); LotteryTicketCO co = new LotteryTicketCO();
co.setId(ticket.getId()); BeanUtils.copyProperties(ticket, co);
co.setTicketSource(ticket.getTicketSource());
co.setTotalCount(ticket.getTotalCount());
co.setUsedCount(ticket.getUsedCount());
co.setRemainingCount(ticket.getRemainingCount());
co.setExpireTime(ticket.getExpireTime());
co.setStatus(ticket.getStatus());
return co; return co;
} }

View File

@ -27,7 +27,7 @@ import org.springframework.stereotype.Service;
*/ */
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class LotteryActivityServiceImpl implements LotteryActivityService { public class LotteryActivityRestServiceImpl implements LotteryActivityRestService {
private final LotteryActivityListQryExe lotteryActivityListQryExe; private final LotteryActivityListQryExe lotteryActivityListQryExe;
private final LotteryActivityDetailQryExe lotteryActivityDetailQryExe; private final LotteryActivityDetailQryExe lotteryActivityDetailQryExe;

View File

@ -1,11 +1,7 @@
package com.red.circle.other.app.service.activity; package com.red.circle.other.app.service.activity;
import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.common.business.dto.cmd.AppExtCommand;
import com.red.circle.other.app.command.activity.LotteryDrawExe; import com.red.circle.other.app.command.activity.*;
import com.red.circle.other.app.command.activity.query.LotteryActivityDetailQryExe;
import com.red.circle.other.app.command.activity.query.LotteryActivityListQryExe;
import com.red.circle.other.app.command.activity.query.LotteryRecordQryExe;
import com.red.circle.other.app.command.activity.query.LotteryTicketQryExe;
import com.red.circle.other.app.dto.clientobject.activity.LotteryActivityCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryActivityCO;
import com.red.circle.other.app.dto.clientobject.activity.LotteryActivityDetailCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryActivityDetailCO;
import com.red.circle.other.app.dto.clientobject.activity.LotteryDrawResultCO; import com.red.circle.other.app.dto.clientobject.activity.LotteryDrawResultCO;
@ -48,11 +44,6 @@ public class LotteryServiceImpl implements LotteryService {
return lotteryDrawExe.execute(cmd); return lotteryDrawExe.execute(cmd);
} }
@Override
public List<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd) {
return lotteryRecordQryExe.execute(cmd);
}
@Override @Override
public List<LotteryTicketCO> listMyTickets(AppExtCommand cmd) { public List<LotteryTicketCO> listMyTickets(AppExtCommand cmd) {
return lotteryTicketQryExe.execute(cmd); return lotteryTicketQryExe.execute(cmd);

View File

@ -1,7 +1,7 @@
package com.red.circle.other.app.dto.clientobject.activity; package com.red.circle.other.app.dto.clientobject.activity;
import com.red.circle.framework.dto.ClientObject; import com.red.circle.framework.dto.ClientObject;
import java.time.LocalDateTime; import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@ -40,12 +40,12 @@ public class LotteryActivityCO extends ClientObject {
/** /**
* 开始时间. * 开始时间.
*/ */
private LocalDateTime startTime; private Timestamp startTime;
/** /**
* 结束时间. * 结束时间.
*/ */
private LocalDateTime endTime; private Timestamp endTime;
/** /**
* 状态0-未开始1-进行中2-已结束3-已关闭. * 状态0-未开始1-进行中2-已结束3-已关闭.

View File

@ -1,7 +1,7 @@
package com.red.circle.other.app.dto.clientobject.activity; package com.red.circle.other.app.dto.clientobject.activity;
import com.red.circle.framework.dto.ClientObject; import com.red.circle.framework.dto.ClientObject;
import java.time.LocalDateTime; import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@ -35,6 +35,6 @@ public class LotteryDrawResultCO extends ClientObject {
/** /**
* 抽奖时间. * 抽奖时间.
*/ */
private LocalDateTime drawTime; private Timestamp drawTime;
} }

View File

@ -35,7 +35,7 @@ public class LotteryPrizeCO extends ClientObject {
/** /**
* 奖品类型. * 奖品类型.
*/ */
private Integer prizeType; private String prizeType;
/** /**
* 奖品价值. * 奖品价值.

View File

@ -1,7 +1,7 @@
package com.red.circle.other.app.dto.clientobject.activity; package com.red.circle.other.app.dto.clientobject.activity;
import com.red.circle.framework.dto.ClientObject; import com.red.circle.framework.dto.ClientObject;
import java.time.LocalDateTime; import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@ -40,7 +40,7 @@ public class LotteryRecordCO extends ClientObject {
/** /**
* 抽奖时间. * 抽奖时间.
*/ */
private LocalDateTime drawTime; private Timestamp drawTime;
/** /**
* 奖品状态0-待发放1-已发放2-发放失败. * 奖品状态0-待发放1-已发放2-发放失败.

View File

@ -1,7 +1,7 @@
package com.red.circle.other.app.dto.clientobject.activity; package com.red.circle.other.app.dto.clientobject.activity;
import com.red.circle.framework.dto.ClientObject; import com.red.circle.framework.dto.ClientObject;
import java.time.LocalDateTime; import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@ -45,7 +45,7 @@ public class LotteryTicketCO extends ClientObject {
/** /**
* 过期时间. * 过期时间.
*/ */
private LocalDateTime expireTime; private Timestamp expireTime;
/** /**
* 状态. * 状态.

View File

@ -1,7 +1,7 @@
package com.red.circle.other.app.dto.cmd.activity; package com.red.circle.other.app.dto.cmd.activity;
import com.red.circle.common.business.dto.cmd.AppExtCommand; import com.red.circle.common.business.dto.cmd.AppExtCommand;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -16,11 +16,11 @@ import lombok.EqualsAndHashCode;
public class LotteryDrawCmd extends AppExtCommand { public class LotteryDrawCmd extends AppExtCommand {
/** /**
* 活动编码. * 活动ID.
* *
* @eo.required * @eo.required
*/ */
@NotBlank(message = "activityCode required.") @NotNull(message = "activityId required.")
private String activityCode; private Long activityId;
} }

View File

@ -17,7 +17,7 @@ import java.util.List;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
public interface LotteryActivityService { public interface LotteryActivityRestService {
/** /**
* 获取有效活动列表. * 获取有效活动列表.

View File

@ -33,11 +33,6 @@ public interface LotteryService {
*/ */
LotteryDrawResultCO draw(LotteryDrawCmd cmd); LotteryDrawResultCO draw(LotteryDrawCmd cmd);
/**
* 查询用户抽奖记录.
*/
List<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd);
/** /**
* 查询用户抽奖券. * 查询用户抽奖券.
*/ */

View File

@ -1,8 +1,7 @@
package com.red.circle.other.infra.database.rds.dao.activity; package com.red.circle.other.infra.database.rds.dao.activity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.red.circle.framework.mybatis.dao.BaseDAO;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity; import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
import org.apache.ibatis.annotations.Mapper;
/** /**
* 抽奖活动Mapper. * 抽奖活动Mapper.
@ -10,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Mapper public interface LotteryActivityMapper extends BaseDAO<LotteryActivity> {
public interface LotteryActivityMapper extends BaseMapper<LotteryActivity> {
} }

View File

@ -1,8 +1,7 @@
package com.red.circle.other.infra.database.rds.dao.activity; package com.red.circle.other.infra.database.rds.dao.activity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.red.circle.framework.mybatis.dao.BaseDAO;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize; import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
import org.apache.ibatis.annotations.Mapper;
/** /**
* 奖品配置Mapper. * 奖品配置Mapper.
@ -10,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Mapper public interface LotteryPrizeMapper extends BaseDAO<LotteryPrize> {
public interface LotteryPrizeMapper extends BaseMapper<LotteryPrize> {
} }

View File

@ -1,8 +1,7 @@
package com.red.circle.other.infra.database.rds.dao.activity; package com.red.circle.other.infra.database.rds.dao.activity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.red.circle.framework.mybatis.dao.BaseDAO;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
import org.apache.ibatis.annotations.Mapper;
/** /**
* 中奖记录Mapper. * 中奖记录Mapper.
@ -10,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Mapper public interface LotteryRecordMapper extends BaseDAO<LotteryRecord> {
public interface LotteryRecordMapper extends BaseMapper<LotteryRecord> {
} }

View File

@ -1,8 +1,7 @@
package com.red.circle.other.infra.database.rds.dao.activity; package com.red.circle.other.infra.database.rds.dao.activity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.red.circle.framework.mybatis.dao.BaseDAO;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
import org.apache.ibatis.annotations.Mapper;
/** /**
* 抽奖券Mapper. * 抽奖券Mapper.
@ -10,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Mapper public interface LotteryTicketMapper extends BaseDAO<LotteryTicket> {
public interface LotteryTicketMapper extends BaseMapper<LotteryTicket> {
} }

View File

@ -1,8 +1,7 @@
package com.red.circle.other.infra.database.rds.dao.activity; package com.red.circle.other.infra.database.rds.dao.activity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.red.circle.framework.mybatis.dao.BaseDAO;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord;
import org.apache.ibatis.annotations.Mapper;
/** /**
* 抽奖券使用记录Mapper. * 抽奖券使用记录Mapper.
@ -10,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Mapper public interface LotteryTicketRecordMapper extends BaseDAO<LotteryTicketRecord> {
public interface LotteryTicketRecordMapper extends BaseMapper<LotteryTicketRecord> {
} }

View File

@ -1,8 +1,7 @@
package com.red.circle.other.infra.database.rds.dao.activity; package com.red.circle.other.infra.database.rds.dao.activity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.red.circle.framework.mybatis.dao.BaseDAO;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount; import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
import org.apache.ibatis.annotations.Mapper;
/** /**
* 用户抽奖次数统计Mapper. * 用户抽奖次数统计Mapper.
@ -10,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Mapper public interface LotteryUserCountMapper extends BaseDAO<LotteryUserCount> {
public interface LotteryUserCountMapper extends BaseMapper<LotteryUserCount> {
} }

View File

@ -5,7 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity; import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
import java.io.Serial; import java.io.Serial;
import java.time.LocalDateTime; import java.io.Serializable;
import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@ -19,10 +20,9 @@ import lombok.experimental.Accessors;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("lottery_activity") @TableName("lottery_activity")
public class LotteryActivity extends TimestampBaseEntity { public class LotteryActivity implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -55,13 +55,13 @@ public class LotteryActivity extends TimestampBaseEntity {
* 开始时间. * 开始时间.
*/ */
@TableField("start_time") @TableField("start_time")
private LocalDateTime startTime; private Timestamp startTime;
/** /**
* 结束时间. * 结束时间.
*/ */
@TableField("end_time") @TableField("end_time")
private LocalDateTime endTime; private Timestamp endTime;
/** /**
* 状态0-未开始1-进行中2-已结束3-已关闭. * 状态0-未开始1-进行中2-已结束3-已关闭.
@ -111,4 +111,8 @@ public class LotteryActivity extends TimestampBaseEntity {
@TableField("sort_order") @TableField("sort_order")
private Integer sortOrder; private Integer sortOrder;
private Timestamp createTime;
private Timestamp updateTime;
} }

View File

@ -3,9 +3,11 @@ package com.red.circle.other.infra.database.rds.entity.activity;
import com.baomidou.mybatisplus.annotation.TableField; 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 com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@ -19,10 +21,9 @@ import lombok.experimental.Accessors;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("lottery_prize") @TableName("lottery_prize")
public class LotteryPrize extends TimestampBaseEntity { public class LotteryPrize implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -55,7 +56,7 @@ public class LotteryPrize extends TimestampBaseEntity {
* 奖品类型1-实物2-虚拟币3-优惠券4-积分5-谢谢参与. * 奖品类型1-实物2-虚拟币3-优惠券4-积分5-谢谢参与.
*/ */
@TableField("prize_type") @TableField("prize_type")
private Integer prizeType; private String prizeType;
/** /**
* 奖品价值/数量. * 奖品价值/数量.
@ -111,4 +112,8 @@ public class LotteryPrize extends TimestampBaseEntity {
@TableField("is_display") @TableField("is_display")
private Integer isDisplay; private Integer isDisplay;
private Timestamp createTime;
private Timestamp updateTime;
} }

View File

@ -3,11 +3,10 @@ package com.red.circle.other.infra.database.rds.entity.activity;
import com.baomidou.mybatisplus.annotation.TableField; 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 com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
import java.io.Serial; import java.io.Serial;
import java.time.LocalDateTime; import java.io.Serializable;
import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
/** /**
@ -19,10 +18,9 @@ import lombok.experimental.Accessors;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("lottery_record") @TableName("lottery_record")
public class LotteryRecord extends TimestampBaseEntity { public class LotteryRecord implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -67,7 +65,7 @@ public class LotteryRecord extends TimestampBaseEntity {
* 奖品类型快照. * 奖品类型快照.
*/ */
@TableField("prize_type") @TableField("prize_type")
private Integer prizeType; private String prizeType;
/** /**
* 是否中奖0-未中奖1-中奖. * 是否中奖0-未中奖1-中奖.
@ -79,7 +77,7 @@ public class LotteryRecord extends TimestampBaseEntity {
* 抽奖时间. * 抽奖时间.
*/ */
@TableField("draw_time") @TableField("draw_time")
private LocalDateTime drawTime; private Timestamp drawTime;
/** /**
* 奖品状态0-待发放1-已发放2-发放失败. * 奖品状态0-待发放1-已发放2-发放失败.
@ -91,7 +89,7 @@ public class LotteryRecord extends TimestampBaseEntity {
* 发放时间. * 发放时间.
*/ */
@TableField("deliver_time") @TableField("deliver_time")
private LocalDateTime deliverTime; private Timestamp deliverTime;
/** /**
* 备注. * 备注.

View File

@ -3,11 +3,10 @@ package com.red.circle.other.infra.database.rds.entity.activity;
import com.baomidou.mybatisplus.annotation.TableField; 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 com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
import java.io.Serial; import java.io.Serial;
import java.time.LocalDateTime; import java.io.Serializable;
import java.sql.Timestamp;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
/** /**
@ -19,10 +18,9 @@ import lombok.experimental.Accessors;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("lottery_ticket") @TableName("lottery_ticket")
public class LotteryTicket extends TimestampBaseEntity { public class LotteryTicket implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -73,7 +71,7 @@ public class LotteryTicket extends TimestampBaseEntity {
* 过期时间. * 过期时间.
*/ */
@TableField("expire_time") @TableField("expire_time")
private LocalDateTime expireTime; private Timestamp expireTime;
/** /**
* 状态0-已失效1-正常. * 状态0-已失效1-正常.

View File

@ -3,10 +3,10 @@ package com.red.circle.other.infra.database.rds.entity.activity;
import com.baomidou.mybatisplus.annotation.TableField; 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 com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
/** /**
@ -18,10 +18,9 @@ import lombok.experimental.Accessors;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("lottery_ticket_record") @TableName("lottery_ticket_record")
public class LotteryTicketRecord extends TimestampBaseEntity { public class LotteryTicketRecord implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -3,9 +3,11 @@ package com.red.circle.other.infra.database.rds.entity.activity;
import com.baomidou.mybatisplus.annotation.TableField; 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 com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable;
import java.sql.Timestamp;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
@ -19,10 +21,9 @@ import lombok.experimental.Accessors;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true) @Accessors(chain = true)
@TableName("lottery_user_count") @TableName("lottery_user_count")
public class LotteryUserCount extends TimestampBaseEntity { public class LotteryUserCount implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -57,4 +58,7 @@ public class LotteryUserCount extends TimestampBaseEntity {
@TableField("draw_count") @TableField("draw_count")
private Integer drawCount; private Integer drawCount;
private Timestamp createTime;
private Timestamp updateTime;
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity; package com.red.circle.other.infra.database.rds.service.activity;
import com.baomidou.mybatisplus.extension.service.IService; import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity; import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
/** /**
@ -9,6 +9,6 @@ import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
public interface LotteryActivityService extends IService<LotteryActivity> { public interface LotteryActivityService extends BaseService<LotteryActivity> {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity; package com.red.circle.other.infra.database.rds.service.activity;
import com.baomidou.mybatisplus.extension.service.IService; import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize; import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
/** /**
@ -9,6 +9,6 @@ import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
public interface LotteryPrizeService extends IService<LotteryPrize> { public interface LotteryPrizeService extends BaseService<LotteryPrize> {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity; package com.red.circle.other.infra.database.rds.service.activity;
import com.baomidou.mybatisplus.extension.service.IService; import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
/** /**
@ -9,6 +9,6 @@ import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
public interface LotteryRecordService extends IService<LotteryRecord> { public interface LotteryRecordService extends BaseService<LotteryRecord> {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity; package com.red.circle.other.infra.database.rds.service.activity;
import com.baomidou.mybatisplus.extension.service.IService; import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord;
/** /**
@ -9,6 +9,6 @@ import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketReco
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
public interface LotteryTicketRecordService extends IService<LotteryTicketRecord> { public interface LotteryTicketRecordService extends BaseService<LotteryTicketRecord> {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity; package com.red.circle.other.infra.database.rds.service.activity;
import com.baomidou.mybatisplus.extension.service.IService; import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
/** /**
@ -9,6 +9,6 @@ import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
public interface LotteryTicketService extends IService<LotteryTicket> { public interface LotteryTicketService extends BaseService<LotteryTicket> {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity; package com.red.circle.other.infra.database.rds.service.activity;
import com.baomidou.mybatisplus.extension.service.IService; import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount; import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
/** /**
@ -9,6 +9,6 @@ import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
* @author system * @author system
* @since 2025-10-18 * @since 2025-10-18
*/ */
public interface LotteryUserCountService extends IService<LotteryUserCount> { public interface LotteryUserCountService extends BaseService<LotteryUserCount> {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity.impl; package com.red.circle.other.infra.database.rds.service.activity.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity; import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
import com.red.circle.other.infra.database.rds.dao.activity.LotteryActivityMapper; import com.red.circle.other.infra.database.rds.dao.activity.LotteryActivityMapper;
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService; import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Service @Service
public class LotteryActivityServiceImpl extends ServiceImpl<LotteryActivityMapper, LotteryActivity> public class LotteryActivityServiceImpl extends BaseServiceImpl<LotteryActivityMapper, LotteryActivity>
implements LotteryActivityService { implements LotteryActivityService {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity.impl; package com.red.circle.other.infra.database.rds.service.activity.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize; import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
import com.red.circle.other.infra.database.rds.dao.activity.LotteryPrizeMapper; import com.red.circle.other.infra.database.rds.dao.activity.LotteryPrizeMapper;
import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService; import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService;
@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Service @Service
public class LotteryPrizeServiceImpl extends ServiceImpl<LotteryPrizeMapper, LotteryPrize> public class LotteryPrizeServiceImpl extends BaseServiceImpl<LotteryPrizeMapper, LotteryPrize>
implements LotteryPrizeService { implements LotteryPrizeService {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity.impl; package com.red.circle.other.infra.database.rds.service.activity.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
import com.red.circle.other.infra.database.rds.dao.activity.LotteryRecordMapper; import com.red.circle.other.infra.database.rds.dao.activity.LotteryRecordMapper;
import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordService; import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordService;
@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Service @Service
public class LotteryRecordServiceImpl extends ServiceImpl<LotteryRecordMapper, LotteryRecord> public class LotteryRecordServiceImpl extends BaseServiceImpl<LotteryRecordMapper, LotteryRecord>
implements LotteryRecordService { implements LotteryRecordService {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity.impl; package com.red.circle.other.infra.database.rds.service.activity.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord;
import com.red.circle.other.infra.database.rds.dao.activity.LotteryTicketRecordMapper; import com.red.circle.other.infra.database.rds.dao.activity.LotteryTicketRecordMapper;
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketRecordService; import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketRecordService;
@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Service @Service
public class LotteryTicketRecordServiceImpl extends ServiceImpl<LotteryTicketRecordMapper, LotteryTicketRecord> public class LotteryTicketRecordServiceImpl extends BaseServiceImpl<LotteryTicketRecordMapper, LotteryTicketRecord>
implements LotteryTicketRecordService { implements LotteryTicketRecordService {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity.impl; package com.red.circle.other.infra.database.rds.service.activity.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
import com.red.circle.other.infra.database.rds.dao.activity.LotteryTicketMapper; import com.red.circle.other.infra.database.rds.dao.activity.LotteryTicketMapper;
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService; import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService;
@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Service @Service
public class LotteryTicketServiceImpl extends ServiceImpl<LotteryTicketMapper, LotteryTicket> public class LotteryTicketServiceImpl extends BaseServiceImpl<LotteryTicketMapper, LotteryTicket>
implements LotteryTicketService { implements LotteryTicketService {
} }

View File

@ -1,6 +1,6 @@
package com.red.circle.other.infra.database.rds.service.activity.impl; package com.red.circle.other.infra.database.rds.service.activity.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount; import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
import com.red.circle.other.infra.database.rds.dao.activity.LotteryUserCountMapper; import com.red.circle.other.infra.database.rds.dao.activity.LotteryUserCountMapper;
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService; import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService;
@ -13,7 +13,7 @@ import org.springframework.stereotype.Service;
* @since 2025-10-18 * @since 2025-10-18
*/ */
@Service @Service
public class LotteryUserCountServiceImpl extends ServiceImpl<LotteryUserCountMapper, LotteryUserCount> public class LotteryUserCountServiceImpl extends BaseServiceImpl<LotteryUserCountMapper, LotteryUserCount>
implements LotteryUserCountService { implements LotteryUserCountService {
} }

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.red.circle.other.infra.database.rds.dao.activity.LotteryActivityMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.red.circle.other.infra.database.rds.dao.activity.LotteryPrizeMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.red.circle.other.infra.database.rds.dao.activity.LotteryRecordMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace="com.red.circle.other.infra.database.rds.dao.activity.LotteryTicketMapper">
</mapper>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.red.circle.other.infra.database.rds.dao.activity.LotteryTicketRecordMapper">
</mapper>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.red.circle.other.infra.database.rds.dao.activity.LotteryUserCountMapper">
</mapper>

View File

@ -30,9 +30,9 @@ public class LotteryActivityClientEndpoint implements LotteryActivityClientApi {
@Override @Override
public ResultResponse<LotteryActivityDTO> getByActivityCode(String activityCode) { public ResultResponse<LotteryActivityDTO> getByActivityCode(String activityCode) {
LotteryActivity activity = lotteryActivityService.lambdaQuery() LotteryActivity activity = lotteryActivityService.query()
.eq(LotteryActivity::getActivityCode, activityCode) .eq(LotteryActivity::getActivityCode, activityCode)
.one(); .getOne();
if (activity == null) { if (activity == null) {
return ResultResponse.success(null); return ResultResponse.success(null);
@ -54,7 +54,7 @@ public class LotteryActivityClientEndpoint implements LotteryActivityClientApi {
@Override @Override
public ResultResponse<List<LotteryActivityDTO>> listActivities() { public ResultResponse<List<LotteryActivityDTO>> listActivities() {
List<LotteryActivity> activities = lotteryActivityService.lambdaQuery() List<LotteryActivity> activities = lotteryActivityService.query()
.eq(LotteryActivity::getStatus, 1) .eq(LotteryActivity::getStatus, 1)
.orderByDesc(LotteryActivity::getCreateTime) .orderByDesc(LotteryActivity::getCreateTime)
.list(); .list();

View File

@ -8,6 +8,10 @@ import com.red.circle.other.inner.asserts.lottery.LotteryErrorCode;
import com.red.circle.other.inner.endpoint.activity.api.LotteryActivityManageClientApi; import com.red.circle.other.inner.endpoint.activity.api.LotteryActivityManageClientApi;
import com.red.circle.other.inner.model.cmd.activity.LotteryActivitySaveCmd; import com.red.circle.other.inner.model.cmd.activity.LotteryActivitySaveCmd;
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO; import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
import java.sql.Timestamp;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -34,9 +38,9 @@ public class LotteryActivityManageClientEndpoint implements LotteryActivityManag
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResultResponse<Void> createActivity(LotteryActivitySaveCmd cmd) { public ResultResponse<Void> createActivity(LotteryActivitySaveCmd cmd) {
// 校验活动编码唯一性 // 校验活动编码唯一性
LotteryActivity exists = lotteryActivityService.lambdaQuery() LotteryActivity exists = lotteryActivityService.query()
.eq(LotteryActivity::getActivityCode, cmd.getActivityCode()) .eq(LotteryActivity::getActivityCode, cmd.getActivityCode())
.one(); .getOne();
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_CODE_EXISTS, exists == null); ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_CODE_EXISTS, exists == null);
LotteryActivity activity = new LotteryActivity(); LotteryActivity activity = new LotteryActivity();
@ -58,15 +62,8 @@ public class LotteryActivityManageClientEndpoint implements LotteryActivityManag
LotteryActivity activity = lotteryActivityService.getById(cmd.getId()); LotteryActivity activity = lotteryActivityService.getById(cmd.getId());
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null); ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null);
// 校验活动编码唯一性
LotteryActivity exists = lotteryActivityService.lambdaQuery()
.eq(LotteryActivity::getActivityCode, cmd.getActivityCode())
.ne(LotteryActivity::getId, cmd.getId())
.one();
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_CODE_EXISTS, exists == null);
BeanUtils.copyProperties(cmd, activity); BeanUtils.copyProperties(cmd, activity);
lotteryActivityService.updateById(activity); lotteryActivityService.updateSelectiveById(activity);
return ResultResponse.success(); return ResultResponse.success();
} }
@ -77,8 +74,44 @@ public class LotteryActivityManageClientEndpoint implements LotteryActivityManag
LotteryActivity activity = lotteryActivityService.getById(id); LotteryActivity activity = lotteryActivityService.getById(id);
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null); ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null);
Integer currentStatus = activity.getStatus();
Timestamp now = TimestampUtils.now();
// 状态校验规则0-未开始1-进行中2-已结束3-已关闭
// 1. 未开始(0) -> 可以转换为进行中(1)已关闭(3)
// 2. 进行中(1) -> 可以转换为已结束(2)已关闭(3)
// 3. 已结束(2) -> 可以转换为已关闭(3)
// 4. 已关闭(3) -> 不可再转换
// 校验已关闭的活动不能再修改状态
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_STATUS_NOT_ALLOW_UPDATE,
currentStatus != 3);
// 校验状态转换的合法性
if (currentStatus == 0) {
// 未开始 -> 只能转换为 进行中(1) 已关闭(3)
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_STATUS_NOT_ALLOW_UPDATE,
status == 1 || status == 3);
// 转换为进行中时需要校验时间
if (status == 1) {
ResponseAssert.isTrue(LotteryErrorCode.NOT_IN_ACTIVITY_TIME,
now.after(activity.getStartTime()) || now.equals(activity.getStartTime()));
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_ENDED,
now.before(activity.getEndTime()));
}
} else if (currentStatus == 1) {
// 进行中 -> 只能转换为 已结束(2) 已关闭(3)
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_STATUS_NOT_ALLOW_UPDATE,
status == 2 || status == 3);
} else if (currentStatus == 2) {
// 已结束 -> 只能转换为 已关闭(3)
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_STATUS_NOT_ALLOW_UPDATE,
status == 3);
}
activity.setStatus(status); activity.setStatus(status);
lotteryActivityService.updateById(activity); lotteryActivityService.updateSelectiveById(activity);
return ResultResponse.success(); return ResultResponse.success();
} }

View File

@ -1,5 +1,6 @@
package com.red.circle.other.app.inner.endpoint.activity; package com.red.circle.other.app.inner.endpoint.activity;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.red.circle.framework.dto.PageResult; import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.dto.ResultResponse; import com.red.circle.framework.dto.ResultResponse;
@ -37,7 +38,7 @@ public class LotteryActivityQueryClientEndpoint implements LotteryActivityQueryC
Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20; Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20;
Page<LotteryActivity> page = new Page<>(pageNo, pageSize); Page<LotteryActivity> page = new Page<>(pageNo, pageSize);
var query = lotteryActivityService.lambdaQuery(); var query = lotteryActivityService.query();
if (cmd.getActivityName() != null) { if (cmd.getActivityName() != null) {
query.like(LotteryActivity::getActivityName, cmd.getActivityName()); query.like(LotteryActivity::getActivityName, cmd.getActivityName());
@ -55,7 +56,7 @@ public class LotteryActivityQueryClientEndpoint implements LotteryActivityQueryC
query.le(LotteryActivity::getStartTime, cmd.getStartTimeEnd()); query.le(LotteryActivity::getStartTime, cmd.getStartTimeEnd());
} }
Page<LotteryActivity> result = query.orderByDesc(LotteryActivity::getCreateTime).page(page); IPage<LotteryActivity> result = query.orderByDesc(LotteryActivity::getCreateTime).page(page);
List<LotteryActivityDTO> dtoList = result.getRecords().stream() List<LotteryActivityDTO> dtoList = result.getRecords().stream()
.map(activity -> { .map(activity -> {

View File

@ -1,6 +1,9 @@
package com.red.circle.other.app.inner.endpoint.activity; package com.red.circle.other.app.inner.endpoint.activity;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.red.circle.framework.dto.ResultResponse; import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.framework.mybatis.mybatisplus.LambdaQueryWrapperChain;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize; import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService; import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService;
import com.red.circle.other.inner.endpoint.activity.api.LotteryPrizeClientApi; import com.red.circle.other.inner.endpoint.activity.api.LotteryPrizeClientApi;
@ -30,7 +33,7 @@ public class LotteryPrizeClientEndpoint implements LotteryPrizeClientApi {
@Override @Override
public ResultResponse<List<LotteryPrizeDTO>> listByActivityId(Long activityId) { public ResultResponse<List<LotteryPrizeDTO>> listByActivityId(Long activityId) {
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery() List<LotteryPrize> prizes = lotteryPrizeService.query()
.eq(LotteryPrize::getActivityId, activityId) .eq(LotteryPrize::getActivityId, activityId)
.orderByAsc(LotteryPrize::getSortOrder) .orderByAsc(LotteryPrize::getSortOrder)
.list(); .list();
@ -55,12 +58,10 @@ public class LotteryPrizeClientEndpoint implements LotteryPrizeClientApi {
@Override @Override
public ResultResponse<Boolean> deductStock(Long id, Integer count) { public ResultResponse<Boolean> deductStock(Long id, Integer count) {
boolean success = lotteryPrizeService.lambdaUpdate() LambdaUpdateWrapper<LotteryPrize> wrapper = new LambdaUpdateWrapper<LotteryPrize>().eq(LotteryPrize::getId, id)
.eq(LotteryPrize::getId, id)
.gt(LotteryPrize::getRemainingStock, 0) .gt(LotteryPrize::getRemainingStock, 0)
.setSql("remaining_stock = remaining_stock - " + count) .setSql("remaining_stock = remaining_stock - " + count);
.update(); boolean success = lotteryPrizeService.update(wrapper);
return ResultResponse.success(success); return ResultResponse.success(success);
} }

View File

@ -65,7 +65,7 @@ public class LotteryPrizeManageClientEndpoint implements LotteryPrizeManageClien
@Override @Override
public ResultResponse<List<LotteryPrizeDTO>> listByActivityId(Long activityId) { public ResultResponse<List<LotteryPrizeDTO>> listByActivityId(Long activityId) {
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery() List<LotteryPrize> prizes = lotteryPrizeService.query()
.eq(LotteryPrize::getActivityId, activityId) .eq(LotteryPrize::getActivityId, activityId)
.orderByAsc(LotteryPrize::getSortOrder) .orderByAsc(LotteryPrize::getSortOrder)
.list(); .list();
@ -107,7 +107,7 @@ public class LotteryPrizeManageClientEndpoint implements LotteryPrizeManageClien
* 更新活动总库存内部方法. * 更新活动总库存内部方法.
*/ */
private void updateActivityStockInternal(Long activityId) { private void updateActivityStockInternal(Long activityId) {
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery() List<LotteryPrize> prizes = lotteryPrizeService.query()
.eq(LotteryPrize::getActivityId, activityId) .eq(LotteryPrize::getActivityId, activityId)
.list(); .list();
@ -119,11 +119,11 @@ public class LotteryPrizeManageClientEndpoint implements LotteryPrizeManageClien
.mapToInt(LotteryPrize::getRemainingStock) .mapToInt(LotteryPrize::getRemainingStock)
.sum(); .sum();
lotteryActivityService.lambdaUpdate() lotteryActivityService.update()
.eq(LotteryActivity::getId, activityId) .eq(LotteryActivity::getId, activityId)
.set(LotteryActivity::getTotalStock, totalStock) .set(LotteryActivity::getTotalStock, totalStock)
.set(LotteryActivity::getConsumedStock, totalStock - remainingStock) .set(LotteryActivity::getConsumedStock, totalStock - remainingStock)
.update(); .execute();
} }
} }

View File

@ -6,6 +6,8 @@ import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordSer
import com.red.circle.other.inner.endpoint.activity.api.LotteryRecordClientApi; import com.red.circle.other.inner.endpoint.activity.api.LotteryRecordClientApi;
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO; import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.red.circle.tool.core.date.TimestampUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -29,7 +31,7 @@ public class LotteryRecordClientEndpoint implements LotteryRecordClientApi {
@Override @Override
public ResultResponse<Long> saveRecord(String recordNo, Long userId, Long activityId, public ResultResponse<Long> saveRecord(String recordNo, Long userId, Long activityId,
Long prizeId, String prizeName, Integer prizeType, Long prizeId, String prizeName, String prizeType,
Integer isWin) { Integer isWin) {
LotteryRecord record = new LotteryRecord(); LotteryRecord record = new LotteryRecord();
record.setRecordNo(recordNo); record.setRecordNo(recordNo);
@ -39,7 +41,7 @@ public class LotteryRecordClientEndpoint implements LotteryRecordClientApi {
record.setPrizeName(prizeName); record.setPrizeName(prizeName);
record.setPrizeType(prizeType); record.setPrizeType(prizeType);
record.setIsWin(isWin); record.setIsWin(isWin);
record.setDrawTime(LocalDateTime.now()); record.setDrawTime(TimestampUtils.now());
record.setPrizeStatus(isWin == 1 ? 0 : null); record.setPrizeStatus(isWin == 1 ? 0 : null);
lotteryRecordService.save(record); lotteryRecordService.save(record);
@ -49,9 +51,9 @@ public class LotteryRecordClientEndpoint implements LotteryRecordClientApi {
@Override @Override
public ResultResponse<LotteryRecordDTO> getByRecordNo(String recordNo) { public ResultResponse<LotteryRecordDTO> getByRecordNo(String recordNo) {
LotteryRecord record = lotteryRecordService.lambdaQuery() LotteryRecord record = lotteryRecordService.query()
.eq(LotteryRecord::getRecordNo, recordNo) .eq(LotteryRecord::getRecordNo, recordNo)
.one(); .getOne();
if (record == null) { if (record == null) {
return ResultResponse.success(null); return ResultResponse.success(null);

View File

@ -1,5 +1,6 @@
package com.red.circle.other.app.inner.endpoint.activity; package com.red.circle.other.app.inner.endpoint.activity;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.PageResult; import com.red.circle.framework.dto.PageResult;
@ -13,10 +14,14 @@ import com.red.circle.other.inner.endpoint.activity.api.LotteryRecordManageClien
import com.red.circle.other.inner.model.cmd.activity.LotteryRecordQryCmd; import com.red.circle.other.inner.model.cmd.activity.LotteryRecordQryCmd;
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO; import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO; import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
import java.sql.Timestamp;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.red.circle.tool.core.date.TimestampUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -46,7 +51,7 @@ public class LotteryRecordManageClientEndpoint implements LotteryRecordManageCli
Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20; Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20;
Page<LotteryRecord> page = new Page<>(pageNo, pageSize); Page<LotteryRecord> page = new Page<>(pageNo, pageSize);
var query = lotteryRecordService.lambdaQuery(); var query = lotteryRecordService.query();
if (cmd.getUserId() != null) { if (cmd.getUserId() != null) {
query.eq(LotteryRecord::getUserId, cmd.getUserId()); query.eq(LotteryRecord::getUserId, cmd.getUserId());
@ -55,9 +60,9 @@ public class LotteryRecordManageClientEndpoint implements LotteryRecordManageCli
query.eq(LotteryRecord::getActivityId, cmd.getActivityId()); query.eq(LotteryRecord::getActivityId, cmd.getActivityId());
} }
if (cmd.getActivityCode() != null) { if (cmd.getActivityCode() != null) {
LotteryActivity activity = lotteryActivityService.lambdaQuery() LotteryActivity activity = lotteryActivityService.query()
.eq(LotteryActivity::getActivityCode, cmd.getActivityCode()) .eq(LotteryActivity::getActivityCode, cmd.getActivityCode())
.one(); .getOne();
if (activity != null) { if (activity != null) {
query.eq(LotteryRecord::getActivityId, activity.getId()); query.eq(LotteryRecord::getActivityId, activity.getId());
} }
@ -75,7 +80,7 @@ public class LotteryRecordManageClientEndpoint implements LotteryRecordManageCli
query.le(LotteryRecord::getDrawTime, cmd.getDrawTimeEnd()); query.le(LotteryRecord::getDrawTime, cmd.getDrawTimeEnd());
} }
Page<LotteryRecord> result = query.orderByDesc(LotteryRecord::getDrawTime).page(page); IPage<LotteryRecord> result = query.orderByDesc(LotteryRecord::getDrawTime).page(page);
// 查询活动信息 // 查询活动信息
List<Long> activityIds = result.getRecords().stream() List<Long> activityIds = result.getRecords().stream()
@ -83,7 +88,11 @@ public class LotteryRecordManageClientEndpoint implements LotteryRecordManageCli
.distinct() .distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<Long, LotteryActivity> activityMap = lotteryActivityService.lambdaQuery() if (activityIds.isEmpty()) {
return ResultResponse.success(PageResult.newPageResult(cmd.getPageSize()));
}
Map<Long, LotteryActivity> activityMap = lotteryActivityService.query()
.in(LotteryActivity::getId, activityIds) .in(LotteryActivity::getId, activityIds)
.list() .list()
.stream() .stream()
@ -126,8 +135,8 @@ public class LotteryRecordManageClientEndpoint implements LotteryRecordManageCli
// 4-积分调用积分服务 // 4-积分调用积分服务
record.setPrizeStatus(1); // 已发放 record.setPrizeStatus(1); // 已发放
record.setDeliverTime(LocalDateTime.now()); record.setDeliverTime(TimestampUtils.now());
lotteryRecordService.updateById(record); lotteryRecordService.updateSelectiveById(record);
return ResultResponse.success(); return ResultResponse.success();
} }

View File

@ -1,5 +1,6 @@
package com.red.circle.other.app.inner.endpoint.activity; package com.red.circle.other.app.inner.endpoint.activity;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.red.circle.framework.dto.ResultResponse; import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord;
@ -31,7 +32,7 @@ public class LotteryTicketClientEndpoint implements LotteryTicketClientApi {
@Override @Override
public ResultResponse<Integer> getUserTicketCount(Long userId) { public ResultResponse<Integer> getUserTicketCount(Long userId) {
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery() List<LotteryTicket> tickets = lotteryTicketService.query()
.eq(LotteryTicket::getUserId, userId) .eq(LotteryTicket::getUserId, userId)
.eq(LotteryTicket::getStatus, 1) .eq(LotteryTicket::getStatus, 1)
.gt(LotteryTicket::getRemainingCount, 0) .gt(LotteryTicket::getRemainingCount, 0)
@ -47,7 +48,7 @@ public class LotteryTicketClientEndpoint implements LotteryTicketClientApi {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResultResponse<Boolean> deductTicket(Long userId, Integer count) { public ResultResponse<Boolean> deductTicket(Long userId, Integer count) {
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery() List<LotteryTicket> tickets = lotteryTicketService.query()
.eq(LotteryTicket::getUserId, userId) .eq(LotteryTicket::getUserId, userId)
.eq(LotteryTicket::getStatus, 1) .eq(LotteryTicket::getStatus, 1)
.gt(LotteryTicket::getRemainingCount, 0) .gt(LotteryTicket::getRemainingCount, 0)
@ -70,11 +71,11 @@ public class LotteryTicketClientEndpoint implements LotteryTicketClientApi {
int deduct = Math.min(remaining, ticket.getRemainingCount()); int deduct = Math.min(remaining, ticket.getRemainingCount());
lotteryTicketService.lambdaUpdate() LambdaUpdateWrapper<LotteryTicket> updateWrapper = new LambdaUpdateWrapper<LotteryTicket>()
.eq(LotteryTicket::getId, ticket.getId()) .eq(LotteryTicket::getId, ticket.getId())
.setSql("used_count = used_count + " + deduct) .setSql("used_count = used_count + " + deduct)
.setSql("remaining_count = remaining_count - " + deduct) .setSql("remaining_count = remaining_count - " + deduct);
.update(); lotteryTicketService.update(updateWrapper);
// 记录使用 // 记录使用
LotteryTicketRecord ticketRecord = new LotteryTicketRecord(); LotteryTicketRecord ticketRecord = new LotteryTicketRecord();

View File

@ -1,12 +1,15 @@
package com.red.circle.other.app.inner.endpoint.activity; package com.red.circle.other.app.inner.endpoint.activity;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.ResultResponse; import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord; import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord;
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketRecordService; import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketRecordService;
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService; import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService;
import com.red.circle.other.inner.asserts.lottery.LotteryErrorCode;
import com.red.circle.other.inner.endpoint.activity.api.LotteryTicketManageClientApi; import com.red.circle.other.inner.endpoint.activity.api.LotteryTicketManageClientApi;
import com.red.circle.other.inner.model.cmd.activity.LotteryTicketGrantCmd; import com.red.circle.other.inner.model.cmd.activity.LotteryTicketGrantCmd;
import java.sql.Timestamp;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -32,9 +35,21 @@ public class LotteryTicketManageClientEndpoint implements LotteryTicketManageCli
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResultResponse<Void> grantTickets(LotteryTicketGrantCmd cmd) { public ResultResponse<Void> grantTickets(LotteryTicketGrantCmd cmd) {
// 校验必填参数
ResponseAssert.isTrue(LotteryErrorCode.USER_ID_REQUIRED,
cmd.getUserIds() != null && !cmd.getUserIds().isEmpty());
ResponseAssert.isTrue(LotteryErrorCode.GRANT_COUNT_INVALID,
cmd.getCount() != null && cmd.getCount() > 0);
// 来源ID必填 - 用于追踪抽奖券的发放来源
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_ID_REQUIRED,
cmd.getSourceId() != null && !cmd.getSourceId().isEmpty());
String ticketSource = cmd.getTicketSource() != null ? cmd.getTicketSource() : "SYSTEM"; String ticketSource = cmd.getTicketSource() != null ? cmd.getTicketSource() : "SYSTEM";
Timestamp now = new Timestamp(System.currentTimeMillis());
for (Long userId : cmd.getUserIds()) { for (Long userId : cmd.getUserIds()) {
// 创建抽奖券记录
LotteryTicket ticket = new LotteryTicket(); LotteryTicket ticket = new LotteryTicket();
ticket.setUserId(userId); ticket.setUserId(userId);
ticket.setTicketSource(ticketSource); ticket.setTicketSource(ticketSource);
@ -43,16 +58,16 @@ public class LotteryTicketManageClientEndpoint implements LotteryTicketManageCli
ticket.setUsedCount(0); ticket.setUsedCount(0);
ticket.setRemainingCount(cmd.getCount()); ticket.setRemainingCount(cmd.getCount());
ticket.setExpireTime(cmd.getExpireTime()); ticket.setExpireTime(cmd.getExpireTime());
ticket.setStatus(1); ticket.setStatus(1); // 正常状态
lotteryTicketService.save(ticket); lotteryTicketService.save(ticket);
// 记录发放 // 记录发放日志
LotteryTicketRecord ticketRecord = new LotteryTicketRecord(); LotteryTicketRecord ticketRecord = new LotteryTicketRecord();
ticketRecord.setUserId(userId); ticketRecord.setUserId(userId);
ticketRecord.setTicketId(ticket.getId()); ticketRecord.setTicketId(ticket.getId());
ticketRecord.setChangeCount(cmd.getCount()); ticketRecord.setChangeCount(cmd.getCount());
ticketRecord.setChangeType(1); // 发放 ticketRecord.setChangeType(1); // 1-发放
ticketRecord.setRemark(cmd.getRemark()); ticketRecord.setRemark(cmd.getRemark() != null ? cmd.getRemark() : "系统发放抽奖券");
lotteryTicketRecordService.save(ticketRecord); lotteryTicketRecordService.save(ticketRecord);
} }

View File

@ -27,11 +27,11 @@ public class LotteryUserCountClientEndpoint implements LotteryUserCountClientApi
@Override @Override
public ResultResponse<Integer> getTodayCount(Long userId, Long activityId) { public ResultResponse<Integer> getTodayCount(Long userId, Long activityId) {
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery() LotteryUserCount userCount = lotteryUserCountService.query()
.eq(LotteryUserCount::getUserId, userId) .eq(LotteryUserCount::getUserId, userId)
.eq(LotteryUserCount::getActivityId, activityId) .eq(LotteryUserCount::getActivityId, activityId)
.eq(LotteryUserCount::getDrawDate, LocalDate.now()) .eq(LotteryUserCount::getDrawDate, LocalDate.now())
.one(); .getOne();
int count = userCount != null ? userCount.getDrawCount() : 0; int count = userCount != null ? userCount.getDrawCount() : 0;
@ -40,11 +40,11 @@ public class LotteryUserCountClientEndpoint implements LotteryUserCountClientApi
@Override @Override
public ResultResponse<Void> incrDrawCount(Long userId, Long activityId) { public ResultResponse<Void> incrDrawCount(Long userId, Long activityId) {
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery() LotteryUserCount userCount = lotteryUserCountService.query()
.eq(LotteryUserCount::getUserId, userId) .eq(LotteryUserCount::getUserId, userId)
.eq(LotteryUserCount::getActivityId, activityId) .eq(LotteryUserCount::getActivityId, activityId)
.eq(LotteryUserCount::getDrawDate, LocalDate.now()) .eq(LotteryUserCount::getDrawDate, LocalDate.now())
.one(); .getOne();
if (userCount == null) { if (userCount == null) {
userCount = new LotteryUserCount(); userCount = new LotteryUserCount();
@ -54,10 +54,10 @@ public class LotteryUserCountClientEndpoint implements LotteryUserCountClientApi
userCount.setDrawCount(1); userCount.setDrawCount(1);
lotteryUserCountService.save(userCount); lotteryUserCountService.save(userCount);
} else { } else {
lotteryUserCountService.lambdaUpdate() lotteryUserCountService.update()
.eq(LotteryUserCount::getId, userCount.getId()) .eq(LotteryUserCount::getId, userCount.getId())
.setSql("draw_count = draw_count + 1") .setSql("draw_count = draw_count + 1")
.update(); .execute();
} }
return ResultResponse.success(); return ResultResponse.success();