koishi-plugin-bind-bot 2.0.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.
Files changed (48) hide show
  1. package/lib/export-utils.d.ts +49 -0
  2. package/lib/export-utils.js +305 -0
  3. package/lib/force-bind-utils.d.ts +40 -0
  4. package/lib/force-bind-utils.js +242 -0
  5. package/lib/handlers/base.handler.d.ts +61 -0
  6. package/lib/handlers/base.handler.js +22 -0
  7. package/lib/handlers/binding.handler.d.ts +45 -0
  8. package/lib/handlers/binding.handler.js +285 -0
  9. package/lib/handlers/buid.handler.d.ts +71 -0
  10. package/lib/handlers/buid.handler.js +694 -0
  11. package/lib/handlers/index.d.ts +6 -0
  12. package/lib/handlers/index.js +22 -0
  13. package/lib/handlers/mcid.handler.d.ts +101 -0
  14. package/lib/handlers/mcid.handler.js +1045 -0
  15. package/lib/handlers/tag.handler.d.ts +14 -0
  16. package/lib/handlers/tag.handler.js +382 -0
  17. package/lib/handlers/whitelist.handler.d.ts +84 -0
  18. package/lib/handlers/whitelist.handler.js +1011 -0
  19. package/lib/index.d.ts +7 -0
  20. package/lib/index.js +2693 -0
  21. package/lib/managers/rcon-manager.d.ts +24 -0
  22. package/lib/managers/rcon-manager.js +308 -0
  23. package/lib/repositories/mcidbind.repository.d.ts +105 -0
  24. package/lib/repositories/mcidbind.repository.js +288 -0
  25. package/lib/repositories/schedule-mute.repository.d.ts +68 -0
  26. package/lib/repositories/schedule-mute.repository.js +175 -0
  27. package/lib/types/api.d.ts +135 -0
  28. package/lib/types/api.js +6 -0
  29. package/lib/types/common.d.ts +40 -0
  30. package/lib/types/common.js +6 -0
  31. package/lib/types/config.d.ts +55 -0
  32. package/lib/types/config.js +6 -0
  33. package/lib/types/database.d.ts +47 -0
  34. package/lib/types/database.js +6 -0
  35. package/lib/types/index.d.ts +8 -0
  36. package/lib/types/index.js +28 -0
  37. package/lib/utils/helpers.d.ts +76 -0
  38. package/lib/utils/helpers.js +275 -0
  39. package/lib/utils/logger.d.ts +75 -0
  40. package/lib/utils/logger.js +134 -0
  41. package/lib/utils/message-utils.d.ts +46 -0
  42. package/lib/utils/message-utils.js +234 -0
  43. package/lib/utils/rate-limiter.d.ts +26 -0
  44. package/lib/utils/rate-limiter.js +47 -0
  45. package/lib/utils/session-manager.d.ts +70 -0
  46. package/lib/utils/session-manager.js +120 -0
  47. package/package.json +39 -0
  48. package/readme.md +281 -0
@@ -0,0 +1,14 @@
1
+ import { BaseHandler } from './base.handler';
2
+ export declare class TagHandler extends BaseHandler {
3
+ register(): void;
4
+ private isAdmin;
5
+ private isMaster;
6
+ private getFriendlyErrorMessage;
7
+ private validateTagName;
8
+ private handleTagAdd;
9
+ private handleTagRemove;
10
+ private handleTagList;
11
+ private handleTagFind;
12
+ private handleTagRename;
13
+ private handleTagDeleteAll;
14
+ }
@@ -0,0 +1,382 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TagHandler = void 0;
4
+ const koishi_1 = require("koishi");
5
+ const base_handler_1 = require("./base.handler");
6
+ class TagHandler extends base_handler_1.BaseHandler {
7
+ register() {
8
+ const cmd = this.ctx.command('mcid', 'Minecraft账号和B站账号绑定管理');
9
+ const tagCmd = cmd.subcommand('.tag', '[管理员]用户标签管理');
10
+ tagCmd.subcommand('.add <tagName:string> [...targets:string]', '为用户添加标签')
11
+ .action(async ({ session }, tagName, ...targets) => this.handleTagAdd(session, tagName, ...targets));
12
+ tagCmd.subcommand('.remove <tagName:string> [...targets:string]', '移除用户标签')
13
+ .action(async ({ session }, tagName, ...targets) => this.handleTagRemove(session, tagName, ...targets));
14
+ tagCmd.subcommand('.list [target:string]', '查看用户的所有标签')
15
+ .action(async ({ session }, target) => this.handleTagList(session, target));
16
+ tagCmd.subcommand('.find <tagName:string>', '查找有特定标签的所有用户')
17
+ .action(async ({ session }, tagName) => this.handleTagFind(session, tagName));
18
+ tagCmd.subcommand('.rename <oldTagName:string> <newTagName:string>', '[管理员]重命名标签')
19
+ .action(async ({ session }, oldTagName, newTagName) => this.handleTagRename(session, oldTagName, newTagName));
20
+ tagCmd.subcommand('.deleteall <tagName:string>', '[主人]删除所有用户的某个标签')
21
+ .action(async ({ session }, tagName) => this.handleTagDeleteAll(session, tagName));
22
+ }
23
+ async isAdmin(userId) {
24
+ const normalizedUserId = this.deps.normalizeQQId(userId);
25
+ const normalizedMasterId = this.deps.normalizeQQId(this.config.masterId);
26
+ if (normalizedUserId === normalizedMasterId)
27
+ return true;
28
+ try {
29
+ const bind = await this.deps.getBindInfo(normalizedUserId);
30
+ return bind && bind.isAdmin === true;
31
+ }
32
+ catch (error) {
33
+ this.logger.error('权限检查', `QQ(${normalizedUserId})的管理员状态查询失败`, error);
34
+ return false;
35
+ }
36
+ }
37
+ isMaster(userId) {
38
+ const normalizedUserId = this.deps.normalizeQQId(userId);
39
+ const normalizedMasterId = this.deps.normalizeQQId(this.config.masterId);
40
+ return normalizedUserId === normalizedMasterId;
41
+ }
42
+ getFriendlyErrorMessage(error) {
43
+ return error instanceof Error ? error.message : error;
44
+ }
45
+ validateTagName(tagName) {
46
+ return /^[\u4e00-\u9fa5a-zA-Z0-9_-]+$/.test(tagName);
47
+ }
48
+ async handleTagAdd(session, tagName, ...targets) {
49
+ try {
50
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
51
+ if (!await this.isAdmin(session.userId)) {
52
+ this.logger.warn('标签', `权限不足: QQ(${normalizedUserId})不是管理员`);
53
+ return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能管理用户标签')]);
54
+ }
55
+ if (!tagName) {
56
+ this.logger.warn('标签', `QQ(${normalizedUserId})未提供标签名称`);
57
+ return this.deps.sendMessage(session, [koishi_1.h.text('请提供标签名称')]);
58
+ }
59
+ if (!this.validateTagName(tagName)) {
60
+ this.logger.warn('标签', `QQ(${normalizedUserId})提供的标签名称"${tagName}"格式无效`);
61
+ return this.deps.sendMessage(session, [koishi_1.h.text('标签名称只能包含中文、字母、数字、下划线和连字符')]);
62
+ }
63
+ if (!targets || targets.length === 0) {
64
+ this.logger.warn('标签', `QQ(${normalizedUserId})未指定目标用户`);
65
+ return this.deps.sendMessage(session, [koishi_1.h.text('请使用@指定要添加标签的用户')]);
66
+ }
67
+ if (targets.length === 1) {
68
+ const target = targets[0];
69
+ const normalizedTargetId = this.deps.normalizeQQId(target);
70
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})尝试为QQ(${normalizedTargetId})添加标签"${tagName}"`, true);
71
+ let targetBind = await this.deps.getBindInfo(normalizedTargetId);
72
+ if (!targetBind) {
73
+ const tempUsername = `_temp_${normalizedTargetId}`;
74
+ await this.repos.mcidbind.create({ qqId: normalizedTargetId, mcUsername: tempUsername, mcUuid: '', lastModified: new Date(), isAdmin: false, whitelist: [], tags: [] });
75
+ targetBind = await this.deps.getBindInfo(normalizedTargetId);
76
+ }
77
+ if (targetBind.tags && targetBind.tags.includes(tagName)) {
78
+ this.logger.warn('标签', `QQ(${normalizedTargetId})已有标签"${tagName}"`);
79
+ return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 已有标签"${tagName}"`)]);
80
+ }
81
+ const newTags = [...(targetBind.tags || []), tagName];
82
+ await this.repos.mcidbind.update(normalizedTargetId, { tags: newTags });
83
+ this.logger.info('标签', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})添加了标签"${tagName}"`, true);
84
+ return this.deps.sendMessage(session, [koishi_1.h.text(`已成功为用户 ${normalizedTargetId} 添加标签"${tagName}"`)]);
85
+ }
86
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})尝试批量为${targets.length}个用户添加标签"${tagName}"`, true);
87
+ await this.deps.sendMessage(session, [koishi_1.h.text(`开始为${targets.length}个用户添加标签"${tagName}",请稍候...`)]);
88
+ let successCount = 0, failCount = 0, skipCount = 0;
89
+ const results = [];
90
+ for (let i = 0; i < targets.length; i++) {
91
+ const target = targets[i];
92
+ const normalizedTargetId = this.deps.normalizeQQId(target);
93
+ try {
94
+ let targetBind = await this.deps.getBindInfo(normalizedTargetId);
95
+ if (!targetBind) {
96
+ const tempUsername = `_temp_${normalizedTargetId}`;
97
+ await this.repos.mcidbind.create({ qqId: normalizedTargetId, mcUsername: tempUsername, mcUuid: '', lastModified: new Date(), isAdmin: false, whitelist: [], tags: [] });
98
+ targetBind = await this.deps.getBindInfo(normalizedTargetId);
99
+ }
100
+ if (targetBind.tags && targetBind.tags.includes(tagName)) {
101
+ skipCount++;
102
+ results.push(`⏭️ ${normalizedTargetId}: 已有该标签`);
103
+ this.logger.warn('标签', `QQ(${normalizedTargetId})已有标签"${tagName}"`);
104
+ continue;
105
+ }
106
+ const newTags = [...(targetBind.tags || []), tagName];
107
+ await this.repos.mcidbind.update(normalizedTargetId, { tags: newTags });
108
+ successCount++;
109
+ results.push(`✅ ${normalizedTargetId}: 添加成功`);
110
+ this.logger.info('标签', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})添加了标签"${tagName}"`, true);
111
+ if (i < targets.length - 1)
112
+ await new Promise(resolve => setTimeout(resolve, 100));
113
+ }
114
+ catch (error) {
115
+ failCount++;
116
+ results.push(`❌ ${normalizedTargetId}: 处理出错`);
117
+ this.logger.error('标签', `处理用户QQ(${normalizedTargetId})时出错: ${error.message}`);
118
+ }
119
+ }
120
+ let resultMessage = `批量添加标签"${tagName}"完成\n共处理${targets.length}个用户\n✅ 成功: ${successCount} 个\n❌ 失败: ${failCount} 个\n⏭️ 跳过: ${skipCount} 个`;
121
+ if (targets.length <= 10)
122
+ resultMessage += '\n\n详细结果:\n' + results.join('\n');
123
+ this.logger.info('标签', `批量操作完成: 管理员QQ(${normalizedUserId})为${targets.length}个用户添加标签"${tagName}",成功: ${successCount},失败: ${failCount},跳过: ${skipCount}`, true);
124
+ return this.deps.sendMessage(session, [koishi_1.h.text(resultMessage)]);
125
+ }
126
+ catch (error) {
127
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
128
+ this.logger.error('标签', `QQ(${normalizedUserId})添加标签失败: ${error.message}`);
129
+ return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
130
+ }
131
+ }
132
+ async handleTagRemove(session, tagName, ...targets) {
133
+ try {
134
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
135
+ if (!await this.isAdmin(session.userId)) {
136
+ this.logger.warn('标签', `权限不足: QQ(${normalizedUserId})不是管理员`);
137
+ return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能管理用户标签')]);
138
+ }
139
+ if (!tagName) {
140
+ this.logger.warn('标签', `QQ(${normalizedUserId})未提供标签名称`);
141
+ return this.deps.sendMessage(session, [koishi_1.h.text('请提供标签名称')]);
142
+ }
143
+ if (!targets || targets.length === 0) {
144
+ this.logger.warn('标签', `QQ(${normalizedUserId})未指定目标用户`);
145
+ return this.deps.sendMessage(session, [koishi_1.h.text('请使用@指定要移除标签的用户')]);
146
+ }
147
+ if (targets.length === 1) {
148
+ const target = targets[0];
149
+ const normalizedTargetId = this.deps.normalizeQQId(target);
150
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})尝试为QQ(${normalizedTargetId})移除标签"${tagName}"`, true);
151
+ const targetBind = await this.deps.getBindInfo(normalizedTargetId);
152
+ if (!targetBind) {
153
+ this.logger.warn('标签', `QQ(${normalizedTargetId})无记录`);
154
+ return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 无记录`)]);
155
+ }
156
+ if (!targetBind.tags || !targetBind.tags.includes(tagName)) {
157
+ this.logger.warn('标签', `QQ(${normalizedTargetId})没有标签"${tagName}"`);
158
+ return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 没有标签"${tagName}"`)]);
159
+ }
160
+ const newTags = targetBind.tags.filter(tag => tag !== tagName);
161
+ await this.repos.mcidbind.update(normalizedTargetId, { tags: newTags });
162
+ this.logger.info('标签', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})移除了标签"${tagName}"`, true);
163
+ return this.deps.sendMessage(session, [koishi_1.h.text(`已成功为用户 ${normalizedTargetId} 移除标签"${tagName}"`)]);
164
+ }
165
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})尝试批量为${targets.length}个用户移除标签"${tagName}"`, true);
166
+ await this.deps.sendMessage(session, [koishi_1.h.text(`开始为${targets.length}个用户移除标签"${tagName}",请稍候...`)]);
167
+ let successCount = 0, failCount = 0, skipCount = 0;
168
+ const results = [];
169
+ for (let i = 0; i < targets.length; i++) {
170
+ const target = targets[i];
171
+ const normalizedTargetId = this.deps.normalizeQQId(target);
172
+ try {
173
+ const targetBind = await this.deps.getBindInfo(normalizedTargetId);
174
+ if (!targetBind) {
175
+ failCount++;
176
+ results.push(`❌ ${normalizedTargetId}: 无记录`);
177
+ this.logger.warn('标签', `QQ(${normalizedTargetId})无记录`);
178
+ continue;
179
+ }
180
+ if (!targetBind.tags || !targetBind.tags.includes(tagName)) {
181
+ skipCount++;
182
+ results.push(`⏭️ ${normalizedTargetId}: 没有该标签`);
183
+ this.logger.warn('标签', `QQ(${normalizedTargetId})没有标签"${tagName}"`);
184
+ continue;
185
+ }
186
+ const newTags = targetBind.tags.filter(tag => tag !== tagName);
187
+ await this.repos.mcidbind.update(normalizedTargetId, { tags: newTags });
188
+ successCount++;
189
+ results.push(`✅ ${normalizedTargetId}: 移除成功`);
190
+ this.logger.info('标签', `成功: 管理员QQ(${normalizedUserId})为QQ(${normalizedTargetId})移除了标签"${tagName}"`, true);
191
+ if (i < targets.length - 1)
192
+ await new Promise(resolve => setTimeout(resolve, 100));
193
+ }
194
+ catch (error) {
195
+ failCount++;
196
+ results.push(`❌ ${normalizedTargetId}: 处理出错`);
197
+ this.logger.error('标签', `处理用户QQ(${normalizedTargetId})时出错: ${error.message}`);
198
+ }
199
+ }
200
+ let resultMessage = `批量移除标签"${tagName}"完成\n共处理${targets.length}个用户\n✅ 成功: ${successCount} 个\n❌ 失败: ${failCount} 个\n⏭️ 跳过: ${skipCount} 个`;
201
+ if (targets.length <= 10)
202
+ resultMessage += '\n\n详细结果:\n' + results.join('\n');
203
+ this.logger.info('标签', `批量操作完成: 管理员QQ(${normalizedUserId})为${targets.length}个用户移除标签"${tagName}",成功: ${successCount},失败: ${failCount},跳过: ${skipCount}`, true);
204
+ return this.deps.sendMessage(session, [koishi_1.h.text(resultMessage)]);
205
+ }
206
+ catch (error) {
207
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
208
+ this.logger.error('标签', `QQ(${normalizedUserId})移除标签失败: ${error.message}`);
209
+ return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
210
+ }
211
+ }
212
+ async handleTagList(session, target) {
213
+ try {
214
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
215
+ if (!await this.isAdmin(session.userId)) {
216
+ this.logger.warn('标签', `权限不足: QQ(${normalizedUserId})不是管理员`);
217
+ return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能查看用户标签')]);
218
+ }
219
+ if (target) {
220
+ const normalizedTargetId = this.deps.normalizeQQId(target);
221
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})查看QQ(${normalizedTargetId})的标签`, true);
222
+ const targetBind = await this.deps.getBindInfo(normalizedTargetId);
223
+ if (!targetBind) {
224
+ this.logger.info('标签', `QQ(${normalizedTargetId})无记录`);
225
+ return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 无记录`)]);
226
+ }
227
+ if (!targetBind.tags || targetBind.tags.length === 0) {
228
+ this.logger.info('标签', `QQ(${normalizedTargetId})没有任何标签`);
229
+ return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 没有任何标签`)]);
230
+ }
231
+ const tagList = targetBind.tags.map(tag => `• ${tag}`).join('\n');
232
+ return this.deps.sendMessage(session, [koishi_1.h.text(`用户 ${normalizedTargetId} 的标签:\n${tagList}`)]);
233
+ }
234
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})查看所有标签统计`, true);
235
+ const allBinds = await this.repos.mcidbind.findAll();
236
+ const tagStats = {};
237
+ for (const bind of allBinds) {
238
+ if (bind.tags && bind.tags.length > 0) {
239
+ for (const tag of bind.tags) {
240
+ tagStats[tag] = (tagStats[tag] || 0) + 1;
241
+ }
242
+ }
243
+ }
244
+ if (Object.keys(tagStats).length === 0) {
245
+ return this.deps.sendMessage(session, [koishi_1.h.text('当前没有任何用户标签')]);
246
+ }
247
+ const sortedTags = Object.entries(tagStats).sort((a, b) => b[1] - a[1]).map(([tag, count]) => `• ${tag} (${count}人)`).join('\n');
248
+ return this.deps.sendMessage(session, [koishi_1.h.text(`所有标签统计:\n${sortedTags}`)]);
249
+ }
250
+ catch (error) {
251
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
252
+ this.logger.error('标签', `QQ(${normalizedUserId})查看标签失败: ${error.message}`);
253
+ return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
254
+ }
255
+ }
256
+ async handleTagFind(session, tagName) {
257
+ try {
258
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
259
+ if (!await this.isAdmin(session.userId)) {
260
+ this.logger.warn('标签', `权限不足: QQ(${normalizedUserId})不是管理员`);
261
+ return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能查找标签')]);
262
+ }
263
+ if (!tagName) {
264
+ this.logger.warn('标签', `QQ(${normalizedUserId})未提供标签名称`);
265
+ return this.deps.sendMessage(session, [koishi_1.h.text('请提供要查找的标签名称')]);
266
+ }
267
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})查找标签"${tagName}"的用户`, true);
268
+ const allBinds = await this.repos.mcidbind.findAll();
269
+ const usersWithTag = allBinds.filter(bind => bind.tags && bind.tags.includes(tagName));
270
+ if (usersWithTag.length === 0) {
271
+ this.logger.info('标签', `没有用户有标签"${tagName}"`);
272
+ return this.deps.sendMessage(session, [koishi_1.h.text(`没有用户有标签"${tagName}"`)]);
273
+ }
274
+ const userList = usersWithTag.map(bind => {
275
+ const mcInfo = bind.mcUsername && !bind.mcUsername.startsWith('_temp_') ? ` (MC: ${bind.mcUsername})` : '';
276
+ return `• ${bind.qqId}${mcInfo}`;
277
+ }).join('\n');
278
+ this.logger.info('标签', `找到${usersWithTag.length}个用户有标签"${tagName}"`, true);
279
+ return this.deps.sendMessage(session, [koishi_1.h.text(`有标签"${tagName}"的用户 (共${usersWithTag.length}人):\n${userList}`)]);
280
+ }
281
+ catch (error) {
282
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
283
+ this.logger.error('标签', `QQ(${normalizedUserId})查找标签失败: ${error.message}`);
284
+ return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
285
+ }
286
+ }
287
+ async handleTagRename(session, oldTagName, newTagName) {
288
+ try {
289
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
290
+ if (!await this.isAdmin(session.userId)) {
291
+ this.logger.warn('标签', `权限不足: QQ(${normalizedUserId})不是管理员`);
292
+ return this.deps.sendMessage(session, [koishi_1.h.text('只有管理员才能重命名标签')]);
293
+ }
294
+ if (!oldTagName || !newTagName) {
295
+ this.logger.warn('标签', `QQ(${normalizedUserId})参数不完整`);
296
+ return this.deps.sendMessage(session, [koishi_1.h.text('请提供旧标签名和新标签名')]);
297
+ }
298
+ if (!this.validateTagName(newTagName)) {
299
+ this.logger.warn('标签', `QQ(${normalizedUserId})提供的新标签名称"${newTagName}"格式无效`);
300
+ return this.deps.sendMessage(session, [koishi_1.h.text('新标签名称只能包含中文、字母、数字、下划线和连字符')]);
301
+ }
302
+ const allBinds = await this.repos.mcidbind.findAll();
303
+ const usersWithOldTag = allBinds.filter(bind => bind.tags && bind.tags.includes(oldTagName));
304
+ if (usersWithOldTag.length === 0) {
305
+ this.logger.info('标签', `标签"${oldTagName}"不存在,无需重命名`);
306
+ return this.deps.sendMessage(session, [koishi_1.h.text(`标签"${oldTagName}"不存在`)]);
307
+ }
308
+ const usersWithNewTag = allBinds.filter(bind => bind.tags && bind.tags.includes(newTagName));
309
+ if (usersWithNewTag.length > 0) {
310
+ this.logger.warn('标签', `新标签"${newTagName}"已存在,无法重命名`);
311
+ return this.deps.sendMessage(session, [koishi_1.h.text(`新标签"${newTagName}"已存在,请选择其他名称`)]);
312
+ }
313
+ this.logger.info('标签', `管理员QQ(${normalizedUserId})开始将标签"${oldTagName}"重命名为"${newTagName}"`, true);
314
+ await this.deps.sendMessage(session, [koishi_1.h.text(`找到${usersWithOldTag.length}个用户有标签"${oldTagName}",开始重命名为"${newTagName}"...`)]);
315
+ let successCount = 0, failCount = 0;
316
+ for (const bind of usersWithOldTag) {
317
+ try {
318
+ const newTags = bind.tags.map(tag => tag === oldTagName ? newTagName : tag);
319
+ await this.repos.mcidbind.update(bind.qqId, { tags: newTags });
320
+ successCount++;
321
+ this.logger.debug('标签', `成功为用户QQ(${bind.qqId})将标签"${oldTagName}"重命名为"${newTagName}"`);
322
+ }
323
+ catch (error) {
324
+ failCount++;
325
+ this.logger.error('标签', `为用户QQ(${bind.qqId})重命名标签失败: ${error.message}`);
326
+ }
327
+ }
328
+ const resultMessage = `标签重命名完成\n"${oldTagName}" → "${newTagName}"\n共处理${usersWithOldTag.length}个用户\n✅ 成功: ${successCount} 个\n❌ 失败: ${failCount} 个`;
329
+ this.logger.info('标签', `重命名完成: 管理员QQ(${normalizedUserId})将标签"${oldTagName}"重命名为"${newTagName}",处理${usersWithOldTag.length}个用户,成功: ${successCount},失败: ${failCount}`, true);
330
+ return this.deps.sendMessage(session, [koishi_1.h.text(resultMessage)]);
331
+ }
332
+ catch (error) {
333
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
334
+ this.logger.error('标签', `QQ(${normalizedUserId})重命名标签失败: ${error.message}`);
335
+ return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
336
+ }
337
+ }
338
+ async handleTagDeleteAll(session, tagName) {
339
+ try {
340
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
341
+ if (!this.isMaster(session.userId)) {
342
+ this.logger.warn('标签', `权限不足: QQ(${normalizedUserId})不是主人`);
343
+ return this.deps.sendMessage(session, [koishi_1.h.text('只有主人才能删除所有用户的标签')]);
344
+ }
345
+ if (!tagName) {
346
+ this.logger.warn('标签', `QQ(${normalizedUserId})未提供标签名称`);
347
+ return this.deps.sendMessage(session, [koishi_1.h.text('请提供要删除的标签名称')]);
348
+ }
349
+ this.logger.info('标签', `主人QQ(${normalizedUserId})开始删除所有用户的标签"${tagName}"`, true);
350
+ const allBinds = await this.repos.mcidbind.findAll();
351
+ const usersWithTag = allBinds.filter(bind => bind.tags && bind.tags.includes(tagName));
352
+ if (usersWithTag.length === 0) {
353
+ this.logger.info('标签', `没有用户有标签"${tagName}",无需删除`);
354
+ return this.deps.sendMessage(session, [koishi_1.h.text(`没有用户有标签"${tagName}",无需删除`)]);
355
+ }
356
+ this.logger.info('标签', `找到${usersWithTag.length}个用户有标签"${tagName}",开始批量删除`, true);
357
+ await this.deps.sendMessage(session, [koishi_1.h.text(`找到${usersWithTag.length}个用户有标签"${tagName}",开始批量删除...`)]);
358
+ let successCount = 0, failCount = 0;
359
+ for (const bind of usersWithTag) {
360
+ try {
361
+ const newTags = bind.tags.filter(tag => tag !== tagName);
362
+ await this.repos.mcidbind.update(bind.qqId, { tags: newTags });
363
+ successCount++;
364
+ this.logger.debug('标签', `成功从用户QQ(${bind.qqId})移除标签"${tagName}"`);
365
+ }
366
+ catch (error) {
367
+ failCount++;
368
+ this.logger.error('标签', `从用户QQ(${bind.qqId})移除标签"${tagName}"失败: ${error.message}`);
369
+ }
370
+ }
371
+ const resultMessage = `批量删除标签"${tagName}"完成\n共处理${usersWithTag.length}个用户\n✅ 成功: ${successCount} 个\n❌ 失败: ${failCount} 个`;
372
+ this.logger.info('标签', `批量删除完成: 主人QQ(${normalizedUserId})删除了${usersWithTag.length}个用户的标签"${tagName}",成功: ${successCount},失败: ${failCount}`, true);
373
+ return this.deps.sendMessage(session, [koishi_1.h.text(resultMessage)]);
374
+ }
375
+ catch (error) {
376
+ const normalizedUserId = this.deps.normalizeQQId(session.userId);
377
+ this.logger.error('标签', `QQ(${normalizedUserId})批量删除标签失败: ${error.message}`);
378
+ return this.deps.sendMessage(session, [koishi_1.h.text(this.getFriendlyErrorMessage(error))]);
379
+ }
380
+ }
381
+ }
382
+ exports.TagHandler = TagHandler;
@@ -0,0 +1,84 @@
1
+ import { BaseHandler } from './base.handler';
2
+ /**
3
+ * 白名单命令处理器
4
+ * 处理所有 mcid.whitelist 子命令
5
+ */
6
+ export declare class WhitelistHandler extends BaseHandler {
7
+ /**
8
+ * 注册白名单相关命令
9
+ */
10
+ register(): void;
11
+ /**
12
+ * 列出所有可用的服务器
13
+ */
14
+ private registerServersCommand;
15
+ /**
16
+ * 添加白名单
17
+ */
18
+ private registerAddCommand;
19
+ /**
20
+ * 移除白名单
21
+ */
22
+ private registerRemoveCommand;
23
+ /**
24
+ * 重置服务器所有白名单记录
25
+ */
26
+ private registerResetCommand;
27
+ /**
28
+ * 重置所有未在服务器配置中的白名单ID
29
+ */
30
+ private registerResetAllCommand;
31
+ /**
32
+ * 批量将所有用户添加到服务器白名单
33
+ */
34
+ private registerAddAllCommand;
35
+ /**
36
+ * 私有辅助方法:检查用户是否为管理员
37
+ */
38
+ private isAdmin;
39
+ /**
40
+ * 私有辅助方法:检查是否为主人
41
+ */
42
+ private isMaster;
43
+ /**
44
+ * 私有辅助方法:根据服务器ID或名称获取服务器配置
45
+ */
46
+ private getServerConfigByIdOrName;
47
+ /**
48
+ * 私有辅助方法:根据服务器ID获取服务器配置
49
+ */
50
+ private getServerConfigById;
51
+ /**
52
+ * 私有辅助方法:根据服务器名称获取服务器配置
53
+ */
54
+ private getServerConfigByName;
55
+ /**
56
+ * 私有辅助方法:计算两个字符串的相似度
57
+ */
58
+ private similarityScore;
59
+ /**
60
+ * 私有辅助方法:计算Levenshtein距离
61
+ */
62
+ private levenshteinDistance;
63
+ /**
64
+ * 私有辅助方法:检查用户是否在特定服务器的白名单中
65
+ */
66
+ private isInServerWhitelist;
67
+ /**
68
+ * 私有辅助方法:添加服务器白名单
69
+ * 注意:这是对 RconManager 的封装,实际执行逻辑在主文件中
70
+ */
71
+ private addServerWhitelist;
72
+ /**
73
+ * 私有辅助方法:移除服务器白名单
74
+ */
75
+ private removeServerWhitelist;
76
+ /**
77
+ * 私有辅助方法:安全地替换命令模板
78
+ */
79
+ private safeCommandReplace;
80
+ /**
81
+ * 私有辅助方法:获取友好的错误信息
82
+ */
83
+ private getFriendlyErrorMessage;
84
+ }