From 308a2103ac1f517edbf48cac26f843cc1d6fbadc Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Sun, 11 Oct 2026 15:16:46 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E9=80=9A=E7=9F=A5):=20=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E6=B6=88=E6=81=AF=E7=9A=84=E6=AF=8F=E6=9D=A1?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E8=B7=AF=E5=BE=84=E9=83=BD=E5=86=99=E6=97=A5?= =?UTF-8?q?=E5=BF=97=EF=BC=8C=E4=B8=8D=E5=86=8D=E9=9D=99=E9=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 以前 sendWechatSubscribeToUser 的四条提前返回(no-template / disabled-by-user / no-wechat-openid / no-access-token)都不写日志,线上排查「通知没发出去」时 容器日志里一片空白,只能靠猜。现在每条都打一行 [WeChatSubscribe] ... 跳过:原因, 另外 createSongSelectedNotification 在「用户关了通知总开关」时也补了一行。 用途:发布一首新歌后执行 docker logs --timestamps voicehub-app | grep WeChatSubscribe 即可直接看到卡在哪一步(模板没配 / 用户没绑微信 / 拿不到 token / 没有额度 43101 / 字段 47003)。 --- server/services/notificationService.ts | 23 +++++++++++++++++++---- server/services/wechatSubscribeService.ts | 21 ++++++++++++++++++--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/server/services/notificationService.ts b/server/services/notificationService.ts index 7e5eb63..3836bcd 100644 --- a/server/services/notificationService.ts +++ b/server/services/notificationService.ts @@ -163,6 +163,9 @@ export async function createSongSelectedNotification( // 如果用户关闭了此类通知,则不发送 if (settings && !settings.enabled) { + console.warn( + `[Notification] SONG_SELECTED → user ${userId} 跳过:该用户关闭了通知总开关,微信/MeoW/邮件都不会发` + ) return null } @@ -350,7 +353,10 @@ export async function createSongPlayedNotification(songId: number, ipAddress?: s } // 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService) try { - await sendWechatSubscribeToUser(targetUserId, 'SONG_PLAYED', { songTitle: song.title, message: userMessage }) + await sendWechatSubscribeToUser(targetUserId, 'SONG_PLAYED', { + songTitle: song.title, + message: userMessage + }) } catch (error) { console.error('发送微信订阅消息失败:', error) } @@ -554,7 +560,11 @@ export async function createSongRejectedNotification( } // 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService) try { - await sendWechatSubscribeToUser(userId, 'SONG_REJECTED', { songTitle: songInfo.title, reason: reason, message }) + await sendWechatSubscribeToUser(userId, 'SONG_REJECTED', { + songTitle: songInfo.title, + reason: reason, + message + }) } catch (error) { console.error('发送微信订阅消息失败:', error) } @@ -591,7 +601,9 @@ export async function createSubmissionNoteClearedNotification( ipAddress?: string ) { try { - const uniqueUserIds = [...new Set(userIds.filter((userId) => Number.isInteger(userId) && userId > 0))] + const uniqueUserIds = [ + ...new Set(userIds.filter((userId) => Number.isInteger(userId) && userId > 0)) + ] if (uniqueUserIds.length === 0) { return [] @@ -651,7 +663,10 @@ export async function createSystemNotification( } // 同步发送 微信订阅消息(只有绑了微信、且刚点过授权的用户收得到,见 wechatSubscribeService) try { - await sendWechatSubscribeToUser(userId, 'SYSTEM_NOTICE', { songTitle: title, message: content }) + await sendWechatSubscribeToUser(userId, 'SYSTEM_NOTICE', { + songTitle: title, + message: content + }) } catch (error) { console.error('发送微信订阅消息失败:', error) } diff --git a/server/services/wechatSubscribeService.ts b/server/services/wechatSubscribeService.ts index 064e0d6..55ad8c0 100644 --- a/server/services/wechatSubscribeService.ts +++ b/server/services/wechatSubscribeService.ts @@ -234,7 +234,12 @@ export async function sendWechatSubscribeToUser( ): Promise { try { const conf = getSubscribeTemplates()[kind] - if (!conf || !conf.id) return { ok: false, skipped: 'no-template' } + if (!conf || !conf.id) { + // 这四条跳过路径以前是静默 return,线上排查时日志里什么都没有,只能靠猜。 + // 现在每条都留一行,grep [WeChatSubscribe] 就能看出卡在哪一步。 + console.error(`[WeChatSubscribe] ${kind} → user ${userId} 跳过:没有配置模板 ID(no-template)`) + return { ok: false, skipped: 'no-template' } + } // 用户的通知总开关(与 MeoW / 邮件共用同一份设置) const settings = await db @@ -243,14 +248,24 @@ export async function sendWechatSubscribeToUser( .where(eq(notificationSettings.userId, userId)) .limit(1) if (settings[0] && settings[0].enabled === false) { + console.warn(`[WeChatSubscribe] ${kind} → user ${userId} 跳过:该用户的通知总开关是关的(disabled-by-user)`) return { ok: false, skipped: 'disabled-by-user' } } const openid = await getWechatOpenid(userId) - if (!openid) return { ok: false, skipped: 'no-wechat-openid' } + if (!openid) { + // 用户没有绑定微信(userIdentities 里没有 provider='wechat-mp' 的行)→ 永远发不出去 + console.warn(`[WeChatSubscribe] ${kind} → user ${userId} 跳过:该用户没有绑定微信 openid(no-wechat-openid)`) + return { ok: false, skipped: 'no-wechat-openid' } + } const token = await getMiniAccessToken() - if (!token) return { ok: false, skipped: 'no-access-token' } + if (!token) { + console.error( + `[WeChatSubscribe] ${kind} → user ${userId} 跳过:拿不到小程序 access_token(no-access-token,检查 WECHAT_MINI_APPID / WECHAT_MINI_SECRET)` + ) + return { ok: false, skipped: 'no-access-token' } + } const data = buildTemplateData(conf, Object.assign({ songTitle: '宝一外校园点歌系统' }, vars)) return await postSubscribe(token, openid, conf.id, data, userId, kind)