|
|
@@ -16,9 +16,11 @@ import com.xuekairui.user.entity.BusinessLicense;
|
|
|
import com.xuekairui.user.entity.User;
|
|
|
import com.xuekairui.user.enums.LicenseStatus;
|
|
|
import com.xuekairui.user.enums.MembershipLevel;
|
|
|
+import com.xuekairui.user.enums.OperationType;
|
|
|
import com.xuekairui.user.mapper.BusinessLicenseMapper;
|
|
|
import com.xuekairui.user.mapper.UserMapper;
|
|
|
import com.xuekairui.user.service.MembershipService;
|
|
|
+import com.xuekairui.user.service.OperationAuditLogService;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.dao.DuplicateKeyException;
|
|
|
@@ -64,6 +66,7 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
private final UserMapper userMapper;
|
|
|
private final BusinessLicenseMapper businessLicenseMapper;
|
|
|
private final MembershipService membershipService;
|
|
|
+ private final OperationAuditLogService auditLogService;
|
|
|
|
|
|
// ==========================================
|
|
|
// ActivityInviteGate 门面实现(供 InviteService 调用)
|
|
|
@@ -92,7 +95,7 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
}
|
|
|
|
|
|
// REGISTRATION 模式 → 立即发放
|
|
|
- grantWithLimit(inviterId, inviteeId, config);
|
|
|
+ grantWithLimit(inviterId, inviteeId, config, "REGISTRATION");
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -108,7 +111,7 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
log.info("邀请有礼活动未开启,跳过已入驻补填发奖: inviter={}, invitee={}", inviterId, inviteeId);
|
|
|
return;
|
|
|
}
|
|
|
- grantWithLimit(inviterId, inviteeId, config);
|
|
|
+ grantWithLimit(inviterId, inviteeId, config, "BIND_APPROVED");
|
|
|
log.info("已入驻用户补填邀请码,发放邀请奖励: inviter={}, invitee={}", inviterId, inviteeId);
|
|
|
}
|
|
|
|
|
|
@@ -174,7 +177,7 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
}
|
|
|
|
|
|
// 补发奖励
|
|
|
- grantWithLimit(inviterId, inviteeId, config);
|
|
|
+ grantWithLimit(inviterId, inviteeId, config, "RETROACTIVE");
|
|
|
granted++;
|
|
|
}
|
|
|
|
|
|
@@ -250,7 +253,7 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
}
|
|
|
|
|
|
Long inviterId = invitee.getInviterId();
|
|
|
- grantWithLimit(inviterId, userId, config);
|
|
|
+ grantWithLimit(inviterId, userId, config, "LICENSE_APPROVED");
|
|
|
}
|
|
|
|
|
|
// ==========================================
|
|
|
@@ -321,8 +324,10 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
/**
|
|
|
* 带活动限制的奖励发放(活动开启时使用)。
|
|
|
* 校验 30 次上限 + 幂等插入记录 + 发放会员。
|
|
|
+ *
|
|
|
+ * @param triggerSource 触发来源,用于审计日志(如 REGISTRATION / LICENSE_APPROVED / BIND_APPROVED / RETROACTIVE)
|
|
|
*/
|
|
|
- private void grantWithLimit(Long inviterId, Long inviteeId, ActivityInviteConfig config) {
|
|
|
+ private void grantWithLimit(Long inviterId, Long inviteeId, ActivityInviteConfig config, String triggerSource) {
|
|
|
// 1. 校验邀请人奖励次数上限
|
|
|
long rewarded = rewardRecordMapper.countByInviter(inviterId);
|
|
|
int maxReward = config.getMaxInviterReward() != null ? config.getMaxInviterReward() : 30;
|
|
|
@@ -345,9 +350,24 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 3. 发放奖励
|
|
|
+ // 3. 发放会员奖励
|
|
|
doGrantReward(inviterId, inviteeId, days);
|
|
|
- log.info("邀请有礼活动奖励已发放: inviter={}, invitee={}, days={}", inviterId, inviteeId, days);
|
|
|
+
|
|
|
+ // 4. 审计日志:记录邀请奖励发放
|
|
|
+ String inviterName = getUserNickname(inviterId);
|
|
|
+ String inviteeName = getUserNickname(inviteeId);
|
|
|
+ auditLogService.logSuccess(
|
|
|
+ inviterId,
|
|
|
+ inviterName,
|
|
|
+ "USER",
|
|
|
+ OperationType.INVITE_REWARD_GRANT,
|
|
|
+ "INVITE_REWARD:" + inviteeId,
|
|
|
+ inviterId,
|
|
|
+ null,
|
|
|
+ Map.of("triggerSource", triggerSource, "rewardDays", days, "rewardLevel", "PRO"),
|
|
|
+ String.format("%s → 邀请人%s获赠%d天PRO会员,触发来源:%s", inviteeName, inviterName, days, triggerSource));
|
|
|
+
|
|
|
+ log.info("邀请有礼活动奖励已发放: inviter={}, invitee={}, days={}, trigger={}", inviterId, inviteeId, days, triggerSource);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -396,10 +416,37 @@ public class ActivityInviteService implements ActivityInviteGate {
|
|
|
record.setRevokeTime(LocalDateTime.now());
|
|
|
rewardRecordMapper.updateById(record);
|
|
|
count++;
|
|
|
+
|
|
|
+ // 审计日志:记录奖励撤销
|
|
|
+ String inviterName = getUserNickname(record.getInviterId());
|
|
|
+ String inviteeName = getUserNickname(inviteeId);
|
|
|
+ auditLogService.logSuccess(
|
|
|
+ revokerId,
|
|
|
+ "运营(反作弊)",
|
|
|
+ "ADMIN",
|
|
|
+ OperationType.INVITE_REWARD_GRANT,
|
|
|
+ "INVITE_REVOKE:" + inviteeId,
|
|
|
+ record.getInviterId(),
|
|
|
+ Map.of("rewardDays", record.getRewardDays(), "rewardLevel", "PRO"),
|
|
|
+ null,
|
|
|
+ String.format("撤销邀请奖励:邀请人%s(因被邀请人%s作弊,原因:%s)", inviterName, inviteeName, reason));
|
|
|
+
|
|
|
log.warn("反作弊:撤销邀请奖励记录 id={}, inviter={}, invitee={}, reason={}",
|
|
|
record.getId(), record.getInviterId(), inviteeId, reason);
|
|
|
}
|
|
|
|
|
|
return count;
|
|
|
}
|
|
|
+
|
|
|
+ // ==========================================
|
|
|
+ // 辅助方法
|
|
|
+ // ==========================================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户昵称(用于审计日志等场景)
|
|
|
+ */
|
|
|
+ private String getUserNickname(Long userId) {
|
|
|
+ User user = userMapper.selectById(userId);
|
|
|
+ return user != null && user.getNickname() != null ? user.getNickname() : String.valueOf(userId);
|
|
|
+ }
|
|
|
}
|