报价、合同、备用金、报销、运费结算、车辆充值六类审批。待办只通知当前可审批人;最终通过/驳回通知申请人。CRM和运费申请人按本轮提交人,BX/充值按单据 applicant_id(兼容代申请)。运费业务提交人的审批结果及发放完成通知已恢复,已取消的历史通知不自动补发。
审批通过不等于财务支付。充值进入财务发放节点时通知“通过”,不再用审批模板催办财务;从一开始直接发放、没有实际审批记录的单据不虚构“通过”消息。
现已新增必选3“发放/支付完成”和必选6“证件到期定期汇总”,均复用上述绑定和通知队列,不新增队列表。必选3在真实发放登记成功后通知申请人(运费为业务提交人),表示门户已登记完成,不代表核验了银行到账。报销纯冲抵不发送支付完成;支付并冲抵中实际支付金额大于零才发送。充值审批发放、手工记录关联申请都覆盖,无关联申请的手工记录不推测收件人。
必选3模板 rnPOIVknPqfgwVzKbchj6pCMCWpoDe3h3dkrFbUEsD4:thing3 为“备用金发放/报销支付/运费发放/充值发放”,thing4 为完整业务单号,thing5 为“发放完成/支付完成”,time12 为真实处理时间,无金额字段。单号为空或超过20字符记为 failed,不截断发送。BX重复完成操作保留首次处理时间;撤销充值发放或更换关联申请时取消尚未发出的旧通知。
必选6模板 aYzLZ_EqI8hq7RXrlf73BTAfNvzgJHeg_xWKar01Md0:thing5 示例“3项即将到期,2项已到期”,time6 为实际发送的北京时间,thing3 固定为“系统默认发出”。当天到期计入“已到期”,沿用提醒列表统计口径。
docs/sql/20261027_wechat_cert_notice_role.sql。脚本兼容 MySQL 5.7,使用临时存储过程,需要 CREATE ROUTINE 权限;为已有租户幂等创建“证件到期通知接收人”角色,并关联证件提醒 Web 菜单及祖先目录。WECHAT_OA_CERT_NOTICE_ROLE_NAME 一致。新租户创建后需再次执行角色初始化SQL或在角色管理中手动建立同名角色、菜单和数据范围。新增模板不是公众号新建模板接口自动申请,须确保这两个模板已添加到当前服务号。
WECHAT_OA_ENABLED=false,部署后端及前端。docs/sql/20261027_wechat_approval_notices.sql 建立三张表。SQL兼容MySQL 5.7;既有审批数据不回填。https://门户域名/api/public/wechat-notices/oauth/callback。这是网页授权回调,不是公众号消息接收服务器 URL。WECHAT_OA_ENABLED=true,重启后端。既有自定义加密排除列表可追加回调精确路径;回调位于 public 路径,无需取消其他业务加密或鉴权。WECHAT_OA_ENABLED=false
WECHAT_OA_APPID=wxf63dfb83af901d43
WECHAT_OA_SECRET=
WECHAT_OA_PUBLIC_BASE_URL=https://门户域名
WECHAT_OA_MINI_APPID=
WECHAT_OA_TEMPLATE_PENDING=ukQRYoczEXH1fZe9TdL8uX6LmuJJTlPidboxqtq_7N0
WECHAT_OA_TEMPLATE_RESULT=vA_z15BdP-8LltRmS__1MmUcNKQBy6b6rvAXKEYzoLY
WECHAT_OA_TEMPLATE_COMPLETION=rnPOIVknPqfgwVzKbchj6pCMCWpoDe3h3dkrFbUEsD4
WECHAT_OA_TEMPLATE_CERT_REMINDER=aYzLZ_EqI8hq7RXrlf73BTAfNvzgJHeg_xWKar01Md0
WECHAT_OA_CERT_REMINDER_ENABLED=true
WECHAT_OA_CERT_NOTICE_ROLE_NAME=证件到期通知接收人
WECHAT_OA_CERT_REMINDER_HOUR=10
WECHAT_OA_CERT_REMINDER_MINUTE=0
WECHAT_OA_MINI_APPID 必须是已关联的门户小程序,不能填服务号AppID。未配置时消息使用门户Web回退入口。小程序与服务号OpenID分别保存,不能互换。
证件提醒开关同时受 WECHAT_OA_ENABLED 总开关控制;修改小时/分钟需要重启调度器。证件扫描与微信摘要使用同一调度任务,扫描仍每日执行,微信入队和发送复核均限制在周一、周三。部署时如私有环境仍显式配置旧值8,须改为10并重启后端;本次未修改私有环境。通知关闭时仍执行原证件扫描;已安装队列表时,充值撤销操作仍会取消旧完成通知,避免重新启用后复活。
小程序工作台顶部栏右下角提供金色强调的“关注服务号”按钮,位于欢迎语和退出区域下方,点击直接进入小程序内的关注与绑定页面 pages/common/wechat-official-account,顶部入口不调用微信原生公众号跳转,不弹“即将打开公众号”。按用户要求按钮与“退出登录”相同视觉高度,使用白色文字、无边框;顶部栏预留底部空间,不覆盖标题和退出操作。第1步只保留“打开服务号并关注”按钮,已移除关注卡片、搜索说明和复制名称入口;打开失败提示更新微信后重试或联系管理员。打开主页不表示关注成功。
登录进入工作台后,会通过现有本人绑定接口查询真实关注状态:已绑定且已关注不弹窗;已绑定未关注弹出“关注服务号”;未绑定无法确认关注情况,使用“关注并绑定,如已关注请完成绑定”的中性说明。通知未启用或查询失败时不误判、不阻断登录。弹窗可选“稍后再说”,当前登录在进程内最多提示一次,返回工作台或切换Tab不重复;重新登录或冷启动恢复登录可再次检查。离开工作台、开始退出或切换账号后,旧请求与旧确认回调不会再触发弹窗/跳转。
页面内“打开服务号并关注”按钮使用 微信官方 wx.openOfficialAccountProfile,username为服务号原始ID gh_53e43e6f5c92(不是AppID)。基础库3.7.10起支持,目标公众号须与小程序同主体或关联主体;只能在点击行为同步调用,不在onShow或网络回调中自动调用。登录弹窗确认进入引导页,由用户点击打开。微信可能先显示“即将打开公众号”的原生确认,用户点击允许后进入公众号;本项目未额外添加该确认,接口不提供关闭它的参数。上线须真机核验主页主体及实际关注效果。
关注不等于绑定。 小程序关注页提供“一键绑定当前账号”:用户主动点击后创建五分钟有效的移动绑定会话,在专用web-view完成微信网页授权,回调页尝试自动返回,原登录小程序查询本次会话并自动提交绑定,无需记验证码或再次确认。回调仍仅保存候选身份,不直接绑定;关注、重复绑定冲突、租户与会话归属仍由原接口校验。显示“已开通服务号通知”以后才能接收通知。电脑门户“头像菜单 → 微信通知”的扫码绑定仍保留;仅登录小程序不会自动关联服务号OpenID。发送器还会检查对应账号、业务状态、接收角色及数据权限。后端通知开关、迁移与服务号配置步骤仍需完成。
关注入口及登录提醒本地验证:48项交互、模板、会话保护、原生主页跳转、移动自动绑定及网页返回桥接测试通过;后端微信相关215项测试通过;使用本机HBuilderX内置uni-app编译器完成微信小程序构建,产物位于临时目录,已核对原生主页接口、移动绑定入口与新页面路由。尚未进行真机关注验证、上传或发布。编译依赖通过临时Vite配置指向HBuilderX自带pinia,未修改项目依赖。
pages/common/wechat-binding-authorize 仅从当前关注页通过EventChannel取得服务端签发的门户中转地址(/api/public/wechat-notices/oauth/launch),等待onReady再挂载。web-view 不能直接打开 open.weixin.qq.com,中转页位于已配置的业务域名,再跳到微信授权。登录JWT、服务号OpenID和AppSecret不放进路由参数或本地存储;不接受任意URL query作为web-view来源。{mode: "mobile"},服务端记录模式;电脑无请求体时默认 desktop,仍保留验证码人工确认。移动回调页 backend/app/templates/wechat-binding-mobile.html 使用固定官方 JS SDK 地址 https://res.wx.qq.com/open/js/jweixin-1.6.0.js 和 nonce CSP,尝试 wx.miniProgram.navigateBack 返回上一页,不跳转首页以免丢失发起会话。部署时须包含该模板文件。SDK 或桥接失败时显示返回按钮、左上角返回提示。/#/pl/document-reminder-module/document-reminder;按现有登录和数据权限查看。每15秒处理最多20条。审批与outbox在同一数据库事务,失败回滚不留下通知。发送前复核当前审批、接收人、轮次;撤回/作废/转交取消尚未发送的旧任务,已送达消息不可撤回。
sys_wechat_notice.status:pending待发送、sending已认领、sent微信接口已接受、cancelled业务已失效、skipped未绑定/未关注、failed明确失败、unknown发送结果不确定。sent不表示用户已读。
系统繁忙/频率限制最多尝试5次;超时/网络中断/进程中断可能已经发送,记unknown,不自动重发。先核对微信侧记录,不能直接批量重置unknown造成重复推送。未绑定的历史通知不在绑定后自动补发。
排查时按租户筛选,避免导出payload和openid到公开日志:
SELECT id, business_type, business_id, kind, recipient_id,
status, attempts, last_error, create_time, sent_at
FROM sys_wechat_notice
WHERE tenant_no = '待检查租户' AND del_flag = 0
ORDER BY create_time DESC
LIMIT 100;
使用已关注并绑定的申请人、两名审批人分别验证:提交仅首节点收到;中间通过只通知下一审批人;最终结果为通过或打回,运费提交人收到审批结果及汇款凭证登记完成通知;代申请给实际申请人;撤回/重提不发送旧轮次;或签一人通过取消其他未发任务;未关注/解绑不向小程序OpenID发送。
新增验收:备用金、报销、运费、充值四业务真实发放/支付后收到完成模板,纯冲抵不发;重复操作不重复发送;充值撤销/换绑后未发旧通知失效;长单号只记失败。证件接收人角色开启/移除、停用、不同租户与不同数据范围分别验证;周一/周三10点扫描发送,其他日期及10点前不发送,同日重复扫描不重复发送;续期/删除后更新数量,无预警不发送;跨日滞留取消;核对申请人字面值“系统默认发出”。
本地自动化使用SQLite及假的微信传输,不代替真实账号权限、模板内容、域名、小程序关联、MySQL多实例并发测试。生产发布及真实发送需单独执行上述验收。
复验命令(在对应项目目录执行):
# backend/
venv/bin/python -m pytest tests/test_wechat_approval_notices.py tests/test_wechat_notice_binding.py tests/test_wechat_oa_client.py tests/test_wechat_notice_crm_sources.py tests/test_wechat_notice_bx_sources.py -q
# web-admin/
node --test scripts/wechat-notice-binding.test.cjs
微信通知全部测试198项通过,合并证件扫描及数据权限测试为211项通过;扩展业务回归493项通过、2项既有充值列表模拟数据失败(缺少油卡逻辑所需recharge_type)。规格与代码质量复核通过。Python编译检查通过,本次没有前端代码变更。字段一致性脚本仍不存在;MySQL5.7迁移、真实并发和微信模板接受情况仍需部署验收。
# backend/;隔离配置,不加载业务环境,不调用真实微信
ENV_FILE=/dev/null venv/bin/python -m pytest tests/test_wechat*.py tests/test_pl_scan_cert_expiry.py tests/test_data_scope.py -q
登录关注提醒追加验证(2026-10-27):关注入口与提醒共22项交互/模板/工作台生命周期测试通过,微信小程序构建成功。产物已核对右下金色定位、原生弹窗及show/hide处理。未进行真实关注查询联调、真机交互验收或发布。