优化小程序部分

This commit is contained in:
hero920103 committed 2026-10-31 19:17:37 +08:00
1 parent 727319a6eb
commit d4e89788c5
46 files changed
+4906 -63

No files matched your search

@@ -0,0 +1,142 @@
# 小程序订阅消息:配置与使用(怎么让用户收到提示)
## 一、先分清两条通道
| | 消息推送(服务器配置) | 订阅消息 |
| --- | --- | --- |
| 方向 | **用户 → 你**(用户发客服消息给你) | **你 → 用户**(你主动推提示给用户) |
| 触发 | 用户在小程序点「客服」发消息 | 业务事件发生(审批待办、日程提醒、站内信…) |
| 前置条件 | 无 | 用户必须在微信弹窗里点「允许」(一次性订阅:授权一次 = 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 <host> -P <port> -u <user> -p <db> < go/docs/sql/create_wechat_mini_template.sql
```