mioku-plugin-admin 3.0.1 → 3.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/commands/group.ts CHANGED
@@ -21,7 +21,7 @@ function formatGroupRole(role: string): string {
21
21
 
22
22
  type GroupContext = CommandExecutionContext & {
23
23
  bot: Bot;
24
- groupIdNum: number;
24
+ groupIdNum: string;
25
25
  senderRole: string;
26
26
  };
27
27
 
@@ -32,19 +32,20 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
32
32
  ) => {
33
33
  ctx.command({
34
34
  ...def,
35
- prefixes: false,
35
+ // 原设计:裸命令与 /命令 都可用;这里保留两者并补上 . 前缀
36
+ prefixes: ["", ".", "/"],
36
37
  handler: async (c) => {
37
38
  const event = c.event;
38
39
  if (event.user_id === event.self_id) return;
39
40
  if (event.message_type !== "group") return;
40
41
  const bot = event.bot;
41
42
  if (!bot) return;
42
- const groupIdNum = event.group_id ? Number(event.group_id) : 0;
43
+ const groupIdNum = String(event.group_id ?? "").trim();
43
44
  if (!groupIdNum) return;
44
45
  const senderRole = await getMemberRole(
45
46
  bot,
46
47
  groupIdNum,
47
- Number(event.user_id),
48
+ String(event.user_id ?? "").trim(),
48
49
  );
49
50
  try {
50
51
  await run({ ...c, bot, groupIdNum, senderRole });
@@ -64,7 +65,7 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
64
65
 
65
66
  const ensureDangerousTargetPermission = async (
66
67
  c: GroupContext,
67
- targetUserId: number,
68
+ targetUserId: string,
68
69
  actionName: string,
69
70
  ): Promise<boolean> => {
70
71
  const { bot, groupIdNum, senderRole, event } = c;
@@ -89,7 +90,7 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
89
90
  async (c) => {
90
91
  const { ctx, event, bot, groupIdNum, body } = c;
91
92
  const atUser = getAtUserId(event.message);
92
- if (atUser != null && atUser !== Number(event.user_id)) {
93
+ if (atUser != null && atUser !== String(event.user_id ?? "").trim()) {
93
94
  await event.reply("管好自己呗~", true);
94
95
  return;
95
96
  }
@@ -115,47 +116,43 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
115
116
 
116
117
  register(
117
118
  {
118
- name: "/改头衔",
119
- match: /^\/?改头衔(?:\s|$)/,
119
+ name: "改头衔",
120
+ match: /^\/??改头衔(?:\s|$)/,
120
121
  permission: "admin",
121
122
  description: "设置群成员专属头衔",
122
- usage: "/改头衔 qq号或@人 头衔",
123
+ usage: ".改头衔 <用户ID或@人> 头衔",
123
124
  },
124
125
  async (c) => {
125
126
  const { ctx, event, bot, groupIdNum, body } = c;
126
- const rest = body.replace(/^\/?改头衔\s*/, "").trim();
127
+ const rest = body.replace(/^\/??改头衔\s*/, "").trim();
127
128
  const atUser = getAtUserId(event.message);
128
- let targetUser: number | undefined = atUser;
129
+ let targetUser: string | undefined = atUser;
129
130
  let title: string;
130
131
 
131
- const isSlashCommand = body.startsWith("/");
132
-
133
132
  if (atUser) {
134
- title = rest.replace(/@\d+\s*/, "").trim();
133
+ title = rest.replace(/@[A-Za-z0-9_-]{4,64}\s*/, "").trim();
135
134
  } else {
136
135
  const parts = rest.split(/\s+/);
137
136
  if (parts.length < 2) {
138
- if (!isSlashCommand) return;
139
137
  await replyAdminErrorNotice({
140
138
  ctx,
141
139
  event,
142
140
  instruction:
143
- "用户在让你修改别人的头衔时缺少参数,请提示用户命令后需要加qq号或@人",
141
+ "用户在让你修改别人的头衔时缺少参数,请提示用户命令后需要加用户ID或@人",
144
142
  fallbackMessage: "想改谁的头衔呀~",
145
143
  });
146
144
  return;
147
145
  }
148
- targetUser = parseInt(parts[0], 10);
146
+ targetUser = String(parts[0]).trim();
149
147
  title = parts.slice(1).join(" ");
150
148
  }
151
149
 
152
150
  if (!targetUser || !title) {
153
- if (!isSlashCommand) return;
154
151
  await replyAdminErrorNotice({
155
152
  ctx,
156
153
  event,
157
154
  instruction:
158
- "用户触发改头衔时参数无效,请提示用户命令后需要加qq号或@人",
155
+ "用户触发改头衔时参数无效,请提示用户命令后需要加用户ID或@人",
159
156
  fallbackMessage: "想改谁的头衔呀~",
160
157
  });
161
158
  return;
@@ -178,16 +175,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
178
175
 
179
176
  register(
180
177
  {
181
- name: "/踢",
182
- match: /^\/?踢(?:\s|$)/,
178
+ name: "",
179
+ match: /^\/??踢(?:\s|$)/,
183
180
  permission: "admin",
184
181
  description: "踢出群成员",
185
182
  },
186
183
  async (c) => {
187
184
  const { ctx, event, bot, groupIdNum, body } = c;
188
185
  const atUser = getAtUserId(event.message);
189
- const isSlashCommand = body.startsWith("/");
190
- if (!atUser && !isSlashCommand) return;
191
186
  if (!atUser) {
192
187
  await replyAdminErrorNotice({
193
188
  ctx,
@@ -216,17 +211,15 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
216
211
 
217
212
  register(
218
213
  {
219
- name: "/禁言",
220
- match: /^\/?禁(?:言)?(?:\s|$)/,
214
+ name: "禁言",
215
+ match: /^\/??禁(?:言)?(?:\s|$)/,
221
216
  permission: "admin",
222
217
  description: "禁言群成员(支持分钟/小时/天)",
223
- usage: "/禁言 @人 10分钟",
218
+ usage: ".禁言 @人 10分钟",
224
219
  },
225
220
  async (c) => {
226
221
  const { ctx, event, bot, groupIdNum, body } = c;
227
222
  const atUser = getAtUserId(event.message);
228
- const isSlashCommand = body.startsWith("/");
229
- if (!atUser && !isSlashCommand) return;
230
223
  if (!atUser) {
231
224
  await replyAdminErrorNotice({
232
225
  ctx,
@@ -238,8 +231,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
238
231
  return;
239
232
  }
240
233
  if (!(await ensureDangerousTargetPermission(c, atUser, "禁言"))) return;
241
- const rest = body.replace(/^\/?禁言\s*/, "").trim();
242
- const durationStr = rest.replace(/@\d+\s*/, "").trim();
234
+ const rest = body.replace(/^\/??禁言\s*/, "").trim();
235
+ const durationStr = rest.replace(/@[A-Za-z0-9_-]{4,64}\s*/, "").trim();
243
236
  const durationSec = parseDuration(durationStr) || 10 * 60;
244
237
  try {
245
238
  await bot.banMember(groupIdNum, atUser, durationSec);
@@ -258,16 +251,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
258
251
 
259
252
  register(
260
253
  {
261
- name: "/解禁",
262
- match: /^\/?解(?:禁)?(?:\s|$)/,
254
+ name: "解禁",
255
+ match: /^\/??解(?:禁)?(?:\s|$)/,
263
256
  permission: "admin",
264
257
  description: "解除群成员禁言",
265
258
  },
266
259
  async (c) => {
267
260
  const { ctx, event, bot, groupIdNum, body } = c;
268
261
  const atUser = getAtUserId(event.message);
269
- const isSlashCommand = body.startsWith("/");
270
- if (!atUser && !isSlashCommand) return;
271
262
  if (!atUser) {
272
263
  await replyAdminErrorNotice({
273
264
  ctx,
@@ -295,16 +286,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
295
286
 
296
287
  register(
297
288
  {
298
- name: "/设管理",
299
- match: /^\/?设管理(?:\s|$)/,
289
+ name: "设管理",
290
+ match: /^\/??设管理(?:\s|$)/,
300
291
  permission: "admin",
301
292
  description: "设置群管理员",
302
293
  },
303
294
  async (c) => {
304
295
  const { ctx, event, bot, groupIdNum, body } = c;
305
296
  const atUser = getAtUserId(event.message);
306
- const isSlashCommand = body.startsWith("/");
307
- if (!atUser && !isSlashCommand) return;
308
297
  if (!atUser) {
309
298
  await replyAdminErrorNotice({
310
299
  ctx,
@@ -332,8 +321,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
332
321
 
333
322
  register(
334
323
  {
335
- name: "/全体禁言",
336
- match: /^\/全体禁言$/,
324
+ name: "全体禁言",
325
+ match: /^\/?全体禁言$/,
337
326
  permission: "admin",
338
327
  description: "开启全体禁言",
339
328
  },
@@ -356,8 +345,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
356
345
 
357
346
  register(
358
347
  {
359
- name: "/全体解禁",
360
- match: /^\/全体解禁$/,
348
+ name: "全体解禁",
349
+ match: /^\/?全体解禁$/,
361
350
  permission: "admin",
362
351
  description: "关闭全体禁言",
363
352
  },
@@ -380,14 +369,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
380
369
 
381
370
  register(
382
371
  {
383
- name: "/改群名片",
384
- match: /^\/?改群名片(?:\s|$)/,
372
+ name: "改群名片",
373
+ match: /^\/??改群名片(?:\s|$)/,
385
374
  permission: "admin",
386
375
  description: "修改Bot在群里的名片",
387
376
  },
388
377
  async (c) => {
389
378
  const { ctx, event, bot, groupIdNum, body } = c;
390
- const card = body.replace(/^\/?改群名片\s*/, "").trim();
379
+ const card = body.replace(/^\/??改群名片\s*/, "").trim();
391
380
  if (!card) {
392
381
  await replyAdminErrorNotice({
393
382
  ctx,
@@ -414,14 +403,14 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
414
403
 
415
404
  register(
416
405
  {
417
- name: "/改群昵称",
418
- match: /^\/改群昵称/,
406
+ name: "改群昵称",
407
+ match: /^\/?改群昵称/,
419
408
  permission: "admin",
420
409
  description: "修改群聊名称",
421
410
  },
422
411
  async (c) => {
423
412
  const { ctx, event, bot, groupIdNum, body } = c;
424
- const groupName = body.replace(/^\/改群昵称\s*/, "").trim();
413
+ const groupName = body.replace(/^\/?改群昵称\s*/, "").trim();
425
414
  if (!groupName) {
426
415
  await replyAdminErrorNotice({
427
416
  ctx,
@@ -449,8 +438,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
449
438
 
450
439
  register(
451
440
  {
452
- name: "/改群头像",
453
- match: /^\/改群头像/,
441
+ name: "改群头像",
442
+ match: /^\/?改群头像/,
454
443
  permission: "admin",
455
444
  description: "修改群头像",
456
445
  },
@@ -484,8 +473,8 @@ export function registerGroupAdminCommands(ctx: MiokuContext) {
484
473
 
485
474
  register(
486
475
  {
487
- name: "/撤回",
488
- match: /^\/?撤回(?:\s|$)/,
476
+ name: "撤回",
477
+ match: /^\/??撤回(?:\s|$)/,
489
478
  permission: "admin",
490
479
  description: "撤回别人的消息",
491
480
  usage: "引用一条消息后输入 /撤回",
@@ -23,8 +23,8 @@ export async function replyAdminErrorNotice(options: {
23
23
  error?: unknown;
24
24
  }): Promise<void> {
25
25
  const text = options.ctx.text(options.event)?.trim() ?? "";
26
- const hasSlashPrefix = text.startsWith("/");
27
- if (!hasSlashPrefix) {
26
+ // 只对真正的命令消息做 AI 兜底提示,普通聊天不打扰(命令支持 / 与 . 前缀)
27
+ if (!/^[./]/.test(text)) {
28
28
  return;
29
29
  }
30
30
  if (options.error != null) {
@@ -154,7 +154,6 @@ export function registerPersonalCommands(ctx: MiokuContext) {
154
154
  const { handler, ...rest } = command;
155
155
  ctx.command({
156
156
  ...rest,
157
- prefixes: false,
158
157
  handler: async (c) => {
159
158
  if (c.event.user_id === c.event.self_id) return;
160
159
  await handler(c);
@@ -163,8 +162,8 @@ export function registerPersonalCommands(ctx: MiokuContext) {
163
162
  };
164
163
 
165
164
  register({
166
- name: "/改头像",
167
- match: /^\/改头像/,
165
+ name: "改头像",
166
+ match: /^\/?改头像/,
168
167
  permission: "master",
169
168
  description: "修改Bot头像",
170
169
  handler: async ({ event }) => {
@@ -191,14 +190,14 @@ export function registerPersonalCommands(ctx: MiokuContext) {
191
190
  });
192
191
 
193
192
  register({
194
- name: "/改昵称",
195
- match: /^\/改昵称/,
193
+ name: "改昵称",
194
+ match: /^\/?改昵称/,
196
195
  permission: "master",
197
196
  description: "修改Bot昵称",
198
197
  handler: async ({ event, body }) => {
199
198
  const bot = event.bot;
200
199
  if (!bot) return;
201
- const nickname = body.replace(/^\/改昵称\s*/, "").trim();
200
+ const nickname = body.replace(/^\/?改昵称\s*/, "").trim();
202
201
  if (!nickname) {
203
202
  await event.reply("想改成什么昵称呀~", true);
204
203
  return;
@@ -219,14 +218,14 @@ export function registerPersonalCommands(ctx: MiokuContext) {
219
218
  });
220
219
 
221
220
  register({
222
- name: "/改签名",
223
- match: /^\/改签名/,
221
+ name: "改签名",
222
+ match: /^\/?改签名/,
224
223
  permission: "master",
225
224
  description: "修改Bot个性签名",
226
225
  handler: async ({ event, body }) => {
227
226
  const bot = event.bot;
228
227
  if (!bot) return;
229
- const personalNote = body.replace(/^\/改签名\s*/, "").trim();
228
+ const personalNote = body.replace(/^\/?改签名\s*/, "").trim();
230
229
  if (!personalNote) {
231
230
  await event.reply("想改成什么签名呀~", true);
232
231
  return;
@@ -247,14 +246,14 @@ export function registerPersonalCommands(ctx: MiokuContext) {
247
246
  });
248
247
 
249
248
  register({
250
- name: "/改性别",
251
- match: /^\/改性别/,
249
+ name: "改性别",
250
+ match: /^\/?改性别/,
252
251
  permission: "master",
253
252
  description: "修改Bot性别",
254
253
  handler: async ({ event, body }) => {
255
254
  const bot = event.bot;
256
255
  if (!bot) return;
257
- const sex = parseProfileSex(body.replace(/^\/改性别\s*/, ""));
256
+ const sex = parseProfileSex(body.replace(/^\/?改性别\s*/, ""));
258
257
  try {
259
258
  await bot.setProfile({ sex });
260
259
  await event.reply("done");
@@ -271,15 +270,15 @@ export function registerPersonalCommands(ctx: MiokuContext) {
271
270
  });
272
271
 
273
272
  register({
274
- name: "/删好友",
275
- match: /^\/删好友(?:\s|$)/,
273
+ name: "删好友",
274
+ match: /^\/?删好友(?:\s|$)/,
276
275
  permission: "master",
277
276
  description: "删除好友",
278
- usage: "/删好友 qq号",
277
+ usage: ".删好友 qq号",
279
278
  handler: async ({ event, body }) => {
280
279
  const bot = event.bot;
281
280
  if (!bot) return;
282
- const qq = parseInt(body.replace(/^\/删好友\s*/, "").trim(), 10);
281
+ const qq = parseInt(body.replace(/^\/?删好友\s*/, "").trim(), 10);
283
282
  if (!qq) {
284
283
  await replyAdminErrorNotice({
285
284
  ctx,
@@ -305,15 +304,15 @@ export function registerPersonalCommands(ctx: MiokuContext) {
305
304
  });
306
305
 
307
306
  register({
308
- name: "/退群",
309
- match: /^\/退群(?:\s|$)/,
307
+ name: "退群",
308
+ match: /^\/?退群(?:\s|$)/,
310
309
  permission: "master",
311
310
  description: "退出群聊",
312
- usage: "/退群 群号",
311
+ usage: ".退群 群号",
313
312
  handler: async ({ event, body }) => {
314
313
  const bot = event.bot;
315
314
  if (!bot) return;
316
- const targetGroup = parseInt(body.replace(/^\/退群\s*/, "").trim(), 10);
315
+ const targetGroup = parseInt(body.replace(/^\/?退群\s*/, "").trim(), 10);
317
316
  if (!targetGroup) {
318
317
  await replyAdminErrorNotice({
319
318
  ctx,
@@ -339,11 +338,11 @@ export function registerPersonalCommands(ctx: MiokuContext) {
339
338
  });
340
339
 
341
340
  register({
342
- name: "/发好友",
343
- match: /^\/发好友(?:\s|$)/,
341
+ name: "发好友",
342
+ match: /^\/?发好友(?:\s|$)/,
344
343
  permission: "master",
345
344
  description: "给好友发送私聊消息",
346
- usage: "/发好友 qq号 内容",
345
+ usage: ".发好友 qq号 内容",
347
346
  handler: async ({ event, body }) => {
348
347
  const bot = event.bot;
349
348
  if (!bot) return;
@@ -392,11 +391,11 @@ export function registerPersonalCommands(ctx: MiokuContext) {
392
391
  });
393
392
 
394
393
  register({
395
- name: "/发群聊",
396
- match: /^\/发群聊(?:\s|$)/,
394
+ name: "发群聊",
395
+ match: /^\/?发群聊(?:\s|$)/,
397
396
  permission: "master",
398
397
  description: "给群聊发送消息",
399
- usage: "/发群聊 群号 内容",
398
+ usage: ".发群聊 群号 内容",
400
399
  handler: async ({ event, body }) => {
401
400
  const bot = event.bot;
402
401
  if (!bot) return;
@@ -445,8 +444,8 @@ export function registerPersonalCommands(ctx: MiokuContext) {
445
444
  });
446
445
 
447
446
  register({
448
- name: "/全部好友",
449
- match: /^\/全部好友$/,
447
+ name: "全部好友",
448
+ match: /^\/?全部好友$/,
450
449
  permission: "master",
451
450
  description: "获取全部好友列表",
452
451
  handler: async ({ event }) => {
@@ -496,8 +495,8 @@ export function registerPersonalCommands(ctx: MiokuContext) {
496
495
  });
497
496
 
498
497
  register({
499
- name: "/全部群聊",
500
- match: /^\/全部群聊$/,
498
+ name: "全部群聊",
499
+ match: /^\/?全部群聊$/,
501
500
  permission: "master",
502
501
  description: "获取全部群聊列表",
503
502
  handler: async ({ event }) => {
@@ -37,9 +37,9 @@ const VERIFY_MODE_LABELS: Record<string, string> = {
37
37
 
38
38
  type VerifyContext = CommandExecutionContext & {
39
39
  bot: Bot;
40
- groupIdNum: number;
40
+ groupIdNum: string;
41
41
  groupName: string;
42
- selfId: number;
42
+ selfId: string;
43
43
  };
44
44
 
45
45
  async function extractQuoteImageUrls(event: MessageEvent): Promise<string[]> {
@@ -61,22 +61,21 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
61
61
  ) => {
62
62
  ctx.command({
63
63
  ...def,
64
- prefixes: false,
65
64
  handler: async (c) => {
66
65
  const event = c.event;
67
66
  if (event.user_id === event.self_id) return;
68
67
  if (event.message_type !== "group") return;
69
68
  const bot = event.bot;
70
69
  if (!bot) return;
71
- const groupIdNum = event.group_id ? Number(event.group_id) : 0;
70
+ const groupIdNum = String(event.group_id ?? "").trim();
72
71
  if (!groupIdNum) return;
73
72
  try {
74
73
  await run({
75
74
  ...c,
76
75
  bot,
77
76
  groupIdNum,
78
- groupName: String(event?.group?.group_name || "").trim() || String(groupIdNum),
79
- selfId: Number(event.self_id),
77
+ groupName: String(event?.group?.group_name || "").trim() || groupIdNum,
78
+ selfId: String(event.self_id ?? "").trim(),
80
79
  });
81
80
  } catch (err) {
82
81
  ctx.logger.error(`[admin verify] 未捕获异常: ${String(err)}`);
@@ -94,7 +93,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
94
93
 
95
94
  register(
96
95
  {
97
- name: "/开启验证",
96
+ name: "开启验证",
98
97
  match: /^[/#]开启验证$/,
99
98
  permission: "admin",
100
99
  description: "开启本群入群验证",
@@ -128,7 +127,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
128
127
 
129
128
  register(
130
129
  {
131
- name: "/关闭验证",
130
+ name: "关闭验证",
132
131
  match: /^[/#]关闭验证$/,
133
132
  permission: "admin",
134
133
  description: "关闭本群入群验证",
@@ -151,11 +150,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
151
150
 
152
151
  register(
153
152
  {
154
- name: "/切换验证模式",
153
+ name: "切换验证模式",
155
154
  match: /^[/#]切换验证模式(?:\s|$)/,
156
155
  permission: "admin",
157
156
  description: "切换验证模式:回应/数字/手性碳",
158
- usage: "/切换验证模式 回应",
157
+ usage: ".切换验证模式 回应",
159
158
  },
160
159
  async (c) => {
161
160
  const { ctx, event, groupIdNum, body } = c;
@@ -183,11 +182,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
183
182
 
184
183
  register(
185
184
  {
186
- name: "/绕过验证",
185
+ name: "绕过验证",
187
186
  match: /^[/#]绕过验证(?:\s|$)/,
188
187
  permission: "admin",
189
188
  description: "绕过指定新成员的验证直接欢迎",
190
- usage: "/绕过验证 @新成员",
189
+ usage: ".绕过验证 @新成员",
191
190
  },
192
191
  async (c) => {
193
192
  const { ctx, event, groupIdNum, groupName, selfId } = c;
@@ -224,11 +223,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
224
223
 
225
224
  register(
226
225
  {
227
- name: "/重新验证",
226
+ name: "重新验证",
228
227
  match: /^[/#]重新验证(?:\s|$)/,
229
228
  permission: "admin",
230
229
  description: "让指定成员重新进行入群验证",
231
- usage: "/重新验证 @成员",
230
+ usage: ".重新验证 @成员",
232
231
  },
233
232
  async (c) => {
234
233
  const { ctx, event, bot, groupIdNum, groupName, selfId } = c;
@@ -282,11 +281,11 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
282
281
 
283
282
  register(
284
283
  {
285
- name: "/入群提示",
284
+ name: "入群提示",
286
285
  match: /^[/#]入群提示(?:\s|$)/,
287
286
  permission: "admin",
288
287
  description: "设置本群自定义入群提示,可附带文字+图片",
289
- usage: "/入群提示 xxx;/入群提示 关闭",
288
+ usage: ".入群提示 xxx;/入群提示 关闭",
290
289
  },
291
290
  async (c) => {
292
291
  const { ctx, event, groupIdNum, body } = c;
package/config.ts CHANGED
@@ -1,7 +1,6 @@
1
- import type { RecvAtElement, RecvElement, RecvImageElement } from "napcat-sdk";
2
1
 
3
2
  export interface AdminConfig {
4
- notifyTarget: number[];
3
+ notifyTarget: string[];
5
4
  notifyFriendMsg: boolean;
6
5
  notifyFriendRequest: boolean;
7
6
  notifyGroupInvite: boolean;
@@ -37,7 +36,9 @@ export const DEFAULT_CONFIG: AdminConfig = {
37
36
  export function normalizeConfig(raw: any): AdminConfig {
38
37
  return {
39
38
  notifyTarget: Array.isArray(raw?.notifyTarget)
40
- ? raw.notifyTarget.map((v: any) => Number(v)).filter((n: number) => n > 0)
39
+ ? raw.notifyTarget
40
+ .map((v: unknown) => String(v ?? "").trim())
41
+ .filter((id: string) => id.length > 0)
41
42
  : DEFAULT_CONFIG.notifyTarget,
42
43
  notifyFriendMsg: raw?.notifyFriendMsg ?? DEFAULT_CONFIG.notifyFriendMsg,
43
44
  notifyFriendRequest:
@@ -136,7 +137,9 @@ export function extractImageUrls(message: readonly SegmentLike[] | null | undefi
136
137
  }
137
138
 
138
139
  // 从消息中提取被@的人的QQ号
139
- export function getAtUserId(message: readonly SegmentLike[] | null | undefined): number | undefined {
140
+ export function getAtUserId(
141
+ message: readonly SegmentLike[] | null | undefined,
142
+ ): string | undefined {
140
143
  if (!Array.isArray(message)) return undefined;
141
144
  const atSeg = message.find(
142
145
  (seg) =>
@@ -144,18 +147,25 @@ export function getAtUserId(message: readonly SegmentLike[] | null | undefined):
144
147
  String(seg.data?.qq ?? seg.data?.target) !== "all",
145
148
  );
146
149
  if (!atSeg) return undefined;
147
- const qq = Number(atSeg.data?.qq ?? atSeg.data?.target);
148
- return Number.isFinite(qq) ? qq : undefined;
150
+ const id = String(atSeg.data?.qq ?? atSeg.data?.target ?? "").trim();
151
+ return id || undefined;
152
+ }
153
+
154
+ /** qlogo 头像服务只认数字 QQ 号,openid 一律返回空串 */
155
+ function qlogoUrl(host: string, id: string, suffix: string): string {
156
+ if (!/^\d+$/.test(id)) return "";
157
+ return `https://${host}/${id}${suffix}`;
149
158
  }
150
159
 
151
160
  // 获取群成员头像URL
152
- export function getAvatarUrl(userId: number | string): string {
153
- return `https://q1.qlogo.cn/g?b=qq&nk=${String(userId)}&s=640`;
161
+ export function getAvatarUrl(userId: string): string {
162
+ return qlogoUrl("q1.qlogo.cn/g?b=qq&nk=", String(userId ?? "").trim(), "&s=640");
154
163
  }
155
164
 
156
165
  // 获取群头像URL
157
- export function getGroupAvatarUrl(groupId: number | string): string {
158
- const g = String(groupId);
166
+ export function getGroupAvatarUrl(groupId: string): string {
167
+ const g = String(groupId ?? "").trim();
168
+ if (!/^\d+$/.test(g)) return "";
159
169
  return `https://p.qlogo.cn/gh/${g}/${g}/640/`;
160
170
  }
161
171