微信小程序企业审批系统开发实战:表单与审批流设计
简介这套企业办公审批小程序面向大中型公司、企业及机关部门的日常审批管理覆盖请假、报销、外出、合同、采购、入职等常见流程并划分管理员、员工、审批人员三种角色审批结果通过微信消息提醒及时触达申请者适合需要规范化、移动化审批的团队快速部署使用。资源共包含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分布式锁三是数据兼容性测试正式上线前的测试数据要清空避免把脏数据带进生产环境。如果公司允许多环境部署建议开发、测试、生产三个环境完全隔离数据库也各自独立。我个人在实际操作中最深的体会是办公审批小程序的核心不是技术炫技而是把审批流程的每个环节都打磨得让用户感觉“本来就该这样”。技术选型上能轻则轻能用配置解决的就不要写死代码功能边界上先做完请假、报销、外出这三个高频流程让公司员工先用起来再迭代合同和采购这些相对低频但逻辑复杂的场景。踩坑踩多了以后你会发现审批系统做得好不好员工嘴上不说但报销到账变快了请假不用跑来跑去签字了大家的怨气自然就下去了。如果你正准备做这一块希望这些实操细节能帮你少走一些弯路。本文还有配套的精品资源点击获取