diff --git a/src/main/java/com/tailbet/controller/GameController.java b/src/main/java/com/tailbet/controller/GameController.java
index f1d0a2f..673fbc8 100644
--- a/src/main/java/com/tailbet/controller/GameController.java
+++ b/src/main/java/com/tailbet/controller/GameController.java
@@ -1,20 +1,17 @@
package com.tailbet.controller;
import com.tailbet.job.GameJob;
-import com.tailbet.mapper.DigitWhiteMapper;
import com.tailbet.model.dto.BetDTO;
import com.tailbet.model.dto.GameOperateDTO;
import com.tailbet.model.dto.HistoryQueryDTO;
import com.tailbet.model.dto.SetDigitDTO;
import com.tailbet.model.entity.BetOrder;
-import com.tailbet.model.entity.DigitWhite;
import com.tailbet.model.entity.GameRound;
import com.tailbet.model.vo.DigitTrialVo;
import com.tailbet.model.vo.R;
import com.tailbet.model.vo.UserContext;
import com.tailbet.service.IBetService;
import com.tailbet.service.IGameService;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@@ -32,7 +29,6 @@ public class GameController {
private final IGameService gameService;
private final IBetService betService;
private final GameJob gameJob;
- private final DigitWhiteMapper digitWhiteMapper;
/**
* 开始游戏(群主)
diff --git a/src/main/java/com/tailbet/job/GameBroadcaster.java b/src/main/java/com/tailbet/job/GameBroadcaster.java
index 862057f..595034a 100644
--- a/src/main/java/com/tailbet/job/GameBroadcaster.java
+++ b/src/main/java/com/tailbet/job/GameBroadcaster.java
@@ -1,13 +1,13 @@
package com.tailbet.job;
import com.tailbet.config.OpenIMProperties;
-import com.tailbet.mapper.DigitWhiteMapper;
import com.tailbet.mapper.DrawRecordMapper;
import com.tailbet.mapper.GameRoundMapper;
+import com.tailbet.mapper.GroupMemberMapper;
import com.tailbet.mapper.UserMapper;
-import com.tailbet.model.entity.DigitWhite;
import com.tailbet.model.entity.DrawRecord;
import com.tailbet.model.entity.GameRound;
+import com.tailbet.model.entity.GroupMember;
import com.tailbet.model.entity.User;
import com.tailbet.openim.OpenIMApiClient;
import com.tailbet.service.IGameService;
@@ -17,6 +17,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* 游戏广播器 —— 把 OpenIM 消息发送逻辑从 {@link GameJob} 抽出
@@ -48,25 +50,57 @@ public class GameBroadcaster {
private final OpenIMProperties openIMProperties;
private final GameRoundMapper gameRoundMapper;
private final DrawRecordMapper drawRecordMapper;
- private final DigitWhiteMapper digitWhiteMapper;
private final UserMapper userMapper;
+ private final GroupMemberMapper groupMemberMapper;
private final IGameService gameService;
/**
- * 通知白名单用户(尾数试算完成)
+ * 通知当前群的白名单用户(尾数试算完成)
+ *
白名单以 {@code user.is_white=1} 为权威源,与本群成员({@code group_member})取交集后通知。
*/
public void notifyWhiteUsers(Long roundId) {
try {
GameRound round = gameRoundMapper.selectById(roundId);
if (round == null) return;
+ Long groupId = round.getGroupId();
- List whites = digitWhiteMapper.selectList(new LambdaQueryWrapper<>());
- for (DigitWhite white : whites) {
- User user = userMapper.selectById(white.getUserId());
- if (user == null) continue;
+ // 1. 取本群成员用户ID集合(逻辑删除由全局配置自动过滤)
+ Set memberIds = groupMemberMapper.selectList(
+ new LambdaQueryWrapper()
+ .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());
- log.info("通知白名单用户尾数试算完成: userId={}, roundId={}", user.getId(), roundId);
+ // 2. 取白名单用户ID集合(user.is_white = 1)
+ Set whiteIds = userMapper.selectList(
+ new LambdaQueryWrapper()
+ .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) {
log.error("通知白名单用户失败: roundId={}, error={}", roundId, e.getMessage(), e);
diff --git a/src/main/java/com/tailbet/mapper/DigitWhiteMapper.java b/src/main/java/com/tailbet/mapper/DigitWhiteMapper.java
deleted file mode 100644
index 385bcb2..0000000
--- a/src/main/java/com/tailbet/mapper/DigitWhiteMapper.java
+++ /dev/null
@@ -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 {
-}
diff --git a/src/main/java/com/tailbet/model/entity/DigitWhite.java b/src/main/java/com/tailbet/model/entity/DigitWhite.java
deleted file mode 100644
index b4ec5bc..0000000
--- a/src/main/java/com/tailbet/model/entity/DigitWhite.java
+++ /dev/null
@@ -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;
-}
diff --git a/src/main/java/com/tailbet/service/impl/PushServiceImpl.java b/src/main/java/com/tailbet/service/impl/PushServiceImpl.java
index eff7ff3..af69cdf 100644
--- a/src/main/java/com/tailbet/service/impl/PushServiceImpl.java
+++ b/src/main/java/com/tailbet/service/impl/PushServiceImpl.java
@@ -2,8 +2,8 @@ package com.tailbet.service.impl;
import com.tailbet.mapper.UserMapper;
-import com.tailbet.mapper.DigitWhiteMapper;
-import com.tailbet.model.entity.DigitWhite;
+import com.tailbet.mapper.GroupMemberMapper;
+import com.tailbet.model.entity.GroupMember;
import com.tailbet.model.entity.User;
import com.tailbet.openim.OpenIMApiClient;
import com.tailbet.service.IPushService;
@@ -13,6 +13,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
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 {
private final UserMapper userMapper;
- private final DigitWhiteMapper digitWhiteMapper;
+ private final GroupMemberMapper groupMemberMapper;
private final OpenIMApiClient openIMApiClient;
private final com.tailbet.config.OpenIMProperties openIMProperties;
/**
- * 推送尾数试算完成通知给白名单用户
+ * 推送尾数试算完成通知给当前群的白名单用户
+ * 白名单以 {@code user.is_white=1} 为权威源,与本群成员({@code group_member})取交集后推送。
*/
@Override
public void pushDigitTrialComplete(Long groupId, Long roundId) {
- List whites = digitWhiteMapper.selectList(new LambdaQueryWrapper());
- for (DigitWhite white : whites) {
- User user = userMapper.selectById(white.getUserId());
- if (user != null) {
- IPushService.PushMessage message = new IPushService.PushMessage();
- message.setType(PUSH_TYPE_DIGIT_TRIAL);
- message.setTitle("尾数试算完成");
- message.setContent("可前往修改尾数");
- message.setUserId(user.getId());
- message.setGroupId(groupId);
- message.setRoundId(roundId);
-
- sendPush(message);
- }
+ // 1. 取本群成员用户ID集合
+ Set memberIds = groupMemberMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(GroupMember::getGroupId, groupId)
+ .select(GroupMember::getUserId))
+ .stream()
+ .map(GroupMember::getUserId)
+ .collect(Collectors.toSet());
+ if (memberIds.isEmpty()) {
+ log.debug("群{}无成员,跳过白名单通知", groupId);
+ return;
}
+
+ // 2. 取白名单用户ID集合(user.is_white = 1)
+ Set whiteIds = userMapper.selectList(
+ new LambdaQueryWrapper()
+ .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;
}
/**
diff --git a/src/main/resources/sql/init.sql b/src/main/resources/sql/init.sql
index c94d893..f64ec7a 100644
--- a/src/main/resources/sql/init.sql
+++ b/src/main/resources/sql/init.sql
@@ -168,14 +168,16 @@ CREATE TABLE IF NOT EXISTS draw_record (
INDEX idx_group_time (group_id, create_time)
) COMMENT '开奖记录表';
--- 尾数控制白名单表
-CREATE TABLE IF NOT EXISTS digit_white (
- id BIGINT PRIMARY KEY AUTO_INCREMENT,
- user_id BIGINT NOT NULL UNIQUE COMMENT '用户ID',
- deleted TINYINT DEFAULT 0 COMMENT '逻辑删除',
- create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
- INDEX idx_user (user_id)
-) COMMENT '尾数控制白名单';
+-- 尾数控制白名单表(已废弃:白名单以 user.is_white 字段为准,digit_white 表不再被应用写入)
+-- 如需彻底清理可执行:
+-- DROP TABLE IF EXISTS `digit_white`;
+-- CREATE TABLE IF NOT EXISTS digit_white (
+-- id BIGINT PRIMARY KEY AUTO_INCREMENT,
+-- user_id BIGINT NOT NULL UNIQUE COMMENT '用户ID',
+-- deleted TINYINT DEFAULT 0 COMMENT '逻辑删除',
+-- create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
+-- INDEX idx_user (user_id)
+-- ) COMMENT '尾数控制白名单';
-- 审计日志表
CREATE TABLE IF NOT EXISTS audit_log (