import { inspectWechatSubscribe, sendWechatSubscribe } from '~~/server/services/wechatSubscribeService' /** * 微信订阅消息的**一键体检**(仅超级管理员,GET,浏览器里直接打开就能看)。 * * 为什么要有它:线上「通知没发出去」以前只能靠猜 —— 发送前的四条跳过路径一句日志 * 都不写。现在体检接口把判断要用的事实一次全返回,并且每一项都配一句人话结论。 * * 用法(在已登录后台的浏览器里打开): * /api/admin/wechat/diagnose → 只体检(**不发消息、不消耗额度**) * /api/admin/wechat/diagnose?send=1 → 顺手给这个用户每个模板真发一条(消耗额度,返回微信原始 errcode) * /api/admin/wechat/diagnose?userId=5 → 体检别的用户 * /api/admin/wechat/diagnose?send=1&force=1 → 忽略本地记账的额度预检,强制发(仍可能被微信 43101 拒) * * 读返回值:先看 `user.verdict` 与 `templates[].verdict`(人话),再看 `actions[]` * (照着做就能修),最后需要原始错误码时看 `?send=1` 的 `sendAttempts[].errcode`。 */ export default defineEventHandler(async (event) => { const user = event.context.user if (!user || user.role !== 'SUPER_ADMIN') { throw createError({ statusCode: 403, message: '只有超级管理员可以使用微信订阅体检' }) } const query = getQuery(event) const doSend = query.send === '1' || query.send === 'true' const force = query.force === '1' || query.force === 'true' const forceRemote = query.remote === '1' || query.remote === 'true' const requestedId = query.userId != null ? Number(query.userId) : NaN const targetUserId = Number.isFinite(requestedId) && requestedId > 0 ? requestedId : Number(user.id) // 只读体检:不发消息、不消耗额度。所有导出函数都不抛异常,失败信息都在返回值里 const inspection = await inspectWechatSubscribe(targetUserId, { username: targetUserId === Number(user.id) ? user.username : null, forceRemote }) const result: Record = { ...inspection, requestedBy: { userId: Number(user.id), username: user.username }, note: doSend ? '已执行真实发送:sendAttempts 里的 errcode 就是微信的原始回复(0=成功 / 43101=没有可用授权 / 47003=字段名或值不合规 / 40003=openid 不对 / 40001=token 失效)' : '本次只体检、没有发消息,也没有消耗任何授权额度;要真发一次加 ?send=1' } if (doSend) { const attempts: Array> = [] const kinds = Array.from(new Set(inspection.templates.map((t) => t.kind))) for (const kind of kinds) { const outcome = await sendWechatSubscribe( targetUserId, kind, { songTitle: '测试歌曲《晴天》', playDate: '2026-02-14', playTime: '2026-02-14 12:30', sequence: '1', status: '已排期', reason: '测试驳回原因', message: '这是一条测试通知' }, { force, forceRemote, source: 'diagnose' } ) attempts.push({ kind, ok: outcome.ok, stage: outcome.stage, errcode: outcome.errcode ?? null, errmsg: outcome.errmsg ?? null, detail: outcome.detail }) } result.sendAttempts = attempts } return result })