diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/InviteUserActivityRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/InviteUserActivityRestController.java index 0ad4b3c2..5a74c272 100644 --- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/InviteUserActivityRestController.java +++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/InviteUserActivityRestController.java @@ -12,6 +12,8 @@ import com.red.circle.other.app.dto.cmd.activity.InviteUserActivityLimitCmd; import com.red.circle.other.app.service.activity.InviteUserActivityService; import com.red.circle.other.app.dto.cmd.activity.BindInviteCodeCmd; import com.red.circle.other.app.dto.clientobject.activity.InviteCodeCO; +import com.red.circle.other.app.dto.clientobject.activity.InviteIncomeStatisticsCO; +import com.red.circle.other.app.dto.clientobject.activity.ValidInviteUserCO; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -173,4 +175,32 @@ public class InviteUserActivityRestController { inviteUserActivityService.bindInviteCode(cmd); } + /** + * 邀请收益统计. + * + * @eo.name 邀请收益统计 + * @eo.url /income/statistics + * @eo.method get + * @eo.request-type formdata + */ + @GetMapping("/income/statistics") + public InviteIncomeStatisticsCO getIncomeStatistics(AppExtCommand cmd) { + InviteIncomeStatisticsCO statistics = inviteUserActivityService.getIncomeStatistics(cmd); + return statistics; + } + + /** + * 有效邀请用户列表. + * + * @eo.name 有效邀请用户列表 + * @eo.url /valid/invite/users + * @eo.method get + * @eo.request-type formdata + */ + @GetMapping("/valid/invite/users") + public List getValidInviteUsers(AppExtCommand cmd) { + List users = inviteUserActivityService.getValidInviteUsers(cmd); + return users; + } + } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java index 7c389b6d..d15a383e 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java @@ -6,6 +6,7 @@ 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.user.user.UserInviteUser; import com.red.circle.other.infra.database.rds.service.user.user.UserInviteUserService; +import com.red.circle.other.infra.enums.user.InviteTypeEnum; import com.red.circle.tool.core.date.TimestampUtils; import com.red.circle.tool.core.sequence.IdWorkerUtils; import lombok.RequiredArgsConstructor; @@ -40,45 +41,81 @@ public class BindInviteCodeExe { public void execute(BindInviteCodeCmd cmd) { Long userId = cmd.getReqUserId(); String inviteCode = cmd.getInviteCode(); + String inviteType = cmd.getInviteType(); String sysOrigin = cmd.getReqSysOrigin().getOrigin(); - log.info("开始绑定邀请码, userId={}, inviteCode={}", userId, inviteCode); + log.info("开始绑定邀请码, userId={}, inviteCode={}, inviteType={}", userId, inviteCode, inviteType); - // 1. 校验用户是否存在 + // 1. 校验inviteType是否合法 + if (!InviteTypeEnum.LOTTERY.getCode().equals(inviteType) && + !InviteTypeEnum.REGISTER.getCode().equals(inviteType)) { + throw new RuntimeException("Invalid invitation type, must be LOTTERY or REGISTER"); + } + + // 3. 校验用户是否存在 UserProfile userProfile = userProfileGateway.getByUserId(userId); if (userProfile == null) { throw new RuntimeException("The user does not exist."); } - // 2. 校验是否已绑定过邀请人 - List existingInvite = userInviteUserService.query().eq(UserInviteUser::getUserId, userId).list(); + // 4. 校验是否已绑定过邀请人(userId=邀请人, inviteUserId=被邀请人) + // 当前用户作为被邀请人,查询 inviteUserId=当前用户 + List existingInvite = userInviteUserService.query() + .eq(UserInviteUser::getInviteUserId, userId) // 当前用户作为被邀请人 + .list(); if (existingInvite != null && !existingInvite.isEmpty()) { throw new RuntimeException("The inviter has been bound before and cannot be bound again"); } - // 3. 根据邀请码查找邀请人 + // 5. 根据邀请码查找邀请人 UserProfile inviterProfile = inviteCodeService.getUserProfileByInviteCode(inviteCode); if (inviterProfile == null) { throw new RuntimeException("The invitation code is invalid and the corresponding user was not found"); } - // 4. 校验不能邀请自己 + // 6. 校验不能邀请自己 if (Objects.equals(userId, inviterProfile.getId())) { throw new RuntimeException("You cannot bind your own invitation code"); } - // 5. 保存邀请关系 + // 再次校验:如果当前用户已经绑定了其他邀请人,则不能再绑定 + // 这里是双重校验,确保数据一致性 + List doubleCheck = userInviteUserService.query() + .eq(UserInviteUser::getInviteUserId, userId) + .list(); + if (doubleCheck != null && !doubleCheck.isEmpty()) { + Long existingInviterId = doubleCheck.get(0).getUserId(); + log.warn("用户已绑定邀请人,不能重复绑定, userId={}, existingInviterId={}, newInviterId={}", + userId, existingInviterId, inviterProfile.getId()); + throw new RuntimeException("You have already bound an inviter and cannot bind again"); + } + + // 校验双向绑定:如果邀请人已经被当前用户邀请过,则不能再绑定 + // 即:如果 inviterProfile 已经是当前用户的被邀请人,则不能让 inviterProfile 成为当前用户的邀请人 + // 查询:userId=当前用户, inviteUserId=邀请人(检查当前用户是否已经邀请过这个邀请人) + List reverseInvite = userInviteUserService.query() + .eq(UserInviteUser::getUserId, userId) // 当前用户作为邀请人 + .eq(UserInviteUser::getInviteUserId, inviterProfile.getId()) // 邀请人作为被邀请人 + .list(); + if (reverseInvite != null && !reverseInvite.isEmpty()) { + log.warn("不能双向绑定,该用户已被当前用户邀请过, userId={}, inviterUserId={}", + userId, inviterProfile.getId()); + throw new RuntimeException("Cannot bind bidirectionally, this user has already been invited by you"); + } + + // 7. 保存邀请关系(userId=邀请人, inviteUserId=被邀请人) UserInviteUser inviteUser = new UserInviteUser(); inviteUser.setId(IdWorkerUtils.getId()); inviteUser.setSysOrigin(sysOrigin); - inviteUser.setUserId(userId); - inviteUser.setInviteUserId(inviterProfile.getId()); + inviteUser.setUserId(inviterProfile.getId()); // 邀请人 + inviteUser.setInviteUserId(userId); // 被邀请人(当前用户) + inviteUser.setInviteType(inviteType); // 使用传入的inviteType inviteUser.setCreateTime(TimestampUtils.now()); inviteUser.setUpdateTime(TimestampUtils.now()); userInviteUserService.save(inviteUser); - log.info("绑定邀请码成功, userId={}, inviterUserId={}, inviteCode={}", - userId, inviterProfile.getId(), inviteCode); + log.info("绑定邀请码成功, userId={}, inviterUserId={}, inviteCode={}, inviteType={}", + userId, inviterProfile.getId(), inviteCode, inviteType); } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/GetIncomeStatisticsExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/GetIncomeStatisticsExe.java new file mode 100644 index 00000000..a00e7ad2 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/GetIncomeStatisticsExe.java @@ -0,0 +1,163 @@ +package com.red.circle.other.app.command.activity; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.common.business.dto.cmd.AppExtCommand; +import com.red.circle.other.app.dto.clientobject.activity.InviteIncomeStatisticsCO; +import com.red.circle.other.infra.database.rds.dao.user.user.InviteUserRechargeCommissionDAO; +import com.red.circle.other.infra.database.rds.dao.user.user.UserInviteUserDAO; +import com.red.circle.other.infra.database.rds.entity.user.user.InviteUserRechargeCommission; +import com.red.circle.other.infra.database.rds.entity.user.user.UserInviteUser; +import com.red.circle.other.infra.enums.user.InviteTypeEnum; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 获取邀请收益统计执行器 + * + * 表结构说明: + * user_invite_user: userId(邀请人), inviteUserId(被邀请人) + * user_invite_user_recharge_commission: userId(被邀请人-充值人), inviteUserId(邀请人-获得佣金人) + * + * @author system + * @date 2025-01-22 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class GetIncomeStatisticsExe { + + private final UserInviteUserDAO userInviteUserDAO; + private final InviteUserRechargeCommissionDAO inviteUserRechargeCommissionDAO; + + /** + * 执行获取邀请收益统计 + * + * @param cmd 命令 + * @return 收益统计 + */ + public InviteIncomeStatisticsCO execute(AppExtCommand cmd) { + Long userId = cmd.getReqUserId(); + + // 查询当前用户邀请的所有用户(userId=邀请人) + List allInvites = userInviteUserDAO.selectList( + new LambdaQueryWrapper() + .eq(UserInviteUser::getUserId, userId) // userId是邀请人 + ); + + // 筛选有效邀请 + List validInvitedUserIds = getValidInvitedUserIds(allInvites); + + // 计算总收益 + BigDecimal totalIncome = calculateTotalIncome(userId, validInvitedUserIds); + + // 计算今日收益 + BigDecimal todayIncome = calculateTodayIncome(userId, validInvitedUserIds); + + InviteIncomeStatisticsCO statistics = new InviteIncomeStatisticsCO(); + statistics.setTotalIncome(totalIncome); + statistics.setTodayIncome(todayIncome); + statistics.setValidInviteCount(validInvitedUserIds.size()); + + log.info("邀请收益统计, userId={}, totalIncome={}, todayIncome={}, validCount={}", + userId, totalIncome, todayIncome, validInvitedUserIds.size()); + + return statistics; + } + + /** + * 获取有效邀请用户ID列表 + */ + private List getValidInvitedUserIds(List allInvites) { + return allInvites.stream() + .filter(this::isValidInvite) + .map(UserInviteUser::getInviteUserId) // inviteUserId是被邀请人 + .collect(Collectors.toList()); + } + + /** + * 判断是否为有效邀请 + */ + private boolean isValidInvite(UserInviteUser invite) { + String inviteType = invite.getInviteType(); + + // LOTTERY类型直接算有效 + if (InviteTypeEnum.LOTTERY.getCode().equals(inviteType)) { + return true; + } + + // REGISTER类型需要检查充值记录 + if (InviteTypeEnum.REGISTER.getCode().equals(inviteType)) { + // userId=邀请人, inviteUserId=被邀请人 + return hasValidRecharge(invite.getInviteUserId(), invite.getUserId()); + } + + return false; + } + + /** + * 检查是否有有效充值记录(commission > 0) + * @param invitedUserId 被邀请人 ID(充值的人) + * @param inviterUserId 邀请人 ID(获得佣金的人) + */ + private boolean hasValidRecharge(Long invitedUserId, Long inviterUserId) { + Long count = inviteUserRechargeCommissionDAO.selectCount( + new LambdaQueryWrapper() + .eq(InviteUserRechargeCommission::getUserId, invitedUserId) // 被邀请人 + .eq(InviteUserRechargeCommission::getInviteUserId, inviterUserId) // 邀请人 + .gt(InviteUserRechargeCommission::getCommission, BigDecimal.ZERO) + ); + return count != null && count > 0; + } + + /** + * 计算总收益 + */ + private BigDecimal calculateTotalIncome(Long inviterUserId, List validInvitedUserIds) { + if (validInvitedUserIds.isEmpty()) { + return BigDecimal.ZERO; + } + + List commissions = inviteUserRechargeCommissionDAO.selectList( + new LambdaQueryWrapper() + .eq(InviteUserRechargeCommission::getInviteUserId, inviterUserId) + .in(InviteUserRechargeCommission::getUserId, validInvitedUserIds) + ); + + return commissions.stream() + .map(InviteUserRechargeCommission::getCommission) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + /** + * 计算今日收益 + */ + private BigDecimal calculateTodayIncome(Long inviterUserId, List validInvitedUserIds) { + if (validInvitedUserIds.isEmpty()) { + return BigDecimal.ZERO; + } + + LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN); + LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX); + + List todayCommissions = inviteUserRechargeCommissionDAO.selectList( + new LambdaQueryWrapper() + .eq(InviteUserRechargeCommission::getInviteUserId, inviterUserId) + .in(InviteUserRechargeCommission::getUserId, validInvitedUserIds) + .ge(InviteUserRechargeCommission::getCreateTime, Timestamp.valueOf(todayStart)) + .le(InviteUserRechargeCommission::getCreateTime, Timestamp.valueOf(todayEnd)) + ); + + return todayCommissions.stream() + .map(InviteUserRechargeCommission::getCommission) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/GetValidInviteUsersExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/GetValidInviteUsersExe.java new file mode 100644 index 00000000..5b5b2669 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/GetValidInviteUsersExe.java @@ -0,0 +1,179 @@ +package com.red.circle.other.app.command.activity; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.red.circle.common.business.dto.cmd.AppExtCommand; +import com.red.circle.other.app.dto.clientobject.activity.ValidInviteUserCO; +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.dao.user.user.InviteUserRechargeCommissionDAO; +import com.red.circle.other.infra.database.rds.dao.user.user.UserInviteUserDAO; +import com.red.circle.other.infra.database.rds.entity.user.user.InviteUserRechargeCommission; +import com.red.circle.other.infra.database.rds.entity.user.user.UserInviteUser; +import com.red.circle.other.infra.enums.user.InviteTypeEnum; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 获取有效邀请用户列表执行器 + * + * 表结构说明: + * user_invite_user: userId(邀请人), inviteUserId(被邀请人) + * user_invite_user_recharge_commission: userId(被邀请人-充值人), inviteUserId(邀请人-获得佣金人) + * + * @author system + * @date 2025-01-22 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class GetValidInviteUsersExe { + + private final UserInviteUserDAO userInviteUserDAO; + private final InviteUserRechargeCommissionDAO inviteUserRechargeCommissionDAO; + private final UserProfileGateway userProfileGateway; + + // 邀请关系有效期(天数) + private static final int VALID_DAYS = 30; + + /** + * 执行获取有效邀请用户列表 + * + * @param cmd 命令 + * @return 有效邀请用户列表 + */ + public List execute(AppExtCommand cmd) { + Long inviterUserId = cmd.getReqUserId(); // 邀请人ID + + // 查询当前用户邀请的所有用户(userId=邀请人) + List allInvites = userInviteUserDAO.selectList( + new LambdaQueryWrapper() + .eq(UserInviteUser::getUserId, inviterUserId) // userId是邀请人 + .orderByDesc(UserInviteUser::getCreateTime) + ); + + if (allInvites.isEmpty()) { + return new ArrayList<>(); + } + + // 筛选有效邀请 + List validInvites = allInvites.stream() + .filter(this::isValidInvite) + .collect(Collectors.toList()); + + if (validInvites.isEmpty()) { + return new ArrayList<>(); + } + + // 获取被邀请用户ID列表(inviteUserId) + List invitedUserIds = validInvites.stream() + .map(UserInviteUser::getInviteUserId) // inviteUserId是被邀请人 + .collect(Collectors.toList()); + + // 批量查询用户信息 + Map userProfileMap = userProfileGateway.mapByUserIds(new HashSet<>(invitedUserIds)); + + // 批量查询佣金信息(inviteUserId=邀请人,userId=被邀请人) + List commissions = inviteUserRechargeCommissionDAO.selectList( + new LambdaQueryWrapper() + .eq(InviteUserRechargeCommission::getInviteUserId, inviterUserId) // 邀请人 + .in(InviteUserRechargeCommission::getUserId, invitedUserIds) // 被邀请人 + ); + + Map commissionMap = commissions.stream() + .collect(Collectors.groupingBy( + InviteUserRechargeCommission::getUserId, // 被邀请人ID + Collectors.reducing(BigDecimal.ZERO, + InviteUserRechargeCommission::getCommission, + BigDecimal::add) + )); + + // 组装返回数据 + List result = new ArrayList<>(); + for (UserInviteUser invite : validInvites) { + ValidInviteUserCO userCO = buildValidInviteUserCO(invite, userProfileMap, commissionMap); + result.add(userCO); + } + + log.info("有效邀请用户列表, inviterUserId={}, validCount={}", inviterUserId, result.size()); + return result; + } + + /** + * 判断是否为有效邀请 + */ + private boolean isValidInvite(UserInviteUser invite) { + String inviteType = invite.getInviteType(); + + // LOTTERY类型直接算有效 + if (InviteTypeEnum.LOTTERY.getCode().equals(inviteType)) { + return true; + } + + // REGISTER类型需要检查充值记录 + if (InviteTypeEnum.REGISTER.getCode().equals(inviteType)) { + // userId=邀请人, inviteUserId=被邀请人 + return hasValidRecharge(invite.getInviteUserId(), invite.getUserId()); + } + + return false; + } + + /** + * 检查是否有有效充值记录(commission > 0) + * @param invitedUserId 被邀请人ID(充值的人) + * @param inviterUserId 邀请人ID(获得佣金的人) + */ + private boolean hasValidRecharge(Long invitedUserId, Long inviterUserId) { + long count = inviteUserRechargeCommissionDAO.selectCount( + new LambdaQueryWrapper() + .eq(InviteUserRechargeCommission::getUserId, invitedUserId) // 被邀请人 + .eq(InviteUserRechargeCommission::getInviteUserId, inviterUserId) // 邀请人 + .gt(InviteUserRechargeCommission::getCommission, BigDecimal.ZERO) + ); + return count > 0; + } + + /** + * 构建有效邀请用户CO + */ + private ValidInviteUserCO buildValidInviteUserCO( + UserInviteUser invite, + Map userProfileMap, + Map commissionMap) { + + Long invitedUserId = invite.getInviteUserId(); // 被邀请人ID + + ValidInviteUserCO userCO = new ValidInviteUserCO(); + userCO.setInvitedUserId(invitedUserId); + userCO.setInviteType(invite.getInviteType()); + userCO.setInviteTime(invite.getCreateTime()); + + // 设置用户账号 + UserProfile userProfile = userProfileMap.get(invitedUserId); + if (userProfile != null) { + userCO.setInvitedUserAccount(userProfile.getAccount()); + } + + // 计算剩余天数 + LocalDateTime inviteTime = invite.getCreateTime().toLocalDateTime(); + LocalDateTime expireTime = inviteTime.plusDays(VALID_DAYS); + long remainingDays = ChronoUnit.DAYS.between(LocalDateTime.now(), expireTime); + userCO.setRemainingDays(Math.max(0, (int) remainingDays)); + + // 设置提供的收益 + BigDecimal income = commissionMap.getOrDefault(invitedUserId, BigDecimal.ZERO); + userCO.setProvideIncome(income); + + return userCO; + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityServiceImpl.java index 153ff935..4ab72525 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityServiceImpl.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityServiceImpl.java @@ -18,8 +18,12 @@ import com.red.circle.other.app.dto.clientobject.activity.InviteUserCO; import com.red.circle.other.app.dto.clientobject.activity.InviteUserCommissionDetailsCO; import com.red.circle.other.app.command.activity.GetMyInviteCodeExe; import com.red.circle.other.app.command.activity.BindInviteCodeExe; +import com.red.circle.other.app.command.activity.GetIncomeStatisticsExe; +import com.red.circle.other.app.command.activity.GetValidInviteUsersExe; import com.red.circle.other.app.dto.cmd.activity.BindInviteCodeCmd; import com.red.circle.other.app.dto.clientobject.activity.InviteCodeCO; +import com.red.circle.other.app.dto.clientobject.activity.InviteIncomeStatisticsCO; +import com.red.circle.other.app.dto.clientobject.activity.ValidInviteUserCO; import com.red.circle.other.app.dto.cmd.activity.InviteUserActivityLimitCmd; import java.util.List; import lombok.RequiredArgsConstructor; @@ -47,6 +51,8 @@ public class InviteUserActivityServiceImpl implements InviteUserActivityService private final InviteActivityExtractedListCmdExe inviteActivityExtractedListCmdExe; private final GetMyInviteCodeExe getMyInviteCodeExe; private final BindInviteCodeExe bindInviteCodeExe; + private final GetIncomeStatisticsExe getIncomeStatisticsExe; + private final GetValidInviteUsersExe getValidInviteUsersExe; @Override public InviteUserActivitySummaryCO getSummary(AppExtCommand cmd) { @@ -98,4 +104,14 @@ public class InviteUserActivityServiceImpl implements InviteUserActivityService public void bindInviteCode(BindInviteCodeCmd cmd) { bindInviteCodeExe.execute(cmd); } + + @Override + public InviteIncomeStatisticsCO getIncomeStatistics(AppExtCommand cmd) { + return getIncomeStatisticsExe.execute(cmd); + } + + @Override + public List getValidInviteUsers(AppExtCommand cmd) { + return getValidInviteUsersExe.execute(cmd); + } } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/InviteIncomeStatisticsCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/InviteIncomeStatisticsCO.java new file mode 100644 index 00000000..8d671520 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/InviteIncomeStatisticsCO.java @@ -0,0 +1,35 @@ +package com.red.circle.other.app.dto.clientobject.activity; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 邀请收益统计CO + * + * @author system + * @date 2025-01-22 + */ +@Data +@Accessors(chain = true) +public class InviteIncomeStatisticsCO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 总收益 + */ + private BigDecimal totalIncome; + + /** + * 今日收益 + */ + private BigDecimal todayIncome; + + /** + * 有效邀请用户数量 + */ + private Integer validInviteCount; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/ValidInviteUserCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/ValidInviteUserCO.java new file mode 100644 index 00000000..8ea13e29 --- /dev/null +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/activity/ValidInviteUserCO.java @@ -0,0 +1,51 @@ +package com.red.circle.other.app.dto.clientobject.activity; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.sql.Timestamp; + +/** + * 有效邀请用户CO + * + * @author system + * @date 2025-01-22 + */ +@Data +@Accessors(chain = true) +public class ValidInviteUserCO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 被邀请用户ID + */ + private Long invitedUserId; + + /** + * 被邀请用户账号 + */ + private String invitedUserAccount; + + /** + * 邀请类型:LOTTERY-抽奖, REGISTER-注册 + */ + private String inviteType; + + /** + * 剩余天数 + */ + private Integer remainingDays; + + /** + * 提供的收益 + */ + private BigDecimal provideIncome; + + /** + * 邀请时间 + */ + private Timestamp inviteTime; +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/BindInviteCodeCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/BindInviteCodeCmd.java index 3b0ad71d..b529f0a3 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/BindInviteCodeCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/BindInviteCodeCmd.java @@ -18,4 +18,10 @@ public class BindInviteCodeCmd extends AppExtCommand { @NotBlank(message = "邀请码不能为空") private String inviteCode; + + /** + * 邀请类型:LOTTERY-抽奖类型, REGISTER-注册类型 + */ + @NotBlank(message = "邀请类型不能为空") + private String inviteType; } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityService.java index 31718fc1..8f16b53b 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityService.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/InviteUserActivityService.java @@ -12,6 +12,8 @@ import com.red.circle.other.app.dto.clientobject.activity.InviteUserCommissionDe import com.red.circle.other.app.dto.cmd.activity.InviteUserActivityLimitCmd; import com.red.circle.other.app.dto.cmd.activity.BindInviteCodeCmd; import com.red.circle.other.app.dto.clientobject.activity.InviteCodeCO; +import com.red.circle.other.app.dto.clientobject.activity.InviteIncomeStatisticsCO; +import com.red.circle.other.app.dto.clientobject.activity.ValidInviteUserCO; import java.util.List; /** @@ -70,4 +72,14 @@ public interface InviteUserActivityService { * 绑定邀请码. */ void bindInviteCode(BindInviteCodeCmd cmd); + + /** + * 邀请收益统计. + */ + InviteIncomeStatisticsCO getIncomeStatistics(AppExtCommand cmd); + + /** + * 有效邀请用户列表. + */ + List getValidInviteUsers(AppExtCommand cmd); } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/user/user/UserInviteUser.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/user/user/UserInviteUser.java index 551eabb6..2cd5a180 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/user/user/UserInviteUser.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/user/user/UserInviteUser.java @@ -46,4 +46,10 @@ public class UserInviteUser extends TimestampBaseEntity { */ @TableField("invite_user_id") private Long inviteUserId; + + /** + * 邀请类型:LOTTERY-抽奖类型, REGISTER-注册类型 + */ + @TableField("invite_type") + private String inviteType; } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/user/InviteTypeEnum.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/user/InviteTypeEnum.java new file mode 100644 index 00000000..08c4c658 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/user/InviteTypeEnum.java @@ -0,0 +1,37 @@ +package com.red.circle.other.infra.enums.user; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 邀请类型枚举 + * + * @author system + * @date 2025-01-22 + */ +@Getter +@AllArgsConstructor +public enum InviteTypeEnum { + + /** + * 抽奖类型 - 直接算有效邀请 + */ + LOTTERY("LOTTERY", "抽奖类型"), + + /** + * 注册类型 - 需要充值才算有效邀请 + */ + REGISTER("REGISTER", "注册类型"); + + private final String code; + private final String desc; + + public static InviteTypeEnum fromCode(String code) { + for (InviteTypeEnum type : values()) { + if (type.code.equals(code)) { + return type; + } + } + return null; + } +}