salarybill
This commit is contained in:
parent
de6cfbc773
commit
54e05acc91
|
@ -13,6 +13,16 @@ var (
|
||||||
StaffSalaryStatusPayed = 2
|
StaffSalaryStatusPayed = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SalaryBillLine struct {
|
||||||
|
Label string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SalaryBillSection struct {
|
||||||
|
Name string
|
||||||
|
Line []*SalaryBillLine
|
||||||
|
}
|
||||||
|
|
||||||
type StaffSalary struct {
|
type StaffSalary struct {
|
||||||
Id int64
|
Id int64
|
||||||
CorpId int64
|
CorpId int64
|
||||||
|
|
|
@ -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
3
go.mod
|
@ -8,6 +8,7 @@ require (
|
||||||
git.u8t.cn/open/gosdk v0.0.0-20250309163531-2f47649d3dbd
|
git.u8t.cn/open/gosdk v0.0.0-20250309163531-2f47649d3dbd
|
||||||
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.27
|
github.com/ArtisanCloud/PowerWeChat/v3 v3.2.27
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874
|
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/gin-gonic/gin v1.10.0
|
||||||
github.com/go-co-op/gocron v1.37.0
|
github.com/go-co-op/gocron v1.37.0
|
||||||
github.com/gogap/errors v0.0.0-20210818113853-edfbba0ddea9
|
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/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/gogap/stack v0.0.0-20150131034635-fef68dddd4f8 // 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/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
@ -92,6 +94,7 @@ require (
|
||||||
go.uber.org/zap v1.21.0 // indirect
|
go.uber.org/zap v1.21.0 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // 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/net v0.27.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
|
|
|
@ -92,3 +92,9 @@ func (s *Salary) SyncStaffSalary(ctx *gin.Context) {
|
||||||
go new(worker.Staff).SyncStaffSalary(corp.Id, "")
|
go new(worker.Staff).SyncStaffSalary(corp.Id, "")
|
||||||
ctx.JSON(http.StatusOK, session.NewRspOk())
|
ctx.JSON(http.StatusOK, session.NewRspOk())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Salary) Bill(ctx *gin.Context) {
|
||||||
|
id := cast.ToInt64(ctx.Query("id"))
|
||||||
|
|
||||||
|
service.NewStaffSalary().Bill(id, ctx)
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ func initRoutge(engine *gin.Engine) {
|
||||||
apiGroup.POST("/salary/pay", controller.NewSalary().Pay)
|
apiGroup.POST("/salary/pay", controller.NewSalary().Pay)
|
||||||
apiGroup.PUT("/staff/salary", controller.NewSalary().Update)
|
apiGroup.PUT("/staff/salary", controller.NewSalary().Update)
|
||||||
apiGroup.DELETE("/staff/salary", controller.NewSalary().Delete)
|
apiGroup.DELETE("/staff/salary", controller.NewSalary().Delete)
|
||||||
|
noTokenGroup.GET("/staff/salary/bill", controller.NewSalary().Bill)
|
||||||
|
|
||||||
apiGroup.GET("/staff/suggest", controller.NewStaff().Suggest)
|
apiGroup.GET("/staff/suggest", controller.NewStaff().Suggest)
|
||||||
apiGroup.POST("/staff/pay", controller.NewStaff().Pay)
|
apiGroup.POST("/staff/pay", controller.NewStaff().Pay)
|
||||||
|
|
|
@ -426,3 +426,70 @@ func (s *StaffSalary) toExcel(filePath string, header []string, datas [][]string
|
||||||
ctx.Writer.Header().Add("Content-Type", "application/msexcel")
|
ctx.Writer.Header().Add("Content-Type", "application/msexcel")
|
||||||
ctx.File(filePath)
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue