日期:2026-08-13
工程:backend+mobile-h5(微信小程序);mobile-oa-h5/web-admin首期基本不动
相关:docs/superpowers/specs/2026-08-10-mobile-h5-wechat-login-design.md、OA 待办中心与pages/oa/webview深链
approval + pending)与抄送任务(cc)。mobile-h5 已具备待办/抄送列表与详情 web-view(instanceId + taskId)。wx_openid;微信授权登录已支持微信侧多手机号选择(getPhoneNumber 系统面板)。WechatMessageService 雏形,但配置与调用偏向小程序 appid,不能直接作为服务号推送实现。| 决策点 | 结论 |
|---|---|
| 推送通道 | 已认证服务号模板消息;小程序与服务号可关联 |
| 身份绑定 | 员工关注服务号 + 登录后显式绑定,写入服务号 openid / unionid |
| 推送范围 | OA 审批待办 + 抄送;各用一套模板文案区分 |
| 点击落地 | 直达 pages/oa/webview(instanceId + taskId);审批 mode=approve,抄送 mode=view |
| 会话恢复 | 已绑小程序 openid → 深链可静默换票;否则走现有登录页 + returnUrl 回跳 |
| 多手机号 | 系统侧一人一账号一手机号;微信侧多号由现有登录页微信授权处理,深链不重复造选号 UI |
| 登录页关注 | 次要链接「关注服务号,接收审批通知」→ 优先 wx.openOfficialAccountProfile;失败/低版本 → 二维码弹层 |
| 未绑定推送 | 跳过发送并记日志,不阻断 OA 提交/流转 |
OA 引擎 _create_tasks_for_node
├─ approval(pending) → 异步:审批模板 → 服务号 API
└─ cc → 异步:抄送模板 → 服务号 API
│
▼
查 sys_user.wx_mp_openid
│ 无则 skip
▼
template/send + miniprogram.pagepath
│
▼
用户点击 → 打开小程序 webview 详情
│
├─ 本地 JWT 有效 → 直接办/看
├─ 无 JWT + 小程序 openid 已绑定 → 静默 wechat-login(仅 loginCode) → 详情
└─ 否则 → 登录页(已有选手机号)→ returnUrl 回详情
| 标识 | 用途 |
|---|---|
小程序 wx_openid |
已有;静默恢复登录、业务鉴权侧微信身份 |
服务号 wx_mp_openid |
模板消息 touser |
wx_unionid |
开放平台下打通两端;绑定与排查用 |
前提:服务号与小程序绑定同一微信开放平台;服务号与小程序关联;跳转主页需同主体或开放平台主体关联(openOfficialAccountProfile)。
在 sys_user 增加(SQL 落 docs/sql/,同步 ORM):
| 列名 | 类型 | 说明 |
|---|---|---|
wx_mp_openid |
VARCHAR(64) NULL |
服务号下 openid |
wx_unionid |
VARCHAR(64) NULL |
开放平台 unionid |
wx_mp_bind_time |
DATETIME NULL |
服务号绑定时间(可选,便于审计) |
约束建议:
wx_mp_openid 非空唯一(应用层保证一微信号服务号身份不绑两人)。wx_unionid 可索引,非强制唯一(历史脏数据时以 openid 为准)。可选(实现阶段二选一,设计允许延后):
biz_wx_notify_log(user_id、task_id、template_type、status、errcode、create_time),便于客诉排查;首期也可用应用日志,表可后补。.env,禁止写入前端源码)| 变量 | 说明 |
|---|---|
WX_MP_APPID |
服务号 AppID |
WX_MP_SECRET |
服务号 AppSecret |
WX_MP_TEMPLATE_APPROVAL |
审批待办模板 ID |
WX_MP_TEMPLATE_CC |
抄送知会模板 ID |
WX_MP_GH_USERNAME |
服务号原始 ID(gh_…),供小程序跳转主页;也可仅配前端 |
已有 WXPAY_MINI_APPID / WXPAY_SECRET |
小程序;模板消息 miniprogram.appid 使用小程序 AppID |
新建(或重构)WechatMpMessageService(与现有小程序向 WechatMessageService 分离,避免 appid/token 混用):
access_token。POST /cgi-bin/message/template/send。touser = wx_mp_openid。miniprogram: { appid: 小程序AppID, pagepath: "pages/oa/webview/index?instanceId=…&taskId=…&mode=…" }pagepath 无前导 /。mode=approve;抄送:mode=view。url(H5 说明页);与 miniprogram 同传时优先小程序。模板字段(以微信后台最终审核字段名为准,实现时做映射配置):建议包含审批类型/标题、申请人、时间、摘要或节点名;审批模板标题语义为「待您审批」,抄送为「抄送知会」。
POST /api/mini/auth/mp-bind(需登录):小程序 web-view 中间页走服务号网页授权 snsapi_base,将 code 交给后端,换取 wx_mp_openid(及 unionid),写入当前用户。GET /api/mini/auth/mp-bind-status:是否已绑定(供个人中心展示)。绑定冲突:该 wx_mp_openid 已绑其他用户 → 返回明确错误。
调整 POST /api/mini/auth/wechat-login:
loginCode 换得的小程序 openid 已绑定唯一启用用户,且未传 phoneCode → 允许直接发 JWT(深链会话恢复)。phoneCode:须校验手机号与账号 phone_no 一致(保持安全)。在 oa_engine._create_tasks_for_node(或统一的任务创建出口)于任务入库后:
task_type == "approval" 且 status == "pending" → 审批模板。task_type == "cc" → 抄送模板。wx_mp_openid;空则 debug/info 日志后返回。同一用户同一节点多人并签/或签:每人一条任务则每人一条通知(与任务一一对应)。
mobile-h5)设计入口已迁移(2026-08-14): 登录页关注与工作台顶栏绑定入口已废弃;统一见
docs/superpowers/specs/2026-08-14-wechat-notify-menu-entry-design.md与菜单「开启微信通知」。
wx.openOfficialAccountProfile({ username: gh_… })(基础库 ≥ 3.7.10)。fail 或基础库不足 → 弹出服务号二维码(长按识别);二维码资源可静态配置或远端 URL。入口已迁移(2026-08-14): 登录页关注与工作台顶栏绑定入口已废弃;统一见
docs/superpowers/specs/2026-08-14-wechat-notify-menu-entry-design.md与菜单「开启微信通知」。
pagepath 打开 pages/oa/webview/index。wx.login + wechat-login(仅 loginCode);成功则继续。forceRelogin 并写入 returnUrl(完整 path + query);登录成功后 reLaunch/redirectTo 回该页。| 情况 | 行为 |
|---|---|
| 未关注 / 取消关注 | 发送失败或未绑定;OA 正常;引导重新关注并绑定 |
| 未绑定 mp_openid | 不发送;个人中心可提示 |
| 模板字段不符 | 发送失败日志;需运营修正模板 |
| 小程序未发布 / 未关联 | 点击无法跳小程序;发布前勿对生产用户推送 |
| 任务已办结仍点开 | 详情页只读或提示已处理(沿用现有详情权限逻辑) |
| 登录选错手机号 | 现有登录错误提示;换号或账号密码 |
| 阶段 | 内容 |
|---|---|
| P0 | 字段与配置、服务号发送服务、OA 钩子、两套模板联调 |
| P1 | 绑定 API + 个人中心绑定、登录页关注入口 |
| P2 | 深链静默登录 + returnUrl、发送日志(可选表) |
P0 在绑定未完成前可用测试号手工写入 wx_mp_openid 验证推送与跳转。
| 项 | 约定 |
|---|---|
| 绑定方式 | 服务号网页授权 snsapi_base:登录后经小程序 web-view 中间页拿 code → POST /mini/auth/mp-bind 换票写入。不做带参关注二维码主路径。 |
| 前端配置 | mobile-h5 配置:MP_GH_USERNAME(原始 ID)、MP_QRCODE_URL(兜底二维码图)。密钥仅后端 .env。 |
| 模板字段 | 微信后台申请通过后,将字段名写入后端映射配置(如 env 或常量);联调前用占位字段名,上线前替换为正式值。 |
| 二维码资源 | 由运营提供服务号关注二维码图片,放入小程序 static/ 或 CDN,并配置 MP_QRCODE_URL。 |
运营依赖(非代码阻塞):服务号模板审核通过、小程序与服务号关联并已发布、开放平台同主体/主体关联。
.env: WX_MP_APPID / WX_MP_SECRET / WX_MP_TEMPLATE_APPROVAL / WX_MP_TEMPLATE_CC / WX_MP_TPL_FIELD_*mobile-oa-h5 VITE_WX_MP_APPIDmobile-h5/utils/config.js MP_GH_USERNAME + 真实 static/mp-qrcode.pngdocs/sql/alter-sys-user-wx-mp-openid.sql(若未执行)