diff --git a/rc-service/lottery_system_init.sql b/rc-service/lottery_system_init.sql new file mode 100644 index 00000000..acc3a266 --- /dev/null +++ b/rc-service/lottery_system_init.sql @@ -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 '用户抽奖次数统计表'; +``` diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityClient.java new file mode 100644 index 00000000..36748640 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityManageClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityManageClient.java new file mode 100644 index 00000000..45876246 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityManageClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityQueryClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityQueryClient.java new file mode 100644 index 00000000..4c99275d --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryActivityQueryClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryPrizeClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryPrizeClient.java new file mode 100644 index 00000000..c8367923 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryPrizeClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryPrizeManageClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryPrizeManageClient.java new file mode 100644 index 00000000..24c72446 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryPrizeManageClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryRecordClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryRecordClient.java new file mode 100644 index 00000000..57c2cbc9 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryRecordClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryRecordManageClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryRecordManageClient.java new file mode 100644 index 00000000..32824e92 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryRecordManageClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryTicketClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryTicketClient.java new file mode 100644 index 00000000..6dcc85c1 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryTicketClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryTicketManageClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryTicketManageClient.java new file mode 100644 index 00000000..791639aa --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryTicketManageClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryUserCountClient.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryUserCountClient.java new file mode 100644 index 00000000..9d4ee60b --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/LotteryUserCountClient.java @@ -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 { + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityClientApi.java new file mode 100644 index 00000000..4a83b211 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityClientApi.java @@ -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 getByActivityCode(@RequestParam("activityCode") String activityCode); + + /** + * 根据活动ID获取活动信息. + */ + @GetMapping("/getById") + ResultResponse getById(@RequestParam("id") Long id); + + /** + * 获取活动列表. + */ + @GetMapping("/list") + ResultResponse> listActivities(); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityManageClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityManageClientApi.java new file mode 100644 index 00000000..8b4feda7 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityManageClientApi.java @@ -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 createActivity(@RequestBody LotteryActivitySaveCmd cmd); + + /** + * 更新活动. + */ + @PutMapping("/update") + ResultResponse updateActivity(@RequestBody LotteryActivitySaveCmd cmd); + + /** + * 更新活动状态. + */ + @PutMapping("/updateStatus") + ResultResponse updateActivityStatus( + @RequestParam("id") Long id, + @RequestParam("status") Integer status + ); + + /** + * 根据ID获取活动. + */ + @GetMapping("/getById") + ResultResponse getById(@RequestParam("id") Long id); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityQueryClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityQueryClientApi.java new file mode 100644 index 00000000..b4d29950 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryActivityQueryClientApi.java @@ -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> listActivities(@RequestBody LotteryActivityQryCmd cmd); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryPrizeClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryPrizeClientApi.java new file mode 100644 index 00000000..44a68ff8 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryPrizeClientApi.java @@ -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> listByActivityId(@RequestParam("activityId") Long activityId); + + /** + * 根据奖品ID获取奖品信息. + */ + @GetMapping("/getById") + ResultResponse getById(@RequestParam("id") Long id); + + /** + * 扣减奖品库存. + */ + @GetMapping("/deductStock") + ResultResponse deductStock(@RequestParam("id") Long id, @RequestParam("count") Integer count); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryPrizeManageClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryPrizeManageClientApi.java new file mode 100644 index 00000000..30a5e5fd --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryPrizeManageClientApi.java @@ -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 savePrize(@RequestBody LotteryPrizeSaveCmd cmd); + + /** + * 根据活动ID获取奖品列表. + */ + @GetMapping("/listByActivityId") + ResultResponse> listByActivityId(@RequestParam("activityId") Long activityId); + + /** + * 删除奖品. + */ + @DeleteMapping("/delete") + ResultResponse deletePrize(@RequestParam("id") Long id); + + /** + * 更新活动总库存. + */ + @PostMapping("/updateActivityStock") + ResultResponse updateActivityStock(@RequestParam("activityId") Long activityId); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryRecordClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryRecordClientApi.java new file mode 100644 index 00000000..3d04ee7f --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryRecordClientApi.java @@ -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 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 getByRecordNo(@RequestParam("recordNo") String recordNo); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryRecordManageClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryRecordManageClientApi.java new file mode 100644 index 00000000..7fc3fcae --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryRecordManageClientApi.java @@ -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> listRecords(@RequestBody LotteryRecordQryCmd cmd); + + /** + * 发放奖品. + */ + @PostMapping("/deliverPrize") + ResultResponse deliverPrize(@RequestParam("recordId") Long recordId); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketClientApi.java new file mode 100644 index 00000000..5002c022 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketClientApi.java @@ -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 getUserTicketCount(@RequestParam("userId") Long userId); + + /** + * 扣减用户抽奖券. + */ + @PostMapping("/deductTicket") + ResultResponse deductTicket( + @RequestParam("userId") Long userId, + @RequestParam("count") Integer count + ); + + /** + * 增加用户抽奖券. + */ + @PostMapping("/addTicket") + ResultResponse addTicket( + @RequestParam("userId") Long userId, + @RequestParam("count") Integer count, + @RequestParam(value = "source", required = false) String source, + @RequestParam(value = "sourceId", required = false) String sourceId + ); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketManageClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketManageClientApi.java new file mode 100644 index 00000000..d2726dbb --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryTicketManageClientApi.java @@ -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 grantTickets(@RequestBody LotteryTicketGrantCmd cmd); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryUserCountClientApi.java b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryUserCountClientApi.java new file mode 100644 index 00000000..245de284 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-api/src/main/java/com/red/circle/other/inner/endpoint/activity/api/LotteryUserCountClientApi.java @@ -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 getTodayCount( + @RequestParam("userId") Long userId, + @RequestParam("activityId") Long activityId + ); + + /** + * 增加用户抽奖次数. + */ + @GetMapping("/incrDrawCount") + ResultResponse incrDrawCount( + @RequestParam("userId") Long userId, + @RequestParam("activityId") Long activityId + ); + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/asserts/lottery/LotteryErrorCode.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/asserts/lottery/LotteryErrorCode.java new file mode 100644 index 00000000..37ffd533 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/asserts/lottery/LotteryErrorCode.java @@ -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(); + } + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryActivityQryCmd.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryActivityQryCmd.java new file mode 100644 index 00000000..8a132208 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryActivityQryCmd.java @@ -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; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryActivitySaveCmd.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryActivitySaveCmd.java new file mode 100644 index 00000000..df62b3a7 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryActivitySaveCmd.java @@ -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; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryPrizeSaveCmd.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryPrizeSaveCmd.java new file mode 100644 index 00000000..591638ce --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryPrizeSaveCmd.java @@ -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; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryRecordQryCmd.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryRecordQryCmd.java new file mode 100644 index 00000000..4599216e --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryRecordQryCmd.java @@ -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; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryTicketGrantCmd.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryTicketGrantCmd.java new file mode 100644 index 00000000..0be986e1 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/cmd/activity/LotteryTicketGrantCmd.java @@ -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 userIds; + + /** + * 发放数量. + */ + @NotNull(message = "发放数量不能为空") + private Integer count; + + /** + * 来源. + */ + private String ticketSource; + + /** + * 来源ID. + */ + private String sourceId; + + /** + * 过期时间. + */ + private LocalDateTime expireTime; + + /** + * 备注. + */ + private String remark; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryActivityDTO.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryActivityDTO.java new file mode 100644 index 00000000..e367fa69 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryActivityDTO.java @@ -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; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryPrizeDTO.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryPrizeDTO.java new file mode 100644 index 00000000..ada4222a --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryPrizeDTO.java @@ -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; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryRecordDTO.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryRecordDTO.java new file mode 100644 index 00000000..f2c1b854 --- /dev/null +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/activity/LotteryRecordDTO.java @@ -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; + +} diff --git a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/activity/LotteryActivityBackRestController.java b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/activity/LotteryActivityBackRestController.java new file mode 100644 index 00000000..c285b661 --- /dev/null +++ b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/app/activity/LotteryActivityBackRestController.java @@ -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 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 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 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); + } + +} diff --git a/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/activity/LotteryActivityBackServiceImpl.java b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/activity/LotteryActivityBackServiceImpl.java new file mode 100644 index 00000000..a88eb3e9 --- /dev/null +++ b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/app/activity/LotteryActivityBackServiceImpl.java @@ -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 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 listPrizes(Long activityId) { + return lotteryPrizeManageClient.listByActivityId(activityId).getBody(); + } + + @Override + public void deletePrize(Long id) { + lotteryPrizeManageClient.deletePrize(id); + } + + @Override + public PageResult 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); + } + +} diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/activity/LotteryActivityBackService.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/activity/LotteryActivityBackService.java new file mode 100644 index 00000000..03bff45e --- /dev/null +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/app/activity/LotteryActivityBackService.java @@ -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 listActivities(LotteryActivityQryCmd cmd); + + /** + * 活动详情. + */ + LotteryActivityDTO getActivity(Long id); + + /** + * 启用/禁用活动. + */ + void updateActivityStatus(Long id, Integer status); + + /** + * 配置奖品. + */ + void savePrize(LotteryPrizeSaveCmd cmd); + + /** + * 奖品列表. + */ + List listPrizes(Long activityId); + + /** + * 删除奖品. + */ + void deletePrize(Long id); + + /** + * 中奖记录列表. + */ + PageResult listRecords(LotteryRecordQryCmd cmd); + + /** + * 发放奖品. + */ + void deliverPrize(Long recordId); + + /** + * 批量发放抽奖券. + */ + void grantTickets(LotteryTicketGrantCmd cmd); + +} diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java new file mode 100644 index 00000000..84731339 --- /dev/null +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java @@ -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; + +/** + *

+ * 抽奖活动 前端控制器. + *

+ * + * @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 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 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 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); + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryActivityDetailQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryActivityDetailQryExe.java new file mode 100644 index 00000000..d4e8b2fa --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryActivityDetailQryExe.java @@ -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 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; + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryActivityListQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryActivityListQryExe.java new file mode 100644 index 00000000..18949cf1 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryActivityListQryExe.java @@ -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 execute(AppExtCommand cmd) { + Long userId = cmd.requiredReqUserId(); + LocalDateTime now = LocalDateTime.now(); + + // 查询进行中的活动 + List 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 activityIds = activities.stream() + .map(LotteryActivity::getId) + .collect(Collectors.toList()); + + Map 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 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; + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryDrawExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryDrawExe.java new file mode 100644 index 00000000..83f5ab0c --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryDrawExe.java @@ -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 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 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; + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryRecordQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryRecordQryExe.java new file mode 100644 index 00000000..90875937 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryRecordQryExe.java @@ -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 execute(LotteryRecordQryCmd cmd) { + Long userId = cmd.requiredReqUserId(); + Integer pageNo = cmd.getPageNo() != null ? cmd.getPageNo() : 1; + Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20; + + // 构建查询条件 + Page 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 recordPage = query.orderByDesc(LotteryRecord::getDrawTime).page(page); + + // 查询关联数据 + List activityIds = recordPage.getRecords().stream() + .map(LotteryRecord::getActivityId) + .distinct() + .collect(Collectors.toList()); + + List prizeIds = recordPage.getRecords().stream() + .map(LotteryRecord::getPrizeId) + .filter(id -> id != null) + .distinct() + .collect(Collectors.toList()); + + Map activityMap = lotteryActivityService.lambdaQuery() + .in(LotteryActivity::getId, activityIds) + .list() + .stream() + .collect(Collectors.toMap(LotteryActivity::getId, a -> a)); + + Map prizeMap = lotteryPrizeService.lambdaQuery() + .in(LotteryPrize::getId, prizeIds) + .list() + .stream() + .collect(Collectors.toMap(LotteryPrize::getId, p -> p)); + + // 转换为CO + List 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 activityMap, + Map 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; + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTicketCountQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTicketCountQryExe.java new file mode 100644 index 00000000..28c163cc --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTicketCountQryExe.java @@ -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 tickets = lotteryTicketService.lambdaQuery() + .eq(LotteryTicket::getUserId, userId) + .eq(LotteryTicket::getStatus, 1) + .gt(LotteryTicket::getRemainingCount, 0) + .list(); + + return tickets.stream() + .mapToInt(LotteryTicket::getRemainingCount) + .sum(); + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTicketQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTicketQryExe.java new file mode 100644 index 00000000..a5ef4498 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTicketQryExe.java @@ -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 execute(AppExtCommand cmd) { + Long userId = cmd.requiredReqUserId(); + + List 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; + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityServiceImpl.java new file mode 100644 index 00000000..2d8372af --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityServiceImpl.java @@ -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 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 listMyRecords(LotteryRecordQryCmd cmd) { + return lotteryRecordQryExe.execute(cmd); + } + + @Override + public List listMyTickets(AppExtCommand cmd) { + return lotteryTicketQryExe.execute(cmd); + } + + @Override + public Integer getMyTicketCount(AppExtCommand cmd) { + return lotteryTicketCountQryExe.execute(cmd); + } + +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryServiceImpl.java new file mode 100644 index 00000000..cff72413 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryServiceImpl.java @@ -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 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 listMyRecords(LotteryRecordQryCmd cmd) { + return lotteryRecordQryExe.execute(cmd); + } + + @Override + public List listMyTickets(AppExtCommand cmd) { + return lotteryTicketQryExe.execute(cmd); + } + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryActivityCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryActivityCO.java new file mode 100644 index 00000000..a8234b9c --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryActivityCO.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryActivityDetailCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryActivityDetailCO.java new file mode 100644 index 00000000..0b173441 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryActivityDetailCO.java @@ -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 prizeList; + + /** + * 用户抽奖券数量. + */ + private Integer userTicketCount; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryDrawResultCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryDrawResultCO.java new file mode 100644 index 00000000..c1ff5a79 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryDrawResultCO.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryPrizeCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryPrizeCO.java new file mode 100644 index 00000000..667eb2ce --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryPrizeCO.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryRecordCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryRecordCO.java new file mode 100644 index 00000000..4aecd9c2 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryRecordCO.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryTicketCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryTicketCO.java new file mode 100644 index 00000000..e43c54a9 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/LotteryTicketCO.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryDrawCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryDrawCmd.java new file mode 100644 index 00000000..88e5e679 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryDrawCmd.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryRecordQryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryRecordQryCmd.java new file mode 100644 index 00000000..8a875def --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryRecordQryCmd.java @@ -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; + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityService.java new file mode 100644 index 00000000..7ef198b3 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityService.java @@ -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 listValidActivities(AppExtCommand cmd); + + /** + * 获取活动详情. + */ + LotteryActivityDetailCO getActivityDetail(String activityCode, AppExtCommand cmd); + + /** + * 执行抽奖. + */ + LotteryDrawResultCO draw(LotteryDrawCmd cmd); + + /** + * 查询我的中奖记录. + */ + PageResult listMyRecords(LotteryRecordQryCmd cmd); + + /** + * 查询我的抽奖券. + */ + List listMyTickets(AppExtCommand cmd); + + /** + * 获取抽奖券总数. + */ + Integer getMyTicketCount(AppExtCommand cmd); + +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryService.java new file mode 100644 index 00000000..c978b16e --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryService.java @@ -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 listActiveActivities(AppExtCommand cmd); + + /** + * 获取活动详情. + */ + LotteryActivityDetailCO getActivityDetail(String activityCode, AppExtCommand cmd); + + /** + * 执行抽奖. + */ + LotteryDrawResultCO draw(LotteryDrawCmd cmd); + + /** + * 查询用户抽奖记录. + */ + List listMyRecords(LotteryRecordQryCmd cmd); + + /** + * 查询用户抽奖券. + */ + List listMyTickets(AppExtCommand cmd); + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryActivityMapper.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryActivityMapper.java new file mode 100644 index 00000000..add7d526 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryActivityMapper.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryPrizeMapper.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryPrizeMapper.java new file mode 100644 index 00000000..4e7d0815 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryPrizeMapper.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryRecordMapper.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryRecordMapper.java new file mode 100644 index 00000000..483a80cb --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryRecordMapper.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryTicketMapper.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryTicketMapper.java new file mode 100644 index 00000000..34b04817 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryTicketMapper.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryTicketRecordMapper.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryTicketRecordMapper.java new file mode 100644 index 00000000..3488fa10 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryTicketRecordMapper.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryUserCountMapper.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryUserCountMapper.java new file mode 100644 index 00000000..7ae2fffc --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/activity/LotteryUserCountMapper.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryActivity.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryActivity.java new file mode 100644 index 00000000..089209b3 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryActivity.java @@ -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; + +/** + *

+ * 抽奖活动表. + *

+ * + * @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; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryPrize.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryPrize.java new file mode 100644 index 00000000..e1add975 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryPrize.java @@ -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; + +/** + *

+ * 奖品配置表. + *

+ * + * @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; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryRecord.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryRecord.java new file mode 100644 index 00000000..8c992ad0 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryRecord.java @@ -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; + +/** + *

+ * 中奖记录表. + *

+ * + * @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; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryTicket.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryTicket.java new file mode 100644 index 00000000..94030abf --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryTicket.java @@ -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; + +/** + *

+ * 抽奖券表. + *

+ * + * @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; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryTicketRecord.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryTicketRecord.java new file mode 100644 index 00000000..11ba7e2e --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryTicketRecord.java @@ -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; + +/** + *

+ * 抽奖券使用记录表. + *

+ * + * @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; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryUserCount.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryUserCount.java new file mode 100644 index 00000000..48e6ecbd --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/activity/LotteryUserCount.java @@ -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; + +/** + *

+ * 用户抽奖次数统计表. + *

+ * + * @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; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryActivityService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryActivityService.java new file mode 100644 index 00000000..f786327a --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryActivityService.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryPrizeService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryPrizeService.java new file mode 100644 index 00000000..0fbc3242 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryPrizeService.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryRecordService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryRecordService.java new file mode 100644 index 00000000..f0cf47bf --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryRecordService.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryTicketRecordService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryTicketRecordService.java new file mode 100644 index 00000000..2cb629c0 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryTicketRecordService.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryTicketService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryTicketService.java new file mode 100644 index 00000000..5c203a82 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryTicketService.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryUserCountService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryUserCountService.java new file mode 100644 index 00000000..001f0a69 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/LotteryUserCountService.java @@ -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 { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryActivityServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryActivityServiceImpl.java new file mode 100644 index 00000000..c6e3f48d --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryActivityServiceImpl.java @@ -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 + implements LotteryActivityService { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryPrizeServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryPrizeServiceImpl.java new file mode 100644 index 00000000..d73f38e6 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryPrizeServiceImpl.java @@ -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 + implements LotteryPrizeService { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryRecordServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryRecordServiceImpl.java new file mode 100644 index 00000000..e170e215 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryRecordServiceImpl.java @@ -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 + implements LotteryRecordService { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryTicketRecordServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryTicketRecordServiceImpl.java new file mode 100644 index 00000000..44bf4eb0 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryTicketRecordServiceImpl.java @@ -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 + implements LotteryTicketRecordService { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryTicketServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryTicketServiceImpl.java new file mode 100644 index 00000000..8bce3b76 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryTicketServiceImpl.java @@ -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 + implements LotteryTicketService { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryUserCountServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryUserCountServiceImpl.java new file mode 100644 index 00000000..576be188 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/activity/impl/LotteryUserCountServiceImpl.java @@ -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 + implements LotteryUserCountService { + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityClientEndpoint.java new file mode 100644 index 00000000..ab746c36 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityClientEndpoint.java @@ -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 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 getById(Long id) { + LotteryActivity activity = lotteryActivityService.getById(id); + + if (activity == null) { + return ResultResponse.success(null); + } + + return ResultResponse.success(convertToDTO(activity)); + } + + @Override + public ResultResponse> listActivities() { + List activities = lotteryActivityService.lambdaQuery() + .eq(LotteryActivity::getStatus, 1) + .orderByDesc(LotteryActivity::getCreateTime) + .list(); + + List 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; + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityManageClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityManageClientEndpoint.java new file mode 100644 index 00000000..999b7300 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityManageClientEndpoint.java @@ -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 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 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 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 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); + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityQueryClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityQueryClientEndpoint.java new file mode 100644 index 00000000..2389517e --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryActivityQueryClientEndpoint.java @@ -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> listActivities(LotteryActivityQryCmd cmd) { + Integer pageNo = cmd.getPageNo() != null ? cmd.getPageNo() : 1; + Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20; + + Page 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 result = query.orderByDesc(LotteryActivity::getCreateTime).page(page); + + List dtoList = result.getRecords().stream() + .map(activity -> { + LotteryActivityDTO dto = new LotteryActivityDTO(); + BeanUtils.copyProperties(activity, dto); + return dto; + }) + .collect(Collectors.toList()); + + PageResult pageResult = new PageResult<>(); + pageResult.setCurrent(pageNo); + pageResult.setSize(pageSize); + pageResult.setTotal(result.getTotal()); + pageResult.setRecords(dtoList); + return ResultResponse.success(pageResult); + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryPrizeClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryPrizeClientEndpoint.java new file mode 100644 index 00000000..9253b630 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryPrizeClientEndpoint.java @@ -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> listByActivityId(Long activityId) { + List prizes = lotteryPrizeService.lambdaQuery() + .eq(LotteryPrize::getActivityId, activityId) + .orderByAsc(LotteryPrize::getSortOrder) + .list(); + + List dtoList = prizes.stream() + .map(this::convertToDTO) + .collect(Collectors.toList()); + + return ResultResponse.success(dtoList); + } + + @Override + public ResultResponse getById(Long id) { + LotteryPrize prize = lotteryPrizeService.getById(id); + + if (prize == null) { + return ResultResponse.success(null); + } + + return ResultResponse.success(convertToDTO(prize)); + } + + @Override + public ResultResponse 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; + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryPrizeManageClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryPrizeManageClientEndpoint.java new file mode 100644 index 00000000..b48155a4 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryPrizeManageClientEndpoint.java @@ -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 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> listByActivityId(Long activityId) { + List prizes = lotteryPrizeService.lambdaQuery() + .eq(LotteryPrize::getActivityId, activityId) + .orderByAsc(LotteryPrize::getSortOrder) + .list(); + + List 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 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 updateActivityStock(Long activityId) { + updateActivityStockInternal(activityId); + return ResultResponse.success(); + } + + /** + * 更新活动总库存(内部方法). + */ + private void updateActivityStockInternal(Long activityId) { + List 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(); + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryRecordClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryRecordClientEndpoint.java new file mode 100644 index 00000000..0a8377c9 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryRecordClientEndpoint.java @@ -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 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 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); + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryRecordManageClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryRecordManageClientEndpoint.java new file mode 100644 index 00000000..f94c2e11 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryRecordManageClientEndpoint.java @@ -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> listRecords(LotteryRecordQryCmd cmd) { + Integer pageNo = cmd.getPageNo() != null ? cmd.getPageNo() : 1; + Integer pageSize = cmd.getPageSize() != null ? cmd.getPageSize() : 20; + + Page 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 result = query.orderByDesc(LotteryRecord::getDrawTime).page(page); + + // 查询活动信息 + List activityIds = result.getRecords().stream() + .map(LotteryRecord::getActivityId) + .distinct() + .collect(Collectors.toList()); + + Map activityMap = lotteryActivityService.lambdaQuery() + .in(LotteryActivity::getId, activityIds) + .list() + .stream() + .collect(Collectors.toMap(LotteryActivity::getId, a -> a)); + + List 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 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 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(); + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketClientEndpoint.java new file mode 100644 index 00000000..0f14f253 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketClientEndpoint.java @@ -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 getUserTicketCount(Long userId) { + List 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 deductTicket(Long userId, Integer count) { + List 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 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); + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketManageClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketManageClientEndpoint.java new file mode 100644 index 00000000..3146aa54 --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryTicketManageClientEndpoint.java @@ -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 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(); + } + +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryUserCountClientEndpoint.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryUserCountClientEndpoint.java new file mode 100644 index 00000000..8a6fdc9d --- /dev/null +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/endpoint/activity/LotteryUserCountClientEndpoint.java @@ -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 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 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(); + } + +}