新增抽奖功能
This commit is contained in:
parent
4f9295b41a
commit
0ee3f41c1b
125
rc-service/lottery_system_init.sql
Normal file
125
rc-service/lottery_system_init.sql
Normal file
@ -0,0 +1,125 @@
|
||||
# 抽奖系统数据库初始化SQL
|
||||
|
||||
## 1. 抽奖活动表
|
||||
```sql
|
||||
CREATE TABLE lottery_activity (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
activity_code VARCHAR(50) UNIQUE NOT NULL COMMENT '活动编码',
|
||||
activity_name VARCHAR(100) NOT NULL COMMENT '活动名称',
|
||||
activity_desc VARCHAR(500) COMMENT '活动描述',
|
||||
start_time DATETIME NOT NULL COMMENT '开始时间',
|
||||
end_time DATETIME NOT NULL COMMENT '结束时间',
|
||||
status TINYINT DEFAULT 0 COMMENT '状态:0-未开始,1-进行中,2-已结束,3-已关闭',
|
||||
total_stock INT DEFAULT 0 COMMENT '总奖品库存',
|
||||
consumed_stock INT DEFAULT 0 COMMENT '已消耗库存',
|
||||
draw_count_limit INT DEFAULT 0 COMMENT '每人抽奖次数限制(0为不限制)',
|
||||
draw_count_cycle VARCHAR(20) COMMENT '次数限制周期:DAILY-每天,TOTAL-总计',
|
||||
need_ticket TINYINT DEFAULT 0 COMMENT '是否需要抽奖券:0-否,1-是',
|
||||
ticket_cost INT DEFAULT 1 COMMENT '每次消耗抽奖券数量',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_status_time (status, start_time, end_time),
|
||||
INDEX idx_code (activity_code)
|
||||
) COMMENT '抽奖活动表';
|
||||
```
|
||||
|
||||
## 2. 奖品配置表
|
||||
```sql
|
||||
CREATE TABLE lottery_prize (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
activity_id BIGINT NOT NULL COMMENT '活动ID',
|
||||
prize_code VARCHAR(50) NOT NULL COMMENT '奖品编码',
|
||||
prize_name VARCHAR(100) NOT NULL COMMENT '奖品名称',
|
||||
prize_type TINYINT NOT NULL COMMENT '奖品类型:1-实物,2-虚拟币,3-优惠券,4-积分,5-谢谢参与',
|
||||
prize_value DECIMAL(10,2) COMMENT '奖品价值/数量',
|
||||
prize_image VARCHAR(200) COMMENT '奖品图片',
|
||||
prize_level TINYINT COMMENT '奖品等级:1-特等奖,2-一等奖,3-二等奖...',
|
||||
total_stock INT NOT NULL COMMENT '总库存',
|
||||
remaining_stock INT NOT NULL COMMENT '剩余库存',
|
||||
daily_stock INT DEFAULT 0 COMMENT '每日库存限制(0为不限制)',
|
||||
probability DECIMAL(10,6) NOT NULL COMMENT '中奖概率(0-1之间)',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序(九宫格位置)',
|
||||
is_display TINYINT DEFAULT 1 COMMENT '是否展示:0-否,1-是',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_activity (activity_id),
|
||||
INDEX idx_code (prize_code),
|
||||
UNIQUE KEY uk_activity_code (activity_id, prize_code)
|
||||
) COMMENT '奖品配置表';
|
||||
```
|
||||
|
||||
## 3. 中奖记录表
|
||||
```sql
|
||||
CREATE TABLE lottery_record (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
record_no VARCHAR(50) UNIQUE NOT NULL COMMENT '记录编号',
|
||||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||||
activity_id BIGINT NOT NULL COMMENT '活动ID',
|
||||
prize_id BIGINT COMMENT '奖品ID(未中奖为NULL)',
|
||||
prize_name VARCHAR(100) COMMENT '奖品名称快照',
|
||||
prize_type TINYINT COMMENT '奖品类型快照',
|
||||
is_win TINYINT NOT NULL COMMENT '是否中奖:0-未中奖,1-中奖',
|
||||
draw_time DATETIME NOT NULL COMMENT '抽奖时间',
|
||||
prize_status TINYINT DEFAULT 0 COMMENT '奖品状态:0-待发放,1-已发放,2-发放失败',
|
||||
deliver_time DATETIME COMMENT '发放时间',
|
||||
remark VARCHAR(500) COMMENT '备注',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_user_activity (user_id, activity_id),
|
||||
INDEX idx_draw_time (draw_time),
|
||||
INDEX idx_activity_win (activity_id, is_win),
|
||||
INDEX idx_record_no (record_no)
|
||||
) COMMENT '中奖记录表';
|
||||
```
|
||||
|
||||
## 4. 抽奖券表
|
||||
```sql
|
||||
CREATE TABLE lottery_ticket (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||||
ticket_source VARCHAR(50) COMMENT '来源:SYSTEM-系统发放,ACTIVITY-活动赠送,PURCHASE-购买',
|
||||
source_id VARCHAR(50) COMMENT '来源ID',
|
||||
total_count INT NOT NULL COMMENT '总数量',
|
||||
used_count INT DEFAULT 0 COMMENT '已使用数量',
|
||||
remaining_count INT NOT NULL COMMENT '剩余数量',
|
||||
expire_time DATETIME COMMENT '过期时间',
|
||||
status TINYINT DEFAULT 1 COMMENT '状态:0-已失效,1-正常',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_user_status (user_id, status),
|
||||
INDEX idx_expire (expire_time)
|
||||
) COMMENT '抽奖券表';
|
||||
```
|
||||
|
||||
## 5. 抽奖券使用记录表
|
||||
```sql
|
||||
CREATE TABLE lottery_ticket_record (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||||
ticket_id BIGINT NOT NULL COMMENT '抽奖券ID',
|
||||
change_count INT NOT NULL COMMENT '变动数量(正数增加,负数减少)',
|
||||
change_type TINYINT NOT NULL COMMENT '变动类型:1-发放,2-消耗,3-过期,4-退回',
|
||||
lottery_record_id BIGINT COMMENT '关联的抽奖记录ID',
|
||||
remark VARCHAR(200) COMMENT '备注',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_user (user_id),
|
||||
INDEX idx_ticket (ticket_id),
|
||||
INDEX idx_lottery_record (lottery_record_id)
|
||||
) COMMENT '抽奖券使用记录表';
|
||||
```
|
||||
|
||||
## 6. 用户抽奖次数统计表
|
||||
```sql
|
||||
CREATE TABLE lottery_user_count (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||||
activity_id BIGINT NOT NULL COMMENT '活动ID',
|
||||
draw_date DATE NOT NULL COMMENT '统计日期',
|
||||
draw_count INT DEFAULT 0 COMMENT '抽奖次数',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_user_activity_date (user_id, activity_id, draw_date),
|
||||
INDEX idx_user_activity (user_id, activity_id)
|
||||
) COMMENT '用户抽奖次数统计表';
|
||||
```
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryActivityClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 抽奖活动Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryActivityClient", url = "${feign.other.url}" +
|
||||
LotteryActivityClientApi.API_PREFIX)
|
||||
public interface LotteryActivityClient extends LotteryActivityClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryActivityManageClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 抽奖活动管理Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryActivityManageClient", url = "${feign.other.url}" +
|
||||
LotteryActivityManageClientApi.API_PREFIX)
|
||||
public interface LotteryActivityManageClient extends LotteryActivityManageClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryActivityQueryClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 活动查询Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryActivityQueryClient", url = "${feign.other.url}" +
|
||||
LotteryActivityQueryClientApi.API_PREFIX)
|
||||
public interface LotteryActivityQueryClient extends LotteryActivityQueryClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryPrizeClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 奖品配置Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryPrizeClient", url = "${feign.other.url}" +
|
||||
LotteryPrizeClientApi.API_PREFIX)
|
||||
public interface LotteryPrizeClient extends LotteryPrizeClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryPrizeManageClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 奖品管理Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryPrizeManageClient", url = "${feign.other.url}" +
|
||||
LotteryPrizeManageClientApi.API_PREFIX)
|
||||
public interface LotteryPrizeManageClient extends LotteryPrizeManageClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryRecordClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 中奖记录Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryRecordClient", url = "${feign.other.url}" +
|
||||
LotteryRecordClientApi.API_PREFIX)
|
||||
public interface LotteryRecordClient extends LotteryRecordClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryRecordManageClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 中奖记录管理Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryRecordManageClient", url = "${feign.other.url}" +
|
||||
LotteryRecordManageClientApi.API_PREFIX)
|
||||
public interface LotteryRecordManageClient extends LotteryRecordManageClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryTicketClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 抽奖券Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryTicketClient", url = "${feign.other.url}" +
|
||||
LotteryTicketClientApi.API_PREFIX)
|
||||
public interface LotteryTicketClient extends LotteryTicketClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryTicketManageClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 抽奖券管理Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryTicketManageClient", url = "${feign.other.url}" +
|
||||
LotteryTicketManageClientApi.API_PREFIX)
|
||||
public interface LotteryTicketManageClient extends LotteryTicketManageClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryUserCountClientApi;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
/**
|
||||
* 用户抽奖次数统计Client.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@FeignClient(name = "lotteryUserCountClient", url = "${feign.other.url}" +
|
||||
LotteryUserCountClientApi.API_PREFIX)
|
||||
public interface LotteryUserCountClient extends LotteryUserCountClientApi {
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 抽奖活动Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryActivityClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-activity/client";
|
||||
|
||||
/**
|
||||
* 根据活动编码获取活动信息.
|
||||
*/
|
||||
@GetMapping("/getByCode")
|
||||
ResultResponse<LotteryActivityDTO> getByActivityCode(@RequestParam("activityCode") String activityCode);
|
||||
|
||||
/**
|
||||
* 根据活动ID获取活动信息.
|
||||
*/
|
||||
@GetMapping("/getById")
|
||||
ResultResponse<LotteryActivityDTO> getById(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 获取活动列表.
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
ResultResponse<List<LotteryActivityDTO>> listActivities();
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivitySaveCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 抽奖活动管理Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryActivityManageClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-activity-manage/client";
|
||||
|
||||
/**
|
||||
* 创建活动.
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
ResultResponse<Void> createActivity(@RequestBody LotteryActivitySaveCmd cmd);
|
||||
|
||||
/**
|
||||
* 更新活动.
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
ResultResponse<Void> updateActivity(@RequestBody LotteryActivitySaveCmd cmd);
|
||||
|
||||
/**
|
||||
* 更新活动状态.
|
||||
*/
|
||||
@PutMapping("/updateStatus")
|
||||
ResultResponse<Void> updateActivityStatus(
|
||||
@RequestParam("id") Long id,
|
||||
@RequestParam("status") Integer status
|
||||
);
|
||||
|
||||
/**
|
||||
* 根据ID获取活动.
|
||||
*/
|
||||
@GetMapping("/getById")
|
||||
ResultResponse<LotteryActivityDTO> getById(@RequestParam("id") Long id);
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivityQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
/**
|
||||
* 活动查询Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryActivityQueryClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-activity-query/client";
|
||||
|
||||
/**
|
||||
* 分页查询活动列表.
|
||||
*/
|
||||
@GetMapping("/listActivities")
|
||||
ResultResponse<PageResult<LotteryActivityDTO>> listActivities(@RequestBody LotteryActivityQryCmd cmd);
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 奖品配置Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryPrizeClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-prize/client";
|
||||
|
||||
/**
|
||||
* 根据活动ID获取奖品列表.
|
||||
*/
|
||||
@GetMapping("/listByActivityId")
|
||||
ResultResponse<List<LotteryPrizeDTO>> listByActivityId(@RequestParam("activityId") Long activityId);
|
||||
|
||||
/**
|
||||
* 根据奖品ID获取奖品信息.
|
||||
*/
|
||||
@GetMapping("/getById")
|
||||
ResultResponse<LotteryPrizeDTO> getById(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 扣减奖品库存.
|
||||
*/
|
||||
@GetMapping("/deductStock")
|
||||
ResultResponse<Boolean> deductStock(@RequestParam("id") Long id, @RequestParam("count") Integer count);
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryPrizeSaveCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
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.RequestParam;
|
||||
|
||||
/**
|
||||
* 奖品管理Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryPrizeManageClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-prize-manage/client";
|
||||
|
||||
/**
|
||||
* 保存奖品(新增或更新).
|
||||
*/
|
||||
@PostMapping("/save")
|
||||
ResultResponse<Void> savePrize(@RequestBody LotteryPrizeSaveCmd cmd);
|
||||
|
||||
/**
|
||||
* 根据活动ID获取奖品列表.
|
||||
*/
|
||||
@GetMapping("/listByActivityId")
|
||||
ResultResponse<List<LotteryPrizeDTO>> listByActivityId(@RequestParam("activityId") Long activityId);
|
||||
|
||||
/**
|
||||
* 删除奖品.
|
||||
*/
|
||||
@DeleteMapping("/delete")
|
||||
ResultResponse<Void> deletePrize(@RequestParam("id") Long id);
|
||||
|
||||
/**
|
||||
* 更新活动总库存.
|
||||
*/
|
||||
@PostMapping("/updateActivityStock")
|
||||
ResultResponse<Void> updateActivityStock(@RequestParam("activityId") Long activityId);
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 中奖记录Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryRecordClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-record/client";
|
||||
|
||||
/**
|
||||
* 保存中奖记录.
|
||||
*/
|
||||
@PostMapping("/save")
|
||||
ResultResponse<Long> saveRecord(
|
||||
@RequestParam("recordNo") String recordNo,
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("activityId") Long activityId,
|
||||
@RequestParam(value = "prizeId", required = false) Long prizeId,
|
||||
@RequestParam(value = "prizeName", required = false) String prizeName,
|
||||
@RequestParam(value = "prizeType", required = false) Integer prizeType,
|
||||
@RequestParam("isWin") Integer isWin
|
||||
);
|
||||
|
||||
/**
|
||||
* 根据记录编号获取记录.
|
||||
*/
|
||||
@GetMapping("/getByRecordNo")
|
||||
ResultResponse<LotteryRecordDTO> getByRecordNo(@RequestParam("recordNo") String recordNo);
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryRecordQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
|
||||
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.RequestParam;
|
||||
|
||||
/**
|
||||
* 中奖记录管理Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryRecordManageClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-record-manage/client";
|
||||
|
||||
/**
|
||||
* 分页查询中奖记录.
|
||||
*/
|
||||
@GetMapping("/listRecords")
|
||||
ResultResponse<PageResult<LotteryRecordDTO>> listRecords(@RequestBody LotteryRecordQryCmd cmd);
|
||||
|
||||
/**
|
||||
* 发放奖品.
|
||||
*/
|
||||
@PostMapping("/deliverPrize")
|
||||
ResultResponse<Void> deliverPrize(@RequestParam("recordId") Long recordId);
|
||||
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 抽奖券Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryTicketClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-ticket/client";
|
||||
|
||||
/**
|
||||
* 获取用户抽奖券总数.
|
||||
*/
|
||||
@GetMapping("/getUserTicketCount")
|
||||
ResultResponse<Integer> getUserTicketCount(@RequestParam("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 扣减用户抽奖券.
|
||||
*/
|
||||
@PostMapping("/deductTicket")
|
||||
ResultResponse<Boolean> deductTicket(
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("count") Integer count
|
||||
);
|
||||
|
||||
/**
|
||||
* 增加用户抽奖券.
|
||||
*/
|
||||
@PostMapping("/addTicket")
|
||||
ResultResponse<Boolean> addTicket(
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("count") Integer count,
|
||||
@RequestParam(value = "source", required = false) String source,
|
||||
@RequestParam(value = "sourceId", required = false) String sourceId
|
||||
);
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryTicketGrantCmd;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
/**
|
||||
* 抽奖券管理Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryTicketManageClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-ticket-manage/client";
|
||||
|
||||
/**
|
||||
* 批量发放抽奖券.
|
||||
*/
|
||||
@PostMapping("/grantTickets")
|
||||
ResultResponse<Void> grantTickets(@RequestBody LotteryTicketGrantCmd cmd);
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 用户抽奖次数统计Client API.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryUserCountClientApi {
|
||||
|
||||
String API_PREFIX = "/lottery-user-count/client";
|
||||
|
||||
/**
|
||||
* 获取用户今日抽奖次数.
|
||||
*/
|
||||
@GetMapping("/getTodayCount")
|
||||
ResultResponse<Integer> getTodayCount(
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("activityId") Long activityId
|
||||
);
|
||||
|
||||
/**
|
||||
* 增加用户抽奖次数.
|
||||
*/
|
||||
@GetMapping("/incrDrawCount")
|
||||
ResultResponse<Void> incrDrawCount(
|
||||
@RequestParam("userId") Long userId,
|
||||
@RequestParam("activityId") Long activityId
|
||||
);
|
||||
|
||||
}
|
||||
@ -0,0 +1,185 @@
|
||||
package com.red.circle.other.inner.asserts.lottery;
|
||||
|
||||
import com.red.circle.framework.dto.IResponseErrorCode;
|
||||
import com.red.circle.framework.dto.ResErrorCode;
|
||||
|
||||
/**
|
||||
* 抽奖活动错误码: 9700 ~ 9900
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@ResErrorCode(describe = "抽奖活动Code", minCode = 9700, maxCode = 9900)
|
||||
public enum LotteryErrorCode implements IResponseErrorCode {
|
||||
|
||||
/**
|
||||
* 活动不存在.
|
||||
*/
|
||||
ACTIVITY_NOT_FOUND(9701, "Activity does not exist"),
|
||||
|
||||
/**
|
||||
* 活动编码已存在.
|
||||
*/
|
||||
ACTIVITY_CODE_EXISTS(9702, "Activity code already exists"),
|
||||
|
||||
/**
|
||||
* 活动未开始.
|
||||
*/
|
||||
ACTIVITY_NOT_STARTED(9703, "Activity has not started yet"),
|
||||
|
||||
/**
|
||||
* 活动已结束.
|
||||
*/
|
||||
ACTIVITY_ENDED(9704, "Activity has ended"),
|
||||
|
||||
/**
|
||||
* 活动已关闭.
|
||||
*/
|
||||
ACTIVITY_CLOSED(9705, "Activity is closed"),
|
||||
|
||||
/**
|
||||
* 不在活动时间内.
|
||||
*/
|
||||
NOT_IN_ACTIVITY_TIME(9706, "Not within the activity time"),
|
||||
|
||||
/**
|
||||
* 今日抽奖次数已用完.
|
||||
*/
|
||||
DRAW_COUNT_EXHAUSTED(9707, "Today's lottery draw limit has been reached"),
|
||||
|
||||
/**
|
||||
* 抽奖券不足.
|
||||
*/
|
||||
INSUFFICIENT_TICKETS(9708, "Insufficient lottery tickets"),
|
||||
|
||||
/**
|
||||
* 奖品不存在.
|
||||
*/
|
||||
PRIZE_NOT_FOUND(9709, "Prize does not exist"),
|
||||
|
||||
/**
|
||||
* 奖品库存不足.
|
||||
*/
|
||||
PRIZE_STOCK_INSUFFICIENT(9710, "Prize stock is insufficient"),
|
||||
|
||||
/**
|
||||
* 中奖记录不存在.
|
||||
*/
|
||||
RECORD_NOT_FOUND(9711, "Lottery record does not exist"),
|
||||
|
||||
/**
|
||||
* 未中奖.
|
||||
*/
|
||||
NOT_WIN(9712, "Did not win a prize"),
|
||||
|
||||
/**
|
||||
* 奖品已发放.
|
||||
*/
|
||||
PRIZE_ALREADY_DELIVERED(9713, "Prize has already been delivered"),
|
||||
|
||||
/**
|
||||
* 奖品发放失败.
|
||||
*/
|
||||
PRIZE_DELIVERY_FAILED(9714, "Prize delivery failed"),
|
||||
|
||||
/**
|
||||
* 抽奖券已失效.
|
||||
*/
|
||||
TICKET_EXPIRED(9715, "Lottery ticket has expired"),
|
||||
|
||||
/**
|
||||
* 抽奖券状态异常.
|
||||
*/
|
||||
TICKET_STATUS_ABNORMAL(9716, "Lottery ticket status is abnormal"),
|
||||
|
||||
/**
|
||||
* 用户抽奖券不足.
|
||||
*/
|
||||
USER_TICKET_INSUFFICIENT(9717, "User has insufficient lottery tickets"),
|
||||
|
||||
/**
|
||||
* 活动总库存不足.
|
||||
*/
|
||||
ACTIVITY_STOCK_INSUFFICIENT(9718, "Activity total stock is insufficient"),
|
||||
|
||||
/**
|
||||
* 奖品概率配置错误.
|
||||
*/
|
||||
PRIZE_PROBABILITY_ERROR(9719, "Prize probability configuration error"),
|
||||
|
||||
/**
|
||||
* 活动状态不允许修改.
|
||||
*/
|
||||
ACTIVITY_STATUS_NOT_ALLOW_UPDATE(9720, "Activity status does not allow updates"),
|
||||
|
||||
/**
|
||||
* 活动ID不能为空.
|
||||
*/
|
||||
ACTIVITY_ID_REQUIRED(9721, "Activity ID is required"),
|
||||
|
||||
/**
|
||||
* 奖品ID不能为空.
|
||||
*/
|
||||
PRIZE_ID_REQUIRED(9722, "Prize ID is required"),
|
||||
|
||||
/**
|
||||
* 记录编号不能为空.
|
||||
*/
|
||||
RECORD_NO_REQUIRED(9723, "Record number is required"),
|
||||
|
||||
/**
|
||||
* 用户ID不能为空.
|
||||
*/
|
||||
USER_ID_REQUIRED(9724, "User ID is required"),
|
||||
|
||||
/**
|
||||
* 发放数量必须大于0.
|
||||
*/
|
||||
GRANT_COUNT_INVALID(9725, "Grant count must be greater than 0"),
|
||||
|
||||
/**
|
||||
* 抽奖失败,请稍后重试.
|
||||
*/
|
||||
DRAW_FAILED(9726, "Lottery draw failed, please try again later"),
|
||||
|
||||
/**
|
||||
* 无可用奖品.
|
||||
*/
|
||||
NO_AVAILABLE_PRIZE(9727, "No available prize"),
|
||||
|
||||
/**
|
||||
* 奖品扣减库存失败.
|
||||
*/
|
||||
PRIZE_DEDUCT_STOCK_FAILED(9728, "Failed to deduct prize stock"),
|
||||
|
||||
/**
|
||||
* 用户抽奖次数更新失败.
|
||||
*/
|
||||
USER_DRAW_COUNT_UPDATE_FAILED(9729, "Failed to update user draw count"),
|
||||
|
||||
;
|
||||
|
||||
private final Integer code;
|
||||
private final String message;
|
||||
|
||||
LotteryErrorCode(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorCodeName() {
|
||||
return this.name();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.red.circle.other.inner.model.cmd.activity;
|
||||
|
||||
import com.red.circle.framework.dto.Command;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 抽奖活动查询命令.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LotteryActivityQryCmd extends Command {
|
||||
|
||||
/**
|
||||
* 活动名称.
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*/
|
||||
private String activityCode;
|
||||
|
||||
/**
|
||||
* 状态.
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 开始时间-起.
|
||||
*/
|
||||
private LocalDateTime startTimeBegin;
|
||||
|
||||
/**
|
||||
* 开始时间-止.
|
||||
*/
|
||||
private LocalDateTime startTimeEnd;
|
||||
|
||||
/**
|
||||
* 页码.
|
||||
*/
|
||||
private Integer pageNo;
|
||||
|
||||
/**
|
||||
* 页大小.
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
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.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 创建/更新活动命令.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LotteryActivitySaveCmd extends Command {
|
||||
|
||||
/**
|
||||
* 活动ID(更新时需要).
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*/
|
||||
@NotBlank(message = "活动编码不能为空")
|
||||
private String activityCode;
|
||||
|
||||
/**
|
||||
* 活动名称.
|
||||
*/
|
||||
@NotBlank(message = "活动名称不能为空")
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 活动描述.
|
||||
*/
|
||||
private String activityDesc;
|
||||
|
||||
/**
|
||||
* 开始时间.
|
||||
*/
|
||||
@NotNull(message = "开始时间不能为空")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 结束时间.
|
||||
*/
|
||||
@NotNull(message = "结束时间不能为空")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 抽奖次数限制.
|
||||
*/
|
||||
private Integer drawCountLimit;
|
||||
|
||||
/**
|
||||
* 次数限制周期.
|
||||
*/
|
||||
private String drawCountCycle;
|
||||
|
||||
/**
|
||||
* 是否需要抽奖券.
|
||||
*/
|
||||
private Integer needTicket;
|
||||
|
||||
/**
|
||||
* 每次消耗抽奖券数量.
|
||||
*/
|
||||
private Integer ticketCost;
|
||||
|
||||
/**
|
||||
* 排序.
|
||||
*/
|
||||
private Integer sortOrder;
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
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.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 奖品配置命令.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LotteryPrizeSaveCmd extends Command {
|
||||
|
||||
/**
|
||||
* 奖品ID(更新时需要).
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
@NotNull(message = "活动ID不能为空")
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 奖品编码.
|
||||
*/
|
||||
@NotBlank(message = "奖品编码不能为空")
|
||||
private String prizeCode;
|
||||
|
||||
/**
|
||||
* 奖品名称.
|
||||
*/
|
||||
@NotBlank(message = "奖品名称不能为空")
|
||||
private String prizeName;
|
||||
|
||||
/**
|
||||
* 奖品类型.
|
||||
*/
|
||||
@NotNull(message = "奖品类型不能为空")
|
||||
private Integer prizeType;
|
||||
|
||||
/**
|
||||
* 奖品价值.
|
||||
*/
|
||||
private BigDecimal prizeValue;
|
||||
|
||||
/**
|
||||
* 奖品图片.
|
||||
*/
|
||||
private String prizeImage;
|
||||
|
||||
/**
|
||||
* 奖品等级.
|
||||
*/
|
||||
private Integer prizeLevel;
|
||||
|
||||
/**
|
||||
* 总库存.
|
||||
*/
|
||||
@NotNull(message = "总库存不能为空")
|
||||
private Integer totalStock;
|
||||
|
||||
/**
|
||||
* 每日库存限制.
|
||||
*/
|
||||
private Integer dailyStock;
|
||||
|
||||
/**
|
||||
* 中奖概率.
|
||||
*/
|
||||
@NotNull(message = "中奖概率不能为空")
|
||||
private BigDecimal probability;
|
||||
|
||||
/**
|
||||
* 排序.
|
||||
*/
|
||||
private Integer sortOrder;
|
||||
|
||||
/**
|
||||
* 是否展示.
|
||||
*/
|
||||
private Integer isDisplay;
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.red.circle.other.inner.model.cmd.activity;
|
||||
|
||||
import com.red.circle.framework.dto.Command;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 中奖记录查询命令.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LotteryRecordQryCmd extends Command {
|
||||
|
||||
/**
|
||||
* 用户ID.
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*/
|
||||
private String activityCode;
|
||||
|
||||
/**
|
||||
* 是否中奖.
|
||||
*/
|
||||
private Integer isWin;
|
||||
|
||||
/**
|
||||
* 奖品状态.
|
||||
*/
|
||||
private Integer prizeStatus;
|
||||
|
||||
/**
|
||||
* 抽奖时间-起.
|
||||
*/
|
||||
private LocalDateTime drawTimeBegin;
|
||||
|
||||
/**
|
||||
* 抽奖时间-止.
|
||||
*/
|
||||
private LocalDateTime drawTimeEnd;
|
||||
|
||||
/**
|
||||
* 页码.
|
||||
*/
|
||||
private Integer pageNo;
|
||||
|
||||
/**
|
||||
* 页大小.
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.red.circle.other.inner.model.cmd.activity;
|
||||
|
||||
import com.red.circle.framework.dto.Command;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 发放抽奖券命令.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LotteryTicketGrantCmd extends Command {
|
||||
|
||||
/**
|
||||
* 用户ID列表.
|
||||
*/
|
||||
@NotNull(message = "用户ID列表不能为空")
|
||||
private java.util.List<Long> userIds;
|
||||
|
||||
/**
|
||||
* 发放数量.
|
||||
*/
|
||||
@NotNull(message = "发放数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
/**
|
||||
* 来源.
|
||||
*/
|
||||
private String ticketSource;
|
||||
|
||||
/**
|
||||
* 来源ID.
|
||||
*/
|
||||
private String sourceId;
|
||||
|
||||
/**
|
||||
* 过期时间.
|
||||
*/
|
||||
private LocalDateTime expireTime;
|
||||
|
||||
/**
|
||||
* 备注.
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
package com.red.circle.other.inner.model.dto.activity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 抽奖活动DTO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
public class LotteryActivityDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*/
|
||||
private String activityCode;
|
||||
|
||||
/**
|
||||
* 活动名称.
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 活动描述.
|
||||
*/
|
||||
private String activityDesc;
|
||||
|
||||
/**
|
||||
* 开始时间.
|
||||
*/
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 结束时间.
|
||||
*/
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 状态.
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 总库存.
|
||||
*/
|
||||
private Integer totalStock;
|
||||
|
||||
/**
|
||||
* 已消耗库存.
|
||||
*/
|
||||
private Integer consumedStock;
|
||||
|
||||
/**
|
||||
* 抽奖次数限制.
|
||||
*/
|
||||
private Integer drawCountLimit;
|
||||
|
||||
/**
|
||||
* 次数限制周期.
|
||||
*/
|
||||
private String drawCountCycle;
|
||||
|
||||
/**
|
||||
* 是否需要抽奖券.
|
||||
*/
|
||||
private Integer needTicket;
|
||||
|
||||
/**
|
||||
* 每次消耗抽奖券数量.
|
||||
*/
|
||||
private Integer ticketCost;
|
||||
|
||||
/**
|
||||
* 排序.
|
||||
*/
|
||||
private Integer sortOrder;
|
||||
|
||||
/**
|
||||
* 创建时间.
|
||||
*/
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间.
|
||||
*/
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
package com.red.circle.other.inner.model.dto.activity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 奖品配置DTO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
public class LotteryPrizeDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 奖品ID.
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 奖品编码.
|
||||
*/
|
||||
private String prizeCode;
|
||||
|
||||
/**
|
||||
* 奖品名称.
|
||||
*/
|
||||
private String prizeName;
|
||||
|
||||
/**
|
||||
* 奖品类型.
|
||||
*/
|
||||
private Integer prizeType;
|
||||
|
||||
/**
|
||||
* 奖品价值.
|
||||
*/
|
||||
private BigDecimal prizeValue;
|
||||
|
||||
/**
|
||||
* 奖品图片.
|
||||
*/
|
||||
private String prizeImage;
|
||||
|
||||
/**
|
||||
* 奖品等级.
|
||||
*/
|
||||
private Integer prizeLevel;
|
||||
|
||||
/**
|
||||
* 总库存.
|
||||
*/
|
||||
private Integer totalStock;
|
||||
|
||||
/**
|
||||
* 剩余库存.
|
||||
*/
|
||||
private Integer remainingStock;
|
||||
|
||||
/**
|
||||
* 每日库存限制.
|
||||
*/
|
||||
private Integer dailyStock;
|
||||
|
||||
/**
|
||||
* 中奖概率.
|
||||
*/
|
||||
private BigDecimal probability;
|
||||
|
||||
/**
|
||||
* 排序.
|
||||
*/
|
||||
private Integer sortOrder;
|
||||
|
||||
/**
|
||||
* 是否展示.
|
||||
*/
|
||||
private Integer isDisplay;
|
||||
|
||||
/**
|
||||
* 创建时间.
|
||||
*/
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间.
|
||||
*/
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.red.circle.other.inner.model.dto.activity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 中奖记录DTO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
public class LotteryRecordDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录ID.
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 记录编号.
|
||||
*/
|
||||
private String recordNo;
|
||||
|
||||
/**
|
||||
* 用户ID.
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 活动名称.
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 奖品ID.
|
||||
*/
|
||||
private Long prizeId;
|
||||
|
||||
/**
|
||||
* 奖品名称.
|
||||
*/
|
||||
private String prizeName;
|
||||
|
||||
/**
|
||||
* 奖品类型.
|
||||
*/
|
||||
private Integer prizeType;
|
||||
|
||||
/**
|
||||
* 是否中奖.
|
||||
*/
|
||||
private Integer isWin;
|
||||
|
||||
/**
|
||||
* 抽奖时间.
|
||||
*/
|
||||
private LocalDateTime drawTime;
|
||||
|
||||
/**
|
||||
* 奖品状态.
|
||||
*/
|
||||
private Integer prizeStatus;
|
||||
|
||||
/**
|
||||
* 发放时间.
|
||||
*/
|
||||
private LocalDateTime deliverTime;
|
||||
|
||||
/**
|
||||
* 备注.
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建时间.
|
||||
*/
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
package com.red.circle.console.adapter.app.activity;
|
||||
|
||||
import com.red.circle.console.app.service.app.activity.LotteryActivityBackService;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivityQryCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivitySaveCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryPrizeSaveCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryRecordQryCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryTicketGrantCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 抽奖活动管理.
|
||||
*
|
||||
* @author system on 2025-10-18
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/activity/lottery")
|
||||
public class LotteryActivityBackRestController extends BaseController {
|
||||
|
||||
private final LotteryActivityBackService lotteryActivityBackService;
|
||||
|
||||
/**
|
||||
* 创建活动.
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public void createActivity(@RequestBody @Validated LotteryActivitySaveCmd cmd) {
|
||||
lotteryActivityBackService.createActivity(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新活动.
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
public void updateActivity(@RequestBody @Validated LotteryActivitySaveCmd cmd) {
|
||||
lotteryActivityBackService.updateActivity(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动列表.
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public PageResult<LotteryActivityDTO> listActivities(LotteryActivityQryCmd cmd) {
|
||||
return lotteryActivityBackService.listActivities(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动详情.
|
||||
*/
|
||||
@GetMapping("/detail/{id}")
|
||||
public LotteryActivityDTO getActivity(@PathVariable Long id) {
|
||||
return lotteryActivityBackService.getActivity(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新活动状态.
|
||||
*/
|
||||
@PutMapping("/status/{id}")
|
||||
public void updateActivityStatus(@PathVariable Long id, @RequestParam Integer status) {
|
||||
lotteryActivityBackService.updateActivityStatus(id, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置奖品.
|
||||
*/
|
||||
@PostMapping("/prize/save")
|
||||
public void savePrize(@RequestBody @Validated LotteryPrizeSaveCmd cmd) {
|
||||
lotteryActivityBackService.savePrize(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 奖品列表.
|
||||
*/
|
||||
@GetMapping("/prize/list/{activityId}")
|
||||
public List<LotteryPrizeDTO> listPrizes(@PathVariable Long activityId) {
|
||||
return lotteryActivityBackService.listPrizes(activityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除奖品.
|
||||
*/
|
||||
@DeleteMapping("/prize/delete/{id}")
|
||||
public void deletePrize(@PathVariable Long id) {
|
||||
lotteryActivityBackService.deletePrize(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 中奖记录列表.
|
||||
*/
|
||||
@GetMapping("/record/list")
|
||||
public PageResult<LotteryRecordDTO> listRecords(LotteryRecordQryCmd cmd) {
|
||||
return lotteryActivityBackService.listRecords(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发放奖品.
|
||||
*/
|
||||
@PostMapping("/record/deliver/{recordId}")
|
||||
public void deliverPrize(@PathVariable Long recordId) {
|
||||
lotteryActivityBackService.deliverPrize(recordId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量发放抽奖券.
|
||||
*/
|
||||
@PostMapping("/ticket/grant")
|
||||
public void grantTickets(@RequestBody @Validated LotteryTicketGrantCmd cmd) {
|
||||
lotteryActivityBackService.grantTickets(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
package com.red.circle.console.app.service.app.activity;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
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.LotteryPrizeManageClient;
|
||||
import com.red.circle.other.inner.endpoint.activity.LotteryRecordManageClient;
|
||||
import com.red.circle.other.inner.endpoint.activity.LotteryTicketManageClient;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivityQryCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivitySaveCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryPrizeSaveCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryRecordQryCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryTicketGrantCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 抽奖活动管理服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityBackServiceImpl implements LotteryActivityBackService {
|
||||
|
||||
private final LotteryActivityManageClient lotteryActivityManageClient;
|
||||
private final LotteryActivityQueryClient lotteryActivityQueryClient;
|
||||
private final LotteryPrizeManageClient lotteryPrizeManageClient;
|
||||
private final LotteryRecordManageClient lotteryRecordManageClient;
|
||||
private final LotteryTicketManageClient lotteryTicketManageClient;
|
||||
|
||||
@Override
|
||||
public void createActivity(LotteryActivitySaveCmd cmd) {
|
||||
lotteryActivityManageClient.createActivity(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateActivity(LotteryActivitySaveCmd cmd) {
|
||||
lotteryActivityManageClient.updateActivity(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<LotteryActivityDTO> listActivities(LotteryActivityQryCmd cmd) {
|
||||
return lotteryActivityQueryClient.listActivities(cmd).getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LotteryActivityDTO getActivity(Long id) {
|
||||
return lotteryActivityManageClient.getById(id).getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateActivityStatus(Long id, Integer status) {
|
||||
lotteryActivityManageClient.updateActivityStatus(id, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePrize(LotteryPrizeSaveCmd cmd) {
|
||||
lotteryPrizeManageClient.savePrize(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LotteryPrizeDTO> listPrizes(Long activityId) {
|
||||
return lotteryPrizeManageClient.listByActivityId(activityId).getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePrize(Long id) {
|
||||
lotteryPrizeManageClient.deletePrize(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<LotteryRecordDTO> listRecords(LotteryRecordQryCmd cmd) {
|
||||
return lotteryRecordManageClient.listRecords(cmd).getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverPrize(Long recordId) {
|
||||
lotteryRecordManageClient.deliverPrize(recordId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void grantTickets(LotteryTicketGrantCmd cmd) {
|
||||
lotteryTicketManageClient.grantTickets(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
package com.red.circle.console.app.service.app.activity;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivityQryCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivitySaveCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryPrizeSaveCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryRecordQryCmd;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryTicketGrantCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 抽奖活动管理服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryActivityBackService {
|
||||
|
||||
/**
|
||||
* 创建活动.
|
||||
*/
|
||||
void createActivity(LotteryActivitySaveCmd cmd);
|
||||
|
||||
/**
|
||||
* 更新活动.
|
||||
*/
|
||||
void updateActivity(LotteryActivitySaveCmd cmd);
|
||||
|
||||
/**
|
||||
* 活动列表.
|
||||
*/
|
||||
PageResult<LotteryActivityDTO> listActivities(LotteryActivityQryCmd cmd);
|
||||
|
||||
/**
|
||||
* 活动详情.
|
||||
*/
|
||||
LotteryActivityDTO getActivity(Long id);
|
||||
|
||||
/**
|
||||
* 启用/禁用活动.
|
||||
*/
|
||||
void updateActivityStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 配置奖品.
|
||||
*/
|
||||
void savePrize(LotteryPrizeSaveCmd cmd);
|
||||
|
||||
/**
|
||||
* 奖品列表.
|
||||
*/
|
||||
List<LotteryPrizeDTO> listPrizes(Long activityId);
|
||||
|
||||
/**
|
||||
* 删除奖品.
|
||||
*/
|
||||
void deletePrize(Long id);
|
||||
|
||||
/**
|
||||
* 中奖记录列表.
|
||||
*/
|
||||
PageResult<LotteryRecordDTO> listRecords(LotteryRecordQryCmd cmd);
|
||||
|
||||
/**
|
||||
* 发放奖品.
|
||||
*/
|
||||
void deliverPrize(Long recordId);
|
||||
|
||||
/**
|
||||
* 批量发放抽奖券.
|
||||
*/
|
||||
void grantTickets(LotteryTicketGrantCmd cmd);
|
||||
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
package com.red.circle.other.adapter.app.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
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.LotteryDrawResultCO;
|
||||
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.cmd.activity.LotteryDrawCmd;
|
||||
import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
|
||||
import com.red.circle.other.app.service.activity.LotteryActivityService;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 抽奖活动 前端控制器.
|
||||
* </p>
|
||||
*
|
||||
* @author system
|
||||
* @eo.api-type http
|
||||
* @eo.groupName 活动服务.抽奖活动
|
||||
* @eo.path /activity/lottery
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping(value = "/activity/lottery", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityRestController extends BaseController {
|
||||
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
|
||||
/**
|
||||
* 获取有效活动列表.
|
||||
*
|
||||
* @eo.name 获取有效活动列表.
|
||||
* @eo.url /list
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public List<LotteryActivityCO> listValidActivities(AppExtCommand cmd) {
|
||||
return lotteryActivityService.listValidActivities(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活动详情.
|
||||
*
|
||||
* @eo.name 获取活动详情.
|
||||
* @eo.url /detail/{activityCode}
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/detail/{activityCode}")
|
||||
public LotteryActivityDetailCO getActivityDetail(@PathVariable String activityCode, AppExtCommand cmd) {
|
||||
return lotteryActivityService.getActivityDetail(activityCode, cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行抽奖.
|
||||
*
|
||||
* @eo.name 执行抽奖.
|
||||
* @eo.url /draw
|
||||
* @eo.method post
|
||||
* @eo.request-type json
|
||||
*/
|
||||
@PostMapping("/draw")
|
||||
public LotteryDrawResultCO draw(@RequestBody @Validated LotteryDrawCmd cmd) {
|
||||
return lotteryActivityService.draw(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的中奖记录.
|
||||
*
|
||||
* @eo.name 查询我的中奖记录.
|
||||
* @eo.url /my-records
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/my-records")
|
||||
public PageResult<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd) {
|
||||
return lotteryActivityService.listMyRecords(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的抽奖券.
|
||||
*
|
||||
* @eo.name 查询我的抽奖券.
|
||||
* @eo.url /my-tickets
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/my-tickets")
|
||||
public List<LotteryTicketCO> listMyTickets(AppExtCommand cmd) {
|
||||
return lotteryActivityService.listMyTickets(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取抽奖券总数.
|
||||
*
|
||||
* @eo.name 获取抽奖券总数.
|
||||
* @eo.url /ticket-count
|
||||
* @eo.method get
|
||||
* @eo.request-type formdata
|
||||
*/
|
||||
@GetMapping("/ticket-count")
|
||||
public Integer getMyTicketCount(AppExtCommand cmd) {
|
||||
return lotteryActivityService.getMyTicketCount(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
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.LotteryPrizeCO;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
|
||||
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.LotteryPrizeService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 查询活动详情.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityDetailQryExe {
|
||||
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
private final LotteryPrizeService lotteryPrizeService;
|
||||
private final LotteryTicketService lotteryTicketService;
|
||||
private final LotteryUserCountService lotteryUserCountService;
|
||||
|
||||
public LotteryActivityDetailCO execute(String activityCode, AppExtCommand cmd) {
|
||||
Long userId = cmd.requiredReqUserId();
|
||||
|
||||
// 查询活动
|
||||
LotteryActivity activity = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getActivityCode, activityCode)
|
||||
.one();
|
||||
ResponseAssert.isTrue(activity != null, "活动不存在");
|
||||
|
||||
// 查询奖品列表
|
||||
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery()
|
||||
.eq(LotteryPrize::getActivityId, activity.getId())
|
||||
.eq(LotteryPrize::getIsDisplay, 1)
|
||||
.orderByAsc(LotteryPrize::getSortOrder)
|
||||
.list();
|
||||
|
||||
// 查询用户抽奖券数量
|
||||
Integer ticketCount = 0;
|
||||
if (activity.getNeedTicket() == 1) {
|
||||
ticketCount = lotteryTicketService.lambdaQuery()
|
||||
.eq(LotteryTicket::getUserId, userId)
|
||||
.eq(LotteryTicket::getStatus, 1)
|
||||
.gt(LotteryTicket::getRemainingCount, 0)
|
||||
.list()
|
||||
.stream()
|
||||
.mapToInt(LotteryTicket::getRemainingCount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
// 查询用户今日抽奖次数
|
||||
Integer usedCount = 0;
|
||||
if (activity.getDrawCountLimit() != null && activity.getDrawCountLimit() > 0) {
|
||||
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery()
|
||||
.eq(LotteryUserCount::getUserId, userId)
|
||||
.eq(LotteryUserCount::getActivityId, activity.getId())
|
||||
.eq(LotteryUserCount::getDrawDate, LocalDate.now())
|
||||
.one();
|
||||
if (userCount != null) {
|
||||
usedCount = userCount.getDrawCount();
|
||||
}
|
||||
}
|
||||
|
||||
// 组装返回数据
|
||||
LotteryActivityDetailCO detail = new LotteryActivityDetailCO();
|
||||
detail.setActivity(convertActivityToCO(activity, usedCount));
|
||||
detail.setPrizeList(prizes.stream()
|
||||
.map(this::convertPrizeToCO)
|
||||
.collect(Collectors.toList()));
|
||||
detail.setUserTicketCount(ticketCount);
|
||||
|
||||
return detail;
|
||||
}
|
||||
|
||||
private LotteryActivityCO convertActivityToCO(LotteryActivity activity, Integer usedCount) {
|
||||
LotteryActivityCO co = new LotteryActivityCO();
|
||||
co.setId(activity.getId());
|
||||
co.setActivityCode(activity.getActivityCode());
|
||||
co.setActivityName(activity.getActivityName());
|
||||
co.setActivityDesc(activity.getActivityDesc());
|
||||
co.setStartTime(activity.getStartTime());
|
||||
co.setEndTime(activity.getEndTime());
|
||||
co.setStatus(activity.getStatus());
|
||||
co.setNeedTicket(activity.getNeedTicket());
|
||||
co.setTicketCost(activity.getTicketCost());
|
||||
co.setDrawCountLimit(activity.getDrawCountLimit());
|
||||
co.setDrawCountCycle(activity.getDrawCountCycle());
|
||||
|
||||
if (activity.getDrawCountLimit() != null && activity.getDrawCountLimit() > 0) {
|
||||
co.setUserRemainingCount(Math.max(0, activity.getDrawCountLimit() - usedCount));
|
||||
} else {
|
||||
co.setUserRemainingCount(-1);
|
||||
}
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
private LotteryPrizeCO convertPrizeToCO(LotteryPrize prize) {
|
||||
LotteryPrizeCO co = new LotteryPrizeCO();
|
||||
co.setId(prize.getId());
|
||||
co.setPrizeCode(prize.getPrizeCode());
|
||||
co.setPrizeName(prize.getPrizeName());
|
||||
co.setPrizeType(prize.getPrizeType());
|
||||
co.setPrizeValue(prize.getPrizeValue());
|
||||
co.setPrizeImage(prize.getPrizeImage());
|
||||
co.setPrizeLevel(prize.getPrizeLevel());
|
||||
co.setSortOrder(prize.getSortOrder());
|
||||
return co;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryActivityCO;
|
||||
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.service.activity.LotteryActivityService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 查询有效活动列表.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityListQryExe {
|
||||
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
private final LotteryUserCountService lotteryUserCountService;
|
||||
|
||||
public List<LotteryActivityCO> execute(AppExtCommand cmd) {
|
||||
Long userId = cmd.requiredReqUserId();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
// 查询进行中的活动
|
||||
List<LotteryActivity> activities = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getStatus, 1)
|
||||
.le(LotteryActivity::getStartTime, now)
|
||||
.ge(LotteryActivity::getEndTime, now)
|
||||
.orderByAsc(LotteryActivity::getSortOrder)
|
||||
.list();
|
||||
|
||||
if (activities.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// 查询用户今日抽奖次数
|
||||
List<Long> activityIds = activities.stream()
|
||||
.map(LotteryActivity::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<Long, Integer> userDrawCountMap = lotteryUserCountService.lambdaQuery()
|
||||
.eq(LotteryUserCount::getUserId, userId)
|
||||
.in(LotteryUserCount::getActivityId, activityIds)
|
||||
.eq(LotteryUserCount::getDrawDate, LocalDate.now())
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
LotteryUserCount::getActivityId,
|
||||
LotteryUserCount::getDrawCount
|
||||
));
|
||||
|
||||
// 转换为CO
|
||||
return activities.stream()
|
||||
.map(activity -> convertToCO(activity, userDrawCountMap))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private LotteryActivityCO convertToCO(LotteryActivity activity, Map<Long, Integer> userDrawCountMap) {
|
||||
LotteryActivityCO co = new LotteryActivityCO();
|
||||
co.setId(activity.getId());
|
||||
co.setActivityCode(activity.getActivityCode());
|
||||
co.setActivityName(activity.getActivityName());
|
||||
co.setActivityDesc(activity.getActivityDesc());
|
||||
co.setStartTime(activity.getStartTime());
|
||||
co.setEndTime(activity.getEndTime());
|
||||
co.setStatus(activity.getStatus());
|
||||
co.setNeedTicket(activity.getNeedTicket());
|
||||
co.setTicketCost(activity.getTicketCost());
|
||||
co.setDrawCountLimit(activity.getDrawCountLimit());
|
||||
co.setDrawCountCycle(activity.getDrawCountCycle());
|
||||
|
||||
// 计算剩余次数
|
||||
if (activity.getDrawCountLimit() != null && activity.getDrawCountLimit() > 0) {
|
||||
int usedCount = userDrawCountMap.getOrDefault(activity.getId(), 0);
|
||||
co.setUserRemainingCount(Math.max(0, activity.getDrawCountLimit() - usedCount));
|
||||
} else {
|
||||
co.setUserRemainingCount(-1); // -1表示不限制
|
||||
}
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,253 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryDrawResultCO;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryPrizeCO;
|
||||
import com.red.circle.other.app.dto.cmd.activity.LotteryDrawCmd;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
|
||||
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.LotteryUserCount;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordService;
|
||||
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.LotteryUserCountService;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 执行抽奖.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryDrawExe {
|
||||
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
private final LotteryPrizeService lotteryPrizeService;
|
||||
private final LotteryRecordService lotteryRecordService;
|
||||
private final LotteryTicketService lotteryTicketService;
|
||||
private final LotteryTicketRecordService lotteryTicketRecordService;
|
||||
private final LotteryUserCountService lotteryUserCountService;
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LotteryDrawResultCO execute(LotteryDrawCmd cmd) {
|
||||
Long userId = cmd.requiredReqUserId();
|
||||
String activityCode = cmd.getActivityCode();
|
||||
|
||||
// 1. 校验活动
|
||||
LotteryActivity activity = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getActivityCode, activityCode)
|
||||
.one();
|
||||
ResponseAssert.isTrue(activity != null, "活动不存在");
|
||||
ResponseAssert.isTrue(activity.getStatus() == 1, "活动未开始或已结束");
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
ResponseAssert.isTrue(now.isAfter(activity.getStartTime()) && now.isBefore(activity.getEndTime()),
|
||||
"不在活动时间内");
|
||||
|
||||
// 2. 校验抽奖次数
|
||||
if (activity.getDrawCountLimit() != null && activity.getDrawCountLimit() > 0) {
|
||||
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery()
|
||||
.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. 执行抽奖算法
|
||||
LotteryPrize prize = drawPrize(activity.getId());
|
||||
|
||||
// 5. 保存抽奖记录
|
||||
String recordNo = generateRecordNo();
|
||||
LotteryRecord record = new LotteryRecord();
|
||||
record.setRecordNo(recordNo);
|
||||
record.setUserId(userId);
|
||||
record.setActivityId(activity.getId());
|
||||
record.setDrawTime(now);
|
||||
|
||||
if (prize != null) {
|
||||
record.setPrizeId(prize.getId());
|
||||
record.setPrizeName(prize.getPrizeName());
|
||||
record.setPrizeType(prize.getPrizeType());
|
||||
record.setIsWin(1);
|
||||
record.setPrizeStatus(0); // 待发放
|
||||
|
||||
// 扣减库存
|
||||
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. 更新用户抽奖次数
|
||||
updateUserDrawCount(userId, activity.getId());
|
||||
|
||||
// 7. 组装返回结果
|
||||
return convertToResultCO(record, prize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 扣除抽奖券.
|
||||
*/
|
||||
private void deductTicket(Long userId, Integer ticketCost) {
|
||||
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery()
|
||||
.eq(LotteryTicket::getUserId, userId)
|
||||
.eq(LotteryTicket::getStatus, 1)
|
||||
.gt(LotteryTicket::getRemainingCount, 0)
|
||||
.orderByAsc(LotteryTicket::getExpireTime)
|
||||
.list();
|
||||
|
||||
int totalRemaining = tickets.stream()
|
||||
.mapToInt(LotteryTicket::getRemainingCount)
|
||||
.sum();
|
||||
ResponseAssert.isTrue(totalRemaining >= ticketCost, "抽奖券不足");
|
||||
|
||||
int remaining = ticketCost;
|
||||
for (LotteryTicket ticket : tickets) {
|
||||
if (remaining <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int deduct = Math.min(remaining, ticket.getRemainingCount());
|
||||
|
||||
lotteryTicketService.lambdaUpdate()
|
||||
.eq(LotteryTicket::getId, ticket.getId())
|
||||
.setSql("used_count = used_count + " + deduct)
|
||||
.setSql("remaining_count = remaining_count - " + deduct)
|
||||
.update();
|
||||
|
||||
// 记录使用
|
||||
LotteryTicketRecord ticketRecord = new LotteryTicketRecord();
|
||||
ticketRecord.setUserId(userId);
|
||||
ticketRecord.setTicketId(ticket.getId());
|
||||
ticketRecord.setChangeCount(-deduct);
|
||||
ticketRecord.setChangeType(2); // 消耗
|
||||
ticketRecord.setRemark("抽奖消耗");
|
||||
lotteryTicketRecordService.save(ticketRecord);
|
||||
|
||||
remaining -= deduct;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽奖算法 - 权重随机.
|
||||
*/
|
||||
private LotteryPrize drawPrize(Long activityId) {
|
||||
// 查询所有可用奖品
|
||||
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery()
|
||||
.eq(LotteryPrize::getActivityId, activityId)
|
||||
.gt(LotteryPrize::getRemainingStock, 0)
|
||||
.list();
|
||||
|
||||
if (prizes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 计算总概率
|
||||
BigDecimal totalProbability = prizes.stream()
|
||||
.map(LotteryPrize::getProbability)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
// 生成随机数
|
||||
double randomValue = random.nextDouble() * totalProbability.doubleValue();
|
||||
double cumulative = 0.0;
|
||||
|
||||
// 根据概率选择奖品
|
||||
for (LotteryPrize prize : prizes) {
|
||||
cumulative += prize.getProbability().doubleValue();
|
||||
if (randomValue <= cumulative) {
|
||||
return prize;
|
||||
}
|
||||
}
|
||||
|
||||
return prizes.get(prizes.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户抽奖次数.
|
||||
*/
|
||||
private void updateUserDrawCount(Long userId, Long activityId) {
|
||||
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery()
|
||||
.eq(LotteryUserCount::getUserId, userId)
|
||||
.eq(LotteryUserCount::getActivityId, activityId)
|
||||
.eq(LotteryUserCount::getDrawDate, LocalDate.now())
|
||||
.one();
|
||||
|
||||
if (userCount == null) {
|
||||
userCount = new LotteryUserCount();
|
||||
userCount.setUserId(userId);
|
||||
userCount.setActivityId(activityId);
|
||||
userCount.setDrawDate(LocalDate.now());
|
||||
userCount.setDrawCount(1);
|
||||
lotteryUserCountService.save(userCount);
|
||||
} else {
|
||||
lotteryUserCountService.lambdaUpdate()
|
||||
.eq(LotteryUserCount::getId, userCount.getId())
|
||||
.setSql("draw_count = draw_count + 1")
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成记录编号.
|
||||
*/
|
||||
private String generateRecordNo() {
|
||||
return "LT" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为结果CO.
|
||||
*/
|
||||
private LotteryDrawResultCO convertToResultCO(LotteryRecord record, LotteryPrize prize) {
|
||||
LotteryDrawResultCO result = new LotteryDrawResultCO();
|
||||
result.setRecordNo(record.getRecordNo());
|
||||
result.setIsWin(record.getIsWin() == 1);
|
||||
result.setDrawTime(record.getDrawTime());
|
||||
|
||||
if (prize != null) {
|
||||
LotteryPrizeCO prizeCO = new LotteryPrizeCO();
|
||||
prizeCO.setId(prize.getId());
|
||||
prizeCO.setPrizeCode(prize.getPrizeCode());
|
||||
prizeCO.setPrizeName(prize.getPrizeName());
|
||||
prizeCO.setPrizeType(prize.getPrizeType());
|
||||
prizeCO.setPrizeValue(prize.getPrizeValue());
|
||||
prizeCO.setPrizeImage(prize.getPrizeImage());
|
||||
prizeCO.setPrizeLevel(prize.getPrizeLevel());
|
||||
result.setPrize(prizeCO);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.LotteryRecordCO;
|
||||
import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 查询我的抽奖记录.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryRecordQryExe {
|
||||
|
||||
private final LotteryRecordService lotteryRecordService;
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
private final LotteryPrizeService lotteryPrizeService;
|
||||
|
||||
public PageResult<LotteryRecordCO> execute(LotteryRecordQryCmd cmd) {
|
||||
Long userId = cmd.requiredReqUserId();
|
||||
Integer pageNo = cmd.getPageNo() != null ? cmd.getPageNo() : 1;
|
||||
Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20;
|
||||
|
||||
// 构建查询条件
|
||||
Page<LotteryRecord> page = new Page<>(pageNo, pageSize);
|
||||
var query = lotteryRecordService.lambdaQuery()
|
||||
.eq(LotteryRecord::getUserId, userId);
|
||||
|
||||
if (cmd.getActivityCode() != null) {
|
||||
LotteryActivity activity = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getActivityCode, cmd.getActivityCode())
|
||||
.one();
|
||||
if (activity != null) {
|
||||
query.eq(LotteryRecord::getActivityId, activity.getId());
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd.getOnlyWin() != null && cmd.getOnlyWin()) {
|
||||
query.eq(LotteryRecord::getIsWin, 1);
|
||||
}
|
||||
|
||||
Page<LotteryRecord> recordPage = query.orderByDesc(LotteryRecord::getDrawTime).page(page);
|
||||
|
||||
// 查询关联数据
|
||||
List<Long> activityIds = recordPage.getRecords().stream()
|
||||
.map(LotteryRecord::getActivityId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<Long> prizeIds = recordPage.getRecords().stream()
|
||||
.map(LotteryRecord::getPrizeId)
|
||||
.filter(id -> id != null)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<Long, LotteryActivity> activityMap = lotteryActivityService.lambdaQuery()
|
||||
.in(LotteryActivity::getId, activityIds)
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(LotteryActivity::getId, a -> a));
|
||||
|
||||
Map<Long, LotteryPrize> prizeMap = lotteryPrizeService.lambdaQuery()
|
||||
.in(LotteryPrize::getId, prizeIds)
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(LotteryPrize::getId, p -> p));
|
||||
|
||||
// 转换为CO
|
||||
List<LotteryRecordCO> records = recordPage.getRecords().stream()
|
||||
.map(record -> convertToCO(record, activityMap, prizeMap))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return PageResult.of(records, recordPage.getTotal(), pageNo, pageSize);
|
||||
}
|
||||
|
||||
private LotteryRecordCO convertToCO(LotteryRecord record,
|
||||
Map<Long, LotteryActivity> activityMap,
|
||||
Map<Long, LotteryPrize> prizeMap) {
|
||||
LotteryRecordCO co = new LotteryRecordCO();
|
||||
co.setRecordNo(record.getRecordNo());
|
||||
co.setIsWin(record.getIsWin() == 1);
|
||||
co.setDrawTime(record.getDrawTime());
|
||||
co.setPrizeStatus(record.getPrizeStatus());
|
||||
|
||||
LotteryActivity activity = activityMap.get(record.getActivityId());
|
||||
if (activity != null) {
|
||||
co.setActivityName(activity.getActivityName());
|
||||
}
|
||||
|
||||
if (record.getPrizeId() != null) {
|
||||
LotteryPrize prize = prizeMap.get(record.getPrizeId());
|
||||
if (prize != null) {
|
||||
LotteryPrizeCO prizeCO = new LotteryPrizeCO();
|
||||
prizeCO.setId(prize.getId());
|
||||
prizeCO.setPrizeCode(prize.getPrizeCode());
|
||||
prizeCO.setPrizeName(prize.getPrizeName());
|
||||
prizeCO.setPrizeType(prize.getPrizeType());
|
||||
prizeCO.setPrizeValue(prize.getPrizeValue());
|
||||
prizeCO.setPrizeImage(prize.getPrizeImage());
|
||||
prizeCO.setPrizeLevel(prize.getPrizeLevel());
|
||||
co.setPrize(prizeCO);
|
||||
}
|
||||
}
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 查询我的抽奖券总数.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryTicketCountQryExe {
|
||||
|
||||
private final LotteryTicketService lotteryTicketService;
|
||||
|
||||
public Integer execute(AppExtCommand cmd) {
|
||||
Long userId = cmd.requiredReqUserId();
|
||||
|
||||
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery()
|
||||
.eq(LotteryTicket::getUserId, userId)
|
||||
.eq(LotteryTicket::getStatus, 1)
|
||||
.gt(LotteryTicket::getRemainingCount, 0)
|
||||
.list();
|
||||
|
||||
return tickets.stream()
|
||||
.mapToInt(LotteryTicket::getRemainingCount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryTicketCO;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryTicketService;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 查询我的抽奖券.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryTicketQryExe {
|
||||
|
||||
private final LotteryTicketService lotteryTicketService;
|
||||
|
||||
public List<LotteryTicketCO> execute(AppExtCommand cmd) {
|
||||
Long userId = cmd.requiredReqUserId();
|
||||
|
||||
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery()
|
||||
.eq(LotteryTicket::getUserId, userId)
|
||||
.eq(LotteryTicket::getStatus, 1)
|
||||
.gt(LotteryTicket::getRemainingCount, 0)
|
||||
.orderByAsc(LotteryTicket::getExpireTime)
|
||||
.list();
|
||||
|
||||
return tickets.stream()
|
||||
.map(this::convertToCO)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private LotteryTicketCO convertToCO(LotteryTicket ticket) {
|
||||
LotteryTicketCO co = new LotteryTicketCO();
|
||||
co.setId(ticket.getId());
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.red.circle.other.app.service.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.other.app.command.activity.LotteryActivityDetailQryExe;
|
||||
import com.red.circle.other.app.command.activity.LotteryActivityListQryExe;
|
||||
import com.red.circle.other.app.command.activity.LotteryDrawExe;
|
||||
import com.red.circle.other.app.command.activity.LotteryRecordQryExe;
|
||||
import com.red.circle.other.app.command.activity.LotteryTicketCountQryExe;
|
||||
import com.red.circle.other.app.command.activity.LotteryTicketQryExe;
|
||||
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.LotteryDrawResultCO;
|
||||
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.cmd.activity.LotteryDrawCmd;
|
||||
import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 抽奖活动服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityServiceImpl implements LotteryActivityService {
|
||||
|
||||
private final LotteryActivityListQryExe lotteryActivityListQryExe;
|
||||
private final LotteryActivityDetailQryExe lotteryActivityDetailQryExe;
|
||||
private final LotteryDrawExe lotteryDrawExe;
|
||||
private final LotteryRecordQryExe lotteryRecordQryExe;
|
||||
private final LotteryTicketQryExe lotteryTicketQryExe;
|
||||
private final LotteryTicketCountQryExe lotteryTicketCountQryExe;
|
||||
|
||||
@Override
|
||||
public List<LotteryActivityCO> listValidActivities(AppExtCommand cmd) {
|
||||
return lotteryActivityListQryExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LotteryActivityDetailCO getActivityDetail(String activityCode, AppExtCommand cmd) {
|
||||
return lotteryActivityDetailQryExe.execute(activityCode, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LotteryDrawResultCO draw(LotteryDrawCmd cmd) {
|
||||
return lotteryDrawExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd) {
|
||||
return lotteryRecordQryExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LotteryTicketCO> listMyTickets(AppExtCommand cmd) {
|
||||
return lotteryTicketQryExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMyTicketCount(AppExtCommand cmd) {
|
||||
return lotteryTicketCountQryExe.execute(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package com.red.circle.other.app.service.activity;
|
||||
|
||||
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.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.LotteryActivityDetailCO;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.LotteryDrawResultCO;
|
||||
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.cmd.activity.LotteryDrawCmd;
|
||||
import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 抽奖服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryServiceImpl implements LotteryService {
|
||||
|
||||
private final LotteryActivityListQryExe lotteryActivityListQryExe;
|
||||
private final LotteryActivityDetailQryExe lotteryActivityDetailQryExe;
|
||||
private final LotteryDrawExe lotteryDrawExe;
|
||||
private final LotteryRecordQryExe lotteryRecordQryExe;
|
||||
private final LotteryTicketQryExe lotteryTicketQryExe;
|
||||
|
||||
@Override
|
||||
public List<LotteryActivityCO> listActiveActivities(AppExtCommand cmd) {
|
||||
return lotteryActivityListQryExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LotteryActivityDetailCO getActivityDetail(String activityCode, AppExtCommand cmd) {
|
||||
return lotteryActivityDetailQryExe.execute(activityCode, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LotteryDrawResultCO draw(LotteryDrawCmd cmd) {
|
||||
return lotteryDrawExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd) {
|
||||
return lotteryRecordQryExe.execute(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LotteryTicketCO> listMyTickets(AppExtCommand cmd) {
|
||||
return lotteryTicketQryExe.execute(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package com.red.circle.other.app.dto.clientobject.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 抽奖活动CO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LotteryActivityCO extends ClientObject {
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*/
|
||||
private String activityCode;
|
||||
|
||||
/**
|
||||
* 活动名称.
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 活动描述.
|
||||
*/
|
||||
private String activityDesc;
|
||||
|
||||
/**
|
||||
* 开始时间.
|
||||
*/
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 结束时间.
|
||||
*/
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 状态:0-未开始,1-进行中,2-已结束,3-已关闭.
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 是否需要抽奖券.
|
||||
*/
|
||||
private Integer needTicket;
|
||||
|
||||
/**
|
||||
* 每次消耗抽奖券数量.
|
||||
*/
|
||||
private Integer ticketCost;
|
||||
|
||||
/**
|
||||
* 每人抽奖次数限制.
|
||||
*/
|
||||
private Integer drawCountLimit;
|
||||
|
||||
/**
|
||||
* 次数限制周期.
|
||||
*/
|
||||
private String drawCountCycle;
|
||||
|
||||
/**
|
||||
* 用户剩余抽奖次数.
|
||||
*/
|
||||
private Integer userRemainingCount;
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package com.red.circle.other.app.dto.clientobject.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 抽奖活动详情CO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LotteryActivityDetailCO extends ClientObject {
|
||||
|
||||
/**
|
||||
* 活动信息.
|
||||
*/
|
||||
private LotteryActivityCO activity;
|
||||
|
||||
/**
|
||||
* 奖品列表.
|
||||
*/
|
||||
private List<LotteryPrizeCO> prizeList;
|
||||
|
||||
/**
|
||||
* 用户抽奖券数量.
|
||||
*/
|
||||
private Integer userTicketCount;
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.red.circle.other.app.dto.clientobject.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 抽奖结果CO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LotteryDrawResultCO extends ClientObject {
|
||||
|
||||
/**
|
||||
* 记录编号.
|
||||
*/
|
||||
private String recordNo;
|
||||
|
||||
/**
|
||||
* 是否中奖.
|
||||
*/
|
||||
private Boolean isWin;
|
||||
|
||||
/**
|
||||
* 中奖奖品信息.
|
||||
*/
|
||||
private LotteryPrizeCO prize;
|
||||
|
||||
/**
|
||||
* 抽奖时间.
|
||||
*/
|
||||
private LocalDateTime drawTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.red.circle.other.app.dto.clientobject.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 奖品CO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LotteryPrizeCO extends ClientObject {
|
||||
|
||||
/**
|
||||
* 奖品ID.
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 奖品编码.
|
||||
*/
|
||||
private String prizeCode;
|
||||
|
||||
/**
|
||||
* 奖品名称.
|
||||
*/
|
||||
private String prizeName;
|
||||
|
||||
/**
|
||||
* 奖品类型.
|
||||
*/
|
||||
private Integer prizeType;
|
||||
|
||||
/**
|
||||
* 奖品价值.
|
||||
*/
|
||||
private BigDecimal prizeValue;
|
||||
|
||||
/**
|
||||
* 奖品图片.
|
||||
*/
|
||||
private String prizeImage;
|
||||
|
||||
/**
|
||||
* 奖品等级.
|
||||
*/
|
||||
private Integer prizeLevel;
|
||||
|
||||
/**
|
||||
* 排序(九宫格位置).
|
||||
*/
|
||||
private Integer sortOrder;
|
||||
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.red.circle.other.app.dto.clientobject.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 抽奖记录CO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LotteryRecordCO extends ClientObject {
|
||||
|
||||
/**
|
||||
* 记录编号.
|
||||
*/
|
||||
private String recordNo;
|
||||
|
||||
/**
|
||||
* 活动名称.
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 奖品信息.
|
||||
*/
|
||||
private LotteryPrizeCO prize;
|
||||
|
||||
/**
|
||||
* 是否中奖.
|
||||
*/
|
||||
private Boolean isWin;
|
||||
|
||||
/**
|
||||
* 抽奖时间.
|
||||
*/
|
||||
private LocalDateTime drawTime;
|
||||
|
||||
/**
|
||||
* 奖品状态:0-待发放,1-已发放,2-发放失败.
|
||||
*/
|
||||
private Integer prizeStatus;
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.red.circle.other.app.dto.clientobject.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户抽奖券CO.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LotteryTicketCO extends ClientObject {
|
||||
|
||||
/**
|
||||
* 抽奖券ID.
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 来源.
|
||||
*/
|
||||
private String ticketSource;
|
||||
|
||||
/**
|
||||
* 总数量.
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 已使用数量.
|
||||
*/
|
||||
private Integer usedCount;
|
||||
|
||||
/**
|
||||
* 剩余数量.
|
||||
*/
|
||||
private Integer remainingCount;
|
||||
|
||||
/**
|
||||
* 过期时间.
|
||||
*/
|
||||
private LocalDateTime expireTime;
|
||||
|
||||
/**
|
||||
* 状态.
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.red.circle.other.app.dto.cmd.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 执行抽奖Cmd.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LotteryDrawCmd extends AppExtCommand {
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*
|
||||
* @eo.required
|
||||
*/
|
||||
@NotBlank(message = "activityCode required.")
|
||||
private String activityCode;
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.red.circle.other.app.dto.cmd.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 抽奖记录查询命令.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class LotteryRecordQryCmd extends AppExtCommand {
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*/
|
||||
private String activityCode;
|
||||
|
||||
/**
|
||||
* 是否只查询中奖记录.
|
||||
*/
|
||||
private Boolean onlyWin;
|
||||
|
||||
/**
|
||||
* 页码.
|
||||
*/
|
||||
private Integer pageNo;
|
||||
|
||||
/**
|
||||
* 页大小.
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package com.red.circle.other.app.service.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
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.LotteryDrawResultCO;
|
||||
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.cmd.activity.LotteryDrawCmd;
|
||||
import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 抽奖活动服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryActivityService {
|
||||
|
||||
/**
|
||||
* 获取有效活动列表.
|
||||
*/
|
||||
List<LotteryActivityCO> listValidActivities(AppExtCommand cmd);
|
||||
|
||||
/**
|
||||
* 获取活动详情.
|
||||
*/
|
||||
LotteryActivityDetailCO getActivityDetail(String activityCode, AppExtCommand cmd);
|
||||
|
||||
/**
|
||||
* 执行抽奖.
|
||||
*/
|
||||
LotteryDrawResultCO draw(LotteryDrawCmd cmd);
|
||||
|
||||
/**
|
||||
* 查询我的中奖记录.
|
||||
*/
|
||||
PageResult<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd);
|
||||
|
||||
/**
|
||||
* 查询我的抽奖券.
|
||||
*/
|
||||
List<LotteryTicketCO> listMyTickets(AppExtCommand cmd);
|
||||
|
||||
/**
|
||||
* 获取抽奖券总数.
|
||||
*/
|
||||
Integer getMyTicketCount(AppExtCommand cmd);
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.red.circle.other.app.service.activity;
|
||||
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
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.LotteryDrawResultCO;
|
||||
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.cmd.activity.LotteryDrawCmd;
|
||||
import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 抽奖服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryService {
|
||||
|
||||
/**
|
||||
* 获取有效活动列表.
|
||||
*/
|
||||
List<LotteryActivityCO> listActiveActivities(AppExtCommand cmd);
|
||||
|
||||
/**
|
||||
* 获取活动详情.
|
||||
*/
|
||||
LotteryActivityDetailCO getActivityDetail(String activityCode, AppExtCommand cmd);
|
||||
|
||||
/**
|
||||
* 执行抽奖.
|
||||
*/
|
||||
LotteryDrawResultCO draw(LotteryDrawCmd cmd);
|
||||
|
||||
/**
|
||||
* 查询用户抽奖记录.
|
||||
*/
|
||||
List<LotteryRecordCO> listMyRecords(LotteryRecordQryCmd cmd);
|
||||
|
||||
/**
|
||||
* 查询用户抽奖券.
|
||||
*/
|
||||
List<LotteryTicketCO> listMyTickets(AppExtCommand cmd);
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.infra.database.rds.dao.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 抽奖活动Mapper.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface LotteryActivityMapper extends BaseMapper<LotteryActivity> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.infra.database.rds.dao.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 奖品配置Mapper.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface LotteryPrizeMapper extends BaseMapper<LotteryPrize> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.infra.database.rds.dao.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 中奖记录Mapper.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface LotteryRecordMapper extends BaseMapper<LotteryRecord> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.infra.database.rds.dao.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 抽奖券Mapper.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface LotteryTicketMapper extends BaseMapper<LotteryTicket> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.infra.database.rds.dao.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 抽奖券使用记录Mapper.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface LotteryTicketRecordMapper extends BaseMapper<LotteryTicketRecord> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.other.infra.database.rds.dao.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户抽奖次数统计Mapper.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Mapper
|
||||
public interface LotteryUserCountMapper extends BaseMapper<LotteryUserCount> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
package com.red.circle.other.infra.database.rds.entity.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 抽奖活动表.
|
||||
* </p>
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("lottery_activity")
|
||||
public class LotteryActivity extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键标识.
|
||||
*/
|
||||
@TableId("id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动编码.
|
||||
*/
|
||||
@TableField("activity_code")
|
||||
private String activityCode;
|
||||
|
||||
/**
|
||||
* 活动名称.
|
||||
*/
|
||||
@TableField("activity_name")
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 活动描述.
|
||||
*/
|
||||
@TableField("activity_desc")
|
||||
private String activityDesc;
|
||||
|
||||
/**
|
||||
* 开始时间.
|
||||
*/
|
||||
@TableField("start_time")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 结束时间.
|
||||
*/
|
||||
@TableField("end_time")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 状态:0-未开始,1-进行中,2-已结束,3-已关闭.
|
||||
*/
|
||||
@TableField("status")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 总奖品库存.
|
||||
*/
|
||||
@TableField("total_stock")
|
||||
private Integer totalStock;
|
||||
|
||||
/**
|
||||
* 已消耗库存.
|
||||
*/
|
||||
@TableField("consumed_stock")
|
||||
private Integer consumedStock;
|
||||
|
||||
/**
|
||||
* 每人抽奖次数限制(0为不限制).
|
||||
*/
|
||||
@TableField("draw_count_limit")
|
||||
private Integer drawCountLimit;
|
||||
|
||||
/**
|
||||
* 次数限制周期:DAILY-每天,TOTAL-总计.
|
||||
*/
|
||||
@TableField("draw_count_cycle")
|
||||
private String drawCountCycle;
|
||||
|
||||
/**
|
||||
* 是否需要抽奖券:0-否,1-是.
|
||||
*/
|
||||
@TableField("need_ticket")
|
||||
private Integer needTicket;
|
||||
|
||||
/**
|
||||
* 每次消耗抽奖券数量.
|
||||
*/
|
||||
@TableField("ticket_cost")
|
||||
private Integer ticketCost;
|
||||
|
||||
/**
|
||||
* 排序.
|
||||
*/
|
||||
@TableField("sort_order")
|
||||
private Integer sortOrder;
|
||||
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
package com.red.circle.other.infra.database.rds.entity.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 奖品配置表.
|
||||
* </p>
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("lottery_prize")
|
||||
public class LotteryPrize extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键标识.
|
||||
*/
|
||||
@TableId("id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
@TableField("activity_id")
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 奖品编码.
|
||||
*/
|
||||
@TableField("prize_code")
|
||||
private String prizeCode;
|
||||
|
||||
/**
|
||||
* 奖品名称.
|
||||
*/
|
||||
@TableField("prize_name")
|
||||
private String prizeName;
|
||||
|
||||
/**
|
||||
* 奖品类型:1-实物,2-虚拟币,3-优惠券,4-积分,5-谢谢参与.
|
||||
*/
|
||||
@TableField("prize_type")
|
||||
private Integer prizeType;
|
||||
|
||||
/**
|
||||
* 奖品价值/数量.
|
||||
*/
|
||||
@TableField("prize_value")
|
||||
private BigDecimal prizeValue;
|
||||
|
||||
/**
|
||||
* 奖品图片.
|
||||
*/
|
||||
@TableField("prize_image")
|
||||
private String prizeImage;
|
||||
|
||||
/**
|
||||
* 奖品等级:1-特等奖,2-一等奖,3-二等奖.
|
||||
*/
|
||||
@TableField("prize_level")
|
||||
private Integer prizeLevel;
|
||||
|
||||
/**
|
||||
* 总库存.
|
||||
*/
|
||||
@TableField("total_stock")
|
||||
private Integer totalStock;
|
||||
|
||||
/**
|
||||
* 剩余库存.
|
||||
*/
|
||||
@TableField("remaining_stock")
|
||||
private Integer remainingStock;
|
||||
|
||||
/**
|
||||
* 每日库存限制(0为不限制).
|
||||
*/
|
||||
@TableField("daily_stock")
|
||||
private Integer dailyStock;
|
||||
|
||||
/**
|
||||
* 中奖概率(0-1之间).
|
||||
*/
|
||||
@TableField("probability")
|
||||
private BigDecimal probability;
|
||||
|
||||
/**
|
||||
* 排序(九宫格位置).
|
||||
*/
|
||||
@TableField("sort_order")
|
||||
private Integer sortOrder;
|
||||
|
||||
/**
|
||||
* 是否展示:0-否,1-是.
|
||||
*/
|
||||
@TableField("is_display")
|
||||
private Integer isDisplay;
|
||||
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
package com.red.circle.other.infra.database.rds.entity.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 中奖记录表.
|
||||
* </p>
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("lottery_record")
|
||||
public class LotteryRecord extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键标识.
|
||||
*/
|
||||
@TableId("id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 记录编号.
|
||||
*/
|
||||
@TableField("record_no")
|
||||
private String recordNo;
|
||||
|
||||
/**
|
||||
* 用户ID.
|
||||
*/
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
@TableField("activity_id")
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 奖品ID(未中奖为NULL).
|
||||
*/
|
||||
@TableField("prize_id")
|
||||
private Long prizeId;
|
||||
|
||||
/**
|
||||
* 奖品名称快照.
|
||||
*/
|
||||
@TableField("prize_name")
|
||||
private String prizeName;
|
||||
|
||||
/**
|
||||
* 奖品类型快照.
|
||||
*/
|
||||
@TableField("prize_type")
|
||||
private Integer prizeType;
|
||||
|
||||
/**
|
||||
* 是否中奖:0-未中奖,1-中奖.
|
||||
*/
|
||||
@TableField("is_win")
|
||||
private Integer isWin;
|
||||
|
||||
/**
|
||||
* 抽奖时间.
|
||||
*/
|
||||
@TableField("draw_time")
|
||||
private LocalDateTime drawTime;
|
||||
|
||||
/**
|
||||
* 奖品状态:0-待发放,1-已发放,2-发放失败.
|
||||
*/
|
||||
@TableField("prize_status")
|
||||
private Integer prizeStatus;
|
||||
|
||||
/**
|
||||
* 发放时间.
|
||||
*/
|
||||
@TableField("deliver_time")
|
||||
private LocalDateTime deliverTime;
|
||||
|
||||
/**
|
||||
* 备注.
|
||||
*/
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package com.red.circle.other.infra.database.rds.entity.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 抽奖券表.
|
||||
* </p>
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("lottery_ticket")
|
||||
public class LotteryTicket extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键标识.
|
||||
*/
|
||||
@TableId("id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID.
|
||||
*/
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 来源:SYSTEM-系统发放,ACTIVITY-活动赠送,PURCHASE-购买.
|
||||
*/
|
||||
@TableField("ticket_source")
|
||||
private String ticketSource;
|
||||
|
||||
/**
|
||||
* 来源ID.
|
||||
*/
|
||||
@TableField("source_id")
|
||||
private String sourceId;
|
||||
|
||||
/**
|
||||
* 总数量.
|
||||
*/
|
||||
@TableField("total_count")
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 已使用数量.
|
||||
*/
|
||||
@TableField("used_count")
|
||||
private Integer usedCount;
|
||||
|
||||
/**
|
||||
* 剩余数量.
|
||||
*/
|
||||
@TableField("remaining_count")
|
||||
private Integer remainingCount;
|
||||
|
||||
/**
|
||||
* 过期时间.
|
||||
*/
|
||||
@TableField("expire_time")
|
||||
private LocalDateTime expireTime;
|
||||
|
||||
/**
|
||||
* 状态:0-已失效,1-正常.
|
||||
*/
|
||||
@TableField("status")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.red.circle.other.infra.database.rds.entity.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 抽奖券使用记录表.
|
||||
* </p>
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("lottery_ticket_record")
|
||||
public class LotteryTicketRecord extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键标识.
|
||||
*/
|
||||
@TableId("id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID.
|
||||
*/
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 抽奖券ID.
|
||||
*/
|
||||
@TableField("ticket_id")
|
||||
private Long ticketId;
|
||||
|
||||
/**
|
||||
* 变动数量(正数增加,负数减少).
|
||||
*/
|
||||
@TableField("change_count")
|
||||
private Integer changeCount;
|
||||
|
||||
/**
|
||||
* 变动类型:1-发放,2-消耗,3-过期,4-退回.
|
||||
*/
|
||||
@TableField("change_type")
|
||||
private Integer changeType;
|
||||
|
||||
/**
|
||||
* 关联的抽奖记录ID.
|
||||
*/
|
||||
@TableField("lottery_record_id")
|
||||
private Long lotteryRecordId;
|
||||
|
||||
/**
|
||||
* 备注.
|
||||
*/
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.red.circle.other.infra.database.rds.entity.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户抽奖次数统计表.
|
||||
* </p>
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
@TableName("lottery_user_count")
|
||||
public class LotteryUserCount extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键标识.
|
||||
*/
|
||||
@TableId("id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID.
|
||||
*/
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 活动ID.
|
||||
*/
|
||||
@TableField("activity_id")
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 统计日期.
|
||||
*/
|
||||
@TableField("draw_date")
|
||||
private LocalDate drawDate;
|
||||
|
||||
/**
|
||||
* 抽奖次数.
|
||||
*/
|
||||
@TableField("draw_count")
|
||||
private Integer drawCount;
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
|
||||
/**
|
||||
* 抽奖活动服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryActivityService extends IService<LotteryActivity> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
|
||||
|
||||
/**
|
||||
* 奖品配置服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryPrizeService extends IService<LotteryPrize> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
|
||||
|
||||
/**
|
||||
* 中奖记录服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryRecordService extends IService<LotteryRecord> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicketRecord;
|
||||
|
||||
/**
|
||||
* 抽奖券使用记录服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryTicketRecordService extends IService<LotteryTicketRecord> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryTicket;
|
||||
|
||||
/**
|
||||
* 抽奖券服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryTicketService extends IService<LotteryTicket> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
|
||||
|
||||
/**
|
||||
* 用户抽奖次数统计服务.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
public interface LotteryUserCountService extends IService<LotteryUserCount> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
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.service.activity.LotteryActivityService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 抽奖活动服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
public class LotteryActivityServiceImpl extends ServiceImpl<LotteryActivityMapper, LotteryActivity>
|
||||
implements LotteryActivityService {
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
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.service.activity.LotteryPrizeService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 奖品配置服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
public class LotteryPrizeServiceImpl extends ServiceImpl<LotteryPrizeMapper, LotteryPrize>
|
||||
implements LotteryPrizeService {
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
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.service.activity.LotteryRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 中奖记录服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
public class LotteryRecordServiceImpl extends ServiceImpl<LotteryRecordMapper, LotteryRecord>
|
||||
implements LotteryRecordService {
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
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.service.activity.LotteryTicketRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 抽奖券使用记录服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
public class LotteryTicketRecordServiceImpl extends ServiceImpl<LotteryTicketRecordMapper, LotteryTicketRecord>
|
||||
implements LotteryTicketRecordService {
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
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.service.activity.LotteryTicketService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 抽奖券服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
public class LotteryTicketServiceImpl extends ServiceImpl<LotteryTicketMapper, LotteryTicket>
|
||||
implements LotteryTicketService {
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.red.circle.other.infra.database.rds.service.activity.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
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.service.activity.LotteryUserCountService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 用户抽奖次数统计服务实现.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Service
|
||||
public class LotteryUserCountServiceImpl extends ServiceImpl<LotteryUserCountMapper, LotteryUserCount>
|
||||
implements LotteryUserCountService {
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryActivityClientApi;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 抽奖活动ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryActivityClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityClientEndpoint implements LotteryActivityClientApi {
|
||||
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
|
||||
@Override
|
||||
public ResultResponse<LotteryActivityDTO> getByActivityCode(String activityCode) {
|
||||
LotteryActivity activity = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getActivityCode, activityCode)
|
||||
.one();
|
||||
|
||||
if (activity == null) {
|
||||
return ResultResponse.success(null);
|
||||
}
|
||||
|
||||
return ResultResponse.success(convertToDTO(activity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<LotteryActivityDTO> getById(Long id) {
|
||||
LotteryActivity activity = lotteryActivityService.getById(id);
|
||||
|
||||
if (activity == null) {
|
||||
return ResultResponse.success(null);
|
||||
}
|
||||
|
||||
return ResultResponse.success(convertToDTO(activity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<List<LotteryActivityDTO>> listActivities() {
|
||||
List<LotteryActivity> activities = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getStatus, 1)
|
||||
.orderByDesc(LotteryActivity::getCreateTime)
|
||||
.list();
|
||||
|
||||
List<LotteryActivityDTO> dtoList = activities.stream()
|
||||
.map(this::convertToDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ResultResponse.success(dtoList);
|
||||
}
|
||||
|
||||
private LotteryActivityDTO convertToDTO(LotteryActivity activity) {
|
||||
LotteryActivityDTO dto = new LotteryActivityDTO();
|
||||
BeanUtils.copyProperties(activity, dto);
|
||||
return dto;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
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.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
|
||||
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.model.cmd.activity.LotteryActivitySaveCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 抽奖活动管理ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryActivityManageClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityManageClientEndpoint implements LotteryActivityManageClientApi {
|
||||
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> createActivity(LotteryActivitySaveCmd cmd) {
|
||||
// 校验活动编码唯一性
|
||||
LotteryActivity exists = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getActivityCode, cmd.getActivityCode())
|
||||
.one();
|
||||
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_CODE_EXISTS, exists == null);
|
||||
|
||||
LotteryActivity activity = new LotteryActivity();
|
||||
BeanUtils.copyProperties(cmd, activity);
|
||||
activity.setStatus(0); // 未开始
|
||||
activity.setTotalStock(0);
|
||||
activity.setConsumedStock(0);
|
||||
|
||||
lotteryActivityService.save(activity);
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> updateActivity(LotteryActivitySaveCmd cmd) {
|
||||
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_ID_REQUIRED, cmd.getId() != null);
|
||||
|
||||
LotteryActivity activity = lotteryActivityService.getById(cmd.getId());
|
||||
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);
|
||||
lotteryActivityService.updateById(activity);
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> updateActivityStatus(Long id, Integer status) {
|
||||
LotteryActivity activity = lotteryActivityService.getById(id);
|
||||
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null);
|
||||
|
||||
activity.setStatus(status);
|
||||
lotteryActivityService.updateById(activity);
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<LotteryActivityDTO> getById(Long id) {
|
||||
LotteryActivity activity = lotteryActivityService.getById(id);
|
||||
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null);
|
||||
|
||||
LotteryActivityDTO dto = new LotteryActivityDTO();
|
||||
BeanUtils.copyProperties(activity, dto);
|
||||
|
||||
return ResultResponse.success(dto);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryActivityQueryClientApi;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryActivityQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryActivityDTO;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 活动查询ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryActivityQueryClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryActivityQueryClientEndpoint implements LotteryActivityQueryClientApi {
|
||||
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
|
||||
@Override
|
||||
public ResultResponse<PageResult<LotteryActivityDTO>> listActivities(LotteryActivityQryCmd cmd) {
|
||||
Integer pageNo = cmd.getPageNo() != null ? cmd.getPageNo() : 1;
|
||||
Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20;
|
||||
|
||||
Page<LotteryActivity> page = new Page<>(pageNo, pageSize);
|
||||
var query = lotteryActivityService.lambdaQuery();
|
||||
|
||||
if (cmd.getActivityName() != null) {
|
||||
query.like(LotteryActivity::getActivityName, cmd.getActivityName());
|
||||
}
|
||||
if (cmd.getActivityCode() != null) {
|
||||
query.eq(LotteryActivity::getActivityCode, cmd.getActivityCode());
|
||||
}
|
||||
if (cmd.getStatus() != null) {
|
||||
query.eq(LotteryActivity::getStatus, cmd.getStatus());
|
||||
}
|
||||
if (cmd.getStartTimeBegin() != null) {
|
||||
query.ge(LotteryActivity::getStartTime, cmd.getStartTimeBegin());
|
||||
}
|
||||
if (cmd.getStartTimeEnd() != null) {
|
||||
query.le(LotteryActivity::getStartTime, cmd.getStartTimeEnd());
|
||||
}
|
||||
|
||||
Page<LotteryActivity> result = query.orderByDesc(LotteryActivity::getCreateTime).page(page);
|
||||
|
||||
List<LotteryActivityDTO> dtoList = result.getRecords().stream()
|
||||
.map(activity -> {
|
||||
LotteryActivityDTO dto = new LotteryActivityDTO();
|
||||
BeanUtils.copyProperties(activity, dto);
|
||||
return dto;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PageResult<LotteryActivityDTO> pageResult = new PageResult<>();
|
||||
pageResult.setCurrent(pageNo);
|
||||
pageResult.setSize(pageSize);
|
||||
pageResult.setTotal(result.getTotal());
|
||||
pageResult.setRecords(dtoList);
|
||||
return ResultResponse.success(pageResult);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
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.inner.endpoint.activity.api.LotteryPrizeClientApi;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 奖品配置ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryPrizeClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryPrizeClientEndpoint implements LotteryPrizeClientApi {
|
||||
|
||||
private final LotteryPrizeService lotteryPrizeService;
|
||||
|
||||
@Override
|
||||
public ResultResponse<List<LotteryPrizeDTO>> listByActivityId(Long activityId) {
|
||||
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery()
|
||||
.eq(LotteryPrize::getActivityId, activityId)
|
||||
.orderByAsc(LotteryPrize::getSortOrder)
|
||||
.list();
|
||||
|
||||
List<LotteryPrizeDTO> dtoList = prizes.stream()
|
||||
.map(this::convertToDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ResultResponse.success(dtoList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<LotteryPrizeDTO> getById(Long id) {
|
||||
LotteryPrize prize = lotteryPrizeService.getById(id);
|
||||
|
||||
if (prize == null) {
|
||||
return ResultResponse.success(null);
|
||||
}
|
||||
|
||||
return ResultResponse.success(convertToDTO(prize));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<Boolean> deductStock(Long id, Integer count) {
|
||||
boolean success = lotteryPrizeService.lambdaUpdate()
|
||||
.eq(LotteryPrize::getId, id)
|
||||
.gt(LotteryPrize::getRemainingStock, 0)
|
||||
.setSql("remaining_stock = remaining_stock - " + count)
|
||||
.update();
|
||||
|
||||
return ResultResponse.success(success);
|
||||
}
|
||||
|
||||
private LotteryPrizeDTO convertToDTO(LotteryPrize prize) {
|
||||
LotteryPrizeDTO dto = new LotteryPrizeDTO();
|
||||
BeanUtils.copyProperties(prize, dto);
|
||||
return dto;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
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.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryPrize;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryPrizeService;
|
||||
import com.red.circle.other.inner.asserts.lottery.LotteryErrorCode;
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryPrizeManageClientApi;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryPrizeSaveCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryPrizeDTO;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 奖品管理ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryPrizeManageClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryPrizeManageClientEndpoint implements LotteryPrizeManageClientApi {
|
||||
|
||||
private final LotteryPrizeService lotteryPrizeService;
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> savePrize(LotteryPrizeSaveCmd cmd) {
|
||||
// 校验活动存在
|
||||
LotteryActivity activity = lotteryActivityService.getById(cmd.getActivityId());
|
||||
ResponseAssert.isTrue(LotteryErrorCode.ACTIVITY_NOT_FOUND, activity != null);
|
||||
|
||||
LotteryPrize prize;
|
||||
if (cmd.getId() != null) {
|
||||
// 更新
|
||||
prize = lotteryPrizeService.getById(cmd.getId());
|
||||
ResponseAssert.isTrue(LotteryErrorCode.PRIZE_NOT_FOUND, prize != null);
|
||||
BeanUtils.copyProperties(cmd, prize);
|
||||
} else {
|
||||
// 新增
|
||||
prize = new LotteryPrize();
|
||||
BeanUtils.copyProperties(cmd, prize);
|
||||
prize.setRemainingStock(cmd.getTotalStock());
|
||||
}
|
||||
|
||||
lotteryPrizeService.saveOrUpdate(prize);
|
||||
|
||||
// 更新活动总库存
|
||||
updateActivityStockInternal(cmd.getActivityId());
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<List<LotteryPrizeDTO>> listByActivityId(Long activityId) {
|
||||
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery()
|
||||
.eq(LotteryPrize::getActivityId, activityId)
|
||||
.orderByAsc(LotteryPrize::getSortOrder)
|
||||
.list();
|
||||
|
||||
List<LotteryPrizeDTO> dtoList = prizes.stream()
|
||||
.map(prize -> {
|
||||
LotteryPrizeDTO dto = new LotteryPrizeDTO();
|
||||
BeanUtils.copyProperties(prize, dto);
|
||||
return dto;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ResultResponse.success(dtoList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> deletePrize(Long id) {
|
||||
LotteryPrize prize = lotteryPrizeService.getById(id);
|
||||
ResponseAssert.isTrue(LotteryErrorCode.PRIZE_NOT_FOUND, prize != null);
|
||||
|
||||
Long activityId = prize.getActivityId();
|
||||
lotteryPrizeService.removeById(id);
|
||||
|
||||
// 更新活动总库存
|
||||
updateActivityStockInternal(activityId);
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> updateActivityStock(Long activityId) {
|
||||
updateActivityStockInternal(activityId);
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新活动总库存(内部方法).
|
||||
*/
|
||||
private void updateActivityStockInternal(Long activityId) {
|
||||
List<LotteryPrize> prizes = lotteryPrizeService.lambdaQuery()
|
||||
.eq(LotteryPrize::getActivityId, activityId)
|
||||
.list();
|
||||
|
||||
int totalStock = prizes.stream()
|
||||
.mapToInt(LotteryPrize::getTotalStock)
|
||||
.sum();
|
||||
|
||||
int remainingStock = prizes.stream()
|
||||
.mapToInt(LotteryPrize::getRemainingStock)
|
||||
.sum();
|
||||
|
||||
lotteryActivityService.lambdaUpdate()
|
||||
.eq(LotteryActivity::getId, activityId)
|
||||
.set(LotteryActivity::getTotalStock, totalStock)
|
||||
.set(LotteryActivity::getConsumedStock, totalStock - remainingStock)
|
||||
.update();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordService;
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryRecordClientApi;
|
||||
import com.red.circle.other.inner.model.dto.activity.LotteryRecordDTO;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 中奖记录ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryRecordClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryRecordClientEndpoint implements LotteryRecordClientApi {
|
||||
|
||||
private final LotteryRecordService lotteryRecordService;
|
||||
|
||||
@Override
|
||||
public ResultResponse<Long> saveRecord(String recordNo, Long userId, Long activityId,
|
||||
Long prizeId, String prizeName, Integer prizeType,
|
||||
Integer isWin) {
|
||||
LotteryRecord record = new LotteryRecord();
|
||||
record.setRecordNo(recordNo);
|
||||
record.setUserId(userId);
|
||||
record.setActivityId(activityId);
|
||||
record.setPrizeId(prizeId);
|
||||
record.setPrizeName(prizeName);
|
||||
record.setPrizeType(prizeType);
|
||||
record.setIsWin(isWin);
|
||||
record.setDrawTime(LocalDateTime.now());
|
||||
record.setPrizeStatus(isWin == 1 ? 0 : null);
|
||||
|
||||
lotteryRecordService.save(record);
|
||||
|
||||
return ResultResponse.success(record.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<LotteryRecordDTO> getByRecordNo(String recordNo) {
|
||||
LotteryRecord record = lotteryRecordService.lambdaQuery()
|
||||
.eq(LotteryRecord::getRecordNo, recordNo)
|
||||
.one();
|
||||
|
||||
if (record == null) {
|
||||
return ResultResponse.success(null);
|
||||
}
|
||||
|
||||
LotteryRecordDTO dto = new LotteryRecordDTO();
|
||||
BeanUtils.copyProperties(record, dto);
|
||||
|
||||
return ResultResponse.success(dto);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryActivity;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryRecord;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryActivityService;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryRecordService;
|
||||
import com.red.circle.other.inner.asserts.lottery.LotteryErrorCode;
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryRecordManageClientApi;
|
||||
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.LotteryRecordDTO;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 中奖记录管理ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryRecordManageClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryRecordManageClientEndpoint implements LotteryRecordManageClientApi {
|
||||
|
||||
private final LotteryRecordService lotteryRecordService;
|
||||
private final LotteryActivityService lotteryActivityService;
|
||||
|
||||
@Override
|
||||
public ResultResponse<PageResult<LotteryRecordDTO>> listRecords(LotteryRecordQryCmd cmd) {
|
||||
Integer pageNo = cmd.getPageNo() != null ? cmd.getPageNo() : 1;
|
||||
Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20;
|
||||
|
||||
Page<LotteryRecord> page = new Page<>(pageNo, pageSize);
|
||||
var query = lotteryRecordService.lambdaQuery();
|
||||
|
||||
if (cmd.getUserId() != null) {
|
||||
query.eq(LotteryRecord::getUserId, cmd.getUserId());
|
||||
}
|
||||
if (cmd.getActivityId() != null) {
|
||||
query.eq(LotteryRecord::getActivityId, cmd.getActivityId());
|
||||
}
|
||||
if (cmd.getActivityCode() != null) {
|
||||
LotteryActivity activity = lotteryActivityService.lambdaQuery()
|
||||
.eq(LotteryActivity::getActivityCode, cmd.getActivityCode())
|
||||
.one();
|
||||
if (activity != null) {
|
||||
query.eq(LotteryRecord::getActivityId, activity.getId());
|
||||
}
|
||||
}
|
||||
if (cmd.getIsWin() != null) {
|
||||
query.eq(LotteryRecord::getIsWin, cmd.getIsWin());
|
||||
}
|
||||
if (cmd.getPrizeStatus() != null) {
|
||||
query.eq(LotteryRecord::getPrizeStatus, cmd.getPrizeStatus());
|
||||
}
|
||||
if (cmd.getDrawTimeBegin() != null) {
|
||||
query.ge(LotteryRecord::getDrawTime, cmd.getDrawTimeBegin());
|
||||
}
|
||||
if (cmd.getDrawTimeEnd() != null) {
|
||||
query.le(LotteryRecord::getDrawTime, cmd.getDrawTimeEnd());
|
||||
}
|
||||
|
||||
Page<LotteryRecord> result = query.orderByDesc(LotteryRecord::getDrawTime).page(page);
|
||||
|
||||
// 查询活动信息
|
||||
List<Long> activityIds = result.getRecords().stream()
|
||||
.map(LotteryRecord::getActivityId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<Long, LotteryActivity> activityMap = lotteryActivityService.lambdaQuery()
|
||||
.in(LotteryActivity::getId, activityIds)
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(LotteryActivity::getId, a -> a));
|
||||
|
||||
List<LotteryRecordDTO> dtoList = result.getRecords().stream()
|
||||
.map(record -> {
|
||||
LotteryRecordDTO dto = new LotteryRecordDTO();
|
||||
BeanUtils.copyProperties(record, dto);
|
||||
|
||||
LotteryActivity activity = activityMap.get(record.getActivityId());
|
||||
if (activity != null) {
|
||||
dto.setActivityName(activity.getActivityName());
|
||||
}
|
||||
|
||||
return dto;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PageResult<LotteryRecordDTO> pageResult = new PageResult<>();
|
||||
pageResult.setCurrent(pageNo);
|
||||
pageResult.setSize(pageSize);
|
||||
pageResult.setTotal(result.getTotal());
|
||||
pageResult.setRecords(dtoList);
|
||||
return ResultResponse.success(pageResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> deliverPrize(Long recordId) {
|
||||
LotteryRecord record = lotteryRecordService.getById(recordId);
|
||||
ResponseAssert.isTrue(LotteryErrorCode.RECORD_NOT_FOUND, record != null);
|
||||
ResponseAssert.isTrue(LotteryErrorCode.NOT_WIN, record.getIsWin() == 1);
|
||||
ResponseAssert.isTrue(LotteryErrorCode.PRIZE_ALREADY_DELIVERED, record.getPrizeStatus() == 0);
|
||||
|
||||
// TODO: 根据奖品类型执行不同的发放逻辑
|
||||
// 1-实物:生成发货单
|
||||
// 2-虚拟币:调用钱包服务
|
||||
// 3-优惠券:调用优惠券服务
|
||||
// 4-积分:调用积分服务
|
||||
|
||||
record.setPrizeStatus(1); // 已发放
|
||||
record.setDeliverTime(LocalDateTime.now());
|
||||
lotteryRecordService.updateById(record);
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
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.LotteryTicketRecord;
|
||||
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.inner.endpoint.activity.api.LotteryTicketClientApi;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 抽奖券ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryTicketClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryTicketClientEndpoint implements LotteryTicketClientApi {
|
||||
|
||||
private final LotteryTicketService lotteryTicketService;
|
||||
private final LotteryTicketRecordService lotteryTicketRecordService;
|
||||
|
||||
@Override
|
||||
public ResultResponse<Integer> getUserTicketCount(Long userId) {
|
||||
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery()
|
||||
.eq(LotteryTicket::getUserId, userId)
|
||||
.eq(LotteryTicket::getStatus, 1)
|
||||
.gt(LotteryTicket::getRemainingCount, 0)
|
||||
.list();
|
||||
|
||||
int totalCount = tickets.stream()
|
||||
.mapToInt(LotteryTicket::getRemainingCount)
|
||||
.sum();
|
||||
|
||||
return ResultResponse.success(totalCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Boolean> deductTicket(Long userId, Integer count) {
|
||||
List<LotteryTicket> tickets = lotteryTicketService.lambdaQuery()
|
||||
.eq(LotteryTicket::getUserId, userId)
|
||||
.eq(LotteryTicket::getStatus, 1)
|
||||
.gt(LotteryTicket::getRemainingCount, 0)
|
||||
.orderByAsc(LotteryTicket::getExpireTime)
|
||||
.list();
|
||||
|
||||
int totalRemaining = tickets.stream()
|
||||
.mapToInt(LotteryTicket::getRemainingCount)
|
||||
.sum();
|
||||
|
||||
if (totalRemaining < count) {
|
||||
return ResultResponse.success(false);
|
||||
}
|
||||
|
||||
int remaining = count;
|
||||
for (LotteryTicket ticket : tickets) {
|
||||
if (remaining <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int deduct = Math.min(remaining, ticket.getRemainingCount());
|
||||
|
||||
lotteryTicketService.lambdaUpdate()
|
||||
.eq(LotteryTicket::getId, ticket.getId())
|
||||
.setSql("used_count = used_count + " + deduct)
|
||||
.setSql("remaining_count = remaining_count - " + deduct)
|
||||
.update();
|
||||
|
||||
// 记录使用
|
||||
LotteryTicketRecord ticketRecord = new LotteryTicketRecord();
|
||||
ticketRecord.setUserId(userId);
|
||||
ticketRecord.setTicketId(ticket.getId());
|
||||
ticketRecord.setChangeCount(-deduct);
|
||||
ticketRecord.setChangeType(2); // 消耗
|
||||
ticketRecord.setRemark("抽奖消耗");
|
||||
lotteryTicketRecordService.save(ticketRecord);
|
||||
|
||||
remaining -= deduct;
|
||||
}
|
||||
|
||||
return ResultResponse.success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Boolean> addTicket(Long userId, Integer count, String source, String sourceId) {
|
||||
LotteryTicket ticket = new LotteryTicket();
|
||||
ticket.setUserId(userId);
|
||||
ticket.setTicketSource(source != null ? source : "SYSTEM");
|
||||
ticket.setSourceId(sourceId);
|
||||
ticket.setTotalCount(count);
|
||||
ticket.setUsedCount(0);
|
||||
ticket.setRemainingCount(count);
|
||||
ticket.setStatus(1);
|
||||
|
||||
lotteryTicketService.save(ticket);
|
||||
|
||||
// 记录发放
|
||||
LotteryTicketRecord ticketRecord = new LotteryTicketRecord();
|
||||
ticketRecord.setUserId(userId);
|
||||
ticketRecord.setTicketId(ticket.getId());
|
||||
ticketRecord.setChangeCount(count);
|
||||
ticketRecord.setChangeType(1); // 发放
|
||||
ticketRecord.setRemark("系统发放");
|
||||
lotteryTicketRecordService.save(ticketRecord);
|
||||
|
||||
return ResultResponse.success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
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.LotteryTicketRecord;
|
||||
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.inner.endpoint.activity.api.LotteryTicketManageClientApi;
|
||||
import com.red.circle.other.inner.model.cmd.activity.LotteryTicketGrantCmd;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 抽奖券管理ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryTicketManageClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryTicketManageClientEndpoint implements LotteryTicketManageClientApi {
|
||||
|
||||
private final LotteryTicketService lotteryTicketService;
|
||||
private final LotteryTicketRecordService lotteryTicketRecordService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultResponse<Void> grantTickets(LotteryTicketGrantCmd cmd) {
|
||||
String ticketSource = cmd.getTicketSource() != null ? cmd.getTicketSource() : "SYSTEM";
|
||||
|
||||
for (Long userId : cmd.getUserIds()) {
|
||||
LotteryTicket ticket = new LotteryTicket();
|
||||
ticket.setUserId(userId);
|
||||
ticket.setTicketSource(ticketSource);
|
||||
ticket.setSourceId(cmd.getSourceId());
|
||||
ticket.setTotalCount(cmd.getCount());
|
||||
ticket.setUsedCount(0);
|
||||
ticket.setRemainingCount(cmd.getCount());
|
||||
ticket.setExpireTime(cmd.getExpireTime());
|
||||
ticket.setStatus(1);
|
||||
lotteryTicketService.save(ticket);
|
||||
|
||||
// 记录发放
|
||||
LotteryTicketRecord ticketRecord = new LotteryTicketRecord();
|
||||
ticketRecord.setUserId(userId);
|
||||
ticketRecord.setTicketId(ticket.getId());
|
||||
ticketRecord.setChangeCount(cmd.getCount());
|
||||
ticketRecord.setChangeType(1); // 发放
|
||||
ticketRecord.setRemark(cmd.getRemark());
|
||||
lotteryTicketRecordService.save(ticketRecord);
|
||||
}
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.red.circle.other.app.inner.endpoint.activity;
|
||||
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserCount;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.LotteryUserCountService;
|
||||
import com.red.circle.other.inner.endpoint.activity.api.LotteryUserCountClientApi;
|
||||
import java.time.LocalDate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 用户抽奖次数统计ClientEndpoint.
|
||||
*
|
||||
* @author system
|
||||
* @since 2025-10-18
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping(value = LotteryUserCountClientApi.API_PREFIX, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@RequiredArgsConstructor
|
||||
public class LotteryUserCountClientEndpoint implements LotteryUserCountClientApi {
|
||||
|
||||
private final LotteryUserCountService lotteryUserCountService;
|
||||
|
||||
@Override
|
||||
public ResultResponse<Integer> getTodayCount(Long userId, Long activityId) {
|
||||
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery()
|
||||
.eq(LotteryUserCount::getUserId, userId)
|
||||
.eq(LotteryUserCount::getActivityId, activityId)
|
||||
.eq(LotteryUserCount::getDrawDate, LocalDate.now())
|
||||
.one();
|
||||
|
||||
int count = userCount != null ? userCount.getDrawCount() : 0;
|
||||
|
||||
return ResultResponse.success(count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<Void> incrDrawCount(Long userId, Long activityId) {
|
||||
LotteryUserCount userCount = lotteryUserCountService.lambdaQuery()
|
||||
.eq(LotteryUserCount::getUserId, userId)
|
||||
.eq(LotteryUserCount::getActivityId, activityId)
|
||||
.eq(LotteryUserCount::getDrawDate, LocalDate.now())
|
||||
.one();
|
||||
|
||||
if (userCount == null) {
|
||||
userCount = new LotteryUserCount();
|
||||
userCount.setUserId(userId);
|
||||
userCount.setActivityId(activityId);
|
||||
userCount.setDrawDate(LocalDate.now());
|
||||
userCount.setDrawCount(1);
|
||||
lotteryUserCountService.save(userCount);
|
||||
} else {
|
||||
lotteryUserCountService.lambdaUpdate()
|
||||
.eq(LotteryUserCount::getId, userCount.getId())
|
||||
.setSql("draw_count = draw_count + 1")
|
||||
.update();
|
||||
}
|
||||
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user