Browse Source

add:绩效管理

zoie 3 ngày trước cách đây
mục cha
commit
8b734ad5f4

+ 1 - 1
conf/app.conf

@@ -24,7 +24,7 @@ Redis_dbNum = "1"
 
 # 路由排除信息
 FilterExcludeURL =
-FilterOnlyLoginCheckURL =
+FilterOnlyLoginCheckURL = "/PerformanceTarget/List"
 
 # 静态资源
 Qiniu_AccessKey = -8ezB_d-8-eUFTMvhOGbGzgeQRPeKQnaQ3DBcUxo

+ 78 - 44
controllers/Performance.go

@@ -807,11 +807,11 @@ func (c *PerformanceController) GetPerformanceDetail() {
 }
 
 func Cron_Percentage() {
-
+	time.Sleep(10 * time.Second) // 等待10秒,确保数据库初始化完成
 	//创建一个定时任务对象
 	c := cron.New(cron.WithSeconds())
-	//给对象增加定时任务 - 改为每月1日凌晨0点0分执行
-	c.AddFunc("0 0 1 * *", SyncVerifyPercentage)
+	//给对象增加定时任务 - 测试用:每分钟执行一次
+	c.AddFunc("0 0 1 * *", SyncVerifyPercentage) // 生产环境:每月1日凌晨0点0分执行
 
 	//启动定时任务
 	c.Start()
@@ -822,20 +822,23 @@ func Cron_Percentage() {
 
 }
 
-func SyncVerifyPercentage() {
-	urls := "/openapi/task/list"
-	signature, timestamp := lib.GenColdVerifySignature()
-
-	// 构建请求数据
-	var start_time, end_time string
+// VerifyTaskResponse 冷链验证任务响应结构
+type VerifyTaskResponse struct {
+	Data []Performance.VerifyTask
+	Code int64
+	Msg  string
+}
 
-	start_time = lib.GetFirstDayOfLastMonth() + " 00:00:00"
-	end_time = lib.GetLastDayOfLastMonth() + " 23:59:59"
+// buildVerifyRequest 构建冷链验证请求并处理响应
+func GetTaskList(startTime, endTime, requestType string) (*VerifyTaskResponse, error) {
+	urls := "/openapi/task/list2"
+	signature, timestamp := lib.GenColdVerifySignature()
 
 	// 使用标准HTTP库替换resty
 	formData := url.Values{}
-	formData.Set("T_reporting_pass_start_time", start_time)
-	formData.Set("T_reporting_pass_end_time", end_time)
+	formData.Set("T_start_time", startTime)
+	formData.Set("T_end_time", endTime)
+	formData.Set("T_type", requestType)
 	formData.Set("X-API-KEY", lib.ColdVerify_OpenApi_Key)
 	formData.Set("X-API-SIGNATURE", signature)
 	formData.Set("X-API-TIMESTAMP", timestamp)
@@ -843,26 +846,26 @@ func SyncVerifyPercentage() {
 	// 构建完整URL
 	fullURL := conf.ColdVerify_OpenApi_Host + urls
 
-	// 创建HTTP客户端
-	client := &http.Client{
-		Timeout: 30 * time.Second,
-	}
-
 	// 创建POST请求
 	req, err := http.NewRequest("POST", fullURL, strings.NewReader(formData.Encode()))
 	if err != nil {
 		logs.Error("创建HTTP请求失败: %v", err)
-		return
+		return nil, err
 	}
 
 	// 设置请求头
 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 
+	// 创建HTTP客户端
+	client := &http.Client{
+		Timeout: 30 * time.Second,
+	}
+
 	// 发送请求
 	resp, err := client.Do(req)
 	if err != nil {
 		logs.Error("请求冷链验证任务列表接口失败: %v", err)
-		return
+		return nil, err
 	}
 	defer resp.Body.Close()
 
@@ -870,54 +873,87 @@ func SyncVerifyPercentage() {
 	body, err := io.ReadAll(resp.Body)
 	if err != nil {
 		logs.Error("读取响应体失败: %v", err)
-		return
+		return nil, err
 	}
 
 	// 检查响应状态码
 	if resp.StatusCode != http.StatusOK {
 		logs.Error("请求冷链验证任务列表接口失败,状态码: %d", resp.StatusCode)
-		return
+		return nil, fmt.Errorf("请求失败,状态码: %d", resp.StatusCode)
 	}
 
 	// 解析响应
-	type R_JSONS struct {
-		//必须的大写开头
-		Data []Performance.VerifyTask
-		Code int64
-		Msg  string
-	}
-	var res R_JSONS
+	var res VerifyTaskResponse
 	if err = json.Unmarshal(body, &res); err != nil {
 		logs.Error("解析响应数据失败: %v", err)
-		return
+		return nil, err
 	}
 
+	return &res, nil
+}
+
+// processWorkloadStats 处理工作量统计逻辑
+func processWorkloadStats(res *VerifyTaskResponse, workType string) map[string]map[int]int {
 	pointsMap := GetPerformancePointsMap()
 	coldVerifyUUIDMap := GetColdVerifyUUIDMap()
 
-	// 分别为报告编写人员和数据采集人员创建统计映射
-	reportingStat := map[string]map[int]int{}  // 报告编写人员统计
-	collectionStat := map[string]map[int]int{} // 数据采集人员统计
+	// 创建统计映射
+	stat := map[string]map[int]int{}
 
-	// 遍历所有任务,分别统计报告编写人员和数据采集人员的工作量
+	// 遍历所有任务,统计指定类型的工作量
 	for _, task := range res.Data {
 		verifyItem := GetPerformancePoints(Performance.DeviceTypeMap[task.T_device_type], task.T_verify_type, pointsMap)
 		if verifyItem.Id == 0 {
 			continue
 		}
-		// 报告编写人员统计
-		reportingUserUUID := coldVerifyUUIDMap[task.T_reporting]
-		if reportingUserUUID != "" {
-			updateWorkloadStat(reportingStat, reportingUserUUID, verifyItem.Id)
+
+		var userUUID string
+		if workType == "reporting" {
+			// 报告编写人员统计
+			userUUID = coldVerifyUUIDMap[task.T_reporting]
+		} else if workType == "collection" {
+			// 数据采集人员统计
+			userUUID = coldVerifyUUIDMap[task.T_collection]
 		}
 
-		// 数据采集人员统计
-		collectionUserUUID := coldVerifyUUIDMap[task.T_collection]
-		if collectionUserUUID != "" {
-			updateWorkloadStat(collectionStat, collectionUserUUID, verifyItem.Id)
+		if userUUID != "" {
+			updateWorkloadStat(stat, userUUID, verifyItem.Id)
 		}
 	}
+
+	return stat
+}
+
+func SyncVerifyPercentage() {
+	// 构建请求数据
+	start_time := lib.GetFirstDayOfLastMonth() + " 00:00:00"
+	end_time := lib.GetLastDayOfLastMonth() + " 23:59:59"
+
+	// 请求报告编写类型的数据
+	reportingRes, err := GetTaskList(start_time, end_time, "reporting")
+	if err != nil {
+		logs.Error("请求报告编写任务列表失败: %v", err)
+		return
+	}
+
+	// 请求数据采集类型的数据
+	collectionRes, err := GetTaskList(start_time, end_time, "collection")
+	if err != nil {
+		logs.Error("请求数据采集任务列表失败: %v", err)
+		return
+	}
+
+	// 初始化绩效目标
 	Performance.Read_PerformanceTarget_All_Map()
+	userList, _ := NatsServer.Read_User_List_All()
+	Account.Read_User_All_Map(userList)
+
+	// 处理报告编写人员统计
+	reportingStat := processWorkloadStats(reportingRes, "reporting")
+
+	// 处理数据采集人员统计
+	collectionStat := processWorkloadStats(collectionRes, "collection")
+
 	// 保存统计结果到数据库
 	saveReportingStatsToDB(reportingStat, "reporting")
 	saveCollectionStatsToDB(collectionStat, "collection")
@@ -973,7 +1009,6 @@ func saveReportingStatsToDB(stat map[string]map[int]int, workType string) {
 					T_points_numerator:      pointsInfo.T_points_numerator,
 					T_points_denominator:    pointsInfo.T_points_denominator,
 					T_type:                  workType,
-					T_remark:                fmt.Sprintf("报告编写工作量统计: %d项", count),
 				}
 				pointList = append(pointList, point)
 			}
@@ -1038,7 +1073,6 @@ func saveCollectionStatsToDB(stat map[string]map[int]int, workType string) {
 					T_points_numerator:      pointsInfo.T_points_numerator,
 					T_points_denominator:    pointsInfo.T_points_denominator,
 					T_type:                  workType,
-					T_remark:                fmt.Sprintf("数据采集工作量统计: %d项", count),
 				}
 				pointList = append(pointList, point)
 			}

+ 1 - 0
main.go

@@ -57,6 +57,7 @@ func main() {
 	beego.BConfig.WebConfig.AutoRender = false
 	beego.BConfig.RecoverPanic = true
 	beego.BConfig.RecoverFunc = RecoverPanic
+	//go controllers.SyncVerifyPercentage()
 	go controllers.Cron_Percentage()
 	beego.Run()
 

+ 7 - 6
models/Performance/PerformanceTarget.go

@@ -1,11 +1,12 @@
 package Performance
 
 import (
+	db "ERP_salary/initialize"
 	"ERP_salary/logs"
-	"github.com/beego/beego/v2/adapter/orm"
-	"gogs.baozhida.cn/zoie/ERP_libs/lib"
 	"sync"
 	"time"
+
+	"gogs.baozhida.cn/zoie/ERP_libs/lib"
 )
 
 // 绩效点
@@ -37,18 +38,18 @@ func init() {
 func Read_PerformanceTarget_All_Map() {
 	logs.Println("=========== 初始化考核指标 =========")
 
-	o := orm.NewOrm()
 	var r []PerformanceTarget
-	qs := o.QueryTable(new(PerformanceTarget))
-	_, err := qs.Filter("T_State", 1).All(&r)
+	err := db.DB.Model(&PerformanceTarget{}).
+		Where("t__state = ?", 1).
+		Find(&r).Error
 	if err != nil {
 		logs.Error(lib.FuncName(), err)
+		return
 	}
 
 	for _, v := range r {
 		PerformanceTarget_list.Store(v.Id, v)
 	}
-
 }
 func Read_PerformanceTarget_Get(Id int) PerformanceTarget {
 	v, ok := PerformanceTarget_list.Load(Id)

+ 37 - 0
services/Performance.go

@@ -9,6 +9,7 @@ import (
 	"errors"
 
 	"gogs.baozhida.cn/zoie/ERP_libs/lib"
+	"gorm.io/gorm"
 )
 
 type Performance struct {
@@ -126,6 +127,42 @@ func (e *Performance) InsertFromStats(perf *models.Perf, pointList []models.Perf
 		}
 	}()
 
+	// 查询是否存在相同 T_submit 和 T_date 的记录
+	var existingPerf models.Perf
+	queryErr := tx.Model(&models.Perf{}).
+		Scopes(dto.WithNormalState()).
+		Where("t_submit = ? AND t_date = ?", perf.T_submit, perf.T_date).
+		First(&existingPerf).Error
+
+	// 如果找到了记录,先删除(软删除)
+	if queryErr == nil && existingPerf.Id > 0 {
+		// 软删除绩效主记录
+		err = tx.Model(&models.Perf{}).
+			Where("id = ?", existingPerf.Id).
+			Update("t__state", 0).Error
+		if err != nil {
+			logs.Error("删除旧绩效主记录失败: %s", err)
+			return
+		}
+
+		// 软删除关联的绩效点记录
+		err = tx.Model(&models.PerfPoint{}).
+			Where("t_performance_id = ?", existingPerf.Id).
+			Update("t__state", 0).Error
+		if err != nil {
+			logs.Error("删除旧绩效点记录失败: %s", err)
+			return
+		}
+
+		logs.Println("已删除旧记录 - 用户: %s, 日期: %s, ID: %d", perf.T_submit, perf.T_date, existingPerf.Id)
+	}
+	// 如果是查询错误(不是记录不存在的错误),则返回错误
+	if queryErr != nil && !errors.Is(queryErr, gorm.ErrRecordNotFound) {
+		logs.Error("查询已存在记录失败: %s", queryErr)
+		err = queryErr
+		return
+	}
+
 	// 创建绩效主记录
 	err = tx.Create(perf).Error
 	if err != nil {

+ 9 - 9
services/PerformanceTarget.go

@@ -67,14 +67,14 @@ func (e *PerformanceTarget) Insert(c *dto.PerformanceTargetInsertReq) (id int, e
 
 // 修改
 func (e *PerformanceTarget) Update(c *dto.PerformanceTargetUpdateReq) error {
-	var PerformanceTarget = models.PerformanceTarget{}
-	err := db.DB.Scopes(dto.WithNormalState()).First(&PerformanceTarget, c.GetId()).Error
+	var performanceTarget = models.PerformanceTarget{}
+	err := db.DB.Scopes(dto.WithNormalState()).First(&performanceTarget, c.GetId()).Error
 	if err != nil {
 		logs.Error("db error: %s", err)
 		return dto.GetNotFoundErr
 	}
-	c.Generate(&PerformanceTarget)
-	err = db.DB.Save(&PerformanceTarget).Error
+	c.Generate(&performanceTarget)
+	err = db.DB.Save(&performanceTarget).Error
 	if err != nil {
 		logs.Error("db error: %s", err)
 		return dto.UpdateFailedErr
@@ -85,8 +85,8 @@ func (e *PerformanceTarget) Update(c *dto.PerformanceTargetUpdateReq) error {
 
 // 删除
 func (e *PerformanceTarget) Delete(c *dto.PerformanceTargetDeleteReq) error {
-	var PerformanceTarget = models.PerformanceTarget{}
-	err := db.DB.Scopes(dto.WithNormalState()).First(&PerformanceTarget, c.GetId()).Error
+	var performanceTarget = models.PerformanceTarget{}
+	err := db.DB.Scopes(dto.WithNormalState()).First(&performanceTarget, c.GetId()).Error
 	if err != nil {
 		logs.Error("db error: %s", err)
 		return dto.GetNotFoundErr
@@ -95,7 +95,7 @@ func (e *PerformanceTarget) Delete(c *dto.PerformanceTargetDeleteReq) error {
 	var ServiceItemCount int64
 	err = db.DB.Model(&models.PerformanceTarget{}).
 		Scopes(dto.WithNormalState()).
-		Where("t_service_type_id = ?", PerformanceTarget.Id).
+		Where("t_service_type_id = ?", performanceTarget.Id).
 		Count(&ServiceItemCount).Error
 	if err != nil {
 		logs.Error("db error: %s", err)
@@ -106,8 +106,8 @@ func (e *PerformanceTarget) Delete(c *dto.PerformanceTargetDeleteReq) error {
 		return errors.New("存在已关联的服务内容,无法删除!")
 	}
 
-	PerformanceTarget.T_State = 0
-	err = db.DB.Save(&PerformanceTarget).Error
+	performanceTarget.T_State = 0
+	err = db.DB.Save(&performanceTarget).Error
 	if err != nil {
 		logs.Error(lib.FuncName(), err)
 		return dto.DeleteFailedErr