koishi-plugin-group-verification 1.0.33 → 1.0.34

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 (3) hide show
  1. package/lib/index.js +61 -55
  2. package/package.json +2 -2
  3. package/src/index.ts +84 -78
package/lib/index.js CHANGED
@@ -45,12 +45,12 @@ var import_koishi = require("koishi");
45
45
  var name = "group-verification";
46
46
  var logger = console;
47
47
  var Config = import_koishi.Schema.object({
48
- defaultReminderMessage: import_koishi.Schema.string().description("默认提醒消息模板(使用 \\n 表示换行,可包含下方变量)").default("{user}({id}) 申请加入群 {gname}({group})\n申请理由:{question}\n匹配情况:{answer}/{threshold}\n使用 gva 同意或 gvr 拒绝申请"),
48
+ defaultReminderMessage: import_koishi.Schema.string().description("默认提醒消息模板(使用 \\n 表示换行,可包含下方变量)").default("{user}({id}) 申请加入群 {gname}({group})\n申请理由: {question}\n匹配情况: {answer}/{threshold}\n使用 gva 同意或 gvr 拒绝申请"),
49
49
  enableStrictGroupCheck: import_koishi.Schema.boolean().description("是否启用严格的群号检查(检查群号长度)").default(false),
50
50
  logLevel: import_koishi.Schema.union(["debug", "info", "warn", "error"]).description("日志级别").default("info"),
51
- permissionDeniedMessage: import_koishi.Schema.string().description("权限不足时返回给调用者的提示").default("权限不足:需要群主/管理员权限或koishi三级以上权限"),
51
+ permissionDeniedMessage: import_koishi.Schema.string().description("权限不足时返回给调用者的提示").default("权限不足: 需要群主/管理员权限或koishi三级以上权限"),
52
52
  invalidGroupMessage: import_koishi.Schema.string().description("无效群号或机器人未在该群时的提示").default("群号 {group} 格式不合法或机器人不在该群中"),
53
- parameterConflictMessage: import_koishi.Schema.string().description("参数冲突时提示").default("参数冲突:-? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)"),
53
+ parameterConflictMessage: import_koishi.Schema.string().description("参数冲突时提示").default("参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)"),
54
54
  noKeywordsMessage: import_koishi.Schema.string().description("未提供关键词且无法从现有配置继承时的提示").default("请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置"),
55
55
  blacklistAddSuccess: import_koishi.Schema.string().description("将用户加入黑名单后的提示,可使用 {user},{group},{reason}").default("已将用户 {user} 加入群 {group} 黑名单{reason}"),
56
56
  blacklistRemoveSuccess: import_koishi.Schema.string().description("从黑名单移除用户后的提示,可使用 {user},{group}").default("已从群 {group} 的黑名单中移除用户 {user}"),
@@ -162,25 +162,31 @@ function validateKeywordFormat(raw) {
162
162
  }
163
163
  __name(validateKeywordFormat, "validateKeywordFormat");
164
164
  function usageString() {
165
- return `用法:
166
- # 创建/修改配置
167
- gvc 关键词1,关键词2 -m 1 -t 2 # 创建配置
168
- gvc -m 1 -t 2 # 修改审核参数
165
+ return `用法:
166
+ -i 群号
167
+ -m (0|1|2|3)审核方式
168
+ -t 阈值
169
+ -msg [可选,消息内容] 并打开提醒消息
170
+ -nomsg 取消提醒消息(与-msg冲突)
171
+ -r 删除配置
172
+ -? 查询配置
169
173
 
170
- # 提醒消息控制(可用变量详见下方)
171
- gvc -msg "消息内容" # 修改提醒消息
174
+ 对于存在空格的关键词/提醒消息用双引号""包裹
175
+
176
+ # 例
177
+ gvc 关键词1,关键词2 -m 1 -t 2 # 创建配置
178
+ gvc -msg "消息内容" # 修改提醒消息
172
179
  gvc -nomsg # 禁用提醒消息
173
- # 查询/删除
174
180
  gvc -? # 查询配置
175
181
  gvc -r # 删除配置
176
182
 
177
- 审核方式说明(使用 -m 参数):
183
+ 审核方式说明(使用 -m 参数):
178
184
  0 全部同意(默认)
179
- 1 按数量同意,需要 -t 指定数量
185
+ 1 按数量同意,需要 -t 指定数量
180
186
  2 按比例同意,需要 -t 指定百分比
181
- 3 全部拒绝(拒绝后系统会自动阻止任何通过)
187
+ 3 全部拒绝
182
188
 
183
- 提醒消息可用变量:{user} 用户名 {id} 用户ID
189
+ 提醒消息可用变量: {user} 用户名 {id} 用户ID
184
190
  {group} 群号 {gname} 群名称
185
191
  {question} 申请理由 {answer} 匹配情况 {threshold} 阈值
186
192
  使用 \\n 换行`;
@@ -188,7 +194,7 @@ function usageString() {
188
194
  __name(usageString, "usageString");
189
195
  function mergeReminder(existingConfig, cleanedOptions, hasRealMessageParam, hasRealEnableMessageParam, hasRealDisableMessageParam, logger2, defaultMessage) {
190
196
  let reminderEnabled = true;
191
- let reminderMessage = defaultMessage || "{user}({id}) 申请加入群 {gname}({group})\n申请理由:{question}\n匹配情况:{answer}/{threshold}";
197
+ let reminderMessage = defaultMessage || "{user}({id}) 申请加入群 {gname}({group})\n申请理由: {question}\n匹配情况: {answer}/{threshold}";
192
198
  if (existingConfig) {
193
199
  reminderEnabled = existingConfig.reminderEnabled;
194
200
  reminderMessage = existingConfig.reminderMessage || reminderMessage;
@@ -516,7 +522,7 @@ function parseConfigArgs(raw) {
516
522
  }
517
523
  const keywordSection = raw.split(/(?:^|\s+)-(?:i|m|t|msg|nomsg|\?|r)\b/)[0].trim();
518
524
  if (keywordSection && !validateKeywordFormat(keywordSection)) {
519
- error = '关键词应使用逗号分隔或引号框起(如:k1,k2,k3 或 "k1","k2" 或 "k1,k2",k3)';
525
+ error = '关键词应使用逗号分隔或引号框起(如: k1,k2,k3 或 "k1","k2" 或 "k1,k2",k3)';
520
526
  }
521
527
  return { keywords, flags, error };
522
528
  }
@@ -645,7 +651,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
645
651
  const op = parts[0]?.toLowerCase();
646
652
  if (!op || !["a", "r", "l", "i"].includes(op)) {
647
653
  return [
648
- "用法:",
654
+ "用法: ",
649
655
  " gvb a id [reason] [group] 将用户加入黑名单",
650
656
  " gvb r id [group] 将用户移出黑名单",
651
657
  " gvb l [group] 查询群黑名单",
@@ -693,7 +699,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
693
699
  const row = rows[0];
694
700
  const entries = row.entries || {};
695
701
  if (entries[targetUser] !== void 0) {
696
- return `用户 ${targetUser} 已在群 ${group} 的黑名单中:${entries[targetUser]}`;
702
+ return `用户 ${targetUser} 已在群 ${group} 的黑名单中: ${entries[targetUser]}`;
697
703
  }
698
704
  entries[targetUser] = storedReason;
699
705
  await ctx.database.set("group_verification_blacklist", { id: row.id }, { entries });
@@ -711,7 +717,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
711
717
  }
712
718
  }
713
719
  const tmpl = config && config.blacklistAddSuccess || "已将用户 {user} 加入群 {group} 黑名单{reason}";
714
- return tmpl.replace("{user}", targetUser).replace("{group}", group).replace("{reason}", reason ? `,原因:${reason}` : "");
720
+ return tmpl.replace("{user}", targetUser).replace("{group}", group).replace("{reason}", reason ? `,原因: ${reason}` : "");
715
721
  }
716
722
  if (op === "r") {
717
723
  targetUser = parts[1];
@@ -768,7 +774,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
768
774
  `;
769
775
  let msg = prefix;
770
776
  for (const uid in entries) {
771
- msg += `${uid}${entries[uid] ? `:${entries[uid]}` : ""}
777
+ msg += `${uid}${entries[uid] ? `: ${entries[uid]}` : ""}
772
778
  `;
773
779
  }
774
780
  return msg;
@@ -802,7 +808,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
802
808
  }
803
809
  if (groupArg.toLowerCase() === "all") {
804
810
  const auth = session.author?.authority || session.user?.authority;
805
- if (!(auth && auth >= 3)) return "权限不足:查看全局/所有群黑名单需要 koishi 3 级以上权限";
811
+ if (!(auth && auth >= 3)) return "权限不足: 查看全局/所有群黑名单需要 koishi 3 级以上权限";
806
812
  const rows2 = await ctx.database.get("group_verification_blacklist", {});
807
813
  const globalReason2 = globalHit ? globalRows[0].entries[targetUser] : "无";
808
814
  const lines = [];
@@ -987,7 +993,7 @@ function apply(ctx, config) {
987
993
  }
988
994
  logger.debug(`权限检查 - 权限不足`);
989
995
  const debugInfo = `调试信息 - 用户ID:${session.userId}, 群号:${groupId}, 权限等级:${koishiAuthority || "未知"}`;
990
- return [false, (config.permissionDeniedMessage || "权限不足:需要群主/管理员权限或koishi三级以上权限") + `
996
+ return [false, (config.permissionDeniedMessage || "权限不足: 需要群主/管理员权限或koishi三级以上权限") + `
991
997
  ${debugInfo}`];
992
998
  }
993
999
  __name(checkPermission2, "checkPermission");
@@ -1017,14 +1023,14 @@ ${debugInfo}`];
1017
1023
  threshold: flags.threshold || options.threshold,
1018
1024
  message: flags.message !== void 0 ? flags.message : options.message,
1019
1025
  enableMessage: flags.enableMessage,
1020
- // 新增:-msg 裸调用标记
1026
+ // 新增: -msg 裸调用标记
1021
1027
  disableMessage: flags.disableMessage || options.disableMessage,
1022
1028
  query: flags.query || options.query,
1023
1029
  remove: flags.remove || options.remove
1024
1030
  };
1025
1031
  logger.info(`合并后options: ${JSON.stringify(cleanedOptions, null, 2)}`);
1026
1032
  if ((cleanedOptions.query || cleanedOptions.remove) && (parsedKeywords.length > 0 || cleanedOptions.method !== void 0 || cleanedOptions.threshold !== void 0 || cleanedOptions.message !== void 0 || cleanedOptions.enableMessage || cleanedOptions.disableMessage)) {
1027
- return config.parameterConflictMessage || "参数冲突:-? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)";
1033
+ return config.parameterConflictMessage || "参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)";
1028
1034
  }
1029
1035
  const hasRealMessageParam = cleanedOptions.message !== void 0;
1030
1036
  const hasRealEnableMessageParam = cleanedOptions.enableMessage === true;
@@ -1049,7 +1055,7 @@ ${debugInfo}`];
1049
1055
  return "请在群聊中使用此命令或指定群号(-i参数)";
1050
1056
  }
1051
1057
  if ((hasRealMessageParam || hasRealEnableMessageParam) && hasRealDisableMessageParam) {
1052
- return "参数冲突:不能同时使用 -msg 和 -nomsg";
1058
+ return "参数冲突: 不能同时使用 -msg 和 -nomsg";
1053
1059
  }
1054
1060
  const usedOptions = [];
1055
1061
  if (cleanedOptions.method !== void 0) usedOptions.push("-m");
@@ -1107,7 +1113,7 @@ ${debugInfo}`];
1107
1113
  const createTime = new Date(config2.createdAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
1108
1114
  const updateTime = new Date(config2.updatedAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
1109
1115
  const reminderStatus = config2.reminderEnabled ? "启用" : "禁用";
1110
- return `群 ${targetGroupId} 配置:
1116
+ return `群 ${targetGroupId} 配置:
1111
1117
  关键词: ${decodedKeywords2.join(", ")}
1112
1118
  审核方式: ${methodDesc}
1113
1119
  阈值: ${thresholdInfo}
@@ -1164,7 +1170,7 @@ ${config2.reminderMessage || "无"}
1164
1170
  if (cleanedOptions.method !== void 0 && cleanedOptions.method !== "") {
1165
1171
  const methodNum = parseInt(cleanedOptions.method);
1166
1172
  if (isNaN(methodNum) || methodNum < 0 || methodNum > 3) {
1167
- return "审核方式参数错误:0-全部同意, 1-按数量同意, 2-按比例同意, 3-全部拒绝";
1173
+ return "审核方式参数错误: 0-全部同意, 1-按数量同意, 2-按比例同意, 3-全部拒绝";
1168
1174
  }
1169
1175
  const oldMethod = reviewMethod;
1170
1176
  reviewMethod = methodNum;
@@ -1455,7 +1461,7 @@ ${reminderMessage}
1455
1461
  const isGroupId = target && /^\d+$/.test(target);
1456
1462
  const isSpecialTarget = target && validTargets.includes(target.toLowerCase());
1457
1463
  if (target && !isGroupId && !isSpecialTarget) {
1458
- return "参数错误:只能指定群号、all、total或留空";
1464
+ return "参数错误: 只能指定群号、all、total或留空";
1459
1465
  }
1460
1466
  if (target?.toLowerCase() === "total" || target?.toLowerCase() === "all") {
1461
1467
  const koishiAuthority = session.author?.authority || session.user?.authority;
@@ -1496,11 +1502,11 @@ ${reminderMessage}
1496
1502
  if (pendingApplications.length === 0) {
1497
1503
  return "当前没有待审核的加群申请";
1498
1504
  }
1499
- let result = "待审核申请列表:\n";
1505
+ let result = "待审核申请列表: \n";
1500
1506
  pendingApplications.forEach((app, index) => {
1501
1507
  result += `${index + 1}. ${app.userName}(${app.userId})
1502
- 申请时间:${app.applyTime.toLocaleString()}
1503
- 申请理由:${app.requestMessage}
1508
+ 申请时间: ${app.applyTime.toLocaleString()}
1509
+ 申请理由: ${app.requestMessage}
1504
1510
 
1505
1511
  `;
1506
1512
  });
@@ -1518,19 +1524,19 @@ ${reminderMessage}
1518
1524
  return await processBlacklistCommand(ctx, session, args || "", config);
1519
1525
  });
1520
1526
  groupVerify.subcommand(".help", "显示帮助信息").alias("gv.帮助", "gverify.帮助", "group-verify.帮助", "帮助", "hlp", "帮助信息").action(() => {
1521
- return `群组验证命令帮助:
1522
- 主指令别名:gv, gverify
1527
+ return `群组验证命令帮助:
1528
+ 主指令别名: gv, gverify
1523
1529
 
1524
1530
  配置命令 (.config/.cfg):
1525
- 用法:
1526
- 1. 创建新配置:gv.cfg 关键词1,关键词2 -m 1 -t 2
1527
- 2. 修改现有配置:gv.cfg -m 1 -t 2 (不提供关键词)
1528
- 3. 启用提醒消息:gv.cfg -msg "消息内容"
1529
- 4. 禁用提醒消息:gv.cfg -nomsg
1530
- 5. 查询配置:gv.cfg -?
1531
- 6. 删除配置:gv.cfg -r
1531
+ 用法:
1532
+ 1. 创建新配置: gv.cfg 关键词1,关键词2 -m 1 -t 2
1533
+ 2. 修改现有配置: gv.cfg -m 1 -t 2 (不提供关键词)
1534
+ 3. 启用提醒消息: gv.cfg -msg "消息内容"
1535
+ 4. 禁用提醒消息: gv.cfg -nomsg
1536
+ 5. 查询配置: gv.cfg -?
1537
+ 6. 删除配置: gv.cfg -r
1532
1538
 
1533
- 参数说明:
1539
+ 参数说明:
1534
1540
  -i <群号> 指定群号(私聊时必需)
1535
1541
  -m <方式> 审核方式 (0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝)
1536
1542
  -t <阈值> 阈值参数(方式1:0-关键词数, 方式2:0-100)
@@ -1542,19 +1548,19 @@ ${reminderMessage}
1542
1548
  -? 查询当前配置
1543
1549
  -r 删除配置
1544
1550
 
1545
- 引号使用规则:
1546
- 关键词包含空格:gv.cfg "关键词1,关键词 2,关键词3"
1547
- 提醒消息包含空格:gv.cfg -msg "这是包含空格的消息"
1548
- 内部引号转义:gv.cfg -msg "包含\\"引号\\"的内容"
1549
- 换行符:gv.cfg -msg "第一行\\n第二行"
1551
+ 引号使用规则:
1552
+ 关键词包含空格: gv.cfg "关键词1,关键词 2,关键词3"
1553
+ 提醒消息包含空格: gv.cfg -msg "这是包含空格的消息"
1554
+ 内部引号转义: gv.cfg -msg "包含\\"引号\\"的内容"
1555
+ 换行符: gv.cfg -msg "第一行\\n第二行"
1550
1556
 
1551
- 特殊说明:
1557
+ 特殊说明:
1552
1558
  • 阈值可设为0表示全部同意
1553
1559
  • 关键词数量变化时阈值会自动调整
1554
1560
  • 重复参数会使用最后出现的值并提醒
1555
1561
  • 群号检查可在插件配置中开关
1556
1562
 
1557
- 提醒消息变量:
1563
+ 提醒消息变量:
1558
1564
  {user} - 用户名
1559
1565
  {id} - 用户ID
1560
1566
  {group} - 群号
@@ -1563,9 +1569,9 @@ ${reminderMessage}
1563
1569
  {answer} - 答对数量/比例
1564
1570
  {threshold} - 阈值要求
1565
1571
 
1566
- 使用示例:
1572
+ 使用示例:
1567
1573
  gv.cfg "关键词1,关键词2" -m 1 -t 2
1568
- gv.cfg -msg "用户 {user}\\n申请理由:{question}"
1574
+ gv.cfg -msg "用户 {user}\\n申请理由: {question}"
1569
1575
  gv.cfg -m 2 -t 80
1570
1576
  gv.cfg -nomsg
1571
1577
 
@@ -1575,21 +1581,21 @@ ${reminderMessage}
1575
1581
  l [group] 查询群黑名单;传入 all 时查看全局黑名单
1576
1582
  i id [group] 查询账号黑名单;不带参数时查询本群与全局,
1577
1583
  指定群号查询该群与全局,传入 all 则列出所有群及全局(需Koishi 3级)
1578
- 使用示例:
1584
+ 使用示例:
1579
1585
  gvb a 12345 作弊记录
1580
1586
  gvb r 12345 67890
1581
1587
  gvb l
1582
1588
  gvb l all
1583
1589
  gvb i 12345
1584
1590
 
1585
- 快捷命令:
1591
+ 快捷命令:
1586
1592
  gvc - 配置命令快捷方式
1587
1593
  gva - 同意申请快捷命令
1588
1594
  gvr - 拒绝申请快捷命令
1589
1595
  gvp - 查看待审核列表快捷命令
1590
1596
  gvs - 查看统计信息快捷命令
1591
1597
 
1592
- 权限说明:
1598
+ 权限说明:
1593
1599
  - 群主/管理员权限
1594
1600
  - koishi三级以上权限
1595
1601
  - 私聊时必须指定群号(-i参数)`;
@@ -1649,7 +1655,7 @@ ${reminderMessage}
1649
1655
  }
1650
1656
  const stat = stats[0];
1651
1657
  const lastUpdated = new Date(stat.lastUpdated).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
1652
- return `群 ${groupId} 验证统计:
1658
+ return `群 ${groupId} 验证统计:
1653
1659
  自动批准: ${stat.autoApproved}
1654
1660
  手动批准: ${stat.manuallyApproved}
1655
1661
  拒绝: ${stat.rejected}
@@ -1663,7 +1669,7 @@ ${reminderMessage}
1663
1669
  }
1664
1670
  const stat = stats[0];
1665
1671
  const lastUpdated = new Date(stat.lastUpdated).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
1666
- return `总计验证统计:
1672
+ return `总计验证统计:
1667
1673
  自动批准: ${stat.autoApproved}
1668
1674
  手动批准: ${stat.manuallyApproved}
1669
1675
  拒绝: ${stat.rejected}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-group-verification",
3
- "description": "Koishi 群组加群验证插件,支持多关键词匹配审核、多种审核方式和详细统计功能",
3
+ "description": "Koishi 群组加群验证插件,支持多关键词匹配审核、多种审核方式、黑名单和详细统计功能",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/LHDyx/koishi-plugin-group-verification.git"
@@ -8,7 +8,7 @@
8
8
  "bugs": {
9
9
  "url": "https://github.com/LHDyx/koishi-plugin-group-verification/issues"
10
10
  },
11
- "version": "1.0.33",
11
+ "version": "1.0.34",
12
12
  "main": "lib/index.js",
13
13
  "typings": "lib/index.d.ts",
14
14
  "files": [
package/src/index.ts CHANGED
@@ -21,7 +21,7 @@ export interface GroupVerificationConfig {
21
21
  groupId: string
22
22
  keywords: string[]
23
23
  reviewMethod: 0 | 1 | 2 | 3 // 0:全部同意, 1:按数量同意, 2:按比例同意, 3:全部拒绝
24
- reviewParameters: number // 直接存储数字:0表示无阈值,其他表示具体阈值
24
+ reviewParameters: number // 直接存储数字: 0表示无阈值,其他表示具体阈值
25
25
  reminderEnabled: boolean // 是否启用提醒消息
26
26
  reminderMessage: string
27
27
  createdBy: string
@@ -37,12 +37,12 @@ export interface GroupVerificationStats {
37
37
  autoApproved: number
38
38
  manuallyApproved: number
39
39
  rejected: number
40
- // 新增:总入群人数(不论方式,只要检测到成员加入则增加)
40
+ // 新增: 总入群人数(不论方式,只要检测到成员加入则增加)
41
41
  totalJoined: number
42
42
  lastUpdated: string | Date
43
43
  }
44
44
 
45
- // 黑名单行:每个群/全局对应一条记录,entries 保存 userId->reason 对象
45
+ // 黑名单行: 每个群/全局对应一条记录,entries 保存 userId->reason 对象
46
46
  export interface GroupBlacklistEntry {
47
47
  id: number
48
48
  groupId: string // 群号或 "all" 表示全局
@@ -81,12 +81,12 @@ export interface Config {
81
81
  export const Config: Schema<Config> = Schema.object({
82
82
  defaultReminderMessage: Schema.string()
83
83
  .description('默认提醒消息模板(使用 \\n 表示换行,可包含下方变量)')
84
- .default('{user}({id}) 申请加入群 {gname}({group})\n申请理由:{question}\n匹配情况:{answer}/{threshold}\n使用 gva 同意或 gvr 拒绝申请'),
84
+ .default('{user}({id}) 申请加入群 {gname}({group})\n申请理由: {question}\n匹配情况: {answer}/{threshold}\n使用 gva 同意或 gvr 拒绝申请'),
85
85
  enableStrictGroupCheck: Schema.boolean().description('是否启用严格的群号检查(检查群号长度)').default(false),
86
86
  logLevel: Schema.union(['debug', 'info', 'warn', 'error']).description('日志级别').default('info'),
87
- permissionDeniedMessage: Schema.string().description('权限不足时返回给调用者的提示').default('权限不足:需要群主/管理员权限或koishi三级以上权限'),
87
+ permissionDeniedMessage: Schema.string().description('权限不足时返回给调用者的提示').default('权限不足: 需要群主/管理员权限或koishi三级以上权限'),
88
88
  invalidGroupMessage: Schema.string().description('无效群号或机器人未在该群时的提示').default('群号 {group} 格式不合法或机器人不在该群中'),
89
- parameterConflictMessage: Schema.string().description('参数冲突时提示').default('参数冲突:-? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'),
89
+ parameterConflictMessage: Schema.string().description('参数冲突时提示').default('参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'),
90
90
  noKeywordsMessage: Schema.string().description('未提供关键词且无法从现有配置继承时的提示').default('请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置'),
91
91
  blacklistAddSuccess: Schema.string().description('将用户加入黑名单后的提示,可使用 {user},{group},{reason}').default('已将用户 {user} 加入群 {group} 黑名单{reason}'),
92
92
  blacklistRemoveSuccess: Schema.string().description('从黑名单移除用户后的提示,可使用 {user},{group}').default('已从群 {group} 的黑名单中移除用户 {user}'),
@@ -104,7 +104,7 @@ export const inject = ['database']
104
104
  */
105
105
  export interface TokenizeResult {
106
106
  tokens: string[];
107
- seps: string[]; // 每个令牌前面的分隔符:' ' 或 ',' 或 ''(表示开始)
107
+ seps: string[]; // 每个令牌前面的分隔符: ' ' 或 ',' 或 ''(表示开始)
108
108
  error?: string;
109
109
  }
110
110
 
@@ -224,7 +224,7 @@ export interface ParsedArgs {
224
224
  }
225
225
 
226
226
  /**
227
- * 验证关键词格式:仅允许用逗号和引号分隔,禁止纯空格分隔
227
+ * 验证关键词格式: 仅允许用逗号和引号分隔,禁止纯空格分隔
228
228
  */
229
229
  // 解析过程中使用的辅助函数
230
230
  function validateKeywordFormat(raw: string): boolean {
@@ -251,25 +251,31 @@ function validateKeywordFormat(raw: string): boolean {
251
251
  * 对于 -nomsg 不会清除已保存的 message,便于后续再次启用时恢复。
252
252
  */
253
253
  export function usageString(): string {
254
- return `用法:
255
- # 创建/修改配置
256
- gvc 关键词1,关键词2 -m 1 -t 2 # 创建配置
257
- gvc -m 1 -t 2 # 修改审核参数
258
-
259
- # 提醒消息控制(可用变量详见下方)
260
- gvc -msg "消息内容" # 修改提醒消息
254
+ return `用法:
255
+ -i 群号
256
+ -m (0|1|2|3)审核方式
257
+ -t 阈值
258
+ -msg [可选,消息内容] 并打开提醒消息
259
+ -nomsg 取消提醒消息(与-msg冲突)
260
+ -r 删除配置
261
+ -? 查询配置
262
+
263
+ 对于存在空格的关键词/提醒消息用双引号""包裹
264
+
265
+ # 例
266
+ gvc 关键词1,关键词2 -m 1 -t 2 # 创建配置
267
+ gvc -msg "消息内容" # 修改提醒消息
261
268
  gvc -nomsg # 禁用提醒消息
262
- # 查询/删除
263
269
  gvc -? # 查询配置
264
270
  gvc -r # 删除配置
265
271
 
266
- 审核方式说明(使用 -m 参数):
272
+ 审核方式说明(使用 -m 参数):
267
273
  0 全部同意(默认)
268
- 1 按数量同意,需要 -t 指定数量
274
+ 1 按数量同意,需要 -t 指定数量
269
275
  2 按比例同意,需要 -t 指定百分比
270
- 3 全部拒绝(拒绝后系统会自动阻止任何通过)
276
+ 3 全部拒绝
271
277
 
272
- 提醒消息可用变量:{user} 用户名 {id} 用户ID
278
+ 提醒消息可用变量: {user} 用户名 {id} 用户ID
273
279
  {group} 群号 {gname} 群名称
274
280
  {question} 申请理由 {answer} 匹配情况 {threshold} 阈值
275
281
  使用 \\n 换行`;
@@ -290,7 +296,7 @@ export function mergeReminder(
290
296
  ) {
291
297
  let reminderEnabled = true;
292
298
  // 优先使用传入的默认模板,其次使用已有配置,再 fallback 到老写死的样式
293
- let reminderMessage = defaultMessage || '{user}({id}) 申请加入群 {gname}({group})\n申请理由:{question}\n匹配情况:{answer}/{threshold}';
299
+ let reminderMessage = defaultMessage || '{user}({id}) 申请加入群 {gname}({group})\n申请理由: {question}\n匹配情况: {answer}/{threshold}';
294
300
 
295
301
  if (existingConfig) {
296
302
  reminderEnabled = existingConfig.reminderEnabled;
@@ -298,7 +304,7 @@ export function mergeReminder(
298
304
  reminderMessage = existingConfig.reminderMessage || reminderMessage;
299
305
  }
300
306
 
301
- // 优先级:disable > bare enable > new message content
307
+ // 优先级: disable > bare enable > new message content
302
308
  if (hasRealDisableMessageParam) {
303
309
  reminderEnabled = false;
304
310
  logger.debug('禁用提醒消息功能 (保留现有内容)');
@@ -321,7 +327,7 @@ export function mergeReminder(
321
327
  * 返回关键词数组和各类 flag 的值,未出现的 flag 保持 undefined。
322
328
  * 若检测到格式错误(如纯空格分隔关键词),返回 error 字段。
323
329
  */
324
- // 全局缓存:记录通过机器人自动批准的用户,供 guild-member-added 事件使用
330
+ // 全局缓存: 记录通过机器人自动批准的用户,供 guild-member-added 事件使用
325
331
  const autoQueue = new Map<string, Set<string>>();
326
332
 
327
333
  // 更新统计信息函数,提取到模块层供多个位置调用
@@ -381,7 +387,7 @@ export async function updateStats(ctx: Context, groupId: string, action: 'autoAp
381
387
  await syncTotalStats(ctx)
382
388
  }
383
389
 
384
- // 提取成独立函数:增加总入群计数,供事件统一调用
390
+ // 提取成独立函数: 增加总入群计数,供事件统一调用
385
391
  export async function incrementTotal(ctx: Context, groupId: string) {
386
392
  const existingStats = await ctx.database.get('group_verification_stats', { groupId })
387
393
  if (existingStats.length > 0) {
@@ -526,7 +532,7 @@ export async function checkPermission(session: any, targetGroupId?: string): Pro
526
532
  return [false, '权限不足']
527
533
  }
528
534
 
529
- // 提供给测试的辅助函数:处理 guild-member-request 事件的逻辑
535
+ // 提供给测试的辅助函数: 处理 guild-member-request 事件的逻辑
530
536
  export async function handleGuildMemberRequestEvent(ctx: Context, session: any) {
531
537
  logger.debug('guild-member-request event', session)
532
538
  let guildId = (session.guildId || session.channelId || '').toString().trim();
@@ -687,7 +693,7 @@ export function parseConfigArgs(raw: string): ParsedArgs {
687
693
  // remove everything from the first flag onward, including when flag sits at start
688
694
  const keywordSection = raw.split(/(?:^|\s+)-(?:i|m|t|msg|nomsg|\?|r)\b/)[0].trim();
689
695
  if (keywordSection && !validateKeywordFormat(keywordSection)) {
690
- error = '关键词应使用逗号分隔或引号框起(如:k1,k2,k3 或 "k1","k2" 或 "k1,k2",k3)';
696
+ error = '关键词应使用逗号分隔或引号框起(如: k1,k2,k3 或 "k1","k2" 或 "k1,k2",k3)';
691
697
  }
692
698
 
693
699
  return { keywords, flags, error };
@@ -869,7 +875,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
869
875
  if (!op || !['a','r','l','i'].includes(op)) {
870
876
  // present a multiline Chinese usage guide without angle brackets
871
877
  return [
872
- '用法:',
878
+ '用法: ',
873
879
  ' gvb a id [reason] [group] 将用户加入黑名单',
874
880
  ' gvb r id [group] 将用户移出黑名单',
875
881
  ' gvb l [group] 查询群黑名单',
@@ -887,7 +893,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
887
893
  targetUser = parts[1]
888
894
  if (!targetUser) return '请提供用户ID'
889
895
  // handle optional reason and group at end
890
- // 规则:如果只有一个附加参数,则作为 reason;两个及以上时最后一个为群号,其余拼成 reason
896
+ // 规则: 如果只有一个附加参数,则作为 reason;两个及以上时最后一个为群号,其余拼成 reason
891
897
  const rest = parts.slice(2)
892
898
  if (rest.length === 1) {
893
899
  reason = rest[0]
@@ -926,7 +932,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
926
932
  const row = rows[0]
927
933
  const entries = row.entries || {}
928
934
  if (entries[targetUser] !== undefined) {
929
- return `用户 ${targetUser} 已在群 ${group} 的黑名单中:${entries[targetUser]}`
935
+ return `用户 ${targetUser} 已在群 ${group} 的黑名单中: ${entries[targetUser]}`
930
936
  }
931
937
  entries[targetUser] = storedReason
932
938
  await ctx.database.set('group_verification_blacklist', { id: row.id }, { entries })
@@ -945,7 +951,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
945
951
  }
946
952
  }
947
953
  const tmpl = (config && config.blacklistAddSuccess) || '已将用户 {user} 加入群 {group} 黑名单{reason}'
948
- return tmpl.replace('{user}', targetUser).replace('{group}', group).replace('{reason}', reason ? `,原因:${reason}` : '')
954
+ return tmpl.replace('{user}', targetUser).replace('{group}', group).replace('{reason}', reason ? `,原因: ${reason}` : '')
949
955
  }
950
956
  if (op === 'r') {
951
957
  targetUser = parts[1]
@@ -1004,7 +1010,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1004
1010
  let prefix = group && group.toLowerCase() === 'all' ? '全局黑名单: \n' : `群 ${group} 黑名单: \n`
1005
1011
  let msg = prefix
1006
1012
  for (const uid in entries) {
1007
- msg += `${uid}${entries[uid] ? `:${entries[uid]}` : ''}\n`
1013
+ msg += `${uid}${entries[uid] ? `: ${entries[uid]}` : ''}\n`
1008
1014
  }
1009
1015
  return msg
1010
1016
  }
@@ -1041,7 +1047,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1041
1047
  // groupArg provided
1042
1048
  if (groupArg.toLowerCase() === 'all') {
1043
1049
  const auth = session.author?.authority || session.user?.authority
1044
- if (!(auth && auth >= 3)) return '权限不足:查看全局/所有群黑名单需要 koishi 3 级以上权限'
1050
+ if (!(auth && auth >= 3)) return '权限不足: 查看全局/所有群黑名单需要 koishi 3 级以上权限'
1045
1051
  const rows = await ctx.database.get('group_verification_blacklist', {})
1046
1052
  const globalReason = globalHit ? globalRows[0].entries[targetUser] : '无'
1047
1053
  const lines: string[] = []
@@ -1103,7 +1109,7 @@ export function apply(ctx: Context, config: Config) {
1103
1109
  if (config.logLevel) logger.level = config.logLevel
1104
1110
 
1105
1111
  // 设置日志级别
1106
- // 注意:Koishi logger的level设置可能需要不同的方式
1112
+ // 注意: Koishi logger的level设置可能需要不同的方式
1107
1113
 
1108
1114
  // 记录插件启动信息
1109
1115
  logger.info('群组验证插件已启动')
@@ -1142,7 +1148,7 @@ export function apply(ctx: Context, config: Config) {
1142
1148
  autoInc: true
1143
1149
  })
1144
1150
 
1145
- // 黑名单表:每条记录对应一个群(或全局),entries 存储 userId->reason 键值对
1151
+ // 黑名单表: 每条记录对应一个群(或全局),entries 存储 userId->reason 键值对
1146
1152
  ctx.model.extend('group_verification_blacklist', {
1147
1153
  id: 'unsigned',
1148
1154
  groupId: 'string',
@@ -1282,7 +1288,7 @@ export function apply(ctx: Context, config: Config) {
1282
1288
 
1283
1289
  logger.debug(`权限检查 - 权限不足`)
1284
1290
  const debugInfo = `调试信息 - 用户ID:${session.userId}, 群号:${groupId}, 权限等级:${koishiAuthority || '未知'}`
1285
- return [false, (config.permissionDeniedMessage || '权限不足:需要群主/管理员权限或koishi三级以上权限') + `\n${debugInfo}`]
1291
+ return [false, (config.permissionDeniedMessage || '权限不足: 需要群主/管理员权限或koishi三级以上权限') + `\n${debugInfo}`]
1286
1292
  }
1287
1293
 
1288
1294
  // Create main command with aliases
@@ -1305,7 +1311,7 @@ export function apply(ctx: Context, config: Config) {
1305
1311
  .option('query', '-? 查询当前配置')
1306
1312
  .option('remove', '-r 删除配置')
1307
1313
  .action(async ({ session, options }: any, keywords: any) => {
1308
- // 详细调试:记录所有输入信息
1314
+ // 详细调试: 记录所有输入信息
1309
1315
  logger.info(`=== 命令解析调试 ===`)
1310
1316
  logger.info(`session内容: guildId=${session.guildId}, userId=${session.userId}`)
1311
1317
 
@@ -1330,7 +1336,7 @@ export function apply(ctx: Context, config: Config) {
1330
1336
  method: flags.method || (options.method === '' ? undefined : options.method),
1331
1337
  threshold: flags.threshold || options.threshold,
1332
1338
  message: flags.message !== undefined ? flags.message : options.message,
1333
- enableMessage: flags.enableMessage, // 新增:-msg 裸调用标记
1339
+ enableMessage: flags.enableMessage, // 新增: -msg 裸调用标记
1334
1340
  disableMessage: flags.disableMessage || options.disableMessage,
1335
1341
  query: flags.query || options.query,
1336
1342
  remove: flags.remove || options.remove,
@@ -1341,7 +1347,7 @@ export function apply(ctx: Context, config: Config) {
1341
1347
  if ((cleanedOptions.query || cleanedOptions.remove) &&
1342
1348
  (parsedKeywords.length > 0 || cleanedOptions.method !== undefined || cleanedOptions.threshold !== undefined ||
1343
1349
  cleanedOptions.message !== undefined || cleanedOptions.enableMessage || cleanedOptions.disableMessage)) {
1344
- return config.parameterConflictMessage || '参数冲突:-? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'
1350
+ return config.parameterConflictMessage || '参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'
1345
1351
  }
1346
1352
 
1347
1353
  // 检查消息参数冲突
@@ -1378,7 +1384,7 @@ export function apply(ctx: Context, config: Config) {
1378
1384
 
1379
1385
  // 参数冲突检查
1380
1386
  if ((hasRealMessageParam || hasRealEnableMessageParam) && hasRealDisableMessageParam) {
1381
- return '参数冲突:不能同时使用 -msg 和 -nomsg'
1387
+ return '参数冲突: 不能同时使用 -msg 和 -nomsg'
1382
1388
  }
1383
1389
 
1384
1390
  // 重复参数检测
@@ -1451,7 +1457,7 @@ export function apply(ctx: Context, config: Config) {
1451
1457
  const updateTime = new Date(config.updatedAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
1452
1458
  const reminderStatus = config.reminderEnabled ? '启用' : '禁用'
1453
1459
 
1454
- return `群 ${targetGroupId} 配置:
1460
+ return `群 ${targetGroupId} 配置:
1455
1461
  关键词: ${decodedKeywords.join(', ')}
1456
1462
  审核方式: ${methodDesc}
1457
1463
  阈值: ${thresholdInfo}
@@ -1491,7 +1497,7 @@ export function apply(ctx: Context, config: Config) {
1491
1497
  existingConfig = existingConfigs[0]
1492
1498
  }
1493
1499
 
1494
- // 处理关键词:如果没有关键词但有其他参数,从现有配置中获取
1500
+ // 处理关键词: 如果没有关键词但有其他参数,从现有配置中获取
1495
1501
  if (keywordList.length === 0 && !cleanedOptions.query && !cleanedOptions.remove) {
1496
1502
  if (!existingConfig) {
1497
1503
  return config.noKeywordsMessage || '请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置'
@@ -1512,13 +1518,13 @@ export function apply(ctx: Context, config: Config) {
1512
1518
 
1513
1519
  // 解析审核方式和阈值(基于新的数据库模型设计)
1514
1520
  let reviewMethod: 0 | 1 | 2 | 3 = 0 // 默认值
1515
- let reviewParameters: number = 0 // 直接存储数字:0表示无阈值
1521
+ let reviewParameters: number = 0 // 直接存储数字: 0表示无阈值
1516
1522
 
1517
1523
  if (existingConfig) {
1518
1524
  // 默认使用现有配置的参数
1519
1525
  reviewMethod = existingConfig.reviewMethod
1520
1526
 
1521
- // 老版本兼容性处理:处理可能的NaN或无效值
1527
+ // 老版本兼容性处理: 处理可能的NaN或无效值
1522
1528
  if (existingConfig.reviewParameters === undefined ||
1523
1529
  existingConfig.reviewParameters === null ||
1524
1530
  isNaN(existingConfig.reviewParameters)) {
@@ -1533,7 +1539,7 @@ export function apply(ctx: Context, config: Config) {
1533
1539
  if (cleanedOptions.method !== undefined && cleanedOptions.method !== '') {
1534
1540
  const methodNum = parseInt(cleanedOptions.method)
1535
1541
  if (isNaN(methodNum) || methodNum < 0 || methodNum > 3) {
1536
- return '审核方式参数错误:0-全部同意, 1-按数量同意, 2-按比例同意, 3-全部拒绝'
1542
+ return '审核方式参数错误: 0-全部同意, 1-按数量同意, 2-按比例同意, 3-全部拒绝'
1537
1543
  }
1538
1544
  const oldMethod = reviewMethod
1539
1545
  reviewMethod = methodNum as 0 | 1 | 2 | 3
@@ -1873,16 +1879,16 @@ export function apply(ctx: Context, config: Config) {
1873
1879
  'gvs'
1874
1880
  )
1875
1881
  .action(async ({ session }: any, target: any) => {
1876
- // 参数验证:只能是群号、all、total或空
1882
+ // 参数验证: 只能是群号、all、total或空
1877
1883
  const validTargets = ['all', 'total']
1878
1884
  const isGroupId = target && /^\d+$/.test(target)
1879
1885
  const isSpecialTarget = target && validTargets.includes(target.toLowerCase())
1880
1886
 
1881
1887
  if (target && !isGroupId && !isSpecialTarget) {
1882
- return '参数错误:只能指定群号、all、total或留空'
1888
+ return '参数错误: 只能指定群号、all、total或留空'
1883
1889
  }
1884
1890
 
1885
- // 权限检查:总计统计需要3级以上权限
1891
+ // 权限检查: 总计统计需要3级以上权限
1886
1892
  if (target?.toLowerCase() === 'total' || target?.toLowerCase() === 'all') {
1887
1893
  // 检查是否为koishi 3级以上权限
1888
1894
  const koishiAuthority = (session as any).author?.authority || (session as any).user?.authority
@@ -1895,7 +1901,7 @@ export function apply(ctx: Context, config: Config) {
1895
1901
 
1896
1902
  // 处理不同参数情况
1897
1903
  if (!target) {
1898
- // 无参数:显示当前群统计
1904
+ // 无参数: 显示当前群统计
1899
1905
  if (!groupId) {
1900
1906
  return '请在群聊中使用此命令或指定群号'
1901
1907
  }
@@ -1936,11 +1942,11 @@ export function apply(ctx: Context, config: Config) {
1936
1942
  return '当前没有待审核的加群申请'
1937
1943
  }
1938
1944
 
1939
- let result = '待审核申请列表:\n'
1945
+ let result = '待审核申请列表: \n'
1940
1946
  pendingApplications.forEach((app, index) => {
1941
1947
  result += `${index + 1}. ${app.userName}(${app.userId})
1942
- 申请时间:${app.applyTime.toLocaleString()}
1943
- 申请理由:${app.requestMessage}
1948
+ 申请时间: ${app.applyTime.toLocaleString()}
1949
+ 申请理由: ${app.requestMessage}
1944
1950
 
1945
1951
  `
1946
1952
  })
@@ -1965,19 +1971,19 @@ export function apply(ctx: Context, config: Config) {
1965
1971
  .subcommand('.help', '显示帮助信息')
1966
1972
  .alias('gv.帮助', 'gverify.帮助', 'group-verify.帮助', '帮助', 'hlp', '帮助信息')
1967
1973
  .action(() => {
1968
- return `群组验证命令帮助:
1969
- 主指令别名:gv, gverify
1974
+ return `群组验证命令帮助:
1975
+ 主指令别名: gv, gverify
1970
1976
 
1971
1977
  配置命令 (.config/.cfg):
1972
- 用法:
1973
- 1. 创建新配置:gv.cfg 关键词1,关键词2 -m 1 -t 2
1974
- 2. 修改现有配置:gv.cfg -m 1 -t 2 (不提供关键词)
1975
- 3. 启用提醒消息:gv.cfg -msg "消息内容"
1976
- 4. 禁用提醒消息:gv.cfg -nomsg
1977
- 5. 查询配置:gv.cfg -?
1978
- 6. 删除配置:gv.cfg -r
1978
+ 用法:
1979
+ 1. 创建新配置: gv.cfg 关键词1,关键词2 -m 1 -t 2
1980
+ 2. 修改现有配置: gv.cfg -m 1 -t 2 (不提供关键词)
1981
+ 3. 启用提醒消息: gv.cfg -msg "消息内容"
1982
+ 4. 禁用提醒消息: gv.cfg -nomsg
1983
+ 5. 查询配置: gv.cfg -?
1984
+ 6. 删除配置: gv.cfg -r
1979
1985
 
1980
- 参数说明:
1986
+ 参数说明:
1981
1987
  -i <群号> 指定群号(私聊时必需)
1982
1988
  -m <方式> 审核方式 (0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝)
1983
1989
  -t <阈值> 阈值参数(方式1:0-关键词数, 方式2:0-100)
@@ -1989,19 +1995,19 @@ export function apply(ctx: Context, config: Config) {
1989
1995
  -? 查询当前配置
1990
1996
  -r 删除配置
1991
1997
 
1992
- 引号使用规则:
1993
- 关键词包含空格:gv.cfg "关键词1,关键词 2,关键词3"
1994
- 提醒消息包含空格:gv.cfg -msg "这是包含空格的消息"
1995
- 内部引号转义:gv.cfg -msg "包含\\"引号\\"的内容"
1996
- 换行符:gv.cfg -msg "第一行\\n第二行"
1998
+ 引号使用规则:
1999
+ 关键词包含空格: gv.cfg "关键词1,关键词 2,关键词3"
2000
+ 提醒消息包含空格: gv.cfg -msg "这是包含空格的消息"
2001
+ 内部引号转义: gv.cfg -msg "包含\\"引号\\"的内容"
2002
+ 换行符: gv.cfg -msg "第一行\\n第二行"
1997
2003
 
1998
- 特殊说明:
2004
+ 特殊说明:
1999
2005
  • 阈值可设为0表示全部同意
2000
2006
  • 关键词数量变化时阈值会自动调整
2001
2007
  • 重复参数会使用最后出现的值并提醒
2002
2008
  • 群号检查可在插件配置中开关
2003
2009
 
2004
- 提醒消息变量:
2010
+ 提醒消息变量:
2005
2011
  {user} - 用户名
2006
2012
  {id} - 用户ID
2007
2013
  {group} - 群号
@@ -2010,9 +2016,9 @@ export function apply(ctx: Context, config: Config) {
2010
2016
  {answer} - 答对数量/比例
2011
2017
  {threshold} - 阈值要求
2012
2018
 
2013
- 使用示例:
2019
+ 使用示例:
2014
2020
  gv.cfg "关键词1,关键词2" -m 1 -t 2
2015
- gv.cfg -msg "用户 {user}\\n申请理由:{question}"
2021
+ gv.cfg -msg "用户 {user}\\n申请理由: {question}"
2016
2022
  gv.cfg -m 2 -t 80
2017
2023
  gv.cfg -nomsg
2018
2024
 
@@ -2022,21 +2028,21 @@ export function apply(ctx: Context, config: Config) {
2022
2028
  l [group] 查询群黑名单;传入 all 时查看全局黑名单
2023
2029
  i id [group] 查询账号黑名单;不带参数时查询本群与全局,
2024
2030
  指定群号查询该群与全局,传入 all 则列出所有群及全局(需Koishi 3级)
2025
- 使用示例:
2031
+ 使用示例:
2026
2032
  gvb a 12345 作弊记录
2027
2033
  gvb r 12345 67890
2028
2034
  gvb l
2029
2035
  gvb l all
2030
2036
  gvb i 12345
2031
2037
 
2032
- 快捷命令:
2038
+ 快捷命令:
2033
2039
  gvc - 配置命令快捷方式
2034
2040
  gva - 同意申请快捷命令
2035
2041
  gvr - 拒绝申请快捷命令
2036
2042
  gvp - 查看待审核列表快捷命令
2037
2043
  gvs - 查看统计信息快捷命令
2038
2044
 
2039
- 权限说明:
2045
+ 权限说明:
2040
2046
  - 群主/管理员权限
2041
2047
  - koishi三级以上权限
2042
2048
  - 私聊时必须指定群号(-i参数)`
@@ -2044,7 +2050,7 @@ export function apply(ctx: Context, config: Config) {
2044
2050
 
2045
2051
  // 插件初始化时确保总计统计行存在
2046
2052
  ctx.on('ready', async () => {
2047
- // 迁移:将旧版保留的 Date 对象字段转换为 ISO 字符串,以避免绑定错误
2053
+ // 迁移: 将旧版保留的 Date 对象字段转换为 ISO 字符串,以避免绑定错误
2048
2054
  try {
2049
2055
  const configs = await ctx.database.get('group_verification_config', {})
2050
2056
  for (const cfg of configs) {
@@ -2101,7 +2107,7 @@ export function apply(ctx: Context, config: Config) {
2101
2107
  await syncTotalStats(ctx)
2102
2108
  })
2103
2109
 
2104
- // 辅助函数:获取群组统计
2110
+ // 辅助函数: 获取群组统计
2105
2111
  async function getGroupStats(groupId: string): Promise<string> {
2106
2112
  const stats = await ctx.database.get('group_verification_stats', { groupId })
2107
2113
 
@@ -2112,14 +2118,14 @@ export function apply(ctx: Context, config: Config) {
2112
2118
  const stat = stats[0]
2113
2119
  const lastUpdated = new Date(stat.lastUpdated).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
2114
2120
 
2115
- return `群 ${groupId} 验证统计:
2121
+ return `群 ${groupId} 验证统计:
2116
2122
  自动批准: ${stat.autoApproved}
2117
2123
  手动批准: ${stat.manuallyApproved}
2118
2124
  拒绝: ${stat.rejected}
2119
2125
  最后更新: ${lastUpdated}`
2120
2126
  }
2121
2127
 
2122
- // 辅助函数:获取总计统计
2128
+ // 辅助函数: 获取总计统计
2123
2129
  async function getTotalStats(): Promise<string> {
2124
2130
  const stats = await ctx.database.get('group_verification_stats', { groupId: 'TOTAL' })
2125
2131
 
@@ -2130,7 +2136,7 @@ export function apply(ctx: Context, config: Config) {
2130
2136
  const stat = stats[0]
2131
2137
  const lastUpdated = new Date(stat.lastUpdated).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
2132
2138
 
2133
- return `总计验证统计:
2139
+ return `总计验证统计:
2134
2140
  自动批准: ${stat.autoApproved}
2135
2141
  手动批准: ${stat.manuallyApproved}
2136
2142
  拒绝: ${stat.rejected}