# 小程序订阅消息:配置与使用(怎么让用户收到提示) ## 一、先分清两条通道 | | 消息推送(服务器配置) | 订阅消息 | | --- | --- | --- | | 方向 | **用户 → 你**(用户发客服消息给你) | **你 → 用户**(你主动推提示给用户) | | 触发 | 用户在小程序点「客服」发消息 | 业务事件发生(审批待办、日程提醒、站内信…) | | 前置条件 | 无 | 用户必须在微信弹窗里点「允许」(一次性订阅:授权一次 = 1 次推送机会) | | 微信后台位置 | 开发管理 → 开发设置 → 消息推送 | 功能 → 订阅消息 | | 本工程实现 | `services/wechatmini/push.go` + `controllers/api_wechat_mini.go` | `services/wechatmini/subscribe.go` + `controllers/api_mini_subscribe.go` | **结论**:想让用户「收到提示」,靠的是**订阅消息**,不是消息推送。消息推送只是接收端(顺带做客服自动回复)。 --- ## 二、完整流程(4 步) ### 第 1 步:微信后台选一个订阅消息模板 小程序后台 → **功能 → 订阅消息 → 公共模板库 → 选用模板**(例如「审批进度通知」「待办提醒」)。 选完后记下两样东西: - **模板 ID**(一串字母数字) - **模板的字段名**(如 `thing1`、`phrase2`、`time3`、`character_string4`) > 模板选错会导致推送报 40066 / 47003,字段名对不上则报「模板字段不匹配」。 ### 第 2 步:平台端登记模板 平台后台 → **系统设置 → 小程序配置 → 编辑小程序 → 订阅消息模板 → 新增模板** | 字段 | 填什么 | | --- | --- | | 场景码 | `notice`(站内通知/通用提醒;同一个小程序下唯一) | | 场景名称 | 如「站内通知」 | | 模板 ID | 第 1 步复制的模板 ID | | 跳转页面 | 用户点击消息进入的小程序页面,如 `pages/index/index` | | 字段映射 | JSON:`{"thing1":"title","phrase2":"content","time3":"time"}` | **字段映射怎么读**:左边是微信模板的字段名,右边是平台这边的变量名。平台会提供三个变量: - `title` —— 标题(如「您有新的审批待办」) - `content` —— 内容 - `time` —— 推送时间(`2026-10-31 19:00`) 映射里写了哪个字段,就把对应变量填进去;模板有但没映射的字段会自动填 `-`。 ### 第 3 步:小程序端让用户授权 已接入的位置:**小程序「我的 → 消息通知」**,点一下会拉起微信的订阅授权弹窗。 ```js import { requestSubscribeNotice } from '@/utils/subscribe.js' await requestSubscribeNotice() ``` 建议在**用户确实可能需要收到提醒**的时机也调用一次(比如进入工作台、提交完审批之后)——因为微信一次性订阅,授权一次只有一次推送机会,用完了要再授权。 小程序端也可以直接调接口: - `GET /api/mini/subscribe/templates` 取模板列表 - `POST /api/mini/subscribe/authorize` 上报授权结果 - `POST /api/mini/subscribe/test` 给自己发一条测试消息 ### 第 4 步:业务侧触发 已接入的触发点(业务照常发,订阅消息自动跟上,**不影响主流程**,失败只记日志): | 业务 | 代码位置 | | --- | --- | | 站内信(平台端手动发通知) | `services/system_sitereminder.go` → `SendSiteReminder` | | OA 日程提醒(定时任务) | `services/reminder_scheduler.go` → `SiteMsgSender.Send` | | 审批待办(租户侧审批人生成待办) | `services/approval/engine.go` → `createTasks` | 自己接新场景时,直接调: ```go wechatmini.PushTenantNotice(租户用户ID, "标题", "内容") // 或指定场景码: wechatmini.PushSubscribeToTenantUser(租户用户ID, "notice", "", map[string]string{ "title": "标题", "content": "内容", "time": "2026-10-31 19:00", }) ``` --- ## 三、一次性订阅的规则(最容易踩坑) - 用户点一次「允许」= **1 次**推送机会,服务器记在 `yz_platform_wechat_mini_subscribe.remain` - 推送成功自动 `remain - 1`;用户拒绝或机会用尽(微信返回 43101)自动清零 - `remain = 0` 时不会调微信接口,直接跳过(不浪费配额) - 微信一次弹窗最多 3 个模板,前端已自动分批 - 「长期订阅」只有部分类目能用,��务小程序基本用不了,所以要设计好**再次引导授权**的时机 --- ## 四、常见错误码 | errcode | 含义 | 处理 | | --- | --- | --- | | 43101 | 用户未订阅 / 拒绝订阅 | 引导用户在小程序里重新点「消息通知」授权 | | 40066 | 模板 ID 无效 | 检查是不是填了「功能 → 订阅消息」里真正的模板 ID | | 47003 | 模板字段不匹配 | 检查字段映射与微信模板字段是否一致 | | 40003 | openid 无效 | 该用户不是用这个小程序登录的,或 openid 与 AppID 不匹配 | | 40001 | access_token 失效 | 工具会自动刷新,稍后重试 | 平台端「测试」按钮会直接返回中文排查建议。 --- ## 五、接口清单 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/mini/subscribe/templates` | 小程序端:可订阅模板列表(含剩余次数) | | POST | `/api/mini/subscribe/authorize` | 小程序端:上报授权结果 | | POST | `/api/mini/subscribe/test` | 小程序端:给自己发一条测试消息 | | GET | `/platform/wechatMini/templates` | 平台端:模板列表 | | POST | `/platform/wechatMini/template/save` | 平台端:保存模板 | | POST | `/platform/wechatMini/template/delete/:id` | 平台端:删除模板 | | POST | `/platform/wechatMini/template/test` | 平台端:给指定租户用户发测试消息 | ## 六、相关文件 | 文件 | 作用 | | --- | --- | | `go/services/wechatmini/subscribe.go` | 订阅消息 / 客服消息发送、模板 CRUD、授权记录、推送编排 | | `go/controllers/api_mini_subscribe.go` | 小程序端接口 | | `go/controllers/platform_wechat_mini.go` | 平台端模板管理接口 | | `go/models/wechat_mini.go` | `WechatMiniTemplate` / `WechatMiniSubscribe` 模型 | | `go/docs/sql/create_wechat_mini_template.sql` | 建表脚本 | | `uniapp/utils/subscribe.js` | 小程序端授权助手 | | `uniapp/api/subscribe.js` | 小程序端接口封装 | | `uniapp/pages/profile/profile.vue` | 「我的 → 消息通知」授权入口 | 建表脚本: ```bash mysql -h -P -u -p < go/docs/sql/create_wechat_mini_template.sql ```