koishi-plugin-group-verification 1.0.2 → 1.0.3

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/index.d.ts CHANGED
@@ -16,6 +16,8 @@ export interface GroupVerificationConfig {
16
16
  threshold?: number;
17
17
  };
18
18
  reminderMessage: string;
19
+ createdBy: string;
20
+ updatedBy: string;
19
21
  createdAt: Date;
20
22
  updatedAt: Date;
21
23
  }
package/lib/index.js CHANGED
@@ -36,6 +36,8 @@ function apply(ctx, config) {
36
36
  reviewMethod: "integer",
37
37
  reviewParameters: "json",
38
38
  reminderMessage: "string",
39
+ createdBy: "string",
40
+ updatedBy: "string",
39
41
  createdAt: "date",
40
42
  updatedAt: "date"
41
43
  }, {
@@ -75,7 +77,7 @@ function apply(ctx, config) {
75
77
  return;
76
78
  }
77
79
  const config2 = groupConfig[0];
78
- const isValid = await verifyApplication(config2, message);
80
+ const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config2, message, session);
79
81
  if (isValid) {
80
82
  await updateStats(guildId, "autoApproved");
81
83
  } else {
@@ -87,6 +89,13 @@ function apply(ctx, config) {
87
89
  const userId = session.userId;
88
90
  const username = session.username || "未知用户";
89
91
  const message = session.content || "";
92
+ let groupName = "未知群组";
93
+ try {
94
+ const guild = await session.bot.getGuild(guildId);
95
+ groupName = guild.name || groupName;
96
+ } catch (error) {
97
+ }
98
+ const { matchedCount, requiredThreshold } = await verifyApplication(config2, message, session);
90
99
  await ctx2.database.create("group_verification_pending", {
91
100
  groupId: guildId,
92
101
  userId,
@@ -94,30 +103,41 @@ function apply(ctx, config) {
94
103
  requestMessage: message,
95
104
  applyTime: /* @__PURE__ */ new Date()
96
105
  });
97
- const reminderMsg = config2.reminderMessage || `收到新的加群申请:${username}(${userId})
98
- 申请理由:${message}
99
- 请管理员使用 #同意 或 #拒绝 来处理此申请`;
106
+ let reminderMsg = config2.reminderMessage;
107
+ reminderMsg = reminderMsg.replace(/{user}/g, username).replace(/{id}/g, userId).replace(/{group}/g, guildId).replace(/{gname}/g, groupName).replace(/{question}/g, message).replace(/{answer}/g, matchedCount.toString()).replace(/{threshold}/g, requiredThreshold);
100
108
  await ctx2.broadcast([guildId], reminderMsg);
101
109
  }
102
110
  __name(handleFailedVerification, "handleFailedVerification");
103
- async function verifyApplication(config2, message) {
111
+ async function verifyApplication(config2, message, session) {
104
112
  const matchedCount = config2.keywords.filter(
105
113
  (keyword) => message.toLowerCase().includes(keyword.toLowerCase())
106
114
  ).length;
115
+ let isValid = false;
116
+ let requiredThreshold = "";
107
117
  switch (config2.reviewMethod) {
108
118
  case 0:
109
- return true;
119
+ isValid = true;
120
+ requiredThreshold = "null";
121
+ break;
110
122
  case 1:
111
- return matchedCount >= (config2.reviewParameters.threshold || 1);
123
+ isValid = matchedCount >= (config2.reviewParameters.threshold || 1);
124
+ requiredThreshold = `${config2.reviewParameters.threshold || 1}`;
125
+ break;
112
126
  case 2:
113
127
  const ratio = matchedCount / config2.keywords.length;
114
128
  const requiredRatio = (config2.reviewParameters.threshold || 100) / 100;
115
- return ratio >= requiredRatio;
129
+ isValid = ratio >= requiredRatio;
130
+ requiredThreshold = `${config2.reviewParameters.threshold || 100}%`;
131
+ break;
116
132
  case 3:
117
- return false;
133
+ isValid = false;
134
+ requiredThreshold = "null";
135
+ break;
118
136
  default:
119
- return false;
137
+ isValid = false;
138
+ requiredThreshold = "null";
120
139
  }
140
+ return { isValid, matchedCount, requiredThreshold };
121
141
  }
122
142
  __name(verifyApplication, "verifyApplication");
123
143
  async function updateStats(groupId, statType) {
@@ -157,29 +177,42 @@ function apply(ctx, config) {
157
177
  __name(updateStats, "updateStats");
158
178
  async function checkPermission(session, targetGroupId) {
159
179
  const groupId = targetGroupId || session.guildId;
160
- if (groupId) {
161
- try {
162
- const member = await session.bot.getGuildMember(groupId, session.userId);
163
- if (member && (member.roles?.includes("admin") || member.permissions?.includes("ADMINISTRATOR"))) {
164
- return true;
165
- }
166
- } catch (error) {
167
- }
180
+ if (!groupId) {
181
+ return [false, "请在群聊中使用此命令或使用 -i 参数指定群号"];
168
182
  }
169
183
  if (session.author?.authority && session.author.authority >= 3) {
170
- return true;
184
+ return [true];
185
+ }
186
+ try {
187
+ const member = await session.bot.getGuildMember(groupId, session.userId);
188
+ if (member) {
189
+ if (member.permissions?.includes("OWNER")) {
190
+ return [true];
191
+ }
192
+ if (member.roles?.includes("admin") || member.permissions?.includes("ADMINISTRATOR")) {
193
+ return [true];
194
+ }
195
+ }
196
+ } catch (error) {
197
+ return [false, `无法获取群 ${groupId} 的成员信息,请确认机器人已在该群中`];
171
198
  }
172
- return false;
199
+ return [false, "权限不足:需要群主/管理员权限或koishi三级以上权限"];
173
200
  }
174
201
  __name(checkPermission, "checkPermission");
175
- const groupVerify = ctx.command("group-verify", "群组验证管理命令");
176
- groupVerify.subcommand(".config [keywords:text]", "配置群组验证规则").alias("cfg", "配置", "conf", "设置").option("groupId", "-i <groupId> 指定群号").option("method", "-m <method> 审核方式 (0-3)").option("threshold", "-t <threshold> 阈值参数").option("query", "-? 查询当前配置").option("remove", "-r 删除配置").action(async ({ session, options }, keywords) => {
202
+ const groupVerify = ctx.command("group-verify", "群组验证管理命令").alias("gv", "gverify");
203
+ groupVerify.subcommand(".config [keywords:text]", "配置群组验证规则").alias("cfg", "配置", "conf", "设置").option("groupId", "-i <groupId> 指定群号").option("method", "-m <method> 审核方式 (0-3)").option("threshold", "-t <threshold> 阈值参数").option("message", "-msg <message> 自定义提醒消息").option("query", "-? 查询当前配置").option("remove", "-r 删除配置").action(async ({ session, options }, keywords) => {
177
204
  const targetGroupId = options.groupId || session.guildId;
178
- if (!await checkPermission(session, targetGroupId)) {
179
- return "权限不足";
205
+ const [hasPermission, errorMsg] = await checkPermission(session, targetGroupId);
206
+ if (!hasPermission) {
207
+ return errorMsg || "权限不足";
180
208
  }
181
- if (!targetGroupId) {
182
- return "请在群聊中使用此命令或使用 -i 参数指定群号";
209
+ let groupName = "未知群组";
210
+ if (targetGroupId) {
211
+ try {
212
+ const guild = await session.bot.getGuild(targetGroupId);
213
+ groupName = guild.name || groupName;
214
+ } catch (error) {
215
+ }
183
216
  }
184
217
  if (options.remove) {
185
218
  const existingConfig2 = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
@@ -195,34 +228,41 @@ function apply(ctx, config) {
195
228
  if (existingConfig2.length > 0) {
196
229
  const config2 = existingConfig2[0];
197
230
  let methodDesc = "";
231
+ let thresholdInfo = "";
198
232
  switch (config2.reviewMethod) {
199
233
  case 0:
200
234
  methodDesc = "全部同意";
235
+ thresholdInfo = "null";
201
236
  break;
202
237
  case 1:
203
- methodDesc = `按数量同意 (${config2.reviewParameters.threshold || 1})`;
238
+ methodDesc = `按数量同意`;
239
+ thresholdInfo = `${config2.reviewParameters.threshold || 1}`;
204
240
  break;
205
241
  case 2:
206
- methodDesc = `按比例同意 (${config2.reviewParameters.threshold || 100}%)`;
242
+ methodDesc = `按比例同意`;
243
+ thresholdInfo = `${config2.reviewParameters.threshold || 100}%`;
207
244
  break;
208
245
  case 3:
209
246
  methodDesc = "全部拒绝";
247
+ thresholdInfo = "null";
210
248
  break;
211
249
  }
250
+ const createTime = new Date(config2.createdAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
251
+ const updateTime = new Date(config2.updatedAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
212
252
  return `群 ${targetGroupId} 配置:
213
253
  关键词: ${config2.keywords.join(", ")}
214
- 审核方式: ${methodDesc}`;
254
+ 审核方式: ${methodDesc}
255
+ 阈值: ${thresholdInfo}
256
+ 提醒消息: ${config2.reminderMessage}
257
+ 创建时间: ${createTime}
258
+ 更新时间: ${updateTime}
259
+ 创建者: ${config2.createdBy}
260
+ 更新者: ${config2.updatedBy}`;
215
261
  } else {
216
262
  return `群 ${targetGroupId} 无验证配置`;
217
263
  }
218
264
  }
219
- if (!keywords) {
220
- return "请提供关键词参数,或使用 -? 查询配置,-r 删除配置";
221
- }
222
- const keywordList = keywords.split(",").map((k) => k.trim()).filter((k) => k);
223
- if (keywordList.length === 0) {
224
- return "请提供有效的关键词";
225
- }
265
+ const keywordList = keywords ? keywords.split(",").map((k) => k.trim()).filter((k) => k) : [];
226
266
  let reviewMethod = 0;
227
267
  let reviewParameters = {};
228
268
  if (options.method !== void 0) {
@@ -249,25 +289,30 @@ function apply(ctx, config) {
249
289
  }
250
290
  }
251
291
  }
292
+ let reminderMessage = options.message || `用户 {user}({id}) 申请加入群 {gname}({group})
293
+ 申请理由:{question}
294
+ 答对情况:{answer}
295
+ 阈值要求:{threshold}
296
+ 请管理员使用 #同意 或 #拒绝 来处理此申请`;
297
+ reminderMessage = reminderMessage.replace(/\\n/g, "\n");
252
298
  const existingConfig = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
299
+ const configData = {
300
+ keywords: keywordList,
301
+ reviewMethod,
302
+ reviewParameters,
303
+ reminderMessage,
304
+ updatedBy: session.username || session.userId,
305
+ updatedAt: /* @__PURE__ */ new Date()
306
+ };
253
307
  if (existingConfig.length > 0) {
254
- await ctx.database.set("group_verification_config", { id: existingConfig[0].id }, {
255
- keywords: keywordList,
256
- reviewMethod,
257
- reviewParameters,
258
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
259
- updatedAt: /* @__PURE__ */ new Date()
260
- });
308
+ await ctx.database.set("group_verification_config", { id: existingConfig[0].id }, configData);
261
309
  return `已更新群 ${targetGroupId} 的验证配置`;
262
310
  } else {
263
311
  await ctx.database.create("group_verification_config", {
312
+ ...configData,
264
313
  groupId: targetGroupId,
265
- keywords: keywordList,
266
- reviewMethod,
267
- reviewParameters,
268
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
269
- createdAt: /* @__PURE__ */ new Date(),
270
- updatedAt: /* @__PURE__ */ new Date()
314
+ createdBy: session.username || session.userId,
315
+ createdAt: /* @__PURE__ */ new Date()
271
316
  });
272
317
  return `已为群 ${targetGroupId} 创建验证配置`;
273
318
  }
@@ -357,19 +402,42 @@ function apply(ctx, config) {
357
402
  });
358
403
  groupVerify.subcommand(".help", "显示帮助信息").alias("帮助", "hlp", "帮助信息").action(() => {
359
404
  return `群组验证命令帮助:
360
- .config [关键词] [选项] - 配置验证规则
361
- 选项:-i 群号 -m 方式(0-3) -t 阈值 -? 查询 -r 删除
362
- 审核方式:0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝
363
- 示例:group-verify.config 学生,校友,老师 -m 1 -t 2
405
+ 主指令别名:gv, gverify
406
+
407
+ 配置命令 (.config):
408
+ 选项:
409
+ -i <群号> 指定群号(私聊时必需)
410
+ -m <方式> 审核方式 (0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝)
411
+ -t <阈值> 阈值参数(方式1或2时必需)
412
+ -msg <消息> 自定义提醒消息
413
+ -? 查询当前配置
414
+ -r 删除配置
415
+
416
+ 示例:
417
+ gv.config 关键词1,关键词2 -m 1 -t 2
418
+ gv.config -i 123456789 -?
419
+ gv.config -r -i 123456789
420
+
421
+ 提醒消息变量:
422
+ {user} - 用户名
423
+ {id} - 用户ID
424
+ {group} - 群号
425
+ {gname} - 群名称
426
+ {question} - 申请理由
427
+ {answer} - 答对数量/比例
428
+ {threshold} - 阈值要求
429
+ \\n - 换行符
364
430
 
365
- .approve <用户ID> - 同意加群申请 (需管理员权限)
366
- .reject <用户ID> - 拒绝加群申请 (需管理员权限)
367
- .pending - 查看待审核列表
368
- .stats [群号] - 查看统计信息
369
- .help - 显示此帮助信息
431
+ 权限说明:
432
+ - 群主/管理员权限
433
+ - koishi三级以上权限
434
+ - 私聊时必须指定群号(-i参数)
370
435
 
371
- 权限说明:管理命令需群管理员或koishi三级以上权限
372
- 别名:.cfg(配置) .accept(同意) .rej(拒绝) .stat(统计) .list(列表)`;
436
+ 其他命令:
437
+ .approve <用户ID> - 同意加群申请
438
+ .reject <用户ID> - 拒绝加群申请
439
+ .pending - 查看待审核列表
440
+ .stats [群号] - 查看统计信息`;
373
441
  });
374
442
  }
375
443
  __name(apply, "apply");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-group-verification",
3
3
  "description": "Koishi 群组加群验证插件,支持多关键词匹配审核、多种审核方式和详细统计功能",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -34,10 +34,10 @@
34
34
  }
35
35
  },
36
36
  "peerDependencies": {
37
- "koishi": "^4.18.7"
37
+ "koishi": "^4.10.0"
38
38
  },
39
39
  "devDependencies": {
40
- "typescript": "^5.0.0",
41
- "@types/node": "^18.0.0"
40
+ "typescript": "^4.9.0",
41
+ "@types/node": "^16.0.0"
42
42
  }
43
43
  }
package/src/index.ts CHANGED
@@ -21,6 +21,8 @@ export interface GroupVerificationConfig {
21
21
  threshold?: number // 数量阈值或比例阈值
22
22
  }
23
23
  reminderMessage: string
24
+ createdBy: string
25
+ updatedBy: string
24
26
  createdAt: Date
25
27
  updatedAt: Date
26
28
  }
@@ -58,6 +60,8 @@ export function apply(ctx: Context, config: Config) {
58
60
  reviewMethod: 'integer',
59
61
  reviewParameters: 'json',
60
62
  reminderMessage: 'string',
63
+ createdBy: 'string',
64
+ updatedBy: 'string',
61
65
  createdAt: 'date',
62
66
  updatedAt: 'date'
63
67
  }, {
@@ -110,7 +114,7 @@ export function apply(ctx: Context, config: Config) {
110
114
  const config = groupConfig[0]
111
115
 
112
116
  // 执行验证
113
- const isValid = await verifyApplication(config, message)
117
+ const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config, message, session)
114
118
 
115
119
  if (isValid) {
116
120
  // 验证成功,自动同意入群
@@ -131,6 +135,18 @@ export function apply(ctx: Context, config: Config) {
131
135
  const username = session.username || '未知用户'
132
136
  const message = session.content || ''
133
137
 
138
+ // 获取群信息
139
+ let groupName = '未知群组'
140
+ try {
141
+ const guild = await session.bot.getGuild(guildId)
142
+ groupName = guild.name || groupName
143
+ } catch (error) {
144
+ // 无法获取群名称时使用默认值
145
+ }
146
+
147
+ // 执行验证获取详细信息
148
+ const { matchedCount, requiredThreshold } = await verifyApplication(config, message, session)
149
+
134
150
  // 将申请加入待审核列表
135
151
  await ctx.database.create('group_verification_pending', {
136
152
  groupId: guildId,
@@ -140,32 +156,56 @@ export function apply(ctx: Context, config: Config) {
140
156
  applyTime: new Date()
141
157
  })
142
158
 
159
+ // 替换提醒消息中的变量
160
+ let reminderMsg = config.reminderMessage
161
+ reminderMsg = reminderMsg
162
+ .replace(/{user}/g, username)
163
+ .replace(/{id}/g, userId)
164
+ .replace(/{group}/g, guildId)
165
+ .replace(/{gname}/g, groupName)
166
+ .replace(/{question}/g, message)
167
+ .replace(/{answer}/g, matchedCount.toString())
168
+ .replace(/{threshold}/g, requiredThreshold)
169
+
143
170
  // 发送提醒消息到群内
144
- const reminderMsg = config.reminderMessage || `收到新的加群申请:${username}(${userId})\n申请理由:${message}\n请管理员使用 #同意 或 #拒绝 来处理此申请`
145
171
  await ctx.broadcast([guildId], reminderMsg)
146
172
  }
147
173
 
148
174
  // 验证申请
149
- async function verifyApplication(config: GroupVerificationConfig, message: string): Promise<boolean> {
175
+ async function verifyApplication(config: GroupVerificationConfig, message: string, session: any): Promise<{isValid: boolean, matchedCount: number, requiredThreshold: string}> {
150
176
  // 统计匹配的关键词数量
151
177
  const matchedCount = config.keywords.filter(keyword =>
152
178
  message.toLowerCase().includes(keyword.toLowerCase())
153
179
  ).length
154
180
 
181
+ let isValid = false
182
+ let requiredThreshold = ''
183
+
155
184
  switch (config.reviewMethod) {
156
185
  case 0: // 全部同意
157
- return true
186
+ isValid = true
187
+ requiredThreshold = 'null'
188
+ break
158
189
  case 1: // 按数量同意
159
- return matchedCount >= (config.reviewParameters.threshold || 1)
190
+ isValid = matchedCount >= (config.reviewParameters.threshold || 1)
191
+ requiredThreshold = `${config.reviewParameters.threshold || 1}`
192
+ break
160
193
  case 2: // 按比例同意
161
194
  const ratio = matchedCount / config.keywords.length
162
195
  const requiredRatio = (config.reviewParameters.threshold || 100) / 100
163
- return ratio >= requiredRatio
196
+ isValid = ratio >= requiredRatio
197
+ requiredThreshold = `${config.reviewParameters.threshold || 100}%`
198
+ break
164
199
  case 3: // 全部拒绝
165
- return false
200
+ isValid = false
201
+ requiredThreshold = 'null'
202
+ break
166
203
  default:
167
- return false
204
+ isValid = false
205
+ requiredThreshold = 'null'
168
206
  }
207
+
208
+ return { isValid, matchedCount, requiredThreshold }
169
209
  }
170
210
 
171
211
  // 更新统计信息
@@ -210,31 +250,42 @@ export function apply(ctx: Context, config: Config) {
210
250
  }
211
251
 
212
252
  // 权限检查函数
213
- async function checkPermission(session: any, targetGroupId?: string): Promise<boolean> {
253
+ async function checkPermission(session: any, targetGroupId?: string): Promise<[boolean, string?]> {
214
254
  const groupId = targetGroupId || session.guildId
215
255
 
216
- // 检查是否为群管理员
217
- if (groupId) {
218
- try {
219
- const member = await session.bot.getGuildMember(groupId, session.userId)
220
- if (member && (member.roles?.includes('admin') || member.permissions?.includes('ADMINISTRATOR'))) {
221
- return true
222
- }
223
- } catch (error) {
224
- // 如果无法获取群成员信息,继续检查其他权限
225
- }
256
+ // 私聊情况下必须指定群号
257
+ if (!groupId) {
258
+ return [false, '请在群聊中使用此命令或使用 -i 参数指定群号']
226
259
  }
227
260
 
228
261
  // 检查koishi权限等级(三级及以上)
229
262
  if (session.author?.authority && session.author.authority >= 3) {
230
- return true
263
+ return [true]
231
264
  }
232
265
 
233
- return false
266
+ // 检查是否为群主或管理员
267
+ try {
268
+ const member = await session.bot.getGuildMember(groupId, session.userId)
269
+ if (member) {
270
+ // 检查群主权限
271
+ if (member.permissions?.includes('OWNER')) {
272
+ return [true]
273
+ }
274
+ // 检查管理员权限
275
+ if (member.roles?.includes('admin') || member.permissions?.includes('ADMINISTRATOR')) {
276
+ return [true]
277
+ }
278
+ }
279
+ } catch (error) {
280
+ return [false, `无法获取群 ${groupId} 的成员信息,请确认机器人已在该群中`]
281
+ }
282
+
283
+ return [false, '权限不足:需要群主/管理员权限或koishi三级以上权限']
234
284
  }
235
285
 
236
- // Create main command
286
+ // Create main command with aliases
237
287
  const groupVerify = ctx.command('group-verify', '群组验证管理命令')
288
+ .alias('gv', 'gverify')
238
289
 
239
290
  // Subcommand: configure group verification
240
291
  groupVerify
@@ -243,18 +294,27 @@ export function apply(ctx: Context, config: Config) {
243
294
  .option('groupId', '-i <groupId> 指定群号')
244
295
  .option('method', '-m <method> 审核方式 (0-3)')
245
296
  .option('threshold', '-t <threshold> 阈值参数')
297
+ .option('message', '-msg <message> 自定义提醒消息')
246
298
  .option('query', '-? 查询当前配置')
247
299
  .option('remove', '-r 删除配置')
248
300
  .action(async ({ session, options }, keywords) => {
249
301
  const targetGroupId = options.groupId || session.guildId
250
302
 
251
303
  // 权限检查
252
- if (!(await checkPermission(session, targetGroupId))) {
253
- return '权限不足'
304
+ const [hasPermission, errorMsg] = await checkPermission(session, targetGroupId)
305
+ if (!hasPermission) {
306
+ return errorMsg || '权限不足'
254
307
  }
255
308
 
256
- if (!targetGroupId) {
257
- return '请在群聊中使用此命令或使用 -i 参数指定群号'
309
+ // 获取群信息
310
+ let groupName = '未知群组'
311
+ if (targetGroupId) {
312
+ try {
313
+ const guild = await session.bot.getGuild(targetGroupId)
314
+ groupName = guild.name || groupName
315
+ } catch (error) {
316
+ // 无法获取群名称时使用默认值
317
+ }
258
318
  }
259
319
 
260
320
  // 处理删除配置
@@ -274,30 +334,47 @@ export function apply(ctx: Context, config: Config) {
274
334
  if (existingConfig.length > 0) {
275
335
  const config = existingConfig[0]
276
336
  let methodDesc = ''
337
+ let thresholdInfo = ''
277
338
  switch (config.reviewMethod) {
278
- case 0: methodDesc = '全部同意'; break
279
- case 1: methodDesc = `按数量同意 (${config.reviewParameters.threshold || 1})`; break
280
- case 2: methodDesc = `按比例同意 (${config.reviewParameters.threshold || 100}%)`; break
281
- case 3: methodDesc = '全部拒绝'; break
339
+ case 0:
340
+ methodDesc = '全部同意'
341
+ thresholdInfo = 'null'
342
+ break
343
+ case 1:
344
+ methodDesc = `按数量同意`
345
+ thresholdInfo = `${config.reviewParameters.threshold || 1}`
346
+ break
347
+ case 2:
348
+ methodDesc = `按比例同意`
349
+ thresholdInfo = `${config.reviewParameters.threshold || 100}%`
350
+ break
351
+ case 3:
352
+ methodDesc = '全部拒绝'
353
+ thresholdInfo = 'null'
354
+ break
282
355
  }
283
- return `群 ${targetGroupId} 配置:\n关键词: ${config.keywords.join(', ')}\n审核方式: ${methodDesc}`
356
+
357
+ const createTime = new Date(config.createdAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
358
+ const updateTime = new Date(config.updatedAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
359
+
360
+ return `群 ${targetGroupId} 配置:
361
+ 关键词: ${config.keywords.join(', ')}
362
+ 审核方式: ${methodDesc}
363
+ 阈值: ${thresholdInfo}
364
+ 提醒消息: ${config.reminderMessage}
365
+ 创建时间: ${createTime}
366
+ 更新时间: ${updateTime}
367
+ 创建者: ${config.createdBy}
368
+ 更新者: ${config.updatedBy}`
284
369
  } else {
285
370
  return `群 ${targetGroupId} 无验证配置`
286
371
  }
287
372
  }
288
373
 
289
374
  // 处理配置创建/更新
290
- if (!keywords) {
291
- return '请提供关键词参数,或使用 -? 查询配置,-r 删除配置'
292
- }
293
-
294
- const keywordList = keywords.split(',').map(k => k.trim()).filter(k => k)
375
+ const keywordList = keywords ? keywords.split(',').map(k => k.trim()).filter(k => k) : []
295
376
 
296
- if (keywordList.length === 0) {
297
- return '请提供有效的关键词'
298
- }
299
-
300
- // 解析审核方式
377
+ // 解析审核方式和阈值
301
378
  let reviewMethod: 0 | 1 | 2 | 3 = 0 // 默认全部同意
302
379
  let reviewParameters: { threshold?: number } = {}
303
380
 
@@ -329,29 +406,40 @@ export function apply(ctx: Context, config: Config) {
329
406
  }
330
407
  }
331
408
 
409
+ // 处理提醒消息
410
+ let reminderMessage = options.message ||
411
+ `用户 {user}({id}) 申请加入群 {gname}({group})
412
+ 申请理由:{question}
413
+ 答对情况:{answer}
414
+ 阈值要求:{threshold}
415
+ 请管理员使用 #同意 或 #拒绝 来处理此申请`
416
+
417
+ // 替换换行符
418
+ reminderMessage = reminderMessage.replace(/\\n/g, '\n')
419
+
332
420
  // Check if configuration already exists
333
421
  const existingConfig = await ctx.database.get('group_verification_config', { groupId: targetGroupId })
334
422
 
423
+ const configData = {
424
+ keywords: keywordList,
425
+ reviewMethod: reviewMethod,
426
+ reviewParameters: reviewParameters,
427
+ reminderMessage: reminderMessage,
428
+ updatedBy: session.username || session.userId,
429
+ updatedAt: new Date()
430
+ }
431
+
335
432
  if (existingConfig.length > 0) {
336
433
  // Update existing configuration
337
- await ctx.database.set('group_verification_config', { id: existingConfig[0].id }, {
338
- keywords: keywordList,
339
- reviewMethod: reviewMethod,
340
- reviewParameters: reviewParameters,
341
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
342
- updatedAt: new Date()
343
- })
434
+ await ctx.database.set('group_verification_config', { id: existingConfig[0].id }, configData)
344
435
  return `已更新群 ${targetGroupId} 的验证配置`
345
436
  } else {
346
437
  // Create new configuration
347
438
  await ctx.database.create('group_verification_config', {
439
+ ...configData,
348
440
  groupId: targetGroupId,
349
- keywords: keywordList,
350
- reviewMethod: reviewMethod,
351
- reviewParameters: reviewParameters,
352
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
353
- createdAt: new Date(),
354
- updatedAt: new Date()
441
+ createdBy: session.username || session.userId,
442
+ createdAt: new Date()
355
443
  })
356
444
  return `已为群 ${targetGroupId} 创建验证配置`
357
445
  }
@@ -486,17 +574,42 @@ export function apply(ctx: Context, config: Config) {
486
574
  .subcommand('.help', '显示帮助信息')
487
575
  .alias('帮助', 'hlp', '帮助信息')
488
576
  .action(() => {
489
- return `群组验证命令帮助:\n` +
490
- `.config [关键词] [选项] - 配置验证规则\n` +
491
- ` 选项:-i 群号 -m 方式(0-3) -t 阈值 -? 查询 -r 删除\n` +
492
- ` 审核方式:0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝\n` +
493
- ` 示例:group-verify.config 学生,校友,老师 -m 1 -t 2\n\n` +
494
- `.approve <用户ID> - 同意加群申请 (需管理员权限)\n` +
495
- `.reject <用户ID> - 拒绝加群申请 (需管理员权限)\n` +
496
- `.pending - 查看待审核列表\n` +
497
- `.stats [群号] - 查看统计信息\n` +
498
- `.help - 显示此帮助信息\n\n` +
499
- `权限说明:管理命令需群管理员或koishi三级以上权限\n` +
500
- `别名:.cfg(配置) .accept(同意) .rej(拒绝) .stat(统计) .list(列表)`
577
+ return `群组验证命令帮助:
578
+ 主指令别名:gv, gverify
579
+
580
+ 配置命令 (.config):
581
+ 选项:
582
+ -i <群号> 指定群号(私聊时必需)
583
+ -m <方式> 审核方式 (0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝)
584
+ -t <阈值> 阈值参数(方式1或2时必需)
585
+ -msg <消息> 自定义提醒消息
586
+ -? 查询当前配置
587
+ -r 删除配置
588
+
589
+ 示例:
590
+ gv.config 关键词1,关键词2 -m 1 -t 2
591
+ gv.config -i 123456789 -?
592
+ gv.config -r -i 123456789
593
+
594
+ 提醒消息变量:
595
+ {user} - 用户名
596
+ {id} - 用户ID
597
+ {group} - 群号
598
+ {gname} - 群名称
599
+ {question} - 申请理由
600
+ {answer} - 答对数量/比例
601
+ {threshold} - 阈值要求
602
+ \\n - 换行符
603
+
604
+ 权限说明:
605
+ - 群主/管理员权限
606
+ - koishi三级以上权限
607
+ - 私聊时必须指定群号(-i参数)
608
+
609
+ 其他命令:
610
+ .approve <用户ID> - 同意加群申请
611
+ .reject <用户ID> - 拒绝加群申请
612
+ .pending - 查看待审核列表
613
+ .stats [群号] - 查看统计信息`
501
614
  })
502
615
  }