From a5435e6664093cd4b2ead49409cb41e301e46514 Mon Sep 17 00:00:00 2001
From: liujiandao <274878379@qq.com>
Date: 星期二, 30 四月 2024 14:07:04 +0800
Subject: [PATCH] 薪资计算2

---
 task/salary_statistics.go                     |   52 +++-
 controllers/response/report_forms_response.go |   19 +
 controllers/report_forms_controller.go        |   50 +++-
 controllers/salary_plan_controller.go         |    1 
 task/task_init.go                             |   17 +
 go.mod                                        |    4 
 docs/swagger.yaml                             |   87 +++++++
 docs/docs.go                                  |  132 ++++++++++
 docs/swagger.json                             |  132 ++++++++++
 controllers/request/report_forms_request.go   |    3 
 models/salary_report_form.go                  |   29 +
 go.sum                                        |   19 +
 models/db.go                                  |    3 
 main.go                                       |    5 
 models/salary_details.go                      |   10 
 models/lock.go                                |  115 +++++++++
 16 files changed, 625 insertions(+), 53 deletions(-)

diff --git a/controllers/report_forms_controller.go b/controllers/report_forms_controller.go
index b00be87..42d20ff 100644
--- a/controllers/report_forms_controller.go
+++ b/controllers/report_forms_controller.go
@@ -2,6 +2,11 @@
 
 import (
 	"github.com/gin-gonic/gin"
+	"silkserver/controllers/request"
+	"silkserver/controllers/response"
+	"silkserver/extend/code"
+	"silkserver/extend/util"
+	"silkserver/models"
 )
 
 type ReportFormsController struct {
@@ -14,19 +19,38 @@
 //	@Produce	application/json
 //	@Param		object	body		request.SalaryReportForms	true	"鍙傛暟"
 //	@Param     	Authorization	header string true "token"
-//	@Success	200		{object}	util.ResponseList{data=[]models.WorkTypeManage}		"鎴愬姛"
+//	@Success	200		{object}	util.ResponseList{data=[]response.SalaryReportForms}		"鎴愬姛"
 //	@Router		/api-jl/v1/forms/salaryReportForms [post]
 func (slf ReportFormsController) SalaryReportForms(c *gin.Context) {
-	//var params request.SalaryReportForms
-	//err := c.BindJSON(&params)
-	//if err != nil {
-	//	util.ResponseFormat(c, code.RequestParamError, "鍙傛暟瑙f瀽澶辫触锛屾暟鎹被鍨嬮敊璇�")
-	//	return
-	//}
-	//workers, err := models.NewWorkerSearch().SetPage(params.Page, params.PageSize).FindNotTotal()
-	//if err != nil {
-	//	util.ResponseFormat(c, code.RequestParamError, err)
-	//	return
-	//}
-
+	var params request.SalaryReportForms
+	err := c.BindJSON(&params)
+	if err != nil {
+		util.ResponseFormat(c, code.RequestParamError, "鍙傛暟瑙f瀽澶辫触锛屾暟鎹被鍨嬮敊璇�")
+		return
+	}
+	reportForms, total, err := models.NewSalaryReportFormSearch().SetPage(params.Page, params.PageSize).SetKeyword(params.Keyword).SetPreload(true).Find()
+	if err != nil {
+		util.ResponseFormat(c, code.RequestParamError, err)
+		return
+	}
+	data := make([]response.SalaryReportForms, 0)
+	for _, form := range reportForms {
+		var srf response.SalaryReportForms
+		srf.WorkerId = form.WorkerId
+		srf.WorkerName = form.WorkerName
+		srf.Phone = form.Phone
+		srf.IssueSalary = form.IssueSalary
+		srf.Remark = form.Remark
+		srf.WorkType = form.WorkType.WorkName
+		salaryDetails := make([]response.SalaryDetail, 0)
+		for _, detail := range form.Details {
+			var sd response.SalaryDetail
+			sd.SalaryTypeId = detail.SalaryTypeId
+			sd.SalaryType = detail.SalaryType.Name
+			sd.Amount = detail.Amount
+			salaryDetails = append(salaryDetails, sd)
+		}
+		srf.Details = salaryDetails
+	}
+	util.ResponseFormatList(c, code.Success, data, total)
 }
diff --git a/controllers/request/report_forms_request.go b/controllers/request/report_forms_request.go
index 6ce2f3d..399ade5 100644
--- a/controllers/request/report_forms_request.go
+++ b/controllers/request/report_forms_request.go
@@ -2,5 +2,6 @@
 
 type SalaryReportForms struct {
 	PageInfo
-	Month string `json:"month"`
+	Month   string `json:"month"`
+	Keyword string `json:"keyword"`
 }
diff --git a/controllers/response/report_forms_response.go b/controllers/response/report_forms_response.go
index 598df6e..3c4b8bc 100644
--- a/controllers/response/report_forms_response.go
+++ b/controllers/response/report_forms_response.go
@@ -1,8 +1,19 @@
 package response
 
+import "github.com/shopspring/decimal"
+
 type SalaryReportForms struct {
-	WorkerName string `json:"workerName"`
-	WorkerId   string `json:"workerId"`
-	Phone      string `json:"phone"`
-	WorkType   string `json:"workType"`
+	WorkerName  string          `json:"workerName"`
+	WorkerId    string          `json:"workerId"`
+	Phone       string          `json:"phone"`
+	WorkType    string          `json:"workType"`    //宸ョ
+	IssueSalary decimal.Decimal `json:"issueSalary"` //搴斿彂宸ヨ祫
+	Remark      string          `json:"remark"`      //澶囨敞
+	Details     []SalaryDetail  `json:"details"`
+}
+
+type SalaryDetail struct {
+	SalaryTypeId uint            `json:"salaryTypeId"` //钖祫绫诲瀷id
+	SalaryType   string          `json:"salaryType"`   //钖祫绫诲瀷
+	Amount       decimal.Decimal `json:"amount"`       //宸ヨ祫鍊�
 }
diff --git a/controllers/salary_plan_controller.go b/controllers/salary_plan_controller.go
index 02109c9..0212979 100644
--- a/controllers/salary_plan_controller.go
+++ b/controllers/salary_plan_controller.go
@@ -153,6 +153,7 @@
 				}
 				break
 			} else if value.Id == mini.ID {
+				dict.ID = mini.ID
 				update = append(update, &dict)
 				flag = false
 				if i < len(dicts)-1 {
diff --git a/docs/docs.go b/docs/docs.go
index 2a40518..e1824a3 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -800,6 +800,58 @@
                 }
             }
         },
+        "/api-jl/v1/forms/salaryReportForms": {
+            "post": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "鎶ヨ〃绠$悊"
+                ],
+                "summary": "钖祫鎶ヨ〃",
+                "parameters": [
+                    {
+                        "description": "鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.SalaryReportForms"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "token",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "鎴愬姛",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/util.ResponseList"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/response.SalaryReportForms"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "/api-jl/v1/mentor/createMentorInfo": {
             "post": {
                 "produces": [
@@ -2474,6 +2526,9 @@
                 "overTimeDuration": {
                     "type": "number"
                 },
+                "phoneNum": {
+                    "type": "string"
+                },
                 "startWorkTime": {
                     "type": "string"
                 },
@@ -2936,10 +2991,14 @@
                     "type": "string"
                 },
                 "salaryFormula": {
+                    "description": "SalaryType    string            ` + "`" + `json:\"salaryType\" gorm:\"type:varchar(255);comment:钖祫绫诲瀷\"` + "`" + `",
                     "type": "string"
                 },
                 "salaryType": {
-                    "type": "string"
+                    "$ref": "#/definitions/models.MiniDict"
+                },
+                "salaryTypeId": {
+                    "type": "integer"
                 },
                 "updatedAt": {
                     "type": "string"
@@ -3748,6 +3807,25 @@
                 }
             }
         },
+        "request.SalaryReportForms": {
+            "type": "object",
+            "properties": {
+                "keyword": {
+                    "type": "string"
+                },
+                "month": {
+                    "type": "string"
+                },
+                "page": {
+                    "description": "椤电爜",
+                    "type": "integer"
+                },
+                "pageSize": {
+                    "description": "姣忛〉澶у皬",
+                    "type": "integer"
+                }
+            }
+        },
         "request.SalaryType": {
             "type": "object",
             "properties": {
@@ -3770,6 +3848,9 @@
         "request.SalaryTypeValue": {
             "type": "object",
             "properties": {
+                "id": {
+                    "type": "integer"
+                },
                 "isDefault": {
                     "description": "鏄惁鍙紪杈�",
                     "type": "boolean"
@@ -4338,6 +4419,55 @@
                 }
             }
         },
+        "response.SalaryDetail": {
+            "type": "object",
+            "properties": {
+                "amount": {
+                    "description": "宸ヨ祫鍊�",
+                    "type": "number"
+                },
+                "salaryType": {
+                    "description": "钖祫绫诲瀷",
+                    "type": "string"
+                },
+                "salaryTypeId": {
+                    "description": "钖祫绫诲瀷id",
+                    "type": "integer"
+                }
+            }
+        },
+        "response.SalaryReportForms": {
+            "type": "object",
+            "properties": {
+                "details": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/response.SalaryDetail"
+                    }
+                },
+                "issueSalary": {
+                    "description": "搴斿彂宸ヨ祫",
+                    "type": "number"
+                },
+                "phone": {
+                    "type": "string"
+                },
+                "remark": {
+                    "description": "澶囨敞",
+                    "type": "string"
+                },
+                "workType": {
+                    "description": "宸ョ",
+                    "type": "string"
+                },
+                "workerId": {
+                    "type": "string"
+                },
+                "workerName": {
+                    "type": "string"
+                }
+            }
+        },
         "util.Response": {
             "type": "object",
             "properties": {
diff --git a/docs/swagger.json b/docs/swagger.json
index 60235c7..4fd364b 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -788,6 +788,58 @@
                 }
             }
         },
+        "/api-jl/v1/forms/salaryReportForms": {
+            "post": {
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "鎶ヨ〃绠$悊"
+                ],
+                "summary": "钖祫鎶ヨ〃",
+                "parameters": [
+                    {
+                        "description": "鍙傛暟",
+                        "name": "object",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/request.SalaryReportForms"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "description": "token",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "鎴愬姛",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/util.ResponseList"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "type": "array",
+                                            "items": {
+                                                "$ref": "#/definitions/response.SalaryReportForms"
+                                            }
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "/api-jl/v1/mentor/createMentorInfo": {
             "post": {
                 "produces": [
@@ -2462,6 +2514,9 @@
                 "overTimeDuration": {
                     "type": "number"
                 },
+                "phoneNum": {
+                    "type": "string"
+                },
                 "startWorkTime": {
                     "type": "string"
                 },
@@ -2924,10 +2979,14 @@
                     "type": "string"
                 },
                 "salaryFormula": {
+                    "description": "SalaryType    string            `json:\"salaryType\" gorm:\"type:varchar(255);comment:钖祫绫诲瀷\"`",
                     "type": "string"
                 },
                 "salaryType": {
-                    "type": "string"
+                    "$ref": "#/definitions/models.MiniDict"
+                },
+                "salaryTypeId": {
+                    "type": "integer"
                 },
                 "updatedAt": {
                     "type": "string"
@@ -3736,6 +3795,25 @@
                 }
             }
         },
+        "request.SalaryReportForms": {
+            "type": "object",
+            "properties": {
+                "keyword": {
+                    "type": "string"
+                },
+                "month": {
+                    "type": "string"
+                },
+                "page": {
+                    "description": "椤电爜",
+                    "type": "integer"
+                },
+                "pageSize": {
+                    "description": "姣忛〉澶у皬",
+                    "type": "integer"
+                }
+            }
+        },
         "request.SalaryType": {
             "type": "object",
             "properties": {
@@ -3758,6 +3836,9 @@
         "request.SalaryTypeValue": {
             "type": "object",
             "properties": {
+                "id": {
+                    "type": "integer"
+                },
                 "isDefault": {
                     "description": "鏄惁鍙紪杈�",
                     "type": "boolean"
@@ -4326,6 +4407,55 @@
                 }
             }
         },
+        "response.SalaryDetail": {
+            "type": "object",
+            "properties": {
+                "amount": {
+                    "description": "宸ヨ祫鍊�",
+                    "type": "number"
+                },
+                "salaryType": {
+                    "description": "钖祫绫诲瀷",
+                    "type": "string"
+                },
+                "salaryTypeId": {
+                    "description": "钖祫绫诲瀷id",
+                    "type": "integer"
+                }
+            }
+        },
+        "response.SalaryReportForms": {
+            "type": "object",
+            "properties": {
+                "details": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/response.SalaryDetail"
+                    }
+                },
+                "issueSalary": {
+                    "description": "搴斿彂宸ヨ祫",
+                    "type": "number"
+                },
+                "phone": {
+                    "type": "string"
+                },
+                "remark": {
+                    "description": "澶囨敞",
+                    "type": "string"
+                },
+                "workType": {
+                    "description": "宸ョ",
+                    "type": "string"
+                },
+                "workerId": {
+                    "type": "string"
+                },
+                "workerName": {
+                    "type": "string"
+                }
+            }
+        },
         "util.Response": {
             "type": "object",
             "properties": {
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 7d4e568..da4f0f1 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -162,6 +162,8 @@
         type: integer
       overTimeDuration:
         type: number
+      phoneNum:
+        type: string
       startWorkTime:
         type: string
       status:
@@ -477,9 +479,12 @@
       name:
         type: string
       salaryFormula:
+        description: SalaryType    string            `json:"salaryType" gorm:"type:varchar(255);comment:钖祫绫诲瀷"`
         type: string
       salaryType:
-        type: string
+        $ref: '#/definitions/models.MiniDict'
+      salaryTypeId:
+        type: integer
       updatedAt:
         type: string
       workTypes:
@@ -1032,6 +1037,19 @@
         description: 寮�濮嬬氦搴�
         type: number
     type: object
+  request.SalaryReportForms:
+    properties:
+      keyword:
+        type: string
+      month:
+        type: string
+      page:
+        description: 椤电爜
+        type: integer
+      pageSize:
+        description: 姣忛〉澶у皬
+        type: integer
+    type: object
   request.SalaryType:
     properties:
       type:
@@ -1045,6 +1063,8 @@
     type: object
   request.SalaryTypeValue:
     properties:
+      id:
+        type: integer
       isDefault:
         description: 鏄惁鍙紪杈�
         type: boolean
@@ -1445,6 +1465,40 @@
       startFineness:
         description: 寮�濮嬬氦搴�
         type: number
+    type: object
+  response.SalaryDetail:
+    properties:
+      amount:
+        description: 宸ヨ祫鍊�
+        type: number
+      salaryType:
+        description: 钖祫绫诲瀷
+        type: string
+      salaryTypeId:
+        description: 钖祫绫诲瀷id
+        type: integer
+    type: object
+  response.SalaryReportForms:
+    properties:
+      details:
+        items:
+          $ref: '#/definitions/response.SalaryDetail'
+        type: array
+      issueSalary:
+        description: 搴斿彂宸ヨ祫
+        type: number
+      phone:
+        type: string
+      remark:
+        description: 澶囨敞
+        type: string
+      workType:
+        description: 宸ョ
+        type: string
+      workerId:
+        type: string
+      workerName:
+        type: string
     type: object
   util.Response:
     properties:
@@ -1950,6 +2004,37 @@
       summary: 淇濆瓨浜ч噺鐧昏琛�
       tags:
       - 鐢熶骇绠$悊/浜ч噺鐧昏琛�
+  /api-jl/v1/forms/salaryReportForms:
+    post:
+      parameters:
+      - description: 鍙傛暟
+        in: body
+        name: object
+        required: true
+        schema:
+          $ref: '#/definitions/request.SalaryReportForms'
+      - description: token
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: 鎴愬姛
+          schema:
+            allOf:
+            - $ref: '#/definitions/util.ResponseList'
+            - properties:
+                data:
+                  items:
+                    $ref: '#/definitions/response.SalaryReportForms'
+                  type: array
+              type: object
+      summary: 钖祫鎶ヨ〃
+      tags:
+      - 鎶ヨ〃绠$悊
   /api-jl/v1/mentor/createMentorInfo:
     post:
       parameters:
diff --git a/go.mod b/go.mod
index 0b283cf..ed23f5b 100644
--- a/go.mod
+++ b/go.mod
@@ -7,6 +7,7 @@
 	github.com/Knetic/govaluate v3.0.0+incompatible
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/gin-gonic/gin v1.9.1
+	github.com/go-co-op/gocron v1.37.0
 	github.com/golang-jwt/jwt/v4 v4.5.0
 	github.com/nsqio/go-nsq v1.1.0
 	github.com/shopspring/decimal v1.3.1
@@ -45,6 +46,7 @@
 	github.com/goccy/go-json v0.10.2 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/golang/snappy v0.0.1 // indirect
+	github.com/google/uuid v1.6.0 // 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
@@ -62,6 +64,7 @@
 	github.com/pelletier/go-toml/v2 v2.1.0 // indirect
 	github.com/richardlehane/mscfb v1.0.4 // indirect
 	github.com/richardlehane/msoleps v1.0.3 // indirect
+	github.com/robfig/cron/v3 v3.0.1 // indirect
 	github.com/sagikazarmark/locafero v0.4.0 // indirect
 	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
@@ -72,6 +75,7 @@
 	github.com/ugorji/go/codec v1.2.11 // indirect
 	github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 // indirect
 	github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 // indirect
+	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.10.0 // indirect
 	golang.org/x/arch v0.3.0 // indirect
 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
diff --git a/go.sum b/go.sum
index f0f9548..0bf724b 100644
--- a/go.sum
+++ b/go.sum
@@ -31,6 +31,8 @@
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
 github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
+github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY=
 github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
 github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
 github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -62,6 +64,9 @@
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@@ -77,6 +82,8 @@
 github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
 github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -101,12 +108,12 @@
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=
 github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
 github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
 github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
@@ -115,6 +122,10 @@
 github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
 github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
 github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
 github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
@@ -165,6 +176,8 @@
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
@@ -247,8 +260,10 @@
 google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
diff --git a/main.go b/main.go
index b195719..9ff533d 100644
--- a/main.go
+++ b/main.go
@@ -9,6 +9,7 @@
 	"silkserver/models"
 	"silkserver/pkg/logx"
 	"silkserver/router"
+	"silkserver/task"
 	"syscall"
 	"time"
 )
@@ -36,6 +37,10 @@
 		ReadTimeout:  5 * time.Second,
 		WriteTimeout: 5 * time.Second,
 	}
+
+	//瀹氭椂浠诲姟鍒濆鍖�
+	task.Init()
+
 	go shutdown(server)
 	logx.Error(server.ListenAndServe().Error())
 }
diff --git a/models/db.go b/models/db.go
index 9609b84..4226418 100644
--- a/models/db.go
+++ b/models/db.go
@@ -91,6 +91,9 @@
 		AttendanceManage{},
 		WorkerPosition{},
 		AttendanceRule{},
+		SalaryReportForm{},
+		SalaryDetails{},
+		Lock{},
 	)
 	return err
 }
diff --git a/models/lock.go b/models/lock.go
new file mode 100644
index 0000000..5a26fdc
--- /dev/null
+++ b/models/lock.go
@@ -0,0 +1,115 @@
+package models
+
+import (
+	"fmt"
+	"gorm.io/gorm"
+	"silkserver/pkg/mysqlx"
+	"time"
+)
+
+type (
+	// Lock 鍒嗗竷寮忛攣
+	Lock struct {
+		LockName string `gorm:"primaryKey"`
+		LockedBy string
+		LockedAt time.Time
+	}
+
+	LockSearch struct {
+		Lock
+		Orm *gorm.DB
+	}
+)
+
+func (slf *Lock) TableName() string {
+	return "distributed_lock"
+}
+
+func NewLockSearch() *LockSearch {
+	return &LockSearch{Orm: mysqlx.GetDB()}
+}
+
+func (slf *LockSearch) SetOrm(tx *gorm.DB) *LockSearch {
+	slf.Orm = tx
+
+	return slf
+}
+
+func (slf *LockSearch) SetLockName(lockName string) *LockSearch {
+	slf.LockName = lockName
+	return slf
+}
+
+func (slf *LockSearch) SetLockedBy(lockedBy string) *LockSearch {
+	slf.LockedBy = lockedBy
+	return slf
+}
+
+func (slf *LockSearch) build() *gorm.DB {
+	var db = slf.Orm.Model(&Lock{})
+
+	if slf.LockName != "" {
+		db = db.Where("lock_name = ?", slf.LockName)
+	}
+
+	if slf.LockedBy != "" {
+		db = db.Where("locked_by = ?", slf.LockedBy)
+	}
+
+	return db
+}
+
+// Create 鍗曟潯鎻掑叆
+func (slf *LockSearch) Create(record *Lock) error {
+	var db = slf.build()
+
+	if err := db.Create(record).Error; err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (slf *LockSearch) Delete() error {
+	var db = slf.build()
+	return db.Delete(&Lock{}).Error
+}
+
+func (slf *LockSearch) First() (*Lock, error) {
+	var (
+		record = new(Lock)
+		db     = slf.build()
+	)
+
+	if err := db.First(record).Error; err != nil {
+		return record, err
+	}
+
+	return record, nil
+}
+
+func (slf *LockSearch) AcquireLock(lockName, serviceID string) error {
+	err := WithTransaction(func(db *gorm.DB) error {
+		lock, err := slf.SetLockName(lockName).SetLockedBy(serviceID).First()
+		if err != nil && err != gorm.ErrRecordNotFound {
+			return err
+		}
+		if lock.LockedBy != "" {
+			return fmt.Errorf("AcquireLock  failed, lockName: %s, serviceID: %+v", lockName, serviceID)
+		}
+		return slf.Create(&Lock{
+			LockName: lockName,
+			LockedBy: serviceID,
+			LockedAt: time.Now(),
+		})
+	})
+	return err
+}
+
+func (slf *LockSearch) ReleaseLock(lockName, serviceID string) error {
+	err := slf.SetLockName(lockName).SetLockedBy(serviceID).Delete()
+	if err != nil {
+		return fmt.Errorf("AcquireLock  err: %v, lockName: %s, serviceID: %+v", err, lockName, serviceID)
+	}
+	return nil
+}
diff --git a/models/salary_details.go b/models/salary_details.go
index eec1e11..9427d3c 100644
--- a/models/salary_details.go
+++ b/models/salary_details.go
@@ -11,10 +11,10 @@
 	//SalaryDetails 钖祫鏄庣粏琛�
 	SalaryDetails struct {
 		gorm.Model
-		SalaryDetailsId uint            `json:"SalaryDetailsId" gorm:"type:int(11);comment:钖祫鎶ヨ〃id"`
-		SalaryTypeId    uint            `json:"salaryTypeId" gorm:"type:int(11);comment:钖祫绫诲瀷id"`
-		SalaryType      MiniDict        `json:"salaryType" gorm:"foreignKey:SalaryTypeId;references:ID"`
-		Amount          decimal.Decimal `json:"amount" gorm:"type:decimal(20,3);comment:宸ヨ祫鍊�"`
+		SalaryReportFormId uint            `json:"salaryReportFormId" gorm:"type:int(11);not null;comment:钖祫鎶ヨ〃id"`
+		SalaryTypeId       uint            `json:"salaryTypeId" gorm:"type:int(11);comment:钖祫绫诲瀷id"`
+		SalaryType         MiniDict        `json:"salaryType" gorm:"foreignKey:SalaryTypeId;references:ID"`
+		Amount             decimal.Decimal `json:"amount" gorm:"type:decimal(20,3);comment:宸ヨ祫鍊�"`
 	}
 	SalaryDetailsSearch struct {
 		SalaryDetails
@@ -26,7 +26,7 @@
 )
 
 func (slf SalaryDetails) TableName() string {
-	return "salary_details"
+	return "silk_salary_details"
 }
 
 func NewSalaryDetailsSearch() *SalaryDetailsSearch {
diff --git a/models/salary_report_form.go b/models/salary_report_form.go
index 67aa59f..a03738b 100644
--- a/models/salary_report_form.go
+++ b/models/salary_report_form.go
@@ -11,27 +11,28 @@
 	// SalaryReportForm 钖祫鎶ヨ〃
 	SalaryReportForm struct {
 		gorm.Model
-		WorkerId    string          `json:"workerId" gorm:"type:varchar(255);comment:浜哄憳id"`
-		WorkerName  string          `json:"workerName"  gorm:"type:varchar(255);comment:浜哄憳濮撳悕"`
-		Phone       string          `json:"phone" gorm:"type:varchar(255);comment:鐢佃瘽"`
-		WorkTypeId  uint            `json:"workTypeId" gorm:"type:int(11);comment:宸ョ绫诲瀷id"`
-		WorkType    WorkTypeManage  `json:"workType"  gorm:"foreignKey:WorkTypeId;references:ID"`
-		Month       string          `json:"month" gorm:"type:varchar(255);comment:鏈堜唤"`
-		IssueSalary decimal.Decimal `json:"issueSalary" gorm:"type:decimal(20,3);comment:搴斿彂宸ヨ祫"`
-		Remark      string          `json:"remark" gorm:"type:varchar(255);comment:澶囨敞"`
-		Details     []SalaryDetails `json:"details" gorm:"foreignKey:SalaryReportFormId;references:Id"`
+		WorkerId    string           `json:"workerId" gorm:"type:varchar(255);comment:浜哄憳id"`
+		WorkerName  string           `json:"workerName"  gorm:"type:varchar(255);comment:浜哄憳濮撳悕"`
+		Phone       string           `json:"phone" gorm:"type:varchar(255);comment:鐢佃瘽"`
+		WorkTypeId  uint             `json:"workTypeId" gorm:"type:int(11);comment:宸ョ绫诲瀷id"`
+		WorkType    WorkTypeManage   `json:"workType"  gorm:"foreignKey:WorkTypeId;references:ID"`
+		Month       string           `json:"month" gorm:"type:varchar(255);comment:鏈堜唤"`
+		IssueSalary decimal.Decimal  `json:"issueSalary" gorm:"type:decimal(20,3);comment:搴斿彂宸ヨ祫"`
+		Remark      string           `json:"remark" gorm:"type:varchar(255);comment:澶囨敞"`
+		Details     []*SalaryDetails `json:"details" gorm:"foreignKey:SalaryReportFormId"`
 	}
 	SalaryReportFormSearch struct {
 		SalaryReportForm
 		PageNum  int
 		PageSize int
 		Preload  bool
+		Keyword  string
 		Orm      *gorm.DB
 	}
 )
 
 func (slf SalaryReportForm) TableName() string {
-	return "salary_report_form"
+	return "silk_salary_report_form"
 }
 
 func NewSalaryReportFormSearch() *SalaryReportFormSearch {
@@ -53,12 +54,20 @@
 	return slf
 }
 
+func (slf *SalaryReportFormSearch) SetKeyword(keyword string) *SalaryReportFormSearch {
+	slf.Keyword = keyword
+	return slf
+}
+
 func (slf *SalaryReportFormSearch) build() *gorm.DB {
 	var db = slf.Orm.Table(slf.TableName())
 
 	if slf.Preload {
 		db = db.Model(SalaryReportForm{}).Preload("Details").Preload("WorkType")
 	}
+	if slf.Keyword != "" {
+		db = db.Where("worker_name like ? or worker_id like ?", "%"+slf.Keyword+"%", "%"+slf.Keyword+"%")
+	}
 
 	return db
 }
diff --git a/task/salary_statistics.go b/task/salary_statistics.go
index 07e1a1e..254e306 100644
--- a/task/salary_statistics.go
+++ b/task/salary_statistics.go
@@ -11,6 +11,23 @@
 )
 
 func SalaryStatistics() {
+	//鍔犻攣锛屽彧闇�瑕佷竴涓繘绋嬭繍琛屾浠诲姟
+	var (
+		lockName  = "SalaryStatistics"
+		serviceID = "silkServer"
+	)
+	err := models.NewLockSearch().AcquireLock(lockName, serviceID)
+	if err != nil {
+		logx.Errorf("MonthStats AcquireLock err:%v", err)
+		return
+	}
+	defer func() {
+		err := models.NewLockSearch().ReleaseLock(lockName, serviceID)
+		if err != nil {
+			logx.Errorf("MonthStats ReleaseLock err:%v", err)
+		}
+	}()
+
 	lastMonthStart, lastMonthEnd := GetLastMonthPeriod()
 	month := lastMonthStart.Format("2006-01")
 
@@ -24,19 +41,23 @@
 	}
 
 	var reportForms []*models.SalaryReportForm
+	reportMap := make(map[string]*models.SalaryReportForm)
 	workTypeIdMap := make(map[uint]uint)
 	dataMap := make(map[string]utils.SalaryCalculateData)
 	for _, attendance := range attendances {
-		var rf models.SalaryReportForm
+		if _, ok := reportMap[attendance.WorkerId]; !ok {
+			var rf models.SalaryReportForm
+			rf.WorkerId = attendance.WorkerId
+			rf.WorkerName = attendance.WorkerName
+			rf.WorkTypeId = attendance.WorkTypeId
+			rf.Month = month
+			rf.Phone = attendance.PhoneNum
+			reportMap[attendance.WorkerId] = &rf
+		}
 		var data utils.SalaryCalculateData
 		if _, ok := dataMap[attendance.WorkerId]; ok {
 			data = dataMap[attendance.WorkerId]
 		}
-		rf.WorkerId = attendance.WorkerId
-		rf.WorkerName = attendance.WorkerName
-		rf.WorkTypeId = attendance.WorkTypeId
-		rf.Month = month
-		rf.Phone = attendance.PhoneNum
 		if attendance.WorkTypeId > 0 {
 			workTypeIdMap[attendance.WorkTypeId] = attendance.WorkTypeId
 		}
@@ -47,7 +68,9 @@
 			data.TotalAttendanceDays = data.TotalAttendanceDays + 1
 		}
 		dataMap[attendance.WorkerId] = data
-		reportForms = append(reportForms, &rf)
+	}
+	for _, v := range reportMap {
+		reportForms = append(reportForms, v)
 	}
 	workTypeIds := make([]uint, 0)
 	for _, v := range workTypeIdMap {
@@ -61,7 +84,7 @@
 		return
 	}
 	for _, form := range reportForms {
-		details := make([]models.SalaryDetails, 0)
+		details := make([]*models.SalaryDetails, 0)
 		issueSalary := decimal.NewFromInt(0)
 		for _, manage := range workTypeManages {
 			if form.WorkTypeId == manage.ID {
@@ -76,16 +99,15 @@
 						data, err = GetDailySilkProduction(startStr, endStr, form.WorkerId, data)
 						if err != nil {
 							logx.Error("SalaryStatistics 缁熻钖祫鍑洪敊 err: " + err.Error())
-						} else {
-							amount, err = utils.CalculateSalary(data, formula)
-							if err != nil {
-								logx.Error("SalaryStatistics 璁$畻钖祫鍑洪敊 err: " + err.Error())
-							}
 						}
+					}
+					amount, err = utils.CalculateSalary(data, formula)
+					if err != nil {
+						logx.Error("SalaryStatistics 璁$畻钖祫鍑洪敊 err: " + err.Error())
 					}
 					detail.Amount = amount
 					issueSalary = issueSalary.Add(amount)
-					details = append(details, detail)
+					details = append(details, &detail)
 				}
 			}
 		}
@@ -155,7 +177,7 @@
 	//鏌ヨ绾ゅ害鐧昏琛�
 	var fineness []models.FinenessRegister
 	markets := make([]string, 0)
-	err = models.NewFinenessRegisterSearch().Orm.Table("silk_fineness_register").Where("workshop in (?) and workshop_group "+
+	err = models.NewFinenessRegisterSearch().Orm.Table("silk_fineness_register").Where("workshop_number in (?) and workshop_group "+
 		"in (?) and finish_date >= ? and finish_date <= ?", workshops, groups, start, end).Find(&fineness).Error
 	if err != nil {
 		return data, err
diff --git a/task/task_init.go b/task/task_init.go
new file mode 100644
index 0000000..284d37b
--- /dev/null
+++ b/task/task_init.go
@@ -0,0 +1,17 @@
+package task
+
+import (
+	"github.com/go-co-op/gocron"
+	"time"
+)
+
+var s *gocron.Scheduler
+
+func init() {
+	s = gocron.NewScheduler(time.UTC)
+}
+func Init() {
+	s.Every(1).Month().Do(SalaryStatistics) //姣忔湀鍒濇墽琛屼竴娆�
+
+	s.StartAsync()
+}

--
Gitblit v1.8.0