Files
BYW-VoiceHub/server/api/admin/wechat/test-subscribe.post.ts
T
Henry_Du cccaf36990 feat(brand): 站点品牌名统一为「宝一外校园点歌系统」
站长要求全站一致(小程序端已单独提交)。本次只改**用户可见文案与默认值**:

- 服务端默认值/兜底:system-settings-defaults、admin/system-settings(GET/POST)、
  site-config.get、utils/siteUtils —— 原来是 'VoiceHub' / '校园广播站点歌系统'
- 用户可见通知文案:MeoW 绑定验证码与标题、MeoW 测试通知、微信订阅测试通知
- 2FA 应用名(authenticator.keyuri)、WebAuthn rpName(出现在系统密钥弹窗里)
- 网页版界面:首页副标题、后台侧栏品牌名、登录/注册/找回/改密标题与文案、
  年度回顾(IntroSlide / ShareCard / 页面标题)、用户教程、通知发送预览、
  API 密钥与数据库导入说明、酷狗 sidecar 说明、打印页脚与歌单卡片页脚、Logo alt

**刻意不动**:localStorage/sessionStorage 的 `voicehub_*` 键、`voicehub:` 前缀的
STORAGE_KEY 与缓存/Redis 前缀、`window.voiceHubPlayer` 之类代码标识、MeoW 的
User-Agent、以及上游项目链接 `github.com/laoshuikaixue/VoiceHub`(那是对原项目的署名)。

注意:站点名**数据**(systemSettings.siteTitle)仍是你后台里设置的「宝一外校园点歌」,
代码只保证默认值与文案一致;要让全站显示完整名称,请在后台「站点配置 → 站点标题」
改成「宝一外校园点歌系统」。
2026-09-30 20:24:55 +08:00

93 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
buildTemplateData,
getMiniAccessToken,
getSubscribeTemplates,
getWechatOpenid,
sendRawSubscribe
} from '~~/server/services/wechatSubscribeService'
/**
* 微信订阅消息的**自测接口**(仅超级管理员)—— 站长部署完用它「试一下」。
*
* 一次调用能看出四件事:
* 1. access_token 能不能拿到(appid / secret 是否有效)
* 2. 目标用户有没有绑微信(有没有 openid;纯密码用户必然是 null)
* 3. 模板字段名 / 长度对不对(微信会回 47003 / 43101 之类的错误码)
* 4. 微信返回的原文
*
* body(都可省):
* { userId?: number, kind?: string, openid?: string, templateId?: string, data?: object }
* · 默认给自己发、用配置里的第一个模板
* · 想直接指定 openid / 模板 ID / data 也可以(用于排查)
*/
export default defineEventHandler(async (event) => {
const user = event.context.user
if (!user || user.role !== 'SUPER_ADMIN') {
throw createError({ statusCode: 403, message: '只有超级管理员可以测试微信订阅消息' })
}
const body = await readBody(event)
const templates = getSubscribeTemplates()
const kinds = Object.keys(templates)
const kind = body?.kind || kinds[0] || ''
const conf = kind ? templates[kind] : null
const templateId = body?.templateId || conf?.id || ''
const targetUserId = Number(body?.userId) || Number(user.id)
const token = await getMiniAccessToken()
const openid = body?.openid || (await getWechatOpenid(targetUserId))
if (!templateId) {
return {
ok: false,
reason: 'no-template',
hint: '服务器环境变量 WECHAT_MINI_SUBSCRIBE_TEMPLATES 没配置模板 ID(见 wechatSubscribeService.ts 头部注释)',
configuredKinds: kinds,
tokenOk: !!token,
openid: openid ? openid.slice(0, 6) + '****' : null
}
}
if (!openid) {
return {
ok: false,
reason: 'no-wechat-openid',
hint: '该用户没有绑定微信(userIdentities 里没有 provider=wechat-mp 的记录),微信发不到他那里',
kind: kind,
templateId: templateId,
tokenOk: !!token,
targetUserId: targetUserId
}
}
const data =
body?.data && typeof body.data === 'object'
? body.data
: buildTemplateData(conf || { id: templateId }, {
songTitle: '测试歌曲',
message: '这是一条来自宝一外校园点歌系统的测试通知'
})
const result = await sendRawSubscribe(openid, templateId, data)
return {
ok: result.ok,
errcode: result.errcode,
errmsg: result.errmsg,
hint:
result.errcode === 0
? '发送成功,去微信里看「服务通知」'
: result.errcode === 43101
? '用户没有可用授权(一次性订阅:需要用户在小程序里点过「开启微信通知」才行)'
: '看 errmsg:47003 = 模板字段名/长度不对;40003 = openid 不对;40001 = token 失效',
configuredKinds: kinds,
kind: kind,
templateId: templateId,
targetUserId: targetUserId,
openid: openid.slice(0, 6) + '****',
tokenOk: !!token,
data: data,
raw: result.raw
}
})