1. 立项背景和目标
公司原有报销依赖 Excel 手工填写+邮件流转,审批无状态追踪、发票与非发票打款混在一起无法区分,财务打款后还需手动在 1889buy 财务系统重复录入,重复劳动且容易出错。项目目标是建设一套覆盖报销全生命周期的管理系统,实现审批电子化、打款自动化、与外部财务系统实时同步。
2. 核心功能模块
报销单管理:草稿/提交/撤销/重新申请,发票与非发票项区分录入
三级审批流程:部门主管→总经理→财务审核,每级可配置角色,支持自动跳过同一审批人
确认打款:发票/非发票分类型独立确认,打款时必须选择资金账号(从 1889buy 实时拉取),非发票还需选择打款方式(微信/支付宝/银行)
财务接口同步:确认打款后自动调用外部 1889buy 资金账号接口,将打款流水同步到外部财务系统
接口调用流水:每次调用外部财务接口无论成功失败都落库,用于对账和问题排查
3. 业务流程
员工登录→创建报销单→提交→部门审批→总经理审批→财务审核→财务进入"待打款"列表→选择打款类型(发票/非发票)→选择资金账号→确认打款→本地更新报销状态+写审批日志+调外部财务接口+写接口流水→全部打款完成后报销单状态变为"已打款"。
前后端分离架构:
后端:.NET 8 Web API,分层结构(Controller→Service→Repository),SqlSugar ORM + MySQL,自定义 Redis Token 认证(handler 从 Redis 读取 CurrentUserDto 构造 Claims)
前端:Vue 3.5 + TypeScript + Element Plus 2.14 + Pinia 3 + Vue Router 5,PC 端和 H5 移动端共用一套 API
外部集成:通过 HttpClient 调用 1889buy 财务系统 asmx 接口,资金账号列表用 GET,打款同步用 JSON body + text/plain Content-Type
2. 我负责的模块和结果
报销审批核心流程:三级审批状态机实现,含自动跳过同一审批人逻辑,覆盖员工端提交、审批端处理、财务端审核,累计支持 50+ 日活用户
资金账号打款功能:从 1889buy 拉取资金账号列表,打款时前端下拉选择、后端校验必选,发票/非发票独立确认,累计对接 52 个外部资金账号
财务接口流水落库:新建 reimburse_fund_log 表,每次外部调用无论成功失败均独立连接写入,不受打款主事务回滚影响,已记录 100+ 条调用流水
3. 遇到的难点和解决方案
难点一:外部 1889buy 接口文档与实际不符。文档写 Body 格式是 x-www-form-urlencoded,实测 JSON+text/plain 才能被正确解析(form 方式参数解析不到返回"远程超时",msgpack 方式参数校验直接被跳过)。方案:用 Postman 逐轮对照实验(换 Content-Type、换 body 格式、换 opid/agentid 值),定位到 JSON body + text/plain 是唯一能让服务端正确接收参数的组合,同时发现 opid 必须是外部系统有打款权限的操作员(文档示例 277 有权限,本地用户 17544 无权限),agentid 必须是外部真实员工 ID(值为 1 会报"代理ID无效")。
难点二:外部接口失败导致本地事务回滚,报错日志被一起清掉。打款主流程在 SqlSugar 事务中,外部接口失败会触发 RollbackTran,若流水表在同一事务写入会被一起回滚。方案:WriteFundLogAsync 用 new SqlSugarClient 创建独立数据库连接写入流水,与打款主事务完全隔离,确保失败时流水依然保留在 reimburse_fund_log 表中。
难点三:要求从无到有一个人五天完成