新增荣誉徽章佩戴事件

This commit is contained in:
tianfeng 2025-11-21 15:46:28 +08:00
parent dd7017e728
commit 4735496345
8 changed files with 286 additions and 37 deletions

View File

@ -0,0 +1,50 @@
package com.red.circle.mq.business.model.event;
import java.io.Serial;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 徽章操作事件消息.
*
* @author system
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class BadgeOperateEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 用户id.
*/
private Long userId;
/**
* 徽章Key.
*/
private String badgeKey;
/**
* 操作类型: WEAR-佩戴, REMOVE-移除.
*/
private String operationType;
/**
* 操作类型枚举.
*/
public enum OperationType {
/**
* 佩戴徽章.
*/
WEAR,
/**
* 移除徽章.
*/
REMOVE
}
}

View File

@ -62,6 +62,11 @@ public interface QueueNameConstant {
*/
String BADGE_CHECK = "BADGE_CHECK";
/**
* 徽章操作.
*/
String BADGE_OPERATE = "BADGE_OPERATE";
/**
* 红包游戏.
*/

View File

@ -4,6 +4,7 @@ import com.red.circle.component.mq.MessageEvent;
import com.red.circle.component.mq.service.FixedTopic;
import com.red.circle.component.mq.service.SenderService;
import com.red.circle.mq.business.model.event.BadgeEvent;
import com.red.circle.mq.business.model.event.BadgeOperateEvent;
import com.red.circle.mq.business.model.event.user.AccountBeautifulNumberEvent;
import com.red.circle.mq.business.model.event.user.CpApplyEvent;
import com.red.circle.mq.business.model.event.user.LoginLoggerEvent;
@ -12,6 +13,7 @@ import com.red.circle.mq.business.model.event.user.UserHeartbeatEvent;
import com.red.circle.mq.business.model.event.user.UserOnlineStatusEvent;
import com.red.circle.mq.rocket.business.streams.AccountBeautifulNumberSink;
import com.red.circle.mq.rocket.business.streams.BadgeCheckSink;
import com.red.circle.mq.rocket.business.streams.BadgeOperateSink;
import com.red.circle.mq.rocket.business.streams.CpApplySink;
import com.red.circle.mq.rocket.business.streams.LoginRegisterLoggerSink;
import com.red.circle.mq.rocket.business.streams.OnlineStatusUploadSink;
@ -123,5 +125,24 @@ public class UserMqMessageService {
.build());
}
/**
* 发送徽章操作事件.
*
* @param userId 用户ID
* @param badgeKey 徽章Key
* @param operationType 操作类型: WEAR-佩戴, REMOVE-移除
*/
public void sendBadgeOperateEvent(Long userId, String badgeKey, String operationType) {
senderService.sendEventMessage(MessageEvent.builder()
.consumeId(IdWorkerUtils.getIdStr())
.topic(FixedTopic.RC_DEFAULT_APP_ORDINARY)
.tag(BadgeOperateSink.TAG)
.body(new BadgeOperateEvent()
.setUserId(userId)
.setBadgeKey(badgeKey)
.setOperationType(operationType)
)
.build());
}
}

View File

@ -0,0 +1,15 @@
package com.red.circle.mq.rocket.business.streams;
import com.red.circle.mq.rocket.business.constant.QueueNameConstant;
/**
* 徽章操作.
*
* @author system
*/
public interface BadgeOperateSink {
String INPUT = QueueNameConstant.BADGE_OPERATE;
String TAG = "badge_operate_v1";
}

View File

@ -27,33 +27,49 @@ public enum BadgeKeyEnum {
*/
FORTUNE_ROOM,
/**
* 红包徽章.
*/
LUCK_BAG,
/**
* 签到徽章.
*/
CHECK_IN,
/**
* 充值徽章
*/
RECHARGE,
/**
* TODO 需要重构.
* 管理员徽章.
* 经理徽章
*/
MANAGER,
/**
* 充值代理徽章
*/
RECHARGE_AGENCY,
/**
* 代理徽章
*/
AGENCY,
/**
* 主播徽章
*/
HOST,
/**
* 管理员徽章
*/
ADMIN,
/**
* BD领导徽章
*/
BD_LEADER,
/**
* 超级管理员徽章
*/
@Deprecated
SUPER_ADMIN,
/**
* TODO 需要重构.
* 管理员.
* BD徽章
*/
@Deprecated
ADMIN
BD,
}

View File

@ -0,0 +1,145 @@
package com.red.circle.other.app.listener;
import com.google.common.collect.Sets;
import com.red.circle.component.mq.MessageEventProcess;
import com.red.circle.component.mq.MessageEventProcessDescribe;
import com.red.circle.component.mq.config.RocketMqMessageListener;
import com.red.circle.component.mq.service.Action;
import com.red.circle.component.mq.service.ConsumerMessage;
import com.red.circle.component.mq.service.MessageListener;
import com.red.circle.mq.business.model.event.BadgeOperateEvent;
import com.red.circle.mq.rocket.business.streams.BadgeOperateSink;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.rds.entity.badge.BadgeBackpack;
import com.red.circle.other.infra.database.rds.entity.badge.BadgeConfig;
import com.red.circle.other.infra.database.rds.service.badge.BadgeBackpackService;
import com.red.circle.other.infra.database.rds.service.badge.BadgeConfigService;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import com.red.circle.other.inner.enums.material.BadgeBackpackExpireTypeEnum;
import com.red.circle.other.inner.model.dto.user.props.UserUseBadgeDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 徽章操作处理.
*
* @author system
*/
@Slf4j
@RocketMqMessageListener(groupId = BadgeOperateSink.INPUT, tag = BadgeOperateSink.TAG)
@RequiredArgsConstructor
public class BadgeOperateListener implements MessageListener {
private final BadgeConfigService badgeConfigService;
private final BadgeBackpackService badgeBackpackService;
private final MessageEventProcess messageEventProcess;
private final UserProfileGateway userProfileGateway;
@Override
public Action consume(ConsumerMessage message) {
return messageEventProcess.consume(
MessageEventProcessDescribe.builder()
.logTag("徽章操作处理")
.consumeMsgTimeoutMinute(60)
.repeatConsumeMinute(1)
.repeatConsumeTag("BadgeOperate")
.checkConsumeTag(BadgeOperateSink.TAG)
.message(message)
.build(),
BadgeOperateEvent.class,
this::handleBadgeOperate);
}
private void handleBadgeOperate(BadgeOperateEvent event) {
Long userId = event.getUserId();
String badgeKey = event.getBadgeKey();
String operationType = event.getOperationType();
if (userId == null || badgeKey == null || operationType == null) {
log.warn("徽章操作事件参数不完整, userId: {}, badgeKey: {}, operationType: {}",
userId, badgeKey, operationType);
return;
}
// 根据badgeKey查询徽章配置
BadgeConfig badgeConfig = badgeConfigService.getByBadgeKey(badgeKey);
if (badgeConfig == null) {
log.warn("徽章配置不存在, badgeKey: {}", badgeKey);
return;
}
Long badgeId = badgeConfig.getId();
// 根据操作类型执行对应逻辑
if (BadgeOperateEvent.OperationType.WEAR.name().equals(operationType)) {
handleWearBadge(userId, badgeId);
} else if (BadgeOperateEvent.OperationType.REMOVE.name().equals(operationType)) {
handleRemoveBadge(userId, badgeId);
} else {
log.warn("未知的操作类型, operationType: {}", operationType);
}
}
/**
* 佩戴徽章.
*/
private void handleWearBadge(Long userId, Long badgeId) {
// 检查用户是否已经拥有该徽章幂等处理
BadgeBackpack existBadge = badgeBackpackService.query()
.eq(BadgeBackpack::getUserId, userId)
.eq(BadgeBackpack::getBadgeId, badgeId)
.getOne();
if (existBadge != null) {
log.warn("用户已拥有该徽章, 跳过发放, userId: {}, badgeId: {}", userId, badgeId);
return;
}
BadgeBackpack badgeBackpack = badgeBackpackService.getByUserIdByBadgeId(userId, badgeId);
if (Objects.isNull(badgeBackpack)) {
badgeBackpackService.save(buildSaveUserBadgeBackpack(badgeId, userId));
userProfileGateway.removeCacheAll(userId);
}
}
/**
* 移除徽章.
*/
private void handleRemoveBadge(Long userId, Long badgeId) {
badgeBackpackService.deleteBadges(userId, Sets.newHashSet(badgeId));
userProfileGateway.removeCache(userId);
UserProfile userProfile = userProfileGateway.getByUserId(userId);
if (Objects.isNull(userProfile)) {
return;
}
List<UserUseBadgeDTO> wearBadge = userProfile.getWearBadge();
if (CollectionUtils.isEmpty(wearBadge)) {
return;
}
//过滤需要删除的 wearBadge id
Set<Long> saveWear = wearBadge.stream().map(UserUseBadgeDTO::getId)
.filter(id -> !badgeId.equals(id)).collect(Collectors.toSet());
userProfileGateway.updateUserWearBadge(userId, userProfile.getOriginSys(),saveWear);
}
private BadgeBackpack buildSaveUserBadgeBackpack(Long badgeId, Long userId) {
return new BadgeBackpack()
.setUserId(userId)
.setBadgeId(badgeId)
.setExpireTime(TimestampUtils.now())
.setExpireType(BadgeBackpackExpireTypeEnum.PERMANENT.name())
.setUseProps(Boolean.TRUE);
}
}

View File

@ -23,13 +23,6 @@ import java.util.Set;
*/
public interface BadgeConfigService extends BaseService<BadgeConfig> {
/**
* 获取管理员徽章id.
*
* @return ignore
*/
Long getAdminBadge();
List<BadgeConfig> listBadgeByType(SysBadgeConfigTypeEnum type);
/**
@ -125,4 +118,12 @@ public interface BadgeConfigService extends BaseService<BadgeConfig> {
* @return
*/
List<BadgeConfig> getBadgeConfigList(BadgeConfigTypeEnum type, String s);
/**
* 根据徽章Key查询徽章配置.
*
* @param badgeKey 徽章Key
* @return 徽章配置
*/
BadgeConfig getByBadgeKey(String badgeKey);
}

View File

@ -34,19 +34,6 @@ import org.springframework.stereotype.Service;
public class BadgeConfigServiceImpl extends BaseServiceImpl<BadgeConfigDAO, BadgeConfig> implements
BadgeConfigService {
@Override
public Long getAdminBadge() {
return Optional.ofNullable(query().select(BadgeConfig::getId)
.eq(BadgeConfig::getType, BadgeConfigTypeEnum.ADMINISTRATOR)
.eq(BadgeConfig::getBadgeKey, BadgeKeyEnum.ADMIN)
.eq(BadgeConfig::getDel, Boolean.FALSE)
.orderByAsc(BadgeConfig::getBadgeLevel)
.last(PageConstant.LIMIT_ONE)
.getOne())
.map(BadgeConfig::getId)
.orElse(null);
}
@Override
public List<BadgeConfig> listBadgeByType(SysBadgeConfigTypeEnum type) {
@ -204,4 +191,13 @@ public class BadgeConfigServiceImpl extends BaseServiceImpl<BadgeConfigDAO, Badg
public List<BadgeConfig> getBadgeConfigList(BadgeConfigTypeEnum type, String sysOrgin) {
return baseDAO.getBadgeConfigList(type,sysOrgin);
}
@Override
public BadgeConfig getByBadgeKey(String badgeKey) {
return query()
.eq(BadgeConfig::getBadgeKey, badgeKey)
.eq(BadgeConfig::getDel, Boolean.FALSE)
.last(PageConstant.LIMIT_ONE)
.getOne();
}
}