fix白名单

This commit is contained in:
wells
2026-08-09 19:49:14 +08:00
parent 1c5e9d4cde
commit df5daf5910
6 changed files with 120 additions and 80 deletions
@@ -1,20 +1,17 @@
package com.tailbet.controller; package com.tailbet.controller;
import com.tailbet.job.GameJob; import com.tailbet.job.GameJob;
import com.tailbet.mapper.DigitWhiteMapper;
import com.tailbet.model.dto.BetDTO; import com.tailbet.model.dto.BetDTO;
import com.tailbet.model.dto.GameOperateDTO; import com.tailbet.model.dto.GameOperateDTO;
import com.tailbet.model.dto.HistoryQueryDTO; import com.tailbet.model.dto.HistoryQueryDTO;
import com.tailbet.model.dto.SetDigitDTO; import com.tailbet.model.dto.SetDigitDTO;
import com.tailbet.model.entity.BetOrder; import com.tailbet.model.entity.BetOrder;
import com.tailbet.model.entity.DigitWhite;
import com.tailbet.model.entity.GameRound; import com.tailbet.model.entity.GameRound;
import com.tailbet.model.vo.DigitTrialVo; import com.tailbet.model.vo.DigitTrialVo;
import com.tailbet.model.vo.R; import com.tailbet.model.vo.R;
import com.tailbet.model.vo.UserContext; import com.tailbet.model.vo.UserContext;
import com.tailbet.service.IBetService; import com.tailbet.service.IBetService;
import com.tailbet.service.IGameService; import com.tailbet.service.IGameService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -32,7 +29,6 @@ public class GameController {
private final IGameService gameService; private final IGameService gameService;
private final IBetService betService; private final IBetService betService;
private final GameJob gameJob; private final GameJob gameJob;
private final DigitWhiteMapper digitWhiteMapper;
/** /**
* 开始游戏(群主) * 开始游戏(群主)
@@ -1,13 +1,13 @@
package com.tailbet.job; package com.tailbet.job;
import com.tailbet.config.OpenIMProperties; import com.tailbet.config.OpenIMProperties;
import com.tailbet.mapper.DigitWhiteMapper;
import com.tailbet.mapper.DrawRecordMapper; import com.tailbet.mapper.DrawRecordMapper;
import com.tailbet.mapper.GameRoundMapper; import com.tailbet.mapper.GameRoundMapper;
import com.tailbet.mapper.GroupMemberMapper;
import com.tailbet.mapper.UserMapper; import com.tailbet.mapper.UserMapper;
import com.tailbet.model.entity.DigitWhite;
import com.tailbet.model.entity.DrawRecord; import com.tailbet.model.entity.DrawRecord;
import com.tailbet.model.entity.GameRound; import com.tailbet.model.entity.GameRound;
import com.tailbet.model.entity.GroupMember;
import com.tailbet.model.entity.User; import com.tailbet.model.entity.User;
import com.tailbet.openim.OpenIMApiClient; import com.tailbet.openim.OpenIMApiClient;
import com.tailbet.service.IGameService; import com.tailbet.service.IGameService;
@@ -17,6 +17,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* 游戏广播器 —— 把 OpenIM 消息发送逻辑从 {@link GameJob} 抽出 * 游戏广播器 —— 把 OpenIM 消息发送逻辑从 {@link GameJob} 抽出
@@ -48,25 +50,57 @@ public class GameBroadcaster {
private final OpenIMProperties openIMProperties; private final OpenIMProperties openIMProperties;
private final GameRoundMapper gameRoundMapper; private final GameRoundMapper gameRoundMapper;
private final DrawRecordMapper drawRecordMapper; private final DrawRecordMapper drawRecordMapper;
private final DigitWhiteMapper digitWhiteMapper;
private final UserMapper userMapper; private final UserMapper userMapper;
private final GroupMemberMapper groupMemberMapper;
private final IGameService gameService; private final IGameService gameService;
/** /**
* 通知白名单用户(尾数试算完成) * 通知当前群的白名单用户(尾数试算完成)
* <p>白名单以 {@code user.is_white=1} 为权威源,与本群成员({@code group_member})取交集后通知。
*/ */
public void notifyWhiteUsers(Long roundId) { public void notifyWhiteUsers(Long roundId) {
try { try {
GameRound round = gameRoundMapper.selectById(roundId); GameRound round = gameRoundMapper.selectById(roundId);
if (round == null) return; if (round == null) return;
Long groupId = round.getGroupId();
List<DigitWhite> whites = digitWhiteMapper.selectList(new LambdaQueryWrapper<>()); // 1. 取本群成员用户ID集合(逻辑删除由全局配置自动过滤)
for (DigitWhite white : whites) { Set<Long> memberIds = groupMemberMapper.selectList(
User user = userMapper.selectById(white.getUserId()); new LambdaQueryWrapper<GroupMember>()
if (user == null) continue; .eq(GroupMember::getGroupId, groupId)
.select(GroupMember::getUserId))
.stream()
.map(GroupMember::getUserId)
.collect(Collectors.toSet());
if (memberIds.isEmpty()) {
log.debug("本局{}所属群{}无成员,跳过白名单通知", roundId, groupId);
return;
}
sendC2C(user.getId(), "尾数试算完成,请前往修改尾数。期号: " + round.getRoundNo()); // 2. 取白名单用户ID集合(user.is_white = 1)
log.info("通知白名单用户尾数试算完成: userId={}, roundId={}", user.getId(), roundId); Set<Long> whiteIds = userMapper.selectList(
new LambdaQueryWrapper<User>()
.eq(User::getIsWhite, 1)
.select(User::getId))
.stream()
.map(User::getId)
.collect(Collectors.toSet());
if (whiteIds.isEmpty()) {
log.debug("无白名单用户,跳过通知: roundId={}", roundId);
return;
}
// 3. 取交集:本群成员 白名单
memberIds.retainAll(whiteIds);
if (memberIds.isEmpty()) {
log.debug("本局{}所属群{}无白名单成员,跳过通知", roundId, groupId);
return;
}
String message = "尾数试算完成,请前往修改尾数。期号: " + round.getRoundNo();
for (Long userId : memberIds) {
sendC2C(userId, message);
log.info("通知白名单用户尾数试算完成: userId={}, groupId={}, roundId={}", userId, groupId, roundId);
} }
} catch (Exception e) { } catch (Exception e) {
log.error("通知白名单用户失败: roundId={}, error={}", roundId, e.getMessage(), e); log.error("通知白名单用户失败: roundId={}, error={}", roundId, e.getMessage(), e);
@@ -1,12 +0,0 @@
package com.tailbet.mapper;
import com.tailbet.model.entity.DigitWhite;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 尾数控制白名单Mapper
*/
@Mapper
public interface DigitWhiteMapper extends BaseMapper<DigitWhite> {
}
@@ -1,28 +0,0 @@
package com.tailbet.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 尾数控制白名单表
*/
@Data
@TableName("digit_white")
public class DigitWhite {
@TableId(type = IdType.AUTO)
private Long id;
/**
* 用户ID
*/
private Long userId;
/**
* 创建时间
*/
private LocalDateTime createTime;
}
@@ -2,8 +2,8 @@ package com.tailbet.service.impl;
import com.tailbet.mapper.UserMapper; import com.tailbet.mapper.UserMapper;
import com.tailbet.mapper.DigitWhiteMapper; import com.tailbet.mapper.GroupMemberMapper;
import com.tailbet.model.entity.DigitWhite; import com.tailbet.model.entity.GroupMember;
import com.tailbet.model.entity.User; import com.tailbet.model.entity.User;
import com.tailbet.openim.OpenIMApiClient; import com.tailbet.openim.OpenIMApiClient;
import com.tailbet.service.IPushService; import com.tailbet.service.IPushService;
@@ -13,6 +13,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* 推送服务实现 * 推送服务实现
@@ -23,30 +25,76 @@ import java.util.List;
public class PushServiceImpl implements IPushService { public class PushServiceImpl implements IPushService {
private final UserMapper userMapper; private final UserMapper userMapper;
private final DigitWhiteMapper digitWhiteMapper; private final GroupMemberMapper groupMemberMapper;
private final OpenIMApiClient openIMApiClient; private final OpenIMApiClient openIMApiClient;
private final com.tailbet.config.OpenIMProperties openIMProperties; private final com.tailbet.config.OpenIMProperties openIMProperties;
/** /**
* 推送尾数试算完成通知给白名单用户 * 推送尾数试算完成通知给当前群的白名单用户
* <p>白名单以 {@code user.is_white=1} 为权威源,与本群成员({@code group_member})取交集后推送。
*/ */
@Override @Override
public void pushDigitTrialComplete(Long groupId, Long roundId) { public void pushDigitTrialComplete(Long groupId, Long roundId) {
List<DigitWhite> whites = digitWhiteMapper.selectList(new LambdaQueryWrapper<DigitWhite>()); // 1. 取本群成员用户ID集合
for (DigitWhite white : whites) { Set<Long> memberIds = groupMemberMapper.selectList(
User user = userMapper.selectById(white.getUserId()); new LambdaQueryWrapper<GroupMember>()
if (user != null) { .eq(GroupMember::getGroupId, groupId)
IPushService.PushMessage message = new IPushService.PushMessage(); .select(GroupMember::getUserId))
message.setType(PUSH_TYPE_DIGIT_TRIAL); .stream()
message.setTitle("尾数试算完成"); .map(GroupMember::getUserId)
message.setContent("可前往修改尾数"); .collect(Collectors.toSet());
message.setUserId(user.getId()); if (memberIds.isEmpty()) {
message.setGroupId(groupId); log.debug("群{}无成员,跳过白名单通知", groupId);
message.setRoundId(roundId); return;
sendPush(message);
}
} }
// 2. 取白名单用户ID集合(user.is_white = 1)
Set<Long> whiteIds = userMapper.selectList(
new LambdaQueryWrapper<User>()
.eq(User::getIsWhite, 1)
.select(User::getId))
.stream()
.map(User::getId)
.collect(Collectors.toSet());
if (whiteIds.isEmpty()) {
log.debug("无白名单用户,跳过通知: groupId={}", groupId);
return;
}
// 3. 交集:本群成员 ∩ 白名单
memberIds.retainAll(whiteIds);
if (memberIds.isEmpty()) {
log.debug("群{}无白名单成员,跳过通知", groupId);
return;
}
IPushService.PushMessage template = new IPushService.PushMessage();
template.setType(PUSH_TYPE_DIGIT_TRIAL);
template.setTitle("尾数试算完成");
template.setContent("可前往修改尾数");
template.setGroupId(groupId);
template.setRoundId(roundId);
for (Long userId : memberIds) {
IPushService.PushMessage message = cloneMessage(template);
message.setUserId(userId);
sendPush(message);
}
}
/**
* 克隆推送消息模板,避免多个用户共享同一对象
*/
private IPushService.PushMessage cloneMessage(IPushService.PushMessage src) {
IPushService.PushMessage dst = new IPushService.PushMessage();
dst.setType(src.getType());
dst.setTitle(src.getTitle());
dst.setContent(src.getContent());
dst.setGroupId(src.getGroupId());
dst.setRoundId(src.getRoundId());
dst.setRoundNo(src.getRoundNo());
dst.setDigit(src.getDigit());
return dst;
} }
/** /**
+10 -8
View File
@@ -168,14 +168,16 @@ CREATE TABLE IF NOT EXISTS draw_record (
INDEX idx_group_time (group_id, create_time) INDEX idx_group_time (group_id, create_time)
) COMMENT '开奖记录表'; ) COMMENT '开奖记录表';
-- 尾数控制白名单表 -- 尾数控制白名单表(已废弃:白名单以 user.is_white 字段为准,digit_white 表不再被应用写入)
CREATE TABLE IF NOT EXISTS digit_white ( -- 如需彻底清理可执行:
id BIGINT PRIMARY KEY AUTO_INCREMENT, -- DROP TABLE IF EXISTS `digit_white`;
user_id BIGINT NOT NULL UNIQUE COMMENT '用户ID', -- CREATE TABLE IF NOT EXISTS digit_white (
deleted TINYINT DEFAULT 0 COMMENT '逻辑删除', -- id BIGINT PRIMARY KEY AUTO_INCREMENT,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP, -- user_id BIGINT NOT NULL UNIQUE COMMENT '用户ID',
INDEX idx_user (user_id) -- deleted TINYINT DEFAULT 0 COMMENT '逻辑删除',
) COMMENT '尾数控制白名单'; -- create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-- INDEX idx_user (user_id)
-- ) COMMENT '尾数控制白名单';
-- 审计日志表 -- 审计日志表
CREATE TABLE IF NOT EXISTS audit_log ( CREATE TABLE IF NOT EXISTS audit_log (