- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
前言 。
在报表数据处理中,Excel公式拥有强大而多样的功能,广泛应用于各个业务领域。无论是投资收益计算、财务报表编制还是保险收益估算,Excel公式都扮演着不可或缺的角色。传统的做法是直接依赖Excel来实现复杂的业务逻辑,并生成相应的Excel文件。因此只需在预设位置输入相应参数,Excel公式即可被激活,迅速计算并呈现结果。正因如此,在这类场景中,企业积累了大量用于计算的Excel文件,它们已经成为了无价的财富.
然而,传统的Excel文件方式存在难以管理和数据不安全的缺点。为了解决这些问题,可以采用B/S架构+Excel组件库的方式.
本文将以个人所得税的计算为例,使用React+Spring Boot+GcExcel来实现。首先准备好Excel文件,按照国家税务总局提供的个税计算页面进行创建.
个人所得税的收入类型有8种:
其中,工资薪金所得最为复杂,包括社会保险和专项扣除。每种类型的计税方式都不同,为了便于理解,我们为每个类型创建了一个工作表进行计算.
以下是准备好的Excel文件,其中蓝色部分为需要输入参数的单元格,其他单元格将自动计算.
完成准备工作后,下面开始前后端工程的搭建.
实践 。
前端 React 。
创建React工程 。
新建一个文件夹,如TaxCalculator,进入文件夹,在资源管理器的地址栏里输入cmd,然后回车,打开命令行窗口。使用下面的代码创建名为client-app的react app.
npx create-react-app salary-client
进入刚创建的salary-client文件夹,使用IDE,比如VisualStudio Code打开文件夹.
界面部分 。
个人所得税涉及的收入类型一共有8种,其中(“酬劳所得”,“偶然所得”,“利息、股息、红利所得”,“财产转让所得”)四种的计算方式接近,UI布局相似,借助React的component特性,最终需要提供5种表单界面.
如下图所示:
为了让UI看起来更好看一些,可以先引入一个UI框架,这里我们使用了MUI.
npm install @mui/material @emotion/react @emotion/styled
首先,更新Src/App.js的代码,其中添加了DarkMode的Theme, 代码如下:
import './App.css';
import { ThemeProvider } from '@emotion/react';
import { createTheme } from '@mui/material';
import { FormContainer } from './Component/FormContainer';
const darkTheme = createTheme({
palette: {
mode: 'dark',
},
});
function App() {
return (
<ThemeProvider theme={darkTheme}>
<div className="App-header">
<h2>个人所得税计算器</h2>
<FormContainer></FormContainer>
</div>
</ThemeProvider>
);
}
export default App;
可以看到,App.js中引用了FormContainer,下来添加 ./Component/FormContainer.js.
FormContainer主要是提供一个Selector,让用户选择收入类型,根据选择的类型渲染不同的组件.
import React, { useState } from 'react';
import { SalaryIncome } from "./SalaryIncome"
import { NativeSelect, FormControl } from '@mui/material';
import { BounsIncome } from './BounsIncome';
import { CommercialIncome } from './CommercialIncome';
import { LaborIncome } from './LaborIncome';
import { OtherIncome } from './OtherIncome';
export const FormContainer = () => {
const [calcType, setCalcType] = useState("工资薪金所得");
const GetIncomeControl = () => {
switch (calcType) {
case "工资薪金所得":
return <SalaryIncome calcType={calcType}></SalaryIncome>;
case "年终奖所得":
return <BounsIncome calcType={calcType}></BounsIncome>;
case "劳务报酬所得":
return <LaborIncome calcType={calcType}></LaborIncome>;
case "个体工商户、生产经营所得":
return <CommercialIncome calcType={calcType}></CommercialIncome>;
default:
return <OtherIncome calcType={calcType}></OtherIncome>;
}
}
return (
<div style={{ width: "60vw", marginTop: "5vh" }}>
<FormControl fullWidth sx={{ marginBottom: 2 }}>
<NativeSelect labelId="demo-simple-select-label" id="demo-simple-select"
value={calcType} label="类型" onChange={e => setCalcType(e.target.value)} >
<option value="工资薪金所得">工资薪金所得</option>
<option value="年终奖所得">年终奖所得</option>
<option Item value="劳务报酬所得">劳务报酬所得</option>
<option value="个体工商户、生产经营所得">个体工商户、生产经营所得</option>
<option value="酬劳所得">酬劳所得</option>
<option value="偶然所得">偶然所得</option>
<option value="利息、股息、红利所得">利息、股息、红利所得</option>
</NativeSelect>
</FormControl>
{GetIncomeControl()}
</div>);
}
例如:<SalaryIncome calcType={calcType}></SalaryIncome>; 同时会将calcType传递进去.
接下来,分别创建几个xxxIncome组件.
1.工资薪金所得 SalaryIncome.js 。
import React, { useState } from 'react';
import { TextField, Button, Stack } from '@mui/material';
import axios from 'axios';
export const SalaryIncome = (props) => {
const [income, setIncome] = useState("");
const [insurance, setInsurance] = useState("");
const [childEdu, setChildEdu] = useState("");
const [selfEdu, setSelfEdu] = useState("");
const [treatment, setTreatment] = useState("");
const [loans, setLoans] = useState("");
const [rent, setRent] = useState("");
const [elder, setElder] = useState("");
const [taxableIncome, setTaxableIncome] = useState("");
const [taxRate, setTaxRate] = useState("");
const [deduction, setDeduction] = useState("");
const [tax, setTax] = useState("");
const [takeHomeSalary, setTakeHomeSalary] = useState("");
async function calculateTax(event) {
event.preventDefault();
let res = await axios.post("api/calcPersonTax", {
calcType: props.calcType,
income: income,
insurance: insurance,
childEdu: childEdu,
selfEdu: selfEdu,
treatment: treatment,
loans: loans,
rent: rent,
elder: elder,
});
if (res != null) {
let data = res.data;
setTaxableIncome(data.taxableIncome);
setTaxRate(data.taxRate);
setDeduction(data.deduction);
setTax(data.tax);
setTakeHomeSalary(data.takeHomeSalary);
}
}
function reset(event) {
event.preventDefault();
setIncome("");
setInsurance("");
setChildEdu("");
setSelfEdu("");
setTreatment("");
setLoans("");
setRent("");
setElder("");
setTaxableIncome("");
setTaxRate("");
setDeduction("");
setTax("");
setTakeHomeSalary("");
}
return (
<div>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='primary'
label="税前工资" onChange={e => setIncome(e.target.value)}
value={income} fullWidth required size="small"/>
<TextField type="text" variant='outlined' color='secondary'
label="社会保险/公积金" onChange={e => setInsurance(e.target.value)}
value={insurance} fullWidth size="small"/>
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary'
label="子女教育专项扣除" onChange={e => setChildEdu(e.target.value)}
value={childEdu} fullWidth size="small"/>
<TextField type="text" variant='outlined' color='secondary'
label="继续教育专项扣除" onChange={e => setSelfEdu(e.target.value)}
value={selfEdu} fullWidth size="small"/>
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary'
label="大病医疗专项扣除" onChange={e => setTreatment(e.target.value)}
value={treatment} fullWidth size="small"/>
<TextField type="text" variant='outlined' color='secondary'
label="住房贷款利息专项扣除" onChange={e => setLoans(e.target.value)}
value={loans} fullWidth size="small"/>
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary'
label="住房租金专项扣除" onChange={e => setRent(e.target.value)}
value={rent} fullWidth size="small"/>
<TextField type="text" variant='outlined' color='secondary'
label="赡养老人专项扣除" onChange={e => setElder(e.target.value)}
value={elder} fullWidth size="small"/>
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary'
label="起征点" value="5000 元/月" fullWidth disabled size="small"/>
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<Button variant="outlined" color="primary" onClick={calculateTax} fullWidth size="large">计算</Button>
<Button variant="outlined" color="secondary" onClick={reset} fullWidth size="large">重置</Button>
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary'
label="应纳税所得额" value={taxableIncome} fullWidth disabled size="small"/>
<TextField type="text" variant='outlined' color='secondary'
label="税率" value={taxRate} fullWidth disabled size="small"/>
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary'
label="速算扣除数" value={deduction} fullWidth disabled size="small"/>
<TextField type="text" variant='outlined' color='secondary'
label="应纳税额" value={tax} fullWidth disabled size="small"/>
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary'
label="税后工资" value={takeHomeSalary} fullWidth disabled size="small"/>
</Stack>
</div>
)
}
2.年终奖金所得 BounsIncome.js 。
import React, { useState } from 'react';
import { TextField, Button, Stack } from '@mui/material';
import axios from 'axios';
export const BounsIncome = (props) => {
const [income, setIncome] = useState("");
const [taxableIncome, setTaxableIncome] = useState("");
const [taxRate, setTaxRate] = useState("");
const [deduction, setDeduction] = useState("");
const [monthlyWage, setMonthlyWage] = useState("");
const [tax, setTax] = useState("");
const [takeHomeSalary, setTakeHomeSalary] = useState("");
async function calculateTax(event) {
event.preventDefault();
let res = await axios.post("api/calcPersonTax", {
calcType: props.calcType,
income: income,
});
if (res != null) {
let data = res.data;
setTaxableIncome(data.taxableIncome);
setTaxRate(data.taxRate);
setDeduction(data.deduction);
setMonthlyWage(data.monthlyWage);
setTax(data.tax);
setTakeHomeSalary(data.takeHomeSalary);
}
}
function reset(event) {
event.preventDefault();
setIncome("");
setTaxableIncome("");
setTaxRate("");
setDeduction("");
setMonthlyWage("");
setTax("");
setTakeHomeSalary("");
}
return (
<div>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='primary' size="small"
label="税前工资" onChange={e => setIncome(e.target.value)}
value={income} fullWidth required />
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<Button variant="outlined" color="primary" onClick={calculateTax} fullWidth size="large">计算</Button>
<Button variant="outlined" color="secondary" onClick={reset} fullWidth size="large">重置</Button>
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税所得额" value={taxableIncome} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税率" value={taxRate} fullWidth disabled />
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="速算扣除数" value={deduction} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="平均每月工资" value={monthlyWage} fullWidth disabled />
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税额" value={tax} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税后工资" value={takeHomeSalary} fullWidth disabled />
</Stack>
</div>
)
}
3.劳务报酬所得 LaborIncome.js 。
import React, { useState } from 'react';
import { TextField, Button, Stack } from '@mui/material';
import axios from 'axios';
export const LaborIncome = (props) => {
const [income, setIncome] = useState("");
const [taxableIncome, setTaxableIncome] = useState("");
const [taxRate, setTaxRate] = useState("");
const [deduction, setDeduction] = useState("");
const [nonTaxablePart, setNonTaxablePart] = useState("");
const [tax, setTax] = useState("");
const [takeHomeSalary, setTakeHomeSalary] = useState("");
async function calculateTax(event) {
event.preventDefault();
let res = await axios.post("api/calcPersonTax", {
calcType: props.calcType,
income: income,
});
if (res != null) {
let data = res.data;
setTaxableIncome(data.taxableIncome);
setTaxRate(data.taxRate);
setDeduction(data.deduction);
setNonTaxablePart(data.nonTaxablePart);
setTax(data.tax);
setTakeHomeSalary(data.takeHomeSalary);
}
}
function reset(event) {
event.preventDefault();
setIncome("");
setTaxableIncome("");
setTaxRate("");
setDeduction("");
setNonTaxablePart("");
setTax("");
setTakeHomeSalary("");
}
return (
<div>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='primary' size="small"
label="税前工资" onChange={e => setIncome(e.target.value)}
value={income} fullWidth required />
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<Button variant="outlined" color="primary" onClick={calculateTax} fullWidth size="large">计算</Button>
<Button variant="outlined" color="secondary" onClick={reset} fullWidth size="large">重置</Button>
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税所得额" value={taxableIncome} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税率" value={taxRate} fullWidth disabled />
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="速算扣除数" value={deduction} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="减除费用" value={nonTaxablePart} fullWidth disabled />
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税额" value={tax} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税后工资" value={takeHomeSalary} fullWidth disabled />
</Stack>
</div>
)
}
4.个体工商户、生产经营所得 CommercialIncome.js 。
import React, { useState } from 'react';
import { TextField, Button, Stack } from '@mui/material';
import axios from 'axios';
export const CommercialIncome = (props) => {
const [income, setIncome] = useState("");
const [taxableIncome, setTaxableIncome] = useState("");
const [taxRate, setTaxRate] = useState("");
const [deduction, setDeduction] = useState("");
const [tax, setTax] = useState("");
const [takeHomeSalary, setTakeHomeSalary] = useState("");
async function calculateTax(event) {
event.preventDefault();
let res = await axios.post("api/calcPersonTax", {
calcType: props.calcType,
income: income,
});
if (res != null) {
let data = res.data;
setTaxableIncome(data.taxableIncome);
setTaxRate(data.taxRate);
setDeduction(data.deduction);
setTax(data.tax);
setTakeHomeSalary(data.takeHomeSalary);
}
}
function reset(event) {
event.preventDefault();
setIncome("");
setTaxableIncome("");
setTaxRate("");
setDeduction("");
setTax("");
setTakeHomeSalary("");
}
return (
<div>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='primary' size="small"
label="税前工资" onChange={e => setIncome(e.target.value)}
value={income} fullWidth required />
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<Button variant="outlined" color="primary" onClick={calculateTax} fullWidth size="large">计算</Button>
<Button variant="outlined" color="secondary" onClick={reset} fullWidth size="large">重置</Button>
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税所得额" value={taxableIncome} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税率" value={taxRate} fullWidth disabled />
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="速算扣除数" value={deduction} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税额" value={tax} fullWidth disabled />
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税后工资" value={takeHomeSalary} fullWidth disabled />
</Stack>
</div>
)
}
5.余下四种类型 OtherIncome.js 。
import React, { useState } from 'react';
import { TextField, Button, Stack } from '@mui/material';
import axios from 'axios';
export const OtherIncome = (props) => {
const [income, setIncome] = useState("");
const [taxableIncome, setTaxableIncome] = useState("");
const [taxRate, setTaxRate] = useState("");
const [tax, setTax] = useState("");
const [takeHomeSalary, setTakeHomeSalary] = useState("");
async function calculateTax(event) {
event.preventDefault();
let res = await axios.post("api/calcPersonTax", {
calcType: props.calcType,
income: income,
});
if (res != null) {
let data = res.data;
setTaxableIncome(data.taxableIncome);
setTaxRate(data.taxRate);
setTax(data.tax);
setTakeHomeSalary(data.takeHomeSalary);
}
}
function reset(event) {
event.preventDefault();
setIncome("");
setTaxableIncome("");
setTaxRate("");
setTax("");
setTakeHomeSalary("");
}
return (
<div>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='primary' size="small"
label={props.calcType} onChange={e => setIncome(e.target.value)}
value={income} fullWidth required />
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<Button variant="outlined" color="primary" onClick={calculateTax} fullWidth size="large">计算</Button>
<Button variant="outlined" color="secondary" onClick={reset} fullWidth size="large">重置</Button>
</Stack>
<hr></hr>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税所得额" value={taxableIncome} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税率" value={taxRate} fullWidth disabled />
</Stack>
<Stack spacing={2} direction="row" sx={{ marginBottom: 2 }}>
<TextField type="text" variant='outlined' color='secondary' size="small"
label="应纳税额" value={tax} fullWidth disabled />
<TextField type="text" variant='outlined' color='secondary' size="small"
label="税后工资" value={takeHomeSalary} fullWidth disabled />
</Stack>
</div>
)
}
此时,完成UI部分后,可以尝试运行起来,效果如下:
//通过代码运行React app
npm start
可以试着填一些数据,但是当我们点击计算时会报错,这是因为服务端还没有准备好.
前端请求部分 。
熟悉Axios的同学可以跳过这部分,前面的代码里,已经给出了Axois发送请求的代码.
可以看到无论是哪一种类型的组件,请求都发送到了相同的url("api/calcPersonTax"),以SalaryIncome为例,代码如下:
async function calculateTax(event) {
event.preventDefault();
let res = await axios.post("api/calcPersonTax", {
calcType: props.calcType,
income: income,
insurance: insurance,
childEdu: childEdu,
selfEdu: selfEdu,
treatment: treatment,
loans: loans,
rent: rent,
elder: elder,
});
if (res != null) {
let data = res.data;
setTaxableIncome(data.taxableIncome);
setTaxRate(data.taxRate);
setDeduction(data.deduction);
setTax(data.tax);
setTakeHomeSalary(data.takeHomeSalary);
}
}
可以看到,整个请求变得非常简单,主要是把state的值取出来,通过post请求发送到服务端,然后根据返回值,把数据重新设给state,这样就完成UI数据的更新了.
配置请求转发中间件 。
我们在请求时访问的是相对地址,React本身有一个nodeJS,默认的端口是3000,而Spring Boot的默认端口是8080。前端直接访问会有跨域的问题,因此我们要做一个代理的配置.
在src文件夹下面添加文件,名为setupProxy.js,代码如下:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
})
);
};
服务端 Spring Boot 。
创建工程及添加依赖 。
使用IDEA创建一个Spring Boot工程,如果使用的是社区(community)版本,不能直接创建Spring Boot项目,那可以先创建一个空项目,idea创建project的过程,就跳过了,这里我们以创建了一个gradle项目为例.
plugins {
id 'org.springframework.boot' version '3.0.0'
id 'io.spring.dependency-management' version '1.1.0'
id 'java'
id 'war'
}
group = 'org.example'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.grapecity.documents:gcexcel:6.2.0'
implementation 'javax.json:javax.json-api:1.1.4'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
test {
useJUnitPlatform()
}
在dependencies 中,我们除了依赖Spring Boot之外,还添加了GcExcel的依赖,后面导出时会用到GcExcel,目前的版本是6.2.0.
添加API 。
在Application类上,添加属性 @RequestMapping("/api").,并添加 calcPersonTax API.
@Spring BootApplication
@RestController
@RequestMapping("/api")
public class SalaryTaxCalculator {
public static void main(String[] args) {
SpringApplication.run(SalaryTaxCalculator.class, args);
}
@PostMapping("/calcPersonTax")
public CalcResult calcTax(@RequestBody CalcParameter par) {
Workbook workbook = new Workbook();
workbook.open(GetResourcePath());
return CalcInternal(workbook, par);
}
private String GetResourcePath(){
return Objects.requireNonNull(SalaryTaxCalculator.class.getClassLoader().getResource("PersonalTaxCalcEngine.xlsx")).getPath();
}
private CalcResult CalcInternal(Workbook workbook, CalcParameter par) {
//todo
}
}
可以看到在CalcInternal方法内,我们使用GcExcel,根据calcType来判断使用哪一个sheet来进行计算。对不同Sheet只需要通过GcExcel设值,并从特定的格子里取值即可.
同时,我们还需要创建两个类,CalcParameter和CalcResult。CalcParameter用于从request中把post的data解析出来,CalcResult用于在response中返回的数据.
CalcParameter
public class CalcParameter {
public String calcType;
public double income;
public double insurance;
public double childEdu;
public double selfEdu;
public double treatment;
public double loans;
public double rent;
public double elder;
}
CalcResult
public class CalcResult {
public double taxableIncome;
public double taxRate;
public double deduction;
public double tax;
public double takeHomeSalary;
public double monthlyWage;
public double nonTaxablePart;
}
使用GcExcel完成公式计算 。
前面我们定义了 CalcInternal,在 CalcInternal 中,我们需要使用GcExcel来完成公式计算.
GcExcel的公式计算是自动完成的,我们使用workbook打开Excel文件后,只需要set相关的value。之后在取值时,GcExcel会自动计算响应公式的值.
private CalcResult CalcInternal(Workbook workbook, CalcParameter par) {
var result = new CalcResult();
var sheet = workbook.getWorksheets().get(par.calcType);
switch (par.calcType) {
case "工资薪金所得" -> {
sheet.getRange("B1").setValue(par.income);
sheet.getRange("D1").setValue(par.insurance);
sheet.getRange("B2").setValue(par.childEdu);
sheet.getRange("D2").setValue(par.selfEdu);
sheet.getRange("B3").setValue(par.treatment);
sheet.getRange("D3").setValue(par.loans);
sheet.getRange("B4").setValue(par.rent);
sheet.getRange("D4").setValue(par.elder);
result.taxableIncome = (double) sheet.getRange("B9").getValue();
result.taxRate = (double) sheet.getRange("D9").getValue();
result.deduction = (double) sheet.getRange("B10").getValue();
result.tax = (double) sheet.getRange("D10").getValue();
result.takeHomeSalary = (double) sheet.getRange("B11").getValue();
}
case "年终奖所得" -> {
sheet.getRange("B1").setValue(par.income);
result.taxableIncome = (double) sheet.getRange("B3").getValue();
result.taxRate = (double) sheet.getRange("D3").getValue();
result.deduction = (double) sheet.getRange("B4").getValue();
result.monthlyWage = (double) sheet.getRange("D4").getValue();
result.tax = (double) sheet.getRange("B5").getValue();
result.takeHomeSalary = (double) sheet.getRange("D5").getValue();
}
case "劳务报酬所得" -> {
sheet.getRange("B1").setValue(par.income);
result.taxableIncome = (double) sheet.getRange("B3").getValue();
result.taxRate = (double) sheet.getRange("D3").getValue();
result.deduction = (double) sheet.getRange("B4").getValue();
result.nonTaxablePart = (double) sheet.getRange("D4").getValue();
result.tax = (double) sheet.getRange("B5").getValue();
result.takeHomeSalary = (double) sheet.getRange("D5").getValue();
}
case "个体工商户、生产经营所得" -> {
sheet.getRange("B1").setValue(par.income);
result.taxableIncome = (double) sheet.getRange("B3").getValue();
result.taxRate = (double) sheet.getRange("D3").getValue();
result.deduction = (double) sheet.getRange("B4").getValue();
result.tax = (double) sheet.getRange("D4").getValue();
result.takeHomeSalary = (double) sheet.getRange("B5").getValue();
}
default -> {
sheet.getRange("B1").setValue(par.income);
result.taxableIncome = (double) sheet.getRange("B3").getValue();
result.taxRate = (double) sheet.getRange("D3").getValue();
result.tax = (double) sheet.getRange("B4").getValue();
result.takeHomeSalary = (double) sheet.getRange("D4").getValue();
}
}
return result;
}
这样就完成了服务端的代码.
最终效果 。
我们可以使用工资薪金所得试验一下,可以看到数据被计算出来了。因为目的是为了分享服务端公式计算的方案,所以计算的结果是否正确,就不做细致考虑.
总结 。
个税计算的场景并不复杂,主要是通过Excel完成公式计算即可,在服务端使用GcExcel可以大幅度降低前后端的开发难度,系统的搭建过程可以完全不需要考虑计算的逻辑.
在实际的公式计算场景中,可能往往会比个税计算的场景复杂,借助GcExcel这样Excel组件库,可以很容易的把已有的Excel文件迁移到线上,提高工作效率.
另外,本文中分享的代码并不是最符合实际工作中的要求,读者还可以从以下角度去优化自己的代码.
扩展链接:
高级SQL分析函数-如何用窗口函数进行排名计算 。
3D模型+BI分析,打造全新的交互式3D可视化大屏开发方案 。
React + Springboot + Quartz,从0实现Excel报表自动化 。
最后此篇关于如何使用Java+React计算个人所得税?的文章就讲到这里了,如果你想了解更多关于如何使用Java+React计算个人所得税?的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
问题是,当用户回复彼此的帖子时,我必须这样做: margin-left:40px; 对于 1 级深度 react margin-left:80px; 对于 2 层深等 但是我想让 react div
我试图弄清楚如何将 React Router 与 React VR 连接起来。 首先,我应该使用 react-router dom/native ?目前尚不清楚,因为 React VR 构建在 Rea
我是 React 或一般编码背景的新手。我不确定这些陈述之间有什么区别 import * as react from 'react' 和 import react from 'react' 提前致谢!
我正在使用最新的稳定版本的 react、react-native、react-test-renderer、react-dom。 然而,react-native 依赖于 react@16.0.0-alp
是否 react 原生 应用程序开发可以通过软件架构实现,例如 MVC、MVP、MVVM ? 谢谢你。 最佳答案 是的。 React Native 只是你提到的那些软件设计模式中的“V”。如果你考虑其
您好我正在尝试在我的导航器右按钮中绑定(bind)一个功能, 但它给出了错误。 这是我的代码: import React, { Component } from 'react'; import Ico
我使用react native创建了一个应用程序,我正在尝试生成apk。在http://facebook.github.io/react-native/docs/signed-apk-android.
1 [我尝试将分页的 z-index 更改为 0,但没有成功] 这是我的codesandbox的链接:请检查最后一个选择下拉列表,它位于分页后面。 https://codesandbox.io/s/j
我注意到 React 可以这样导入: import * as React from 'react'; ...或者像这样: import React from 'react'; 第一个导入 react
我是 react-native 的新手。我正在使用 React Native Paper 为所有屏幕提供主题。我也在使用 react 导航堆栈导航器和抽屉导航器。首先,对于导航,论文主题在导航组件中不
我有一个使用 Ignite CLI 创建的 React Native 应用程序.我正在尝试将 TabNavigator 与 React Navigation 结合使用,但我似乎无法弄清楚如何将数据从一
我正在尝试在我的 React 应用程序中进行快照测试。我已经在使用 react-testing-library 进行一般的单元测试。然而,对于快照测试,我在网上看到了不同的方法,要么使用 react-
我正在使用 react-native 构建跨平台 native 应用程序,并使用 react-navigation 在屏幕之间导航和使用 redux 管理导航状态。当我嵌套导航器时会出现问题。 例如,
由于分页和 React Native Navigation,我面临着一种复杂的问题。 单击具有类别列表的抽屉,它们都将转到屏幕 问题陈述: 当我随机点击类别时,一切正常。但是,在分页过程中遇到问题。假
这是我的抽屉导航: const DashboardStack = StackNavigator({ Dashboard: { screen: Dashboard
尝试构建 react-native android 应用程序但出现以下错误 info Running jetifier to migrate libraries to AndroidX. You ca
我目前正在一个应用程序中实现 React Router v.4,我也在其中使用 Webpack 进行捆绑。在我的 webpack 配置中,我将 React、ReactDOM 和 React-route
我正在使用 React.children 渲染一些带有 react router 的子路由(对于某个主路由下的所有子路由。 这对我来说一直很好,但是我之前正在解构传递给 children 的 Prop
当我运行 React 应用程序时,它显示 export 'React'(导入为 'React')在 'react' 中找不到。所有页面错误 see image here . 最佳答案 根据图像中的错误
当我使用这个例子在我的应用程序上实现 Image-slider 时,我遇到了这个错误。 import React,{Component} from 'react' import {View,T
我是一名优秀的程序员,十分优秀!