From c7863acf867c0f089df7a2fff7e9db5a2007a927 Mon Sep 17 00:00:00 2001 From: yibo Date: Mon, 25 May 2026 12:50:48 +0800 Subject: [PATCH] fix: 授权指令支持引用回复(type 57 appmsg) --- server/services/wechat/auto-reply.js | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/server/services/wechat/auto-reply.js b/server/services/wechat/auto-reply.js index 40c1b9a..99d956a 100644 --- a/server/services/wechat/auto-reply.js +++ b/server/services/wechat/auto-reply.js @@ -587,15 +587,25 @@ function escapeRegex(str) { */ function parseApprovalCommand(content) { if (!content) return null; + let replyText = content; + let quotedContext = ''; + // 引用回复(type 57 appmsg):真正的回复文本在 里, + // 被引用的原消息内容在 <refermsg> 里(用来判断"同意哪条") + if (content.includes('<appmsg') || content.includes('<refermsg>')) { + const tm = content.match(/<title>([\s\S]*?)<\/title>/); + if (tm) replyText = tm[1]; + const rm = content.match(/<refermsg>([\s\S]*?)<\/refermsg>/); + if (rm) quotedContext = rm[1]; + } // 群消息前缀剥离(owner 私聊一般没有,保险起见) - let t = content; + let t = replyText; const ci = t.indexOf(':\n'); if (ci > 0 && ci < 30) t = t.substring(ci + 2); t = t.trim(); const m = t.match(/^(同意|授权|批准|approve|allow|yes|拒绝|忽略|不同意|deny|no)\s*(.*)$/i); if (!m) return null; const approve = /同意|授权|批准|approve|allow|yes/i.test(m[1]); - return { approve, target: (m[2] || '').trim() }; + return { approve, target: (m[2] || '').trim(), quotedContext }; } // ═══════════════════════════════════════════════════════════════ @@ -973,14 +983,17 @@ class AutoReplyBot { // 处理 owner 的授权指令 async handleApproval(cmd) { - const { approve, target } = cmd; + const { approve, target, quotedContext } = cmd; const pendings = this.whitelist.pendingTalkers(); if (pendings.length === 0) { await this.sendPlainTo(CONFIG.ownerWxid, CONFIG.ownerDisplayName, '当前没有待授权的请求。'); return; } - // 选定目标:指定了就按 wxid / 昵称 / senderName 匹配,没指定取最近一个 + // 选定目标,优先级: + // 1. 显式 target("同意 宜创AI全员群")按 wxid/昵称/senderName 匹配 + // 2. 引用回复的被引用内容里出现哪个 pending 的 displayName("同意"引用了某条授权请求) + // 3. 都没有 → 取最近一个 pending let talker = null; if (target) { talker = pendings.find(t => { @@ -988,7 +1001,13 @@ class AutoReplyBot { return t === target || p.displayName === target || p.senderName === target - || (p.displayName && p.displayName.includes(target)); + || (p.displayName && (p.displayName.includes(target) || target.includes(p.displayName))); + }); + } + if (!talker && quotedContext) { + talker = pendings.find(t => { + const dn = this.whitelist.pending[t].displayName; + return dn && quotedContext.includes(dn); }); } if (!talker) talker = pendings[pendings.length - 1]; -- libgit2 0.21.4