package opsdev import ( "context" "fmt" "time" "dashoo.cn/opms_libary/myerrors" opsdevmodel "dashoo.cn/opms_parent/app/model/opsdev" "dashoo.cn/opms_parent/app/service" "github.com/gogf/gf/frame/g" ) // rawHourRow UNION ALL 查询返回的中间行 type rawHourRow struct { OpsUserId int OpsUserName string WorkDate string OpHour float64 RdHour float64 } // WorkHourStatService 工时统计服务 type WorkHourStatService struct { *service.ContextService } // NewWorkHourStatService 创建工时统计服务实例 func NewWorkHourStatService(ctx context.Context) (svc *WorkHourStatService, err error) { svc = new(WorkHourStatService) if svc.ContextService, err = svc.Init(ctx); err != nil { return nil, err } return svc, nil } // GetStat 获取工时统计 func (s *WorkHourStatService) GetStat(req *opsdevmodel.WorkHourStatReq) (*opsdevmodel.WorkHourStatRsp, error) { startDate, err := time.Parse("2006-01-02", req.StartDate) if err != nil { return nil, myerrors.TipsError("开始日期格式错误: " + err.Error()) } endDate, err := time.Parse("2006-01-02", req.EndDate) if err != nil { return nil, myerrors.TipsError("结束日期格式错误: " + err.Error()) } var allDates []string var dayHeaders []opsdevmodel.DayHeader weekdayNames := []string{"周日", "周一", "周二", "周三", "周四", "周五", "周六"} for d := startDate; !d.After(endDate); d = d.AddDate(0, 0, 1) { dateStr := d.Format("2006-01-02") allDates = append(allDates, dateStr) label := d.Format("01-02") if req.Mode == "week" { label = weekdayNames[d.Weekday()] } dayHeaders = append(dayHeaders, opsdevmodel.DayHeader{ Label: label, Date: dateStr, }) } unionSQL := fmt.Sprintf(` SELECT ops_user_id, ops_user_name, DATE(work_date) AS work_date, SUM(work_hour) AS op_hour, 0.0 AS rd_hour FROM ops_operation_work_hour WHERE work_date >= ? AND work_date <= ? AND deleted_time IS NULL GROUP BY ops_user_id, ops_user_name, DATE(work_date) UNION ALL SELECT ops_user_id, ops_user_name, DATE(actual_work_date) AS work_date, 0.0 AS op_hour, SUM(actual_work_hour) AS rd_hour FROM ops_event_task_work_hour WHERE actual_work_date >= ? AND actual_work_date <= ? AND deleted_time IS NULL GROUP BY ops_user_id, ops_user_name, DATE(actual_work_date) `) startDT := req.StartDate + " 00:00:00" endDT := req.EndDate + " 23:59:59" var rawRows []rawHourRow if err := g.DB(s.Tenant).GetScan(&rawRows, unionSQL, startDT, endDT, startDT, endDT); err != nil { return nil, myerrors.TipsError("查询工时数据失败: " + err.Error()) } type personAgg struct { OpsUserId int OpsUserName string DailyHours map[string]opsdevmodel.DayData } personMap := make(map[int]*personAgg) for i := range rawRows { row := &rawRows[i] p, ok := personMap[row.OpsUserId] if !ok { p = &personAgg{ OpsUserId: row.OpsUserId, OpsUserName: row.OpsUserName, DailyHours: make(map[string]opsdevmodel.DayData), } personMap[row.OpsUserId] = p } dd := p.DailyHours[row.WorkDate] dd.OpHour += row.OpHour dd.RdHour += row.RdHour p.DailyHours[row.WorkDate] = dd } var persons []opsdevmodel.PersonRow for _, p := range personMap { if len(req.UserIds) > 0 { found := false for _, uid := range req.UserIds { if uid == p.OpsUserId { found = true break } } if !found { continue } } dailyHours := make(map[string]opsdevmodel.DayData) var totalOp, totalRd float64 for _, dateStr := range allDates { dd := p.DailyHours[dateStr] dailyHours[dateStr] = dd totalOp += dd.OpHour totalRd += dd.RdHour } persons = append(persons, opsdevmodel.PersonRow{ UserId: p.OpsUserId, UserName: p.OpsUserName, DailyHours: dailyHours, TotalOpHour: totalOp, TotalRdHour: totalRd, }) } return &opsdevmodel.WorkHourStatRsp{ Header: dayHeaders, Persons: persons, }, nil }