Skip to content
本文共 0 字
预计阅读 1 分钟

#指令 与交互 ​

小程序装到群里之后,群成员可以用 #指令 唤起它。

语法 ​

#<command> [参数]
  • command 是 manifest 里声明的指令名(A-Za-z0-9_-,最长 24,统一小写);
  • 指令后面用空格隔开的就是 args,原样传给小程序;
  • 例:#roll、#roll 2d6、#note 周五例会。

解析顺序 ​

  1. 输入框提交时,平台先用 /^#([A-Za-z0-9_-]{1,24})(?:\s+(.*))?$/ 匹配整条文本;
  2. 不匹配 → 当作普通消息发送(完全不影响正常聊天);
  3. 匹配 → 在当前会话可见的安装记录里找:
    • 先找群级安装的同命指令;
    • 再找个人级安装的同命指令;
  4. 找到 → 打开小程序并传参,原文不会发出去;
  5. 没找到 → 仍然按普通消息发送(# 开头也可能是正常的聊天内容)。

输入时的补全 ​

输入框里敲 # 开头(且还没打空格)时,上方会浮出候选列表:

  • 最多 6 条,显示图标、#指令名、小程序名与简介;
  • ↑ / ↓ 切换,Enter 或 Tab 直接调用,Esc 关掉;
  • 也可以直接用鼠标点。

候选只包含当前会话可见的安装:群级安装的本群小程序 + 你自己的个人级安装。

小程序侧:接收调用 ​

平台在握手完成后下发一次 invoke 事件:

js
CircleChat.on('invoke', (p) => {
  // p.command  'roll'
  // p.args     '2d6'
  // p.chatId   'g:xxxx'
});

注意两点:

  • 事件可能早于 ready() 触发,也可能晚一拍。稳妥写法是先 ready(),再注册 on('invoke'), 同时缓存一次事件参数(避免注册晚了漏掉这次调用):
  • 通过侧栏点开(不是指令唤起)时不会有 invoke 事件,页面要能独立工作。
js
let pending = null;
CircleChat.on('invoke', (p) => { pending = p; run(p); });

CircleChat.ready().then((ctx) => {
  if (pending) run(pending);   // 事件先到了
  else render(ctx);            // 正常打开
});

典型交互模式 ​

A. 指令即结果(掷骰子、抽签、翻译)

拿到 invoke 后直接算出结果,有 message.send 就发到群里,让所有人看到:

js
CircleChat.on('invoke', async (p) => {
  const v = 1 + Math.floor(Math.random() * 6);
  await CircleChat.sendMessage(`🎲 ${p.args || '1d6'} → ${v}`);
  CircleChat.close();   // 用完就关,不打扰
});

B. 指令打开面板(便签、投票、统计)

唤起后停在面板里让人操作,是否发消息交给用户决定。

C. 无指令的小工具

不声明 command,只能从侧栏「小程序」分区点开。适合计算器、换算器这类纯本地工具。

边界与注意 ​

情况行为
群里没装这个小程序#xxx 当普通消息发出去
装了但指令名对不上同上
私聊里用 #xxx会匹配你的个人级安装(群级安装只在对应群生效)
只是想发一个 # 开头的普通文本打完按 Esc 关掉候选,再回车发送
同一指令在群级和个人级都装了群级优先
指令被禁言/处罚拦截小程序代发消息时会返回 api.msg.muted / api.msg.banned,页面应给出提示

调用记录 ​

每次成功唤起会记一条审计日志(mini.invoke,含指令名),管理员可在「日志 → 小程序」里看到谁在什么时候调用了什么。 小程序自己发消息还会另记一条 mini.msg。

基于 GPL-3.0 开源