券列表和发券处理

This commit is contained in:
tianfeng 2025-11-06 17:42:05 +08:00
parent b3ae76ea45
commit b1721cf894
8 changed files with 63 additions and 13 deletions

View File

@ -75,12 +75,17 @@ public enum OtherErrorCode implements IResponseErrorCode {
/** /**
* 批量赠送用户数量超过限制 * 批量赠送用户数量超过限制
*/ */
PROP_COUPON_BATCH_USER_LIMIT(30, "Batch user limit exceeded"), PROP_COUPON_BATCH_USER_LIMIT(3212, "Batch user limit exceeded"),
/** /**
* 道具券有效天数超过限制 * 道具券有效天数超过限制
*/ */
PROP_COUPON_VALID_DAYS_LIMIT(365, "Valid days limit exceeded"), PROP_COUPON_VALID_DAYS_LIMIT(3213, "Valid days limit exceeded"),
/**
* 道具已下架
*/
PROP_COUPON_OFF(3214, "This prop has been taken off the shelves"),
; ;
private final int code; private final int code;

View File

@ -3,6 +3,7 @@ package com.red.circle.other.adapter.app.props;
import com.red.circle.framework.dto.PageResult; import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.app.dto.clientobject.PropCouponCO; import com.red.circle.other.app.dto.clientobject.PropCouponCO;
import com.red.circle.other.app.dto.clientobject.PropCouponRecordCO; import com.red.circle.other.app.dto.clientobject.PropCouponRecordCO;
import com.red.circle.other.app.dto.cmd.PropCouponGrantCmd;
import com.red.circle.other.app.dto.cmd.PropCouponQueryCmd; import com.red.circle.other.app.dto.cmd.PropCouponQueryCmd;
import com.red.circle.other.app.dto.cmd.PropCouponSendCmd; import com.red.circle.other.app.dto.cmd.PropCouponSendCmd;
import com.red.circle.other.app.dto.cmd.PropCouponUseCmd; import com.red.circle.other.app.dto.cmd.PropCouponUseCmd;
@ -55,4 +56,13 @@ public class PropCouponRestController {
public PageResult<PropCouponRecordCO> queryUseRecords(@RequestBody @Validated PropCouponQueryCmd cmd) { public PageResult<PropCouponRecordCO> queryUseRecords(@RequestBody @Validated PropCouponQueryCmd cmd) {
return propCouponService.queryUseRecords(cmd); return propCouponService.queryUseRecords(cmd);
} }
/**
* 发放道具券
*/
@PostMapping("/grant")
public void grantCoupons(@RequestBody @Validated PropCouponGrantCmd cmd) {
propCouponService.grantCoupons(cmd);
}
} }

View File

@ -10,8 +10,14 @@ import com.red.circle.other.domain.propcoupon.PropCoupon;
import com.red.circle.other.domain.propcoupon.PropCouponSource; import com.red.circle.other.domain.propcoupon.PropCouponSource;
import com.red.circle.other.domain.propcoupon.PropCouponStatus; import com.red.circle.other.domain.propcoupon.PropCouponStatus;
import com.red.circle.other.domain.propcoupon.PropCouponType; import com.red.circle.other.domain.propcoupon.PropCouponType;
import com.red.circle.other.infra.database.rds.entity.props.PropsCommodityStore;
import com.red.circle.other.infra.database.rds.service.props.PropsCommodityStoreService;
import com.red.circle.other.inner.asserts.OtherErrorCode; import com.red.circle.other.inner.asserts.OtherErrorCode;
import com.red.circle.other.inner.endpoint.material.props.PropsCommodityStoreClient;
import com.red.circle.other.inner.endpoint.material.props.PropsSourceClient;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient; import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.model.dto.material.PropsCommodityStoreDTO;
import com.red.circle.other.inner.model.dto.material.PropsResourcesDTO;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO; import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.sequence.IdWorkerUtils; import com.red.circle.tool.core.sequence.IdWorkerUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -40,6 +46,8 @@ public class PropCouponGrantCmdExe {
private final PropCouponGateway propCouponGateway; private final PropCouponGateway propCouponGateway;
private final UserProfileClient userProfileClient; private final UserProfileClient userProfileClient;
private final OfficialNoticeClient officialNoticeClient; private final OfficialNoticeClient officialNoticeClient;
private final PropsSourceClient propsSourceClient;
private final PropsCommodityStoreService propsCommodityStoreService;
/** /**
* 执行后台赠送道具券 * 执行后台赠送道具券
@ -53,11 +61,22 @@ public class PropCouponGrantCmdExe {
Set<Long> userIds = Set.copyOf(cmd.getUserIds()); Set<Long> userIds = Set.copyOf(cmd.getUserIds());
Map<Long, UserProfileDTO> userMap = validateUsers(userIds); Map<Long, UserProfileDTO> userMap = validateUsers(userIds);
// 3. 解析券类型 // 4. 批量生成券
PropCouponType couponType = PropCouponType.getByCode(cmd.getCouponType()); PropsCommodityStore commodityStore = propsCommodityStoreService.getById(cmd.getPropId());
ResponseAssert.notNull(OtherErrorCode.PROP_COUPON_PROP_NOT_FOUND, commodityStore);
ResponseAssert.isTrue(OtherErrorCode.PROP_COUPON_OFF, commodityStore.getShelfStatus());
PropCouponType couponType = PropCouponType.getByName(commodityStore.getPropsType());
ResponseAssert.notNull(OtherErrorCode.PROP_COUPON_TYPE_NOT_SUPPORT, couponType); ResponseAssert.notNull(OtherErrorCode.PROP_COUPON_TYPE_NOT_SUPPORT, couponType);
// 4. 批量生成券 PropsResourcesDTO propsResourcesDTO = ResponseAssert.requiredSuccess(
propsSourceClient.getById(commodityStore.getSourceId()));
ResponseAssert.notNull(OtherErrorCode.PROP_COUPON_PROP_NOT_FOUND, propsResourcesDTO);
cmd.setPropIcon(propsResourcesDTO.getCover());
cmd.setPropName(propsResourcesDTO.getName());
cmd.setCouponType(couponType.getCode());
List<PropCoupon> propCoupons = generateCoupons(cmd, couponType, userMap.keySet()); List<PropCoupon> propCoupons = generateCoupons(cmd, couponType, userMap.keySet());
// 5. 批量插入券记录 // 5. 批量插入券记录
@ -112,6 +131,7 @@ public class PropCouponGrantCmdExe {
propCoupon.setUserId(userId); propCoupon.setUserId(userId);
propCoupon.setCouponType(couponType); propCoupon.setCouponType(couponType);
propCoupon.setPropId(cmd.getPropId()); propCoupon.setPropId(cmd.getPropId());
propCoupon.setPropIcon(cmd.getPropIcon());
propCoupon.setPropName(cmd.getPropName()); propCoupon.setPropName(cmd.getPropName());
propCoupon.setValidDays(cmd.getValidDays()); propCoupon.setValidDays(cmd.getValidDays());
propCoupon.setStatus(PropCouponStatus.UNUSED); propCoupon.setStatus(PropCouponStatus.UNUSED);
@ -133,7 +153,7 @@ public class PropCouponGrantCmdExe {
// 使用雪花算法生成唯一ID // 使用雪花算法生成唯一ID
long id = IdWorkerUtils.getId(); long id = IdWorkerUtils.getId();
// 格式: COUPON + 时间戳 + ID // 格式: COUPON + 时间戳 + ID
return String.format("COUPON%d%d", System.currentTimeMillis(), id); return String.format("COUPON%d", id);
} }
/** /**

View File

@ -119,7 +119,7 @@ public class PropCouponUseCmdExe {
giveProps(userId, propId, ConsolePropsTypeEnum.RIDE.getName(), validDays); giveProps(userId, propId, ConsolePropsTypeEnum.RIDE.getName(), validDays);
break; break;
case VIP: case NOBLE_VIP:
// 赠送VIP贵族VIP // 赠送VIP贵族VIP
PropsNobleVipAbilityDTO vipAbility = getVipAbilityBySysOriginSourceId(propId, SysOriginPlatformEnum.LIKEI.name()); PropsNobleVipAbilityDTO vipAbility = getVipAbilityBySysOriginSourceId(propId, SysOriginPlatformEnum.LIKEI.name());
giveProps(userId, propId, ConsolePropsTypeEnum.NOBLE_VIP.getName(), validDays); giveProps(userId, propId, ConsolePropsTypeEnum.NOBLE_VIP.getName(), validDays);

View File

@ -1,8 +1,10 @@
package com.red.circle.other.app.dto.cmd; package com.red.circle.other.app.dto.cmd;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List; import java.util.List;
@ -12,13 +14,13 @@ import java.util.List;
* @author system * @author system
* @date 2025-11-05 * @date 2025-11-05
*/ */
@EqualsAndHashCode(callSuper = true)
@Data @Data
public class PropCouponGrantCmd { public class PropCouponGrantCmd extends AppExtCommand {
/** /**
* 券类型1头像框 2座驾 3VIP 4聊天气泡 5主题 6资料卡 7飘屏 8徽章 9靓号 * 券类型1头像框 2座驾 3VIP 4聊天气泡 5主题 6资料卡 7飘屏 8徽章 9靓号
*/ */
@NotNull(message = "券类型不能为空")
private Integer couponType; private Integer couponType;
/** /**
@ -27,10 +29,11 @@ public class PropCouponGrantCmd {
@NotNull(message = "道具ID不能为空") @NotNull(message = "道具ID不能为空")
private Long propId; private Long propId;
private String propIcon;
/** /**
* 道具名称 * 道具名称
*/ */
@NotBlank(message = "道具名称不能为空")
private String propName; private String propName;
/** /**

View File

@ -26,7 +26,7 @@ public enum PropCouponType {
/** /**
* VIP * VIP
*/ */
VIP(3, "VIP"), NOBLE_VIP(3, "VIP"),
/** /**
* 聊天气泡 * 聊天气泡
@ -75,4 +75,14 @@ public enum PropCouponType {
} }
return null; return null;
} }
public static PropCouponType getByName(String name) {
for (PropCouponType type : values()) {
if (type.name().equals(name)) {
return type;
}
}
return null;
}
} }

View File

@ -15,12 +15,12 @@ public enum RankingActivityType {
/** /**
* 革命日 * 革命日
*/ */
REVOLUTION_DAY(1, "革命日", "统计用户送礼消费排行"), REVOLUTION_DAY(1, "革命日", "统计送礼消费排行"),
/** /**
* 英雄日 * 英雄日
*/ */
HEROES_DAY(2, "英雄日", "统计主播收礼收入排行"), HEROES_DAY(2, "英雄日", "统计送礼物消费排行"),
/** /**
* 充值榜 * 充值榜

View File

@ -86,6 +86,7 @@ public class PropCouponGatewayImpl implements PropCouponGateway {
wrapper.eq(PropCouponDO::getStatus, status.getCode()); wrapper.eq(PropCouponDO::getStatus, status.getCode());
} }
wrapper.gt(PropCouponDO::getExpireTime, LocalDateTime.now()); wrapper.gt(PropCouponDO::getExpireTime, LocalDateTime.now());
wrapper.orderByAsc(PropCouponDO::getExpireTime);
wrapper.orderByDesc(PropCouponDO::getCreateTime); wrapper.orderByDesc(PropCouponDO::getCreateTime);
Page<PropCouponDO> page = new Page<>(pageNo, pageSize); Page<PropCouponDO> page = new Page<>(pageNo, pageSize);
@ -160,6 +161,7 @@ public class PropCouponGatewayImpl implements PropCouponGateway {
propCouponDO.setUserId(propCoupon.getUserId()); propCouponDO.setUserId(propCoupon.getUserId());
propCouponDO.setCouponType(propCoupon.getCouponType() != null ? propCoupon.getCouponType().getCode() : null); propCouponDO.setCouponType(propCoupon.getCouponType() != null ? propCoupon.getCouponType().getCode() : null);
propCouponDO.setPropId(propCoupon.getPropId()); propCouponDO.setPropId(propCoupon.getPropId());
propCouponDO.setPropIcon(propCoupon.getPropIcon());
propCouponDO.setPropName(propCoupon.getPropName()); propCouponDO.setPropName(propCoupon.getPropName());
propCouponDO.setValidDays(propCoupon.getValidDays()); propCouponDO.setValidDays(propCoupon.getValidDays());
propCouponDO.setStatus(propCoupon.getStatus() != null ? propCoupon.getStatus().getCode() : null); propCouponDO.setStatus(propCoupon.getStatus() != null ? propCoupon.getStatus().getCode() : null);