salarybill

This commit is contained in:
jiangyong27 2025-04-02 22:20:29 +08:00
parent de6cfbc773
commit 54e05acc91
6 changed files with 202 additions and 0 deletions
common/model
conf/template
go.mod
server

View File

@ -13,6 +13,16 @@ var (
StaffSalaryStatusPayed = 2
)
type SalaryBillLine struct {
Label string
Value string
}
type SalaryBillSection struct {
Name string
Line []*SalaryBillLine
}
type StaffSalary struct {
Id int64
CorpId int64

View File

@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>工资单</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #e0f7fa 0%, #b2ebf2 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}
.payroll-container {
background: white;
border-radius: 15px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
padding: 30px;
width: 90%;
max-width: 500px;
animation: fadeIn 0.6s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
h1 {
text-align: center;
color: #00838f;
font-size: 28px;
margin-bottom: 20px;
}
.section {
background: #f9f9f9;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
}
h2 {
color: #006064;
font-size: 20px;
margin-bottom: 15px;
}
.info-row {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-weight: 600;
color: #333;
}
.info-value {
color: #555;
}
.total-row {
font-weight: bold;
font-size: 1.2em;
color: #00838f;
border-top: 2px solid #00838f;
padding-top: 15px;
}
</style>
</head>
<body>
<div class="payroll-container">
<h1>{{.title}}</h1>
{{range $i, $data := .datas}}
<div class="section">
<h2>{{.Name}}</h2>
{{range $j, $v := .Line}}
<div class="info-row">
<span class="info-label">{{ $v.Label }}</span>
<span class="info-value">{{ $v.Value }}</span>
</div>
{{end}}
</div>
{{end}}
<div class="info-row total-row">
<span class="info-label">实发工资</span>
<span class="info-value">{{ .salary }}</span>
</div>
</div>
</body>
</html>

3
go.mod
View File

@ -8,6 +8,7 @@ require (
git.u8t.cn/open/gosdk v0.0.0-20250309163531-2f47649d3dbd
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.27
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874
github.com/fogleman/gg v1.3.0
github.com/gin-gonic/gin v1.10.0
github.com/go-co-op/gocron v1.37.0
github.com/gogap/errors v0.0.0-20210818113853-edfbba0ddea9
@ -49,6 +50,7 @@ require (
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogap/stack v0.0.0-20150131034635-fef68dddd4f8 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
@ -92,6 +94,7 @@ require (
go.uber.org/zap v1.21.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/image v0.14.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect

View File

@ -92,3 +92,9 @@ func (s *Salary) SyncStaffSalary(ctx *gin.Context) {
go new(worker.Staff).SyncStaffSalary(corp.Id, "")
ctx.JSON(http.StatusOK, session.NewRspOk())
}
func (s *Salary) Bill(ctx *gin.Context) {
id := cast.ToInt64(ctx.Query("id"))
service.NewStaffSalary().Bill(id, ctx)
}

View File

@ -38,6 +38,7 @@ func initRoutge(engine *gin.Engine) {
apiGroup.POST("/salary/pay", controller.NewSalary().Pay)
apiGroup.PUT("/staff/salary", controller.NewSalary().Update)
apiGroup.DELETE("/staff/salary", controller.NewSalary().Delete)
noTokenGroup.GET("/staff/salary/bill", controller.NewSalary().Bill)
apiGroup.GET("/staff/suggest", controller.NewStaff().Suggest)
apiGroup.POST("/staff/pay", controller.NewStaff().Pay)

View File

@ -426,3 +426,70 @@ func (s *StaffSalary) toExcel(filePath string, header []string, datas [][]string
ctx.Writer.Header().Add("Content-Type", "application/msexcel")
ctx.File(filePath)
}
func (s *StaffSalary) Bill(id int64, ctx *gin.Context) {
salary, err := dao.NewStaffSalaryDao().Get(id)
session.CheckDBError(err)
session.CheckNilError(salary, "工资单不存在")
corp, err := dao.NewCorpDao().Get(salary.CorpId)
session.CheckDBError(err)
session.CheckNilError(corp, "企业不存在")
user, err := dao.NewStaffUserDao().Get(salary.UserId)
session.CheckDBError(err)
session.CheckNilError(user, "用户不存在")
datas := make([]*model.SalaryBillSection, 0)
baseDetail := make([]*model.SalaryBillLine, 0)
baseDetail = append(baseDetail, &model.SalaryBillLine{Label: "员工姓名", Value: fmt.Sprintf("%s", user.Realname)})
baseDetail = append(baseDetail, &model.SalaryBillLine{Label: "基本工资", Value: fmt.Sprintf("%s", user.GetSalary().Base)})
baseDetail = append(baseDetail, &model.SalaryBillLine{Label: "出勤工资", Value: fmt.Sprintf("%s", user.GetSalary().Target)})
datas = append(datas, &model.SalaryBillSection{
Name: "基本信息",
Line: baseDetail,
})
salaryDetail := make([]*model.SalaryBillLine, 0)
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "出勤收入", Value: fmt.Sprintf("%.2f 元", salary.AttendSalary)})
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "绩效收入", Value: fmt.Sprintf("%.2f 元", salary.TargetSalary)})
if salary.AwardSalary != 0 {
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "奖金收入", Value: fmt.Sprintf("%.2f 元", salary.AwardSalary)})
}
if salary.OtherSalary != 0 {
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "其他收入", Value: fmt.Sprintf("%.2f 元", salary.OtherSalary)})
}
if salary.SocialDeduct != 0 {
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "社保扣除", Value: fmt.Sprintf("%.2f 元", salary.SocialDeduct)})
}
if salary.HouseDeduct != 0 {
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "公积金扣除", Value: fmt.Sprintf("%.2f 元", salary.HouseDeduct)})
}
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "个税扣除", Value: fmt.Sprintf("%.2f 元", salary.PersonalDeduct)})
if salary.OtherSalary != 0 {
salaryDetail = append(salaryDetail, &model.SalaryBillLine{Label: "其他扣除", Value: fmt.Sprintf("%.2f 元", salary.OtherSalary)})
}
datas = append(datas, &model.SalaryBillSection{
Name: "工资明细",
Line: salaryDetail,
})
attendDetail := make([]*model.SalaryBillLine, 0)
attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "应出勤", Value: fmt.Sprintf("%d 天", salary.ShouldDay)})
attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "休假天数", Value: fmt.Sprintf("%.2f 天", salary.HolidayDay)})
attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "缺勤天数", Value: fmt.Sprintf("%.2f 天", float64(salary.ShouldDay)-salary.AttendDay-salary.HolidayDay)})
attendDetail = append(attendDetail, &model.SalaryBillLine{Label: "实际出勤", Value: fmt.Sprintf("%.2f 天", salary.AttendDay)})
datas = append(datas, &model.SalaryBillSection{
Name: "出勤信息",
Line: attendDetail,
})
ctx.HTML(http.StatusOK, "salary_bill.html", gin.H{
"title": "工资单",
"salary": fmt.Sprintf("%.2f 元", salary.GetRealSalary()),
"datas": datas,
})
}