券列表和发券处理

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;

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.other.app.dto.clientobject.PropCouponCO;
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.PropCouponSendCmd;
import com.red.circle.other.app.dto.cmd.PropCouponUseCmd;
@ -55,4 +56,13 @@ public class PropCouponRestController {
public PageResult<PropCouponRecordCO> queryUseRecords(@RequestBody @Validated PropCouponQueryCmd 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.PropCouponStatus;
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.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.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.tool.core.sequence.IdWorkerUtils;
import lombok.RequiredArgsConstructor;
@ -40,6 +46,8 @@ public class PropCouponGrantCmdExe {
private final PropCouponGateway propCouponGateway;
private final UserProfileClient userProfileClient;
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());
Map<Long, UserProfileDTO> userMap = validateUsers(userIds);
// 3. 解析券类型
PropCouponType couponType = PropCouponType.getByCode(cmd.getCouponType());
// 4. 批量生成券
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);
// 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());
// 5. 批量插入券记录
@ -112,6 +131,7 @@ public class PropCouponGrantCmdExe {
propCoupon.setUserId(userId);
propCoupon.setCouponType(couponType);
propCoupon.setPropId(cmd.getPropId());
propCoupon.setPropIcon(cmd.getPropIcon());
propCoupon.setPropName(cmd.getPropName());
propCoupon.setValidDays(cmd.getValidDays());
propCoupon.setStatus(PropCouponStatus.UNUSED);
@ -133,7 +153,7 @@ public class PropCouponGrantCmdExe {
// 使用雪花算法生成唯一ID
long id = IdWorkerUtils.getId();
// 格式: 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);
break;
case VIP:
case NOBLE_VIP:
// 赠送VIP贵族VIP
PropsNobleVipAbilityDTO vipAbility = getVipAbilityBySysOriginSourceId(propId, SysOriginPlatformEnum.LIKEI.name());
giveProps(userId, propId, ConsolePropsTypeEnum.NOBLE_VIP.getName(), validDays);

View File

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

View File

@ -26,7 +26,7 @@ public enum PropCouponType {
/**
* VIP
*/
VIP(3, "VIP"),
NOBLE_VIP(3, "VIP"),
/**
* 聊天气泡
@ -75,4 +75,14 @@ public enum PropCouponType {
}
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.gt(PropCouponDO::getExpireTime, LocalDateTime.now());
wrapper.orderByAsc(PropCouponDO::getExpireTime);
wrapper.orderByDesc(PropCouponDO::getCreateTime);
Page<PropCouponDO> page = new Page<>(pageNo, pageSize);
@ -160,6 +161,7 @@ public class PropCouponGatewayImpl implements PropCouponGateway {
propCouponDO.setUserId(propCoupon.getUserId());
propCouponDO.setCouponType(propCoupon.getCouponType() != null ? propCoupon.getCouponType().getCode() : null);
propCouponDO.setPropId(propCoupon.getPropId());
propCouponDO.setPropIcon(propCoupon.getPropIcon());
propCouponDO.setPropName(propCoupon.getPropName());
propCouponDO.setValidDays(propCoupon.getValidDays());
propCouponDO.setStatus(propCoupon.getStatus() != null ? propCoupon.getStatus().getCode() : null);