简介:这套企业办公审批小程序面向大中型公司、企业及机关部门的日常审批管理,覆盖请假、报销、外出、合同、采购、入职等常见流程,并划分管理员、员工、审批人员三种角色,审批结果通过微信消息提醒及时触达申请者,适合需要规范化、移动化审批的团队快速部署使用。资源共包含489个文件,压缩包大小约2.12MB,以js、wxss、wxml、json等微信小程序核心文件为主,辅以png、jpg等图片资源以及docx使用手册和md说明文档,代码结构清晰,便于二次开发与流程调整。已有42人学习浏览,适合具备一定微信小程序基础的开发者或企业信息化负责人参考。通过本包可获取完整的前后端交互逻辑、审批状态机设计、消息通知机制及页面布局样例,同时附带的安装使用手册能帮助快速上手部署,节省从零搭建审批系统的时间。 在企业里推行一套好用的审批系统,这事儿本身就挺磨人的。部门多的公司要请假、报销、外出、合同、采购,各部门流程还不一样,用纸质单子往楼上楼下跑吧,效率低还老丢单;直接上全套OA吧,成本高、实施周期长,IT部门还得伺候一堆硬件和账号。身边越来越多同行在尝试用微信小程序来承担这部分工作,理由很简单:员工不用额外装App,在微信里就能点开填单、发起流程,审批人收到通知点一下就能处理。
我最近就帮一家合作公司落地了一套企业办公审批小程序,覆盖请假审批、报销审批、外出审批、合同审批、采购审批这些典型场景。这篇文章把我的完整思路、技术选型、实操过程和踩坑记录都整理了出来,给真正准备自己上手做一套同类小程序的团队做个参考。适合的产品和技术背景是:公司已经有自己的后端服务,或者至少有一位熟悉服务端开发和微信小程序前后端联调的开发者。如果你现在正纠结“审批流程怎么设计”“消息怎么推给用户”“上线要注意什么”这类问题,这篇文章应该能帮你省掉不少试错成本。
1. 整体设计与思路拆解:为什么是“表单+审批流”的组合拳
1.1 企业审批场景的共性痛点
先把场景捋清楚。办公审批这件事,表面上是“人填表、领导批”,实际上牵扯到三件事:一是表单数据结构差异巨大,请假的字段是起止日期、天数、事由,报销单是费用明细、发票凭证、金额汇总,采购申请又变成供应商、品名、数量、预算来源,强行做成一套统一表单模板,业务部门用起来必定别扭;二是审批路径复杂多变,不同金额、不同部门、不同事项都可能路由到不同审批人,还可能涉及反签、加签、推送抄送人;三是实时性要求高,报销拖一礼拜领导没批,财务那儿追着问,员工嘴上不说心里全是火,行政和IT夹在中间最难受。
微信小程序恰好能同时解决这三件事。不用装软件,微信自带入口;表单可以通过代码配置成动态模板,后端返回字段定义,前端动态渲染;审批流引擎用状态机实现,每个审批节点都是一个可配置的处理器。这套架构不需要引入非常重的BPM引擎,轻量但够用,这也是我认为对绝大多数中小企业最合适的方案。
1.2 小程序的天然优势与边界
选择小程序还有一个现实原因:企业微信和微信小程序的打通机制已经很成熟了。员工即使没有加入企业微信组织架构,只要在小程序端通过微信登录并绑定企业内网账号,就能走审批流;如果企业已经在用企业微信,那更顺畅,组织架构和消息通知都可以直接复用。
但也要认清边界。小程序不能完全替代专业的OA产品,它更适合做“移动端审批入口”,也就是高频、轻量、必须在手机上快速处理的那部分环节。比如合同审批涉及法务条款审核,可能还需要在电脑上做对照批注,这类深度工作还是交给专业系统。我的做法是把小程序设计成审批动作中枢,而不是全套业务平台,这样定位清晰,做起来也不至于失控。
1.3 审批流引擎的选型策略
针对请假、报销、外出、合同、采购这五类审批,我设计了一套兼顾灵活度和实现成本的状态机引擎:
- 基础链式审批:提交人 → 直接上级 → 部门负责人 → 归档
- 条件分支审批:金额小于5000元走直线,5000元以上额外加一道财务复核或法务复核
- 加签与转审:审批人可添加会签人,或者将审批单转交给他人代办理
- 撤回与驳回:第一节点未处理时可撤回,被驳回后允许修改重提
这个引擎的核心思想是:所有审批单据共用一套节点模型,节点之间的流转规则由JSON配置驱动,不同表单类型的区别只体现在“表单字段”和“节点规则”的配置上。代码写起来非常简单,但业务扩展性很好,后续即使增加新的审批类型也不用重构引擎,加配置就够了。
2. 核心功能模块与技术细节解析
2.1 登录态与身份绑定机制
审批系统最怕身份错乱。微信小程序里wx.login获取的是临时code,后端拿code换openid,这是每个人在微信体系内的唯一身份标识。但openid不能直接对应到公司内部的工号体系,所以小程序里必须设计一层绑定关系。
我这边采用的流程是:用户首次打开小程序,前端调wx.login拿到code,传给后端;后端用code请求微信接口获取openid,然后查询这个openid是否已绑定内部用户;如果没绑定,就返回“需要绑定”的状态码,前端跳转到输入工号和密码的登录页;绑定成功后,服务端签发一个自定义登录态token,后续所有接口都带着这个token,后端通过token映射到用户身份和权限角色。
这里有个很重要的细节:不要在前端存储openid,更不要把openid当作用户标识传给后端。openid应该被后端完全托管,前端只和token打交道。这样即使小程序前端被反编译,攻击者也拿不到有效的身份凭证。微信开放了wx.getUserProfile接口能拿用户微信昵称和头像,但注意,这是用户主动点击按钮触发的授权能力,不能提前调用,如果业务不依赖真实头像和昵称,建议不要强制用户授权,避免用户因为授权弹窗而流失。
2.2 表单动态渲染与权限控制
请假、报销、外出、合同、采购,这五类表单的样式和字段差异确实很大。如果前端每个表单单独写死一个页面,那每增加一种新表单都要发布一次新版本,非常不优雅。我采用的是后端动态下发表单结构:
{ "formType": "leave", "fields": [ { "key": "startTime", "label": "开始时间", "type": "datetime", "required": true }, { "key": "endTime", "label": "结束时间", "type": "datetime", "required": true }, { "key": "leaveType", "label": "请假类型", "type": "select", "options": ["年假","事假","病假"], "required": true }, { "key": "reason", "label": "请假事由", "type": "textarea", "required": true } ] }前端拿到这个JSON结构,动态渲染输入控件,收集用户填写的值,回传给后端。这样新增或修改表单字段,只需要后端改配置,小程序端完全不用动。这个方案我实际用下来确实能节省大量联调时间。
权限控制上要分两层:菜单权限和操作权限。菜单权限决定用户能看到哪些审批入口(比如普通员工没有“合同审批”入口,但财务能看到“报销审批”的财务复核按钮);操作权限决定用户在审批详情页里能点“通过”“驳回”还是只能看不能动。后端返回用户角色集合,前端根据角色控制按钮显隐,但真正的鉴权一定要在后端做一遍,否则前端绕过界面直接调接口,权限就形同虚设。
2.3 审批状态机与消息触达方案
状态机是整个审批模块的命门。我定义的状态流转包括:待提交、审批中、已通过、已驳回、已撤回、待我审批、已转审。每个状态都对应明确的动作和触发条件,状态变更时必须写入操作日志,方便后续审计。
这里给出一个审批处理接口的示意逻辑:
// 审批动作:通过 / 驳回 / 转审 async function handleApproveAction(action, data) { const { orderId, nodeId, comment, targetUserId } = data; const order = await getOrderById(orderId); const currentNode = order.nodes[nodeId]; if (!currentNode) { throw new Error('审批节点不存在'); } switch (action) { case 'approve': currentNode.status = 'approved'; currentNode.comment = comment; if (hasNextNode(order, nodeId)) { order.currentNode = nextNodeId; order.status = 'approving'; await sendSubscribeMessage(nextApprover, order); } else { order.status = 'done'; } break; case 'reject': order.status = 'rejected'; order.currentNode = null; await sendRejectMessage(order.submitter, order); break; case 'transfer': currentNode.status = 'transferred'; order.currentNode = targetUserId; await sendSubscribeMessage(targetUserId, order); break; } await saveOrder(order); await writeAuditLog(order, action, comment); return order; }消息触达是审批系统被问得最多的问题。微信官方接口从模板消息升级到了订阅消息,订阅消息的关键限制是:一次性订阅消息必须由用户主动触发订阅动作,且每次授权只能推送一次;长期订阅消息需要申请特定类目权限,不是所有企业都能开通。所以审批系统里的正确姿势是,用户在提交审批单时,页面弹出订阅授权请求(同时勾选“审批结果通知”和“新审批待办通知”两条消息),后端获得授权后,在对应事件发生时调用发送接口。
如果企业已经接入企业微信,还可以走企业微信应用消息推送接口,到达率和可发送次数都比微信订阅消息宽松得多。混合方案是性价比最高的:订阅消息负责给微信端用户推送待办和结果,企业微信消息给内部员工提醒。
2.4 附件上传与数据安全
合同审批和采购审批经常要上传PDF、照片、扫描件。小程序端的上传能力有两种:直接传到自己的服务器,或先用wx.uploadFile传到微信临时素材区再转存到云存储。我的建议是直接传到自己的对象存储(比如阿里云OSS、腾讯云COS),不要绕一道微信临时素材,因为微信临时素材有效期只有3天,清理逻辑容易出漏洞。
上传前必须做两件事:一是校验文件类型和大小,禁止上传可执行文件,前端做校验只是提升体验,后端必须重新校验Content-Type和文件头;二是生成新的文件名,不要用用户原始文件名直接存储,避免路径穿越攻击。合同这类敏感文件建议在上传后做访问鉴权,下载URL带签名参数,过期自动失效。
3. 实操过程:从环境配置到核心流程实现
3.1 开发环境与工具链准备
做微信小程序开发,必备工具是微信开发者工具,它提供模拟器、调试器、真机预览等完整能力。我的项目结构大致是:
pages/:前端页面目录,包括提交表单、待办列表、审批详情、消息页等components/:动态表单渲染组件、审批节点时间轴组件utils/:请求库封装、日期格式化、鉴权拦截器config/:环境配置(开发、测试、生产环境)server/:后端Node.js服务,提供审批相关API
首次打开项目,开发者工具会让你填AppID。没注册的话可以先用测试号,但测试号不支持一些高级能力(比如订阅消息),建议第一时间把小程序账号注册好,在微信公众平台后台拿到正式AppID。后端服务我用的Node.js + Express,配合MySQL存储业务数据,Redis缓存用户token。
3.2 数据库核心表设计
审批系统的主表我设计成四张:
- 审批单主表(approval_order):记录单据编号、提交人、审批类型、当前节点、表单数据JSON、状态、创建时间、更新时间
- 审批节点表(approval_node):记录每个审批单从提交到结束的所有节点,包括节点序号、审批人ID、节点状态、审批意见、操作时间
- 附件表(attachment):记录上传文件的对象存储地址、文件名、大小、所属单据ID、上传人
- 审批日志表(approval_log):记录所有状态变更的审计日志,谁在什么时间做了什么事
主表里表单数据直接存JSON字段是刻意为之。因为五类表单字段结构差异大,强行拆成几百个字段列在SQL表里,查询和维护都是灾难。JSON字段配合MySQL的JSON类型,既保留了查询能力,又降低了表设计复杂度。要按某些固定维度统计(比如按日期查请假天数),可以在JSON里抽出几个必要字段单独建索引列。
3.3 前后端联调:从提交到审批完成的完整链路
实际联调中,前端的提交表单页面我拆成了三个步骤:
- 用户选择审批类型,前端向后端请求该类型对应的表单结构
- 动态渲染表单,用户填写并上传附件
- 点击提交,前端把表单数据、附件列表、订阅授权状态一起POST给后端
提交接口的核心工作是将表单内容转为JSON存入主表,初始化审批节点表,向第一位审批人发送订阅消息。注意,提交时一定要用事务包裹主表和节点表的写入操作,不然主表写成功了节点表失败了,会出现“无法审批”的脏数据。
审批人端主要操作是两个页面:待办列表和审批详情。待办列表查询条件是status=当前处理中 AND approver_id=当前用户,按创建时间倒序。审批详情页展示了表单内容、附件列表、审批时间轴,底部是“通过”“驳回”“转审”三个操作按钮。每次审批动作发一个POST请求,后端处理完状态流转后,通过WebSocket或者小程序端下拉刷新同步状态。
3.4 上线前必须处理的配置项
上线不是把代码传上去就完事了。微信公众平台后台有五个地方需要设置:
- 服务器域名:把后端API的HTTPS域名配置到request合法域名、uploadFile合法域名和downloadFile合法域名
- 业务域名:如果审批详情里要打开外部合同预览网页,需要配置业务域名并校验文件
- 订阅消息模板:在公众平台后台申请订阅消息模板,审核通过后把模板ID配置到后端
- 隐私协议:2023年后微信要求小程序必须配置用户隐私保护指引,收集用户微信头像、位置、相册等能力都要在后台声明
- 体验版和审核:提交审核前先用体验版邀请内部人员真机测试;正式审核版本记得把模拟数据和测试环境接口切到生产环境
域名配置是最容易翻车的点,很多人在开发者工具里测试正常,一到真机就失败,十有八九是域名没配好或者没配HTTPS证书。微信强制要求后端API必须是HTTPS,且证书链完整,测试环境中可以临时勾选“不校验合法域名”来调试,但正式版这个选项是没有的。
4. 常见问题与排查技巧实录
4.1 微信登录失败:wx.login拿不到code或者code换openid失败
这个问题出现频率极高。先说code拿不到的情况:一般是基础库版本过低或者用户网络异常,可以加个重试机制,在两秒内重试一次登录。再说code换了openid但请求失败:最常见的陷阱是调用微信接口时用的GET参数拼接错误,appid和secret用了小程序AppID和AppSecret,却拿openid和session_key不匹配,其实是要保证corpid和secret的配对正确。调试时先用Postman直接请求微信接口确认通了,再回代码排查。
还有一点非常容易忽略:wx.login生成的code是一次性的,有效期只有5分钟,且一旦被使用立即失效。千万不要在后端缓存code复用,前端每次登录都要重新调一次wx.login获取新code。
4.2 用户头像昵称获取失败
2022年10月后,微信对小程序获取用户头像昵称做了重大调整,原来那种一进入页面就弹窗让用户授权头像昵称的交互已经不可用。现在最省心、也最合规的做法是:不主动拿用户的微信头像和昵称,而是在用户提交审批单时,提供一个头像昵称填写入口,用户确认后才在表单里关联。如果非要展示用户姓名,建议用公司内部通讯录里的姓名,而不是微信昵称。
如果不做这层适配,上报审核时很大概率会被驳回,微信的理由通常就是“涉及用户个人信息收集,需用户主动授权且明确说明用途”。
4.3 真机调试出现net::ERR_CONNECTION_RESET
开发者在模拟器里跑得好好的,真机预览时页面空白或者请求失败,返回net::ERR_CONNECTION_RESET。排查方向有几个:
- 手机和开发机是否在同一局域网内,因为真机调试默认是手机直接访问开发机IP,不在同一网段就会连接被重置
- 开发者工具是否勾选了“不校验合法域名”,没勾选时HTTP接口会被拦截
- 后端服务是否绑定了只能本机访问的地址,需要改成监听0.0.0.0
- 公司WiFi和手机信号切换也会导致连接中断,建议用5G网络测试排除网络环境问题
这个报错在有HTTPS证书过期的情况下也会出现,检查一下证书有效期,证书失效时微信会直接断开连接。
4.4 订阅消息推送失败、频繁弹出订阅授权
订阅消息发送失败最常见的原因有三个:模板ID配置错误、用户未授权对应模板、微信支付或交易类目限制。前两个都好排查,麻烦的是第三个:不是所有审批类小程序都能申请“审批结果通知”的模板权限,如果你的类目里没有对应模板,需要换一个关键词组合重新申请。
频繁弹出订阅授权框的问题很影响体验。一次性订阅消息必须由用户主动触发才能弹窗,所以我是在用户提交审批单页面上放一个“开启审批通知”的开关,默认打开,用户取消勾选就不调wx.requestSubscribeMessage,下次进入页面再弹。这样既不违反微信规则,又不会让用户觉得每次提交都是强制骚扰。
4.5 包体积过大导致加载缓慢
小程序主包大小限制现在是2MB(总包20MB),超过限制就上传不了。审批小组件加几个页面一般不会超,但如果加入了图片素材库、富文本编辑器这类重型组件,就会非常容易触顶。我的优化策略是:
- 能用分包就分包,各审批类型的提交页按需加载
- 图片统一走线上URL,不本地打包
- 公共组件抽出来复用,避免同样的组件在不同页面各写一份
另外,开发者工具里可以勾选“上传时压缩代码”,能有效瘦身。真机加载慢的时候,把console里打印的接口耗时和包加载时间对照看一下,优先优化接口响应时间,压缩包体积排第二优先级。
4.6 上线前除了功能测试,还要做什么
很多团队把测试重点放在功能流程上,审批业务跑通了就提交审核,结果上线后被打了回来或者线下出问题。我踩了这么多次坑,总结出上线前必做的三个额外测试:
一是边界操作测试,比如流程中审批人离职了怎么办、提交人撤回后当前审批人还能不能看到这条单子;二是并发测试,两个审批人同时打开同一条单据,都点了通过,后端要保证只有一次生效,这个需要在审批动作接口加乐观锁或Redis分布式锁;三是数据兼容性测试,正式上线前的测试数据要清空,避免把脏数据带进生产环境。如果公司允许多环境部署,建议开发、测试、生产三个环境完全隔离,数据库也各自独立。
我个人在实际操作中最深的体会是:办公审批小程序的核心不是技术炫技,而是把审批流程的每个环节都打磨得让用户感觉“本来就该这样”。技术选型上,能轻则轻,能用配置解决的就不要写死代码;功能边界上,先做完请假、报销、外出这三个高频流程,让公司员工先用起来,再迭代合同和采购这些相对低频但逻辑复杂的场景。踩坑踩多了以后你会发现,审批系统做得好不好,员工嘴上不说,但报销到账变快了,请假不用跑来跑去签字了,大家的怨气自然就下去了。如果你正准备做这一块,希望这些实操细节能帮你少走一些弯路。
本文还有配套的精品资源,点击获取