一个全栈的个人所得税最优分配方案计算系统,包含后端 Spring Boot API 服务和前端 React Web 界面。该系统可以帮助用户找到年度工资和一次性奖励的最佳分配比例,以实现税费最小化。
- 📊 年度工资税计算:根据中国个人所得税累进税率计算年度工资应纳税额
- 🎁 一次性奖励税计算:根据一次性奖励金额(除以12后)的月度税率计算应纳税额
- 🎯 最优分配方案:自动计算年度工资和一次性奖励的最优分配比例,使总税费最小
- 💰 精确计算:使用分为单位进行计算,避免出现分以下的精度问题
- ⚡ 高性能算法:提供全遍历和优化两种算法,平衡计算精度与性能
- 🎨 现代化前端界面:基于 React + Ant Design 的友好用户界面
- Java 17
- Spring Boot 3.5.7
- Maven
- Lombok
- React 18.3
- TypeScript 5.9
- Ant Design 5.29
- Rsbuild 1.6
- Axios 1.13
tax/
├── src/ # 后端源代码
│ ├── main/
│ │ ├── java/com/codingapi/tax/
│ │ │ ├── controller/ # REST API 控制器
│ │ │ ├── model/ # 核心业务模型
│ │ │ │ ├── TaxCalculateContext.java # 税费计算上下文
│ │ │ │ ├── TaxLayer.java # 税率层级
│ │ │ │ └── TaxValue.java # 税费结果
│ │ │ ├── pojo/ # 请求对象
│ │ │ ├── utils/ # 工具类
│ │ │ └── exception/ # 异常处理
│ │ └── resources/
│ │ ├── application.properties
│ │ └── static/ # 前端构建产物(构建后生成,已加入.gitignore)
│ └── test/ # 测试代码
├── web/ # 前端源代码
│ ├── src/
│ │ ├── api/ # API 接口封装
│ │ │ └── index.ts
│ │ ├── App.tsx # 主应用组件
│ │ └── index.tsx # 入口文件
│ ├── public/ # 静态资源
│ ├── dist/ # 前端构建产物(构建后生成,已加入.gitignore)
│ ├── rsbuild.config.ts # Rsbuild 配置
│ ├── tsconfig.json # TypeScript 配置
│ └── package.json # 前端依赖
├── scripts/ # 构建脚本
│ └── package.sh # 一体化打包脚本(将前端打包到后端)
└── pom.xml # Maven 配置
| 级数 | 税率 | 速算扣除数 | 应纳税所得额 |
|---|---|---|---|
| 1 | 3% | 0 | 不超过36,000元 |
| 2 | 10% | 2,520 | 超过36,000至144,000元 |
| 3 | 20% | 16,920 | 超过144,000至300,000元 |
| 4 | 25% | 31,920 | 超过300,000至420,000元 |
| 5 | 30% | 52,920 | 超过420,000至660,000元 |
| 6 | 35% | 85,920 | 超过660,000至960,000元 |
| 7 | 45% | 181,920 | 超过960,000元 |
将一次性奖励除以12,然后按照以下税率计算:
| 级数 | 税率 | 速算扣除数 | 月应纳税所得额 |
|---|---|---|---|
| 1 | 3% | 0 | 不超过3,000元 |
| 2 | 10% | 210 | 超过3,000至12,000元 |
| 3 | 20% | 1,410 | 超过12,000至25,000元 |
| 4 | 25% | 2,660 | 超过25,000至35,000元 |
| 5 | 30% | 4,410 | 超过35,000至55,000元 |
| 6 | 35% | 7,160 | 超过55,000至80,000元 |
| 7 | 45% | 15,160 | 超过80,000元 |
后端:
- JDK 17 或更高版本
- Maven 3.6 或更高版本
前端:
- Node.js 16 或更高版本
- pnpm(推荐)或 npm
后端:
# Maven 会自动下载依赖,无需手动安装前端:
cd web
# 使用 pnpm(推荐)
pnpm install
# 或使用 npm
npm install1. 启动后端服务:
# 在项目根目录
./mvnw spring-boot:run
# 或使用 IDE 直接运行 TaxApplication 类后端服务默认运行在:http://localhost:8090
2. 启动前端开发服务器:
# 在 web 目录
cd web
pnpm dev
# 或使用 npm
npm run dev前端开发服务器默认运行在:http://localhost:8000
前端会自动代理 API 请求到后端(配置在 web/rsbuild.config.ts)
使用打包脚本(推荐):
# 赋予脚本执行权限(首次运行)
chmod +x scripts/package.sh
# 执行打包脚本(会自动构建前端并复制到后端资源目录)
./scripts/package.sh
# 构建后端 JAR 包
./mvnw clean package
# 运行 JAR 包
java -jar target/tax-0.0.1-SNAPSHOT.jar运行后访问 http://localhost:8090 即可同时访问前端界面和 API。
1. 构建后端:
# 在项目根目录
./mvnw clean package
# 运行 JAR 包
java -jar target/tax-0.0.1-SNAPSHOT.jar2. 构建前端:
# 在 web 目录
cd web
pnpm build
# 预览生产构建
pnpm preview构建产物位于 web/dist/ 目录,需要配合 Nginx 等静态服务器使用(详见部署说明)
后端配置 (src/main/resources/application.properties):
server.port=8090前端配置 (web/rsbuild.config.ts):
- 前端开发服务器端口:
8000 - API 代理目标:
http://127.0.0.1:8090
如需修改后端端口,需要同步更新前端代理配置。
- 启动前后端服务(见快速开始章节)
- 打开浏览器访问
http://localhost:8000 - 输入参数:
- 个人应纳税额:需要计算的总金额(单位:元)
- 已发工资:已经发放的工资,默认为 0(单位:元)
- 点击"计算最优税率"按钮
- 查看结果:
- 个人应纳税额
- 推荐的年度工资
- 年度工资税费
- 一次性奖励金额
- 一次性奖励税费
- 最优总税金
接口地址: POST /api/tax/calculate
请求示例:
curl -X POST http://localhost:8090/api/tax/calculate \
-H "Content-Type: application/json" \
-d '{
"payableMoney": "200575.94",
"salary": "0"
}'请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| payableMoney | String | 是 | 个人应纳税额(总金额,单位:元) |
| salary | String | 是 | 已发工资(单位:元) |
响应示例:
{
"payableMoney": 200575.94,
"salary": 164576.00,
"oneRewardTax": 1080.00,
"yearSalaryTax": 15995.20,
"totalTax": 17075.20
}响应字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| payableMoney | BigDecimal | 个人应纳税额 |
| salary | BigDecimal | 推荐的年度工资 |
| oneRewardTax | BigDecimal | 一次性奖励的税费 |
| yearSalaryTax | BigDecimal | 年度工资的税费 |
| totalTax | BigDecimal | 总税费(最小税费) |
系统通过遍历所有可能的工资和奖励分配方案,找到使总税费最小的最优解。
-
全遍历算法 (
calculateMinTax):- 以1元(100分)为步长遍历所有可能的分配方案
- 计算每种方案的总税费
- 返回税费最小的方案
- 优点:结果绝对精确
- 缺点:计算量大,适合金额较小的场景
-
优化算法 (
calculateMinTaxPlus):- 第一阶段:粗略搜索(步长10元或1元,根据金额大小动态调整)
- 第二阶段:精确搜索(在粗略最优值附近以1分为步长进行精细搜索)
- 优点:计算效率高,结果精确度高(误差通常小于0.05元)
- 缺点:极少数情况下可能不是绝对最优解
- 所有金额计算均转换为分(整数)进行计算,避免出现分以下的单位(如厘)
- 计算结果四舍五入到分(保留2位小数)
- 使用
BigDecimal确保浮点数计算精度
import com.codingapi.tax.model.TaxCalculateContext;
import com.codingapi.tax.model.TaxValue;
import java.math.BigDecimal;
// 获取计算上下文实例
TaxCalculateContext context = TaxCalculateContext.getInstance();
// 计算最优税费分配(全遍历算法)
TaxValue result = context.calculateMinTax(
new BigDecimal("200575.94"), // 个人应纳税额
new BigDecimal("0") // 已发工资
);
// 打印结果
result.print();
// 使用优化算法(推荐)
TaxValue resultPlus = context.calculateMinTaxPlus(
new BigDecimal("200575.94"),
new BigDecimal("0")
);// 计算年度工资税
Arithmetic yearTax = context.calculateYearSalaryTax(
new BigDecimal("164576.00")
);
System.out.println("年度工资税: " + yearTax.getValue());
// 计算一次性奖励税
Arithmetic rewardTax = context.calculateOneRewardTax(
new BigDecimal("35999.94")
);
System.out.println("一次性奖励税: " + rewardTax.getValue());项目包含完整的单元测试,使用 JUnit 5 和 CSV 参数化测试:
# 运行所有测试
./mvnw test
# 运行特定测试类
./mvnw test -Dtest=TaxCalculateContextTest测试数据位于 src/test/resources/com/codingapi/tax/model/salary.csv
- 金额单位:所有金额以元为单位输入,系统内部转换为分进行计算
- 精度限制:计算结果精确到分(2位小数),不会出现分以下的单位
- 已发工资:
salary参数表示已经发放的工资,系统会在此基础上计算剩余金额的最优分配 - 税率更新:如果税率政策发生变化,需要修改
TaxCalculateContext中的税率层级配置
技术栈说明:
- React:用于构建用户界面
- TypeScript:提供类型安全
- Ant Design:UI 组件库
- Rsbuild:高性能的前端构建工具
- Axios:HTTP 客户端
主要文件:
web/src/App.tsx:主应用组件,包含表单和结果显示web/src/api/index.ts:API 接口封装web/rsbuild.config.ts:构建配置,包含代理设置
开发命令:
cd web
# 启动开发服务器(自动打开浏览器)
pnpm dev
# 构建生产版本
pnpm build
# 预览生产构建
pnpm preview修改 API 地址:
如需修改后端 API 地址,编辑 web/rsbuild.config.ts 中的代理配置:
server: {
proxy: {
'/api': 'http://127.0.0.1:8090', // 修改这里的地址
}
}修改税率:
如需修改税率,请编辑 src/main/java/com/codingapi/tax/model/TaxCalculateContext.java 中的以下方法:
initYearSalaryLayers():年度工资税率层级initOneRewardTaxLayers():一次性奖励税率层级
算法优化:
如需调整优化算法的搜索策略,可修改 calculateMinTaxPlus() 方法中的:
roughStepInFen:粗略搜索步长searchRangeInFen:精确搜索范围
开发命令:
# 编译项目
./mvnw clean compile
# 运行测试
./mvnw test
# 打包项目
./mvnw package
# 运行应用
./mvnw spring-boot:run欢迎提交 Issue 和 Pull Request!
本项目采用 MIT 许可证。
将前端构建产物打包到后端 JAR 中,前后端一起运行,部署更简单。
项目提供了自动化打包脚本 scripts/package.sh:
# 赋予脚本执行权限(首次运行)
chmod +x scripts/package.sh
# 执行打包脚本
./scripts/package.sh脚本执行流程:
- 进入
web目录 - 安装前端依赖(
pnpm i) - 构建前端(
pnpm run build) - 删除后端
src/main/resources/static目录(如果存在) - 将前端构建产物
web/dist复制到src/main/resources/static
如果脚本无法执行,可以手动执行以下步骤:
# 1. 构建前端
cd web
pnpm install
pnpm run build
# 2. 返回项目根目录,将前端构建产物复制到后端资源目录
cd ..
rm -rf ./src/main/resources/static
cp -r ./web/dist/ ./src/main/resources/static打包完成后,构建后端 JAR:
# 构建 JAR 包
./mvnw clean package
# 运行 JAR 包
java -jar target/tax-0.0.1-SNAPSHOT.jar访问应用:
- 前端界面:
http://localhost:8090 - API 接口:
http://localhost:8090/api/tax/calculate
优势:
- ✅ 前后端一体化部署,只需一个 JAR 文件
- ✅ 无需配置 Nginx 等反向代理
- ✅ 部署简单,适合容器化部署
- ✅ Spring Boot 自动提供静态资源服务
前后端分别部署,适合需要独立扩展的场景。
- 构建 JAR 包:
./mvnw clean package- 运行 JAR 包:
java -jar target/tax-0.0.1-SNAPSHOT.jar- 使用环境变量配置(可选):
SERVER_PORT=8090 java -jar target/tax-0.0.1-SNAPSHOT.jar- 构建前端:
cd web
pnpm install
pnpm build-
部署
web/dist/目录到静态文件服务器(如 Nginx、Apache 等) -
配置 Nginx 反向代理(示例):
server {
listen 80;
server_name your-domain.com;
# 前端静态文件
location / {
root /path/to/web/dist;
try_files $uri $uri/ /index.html;
}
# API 代理到后端
location /api {
proxy_pass http://localhost:8090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}注意: 如果使用前后端分离部署,需要修改前端的 API 基础地址配置(web/src/api/index.ts),将 baseURL 改为后端服务器的实际地址。
- 🎯 全栈解决方案:前后端分离架构,职责清晰
- 💰 精确计算:基于分(整数)进行计算,避免浮点精度问题
- ⚡ 性能优化:智能搜索算法,平衡精度与性能
- 🎨 用户友好:现代化 Web 界面,操作简单直观
- 🧪 质量保证:完整的单元测试覆盖
- ✨ 初始版本发布
- ✅ 实现年度工资税和一次性奖励税计算
- ✅ 实现最优分配算法(全遍历和优化两种方式)
- ✅ 使用分为单位进行计算,避免精度问题
- ✅ 提供 RESTful API 接口
- ✅ 完整的单元测试覆盖
- ✅ React + Ant Design 前端界面
- ✅ 前后端分离架构
- ✅ 提供一体化打包脚本(
scripts/package.sh),支持前后端一体化部署