diff --git a/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/gm/GmVipGiftRestController.java b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/gm/GmVipGiftRestController.java new file mode 100644 index 00000000..3a0e1e98 --- /dev/null +++ b/rc-service/rc-service-console/console-adapter/src/main/java/com/red/circle/console/adapter/gm/GmVipGiftRestController.java @@ -0,0 +1,38 @@ +package com.red.circle.console.adapter.gm; + +import com.red.circle.console.app.dto.clienobject.gm.GmVipGiftCO; +import com.red.circle.console.app.dto.cmd.gm.GmVipGiftCmd; +import com.red.circle.console.app.dto.cmd.gm.GmVipGiftPageQryCmd; +import com.red.circle.console.app.service.gm.GmVipGiftService; +import com.red.circle.console.infra.annotations.OpsOperationReqLog; +import com.red.circle.framework.dto.PageResult; +import com.red.circle.framework.web.controller.BaseController; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * GM VIP赠送. + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/gm/vip-gift") +public class GmVipGiftRestController extends BaseController { + + private final GmVipGiftService gmVipGiftService; + + @OpsOperationReqLog("GM VIP赠送") + @PostMapping + public GmVipGiftCO gift(@RequestBody @Validated GmVipGiftCmd cmd) { + return gmVipGiftService.gift(cmd); + } + + @GetMapping("/page") + public PageResult page(GmVipGiftPageQryCmd cmd) { + return gmVipGiftService.page(cmd); + } +} diff --git a/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/gm/GmVipGiftServiceImpl.java b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/gm/GmVipGiftServiceImpl.java new file mode 100644 index 00000000..50012920 --- /dev/null +++ b/rc-service/rc-service-console/console-application/src/main/java/com/red/circle/console/app/service/gm/GmVipGiftServiceImpl.java @@ -0,0 +1,501 @@ +package com.red.circle.console.app.service.gm; + +import com.red.circle.console.app.dto.clienobject.gm.GmVipGiftCO; +import com.red.circle.console.app.dto.cmd.gm.GmVipGiftCmd; +import com.red.circle.console.app.dto.cmd.gm.GmVipGiftPageQryCmd; +import com.red.circle.console.infra.database.rds.entity.admin.User; +import com.red.circle.console.infra.database.rds.entity.app.vip.GmVipGiftRecord; +import com.red.circle.console.infra.database.rds.entity.app.vip.RunningWaterUserProps; +import com.red.circle.console.infra.database.rds.entity.app.vip.UserPropsBackpack; +import com.red.circle.console.infra.database.rds.entity.app.vip.UserVipState; +import com.red.circle.console.infra.database.rds.entity.app.vip.VipLevelConfig; +import com.red.circle.console.infra.database.rds.entity.app.vip.VipOrderRecord; +import com.red.circle.console.infra.database.rds.service.admin.UserService; +import com.red.circle.console.infra.database.rds.service.app.vip.GmVipGiftRecordService; +import com.red.circle.console.infra.database.rds.service.app.vip.RunningWaterUserPropsService; +import com.red.circle.console.infra.database.rds.service.app.vip.UserPropsBackpackService; +import com.red.circle.console.infra.database.rds.service.app.vip.UserVipStateService; +import com.red.circle.console.infra.database.rds.service.app.vip.VipLevelConfigService; +import com.red.circle.console.infra.database.rds.service.app.vip.VipOrderRecordService; +import com.red.circle.console.inner.error.ConsoleErrorCode; +import com.red.circle.framework.core.asserts.ResponseAssert; +import com.red.circle.framework.core.response.ResponseErrorCode; +import com.red.circle.framework.dto.PageResult; +import com.red.circle.framework.mybatis.constant.PageConstant; +import com.red.circle.other.inner.endpoint.material.props.PropsBackpackClient; +import com.red.circle.other.inner.endpoint.user.user.UserProfileClient; +import com.red.circle.other.inner.model.dto.user.UserProfileDTO; +import com.red.circle.tool.core.collection.CollectionUtils; +import com.red.circle.tool.core.sequence.IdWorkerUtils; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.time.Duration; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * GM VIP赠送. + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class GmVipGiftServiceImpl implements GmVipGiftService { + + private static final int VIP_MIN_LEVEL = 1; + private static final int VIP_MAX_LEVEL = 5; + private static final int DEFAULT_DURATION_DAYS = 30; + private static final String STATUS_ACTIVE = "ACTIVE"; + private static final String STATUS_SUCCESS = "SUCCESS"; + private static final String ORDER_TYPE_GM_GIFT = "GM_GIFT"; + private static final String WATER_ORIGIN = "VIP_PURCHASE"; + private static final String WATER_ORIGIN_DESC = "VIP purchase"; + private static final Timestamp MYSQL_DATETIME_MAX = Timestamp.valueOf("2038-01-19 00:00:00"); + + private final GmVipGiftRecordService giftRecordService; + private final VipLevelConfigService vipLevelConfigService; + private final UserVipStateService userVipStateService; + private final VipOrderRecordService vipOrderRecordService; + private final UserPropsBackpackService userPropsBackpackService; + private final RunningWaterUserPropsService runningWaterUserPropsService; + private final UserProfileClient userProfileClient; + private final PropsBackpackClient propsBackpackClient; + private final UserService userService; + + @Override + @Transactional(rollbackFor = Exception.class) + public GmVipGiftCO gift(GmVipGiftCmd cmd) { + validateGift(cmd); + + Timestamp now = now(); + User applicant = getAdminUser(cmd.getReqUserId()); + UserProfileDTO userProfile = getUserProfile(cmd.getUserId()); + VipLevelConfig config = getVipConfig(userProfile.getOriginSys(), cmd.getVipLevel()); + UserVipState currentState = getUserVipState(userProfile.getOriginSys(), userProfile.getId()); + boolean currentActive = isActive(currentState, now); + int fromLevel = currentActive ? Objects.requireNonNullElse(currentState.getLevel(), 0) : 0; + + ResponseAssert.isFalse(ResponseErrorCode.REQUEST_PARAMETER_ERROR, + currentActive && fromLevel > config.getLevel()); + + Timestamp startAt = currentActive && Objects.nonNull(currentState.getStartAt()) + ? currentState.getStartAt() + : now; + Timestamp expireAt = resolveExpireAt(currentState, config, currentActive, now); + Long orderId = IdWorkerUtils.getId(); + String eventId = "GM-VIP-GIFT-" + orderId; + + VipOrderRecord order = buildOrder(orderId, eventId, userProfile, fromLevel, config, startAt, + expireAt, now); + vipOrderRecordService.save(order); + + upsertUserVipState(currentState, userProfile, config, startAt, expireAt, now); + giftVipResources(userProfile.getId(), config, now, cmd.getReqUserId()); + + GmVipGiftRecord record = buildGiftRecord(cmd, applicant, userProfile, fromLevel, config, + orderId, eventId, startAt, expireAt, now); + giftRecordService.save(record); + + removeUserCache(userProfile.getId()); + return toCO(record, userProfile); + } + + @Override + public PageResult page(GmVipGiftPageQryCmd cmd) { + PageResult page = giftRecordService.query() + .eq(Objects.nonNull(cmd.getUserId()), GmVipGiftRecord::getUserId, cmd.getUserId()) + .eq(Objects.nonNull(cmd.getApplicantId()), GmVipGiftRecord::getApplicantId, + cmd.getApplicantId()) + .eq(Objects.nonNull(cmd.getVipLevel()), GmVipGiftRecord::getVipLevel, + cmd.getVipLevel()) + .eq(Objects.nonNull(cmd.getStatus()), GmVipGiftRecord::getStatus, cmd.getStatus()) + .ge(Objects.nonNull(cmd.getStartTime()), GmVipGiftRecord::getCreateTime, + toTimestamp(cmd.getStartTime())) + .le(Objects.nonNull(cmd.getEndTime()), GmVipGiftRecord::getCreateTime, + toTimestamp(cmd.getEndTime())) + .orderByDesc(GmVipGiftRecord::getId) + .page(cmd.getPageQuery()); + + Map userProfileMap = mapUserProfiles(page.getRecords()); + return page.convert(record -> toCO(record, userProfileMap.get(record.getUserId()))); + } + + private void validateGift(GmVipGiftCmd cmd) { + ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getReqUserId()); + ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getUserId(), + cmd.getVipLevel()); + ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR, + cmd.getVipLevel() >= VIP_MIN_LEVEL && cmd.getVipLevel() <= VIP_MAX_LEVEL); + } + + private User getAdminUser(Long userId) { + User user = userService.getById(Math.toIntExact(userId)); + ResponseAssert.notNull(ConsoleErrorCode.USER_NOT_FOUND, user); + return user; + } + + private UserProfileDTO getUserProfile(Long userId) { + UserProfileDTO userProfile = ResponseAssert.requiredSuccess(userProfileClient.getByUserId(userId)); + ResponseAssert.notNull(ConsoleErrorCode.USER_NOT_FOUND, userProfile); + ResponseAssert.notBlank(ConsoleErrorCode.USER_INFO_NOT_FOUND, userProfile.getOriginSys()); + return userProfile; + } + + private VipLevelConfig getVipConfig(String sysOrigin, Integer vipLevel) { + VipLevelConfig config = vipLevelConfigService.query() + .eq(VipLevelConfig::getSysOrigin, sysOrigin) + .eq(VipLevelConfig::getLevel, vipLevel) + .eq(VipLevelConfig::getEnabled, Boolean.TRUE) + .last(PageConstant.LIMIT_ONE) + .getOne(); + ResponseAssert.notNull(ConsoleErrorCode.NOT_FOUND_INFO, config); + if (Objects.isNull(config.getDurationDays()) || config.getDurationDays() <= 0) { + config.setDurationDays(DEFAULT_DURATION_DAYS); + } + return config; + } + + private UserVipState getUserVipState(String sysOrigin, Long userId) { + return userVipStateService.query() + .eq(UserVipState::getSysOrigin, sysOrigin) + .eq(UserVipState::getUserId, userId) + .last(PageConstant.LIMIT_ONE) + .getOne(); + } + + private boolean isActive(UserVipState state, Timestamp now) { + return Objects.nonNull(state) + && STATUS_ACTIVE.equals(state.getStatus()) + && Objects.nonNull(state.getExpireAt()) + && state.getExpireAt().after(now) + && Objects.nonNull(state.getLevel()) + && state.getLevel() > 0; + } + + private Timestamp resolveExpireAt(UserVipState currentState, VipLevelConfig config, + boolean currentActive, Timestamp now) { + Timestamp plusDuration = plusDays(now, config.getDurationDays()); + if (!currentActive) { + return plusDuration; + } + if (Objects.equals(currentState.getLevel(), config.getLevel())) { + return plusDays(max(currentState.getExpireAt(), now), config.getDurationDays()); + } + return max(currentState.getExpireAt(), plusDuration); + } + + private VipOrderRecord buildOrder(Long orderId, String eventId, UserProfileDTO userProfile, + Integer fromLevel, VipLevelConfig config, Timestamp startAt, Timestamp expireAt, + Timestamp now) { + VipOrderRecord order = new VipOrderRecord() + .setId(orderId) + .setEventId(eventId) + .setSysOrigin(userProfile.getOriginSys()) + .setUserId(userProfile.getId()) + .setOrderType(ORDER_TYPE_GM_GIFT) + .setFromLevel(fromLevel) + .setToLevel(config.getLevel()) + .setDurationDays(config.getDurationDays()) + .setOriginalPriceGold(Objects.requireNonNullElse(config.getPriceGold(), 0L)) + .setPaidGold(0L) + .setStatus(STATUS_SUCCESS) + .setStartAt(startAt) + .setExpireAt(expireAt) + .setErrorMessage(""); + order.setCreateTime(now); + order.setUpdateTime(now); + return order; + } + + private void upsertUserVipState(UserVipState currentState, UserProfileDTO userProfile, + VipLevelConfig config, Timestamp startAt, Timestamp expireAt, Timestamp now) { + UserVipState state = Objects.nonNull(currentState) + ? currentState + : new UserVipState().setId(IdWorkerUtils.getId()); + state.setSysOrigin(userProfile.getOriginSys()); + state.setUserId(userProfile.getId()); + state.setLevel(config.getLevel()); + state.setLevelCode(config.getLevelCode()); + state.setDisplayName(config.getDisplayName()); + state.setStatus(STATUS_ACTIVE); + state.setStartAt(startAt); + state.setExpireAt(expireAt); + copyResources(state, config); + state.setUpdateTime(now); + if (Objects.nonNull(currentState)) { + userVipStateService.updateSelectiveById(state); + return; + } + state.setCreateTime(now); + userVipStateService.save(state); + } + + private void copyResources(UserVipState state, VipLevelConfig config) { + state.setBadgeResourceId(config.getBadgeResourceId()); + state.setBadgeName(config.getBadgeName()); + state.setBadgeCover(config.getBadgeCover()); + state.setBadgeUrl(config.getBadgeUrl()); + state.setAvatarFrameResourceId(config.getAvatarFrameResourceId()); + state.setAvatarFrameName(config.getAvatarFrameName()); + state.setAvatarFrameCover(config.getAvatarFrameCover()); + state.setAvatarFrameUrl(config.getAvatarFrameUrl()); + state.setEntryEffectResourceId(config.getEntryEffectResourceId()); + state.setEntryEffectName(config.getEntryEffectName()); + state.setEntryEffectCover(config.getEntryEffectCover()); + state.setEntryEffectUrl(config.getEntryEffectUrl()); + state.setChatBubbleResourceId(config.getChatBubbleResourceId()); + state.setChatBubbleName(config.getChatBubbleName()); + state.setChatBubbleCover(config.getChatBubbleCover()); + state.setChatBubbleUrl(config.getChatBubbleUrl()); + state.setFloatPictureResourceId(config.getFloatPictureResourceId()); + state.setFloatPictureName(config.getFloatPictureName()); + state.setFloatPictureCover(config.getFloatPictureCover()); + state.setFloatPictureUrl(config.getFloatPictureUrl()); + } + + private void giftVipResources(Long userId, VipLevelConfig config, Timestamp now, Long opUser) { + giveProp(userId, config.getBadgeResourceId(), "BADGE", config.getDurationDays(), now, opUser); + giveProp(userId, config.getAvatarFrameResourceId(), "AVATAR_FRAME", config.getDurationDays(), + now, opUser); + giveProp(userId, config.getEntryEffectResourceId(), "RIDE", config.getDurationDays(), now, + opUser); + giveProp(userId, config.getChatBubbleResourceId(), "CHAT_BUBBLE", config.getDurationDays(), + now, opUser); + giveProp(userId, config.getFloatPictureResourceId(), "FLOAT_PICTURE", config.getDurationDays(), + now, opUser); + } + + private void giveProp(Long userId, Long propsId, String type, Integer days, Timestamp now, + Long opUser) { + if (Objects.isNull(propsId) || propsId <= 0 || Objects.isNull(days) || days <= 0) { + return; + } + + UserPropsBackpack oldBackpack = getUserProp(userId, propsId); + boolean useProps = resolveUseProps(userId, propsId, type, oldBackpack, now); + Timestamp expireTime = resolvePropExpireTime(oldBackpack, days, now); + + if (Boolean.TRUE.equals(useProps)) { + userPropsBackpackService.update() + .set(UserPropsBackpack::getUseProps, Boolean.FALSE) + .eq(UserPropsBackpack::getUserId, userId) + .eq(UserPropsBackpack::getType, type) + .eq(UserPropsBackpack::getUseProps, Boolean.TRUE) + .execute(); + } + + if (Objects.nonNull(oldBackpack)) { + oldBackpack.setType(type); + oldBackpack.setExpireTime(expireTime); + oldBackpack.setUseProps(useProps); + oldBackpack.setAllowGive(Boolean.FALSE); + oldBackpack.setUpdateTime(now); + oldBackpack.setUpdateUser(opUser); + userPropsBackpackService.updateSelectiveById(oldBackpack); + } else { + UserPropsBackpack backpack = new UserPropsBackpack() + .setUserId(userId) + .setPropsId(propsId) + .setType(type) + .setExpireTime(expireTime) + .setUseProps(useProps) + .setAllowGive(Boolean.FALSE); + backpack.setCreateTime(now); + backpack.setUpdateTime(now); + backpack.setCreateUser(opUser); + backpack.setUpdateUser(opUser); + userPropsBackpackService.save(backpack); + } + + RunningWaterUserProps water = new RunningWaterUserProps() + .setUserId(userId) + .setPropsId(propsId) + .setPropsCandy(BigDecimal.ZERO) + .setType(type) + .setOrigin(WATER_ORIGIN) + .setOriginDesc(WATER_ORIGIN_DESC) + .setDays(days); + water.setCreateTime(now); + water.setUpdateTime(now); + water.setCreateUser(opUser); + water.setUpdateUser(0L); + runningWaterUserPropsService.save(water); + notifyPropsGift(userId, type, days, propsId); + } + + private UserPropsBackpack getUserProp(Long userId, Long propsId) { + return userPropsBackpackService.query() + .eq(UserPropsBackpack::getUserId, userId) + .eq(UserPropsBackpack::getPropsId, propsId) + .last(PageConstant.LIMIT_ONE) + .getOne(); + } + + private boolean resolveUseProps(Long userId, Long propsId, String type, + UserPropsBackpack oldBackpack, Timestamp now) { + if (Objects.nonNull(oldBackpack)) { + return Boolean.TRUE.equals(oldBackpack.getUseProps()); + } + List notExpiredSameType = userPropsBackpackService.query() + .eq(UserPropsBackpack::getUserId, userId) + .eq(UserPropsBackpack::getType, type) + .gt(UserPropsBackpack::getExpireTime, now) + .list(); + return notExpiredSameType.stream() + .noneMatch(item -> Boolean.TRUE.equals(item.getUseProps()) + && !Objects.equals(item.getPropsId(), propsId)); + } + + private Timestamp resolvePropExpireTime(UserPropsBackpack oldBackpack, Integer days, + Timestamp now) { + if (Objects.isNull(oldBackpack) || Objects.isNull(oldBackpack.getExpireTime()) + || oldBackpack.getExpireTime().before(now)) { + return capExpireTime(plusDays(now, days)); + } + return capExpireTime(plusDays(oldBackpack.getExpireTime(), days)); + } + + private GmVipGiftRecord buildGiftRecord(GmVipGiftCmd cmd, User applicant, + UserProfileDTO userProfile, Integer fromLevel, VipLevelConfig config, Long orderId, + String eventId, Timestamp startAt, Timestamp expireAt, Timestamp now) { + return touchNew(new GmVipGiftRecord() + .setId(IdWorkerUtils.getId()) + .setUserId(userProfile.getId()) + .setSysOrigin(userProfile.getOriginSys()) + .setFromLevel(fromLevel) + .setVipLevel(config.getLevel()) + .setLevelCode(config.getLevelCode()) + .setDisplayName(config.getDisplayName()) + .setDurationDays(config.getDurationDays()) + .setPriceGold(Objects.requireNonNullElse(config.getPriceGold(), 0L)) + .setStartAt(startAt) + .setExpireAt(expireAt) + .setOrderId(orderId) + .setEventId(eventId) + .setStatus(STATUS_SUCCESS) + .setApplicantId(applicant.getId().longValue()) + .setApplicantName(resolveAdminName(applicant)) + .setRemarks(cmd.getRemarks()) + .setExecutedTime(now), now); + } + + private String resolveAdminName(User user) { + if (Objects.isNull(user)) { + return null; + } + if (Objects.nonNull(user.getNickname()) && !user.getNickname().isBlank()) { + return user.getNickname(); + } + return user.getLoginName(); + } + + private Map mapUserProfiles(Collection records) { + if (CollectionUtils.isEmpty(records)) { + return Map.of(); + } + Set userIds = records.stream() + .map(GmVipGiftRecord::getUserId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (CollectionUtils.isEmpty(userIds)) { + return Map.of(); + } + return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(userIds)); + } + + private GmVipGiftCO toCO(GmVipGiftRecord record, UserProfileDTO userProfile) { + GmVipGiftCO co = new GmVipGiftCO(); + co.setId(record.getId()); + co.setUserId(record.getUserId()); + co.setSysOrigin(record.getSysOrigin()); + co.setFromLevel(record.getFromLevel()); + co.setFromLevelName(levelName(record.getFromLevel())); + co.setVipLevel(record.getVipLevel()); + co.setLevelCode(record.getLevelCode()); + co.setDisplayName(record.getDisplayName()); + co.setDurationDays(record.getDurationDays()); + co.setPriceGold(record.getPriceGold()); + co.setStartAt(record.getStartAt()); + co.setExpireAt(record.getExpireAt()); + co.setOrderId(record.getOrderId()); + co.setEventId(record.getEventId()); + co.setStatus(record.getStatus()); + co.setStatusName(statusName(record.getStatus())); + co.setApplicantId(record.getApplicantId()); + co.setApplicantName(record.getApplicantName()); + co.setRemarks(record.getRemarks()); + co.setExecutedTime(record.getExecutedTime()); + co.setCreateTime(record.getCreateTime()); + co.setUpdateTime(record.getUpdateTime()); + co.setUserProfile(userProfile); + return co; + } + + private String levelName(Integer level) { + return Objects.isNull(level) || level <= 0 ? "非VIP" : "VIP" + level; + } + + private String statusName(String status) { + return STATUS_SUCCESS.equals(status) ? "已赠送" : status; + } + + private void notifyPropsGift(Long userId, String type, Integer days, Long propsId) { + try { + propsBackpackClient.givePropsNotify(userId, type, days, propsId); + } catch (Exception exception) { + log.warn("notify vip gift props failed, userId={}, type={}, propsId={}", userId, type, + propsId, exception); + } + } + + private void removeUserCache(Long userId) { + try { + userProfileClient.removeCacheAll(userId); + } catch (Exception exception) { + log.warn("remove user cache after vip gift failed, userId={}", userId, exception); + } + } + + private T touchNew(T entity, + Timestamp now) { + entity.setCreateTime(now); + entity.setUpdateTime(now); + return entity; + } + + private Timestamp max(Timestamp first, Timestamp second) { + if (Objects.isNull(first)) { + return second; + } + if (Objects.isNull(second)) { + return first; + } + return first.after(second) ? first : second; + } + + private Timestamp plusDays(Timestamp value, int days) { + return Timestamp.from(value.toInstant().plus(Duration.ofDays(days))); + } + + private Timestamp capExpireTime(Timestamp expireTime) { + if (Objects.isNull(expireTime)) { + return null; + } + return expireTime.after(MYSQL_DATETIME_MAX) ? MYSQL_DATETIME_MAX : expireTime; + } + + private Timestamp toTimestamp(Long value) { + return Objects.isNull(value) ? null : new Timestamp(value); + } + + private Timestamp now() { + return new Timestamp(System.currentTimeMillis()); + } +} diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/clienobject/gm/GmVipGiftCO.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/clienobject/gm/GmVipGiftCO.java new file mode 100644 index 00000000..7647366f --- /dev/null +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/clienobject/gm/GmVipGiftCO.java @@ -0,0 +1,71 @@ +package com.red.circle.console.app.dto.clienobject.gm; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.red.circle.framework.dto.ClientObject; +import com.red.circle.other.inner.model.dto.user.UserProfileDTO; +import java.io.Serial; +import java.sql.Timestamp; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * GM VIP赠送记录. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class GmVipGiftCO extends ClientObject { + + @Serial + private static final long serialVersionUID = 1L; + + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + @JsonSerialize(using = ToStringSerializer.class) + private Long userId; + + private String sysOrigin; + + private Integer fromLevel; + + private String fromLevelName; + + private Integer vipLevel; + + private String levelCode; + + private String displayName; + + private Integer durationDays; + + private Long priceGold; + + private Timestamp startAt; + + private Timestamp expireAt; + + @JsonSerialize(using = ToStringSerializer.class) + private Long orderId; + + private String eventId; + + private String status; + + private String statusName; + + @JsonSerialize(using = ToStringSerializer.class) + private Long applicantId; + + private String applicantName; + + private String remarks; + + private Timestamp executedTime; + + private Timestamp createTime; + + private Timestamp updateTime; + + private UserProfileDTO userProfile; +} diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/cmd/gm/GmVipGiftCmd.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/cmd/gm/GmVipGiftCmd.java new file mode 100644 index 00000000..c1186a59 --- /dev/null +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/cmd/gm/GmVipGiftCmd.java @@ -0,0 +1,35 @@ +package com.red.circle.console.app.dto.cmd.gm; + +import com.red.circle.framework.core.dto.CommonCommand; +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * GM VIP赠送. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class GmVipGiftCmd extends CommonCommand { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * APP用户ID. + */ + @NotNull + private Long userId; + + /** + * VIP等级: 1-5. + */ + @NotNull + private Integer vipLevel; + + /** + * 备注. + */ + private String remarks; +} diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/cmd/gm/GmVipGiftPageQryCmd.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/cmd/gm/GmVipGiftPageQryCmd.java new file mode 100644 index 00000000..d140c31a --- /dev/null +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/cmd/gm/GmVipGiftPageQryCmd.java @@ -0,0 +1,29 @@ +package com.red.circle.console.app.dto.cmd.gm; + +import com.red.circle.framework.core.dto.PageCommand; +import java.io.Serial; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * GM VIP赠送记录分页查询. + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class GmVipGiftPageQryCmd extends PageCommand { + + @Serial + private static final long serialVersionUID = 1L; + + private Long userId; + + private Long applicantId; + + private Integer vipLevel; + + private String status; + + private Long startTime; + + private Long endTime; +} diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/gm/GmVipGiftService.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/gm/GmVipGiftService.java new file mode 100644 index 00000000..540fbc63 --- /dev/null +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/service/gm/GmVipGiftService.java @@ -0,0 +1,16 @@ +package com.red.circle.console.app.service.gm; + +import com.red.circle.console.app.dto.clienobject.gm.GmVipGiftCO; +import com.red.circle.console.app.dto.cmd.gm.GmVipGiftCmd; +import com.red.circle.console.app.dto.cmd.gm.GmVipGiftPageQryCmd; +import com.red.circle.framework.dto.PageResult; + +/** + * GM VIP赠送. + */ +public interface GmVipGiftService { + + GmVipGiftCO gift(GmVipGiftCmd cmd); + + PageResult page(GmVipGiftPageQryCmd cmd); +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/GmVipGiftRecordDAO.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/GmVipGiftRecordDAO.java new file mode 100644 index 00000000..6dfb86d2 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/GmVipGiftRecordDAO.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.dao.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.GmVipGiftRecord; +import com.red.circle.framework.mybatis.dao.BaseDAO; + +/** + * GM VIP赠送记录 DAO. + */ +public interface GmVipGiftRecordDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/RunningWaterUserPropsDAO.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/RunningWaterUserPropsDAO.java new file mode 100644 index 00000000..b822c055 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/RunningWaterUserPropsDAO.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.dao.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.RunningWaterUserProps; +import com.red.circle.framework.mybatis.dao.BaseDAO; + +/** + * 用户道具流水 DAO. + */ +public interface RunningWaterUserPropsDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/UserPropsBackpackDAO.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/UserPropsBackpackDAO.java new file mode 100644 index 00000000..ddb642de --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/UserPropsBackpackDAO.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.dao.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.UserPropsBackpack; +import com.red.circle.framework.mybatis.dao.BaseDAO; + +/** + * 用户道具背包 DAO. + */ +public interface UserPropsBackpackDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/UserVipStateDAO.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/UserVipStateDAO.java new file mode 100644 index 00000000..618b300b --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/UserVipStateDAO.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.dao.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.UserVipState; +import com.red.circle.framework.mybatis.dao.BaseDAO; + +/** + * 用户VIP当前状态 DAO. + */ +public interface UserVipStateDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/VipLevelConfigDAO.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/VipLevelConfigDAO.java new file mode 100644 index 00000000..3e9d1315 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/VipLevelConfigDAO.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.dao.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.VipLevelConfig; +import com.red.circle.framework.mybatis.dao.BaseDAO; + +/** + * VIP等级配置 DAO. + */ +public interface VipLevelConfigDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/VipOrderRecordDAO.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/VipOrderRecordDAO.java new file mode 100644 index 00000000..6a2fca76 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/dao/app/vip/VipOrderRecordDAO.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.dao.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.VipOrderRecord; +import com.red.circle.framework.mybatis.dao.BaseDAO; + +/** + * VIP订单记录 DAO. + */ +public interface VipOrderRecordDAO extends BaseDAO { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/GmVipGiftRecord.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/GmVipGiftRecord.java new file mode 100644 index 00000000..af83eb57 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/GmVipGiftRecord.java @@ -0,0 +1,79 @@ +package com.red.circle.console.infra.database.rds.entity.app.vip; + +import com.baomidou.mybatisplus.annotation.IdType; +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.sql.Timestamp; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * GM VIP赠送记录. + */ +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@TableName("gm_vip_gift_record") +public class GmVipGiftRecord extends TimestampBaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + private Long id; + + @TableField("user_id") + private Long userId; + + @TableField("sys_origin") + private String sysOrigin; + + @TableField("from_level") + private Integer fromLevel; + + @TableField("vip_level") + private Integer vipLevel; + + @TableField("level_code") + private String levelCode; + + @TableField("display_name") + private String displayName; + + @TableField("duration_days") + private Integer durationDays; + + @TableField("price_gold") + private Long priceGold; + + @TableField("start_at") + private Timestamp startAt; + + @TableField("expire_at") + private Timestamp expireAt; + + @TableField("order_id") + private Long orderId; + + @TableField("event_id") + private String eventId; + + @TableField("status") + private String status; + + @TableField("applicant_id") + private Long applicantId; + + @TableField("applicant_name") + private String applicantName; + + @TableField("remarks") + private String remarks; + + @TableField("executed_time") + private Timestamp executedTime; +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/RunningWaterUserProps.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/RunningWaterUserProps.java new file mode 100644 index 00000000..6359e2dd --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/RunningWaterUserProps.java @@ -0,0 +1,49 @@ +package com.red.circle.console.infra.database.rds.entity.app.vip; + +import com.baomidou.mybatisplus.annotation.IdType; +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; + +/** + * 用户道具流水. + */ +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@TableName("running_water_user_props") +public class RunningWaterUserProps extends TimestampBaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + @TableField("user_id") + private Long userId; + + @TableField("props_id") + private Long propsId; + + @TableField("props_candy") + private BigDecimal propsCandy; + + @TableField("type") + private String type; + + @TableField("origin") + private String origin; + + @TableField("days") + private Integer days; + + @TableField("origin_desc") + private String originDesc; +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/UserPropsBackpack.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/UserPropsBackpack.java new file mode 100644 index 00000000..91c1a8a5 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/UserPropsBackpack.java @@ -0,0 +1,46 @@ +package com.red.circle.console.infra.database.rds.entity.app.vip; + +import com.baomidou.mybatisplus.annotation.IdType; +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.sql.Timestamp; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 用户道具背包. + */ +@Data +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@TableName("user_props_backpack") +public class UserPropsBackpack extends TimestampBaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + @TableField("user_id") + private Long userId; + + @TableField("props_id") + private Long propsId; + + @TableField("type") + private String type; + + @TableField("expire_time") + private Timestamp expireTime; + + @TableField("is_use_props") + private Boolean useProps; + + @TableField("allow_give") + private Boolean allowGive; +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/UserVipState.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/UserVipState.java new file mode 100644 index 00000000..8637ea51 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/UserVipState.java @@ -0,0 +1,116 @@ +package com.red.circle.console.infra.database.rds.entity.app.vip; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serial; +import java.io.Serializable; +import java.sql.Timestamp; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 用户VIP当前状态. + */ +@Data +@Accessors(chain = true) +@TableName("user_vip_state") +public class UserVipState implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + private Long id; + + @TableField("sys_origin") + private String sysOrigin; + + @TableField("user_id") + private Long userId; + + @TableField("level") + private Integer level; + + @TableField("level_code") + private String levelCode; + + @TableField("display_name") + private String displayName; + + @TableField("status") + private String status; + + @TableField("start_at") + private Timestamp startAt; + + @TableField("expire_at") + private Timestamp expireAt; + + @TableField("badge_resource_id") + private Long badgeResourceId; + + @TableField("badge_name") + private String badgeName; + + @TableField("badge_cover") + private String badgeCover; + + @TableField("badge_url") + private String badgeUrl; + + @TableField("avatar_frame_resource_id") + private Long avatarFrameResourceId; + + @TableField("avatar_frame_name") + private String avatarFrameName; + + @TableField("avatar_frame_cover") + private String avatarFrameCover; + + @TableField("avatar_frame_url") + private String avatarFrameUrl; + + @TableField("entry_effect_resource_id") + private Long entryEffectResourceId; + + @TableField("entry_effect_name") + private String entryEffectName; + + @TableField("entry_effect_cover") + private String entryEffectCover; + + @TableField("entry_effect_url") + private String entryEffectUrl; + + @TableField("chat_bubble_resource_id") + private Long chatBubbleResourceId; + + @TableField("chat_bubble_name") + private String chatBubbleName; + + @TableField("chat_bubble_cover") + private String chatBubbleCover; + + @TableField("chat_bubble_url") + private String chatBubbleUrl; + + @TableField("float_picture_resource_id") + private Long floatPictureResourceId; + + @TableField("float_picture_name") + private String floatPictureName; + + @TableField("float_picture_cover") + private String floatPictureCover; + + @TableField("float_picture_url") + private String floatPictureUrl; + + @TableField("create_time") + private Timestamp createTime; + + @TableField("update_time") + private Timestamp updateTime; +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/VipLevelConfig.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/VipLevelConfig.java new file mode 100644 index 00000000..5c86a3d0 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/VipLevelConfig.java @@ -0,0 +1,113 @@ +package com.red.circle.console.infra.database.rds.entity.app.vip; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serial; +import java.io.Serializable; +import java.sql.Timestamp; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * VIP等级配置. + */ +@Data +@Accessors(chain = true) +@TableName("vip_level_config") +public class VipLevelConfig implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + private Long id; + + @TableField("sys_origin") + private String sysOrigin; + + @TableField("level") + private Integer level; + + @TableField("level_code") + private String levelCode; + + @TableField("display_name") + private String displayName; + + @TableField("enabled") + private Boolean enabled; + + @TableField("duration_days") + private Integer durationDays; + + @TableField("price_gold") + private Long priceGold; + + @TableField("badge_resource_id") + private Long badgeResourceId; + + @TableField("badge_name") + private String badgeName; + + @TableField("badge_cover") + private String badgeCover; + + @TableField("badge_url") + private String badgeUrl; + + @TableField("avatar_frame_resource_id") + private Long avatarFrameResourceId; + + @TableField("avatar_frame_name") + private String avatarFrameName; + + @TableField("avatar_frame_cover") + private String avatarFrameCover; + + @TableField("avatar_frame_url") + private String avatarFrameUrl; + + @TableField("entry_effect_resource_id") + private Long entryEffectResourceId; + + @TableField("entry_effect_name") + private String entryEffectName; + + @TableField("entry_effect_cover") + private String entryEffectCover; + + @TableField("entry_effect_url") + private String entryEffectUrl; + + @TableField("chat_bubble_resource_id") + private Long chatBubbleResourceId; + + @TableField("chat_bubble_name") + private String chatBubbleName; + + @TableField("chat_bubble_cover") + private String chatBubbleCover; + + @TableField("chat_bubble_url") + private String chatBubbleUrl; + + @TableField("float_picture_resource_id") + private Long floatPictureResourceId; + + @TableField("float_picture_name") + private String floatPictureName; + + @TableField("float_picture_cover") + private String floatPictureCover; + + @TableField("float_picture_url") + private String floatPictureUrl; + + @TableField("create_time") + private Timestamp createTime; + + @TableField("update_time") + private Timestamp updateTime; +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/VipOrderRecord.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/VipOrderRecord.java new file mode 100644 index 00000000..8e3615ae --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/entity/app/vip/VipOrderRecord.java @@ -0,0 +1,71 @@ +package com.red.circle.console.infra.database.rds.entity.app.vip; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serial; +import java.io.Serializable; +import java.sql.Timestamp; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * VIP购买/赠送订单记录. + */ +@Data +@Accessors(chain = true) +@TableName("vip_order_record") +public class VipOrderRecord implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + private Long id; + + @TableField("event_id") + private String eventId; + + @TableField("sys_origin") + private String sysOrigin; + + @TableField("user_id") + private Long userId; + + @TableField("order_type") + private String orderType; + + @TableField("from_level") + private Integer fromLevel; + + @TableField("to_level") + private Integer toLevel; + + @TableField("duration_days") + private Integer durationDays; + + @TableField("original_price_gold") + private Long originalPriceGold; + + @TableField("paid_gold") + private Long paidGold; + + @TableField("status") + private String status; + + @TableField("start_at") + private Timestamp startAt; + + @TableField("expire_at") + private Timestamp expireAt; + + @TableField("error_message") + private String errorMessage; + + @TableField("create_time") + private Timestamp createTime; + + @TableField("update_time") + private Timestamp updateTime; +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/GmVipGiftRecordService.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/GmVipGiftRecordService.java new file mode 100644 index 00000000..ee4a08ac --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/GmVipGiftRecordService.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.service.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.GmVipGiftRecord; +import com.red.circle.framework.mybatis.service.BaseService; + +/** + * GM VIP赠送记录服务. + */ +public interface GmVipGiftRecordService extends BaseService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/RunningWaterUserPropsService.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/RunningWaterUserPropsService.java new file mode 100644 index 00000000..71e15daa --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/RunningWaterUserPropsService.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.service.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.RunningWaterUserProps; +import com.red.circle.framework.mybatis.service.BaseService; + +/** + * 用户道具流水服务. + */ +public interface RunningWaterUserPropsService extends BaseService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/UserPropsBackpackService.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/UserPropsBackpackService.java new file mode 100644 index 00000000..9aac100c --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/UserPropsBackpackService.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.service.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.UserPropsBackpack; +import com.red.circle.framework.mybatis.service.BaseService; + +/** + * 用户道具背包服务. + */ +public interface UserPropsBackpackService extends BaseService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/UserVipStateService.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/UserVipStateService.java new file mode 100644 index 00000000..e885d3d7 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/UserVipStateService.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.service.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.UserVipState; +import com.red.circle.framework.mybatis.service.BaseService; + +/** + * 用户VIP当前状态服务. + */ +public interface UserVipStateService extends BaseService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/VipLevelConfigService.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/VipLevelConfigService.java new file mode 100644 index 00000000..443c51e5 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/VipLevelConfigService.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.service.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.VipLevelConfig; +import com.red.circle.framework.mybatis.service.BaseService; + +/** + * VIP等级配置服务. + */ +public interface VipLevelConfigService extends BaseService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/VipOrderRecordService.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/VipOrderRecordService.java new file mode 100644 index 00000000..e4754d64 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/VipOrderRecordService.java @@ -0,0 +1,10 @@ +package com.red.circle.console.infra.database.rds.service.app.vip; + +import com.red.circle.console.infra.database.rds.entity.app.vip.VipOrderRecord; +import com.red.circle.framework.mybatis.service.BaseService; + +/** + * VIP订单记录服务. + */ +public interface VipOrderRecordService extends BaseService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/GmVipGiftRecordServiceImpl.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/GmVipGiftRecordServiceImpl.java new file mode 100644 index 00000000..f6c4f22e --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/GmVipGiftRecordServiceImpl.java @@ -0,0 +1,16 @@ +package com.red.circle.console.infra.database.rds.service.app.vip.impl; + +import com.red.circle.console.infra.database.rds.dao.app.vip.GmVipGiftRecordDAO; +import com.red.circle.console.infra.database.rds.entity.app.vip.GmVipGiftRecord; +import com.red.circle.console.infra.database.rds.service.app.vip.GmVipGiftRecordService; +import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl; +import org.springframework.stereotype.Service; + +/** + * GM VIP赠送记录服务实现. + */ +@Service +public class GmVipGiftRecordServiceImpl extends + BaseServiceImpl + implements GmVipGiftRecordService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/RunningWaterUserPropsServiceImpl.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/RunningWaterUserPropsServiceImpl.java new file mode 100644 index 00000000..07972d00 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/RunningWaterUserPropsServiceImpl.java @@ -0,0 +1,16 @@ +package com.red.circle.console.infra.database.rds.service.app.vip.impl; + +import com.red.circle.console.infra.database.rds.dao.app.vip.RunningWaterUserPropsDAO; +import com.red.circle.console.infra.database.rds.entity.app.vip.RunningWaterUserProps; +import com.red.circle.console.infra.database.rds.service.app.vip.RunningWaterUserPropsService; +import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 用户道具流水服务实现. + */ +@Service +public class RunningWaterUserPropsServiceImpl extends + BaseServiceImpl + implements RunningWaterUserPropsService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/UserPropsBackpackServiceImpl.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/UserPropsBackpackServiceImpl.java new file mode 100644 index 00000000..2dcec0b2 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/UserPropsBackpackServiceImpl.java @@ -0,0 +1,16 @@ +package com.red.circle.console.infra.database.rds.service.app.vip.impl; + +import com.red.circle.console.infra.database.rds.dao.app.vip.UserPropsBackpackDAO; +import com.red.circle.console.infra.database.rds.entity.app.vip.UserPropsBackpack; +import com.red.circle.console.infra.database.rds.service.app.vip.UserPropsBackpackService; +import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 用户道具背包服务实现. + */ +@Service +public class UserPropsBackpackServiceImpl extends + BaseServiceImpl + implements UserPropsBackpackService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/UserVipStateServiceImpl.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/UserVipStateServiceImpl.java new file mode 100644 index 00000000..9a8cb9b5 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/UserVipStateServiceImpl.java @@ -0,0 +1,15 @@ +package com.red.circle.console.infra.database.rds.service.app.vip.impl; + +import com.red.circle.console.infra.database.rds.dao.app.vip.UserVipStateDAO; +import com.red.circle.console.infra.database.rds.entity.app.vip.UserVipState; +import com.red.circle.console.infra.database.rds.service.app.vip.UserVipStateService; +import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 用户VIP当前状态服务实现. + */ +@Service +public class UserVipStateServiceImpl extends BaseServiceImpl + implements UserVipStateService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/VipLevelConfigServiceImpl.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/VipLevelConfigServiceImpl.java new file mode 100644 index 00000000..53e913cb --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/VipLevelConfigServiceImpl.java @@ -0,0 +1,15 @@ +package com.red.circle.console.infra.database.rds.service.app.vip.impl; + +import com.red.circle.console.infra.database.rds.dao.app.vip.VipLevelConfigDAO; +import com.red.circle.console.infra.database.rds.entity.app.vip.VipLevelConfig; +import com.red.circle.console.infra.database.rds.service.app.vip.VipLevelConfigService; +import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl; +import org.springframework.stereotype.Service; + +/** + * VIP等级配置服务实现. + */ +@Service +public class VipLevelConfigServiceImpl extends BaseServiceImpl + implements VipLevelConfigService { +} diff --git a/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/VipOrderRecordServiceImpl.java b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/VipOrderRecordServiceImpl.java new file mode 100644 index 00000000..5cfdf7a2 --- /dev/null +++ b/rc-service/rc-service-console/console-infrastructure/src/main/java/com/red/circle/console/infra/database/rds/service/app/vip/impl/VipOrderRecordServiceImpl.java @@ -0,0 +1,15 @@ +package com.red.circle.console.infra.database.rds.service.app.vip.impl; + +import com.red.circle.console.infra.database.rds.dao.app.vip.VipOrderRecordDAO; +import com.red.circle.console.infra.database.rds.entity.app.vip.VipOrderRecord; +import com.red.circle.console.infra.database.rds.service.app.vip.VipOrderRecordService; +import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl; +import org.springframework.stereotype.Service; + +/** + * VIP订单记录服务实现. + */ +@Service +public class VipOrderRecordServiceImpl extends BaseServiceImpl + implements VipOrderRecordService { +} diff --git a/sql/20260504_gm_vip_gift.sql b/sql/20260504_gm_vip_gift.sql new file mode 100644 index 00000000..6d07a5d3 --- /dev/null +++ b/sql/20260504_gm_vip_gift.sql @@ -0,0 +1,74 @@ +SET NAMES utf8mb4; + +CREATE TABLE IF NOT EXISTS `gm_vip_gift_record` ( + `id` bigint NOT NULL COMMENT '记录ID', + `user_id` bigint NOT NULL COMMENT 'APP用户ID', + `sys_origin` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '系统来源', + `from_level` int NOT NULL DEFAULT '0' COMMENT '赠送前VIP等级', + `vip_level` int NOT NULL COMMENT '赠送VIP等级', + `level_code` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '等级编码', + `display_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '显示名称', + `duration_days` int NOT NULL DEFAULT '30' COMMENT '赠送天数', + `price_gold` bigint NOT NULL DEFAULT '0' COMMENT '对应购买价格,金币', + `start_at` datetime(3) DEFAULT NULL COMMENT '权益开始时间', + `expire_at` datetime(3) DEFAULT NULL COMMENT '权益到期时间', + `order_id` bigint NOT NULL COMMENT '关联VIP订单ID', + `event_id` varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '赠送幂等事件ID', + `status` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'SUCCESS' COMMENT '状态', + `applicant_id` bigint NOT NULL COMMENT '后台操作人ID', + `applicant_name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '后台操作人名称', + `remarks` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注', + `executed_time` datetime(3) DEFAULT NULL COMMENT '执行时间', + `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', + `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间', + `create_user` bigint DEFAULT NULL COMMENT '创建用户', + `update_user` bigint DEFAULT NULL COMMENT '更新用户', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_gm_vip_gift_event` (`event_id`), + KEY `idx_gm_vip_gift_user` (`user_id`), + KEY `idx_gm_vip_gift_applicant` (`applicant_id`), + KEY `idx_gm_vip_gift_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='GM VIP赠送记录'; + +SET @gm_operation_menu_id := ( + SELECT `id` FROM `sys_menu` WHERE `alias` = 'GmOperation' LIMIT 1 +); + +INSERT INTO `sys_menu` ( + `id`, `parent_id`, `menu_name`, `path`, `menu_type`, `icon`, `create_user`, `update_user`, + `sort`, `status`, `router`, `alias` +) +SELECT + 1700000403, @gm_operation_menu_id, 'VIP赠送', 'gm/vip-gift', 2, 'lucide:badge', + '0', '0', 3, 0, 'vip-gift', 'GmVipGift' +WHERE @gm_operation_menu_id IS NOT NULL + AND NOT EXISTS ( + SELECT 1 FROM `sys_menu` WHERE `alias` = 'GmVipGift' +); + +UPDATE `sys_menu` +SET + `parent_id` = @gm_operation_menu_id, + `menu_name` = 'VIP赠送', + `path` = 'gm/vip-gift', + `menu_type` = 2, + `icon` = 'lucide:badge', + `create_user` = '0', + `update_user` = '0', + `sort` = 3, + `status` = 0, + `router` = 'vip-gift' +WHERE `alias` = 'GmVipGift'; + +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) +SELECT DISTINCT valid_source_role.`id`, target_menu.`id` +FROM `sys_role_menu` source +JOIN `sys_role` valid_source_role ON valid_source_role.`id` = source.`role_id` +JOIN `sys_menu` target_menu ON target_menu.`alias` = 'GmVipGift' +JOIN `sys_menu` source_menu ON source_menu.`alias` = 'GmGoldOperation' +WHERE source.`menu_id` = source_menu.`id` + AND NOT EXISTS ( + SELECT 1 FROM `sys_role_menu` target + WHERE target.`role_id` = source.`role_id` + AND target.`menu_id` = target_menu.`id` + );