Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Smart Expense

面向企业费用管理场景的智能报销与费控系统。覆盖“票据上传与 OCR、预算控制、分级审批、会计凭证、付款与消息通知”的完整业务闭环。

项目定位

Smart Expense 是一个前后端分离的微服务练习项目,聚焦企业报销系统中最核心、最容易产生数据一致性问题的链路:预算不能超扣、审批不能越级、票据必须可追溯、异步任务不能轻易丢失

项目将员工、经理、财务三类角色串入同一条报销流程,并在关键节点通过 Redis、数据库唯一约束、条件更新、消息重试和死信队列控制风险。

在线流程

员工上传票据
  -> 腾讯云 COS 保存原图
  -> 阿里云 OCR 识别发票信息
  -> 提交报销并预扣部门预算
  -> RabbitMQ 异步验真
  -> 经理审批
  -> 财务审批并实扣预算
  -> 自动生成会计凭证
  -> 财务登记付款
  -> 站内信通知相关人员

状态流转:

PENDING_VERIFY -> PENDING_MANAGER -> PENDING_FINANCE -> APPROVED -> PAID
                    \-> REJECTED / VERIFY_FAIL

核心亮点

场景 实现方式 解决的问题
预算预扣 Redis Lua 原子扣减 + 预扣日志 防止并发提交导致预算超扣
预算实扣 幂等 token + MyBatis-Plus 乐观锁 将冻结额度安全转为已用预算
报销审批 状态机 + 条件更新 SQL 防止越级审批和重复审批
票据处理 COS 原图存储 + 阿里云 OCR 减少手工录入并保留审计影像
重复报销 发票代码与号码联合唯一索引 以数据库约束作为最终兜底
异步验真 RabbitMQ 主队列、重试队列、死信队列 解耦主流程并保留失败消息
财务闭环 费用科目映射 + 会计凭证 + 付款登记 连接报销业务与财务核算
消息提醒 站内信、未读数、已读状态 告知申请人和审批人流程变化

系统架构

Vue 3 + Vite
      |
      v
Gateway & Auth (8080) ---- JWT 鉴权、路由转发
      |
      +------------------------+
      |                        |
      v                        v
Reimbursement Service      Budget Service
      |                        |
      |-- MySQL: reimburse_db  |-- MySQL: budget_db
      |-- Redis                |-- Redis Lua
      |-- RabbitMQ             |
      |-- Tencent COS          |
      `-- Alibaba Cloud OCR    |

功能清单

  • 员工报销:发票图片/PDF 上传、OCR 自动回填、报销单提交、查看原图和处理进度
  • 预算控制:部门预算查询、提交预扣、审批通过实扣、驳回释放、token 幂等
  • 审批工作台:经理按部门审批,财务复核、生成凭证并登记付款
  • 发票验真:异步验真、失败重试、死信兜底、状态自动推进
  • 会计凭证:按费用类型映射借方科目,自动生成期间与流水凭证号
  • 消息中心:提交、验真、审批、付款等关键节点自动通知

技术栈

后端:Java 17、Spring Boot 2.7、Spring Cloud Gateway、OpenFeign、MyBatis-Plus、MySQL 8、Redis、RabbitMQ、JWT、Nacos

前端:Vue 3、Vite、Vue Router、Axios

云服务:腾讯云 COS、阿里云 OCR

项目结构

Smart-expense/
├── backend/
│   ├── common/                  # 统一结果、异常、JWT、枚举和上下文
│   ├── gateway-auth/            # 登录认证、JWT 鉴权、网关路由
│   ├── reimbursement-service/   # 报销、发票、审批、验真、凭证、站内信
│   └── budget-service/          # 预算预扣、实扣、释放与并发控制
├── frontend/                    # Vue 3 前端
└── docs/                        # 数据库设计、分步骤设计与测试说明

快速启动

1. 准备依赖

  • JDK 17
  • Maven 3.8+
  • Node.js 20+
  • MySQL 8、Redis、RabbitMQ
  • 可选:Nacos(当前配置支持本地直连下游服务)
  • 可选:腾讯云 COS 和阿里云 OCR 凭证,用于真实票据上传与识别

数据库表结构见 docs/2-数据库设计.md

2. 配置本地凭证

仓库不包含真实密码、AccessKey 或票据文件。请通过环境变量或本地未提交的 application-local.yml 覆盖以下配置:

spring:
  datasource:
    username: your_mysql_username
    password: your_mysql_password
  redis:
    host: localhost
    password: your_redis_password
  rabbitmq:
    host: localhost
    username: your_rabbitmq_username
    password: your_rabbitmq_password

smart-expense:
  aliyun:
    ocr:
      access-key-id: your_access_key_id
      access-key-secret: your_access_key_secret
  tencent:
    cos:
      region: your_cos_region
      bucket-name: your_cos_bucket_name
      base-url: https://your_cos_domain
      secret-id: your_secret_id
      secret-key: your_secret_key

也可以使用 Spring 环境变量,例如 SMART_EXPENSE_REIMBURSE_DB_PASSWORDSMART_EXPENSE_TENCENT_COS_SECRET_ID

3. 启动后端

cd backend
mvn clean install

# 分别启动网关、预算服务和报销服务
mvn -pl gateway-auth spring-boot:run
mvn -pl budget-service spring-boot:run
mvn -pl reimbursement-service spring-boot:run

默认端口:网关 8080、报销服务 8081、预算服务 8082

4. 启动前端

cd frontend
npm install
npm run dev

前端默认访问 http://localhost:5173,通过网关访问后端接口。

面试可讲的设计点

  1. 为什么预算要分预扣和实扣? 提交时先冻结额度,避免多人同时提交突破预算;最终审批通过后再把冻结额度转为已用额度,驳回则释放。

  2. 如何防止重复提交或重复扣减? 预算操作使用 token 幂等;发票使用联合唯一索引;审批与付款通过“期望状态”条件更新控制并发。

  3. 为什么验真使用 RabbitMQ? OCR/验真耗时且可能失败,异步化避免阻塞提交;重试队列处理瞬时故障,死信队列保留最终失败消息。

  4. 为什么原始票据放 COS 而不是 MySQL? 对象存储更适合大文件,数据库只存 URL,兼顾性能、成本和审计追溯能力。

  5. 为什么凭证在财务审批后生成? 只有业务被最终确认后才应该进入财务核算,避免给被驳回的单据生成无效凭证。

文档索引

安全说明

本仓库仅包含可公开展示的源代码和脱敏配置。请勿提交:数据库密码、Redis/RabbitMQ 凭证、云服务 AccessKey、JWT 生产密钥以及真实发票文件。

About

企业智能报销与费控系统|Spring Cloud + Vue 3 + Redis + RabbitMQ + OCR + COS

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages