koishi-plugin-bind-bot 2.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/handlers/base.handler.d.ts +12 -18
- package/lib/handlers/binding.handler.js +3 -3
- package/lib/handlers/buid.handler.js +4 -4
- package/lib/handlers/index.d.ts +1 -0
- package/lib/handlers/index.js +1 -0
- package/lib/handlers/lottery.handler.d.ts +42 -0
- package/lib/handlers/lottery.handler.js +225 -0
- package/lib/handlers/mcid.handler.js +56 -56
- package/lib/handlers/tag.handler.js +8 -8
- package/lib/handlers/whitelist.handler.js +14 -14
- package/lib/index.js +73 -1061
- package/lib/services/api.service.d.ts +70 -0
- package/lib/services/api.service.js +344 -0
- package/lib/services/database.service.d.ts +64 -0
- package/lib/services/database.service.js +451 -0
- package/lib/services/index.d.ts +6 -0
- package/lib/services/index.js +22 -0
- package/lib/services/nickname.service.d.ts +42 -0
- package/lib/services/nickname.service.js +225 -0
- package/lib/services/service-container.d.ts +17 -0
- package/lib/services/service-container.js +24 -0
- package/lib/types/config.d.ts +2 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +2 -0
- package/lib/types/update-data.d.ts +68 -0
- package/lib/types/update-data.js +5 -0
- package/lib/utils/helpers.d.ts +13 -0
- package/lib/utils/helpers.js +21 -0
- package/lib/utils/message-utils.d.ts +7 -2
- package/lib/utils/message-utils.js +117 -12
- package/package.json +1 -1
|
@@ -6,7 +6,9 @@ import { RconManager } from '../managers/rcon-manager';
|
|
|
6
6
|
import { MessageUtils } from '../utils/message-utils';
|
|
7
7
|
import { ForceBinder } from '../force-bind-utils';
|
|
8
8
|
import { GroupExporter } from '../export-utils';
|
|
9
|
-
import
|
|
9
|
+
import { ApiService } from '../services/api.service';
|
|
10
|
+
import { DatabaseService } from '../services/database.service';
|
|
11
|
+
import { NicknameService } from '../services/nickname.service';
|
|
10
12
|
/**
|
|
11
13
|
* Repositories 接口 - 聚合所有数据仓储
|
|
12
14
|
*/
|
|
@@ -17,32 +19,24 @@ export interface Repositories {
|
|
|
17
19
|
/**
|
|
18
20
|
* Handler 依赖项接口
|
|
19
21
|
* 包含所有 Handler 需要的共享函数和服务
|
|
22
|
+
*
|
|
23
|
+
* 重构说明:
|
|
24
|
+
* - 直接传入服务实例(apiService, databaseService, nicknameService)
|
|
25
|
+
* - 消除了 18 个包装函数,减少代码冗余
|
|
26
|
+
* - 服务方法通过实例直接调用,更清晰易维护
|
|
20
27
|
*/
|
|
21
28
|
export interface HandlerDependencies {
|
|
29
|
+
apiService: ApiService;
|
|
30
|
+
databaseService: DatabaseService;
|
|
31
|
+
nicknameService: NicknameService;
|
|
22
32
|
normalizeQQId: (userId: string) => string;
|
|
23
33
|
formatCommand: (cmd: string) => string;
|
|
24
|
-
formatUuid: (uuid: string) => string;
|
|
25
34
|
checkCooldown: (lastModified: Date | null, multiplier?: number) => boolean;
|
|
26
|
-
getCrafatarUrl: (uuid: string) => string;
|
|
27
|
-
getStarlightSkinUrl: (uuid: string) => string;
|
|
28
|
-
getMcBindByQQId: (qqId: string) => Promise<MCIDBIND | null>;
|
|
29
|
-
getMcBindByUsername: (username: string) => Promise<MCIDBIND | null>;
|
|
30
|
-
createOrUpdateMcBind: (userId: string, username: string, uuid: string, isAdmin?: boolean) => Promise<boolean>;
|
|
31
|
-
deleteMcBind: (userId: string) => Promise<boolean>;
|
|
32
|
-
checkUsernameExists: (username: string, currentUserId?: string, uuid?: string) => Promise<boolean>;
|
|
33
|
-
checkAndUpdateUsername: (bind: MCIDBIND) => Promise<MCIDBIND>;
|
|
34
|
-
checkAndUpdateUsernameWithCache: (bind: MCIDBIND) => Promise<MCIDBIND>;
|
|
35
|
-
validateUsername: (username: string) => Promise<any>;
|
|
36
|
-
validateBUID: (uid: string) => Promise<any>;
|
|
37
|
-
updateBuidInfoOnly: (qqId: string, buidUser: any) => Promise<boolean>;
|
|
38
35
|
isAdmin: (userId: string) => Promise<boolean>;
|
|
39
36
|
isMaster: (userId: string) => boolean;
|
|
40
37
|
sendMessage: (session: Session, content: any[], options?: any) => Promise<void>;
|
|
41
|
-
autoSetGroupNickname: (session: Session, mcUsername: string | null, buidUsername: string, targetUserId?: string, specifiedGroupId?: string) => Promise<void>;
|
|
42
|
-
checkNicknameFormat: (nickname: string, buidUsername: string, mcUsername: string | null) => boolean;
|
|
43
|
-
getBindInfo: (qqId: string) => Promise<MCIDBIND | null>;
|
|
44
|
-
getServerConfigById: (serverId: string) => any;
|
|
45
38
|
getFriendlyErrorMessage: (error: any) => string;
|
|
39
|
+
getServerConfigById: (serverId: string) => any;
|
|
46
40
|
rconManager: RconManager;
|
|
47
41
|
messageUtils: MessageUtils;
|
|
48
42
|
forceBinder: ForceBinder;
|
|
@@ -49,7 +49,7 @@ class BindingHandler extends base_handler_1.BaseHandler {
|
|
|
49
49
|
return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 已有进行中的绑定会话`)]);
|
|
50
50
|
}
|
|
51
51
|
// 检查目标用户当前绑定状态
|
|
52
|
-
const targetBind = await this.deps.
|
|
52
|
+
const targetBind = await this.deps.databaseService.getMcBindByQQId(normalizedTargetId);
|
|
53
53
|
// 如果两个账号都已绑定,不需要进入绑定流程
|
|
54
54
|
if (targetBind && targetBind.mcUsername && targetBind.buidUid) {
|
|
55
55
|
this.logger.info('交互绑定', `QQ(${normalizedTargetId})已完成全部绑定`, true);
|
|
@@ -99,7 +99,7 @@ class BindingHandler extends base_handler_1.BaseHandler {
|
|
|
99
99
|
return this.deps.sendMessage(session, [koishi_1.h.text('您已有进行中的绑定会话,请先完成当前绑定或等待会话超时')]);
|
|
100
100
|
}
|
|
101
101
|
// 检查用户当前绑定状态
|
|
102
|
-
const existingBind = await this.deps.
|
|
102
|
+
const existingBind = await this.deps.databaseService.getMcBindByQQId(normalizedUserId);
|
|
103
103
|
// 如果两个账号都已绑定(且MC不是temp用户名),不需要进入绑定流程
|
|
104
104
|
if (existingBind && existingBind.mcUsername && !existingBind.mcUsername.startsWith('_temp_') && existingBind.buidUid) {
|
|
105
105
|
this.logger.info('交互绑定', `QQ(${normalizedUserId})已完成全部绑定`, true);
|
|
@@ -173,7 +173,7 @@ class BindingHandler extends base_handler_1.BaseHandler {
|
|
|
173
173
|
if (normalizedQQId === normalizedMasterId)
|
|
174
174
|
return true;
|
|
175
175
|
// 查询MCIDBIND表中是否是管理员
|
|
176
|
-
const bind = await this.deps.
|
|
176
|
+
const bind = await this.deps.databaseService.getMcBindByQQId(normalizedQQId);
|
|
177
177
|
return bind && bind.isAdmin === true;
|
|
178
178
|
}
|
|
179
179
|
catch (error) {
|
|
@@ -499,7 +499,7 @@ class BuidHandler extends base_handler_1.BaseHandler {
|
|
|
499
499
|
const latestTargetBind = await this.repos.mcidbind.findByQQId(normalizedTargetId);
|
|
500
500
|
if (latestTargetBind) {
|
|
501
501
|
const mcName = latestTargetBind.mcUsername && !latestTargetBind.mcUsername.startsWith('_temp_') ? latestTargetBind.mcUsername : null;
|
|
502
|
-
await this.deps.autoSetGroupNickname(session, mcName, enhancedUser.username, normalizedTargetId);
|
|
502
|
+
await this.deps.nicknameService.autoSetGroupNickname(session, mcName, enhancedUser.username, String(enhancedUser.uid), normalizedTargetId);
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
505
|
catch (renameError) {
|
|
@@ -530,7 +530,7 @@ class BuidHandler extends base_handler_1.BaseHandler {
|
|
|
530
530
|
const latestBind = await this.repos.mcidbind.findByQQId(operatorQQId);
|
|
531
531
|
if (latestBind) {
|
|
532
532
|
const mcName = latestBind.mcUsername && !latestBind.mcUsername.startsWith('_temp_') ? latestBind.mcUsername : null;
|
|
533
|
-
await this.deps.autoSetGroupNickname(session, mcName, enhancedUser.username);
|
|
533
|
+
await this.deps.nicknameService.autoSetGroupNickname(session, mcName, enhancedUser.username, String(enhancedUser.uid));
|
|
534
534
|
}
|
|
535
535
|
}
|
|
536
536
|
catch (renameError) {
|
|
@@ -599,7 +599,7 @@ class BuidHandler extends base_handler_1.BaseHandler {
|
|
|
599
599
|
const latestTargetBind = await this.repos.mcidbind.findByQQId(normalizedTargetId);
|
|
600
600
|
if (latestTargetBind) {
|
|
601
601
|
const mcName = latestTargetBind.mcUsername && !latestTargetBind.mcUsername.startsWith('_temp_') ? latestTargetBind.mcUsername : null;
|
|
602
|
-
await this.deps.autoSetGroupNickname(session, mcName, buidUser.username, normalizedTargetId);
|
|
602
|
+
await this.deps.nicknameService.autoSetGroupNickname(session, mcName, buidUser.username, actualUid, normalizedTargetId);
|
|
603
603
|
this.logger.info('绑定', `管理员QQ(${operatorQQId})为QQ(${normalizedTargetId})B站绑定完成,已尝试设置群昵称`);
|
|
604
604
|
}
|
|
605
605
|
}
|
|
@@ -653,7 +653,7 @@ class BuidHandler extends base_handler_1.BaseHandler {
|
|
|
653
653
|
const latestBind = await this.repos.mcidbind.findByQQId(operatorQQId);
|
|
654
654
|
if (latestBind) {
|
|
655
655
|
const mcName = latestBind.mcUsername && !latestBind.mcUsername.startsWith('_temp_') ? latestBind.mcUsername : null;
|
|
656
|
-
await this.deps.autoSetGroupNickname(session, mcName, buidUser.username);
|
|
656
|
+
await this.deps.nicknameService.autoSetGroupNickname(session, mcName, buidUser.username, actualUid);
|
|
657
657
|
this.logger.info('绑定', `QQ(${operatorQQId})B站绑定完成,已尝试设置群昵称`);
|
|
658
658
|
}
|
|
659
659
|
}
|
package/lib/handlers/index.d.ts
CHANGED
package/lib/handlers/index.js
CHANGED
|
@@ -20,3 +20,4 @@ __exportStar(require("./binding.handler"), exports);
|
|
|
20
20
|
__exportStar(require("./whitelist.handler"), exports);
|
|
21
21
|
__exportStar(require("./buid.handler"), exports);
|
|
22
22
|
__exportStar(require("./mcid.handler"), exports);
|
|
23
|
+
__exportStar(require("./lottery.handler"), exports);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { BaseHandler } from './base.handler';
|
|
2
|
+
import type { LotteryResult } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* 天选开奖统计信息接口
|
|
5
|
+
*/
|
|
6
|
+
export interface LotteryStats {
|
|
7
|
+
totalWinners: number;
|
|
8
|
+
matchedCount: number;
|
|
9
|
+
notBoundCount: number;
|
|
10
|
+
tagAddedCount: number;
|
|
11
|
+
tagExistedCount: number;
|
|
12
|
+
matchedUsers: Array<{
|
|
13
|
+
qqId: string;
|
|
14
|
+
mcUsername: string;
|
|
15
|
+
buidUsername: string;
|
|
16
|
+
uid: number;
|
|
17
|
+
username: string;
|
|
18
|
+
}>;
|
|
19
|
+
tagName: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 天选开奖处理器
|
|
23
|
+
* 负责处理天选开奖结果并发送通知
|
|
24
|
+
*/
|
|
25
|
+
export declare class LotteryHandler extends BaseHandler {
|
|
26
|
+
/**
|
|
27
|
+
* 注册方法(天选处理器不需要注册命令)
|
|
28
|
+
*/
|
|
29
|
+
register(): void;
|
|
30
|
+
/**
|
|
31
|
+
* 处理天选开奖结果
|
|
32
|
+
*/
|
|
33
|
+
handleLotteryResult(lotteryData: LotteryResult): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* 根据 BUID 查找绑定记录
|
|
36
|
+
* @deprecated 已废弃,使用 deps.getBuidBindByBuid() 替代(复用DatabaseService)
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* 发送天选开奖结果到群
|
|
40
|
+
*/
|
|
41
|
+
private sendLotteryResultToGroup;
|
|
42
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LotteryHandler = void 0;
|
|
4
|
+
const koishi_1 = require("koishi");
|
|
5
|
+
const base_handler_1 = require("./base.handler");
|
|
6
|
+
/**
|
|
7
|
+
* 天选开奖处理器
|
|
8
|
+
* 负责处理天选开奖结果并发送通知
|
|
9
|
+
*/
|
|
10
|
+
class LotteryHandler extends base_handler_1.BaseHandler {
|
|
11
|
+
/**
|
|
12
|
+
* 注册方法(天选处理器不需要注册命令)
|
|
13
|
+
*/
|
|
14
|
+
register() {
|
|
15
|
+
// 天选处理器不需要注册命令
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 处理天选开奖结果
|
|
19
|
+
*/
|
|
20
|
+
async handleLotteryResult(lotteryData) {
|
|
21
|
+
try {
|
|
22
|
+
// 检查天选播报开关
|
|
23
|
+
if (!this.config?.enableLotteryBroadcast) {
|
|
24
|
+
this.logger.debug('天选开奖', `天选播报功能已禁用,跳过处理天选事件: ${lotteryData.lottery_id}`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.logger.info('天选开奖', `开始处理天选事件: ${lotteryData.lottery_id},奖品: ${lotteryData.reward_name},中奖人数: ${lotteryData.winners.length}`, true);
|
|
28
|
+
// 生成标签名称
|
|
29
|
+
const tagName = `天选-${lotteryData.lottery_id}`;
|
|
30
|
+
// 统计信息
|
|
31
|
+
let matchedCount = 0;
|
|
32
|
+
let notBoundCount = 0;
|
|
33
|
+
let tagAddedCount = 0;
|
|
34
|
+
let tagExistedCount = 0;
|
|
35
|
+
const matchedUsers = [];
|
|
36
|
+
// 处理每个中奖用户
|
|
37
|
+
for (const winner of lotteryData.winners) {
|
|
38
|
+
try {
|
|
39
|
+
// 根据B站UID查找绑定的QQ用户(复用DatabaseService)
|
|
40
|
+
const bind = await this.deps.databaseService.getBuidBindByBuid(winner.uid.toString());
|
|
41
|
+
if (bind && bind.qqId) {
|
|
42
|
+
matchedCount++;
|
|
43
|
+
matchedUsers.push({
|
|
44
|
+
qqId: bind.qqId,
|
|
45
|
+
mcUsername: bind.mcUsername || '未绑定MC',
|
|
46
|
+
buidUsername: bind.buidUsername,
|
|
47
|
+
uid: winner.uid,
|
|
48
|
+
username: winner.username
|
|
49
|
+
});
|
|
50
|
+
// 检查是否已有该标签
|
|
51
|
+
if (bind.tags && bind.tags.includes(tagName)) {
|
|
52
|
+
tagExistedCount++;
|
|
53
|
+
this.logger.debug('天选开奖', `QQ(${bind.qqId})已有标签"${tagName}"`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// 添加标签
|
|
57
|
+
const newTags = [...(bind.tags || []), tagName];
|
|
58
|
+
await this.repos.mcidbind.update(bind.qqId, { tags: newTags });
|
|
59
|
+
tagAddedCount++;
|
|
60
|
+
this.logger.debug('天选开奖', `为QQ(${bind.qqId})添加标签"${tagName}"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
notBoundCount++;
|
|
65
|
+
this.logger.debug('天选开奖', `B站UID(${winner.uid})未绑定QQ账号`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
this.logger.error('天选开奖', `处理中奖用户UID(${winner.uid})时出错: ${error.message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
this.logger.info('天选开奖', `处理完成: 总计${lotteryData.winners.length}人中奖,匹配${matchedCount}人,未绑定${notBoundCount}人,新增标签${tagAddedCount}人,已有标签${tagExistedCount}人`, true);
|
|
73
|
+
// 生成并发送结果消息
|
|
74
|
+
await this.sendLotteryResultToGroup(lotteryData, {
|
|
75
|
+
totalWinners: lotteryData.winners.length,
|
|
76
|
+
matchedCount,
|
|
77
|
+
notBoundCount,
|
|
78
|
+
tagAddedCount,
|
|
79
|
+
tagExistedCount,
|
|
80
|
+
matchedUsers,
|
|
81
|
+
tagName
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
this.logger.error('天选开奖', `处理天选事件"${lotteryData.lottery_id}"失败: ${error.message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 根据 BUID 查找绑定记录
|
|
90
|
+
* @deprecated 已废弃,使用 deps.getBuidBindByBuid() 替代(复用DatabaseService)
|
|
91
|
+
*/
|
|
92
|
+
// private async getBuidBindByBuid(buid: string): Promise<MCIDBIND | null> {
|
|
93
|
+
// try {
|
|
94
|
+
// const allBinds = await this.repos.mcidbind.findAll()
|
|
95
|
+
// return allBinds.find(bind => bind.buidUid === buid) || null
|
|
96
|
+
// } catch (error) {
|
|
97
|
+
// this.logger.error('天选开奖', `查询BUID绑定失败: ${error.message}`)
|
|
98
|
+
// return null
|
|
99
|
+
// }
|
|
100
|
+
// }
|
|
101
|
+
/**
|
|
102
|
+
* 发送天选开奖结果到群
|
|
103
|
+
*/
|
|
104
|
+
async sendLotteryResultToGroup(lotteryData, stats) {
|
|
105
|
+
try {
|
|
106
|
+
// 从配置中获取目标群号和私聊目标
|
|
107
|
+
const targetChannelId = this.config?.lotteryTargetGroupId || '';
|
|
108
|
+
const privateTargetId = this.config?.lotteryTargetPrivateId || '';
|
|
109
|
+
// 检查配置是否有效
|
|
110
|
+
if (!targetChannelId && !privateTargetId) {
|
|
111
|
+
this.logger.warn('天选播报', '未配置播报目标(群ID或私聊ID),跳过播报');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// 格式化时间
|
|
115
|
+
const lotteryTime = new Date(lotteryData.timestamp).toLocaleString('zh-CN', {
|
|
116
|
+
timeZone: 'Asia/Shanghai',
|
|
117
|
+
year: 'numeric',
|
|
118
|
+
month: '2-digit',
|
|
119
|
+
day: '2-digit',
|
|
120
|
+
hour: '2-digit',
|
|
121
|
+
minute: '2-digit',
|
|
122
|
+
second: '2-digit'
|
|
123
|
+
});
|
|
124
|
+
// 构建简化版群消息(去掉主播信息、统计信息和标签提示)
|
|
125
|
+
let groupMessage = `🎉 天选开奖结果通知\n\n`;
|
|
126
|
+
groupMessage += `📅 开奖时间: ${lotteryTime}\n`;
|
|
127
|
+
groupMessage += `🎁 奖品名称: ${lotteryData.reward_name}\n`;
|
|
128
|
+
groupMessage += `📊 奖品数量: ${lotteryData.reward_num}个\n`;
|
|
129
|
+
groupMessage += `🎲 总中奖人数: ${stats.totalWinners}人`;
|
|
130
|
+
// 添加未绑定用户说明
|
|
131
|
+
if (stats.notBoundCount > 0) {
|
|
132
|
+
groupMessage += `(其中${stats.notBoundCount}人未绑定跳过)`;
|
|
133
|
+
}
|
|
134
|
+
groupMessage += `\n\n`;
|
|
135
|
+
// 如果有匹配的用户,显示详细信息
|
|
136
|
+
if (stats.matchedUsers.length > 0) {
|
|
137
|
+
groupMessage += `🎯 已绑定的中奖用户:\n`;
|
|
138
|
+
// 限制显示前10个用户,避免消息过长
|
|
139
|
+
const displayUsers = stats.matchedUsers.slice(0, 10);
|
|
140
|
+
for (let i = 0; i < displayUsers.length; i++) {
|
|
141
|
+
const user = displayUsers[i];
|
|
142
|
+
const index = i + 1;
|
|
143
|
+
const displayMcName = user.mcUsername && !user.mcUsername.startsWith('_temp_') ? user.mcUsername : '未绑定';
|
|
144
|
+
groupMessage += `${index}. ${user.buidUsername} (UID: ${user.uid})\n`;
|
|
145
|
+
groupMessage += ` QQ: ${user.qqId} | MC: ${displayMcName}\n`;
|
|
146
|
+
}
|
|
147
|
+
// 如果用户太多,显示省略信息
|
|
148
|
+
if (stats.matchedUsers.length > 10) {
|
|
149
|
+
groupMessage += `... 还有${stats.matchedUsers.length - 10}位中奖用户\n`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
groupMessage += `😔 暂无已绑定用户中奖\n`;
|
|
154
|
+
}
|
|
155
|
+
// 构建完整版私聊消息(包含所有信息和未绑定用户)
|
|
156
|
+
let privateMessage = `🎉 天选开奖结果通知\n\n`;
|
|
157
|
+
privateMessage += `📅 开奖时间: ${lotteryTime}\n`;
|
|
158
|
+
privateMessage += `🎁 奖品名称: ${lotteryData.reward_name}\n`;
|
|
159
|
+
privateMessage += `📊 奖品数量: ${lotteryData.reward_num}个\n`;
|
|
160
|
+
privateMessage += `🏷️ 事件ID: ${lotteryData.lottery_id}\n`;
|
|
161
|
+
privateMessage += `👤 主播: ${lotteryData.host_username} (UID: ${lotteryData.host_uid})\n`;
|
|
162
|
+
privateMessage += `🏠 房间号: ${lotteryData.room_id}\n\n`;
|
|
163
|
+
// 统计信息
|
|
164
|
+
privateMessage += `📈 处理统计:\n`;
|
|
165
|
+
privateMessage += `• 总中奖人数: ${stats.totalWinners}人\n`;
|
|
166
|
+
privateMessage += `• 已绑定用户: ${stats.matchedCount}人 ✅\n`;
|
|
167
|
+
privateMessage += `• 未绑定用户: ${stats.notBoundCount}人 ⚠️\n`;
|
|
168
|
+
privateMessage += `• 新增标签: ${stats.tagAddedCount}人\n`;
|
|
169
|
+
privateMessage += `• 已有标签: ${stats.tagExistedCount}人\n\n`;
|
|
170
|
+
// 显示所有中奖用户(包括未绑定的)
|
|
171
|
+
if (lotteryData.winners.length > 0) {
|
|
172
|
+
privateMessage += `🎯 所有中奖用户:\n`;
|
|
173
|
+
for (let i = 0; i < lotteryData.winners.length; i++) {
|
|
174
|
+
const winner = lotteryData.winners[i];
|
|
175
|
+
const index = i + 1;
|
|
176
|
+
// 查找对应的绑定用户
|
|
177
|
+
const matchedUser = stats.matchedUsers.find(user => user.uid === winner.uid);
|
|
178
|
+
if (matchedUser) {
|
|
179
|
+
const displayMcName = matchedUser.mcUsername && !matchedUser.mcUsername.startsWith('_temp_') ? matchedUser.mcUsername : '未绑定';
|
|
180
|
+
privateMessage += `${index}. ${winner.username} (UID: ${winner.uid})\n`;
|
|
181
|
+
privateMessage += ` QQ: ${matchedUser.qqId} | MC: ${displayMcName}\n`;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
privateMessage += `${index}. ${winner.username} (UID: ${winner.uid})\n`;
|
|
185
|
+
privateMessage += ` 无绑定信息,自动跳过\n`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
privateMessage += `\n🏷️ 标签"${stats.tagName}"已自动添加到已绑定用户\n`;
|
|
189
|
+
}
|
|
190
|
+
// 准备消息元素
|
|
191
|
+
const groupMessageElements = [koishi_1.h.text(groupMessage)];
|
|
192
|
+
const privateMessageElements = [koishi_1.h.text(privateMessage)];
|
|
193
|
+
// 发送消息到指定群(简化版)
|
|
194
|
+
if (targetChannelId) {
|
|
195
|
+
for (const bot of this.ctx.bots) {
|
|
196
|
+
try {
|
|
197
|
+
await bot.sendMessage(targetChannelId, groupMessageElements);
|
|
198
|
+
this.logger.info('天选开奖', `成功发送简化开奖结果到群${targetChannelId}`, true);
|
|
199
|
+
break; // 成功发送后退出循环
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
this.logger.error('天选开奖', `发送消息到群${targetChannelId}失败: ${error.message}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// 发送消息到私聊(完整版)
|
|
207
|
+
if (privateTargetId) {
|
|
208
|
+
for (const bot of this.ctx.bots) {
|
|
209
|
+
try {
|
|
210
|
+
await bot.sendMessage(privateTargetId, privateMessageElements);
|
|
211
|
+
this.logger.info('天选开奖', `成功发送完整开奖结果到私聊${privateTargetId}`, true);
|
|
212
|
+
break; // 成功发送后退出循环
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
this.logger.error('天选开奖', `发送消息到私聊${privateTargetId}失败: ${error.message}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
this.logger.error('天选开奖', `发送开奖结果失败: ${error.message}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.LotteryHandler = LotteryHandler;
|