package oa_logic import ( "context" "dubbo.apache.org/dubbo-go/v3/common/logger" "errors" "fmt" "github.com/fonchain_enterprise/fonchain-main/api/oa" "github.com/fonchain_enterprise/fonchain-main/pkg/e" "github.com/fonchain_enterprise/fonchain-main/pkg/model/oa_model" "github.com/fonchain_enterprise/fonchain-main/pkg/service" "github.com/fonchain_enterprise/fonchain-main/pkg/service/oa_new/common" "github.com/fonchain_enterprise/fonchain-main/pkg/service/oa_new/model" "github.com/fonchain_enterprise/fonchain-main/pkg/utils/holiday" "github.com/shopspring/decimal" "github.com/xuri/excelize/v2" "sort" "strings" "time" ) func QueryOaRecordMonth(staffUID uint64, month string, workingTime *oa.WorkingTime) (status bool, allDayLeave []*model.WorkDayDetail, allDayLeaveNum, needAttendanceDayNum, attendanceDayNum, attendanceRestDayNum, attendanceHolidayNum, attendanceWorkDayNum int, workDays []*model.WorkDayDetail, err error) { fmt.Println("================ QueryOaRecordMonth WorkDayMonth enter =======================") oaRecordReq := new(oa.OARecordReq) if month == "" { month = holiday.CurrentMonth() } month = common.Add25ForMonth(month) dates := holiday.SplitMonthV1(month, common.YYMMDD) oaRecordReq.StaffUID = staffUID oaRecordReq.Dates = dates status = true fmt.Printf("oaRecordReq: %v\n", oaRecordReq) if common.IsAfterMonth(dates[len(dates)-1]) { return } holidaysMap, holidaysMapErr := HolidayList(dates) if holidaysMapErr != nil { return false, nil, 0, 0, 0, 0, 0, 0, nil, holidaysMapErr } for _, date := range holidaysMap { if date.Type == 0 { needAttendanceDayNum++ } } fmt.Printf("HolidayList: %v\n", holidaysMap) // 获取考勤记录 oaRecordRes, oaRecordErr := service.GrpcOAImpl.OARecord(context.Background(), oaRecordReq) if oaRecordErr != nil { logger.Errorf("查询考勤记录失败:%s", oaRecordErr.Error()) return false, nil, 0, 0, 0, 0, 0, 0, nil, errors.New(e.ErrorQueryOaProfile) } fmt.Printf("oaRecordRes: %v\n", oaRecordRes) allDayLeave = make([]*model.WorkDayDetail, 0) workDays = make([]*model.WorkDayDetail, 0) for i := 0; i < len(oaRecordRes.Data); i++ { record := oaRecordRes.Data[i] // 当前时间 在 工作时间之前 if common.ConvertWorkDateAndWorkTime(record.WorkDate, "00:00").After(common.CurrentDateTime()) { return } workDay := new(model.WorkDayDetail) workDay.WorkDate = record.WorkDate if record.Week != 0 { workDay.Week = record.Week } else { workDay.Week = int32(holidaysMap[record.WorkDate].WeekDay) } workDay.Weekly = oa_model.WeekZhCN[int8(workDay.Week)] isWork, isWorkDayErr := IsWorkDay(record.WorkDate, workingTime.Week, workingTime.IsWorkDay) if isWorkDayErr != nil { return false, nil, 0, 0, 0, 0, 0, 0, nil, isWorkDayErr } if isWork { workDay.DateType = model.WorkDayType } else { if holidaysMap[record.WorkDate].Type == 2 { workDay.DateType = model.HolidayDayType } else { workDay.DateType = model.WeekendDayType } } if len(record.Records) > 0 { workDay.IsWork = int8(record.IsWork) workDay.WorkTimes = make([]*model.TimeOption, 0) for k := 0; k < len(record.TimeOptions); k++ { workDay.WorkTimes = append(workDay.WorkTimes, &model.TimeOption{ OnWorkTime: record.TimeOptions[k].OnWorkTime, OffWorkTime: record.TimeOptions[k].OffWorkTime, }) } } else { if isWork { for k := 0; k < len(workingTime.Time); k++ { workDay.WorkTimes = append(workDay.WorkTimes, &model.TimeOption{ OnWorkTime: workingTime.Time[k].OnWorkTime, OffWorkTime: workingTime.Time[k].OffWorkTime, }) } workDay.IsWork = model.IsWork workDay.Abnormal = true // 没有打卡记录 则 表示 异常 } else { workDay.IsWork = model.IsFree } } fmt.Println("============================================= makeWorkDayDetail =============================================") fmt.Printf("workDay: %+v\n", workDay) fmt.Printf("record: %+v\n", record) fmt.Println("============================================= makeWorkDayDetail =============================================") if workDay.IsWork == model.IsFree && len(record.Records) == 0 { continue } makeWorkDayDetailErr := makeWorkDayDetailForMonth(staffUID, record, workDay) if makeWorkDayDetailErr != nil { return false, nil, 0, 0, 0, 0, 0, 0, nil, makeWorkDayDetailErr } // 如果 是工作日 且 没有打卡记录 则 表示 异常 if workDay.IsWork == model.IsWork && len(record.Records) == 0 { workDay.Abnormal = true } if workDay.Abnormal == true { status = false } if len(workDay.Records) > 0 { // 如果 全是缺卡 则 不显示 missNum := 0 for j := 0; j < len(workDay.Records); j++ { //if workDay.Records[j].ActionType == oa_model.TypeBefore || workDay.Records[j].ActionType == oa_model.TypeMiss || workDay.Records[j].ActionType == oa_model.TypeLate { // status = false //} if workDay.Records[j].ActionType == oa_model.TypeCommon || workDay.Records[j].ActionType == oa_model.TypeLate || workDay.Records[j].ActionType == oa_model.TypeBefore || workDay.Records[j].ActionType == oa_model.TypeMakeUpSys || workDay.Records[j].ActionType == oa_model.TypeOutWork || workDay.Records[j].ActionType == oa_model.TypeMakeUp || workDay.Records[j].ActionType == oa_model.TypeOverTime || workDay.Records[j].ActionType == oa_model.TypeOutWorkLate || workDay.Records[j].ActionType == oa_model.TypeOutWorkBefore || workDay.Records[j].ActionType == oa_model.TypeGoOut || workDay.Records[j].ActionType == oa_model.TypeBusinessTrip { break } else { missNum++ } } // 缺卡次数 和 打卡次数相等 不 统计 出勤 if missNum == len(workDay.Records) { allDayLeaveNum++ allDayLeave = append(allDayLeave, workDay) } // 出勤天数 if missNum != len(workDay.Records) { attendanceDayNum++ } // 工作日出勤天数 if workDay.DateType == model.WorkDayType && missNum != len(workDay.Records) { attendanceWorkDayNum++ } // 休息日出勤天数 if workDay.DateType == model.WeekendDayType && workDay.IsWork == model.IsFree { attendanceRestDayNum++ } // 节假日出勤天数 if workDay.DateType == model.HolidayDayType && workDay.IsWork == model.IsFree { attendanceHolidayNum++ } workDays = append(workDays, workDay) } } fmt.Println("================ QueryOaRecordMonth WorkDayMonth out =======================") return status, allDayLeave, allDayLeaveNum, needAttendanceDayNum, attendanceDayNum, attendanceRestDayNum, attendanceHolidayNum, attendanceWorkDayNum, workDays, nil } func QueryOaRecordDates(staffUID uint64, dates []string, workingTime *oa.WorkingTime) (status bool, allDayLeave []*model.WorkDayDetail, allDayLeaveNum, needAttendanceDayNum, attendanceDayNum, attendanceRestDayNum, attendanceHolidayNum, attendanceWorkDayNum int, workDays []*model.WorkDayDetail, err error) { fmt.Println("================ QueryOaRecordDates WorkDayDates enter =======================") oaRecordReq := new(oa.OARecordReq) oaRecordReq.StaffUID = staffUID oaRecordReq.Dates = dates status = true //fmt.Printf("oaRecordReq: %v\n", oaRecordReq) holidaysMap, holidaysMapErr := HolidayList(dates) if holidaysMapErr != nil { return false, nil, 0, 0, 0, 0, 0, 0, nil, holidaysMapErr } for _, date := range holidaysMap { if date.Type == 0 { needAttendanceDayNum++ } } //fmt.Printf("HolidayList: %v\n", holidaysMap) // 获取考勤记录 oaRecordRes, oaRecordErr := service.GrpcOAImpl.OARecord(context.Background(), oaRecordReq) if oaRecordErr != nil { logger.Errorf("查询考勤记录失败:%s", oaRecordErr.Error()) return false, nil, 0, 0, 0, 0, 0, 0, nil, errors.New(e.ErrorQueryOaProfile) } //fmt.Printf("oaRecordRes: %v\n", oaRecordRes) allDayLeave = make([]*model.WorkDayDetail, 0) workDays = make([]*model.WorkDayDetail, 0) for i := 0; i < len(oaRecordRes.Data); i++ { record := oaRecordRes.Data[i] // 当前时间 在 工作时间之前 //if common.ConvertWorkDateAndWorkTime(record.WorkDate, "00:00").After(common.CurrentDateTime()) { // return //} workDay := new(model.WorkDayDetail) workDay.WorkDate = record.WorkDate if record.Week != 0 { workDay.Week = record.Week } else { workDay.Week = int32(holidaysMap[record.WorkDate].WeekDay) } workDay.Weekly = oa_model.WeekZhCN[int8(workDay.Week)] isWork, isWorkDayErr := IsWorkDay(record.WorkDate, workingTime.Week, workingTime.IsWorkDay) if isWorkDayErr != nil { return false, nil, 0, 0, 0, 0, 0, 0, nil, isWorkDayErr } if isWork { workDay.DateType = model.WorkDayType } else { if holidaysMap[record.WorkDate].Type == 2 { workDay.DateType = model.HolidayDayType } else { workDay.DateType = model.WeekendDayType } } if len(record.Records) > 0 { workDay.IsWork = int8(record.IsWork) workDay.WorkTimes = make([]*model.TimeOption, 0) for k := 0; k < len(record.TimeOptions); k++ { workDay.WorkTimes = append(workDay.WorkTimes, &model.TimeOption{ OnWorkTime: record.TimeOptions[k].OnWorkTime, OffWorkTime: record.TimeOptions[k].OffWorkTime, }) } } else { if isWork { for k := 0; k < len(workingTime.Time); k++ { workDay.WorkTimes = append(workDay.WorkTimes, &model.TimeOption{ OnWorkTime: workingTime.Time[k].OnWorkTime, OffWorkTime: workingTime.Time[k].OffWorkTime, }) } workDay.IsWork = model.IsWork workDay.Abnormal = true // 没有打卡记录 则 表示 异常 } else { workDay.IsWork = model.IsFree } } makeWorkDayDetailErr := makeWorkDayDetailForDates(staffUID, record, workDay) if makeWorkDayDetailErr != nil { return false, nil, 0, 0, 0, 0, 0, 0, nil, makeWorkDayDetailErr } fmt.Println("============================================= makeWorkDayDetail before =============================================") fmt.Printf("workDay: %+v\n", workDay) fmt.Println("============================================= makeWorkDayDetail before =============================================") if workDay.Abnormal == true { status = false } fmt.Println("============================================= makeWorkDayDetail after =============================================") fmt.Printf("workDay: %+v\n", workDay) fmt.Printf("status: %+v\n", status) fmt.Println("============================================= makeWorkDayDetail after =============================================") if len(workDay.Records) > 0 { // 如果 全是缺卡 则 不显示 missNum := 0 for j := 0; j < len(workDay.Records); j++ { //if workDay.Records[j].ActionType == oa_model.TypeBefore || workDay.Records[j].ActionType == oa_model.TypeMiss || workDay.Records[j].ActionType == oa_model.TypeLate { // status = false //} if workDay.Records[j].ActionType == oa_model.TypeCommon || workDay.Records[j].ActionType == oa_model.TypeLate || workDay.Records[j].ActionType == oa_model.TypeBefore || workDay.Records[j].ActionType == oa_model.TypeMakeUpSys || workDay.Records[j].ActionType == oa_model.TypeOutWork || workDay.Records[j].ActionType == oa_model.TypeMakeUp || workDay.Records[j].ActionType == oa_model.TypeOverTime || workDay.Records[j].ActionType == oa_model.TypeOutWorkLate || workDay.Records[j].ActionType == oa_model.TypeOutWorkBefore || workDay.Records[j].ActionType == oa_model.TypeGoOut || workDay.Records[j].ActionType == oa_model.TypeBusinessTrip { break } else { missNum++ } } // 缺卡次数 和 打卡次数相等 不 统计 出勤 if missNum == len(workDay.Records) { allDayLeaveNum++ allDayLeave = append(allDayLeave, workDay) } // 出勤天数 if missNum != len(workDay.Records) { attendanceDayNum++ } // 工作日出勤天数 if workDay.DateType == model.WorkDayType && missNum != len(workDay.Records) { attendanceWorkDayNum++ } // 休息日出勤天数 if workDay.DateType == model.WeekendDayType && workDay.IsWork == model.IsFree { attendanceRestDayNum++ } // 节假日出勤天数 if workDay.DateType == model.HolidayDayType && workDay.IsWork == model.IsFree { attendanceHolidayNum++ } } if workDay.IsWork == model.IsFree && len(record.Records) == 0 && len(workDay.ApplyTypes) == 0 { continue } if workDay.Records == nil { continue } workDays = append(workDays, workDay) } fmt.Println("================ QueryOaRecordDates WorkDayDates out =======================") return status, allDayLeave, allDayLeaveNum, needAttendanceDayNum, attendanceDayNum, attendanceRestDayNum, attendanceHolidayNum, attendanceWorkDayNum, workDays, nil } func QueryOaRecordDate(staffUID uint64, date string, workingTime *oa.WorkingTime) (workDay *model.WorkDayDetail, err error) { fmt.Println("================ QueryOaRecordDates WorkDayDate enter =======================") oaRecordReq := new(oa.OARecordReq) oaRecordReq.StaffUID = staffUID oaRecordReq.Dates = []string{date} //fmt.Printf("oaRecordReq: %v\n", oaRecordReq) holidaysMap, holidaysMapErr := HolidayList([]string{date}) if holidaysMapErr != nil { return nil, holidaysMapErr } //fmt.Printf("HolidayList: %v\n", holidaysMap) // 获取考勤记录 oaRecordRes, oaRecordErr := service.GrpcOAImpl.OARecord(context.Background(), oaRecordReq) if oaRecordErr != nil { logger.Errorf("查询考勤记录失败:%s", oaRecordErr.Error()) return nil, errors.New(e.ErrorQueryOaProfile) } //fmt.Printf("oaRecordRes: %v\n", oaRecordRes) workDay = new(model.WorkDayDetail) for i := 0; i < len(oaRecordRes.Data); i++ { record := oaRecordRes.Data[i] // 当前时间 在 工作时间之前 //if common.ConvertWorkDateAndWorkTime(record.WorkDate, "00:00").After(common.CurrentDateTime()) { // return //} workDay.WorkDate = record.WorkDate if record.Week != 0 { workDay.Week = record.Week } else { workDay.Week = int32(holidaysMap[record.WorkDate].WeekDay) } workDay.Weekly = oa_model.WeekZhCN[int8(workDay.Week)] isWork, isWorkDayErr := IsWorkDay(record.WorkDate, workingTime.Week, workingTime.IsWorkDay) if isWorkDayErr != nil { return nil, isWorkDayErr } if isWork { workDay.DateType = model.WorkDayType } else { if holidaysMap[record.WorkDate].Type == 2 { workDay.DateType = model.HolidayDayType } else { workDay.DateType = model.WeekendDayType } } if len(record.Records) > 0 { workDay.IsWork = int8(record.IsWork) workDay.WorkTimes = make([]*model.TimeOption, 0) for k := 0; k < len(record.TimeOptions); k++ { workDay.WorkTimes = append(workDay.WorkTimes, &model.TimeOption{ OnWorkTime: record.TimeOptions[k].OnWorkTime, OffWorkTime: record.TimeOptions[k].OffWorkTime, }) } } else { if isWork { for k := 0; k < len(workingTime.Time); k++ { workDay.WorkTimes = append(workDay.WorkTimes, &model.TimeOption{ OnWorkTime: workingTime.Time[k].OnWorkTime, OffWorkTime: workingTime.Time[k].OffWorkTime, }) } workDay.IsWork = model.IsWork workDay.Abnormal = true // 没有打卡记录 则 表示 异常 } else { workDay.IsWork = model.IsFree } } makeWorkDayDetailErr := makeWorkDayDetailForDates(staffUID, record, workDay) if makeWorkDayDetailErr != nil { return workDay, makeWorkDayDetailErr } //workDay.Records = OrderByRecord(workDay.Records) } fmt.Println("================ QueryOaRecordDate WorkDayDate out =======================") return workDay, nil } // 每天的考勤 以及 审批 func makeWorkDayDetailForMonth(staffUID uint64, record *oa.OARecord, workDay *model.WorkDayDetail) error { // 查询 oa审批 oaApplys, oaApplyErr := QueryOaApplyDatesSpecial(staffUID, []string{record.WorkDate}, []int32{e.ApprovalWorkStatusOk}, nil) if oaApplyErr != nil { return oaApplyErr } workDay.Records = make([]*model.DayRecord, 0) workDay.ApplyTypes = make([]string, 0) applyTypesMap := make(map[string]string) workDay.ActionTypes = make([]string, 0) actionTypesMap := make(map[string]string) workDay.Abnormal = false // 表示 正常 // 是否 有外勤确认记录 //hasOutWorkCheck := false for j := 0; j < len(record.Records); j++ { dayRecord := &model.DayRecord{ ActionType: record.Records[j].ActionType, ActionTime: record.Records[j].ActionTime, WorkTime: record.Records[j].WorkTime, OnOff: record.Records[j].OnOff, CheckAddress: record.Records[j].CheckAddress, CheckMethod: record.Records[j].CheckMethod, ClientID: record.Records[j].ClientID, FacePhoto: record.Records[j].FacePhoto, OutWorkPhoto: record.Records[j].OutworkPic, IsWork: workDay.IsWork, } // 判断 是否严重迟到 if dayRecord.ActionType == oa_model.TypeLate { duration := common.CalcDuration(common.ConvertWorkDateAndWorkTime(record.WorkDate, dayRecord.WorkTime), common.ConvertActionTime(dayRecord.ActionTime)) if duration > 0 { if duration-common.ExtremeLatenessDuration > 0 { dayRecord.IsExtremeLateness = true } else { dayRecord.IsExtremeLateness = false } } } /* if workDay.Abnormal == false && // 如果是正常的话 需要判断是否有异常 (record.Records[j].ActionType == oa_model.TypeMiss || // 缺卡 record.Records[j].ActionType == oa_model.TypeLate || // 迟到 record.Records[j].ActionType == oa_model.TypeBefore) { // 早退 workDay.Abnormal = true // 表示 异常 }*/ workDay.Records = append(workDay.Records, dayRecord) } for i := 0; i < len(workDay.Records); i++ { var actionType string dayRecord := workDay.Records[i] actionType = dayRecord.ActionType // 组装 oa审批 dayRecord.ApplyInfo = make([]*model.ApplyDetail, 0) for k := 0; k < len(oaApplys); k++ { oaApply := oaApplys[k] hasApply := false if oaApply.ApplyType == oa_model.TypeMakeUp { // 补卡 申请 if dayRecord.WorkTime == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Hour && record.WorkDate == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { applyTypesMap[oa_model.TypeMakeUp] = oa_model.TypeMakeUp dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true } } else if oaApply.ApplyType == oa_model.TypeBusinessTrip { // 出差 申请 // 1、 申请的开始时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 // 2、 申请的结束时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 for l := 0; l < len(oaApply.ItineraryList); l++ { applyTime := oaApply.ItineraryList[l].ApplyTimes applyStartDate := common.ConvertApplyStartDateToTimeFour(applyTime[0].Date) applyEndDate := common.ConvertApplyEndDateToTimeEarlyMorningZero(applyTime[len(applyTime)-1].Date) workDate := common.ConvertWorkDateToTimeFour(workDay.WorkDate) // 工作日 在 申请的开始日期 和 申请的结束日期之间 if !workDate.Before(applyStartDate) && !workDate.After(applyEndDate) { // 申请的 开始 日期和结束日期 是同一天 if applyTime[0].Date == applyTime[len(applyTime)-1].Date { if applyTime[0].M == applyTime[len(applyTime)-1].M { if applyTime[0].M == "上午" { // 考勤 打卡时间 为 一班次 // 一定包含了上午的考勤点 if len(workDay.WorkTimes) == 1 { if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了上午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if applyTime[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if applyTime[0].M != applyTime[len(applyTime)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if applyTime[0].Date != applyTime[len(applyTime)-1].Date { // 申请的 开始 日期和结束日期 不是同一天 if applyTime[0].M == applyTime[len(applyTime)-1].M { if applyTime[0].M == "上午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime && applyTime[len(applyTime)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime) && applyTime[len(applyTime)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if applyTime[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime && applyTime[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime) && applyTime[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if applyTime[0].M != applyTime[len(applyTime)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } } else { // 其他申请 // 判断 申请的时间 是 上午 或者 下午 //fmt.Println("============================================= make apply =============================================") //fmt.Printf("oaApply: %v\n", oaApply) //fmt.Println("============================================= make apply =============================================") if oaApply.ApplyTimes[0].M != "" { // 1、 申请的开始时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 // 2、 申请的结束时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 applyStartDate := common.ConvertApplyStartDateToTimeFour(oaApply.ApplyTimes[0].Date) applyEndDate := common.ConvertApplyEndDateToTimeEarlyMorningZero(oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date) workDate := common.ConvertWorkDateToTimeFour(workDay.WorkDate) // 工作日 在 申请的开始日期 和 申请的结束日期之间 if !applyStartDate.After(workDate) && !applyEndDate.Before(workDate) { // 申请的 开始 日期和结束日期 是同一天 if oaApply.ApplyTimes[0].Date == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { if oaApply.ApplyTimes[0].M == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { if oaApply.ApplyTimes[0].M == "上午" { // 考勤 打卡时间 为 一班次 // 一定包含了上午的考勤点 if len(workDay.WorkTimes) == 1 { if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了上午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if oaApply.ApplyTimes[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(record.TimeOptions) == 1 { // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if oaApply.ApplyTimes[0].M != oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if oaApply.ApplyTimes[0].Date != oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { // 申请的 开始 日期和结束日期 不是同一天 if oaApply.ApplyTimes[0].M == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { if oaApply.ApplyTimes[0].M == "上午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime && oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(record.TimeOptions) == 2 { // 考勤 打卡时间 为 二班次 // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime) && oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if oaApply.ApplyTimes[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime && oaApply.ApplyTimes[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime) && oaApply.ApplyTimes[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if oaApply.ApplyTimes[0].M != oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if oaApply.ApplyTimes[0].Hour != "" { // 直接使用 hour 字段的 值 作为 判断 applyStartTime := common.ConvertApplyTimeToTime(oaApply.ApplyTimes[0].Date, oaApply.ApplyTimes[0].Hour) applyEndTime := common.ConvertApplyTimeToTime(oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date, oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Hour) workTime := common.ConvertWorkDateAndWorkTime(workDay.WorkDate, dayRecord.WorkTime) //fmt.Println("============================================= make dayRecord.ApplyInfo =============================================") //fmt.Println("applyStartTime: ", applyStartTime) //fmt.Println("applyEndTime: ", applyEndTime) //fmt.Println("workTime: ", workTime) //fmt.Println("============================================= make dayRecord.ApplyInfo =============================================") if !applyStartTime.After(workTime) && !applyEndTime.Before(workTime) { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } if oaApply.ApplyType == oa_model.TypeOverTime && workDay.IsWork == model.IsFree && workDay.WorkDate == oaApply.ApplyTimes[0].Date && workDay.WorkDate == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) dayRecord.ActionType = oa_model.TypeOverTime hasApply = true actionType = oa_model.TypeOverTime } if oaApply.ApplyType == oa_model.TypeOutWork { applyStartDate := common.ConvertApplyStartDateToTimeFour(oaApply.ApplyTimes[0].Date) applyEndDate := common.ConvertApplyEndDateToTimeEarlyMorningZero(oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date) workDate := common.ConvertWorkDateToTimeFour(workDay.WorkDate) if !workDate.Before(applyStartDate) && !workDate.After(applyEndDate) { outWorkCheckReq := new(oa.OutWorkCheckReq) outWorkCheckReq.StaffUID = oaApply.StaffUID outWorkCheckReq.ApplyUUID = oaApply.ApprovalID outWorkCheckRes, outWorkCheckErr := service.GrpcOAImpl.QueryCheckRecord(context.Background(), outWorkCheckReq) if outWorkCheckErr != nil { logger.Errorf("查询外勤记录失败:%s", outWorkCheckErr.Error()) return errors.New(e.ErrorQueryOutWorkCheck) } if outWorkCheckRes.Data != nil { for l := 0; l < len(outWorkCheckRes.Data); l++ { //hasOutWorkCheck = true workDay.Records = append(workDay.Records, &model.DayRecord{ OnOff: outWorkCheckRes.Data[l].ActionType, ActionTime: outWorkCheckRes.Data[l].ActionTime, }) } } hasApply = true } } } } if hasApply { if oaApply.ApplyType == oa_model.TypeOverTime { applyTypesMap[oa_model.TypeOverTime] = oa_model.TypeOverTime } else if common.LeaveApplyMap[oaApply.ApplyType] != "" { applyTypesMap[oa_model.TypeLeave] = oa_model.TypeLeave } else if oaApply.ApplyType == oa_model.TypeOutWork { applyTypesMap[oa_model.TypeOutWork] = oa_model.TypeOutWork } else if oaApply.ApplyType == oa_model.TypeMakeUp { applyTypesMap[oa_model.TypeMakeUp] = oa_model.TypeMakeUp } else if oaApply.ApplyType == oa_model.TypeDayOff { applyTypesMap[oa_model.TypeDayOff] = oa_model.TypeDayOff } else if oaApply.ApplyType == oa_model.TypeGoOut { applyTypesMap[oa_model.TypeGoOut] = oa_model.TypeGoOut } else if oaApply.ApplyType == oa_model.TypeBusinessTrip { applyTypesMap[oa_model.TypeBusinessTrip] = oa_model.TypeBusinessTrip } } } for j := 0; j < len(dayRecord.ApplyInfo); j++ { if dayRecord.ActionType == oa_model.TypeMiss { if dayRecord.ApplyInfo[j].ApplyType == oa_model.TypeMakeUp || dayRecord.ApplyInfo[j].ApplyType == oa_model.TypeGoOut || dayRecord.ApplyInfo[j].ApplyType == oa_model.TypeBusinessTrip { dayRecord.ActionType = dayRecord.ApplyInfo[len(dayRecord.ApplyInfo)-len(dayRecord.ApplyInfo)].ApplyType dayRecord.ActionTime = workDay.WorkDate + " " + dayRecord.WorkTime actionType = "" break } } if dayRecord.ActionType == oa_model.TypeMiss || dayRecord.ActionType == oa_model.TypeLate || dayRecord.ActionType == oa_model.TypeBefore { if common.LeaveApplyMap[dayRecord.ApplyInfo[j].ApplyType] != "" { dayRecord.ActionType = dayRecord.ApplyInfo[len(dayRecord.ApplyInfo)-len(dayRecord.ApplyInfo)].ApplyType actionType = "" break } } if dayRecord.ActionType == oa_model.TypeOutWorkBefore || dayRecord.ActionType == oa_model.TypeOutWorkLate { if len(applyTypesMap) == 0 { applyTypesMap[oa_model.TypeOutWork] = oa_model.TypeOutWork break } if dayRecord.ApplyInfo[j].ApplyType != oa_model.TypeOutWork { dayRecord.ActionType = dayRecord.ApplyInfo[len(dayRecord.ApplyInfo)-len(dayRecord.ApplyInfo)].ApplyType actionType = "" break } } } if actionType != "" { if actionType == oa_model.TypeOutWorkBefore || actionType == oa_model.TypeOutWorkLate { actionTypesMap[oa_model.TypeOutWork] = oa_model.TypeOutWork } actionTypesMap[actionType] = actionType // 不是 正常的话 异常 //if actionType != oa_model.TypeCommon && actionType != oa_model.TypeMakeUpSys && actionType != oa_model.TypeOutWork { // workDay.Abnormal = true //} // 如果是 缺卡 迟到 早退 旷工 则表示 异常 // 2024-10-28 if actionType == oa_model.TypeMiss || actionType == oa_model.TypeBefore || actionType == oa_model.TypeLate || actionType == oa_model.TypeOutWorkBefore || actionType == oa_model.TypeOutWorkLate { workDay.Abnormal = true } } } // 申请类型 // 如果 申请类型存在 for _, v := range applyTypesMap { workDay.ApplyTypes = append(workDay.ApplyTypes, v) } // 打卡类型 for _, v := range actionTypesMap { workDay.ActionTypes = append(workDay.ActionTypes, v) } //if hasOutWorkCheck { workDay.Records = OrderByRecord(workDay.Records) //} return nil } // 每天的考勤 以及 审批 func makeWorkDayDetailForDates(staffUID uint64, record *oa.OARecord, workDay *model.WorkDayDetail) error { // 查询 oa审批 oaApplys, oaApplyErr := QueryOaApplyDatesSpecial(staffUID, []string{record.WorkDate}, []int32{e.ApprovalWorkStatusOk}, nil) if oaApplyErr != nil { return oaApplyErr } workDay.Records = make([]*model.DayRecord, 0) workDay.ApplyTypes = make([]string, 0) applyTypesMap := make(map[string]string) workDay.ActionTypes = make([]string, 0) actionTypesMap := make(map[string]string) workDay.Abnormal = false // 表示 正常 // 是否 有外勤确认记录 //hasOutWorkCheck := false for j := 0; j < len(record.Records); j++ { dayRecord := &model.DayRecord{ ActionType: record.Records[j].ActionType, ActionTime: record.Records[j].ActionTime, WorkTime: record.Records[j].WorkTime, OnOff: record.Records[j].OnOff, CheckAddress: record.Records[j].CheckAddress, CheckMethod: record.Records[j].CheckMethod, ClientID: record.Records[j].ClientID, FacePhoto: record.Records[j].FacePhoto, OutWorkPhoto: record.Records[j].OutworkPic, IsWork: workDay.IsWork, } // 判断 是否严重迟到 if dayRecord.ActionType == oa_model.TypeLate { duration := common.CalcDuration(common.ConvertWorkDateAndWorkTime(record.WorkDate, dayRecord.WorkTime), common.ConvertActionTime(dayRecord.ActionTime)) if duration > 0 { if duration-common.ExtremeLatenessDuration > 0 { dayRecord.IsExtremeLateness = true } else { dayRecord.IsExtremeLateness = false } } } /* if workDay.Abnormal == false && // 如果是正常的话 需要判断是否有异常 (record.Records[j].ActionType == oa_model.TypeMiss || // 缺卡 record.Records[j].ActionType == oa_model.TypeLate || // 迟到 record.Records[j].ActionType == oa_model.TypeBefore) { // 早退 workDay.Abnormal = true // 表示 异常 }*/ workDay.Records = append(workDay.Records, dayRecord) } // 组装空的 记录 if len(record.Records) == 0 { workDay.Records = MakeDefaultRecord(workDay.WorkTimes) if workDay.IsWork == model.IsFree { workDay.Abnormal = false } else { workDay.Abnormal = true } } for i := 0; i < len(workDay.Records); i++ { var actionType string dayRecord := workDay.Records[i] actionType = dayRecord.ActionType // 组装 oa审批 dayRecord.ApplyInfo = make([]*model.ApplyDetail, 0) for k := 0; k < len(oaApplys); k++ { oaApply := oaApplys[k] hasApply := false if oaApply.ApplyType == oa_model.TypeMakeUp { // 补卡 申请 if dayRecord.WorkTime == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Hour && record.WorkDate == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { applyTypesMap[oa_model.TypeMakeUp] = oa_model.TypeMakeUp dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true } } else if oaApply.ApplyType == oa_model.TypeBusinessTrip { // 出差 申请 // 1、 申请的开始时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 // 2、 申请的结束时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 for l := 0; l < len(oaApply.ItineraryList); l++ { applyTime := oaApply.ItineraryList[l].ApplyTimes applyStartDate := common.ConvertApplyStartDateToTimeFour(applyTime[0].Date) applyEndDate := common.ConvertApplyEndDateToTimeEarlyMorningZero(applyTime[len(applyTime)-1].Date) workDate := common.ConvertWorkDateToTimeFour(workDay.WorkDate) fmt.Printf("applyStartDate: %v, applyEndDate: %v, workDate: %v\n", applyStartDate, applyEndDate, workDate) // 工作日 在 申请的开始日期 和 申请的结束日期之间 if !workDate.Before(applyStartDate) && !workDate.After(applyEndDate) { // 申请的 开始 日期和结束日期 是同一天 if applyTime[0].Date == applyTime[len(applyTime)-1].Date { if applyTime[0].M == applyTime[len(applyTime)-1].M { if applyTime[0].M == "上午" { // 考勤 打卡时间 为 一班次 // 一定包含了上午的考勤点 if len(workDay.WorkTimes) == 1 { if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了上午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if applyTime[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if applyTime[0].M != applyTime[len(applyTime)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if applyTime[0].Date != applyTime[len(applyTime)-1].Date { // 申请的 开始 日期和结束日期 不是同一天 if applyTime[0].M == applyTime[len(applyTime)-1].M { if applyTime[0].M == "上午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime && applyTime[len(applyTime)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime) && applyTime[len(applyTime)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if applyTime[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime && applyTime[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime) && applyTime[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if applyTime[0].M != applyTime[len(applyTime)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } } else { // 其他申请 // 判断 申请的时间 是 上午 或者 下午 //fmt.Println("============================================= make apply =============================================") //fmt.Printf("oaApply: %v\n", oaApply) //fmt.Println("============================================= make apply =============================================") if oaApply.ApplyTimes[0].M != "" { // 1、 申请的开始时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 // 2、 申请的结束时间 和 考勤时间一致 则判断 m 是上午 还是下午 不一致 则 当前考勤点 存在 此申请 applyStartDate := common.ConvertApplyStartDateToTimeFour(oaApply.ApplyTimes[0].Date) applyEndDate := common.ConvertApplyEndDateToTimeEarlyMorningZero(oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date) workDate := common.ConvertWorkDateToTimeFour(workDay.WorkDate) // 工作日 在 申请的开始日期 和 申请的结束日期之间 if !applyStartDate.After(workDate) && !applyEndDate.Before(workDate) { // 申请的 开始 日期和结束日期 是同一天 if oaApply.ApplyTimes[0].Date == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { if oaApply.ApplyTimes[0].M == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { if oaApply.ApplyTimes[0].M == "上午" { // 考勤 打卡时间 为 一 班次 // 一定包含了上午的考勤点 if len(workDay.WorkTimes) == 1 { if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了上午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if oaApply.ApplyTimes[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(record.TimeOptions) == 1 { // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 一定包含了下午的考勤点 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if oaApply.ApplyTimes[0].M != oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if oaApply.ApplyTimes[0].Date != oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { // 申请的 开始 日期和结束日期 不是同一天 if oaApply.ApplyTimes[0].M == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { if oaApply.ApplyTimes[0].M == "上午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime && oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(record.TimeOptions) == 2 { // 考勤 打卡时间 为 二班次 // 所有日期的上午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 除了 申请时间的结束日期的 下午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime) && oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } else if oaApply.ApplyTimes[0].M == "下午" { // 考勤 打卡时间 为 一班次 if len(workDay.WorkTimes) == 1 { // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime && oaApply.ApplyTimes[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } else if len(workDay.WorkTimes) == 2 { // 考勤 打卡时间 为 二班次 // 除了 申请时间的开始日期的 上午的考勤点不包含以外 其他的 包含 if (dayRecord.WorkTime == workDay.WorkTimes[0].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[0].OffWorkTime) && oaApply.ApplyTimes[0].Date != workDay.WorkDate { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } // 所有日期的下午的考勤点都包含 if dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OnWorkTime || dayRecord.WorkTime == workDay.WorkTimes[len(workDay.WorkTimes)-1].OffWorkTime { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if oaApply.ApplyTimes[0].M != oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].M { // 包含了 当天的所有 考勤点 dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } } } } else if oaApply.ApplyTimes[0].Hour != "" { // 直接使用 hour 字段的 值 作为 判断 applyStartTime := common.ConvertApplyTimeToTime(oaApply.ApplyTimes[0].Date, oaApply.ApplyTimes[0].Hour) applyEndTime := common.ConvertApplyTimeToTime(oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date, oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Hour) workTime := common.ConvertWorkDateAndWorkTime(workDay.WorkDate, dayRecord.WorkTime) //fmt.Println("============================================= make dayRecord.ApplyInfo =============================================") //fmt.Println("applyStartTime: ", applyStartTime) //fmt.Println("applyEndTime: ", applyEndTime) //fmt.Println("workTime: ", workTime) //fmt.Println("============================================= make dayRecord.ApplyInfo =============================================") if !applyStartTime.After(workTime) && !applyEndTime.Before(workTime) { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) hasApply = true actionType = "" } if oaApply.ApplyType == oa_model.TypeOverTime && workDay.IsWork == model.IsFree && workDay.WorkDate == oaApply.ApplyTimes[0].Date && workDay.WorkDate == oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date { dayRecord.ApplyInfo = append(dayRecord.ApplyInfo, MakeApplyType(oaApply)) dayRecord.ActionType = oa_model.TypeOverTime hasApply = true actionType = "" } if oaApply.ApplyType == oa_model.TypeOutWork { applyStartDate := common.ConvertApplyStartDateToTimeFour(oaApply.ApplyTimes[0].Date) applyEndDate := common.ConvertApplyEndDateToTimeEarlyMorningZero(oaApply.ApplyTimes[len(oaApply.ApplyTimes)-1].Date) workDate := common.ConvertWorkDateToTimeFour(workDay.WorkDate) if !workDate.Before(applyStartDate) && !workDate.After(applyEndDate) { outWorkCheckReq := new(oa.OutWorkCheckReq) outWorkCheckReq.StaffUID = oaApply.StaffUID outWorkCheckReq.ApplyUUID = oaApply.ApprovalID outWorkCheckRes, outWorkCheckErr := service.GrpcOAImpl.QueryCheckRecord(context.Background(), outWorkCheckReq) if outWorkCheckErr != nil { logger.Errorf("查询外勤记录失败:%s", outWorkCheckErr.Error()) return errors.New(e.ErrorQueryOutWorkCheck) } if outWorkCheckRes.Data != nil { for l := 0; l < len(outWorkCheckRes.Data); l++ { //hasOutWorkCheck = true workDay.Records = append(workDay.Records, &model.DayRecord{ OnOff: outWorkCheckRes.Data[l].ActionType, ActionTime: outWorkCheckRes.Data[l].ActionTime, }) } } hasApply = true } } } } if hasApply { if oaApply.ApplyType == oa_model.TypeOverTime { applyTypesMap[oa_model.TypeOverTime] = oa_model.TypeOverTime } else if common.LeaveApplyMap[oaApply.ApplyType] != "" { applyTypesMap[oa_model.TypeLeave] = oa_model.TypeLeave } else if oaApply.ApplyType == oa_model.TypeOutWork { applyTypesMap[oa_model.TypeOutWork] = oa_model.TypeOutWork } else if oaApply.ApplyType == oa_model.TypeMakeUp { applyTypesMap[oa_model.TypeMakeUp] = oa_model.TypeMakeUp } else if oaApply.ApplyType == oa_model.TypeDayOff { applyTypesMap[oa_model.TypeDayOff] = oa_model.TypeDayOff } else if oaApply.ApplyType == oa_model.TypeGoOut { applyTypesMap[oa_model.TypeGoOut] = oa_model.TypeGoOut } else if oaApply.ApplyType == oa_model.TypeBusinessTrip { applyTypesMap[oa_model.TypeBusinessTrip] = oa_model.TypeBusinessTrip } } } // 如果 当前考勤点 是缺卡的 状态 则 将 当前考勤点 存在的 审批类型 赋值给 打卡类型 // 如果 审批类型是 补卡的 话 则 更新 actionTime 为 workTime for j := 0; j < len(dayRecord.ApplyInfo); j++ { if dayRecord.ActionType == oa_model.TypeMiss { if dayRecord.ApplyInfo[j].ApplyType == oa_model.TypeMakeUp || dayRecord.ApplyInfo[j].ApplyType == oa_model.TypeGoOut || dayRecord.ApplyInfo[j].ApplyType == oa_model.TypeBusinessTrip { dayRecord.ActionType = dayRecord.ApplyInfo[len(dayRecord.ApplyInfo)-len(dayRecord.ApplyInfo)].ApplyType dayRecord.ActionTime = workDay.WorkDate + " " + dayRecord.WorkTime actionType = "" break } } if dayRecord.ActionType == oa_model.TypeMiss || dayRecord.ActionType == oa_model.TypeLate || dayRecord.ActionType == oa_model.TypeBefore { if common.LeaveApplyMap[dayRecord.ApplyInfo[j].ApplyType] != "" { dayRecord.ActionType = dayRecord.ApplyInfo[len(dayRecord.ApplyInfo)-len(dayRecord.ApplyInfo)].ApplyType actionType = "" break } } if dayRecord.ActionType == oa_model.TypeOutWorkBefore || dayRecord.ActionType == oa_model.TypeOutWorkLate { if len(applyTypesMap) == 0 { applyTypesMap[oa_model.TypeOutWork] = oa_model.TypeOutWork break } if dayRecord.ApplyInfo[j].ApplyType != oa_model.TypeOutWork { dayRecord.ActionType = dayRecord.ApplyInfo[len(dayRecord.ApplyInfo)-len(dayRecord.ApplyInfo)].ApplyType actionType = "" break } } } if actionType != "" { if actionType == oa_model.TypeOutWorkBefore || actionType == oa_model.TypeOutWorkLate { actionTypesMap[oa_model.TypeOutWork] = oa_model.TypeOutWork } actionTypesMap[actionType] = actionType // 不是 正常的话 异常 //if actionType != oa_model.TypeCommon && actionType != oa_model.TypeMakeUpSys && actionType != oa_model.TypeOutWork { // workDay.Abnormal = true //} // 如果是 缺卡 迟到 早退 旷工 则表示 异常 // 2024-10-28 if actionType == oa_model.TypeMiss || actionType == oa_model.TypeBefore || actionType == oa_model.TypeLate || actionType == oa_model.TypeOutWorkBefore || actionType == oa_model.TypeOutWorkLate { workDay.Abnormal = true } } } // 申请类型 // 如果 申请类型存在 for _, v := range applyTypesMap { workDay.ApplyTypes = append(workDay.ApplyTypes, v) } // 打卡类型 for _, v := range actionTypesMap { if v == oa_model.TypeCommon { continue } workDay.ActionTypes = append(workDay.ActionTypes, v) } //if hasOutWorkCheck { workDay.Records = OrderByRecord(workDay.Records) //} if CheckActionTypeAndApplyType(workDay) { workDay.Records = nil } return nil } func CalcAverageHour(workDays []*model.WorkDayDetail) (totalHours, averageHourNum float64, averageHour []*model.AverageHourDetail, err error) { averageHourNum = 0 totalHours = 0 averageHour = make([]*model.AverageHourDetail, 0) var days float64 for i := 0; i < len(workDays); i++ { averageHourDetail := new(model.AverageHourDetail) //fmt.Println("=========================================================== averageHourDetail ========================================") //fmt.Printf("workDays %+v\n", workDays[i]) //fmt.Println("=========================================================== averageHourDetail ========================================") averageHourDetail.WorkDate = workDays[i].WorkDate averageHourDetail.Weekly = workDays[i].Weekly for j := 0; j < len(workDays[i].Records); j = j + 2 { if j+1 >= len(workDays[i].Records) { break } if workDays[i].Records[j].ActionTime == "" && workDays[i].Records[j+1].ActionTime == "" { continue } else if workDays[i].Records[j].ActionTime != "" && workDays[i].Records[j+1].ActionTime == "" { continue } else if workDays[i].Records[j].ActionTime == "" && workDays[i].Records[j+1].ActionTime != "" { continue } var startTime time.Time var endTime time.Time startTime = common.ConvertActionTime(workDays[i].Records[j].ActionTime) endTime = common.ConvertActionTime(workDays[i].Records[j+1].ActionTime) averageHourDetail.Hours = averageHourDetail.Hours + endTime.Sub(startTime).Hours() } if averageHourDetail.Hours > 0 { days++ averageHourDetail.Hours = common.HandleHourLeaveASeatNotRounding(averageHourDetail.Hours) averageHour = append(averageHour, averageHourDetail) totalHours = common.HandleHourLeaveASeatNotRounding(totalHours + averageHourDetail.Hours) } } //fmt.Println("=========================================================== CalcAverageHour ========================================") //fmt.Printf("totalHours %+v\n", totalHours) //fmt.Printf("days %+v\n", days) //fmt.Println("=========================================================== CalcAverageHour ========================================") if totalHours != 0 && days != 0 { averageHourNum = common.HandleHourLeaveASeatNotRounding(totalHours / days) } return } func CalcRestDay(workDays []*model.WorkDayDetail, month string, dates []string) (restDayNum int, restDay []*model.RestDayDetail, err error) { restDayNum = 0 restDay = make([]*model.RestDayDetail, 0) if dates != nil { } else { if month == "" { month = holiday.CurrentMonth() } month = common.Add25ForMonth(month) dates = holiday.SplitMonthV1(month, common.YYMMDD) } queryDates := make([]string, 0) for i := 0; i < len(dates); i++ { if common.ConvertWorkDateAndWorkTime(dates[i], "00:00").After(common.CurrentDateTime()) { break } else { queryDates = append(queryDates, dates[i]) } } if len(queryDates) == 0 { return 0, nil, err } //fmt.Println("=============================================== queryDates ===============================================") //fmt.Printf("queryDates %+v\n", queryDates) //fmt.Println("=============================================== queryDates ===============================================") holidaysMap, holidaysMapErr := HolidayList(queryDates) if holidaysMapErr != nil { return 0, nil, holidaysMapErr } //fmt.Println("=============================================== holidaysMap ===============================================") //fmt.Printf("holidaysMap %+v\n", holidaysMap) //fmt.Println("=============================================== holidaysMap ===============================================") workDaysMap := make(map[string]*model.WorkDayDetail) for i := 0; i < len(workDays); i++ { //fmt.Println("=============================================== CalcRestDay ===============================================") //fmt.Printf("workDays %+v value %+v \n", i, workDays[i]) //fmt.Println("=============================================== CalcRestDay ===============================================") // 当前时间 在 工作时间之前 if common.ConvertWorkDateAndWorkTime(workDays[i].WorkDate, "00:00").After(common.CurrentDateTime()) { return } workDaysMap[workDays[i].WorkDate] = workDays[i] } for i := 0; i < len(queryDates); i++ { if workDaysMap[queryDates[i]] == nil && holidaysMap[queryDates[i]].Type > model.WorkDayType { restDay = append(restDay, &model.RestDayDetail{ WorkDate: queryDates[i], Weekly: oa_model.WeekZhCN[holidaysMap[queryDates[i]].WeekDay], Day: 1, }) restDayNum++ } } return } func SelectMiss(workDays []*model.WorkDayDetail, staffUID uint64) (missNum int, miss []*model.MissDetail, err error) { missNum = 0 miss = make([]*model.MissDetail, 0) for i := 0; i < len(workDays); i++ { for j := 0; j < len(workDays[i].Records); j++ { records := workDays[i].Records[j] if records.ActionType == oa_model.TypeMiss { // 查询 oa审批 // TODO 查询 审批 且 只查询 审批状态为 审批中的 因此 不能从 workDays 中 获取 当前只查询了 补卡申请 oaApplys, oaApplyErr := QueryOaApplyDates(staffUID, []string{workDays[i].WorkDate}, []int32{e.ApprovalWorkStatusDoing}, []string{oa_model.TypeMakeUp}) if oaApplyErr != nil { return 0, nil, oaApplyErr } missDetail := &model.MissDetail{ WorkDate: workDays[i].WorkDate, Weekly: workDays[i].Weekly, WorkTime: records.WorkTime, ActionTime: records.ActionTime, WorkTimes: workDays[i].WorkTimes, } for k := 0; k < len(oaApplys); k++ { if oaApplys[k].ApplyType == oa_model.TypeMakeUp && oaApplys[k].ApplyTimes[len(oaApplys[k].ApplyTimes)-1].Hour == records.WorkTime { missDetail.ApplyID = oaApplys[k].ApprovalID missDetail.ApplyStatus = oaApplys[k].Status break } } miss = append(miss, missDetail) missNum++ } } } return } func SelectMakeUp(workDays []*model.WorkDayDetail) (makeUpNum int, makeUp []*model.MakeUpDetail, err error) { makeUpNum = 0 makeUp = make([]*model.MakeUpDetail, 0) for i := 0; i < len(workDays); i++ { for j := 0; j < len(workDays[i].Records); j++ { if workDays[i].Records[j].ActionType == oa_model.TypeMakeUp { makeUp = append(makeUp, &model.MakeUpDetail{ WorkDate: workDays[i].WorkDate, Weekly: workDays[i].Weekly, WorkTime: workDays[i].Records[j].WorkTime, ActionTime: workDays[i].Records[j].ActionTime, }) makeUpNum++ } } } return } func SelectLate(workDays []*model.WorkDayDetail) (lateNum int, commonLateNum int, commonLateDuration float64, extremeLateNum int, extremeLateDuration float64, late []*model.LateDetail, err error) { lateNum = 0 late = make([]*model.LateDetail, 0) for i := 0; i < len(workDays); i++ { for j := 0; j < len(workDays[i].Records); j++ { if workDays[i].Records[j].ActionType == oa_model.TypeLate || workDays[i].Records[j].ActionType == oa_model.TypeOutWorkLate { var duration float64 var extremeLatenessDuration float64 duration = common.CalcDuration(common.ConvertWorkDateAndWorkTime(workDays[i].WorkDate, workDays[i].Records[j].WorkTime), common.ConvertActionTime(workDays[i].Records[j].ActionTime)) //fmt.Println("=============================================== SelectLate ===============================================") //fmt.Printf("workDays[i].work %+v\n", common.ConvertWorkDateAndWorkTime(workDays[i].WorkDate, workDays[i].Records[j].WorkTime)) //fmt.Printf("workDays[i].action %+v\n", common.ConvertActionTime(workDays[i].Records[j].ActionTime)) //fmt.Printf("duration %+v\n", duration) //fmt.Println("=============================================== SelectLate ===============================================") if duration > 0 { if duration-common.ExtremeLatenessDuration > 0 { extremeLatenessDuration = duration extremeLateDuration += duration extremeLateNum++ duration = 0 } else { commonLateNum++ commonLateDuration += duration } } else { duration = 0 } late = append(late, &model.LateDetail{ WorkDate: workDays[i].WorkDate, Weekly: workDays[i].Weekly, WorkTime: workDays[i].Records[j].WorkTime, ActionTime: workDays[i].Records[j].ActionTime, Duration: duration, ExtremeLatenessDuration: extremeLatenessDuration, ActionType: workDays[i].Records[j].ActionType, }) lateNum++ } } } return } func SelectBefore(workDays []*model.WorkDayDetail) (beforeNum int, commonBeforeDuration float64, before []*model.BeforeDetail, err error) { beforeNum = 0 before = make([]*model.BeforeDetail, 0) for i := 0; i < len(workDays); i++ { for j := 0; j < len(workDays[i].Records); j++ { if workDays[i].Records[j].ActionType == oa_model.TypeBefore || workDays[i].Records[j].ActionType == oa_model.TypeOutWorkBefore { duration := common.CalcDuration(common.ConvertActionTime(workDays[i].Records[j].ActionTime), common.ConvertWorkDateAndWorkTime(workDays[i].WorkDate, workDays[i].Records[j].WorkTime)) //fmt.Println("=============================================== SelectBefore ===============================================") //fmt.Printf("workDays[i] %+v\n", workDays[i].WorkDate) //fmt.Printf("workDays[i] WorkTime %+v\n", workDays[i].Records[j].WorkTime) //fmt.Printf("workDays[i] ActionTime %+v\n", workDays[i].Records[j].ActionTime) //fmt.Printf("workDays[i].work %+v\n", common.ConvertWorkDateAndWorkTime(workDays[i].WorkDate, workDays[i].Records[j].WorkTime)) //fmt.Printf("workDays[i].action %+v\n", common.ConvertActionTime(workDays[i].Records[j].ActionTime)) //fmt.Printf("duration %+v\n", duration) //fmt.Println("=============================================== SelectBefore ===============================================") if duration <= 0 { duration = 0 } else { commonBeforeDuration += duration } before = append(before, &model.BeforeDetail{ WorkDate: workDays[i].WorkDate, Weekly: workDays[i].Weekly, WorkTime: workDays[i].Records[j].WorkTime, ActionTime: workDays[i].Records[j].ActionTime, Duration: duration, ActionType: workDays[i].Records[j].ActionType, }) beforeNum++ } } } return } func SelectAbsent(workDays []*model.WorkDayDetail) (missDayNum int, missDay []*model.MissDayDetail, err error) { missDayNum = 0 missDay = make([]*model.MissDayDetail, 0) for i := 0; i < len(workDays); i++ { if workDays[i].IsWork == model.IsFree { continue } allMiss := true for j := 0; j < len(workDays[i].Records); j++ { if workDays[i].Records[j].ActionType != oa_model.TypeMiss { allMiss = false break } } if allMiss { missDay = append(missDay, &model.MissDayDetail{ WorkDate: workDays[i].WorkDate, Weekly: workDays[i].Weekly, Day: 1, }) missDayNum++ } } return } func SelectOutWork(workDays []*model.WorkDayDetail) (outWorkNum int, outWork []*model.OutWorkDetail, err error) { outWorkNum = 0 outWork = make([]*model.OutWorkDetail, 0) outWorkMap := make(map[string][]*model.DayRecord) for i := 0; i < len(workDays); i++ { records := workDays[i].Records var applyID string //var applyType string var applyStatus int32 for j := 0; j < len(records); j++ { if records[j].ActionType == oa_model.TypeOutWork || records[j].ActionType == oa_model.TypeOutWorkLate || records[j].ActionType == oa_model.TypeOutWorkBefore { outWorkMap[workDays[i].WorkDate] = append(outWorkMap[workDays[i].WorkDate], records[j]) for k := 0; k < len(records[j].ApplyInfo); k++ { if records[j].ApplyInfo[k].ApplyType == oa_model.TypeOutWork { applyID = records[j].ApplyInfo[k].ApplyID applyStatus = records[j].ApplyInfo[k].ApplyStatus break } } outWorkNum++ } } if outWorkMap[workDays[i].WorkDate] != nil { outWork = append(outWork, &model.OutWorkDetail{ WorkDate: workDays[i].WorkDate, Weekly: workDays[i].Weekly, Records: outWorkMap[workDays[i].WorkDate], WorkTimes: workDays[i].WorkTimes, ApplyID: applyID, ApplyStatus: applyStatus, }) } } return } func SelectOverTimeOld(req *model.CollectionDetailReq, workDays []*model.WorkDayDetail) (overTimeNum int, overTime *model.OverWorkDetail, err error) { overTime = new(model.OverWorkDetail) overTime.OverWorkDetail = make([]*model.LeaveDetail, 0) oaApply := make([]*oa.OAApply, 0) var oaApplyErr error if req.Month != "" { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyMonth(req.StaffUID, req.Month, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeOverTime}) if oaApplyErr != nil { return 0, nil, oaApplyErr } } else { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyDates(req.StaffUID, req.Dates, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeOverTime}) if oaApplyErr != nil { return 0, nil, oaApplyErr } } workDaysMap := make(map[string]*model.WorkDayDetail) for i := 0; i < len(workDays); i++ { workDaysMap[workDays[i].WorkDate] = workDays[i] } for i := 0; i < len(oaApply); i++ { apply := oaApply[i] // 如果开始时间不在当前月份内 则跳过 if !common.IsInMonth(apply.ApplyTimes[0].Date, req.Month) && req.Month != "" { continue } hours := decimal.NewFromFloat(float64(apply.Hours)) leaveDetail := &model.LeaveDetail{ ApplyID: apply.ApprovalID, ApplyStatus: apply.Status, ApplyStartTime: apply.ApplyTimes[0].Date + " " + apply.ApplyTimes[0].Hour, ApplyEndTime: apply.ApplyTimes[len(apply.ApplyTimes)-1].Date + " " + apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour, DurationType: model.DurationTypeHour, Duration: hours.InexactFloat64(), ApplyType: apply.ApplyType, } if workDaysMap[apply.ApplyTimes[0].Date] != nil { //fmt.Println("=============================================== SelectOverTime MakeOverTimeAbnormal ===============================================") //fmt.Printf("workDaysMap[apply.ApplyTimes[0].Date] %+v\n", workDaysMap[apply.ApplyTimes[0].Date]) //fmt.Printf("apply.ApplyTimes[0].Date %+v\n", apply.ApplyTimes[0].Date) //fmt.Printf("apply.ApplyTimes[0].Hour %+v\n", apply.ApplyTimes[0].Hour) //fmt.Printf("apply.ApplyTimes[len(apply.ApplyTimes)-1].Date %+v\n", apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) //fmt.Printf("apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour %+v\n", apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) //fmt.Println("=============================================== SelectOverTime MakeOverTimeAbnormal ===============================================") leaveDetail.StartAbnormal, leaveDetail.EndAbnormal, leaveDetail.StartActionTime, leaveDetail.EndActionTime = MakeOverTimeAbnormal(workDaysMap[apply.ApplyTimes[0].Date], common.ConvertApplyTimeToTime(apply.ApplyTimes[0].Date, apply.ApplyTimes[0].Hour), common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour)) } holidaysMap, holidaysMapErr := HolidayList([]string{apply.ApplyTimes[0].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Date}) if holidaysMapErr != nil { return 0, nil, holidaysMapErr } leaveDetail.StartDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[0].Date].WeekDay] leaveDetail.StartDayType = int32(holidaysMap[apply.ApplyTimes[0].Date].Type) leaveDetail.EndDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].WeekDay] leaveDetail.EndDayType = int32(holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type) overTime.OverWorkDetail = append(overTime.OverWorkDetail, leaveDetail) // 总加班时长 overTime.OverWorkHour = overTime.OverWorkHour + hours.InexactFloat64() if apply.ApplyTimes[0].Date == apply.ApplyTimes[len(apply.ApplyTimes)-1].Date { if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WorkDayType && holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 overTime.WorkDayHour = overTime.WorkDayHour + hours.InexactFloat64() } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WeekendDayType && holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 overTime.RestDayHour = overTime.RestDayHour + hours.InexactFloat64() } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.HolidayDayType && holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 overTime.HolidayHour = overTime.HolidayHour + hours.InexactFloat64() } } else { // 拆分 日期 dates := holiday.SplitDates(apply.ApplyTimes[0].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, common.YYMMDD) if len(dates) == 2 { // 工作日加班时长 if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WorkDayType { if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 overTime.WorkDayHour = overTime.WorkDayHour + float64(apply.Hours) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 // 申请结束时间的凌晨 applyEndTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) // 申请结束时间 applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) overTime.RestDayHour = overTime.RestDayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) overTime.OverWorkHour = overTime.OverWorkHour + hours.InexactFloat64() - common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 // 申请结束时间的凌晨 applyEndTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) // 申请结束时间 applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) overTime.HolidayHour = overTime.HolidayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) overTime.OverWorkHour = overTime.OverWorkHour + hours.InexactFloat64() - common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WeekendDayType { if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 // 申请结束时间的凌晨 applyEndTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) // 申请结束时间 applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) overTime.WorkDayHour = overTime.WorkDayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) overTime.RestDayHour = overTime.RestDayHour + hours.InexactFloat64() - common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 overTime.RestDayHour = overTime.RestDayHour + hours.InexactFloat64() } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 // 申请结束时间的凌晨 applyEndTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) // 申请结束时间 applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) overTime.HolidayHour = overTime.HolidayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) overTime.RestDayHour = overTime.RestDayHour + hours.InexactFloat64() - common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.HolidayDayType { if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 // 申请结束时间的凌晨 applyEndTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) // 申请结束时间 applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) overTime.WorkDayHour = overTime.WorkDayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) overTime.HolidayHour = overTime.HolidayHour + hours.InexactFloat64() - common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 // 申请结束时间的凌晨 applyEndTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) // 申请结束时间 applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) overTime.RestDayHour = overTime.RestDayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) overTime.HolidayHour = overTime.HolidayHour + hours.InexactFloat64() - common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 overTime.HolidayHour = overTime.HolidayHour + hours.InexactFloat64() } } } else if len(dates) > 2 { var workDayHour, restDayHour, holidayHour float64 for j := 0; j < len(dates); j++ { if j == 0 && dates[j] == apply.ApplyTimes[0].Date { // 申请开始时间的夜里 applyStartTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[0].Date) // 申请开始时间 applyStartTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[0].Date, apply.ApplyTimes[0].Hour) if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WorkDayType { // 工作日加班时长 workDayHour = workDayHour + common.HandleHourLeaveASeatV3(applyStartTimeZero.Sub(applyStartTime).Hours()) } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour + hours.InexactFloat64() } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour + common.HandleHourLeaveASeatV3(applyStartTimeZero.Sub(applyStartTime).Hours()) } } else if j == len(dates)-1 && dates[j] == apply.ApplyTimes[len(apply.ApplyTimes)-1].Date { // 申请结束时间的凌晨 applyEndTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date) // 申请结束时间 applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 workDayHour = workDayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour + hours.InexactFloat64() } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour + common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()) } } else { if holidaysMap[dates[j]].Type == model.WorkDayType { // 工作日加班时长 // TODO 工作日 待确认 目前 是 减去 固定 8小时 workDayHour = workDayHour + float64(24-8) } else if holidaysMap[dates[j]].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour + float64(24) } else if holidaysMap[dates[j]].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour + float64(24) } } } } } // 加班次数 overTimeNum++ } return } func SelectOverTime(req *model.CollectionDetailReq, workDays []*model.WorkDayDetail) (overTimeNum, doingNum int, overTime *model.OverWorkDetail, err error) { overTime = new(model.OverWorkDetail) overTime.OverWorkDetail = make([]*model.LeaveDetail, 0) oaApply := make([]*oa.OAApply, 0) var oaApplyErr error if req.Month != "" { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyMonth(req.StaffUID, req.Month, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeOverTime}) if oaApplyErr != nil { return 0, 0, nil, oaApplyErr } } else { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyDates(req.StaffUID, req.Dates, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeOverTime}) if oaApplyErr != nil { return 0, 0, nil, oaApplyErr } } workDaysMap := make(map[string]*model.WorkDayDetail) for i := 0; i < len(workDays); i++ { workDaysMap[workDays[i].WorkDate] = workDays[i] } var overWorkHour, workDayHour, restDayHour, holidayHour decimal.Decimal for i := 0; i < len(oaApply); i++ { apply := oaApply[i] // 如果开始时间不在当前月份内 则跳过 if !common.IsInMonth(apply.ApplyTimes[0].Date, req.Month) && req.Month != "" { continue } // 如果开始时间不在当前月份内 则跳过 if !common.IsInDates(apply.ApplyTimes[0].Date, req.Dates) && req.Dates != nil { continue } hours := decimal.NewFromFloat(float64(apply.Hours)) leaveDetail := &model.LeaveDetail{ ApplyID: apply.ApprovalID, ApplyStatus: apply.Status, ApplyStartTime: apply.ApplyTimes[0].Date + " " + apply.ApplyTimes[0].Hour, ApplyEndTime: apply.ApplyTimes[len(apply.ApplyTimes)-1].Date + " " + apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour, DurationType: model.DurationTypeHour, Duration: hours.InexactFloat64(), ApplyType: apply.ApplyType, } overWorkHour = overWorkHour.Add(decimal.NewFromFloat(float64(apply.Hours))) if workDaysMap[apply.ApplyTimes[0].Date] != nil { leaveDetail.StartAbnormal, leaveDetail.EndAbnormal, leaveDetail.StartActionTime, leaveDetail.EndActionTime = MakeOverTimeAbnormal(workDaysMap[apply.ApplyTimes[0].Date], common.ConvertApplyTimeToTime(apply.ApplyTimes[0].Date, apply.ApplyTimes[0].Hour), common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour)) } holidaysMap, holidaysMapErr := HolidayList([]string{apply.ApplyTimes[0].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Date}) if holidaysMapErr != nil { return 0, 0, nil, holidaysMapErr } leaveDetail.StartDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[0].Date].WeekDay] leaveDetail.StartDayType = int32(holidaysMap[apply.ApplyTimes[0].Date].Type) leaveDetail.EndDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].WeekDay] leaveDetail.EndDayType = int32(holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type) overTime.OverWorkDetail = append(overTime.OverWorkDetail, leaveDetail) if apply.ApplyTimes[0].Date == apply.ApplyTimes[len(apply.ApplyTimes)-1].Date { if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WorkDayType && holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 workDayHour = workDayHour.Add(hours) } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WeekendDayType && holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour.Add(hours) } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.HolidayDayType && holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour.Add(hours) } } else { // 拆分 日期 dates := holiday.SplitDates(apply.ApplyTimes[0].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, common.YYMMDD) if len(dates) == 2 { applyEndTimeZero := common.ConvertApplyStartDateToTimeWithMinute(apply.ApplyTimes[0].Date, strings.Split(apply.ApplyTimes[0].Hour, ":")[1]) fmt.Println("======================== applyEndTimeZero ================") fmt.Println("applyEndTimeZero := ", applyEndTimeZero) fmt.Println("======================== applyEndTimeZero ================") applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WorkDayType { if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 //workDayHour = workDayHour.Add(decimal.NewFromFloat(float64(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours())))) workDayHour = workDayHour.Add(hours) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 //restDayHour = restDayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()))) //workDayHour = workDayHour.Add(hours.Sub(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours())))) hour := decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours())) restDayHour = restDayHour.Add(hour) workDayHour = workDayHour.Add(hours.Sub(hour)) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // // 节假日加班时长 //holidayHour = holidayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()))) //workDayHour = workDayHour.Add(hours.Sub(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours())))) hour := decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours())) holidayHour = holidayHour.Add(hour) workDayHour = workDayHour.Add(hours.Sub(hour)) } } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WeekendDayType { if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 //workDayHour = workDayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()))) //restDayHour = restDayHour.Add(hours.Sub(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours())))) hour := decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours())) workDayHour = workDayHour.Add(hour) restDayHour = restDayHour.Add(hours.Sub(hour)) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour.Add(hours) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 //holidayHour = holidayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()))) //restDayHour = restDayHour.Add(hours.Sub(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours())))) hour := decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours())) holidayHour = holidayHour.Add(hour) restDayHour = restDayHour.Add(hours.Sub(hour)) } } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.HolidayDayType { if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 //workDayHour = workDayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()))) //holidayHour = holidayHour.Add(hours.Sub(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours())))) hour := decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours())) workDayHour = workDayHour.Add(hour) holidayHour = holidayHour.Add(hours.Sub(hour)) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 //restDayHour = restDayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours()))) //holidayHour = holidayHour.Add(hours.Sub(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTimeZero.Sub(applyEndTime).Hours())))) hour := decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours())) restDayHour = restDayHour.Add(hour) holidayHour = holidayHour.Add(hours.Sub(hour)) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour.Add(hours) } } } else if len(dates) > 2 { for j := 0; j < len(dates); j++ { if j == 0 && dates[j] == apply.ApplyTimes[0].Date { applyStartTimeZero := common.ConvertApplyStartDateToTimeZero(apply.ApplyTimes[0].Date) applyStartTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[0].Date, apply.ApplyTimes[0].Hour) if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WorkDayType { // 工作日加班时长 workDayHour = workDayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyStartTimeZero.Sub(applyStartTime).Hours()))) } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour.Add(decimal.NewFromFloat(float64(apply.Hours))) } else if holidaysMap[apply.ApplyTimes[0].Date].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyStartTimeZero.Sub(applyStartTime).Hours()))) } } else if j == len(dates)-1 && dates[j] == apply.ApplyTimes[len(apply.ApplyTimes)-1].Date { applyEndTimeZero := common.ConvertApplyStartDateToTimeWithMinute(apply.ApplyTimes[0].Date, strings.Split(apply.ApplyTimes[0].Hour, ":")[1]) applyEndTime := common.ConvertApplyTimeToTime(apply.ApplyTimes[len(apply.ApplyTimes)-1].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour) if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WorkDayType { // 工作日加班时长 workDayHour = workDayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours()))) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour.Add(decimal.NewFromFloat(float64(apply.Hours))) } else if holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour.Add(decimal.NewFromFloat(common.HandleHourLeaveASeatV3(applyEndTime.Sub(applyEndTimeZero).Hours()))) } } else { if holidaysMap[dates[j]].Type == model.WorkDayType { // 工作日加班时长 workDayHour = workDayHour.Add(decimal.NewFromFloat(24 - 8)) } else if holidaysMap[dates[j]].Type == model.WeekendDayType { // 休息日加班时长 restDayHour = restDayHour.Add(decimal.NewFromFloat(24)) } else if holidaysMap[dates[j]].Type == model.HolidayDayType { // 节假日加班时长 holidayHour = holidayHour.Add(decimal.NewFromFloat(24)) } } } } } fmt.Printf("=============================================== SelectOverTime %+v ===============================================\n", i) fmt.Println("=============================================== SelectOverTime workDayHour ===============================================") fmt.Printf("workDayHour %+v\n", workDayHour.InexactFloat64()) fmt.Println("=============================================== SelectOverTime workDayHour ===============================================") fmt.Println("=============================================== SelectOverTime restDayHour ===============================================") fmt.Printf("restDayHour %+v\n", restDayHour.InexactFloat64()) fmt.Println("=============================================== SelectOverTime restDayHour ===============================================") fmt.Println("=============================================== SelectOverTime holidayHour ===============================================") fmt.Printf("holidayHour %+v\n", holidayHour.InexactFloat64()) fmt.Println("=============================================== SelectOverTime holidayHour ===============================================") fmt.Println("=============================================== SelectOverTime overWorkHour ===============================================") fmt.Printf("overWorkHour %+v\n", overWorkHour.InexactFloat64()) fmt.Println("=============================================== SelectOverTime overWorkHour ===============================================") // 加班次数 overTimeNum++ if apply.Status == e.ApprovalWorkStatusDoing { doingNum++ } } overTime.WorkDayHour = workDayHour.InexactFloat64() overTime.RestDayHour = restDayHour.InexactFloat64() overTime.HolidayHour = holidayHour.InexactFloat64() overTime.OverWorkHour = overWorkHour.InexactFloat64() return } // SelectLeave 仅为事假 func SelectLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectAnnualLeave 年假详情 func SelectAnnualLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeAnnualLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectSick 病假详情 func SelectSick(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeSick}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectBreastFeedingLeave 哺乳假详情 func SelectBreastFeedingLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeBreastFeedingLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectPaternityLeave 陪产假详情 func SelectPaternityLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum int, leave []*model.LeaveDetail, err error) { var num float64 var doing float64 leaveNum = 0 doingNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} num, doing, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypePaternityLeave}, workingTime) if err != nil { return 0, 0, nil, err } leaveNum = int(num) doingNum = int(doing) return } // SelectMaritalLeave 婚假详情 func SelectMaritalLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum int, leave []*model.LeaveDetail, err error) { var num float64 var doing float64 leaveNum = 0 doingNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} num, doing, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeMaritalLeave}, workingTime) if err != nil { return 0, 0, nil, err } leaveNum = int(num) doingNum = int(doing) return } // SelectFuneralLeave 丧假详情 func SelectFuneralLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeFuneralLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectMaternityLeave 产假详情 func SelectMaternityLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeMaternityLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectGoOut 外出详情 func SelectGoOut(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeGoOut}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectBusinessTrip 出差详情 func SelectBusinessTrip(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeBusinessTrip}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectParentalLeave 育儿假详情 func SelectParentalLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeParentalLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectNursingLeave 独生子女护理假详情 func SelectNursingLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeNursingLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectAbortLeave 流产假详情 func SelectAbortLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeAbortLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectMatingCheckLeave 孕检假详情 func SelectMatingCheckLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) // []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeLeave} leaveNum, doingNum, leave, err = selectLeave(req, []int32{e.ApprovalWorkStatusOk, e.ApprovalWorkStatusDoing}, []string{oa_model.TypeMatingCheckLeave}, workingTime) if err != nil { return 0, 0, nil, err } return } // SelectAllLeave 全部请假详情 func SelectAllLeave(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (allLeaveNum int, allLeave []*model.AllLeaveDetail, err error) { allLeave = make([]*model.AllLeaveDetail, 0) // 事假 leaveNum, _, leave, err := SelectLeave(req, workingTime) if err != nil { return 0, nil, err } if len(leave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeLeave, LeaveNum: leaveNum, DurationType: leave[0].DurationType, Leave: leave, }) allLeaveNum += len(leave) } // 年假 annualLeaveNum, _, annualLeave, err := SelectAnnualLeave(req, workingTime) if err != nil { return 0, nil, err } if len(annualLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeAnnualLeave, LeaveNum: annualLeaveNum, DurationType: annualLeave[0].DurationType, Leave: annualLeave, }) allLeaveNum += len(annualLeave) } // 病假 sickLeaveNum, _, sickLeave, err := SelectSick(req, workingTime) if err != nil { return 0, nil, err } if len(sickLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeSick, LeaveNum: sickLeaveNum, DurationType: sickLeave[0].DurationType, Leave: sickLeave, }) allLeaveNum += len(sickLeave) } // 哺乳假 breastFeedingLeaveNum, _, breastFeedingLeave, err := SelectBreastFeedingLeave(req, workingTime) if err != nil { return 0, nil, err } if len(breastFeedingLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeBreastFeedingLeave, LeaveNum: breastFeedingLeaveNum, DurationType: breastFeedingLeave[0].DurationType, Leave: breastFeedingLeave, }) allLeaveNum += len(breastFeedingLeave) } // 陪产假 paternityLeaveNum, _, paternityLeave, err := SelectPaternityLeave(req, workingTime) if err != nil { return 0, nil, err } if len(paternityLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypePaternityLeave, LeaveNum: float64(paternityLeaveNum), DurationType: paternityLeave[0].DurationType, Leave: paternityLeave, }) allLeaveNum += len(paternityLeave) } // 婚假 maritalLeaveNum, _, maritalLeave, err := SelectMaritalLeave(req, workingTime) if err != nil { return 0, nil, err } if len(maritalLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeMaritalLeave, LeaveNum: float64(maritalLeaveNum), DurationType: maritalLeave[0].DurationType, Leave: maritalLeave, }) allLeaveNum += len(maritalLeave) } // 丧假 funeralLeaveNum, _, funeralLeave, err := SelectFuneralLeave(req, workingTime) if err != nil { return 0, nil, err } if len(funeralLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeFuneralLeave, LeaveNum: funeralLeaveNum, DurationType: funeralLeave[0].DurationType, Leave: funeralLeave, }) allLeaveNum += len(funeralLeave) } // 产假 maternityLeaveNum, _, maternityLeave, err := SelectMaternityLeave(req, workingTime) if err != nil { return 0, nil, err } if len(maternityLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeMaternityLeave, LeaveNum: maternityLeaveNum, DurationType: maternityLeave[0].DurationType, Leave: maternityLeave, }) allLeaveNum += len(maternityLeave) } // 育儿假 parentalLeaveNum, _, parentalLeave, err := SelectParentalLeave(req, workingTime) if err != nil { return 0, nil, err } if len(parentalLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeParentalLeave, LeaveNum: float64(parentalLeaveNum), DurationType: parentalLeave[0].DurationType, Leave: parentalLeave, }) allLeaveNum += len(parentalLeave) } // 独生子女护理假 nursingLeaveNum, _, nursingLeave, err := SelectNursingLeave(req, workingTime) if err != nil { return 0, nil, err } if len(nursingLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeNursingLeave, LeaveNum: float64(nursingLeaveNum), DurationType: nursingLeave[0].DurationType, Leave: nursingLeave, }) allLeaveNum += len(nursingLeave) } // 流产假 abortLeaveNum, _, abortLeave, err := SelectAbortLeave(req, workingTime) if err != nil { return 0, nil, err } if len(abortLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeAbortLeave, LeaveNum: float64(abortLeaveNum), DurationType: abortLeave[0].DurationType, Leave: abortLeave, }) allLeaveNum += len(abortLeave) } // 孕检假 matingCheckLeaveNum, _, matingCheckLeave, err := SelectMatingCheckLeave(req, workingTime) if err != nil { return 0, nil, err } if len(matingCheckLeave) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeMatingCheckLeave, LeaveNum: float64(matingCheckLeaveNum), DurationType: matingCheckLeave[0].DurationType, Leave: matingCheckLeave, }) allLeaveNum += len(matingCheckLeave) } /*// 外出 goOutNum, goOut, err := SelectGoOut(req) if err != nil { return 0, nil, err } if len(goOut) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeGoOut, LeaveNum: goOutNum, DurationType: goOut[0].DurationType, Leave: goOut, }) allLeaveNum += len(goOut) } // 出差 businessTripNum, businessTrip, err := SelectBusinessTrip(req) if err != nil { return 0, nil, err } if len(businessTrip) > 0 { allLeave = append(allLeave, &model.AllLeaveDetail{ LeaveType: oa_model.TypeGoOut, LeaveNum: businessTripNum, DurationType: businessTrip[0].DurationType, Leave: businessTrip, }) allLeaveNum += len(businessTrip) }*/ return } // 公用方法 func selectLeave(req *model.CollectionDetailReq, applyStatus []int32, applyType []string, workingTime *oa.WorkingTime) (leaveNum, doingNum float64, leave []*model.LeaveDetail, err error) { leaveNum = 0 leave = make([]*model.LeaveDetail, 0) oaApply := make([]*oa.OAApply, 0) var oaApplyErr error if req.Month != "" { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyMonth(req.StaffUID, req.Month, applyStatus, applyType) if oaApplyErr != nil { return 0, 0, nil, oaApplyErr } } else { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyDates(req.StaffUID, req.Dates, applyStatus, applyType) if oaApplyErr != nil { return 0, 0, nil, oaApplyErr } } for i := 0; i < len(oaApply); i++ { apply := oaApply[i] leaveDetail := &model.LeaveDetail{ ApplyID: apply.ApprovalID, ApplyStatus: apply.Status, ApplyType: apply.ApplyType, } if len(apply.ApplyTimes) > 0 { // 判断是否 跨考勤时间 day, hour, allIn := CalcDurationForDates(req.Month, req.Dates, apply.ApplyTimes, workingTime, apply.ApplyType) if apply.ApplyTimes[0].Hour != "" && apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour != "" { leaveDetail.ApplyStartTime = apply.ApplyTimes[0].Date + " " + apply.ApplyTimes[0].Hour leaveDetail.ApplyEndTime = apply.ApplyTimes[len(apply.ApplyTimes)-1].Date + " " + apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour leaveDetail.DurationType = model.DurationTypeHour if allIn { leaveDetail.Duration = float64(apply.Hours) leaveNum = leaveNum + float64(apply.Hours) if apply.Status == e.ApprovalWorkStatusDoing { doingNum += float64(apply.Hours) } } else { leaveDetail.Duration = float64(hour) leaveNum = leaveNum + float64(hour) if apply.Status == e.ApprovalWorkStatusDoing { doingNum += float64(hour) } } } else if apply.ApplyTimes[0].M != "" && apply.ApplyTimes[len(apply.ApplyTimes)-1].M != "" { leaveDetail.ApplyStartTime = apply.ApplyTimes[0].Date + " " + apply.ApplyTimes[0].M leaveDetail.ApplyEndTime = apply.ApplyTimes[len(apply.ApplyTimes)-1].Date + " " + apply.ApplyTimes[len(apply.ApplyTimes)-1].M leaveDetail.DurationType = model.DurationTypeDay if allIn { leaveDetail.Duration = float64(apply.Days) leaveNum = leaveNum + float64(apply.Days) if apply.Status == e.ApprovalWorkStatusDoing { doingNum += float64(apply.Days) } } else { leaveDetail.Duration = float64(day) leaveNum = leaveNum + float64(day) if apply.Status == e.ApprovalWorkStatusDoing { doingNum += float64(day) } } } holidaysMap, holidaysMapErr := HolidayList([]string{apply.ApplyTimes[0].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Date}) if holidaysMapErr != nil { return 0, 0, nil, holidaysMapErr } leaveDetail.StartDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[0].Date].WeekDay] leaveDetail.StartDayType = int32(holidaysMap[apply.ApplyTimes[0].Date].Type) leaveDetail.EndDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].WeekDay] leaveDetail.EndDayType = int32(holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type) } if apply.ItineraryList != nil && len(apply.ItineraryList) > 0 { leaveDetail.ItineraryList = make([]*model.Itinerary, 0) for j := 0; j < len(apply.ItineraryList); j++ { holidaysMap, holidaysMapErr := HolidayList([]string{apply.ItineraryList[j].ApplyTimes[0].Date, apply.ItineraryList[j].ApplyTimes[len(apply.ItineraryList[j].ApplyTimes)-1].Date}) if holidaysMapErr != nil { return 0, 0, nil, holidaysMapErr } leaveDetail.ItineraryList = append(leaveDetail.ItineraryList, &model.Itinerary{ StartAddress: apply.ItineraryList[j].StartAddress, EndAddress: apply.ItineraryList[j].EndAddress, ApplyStartTime: apply.ItineraryList[j].ApplyTimes[0].Date + " " + apply.ItineraryList[j].ApplyTimes[0].M, StartDayType: int32(holidaysMap[apply.ItineraryList[j].ApplyTimes[0].Date].Type), StartDayWeekly: oa_model.WeekZhCN[holidaysMap[apply.ItineraryList[j].ApplyTimes[0].Date].WeekDay], ApplyEndTime: apply.ItineraryList[j].ApplyTimes[1].Date + " " + apply.ItineraryList[j].ApplyTimes[1].M, EndDayType: int32(holidaysMap[apply.ItineraryList[j].ApplyTimes[1].Date].Type), EndDayWeekly: oa_model.WeekZhCN[holidaysMap[apply.ItineraryList[j].ApplyTimes[1].Date].WeekDay], Days: apply.ItineraryList[j].Days, Vehicle: apply.ItineraryList[j].Vehicle, }) // 判断是否 跨考勤时间 day, _, allIn := CalcDurationForDates(req.Month, req.Dates, apply.ItineraryList[j].ApplyTimes, workingTime, apply.ApplyType) if allIn { leaveDetail.Duration += float64(apply.ItineraryList[j].Days) leaveNum += float64(apply.ItineraryList[j].Days) if apply.Status == e.ApprovalWorkStatusDoing { doingNum += float64(apply.ItineraryList[j].Days) } } else { leaveDetail.Duration += float64(day) leaveNum += float64(day) if apply.Status == e.ApprovalWorkStatusDoing { doingNum += float64(day) } } } } // 放到 出差详情 中 判断 //if apply.TotalDays > 0 { // leaveDetail.DurationType = model.DurationTypeDay // leaveDetail.Duration += float64(apply.TotalDays) // leaveNum += float64(apply.TotalDays) // if apply.Status == e.ApprovalWorkStatusDoing { // doingNum += float64(apply.TotalDays) // } //} leaveDetail.Reason = apply.Reason leave = append(leave, leaveDetail) } return } func SelectDayOff(req *model.CollectionDetailReq, workingTime *oa.WorkingTime) (dayOffNum, doingNum int, dayOffHours float64, dayOff []*model.LeaveDetail, err error) { dayOffNum = 0 dayOff = make([]*model.LeaveDetail, 0) oaApply := make([]*oa.OAApply, 0) var oaApplyErr error if req.Month != "" { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyMonth(req.StaffUID, req.Month, []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeDayOff}) if oaApplyErr != nil { return 0, 0, 0, nil, oaApplyErr } } else { // 查询 oa审批 oaApply, oaApplyErr = QueryOaApplyDates(req.StaffUID, req.Dates, []int32{e.ApprovalWorkStatusOk}, []string{oa_model.TypeDayOff}) if oaApplyErr != nil { return 0, 0, 0, nil, oaApplyErr } } for i := 0; i < len(oaApply); i++ { apply := oaApply[i] // 判断是否 跨考勤时间 _, hour, allIn := CalcDurationForDates(req.Month, req.Dates, apply.ApplyTimes, workingTime, apply.ApplyType) dayOffDetail := &model.LeaveDetail{ ApplyID: apply.ApprovalID, ApplyStatus: apply.Status, ApplyStartTime: apply.ApplyTimes[0].Date + " " + apply.ApplyTimes[0].Hour, ApplyEndTime: apply.ApplyTimes[len(apply.ApplyTimes)-1].Date + " " + apply.ApplyTimes[len(apply.ApplyTimes)-1].Hour, DurationType: model.DurationTypeHour, Duration: float64(apply.Hours), ApplyType: apply.ApplyType, } holidaysMap, holidaysMapErr := HolidayList([]string{apply.ApplyTimes[0].Date, apply.ApplyTimes[len(apply.ApplyTimes)-1].Date}) if holidaysMapErr != nil { return 0, 0, 0, nil, holidaysMapErr } dayOffDetail.StartDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[0].Date].WeekDay] dayOffDetail.StartDayType = int32(holidaysMap[apply.ApplyTimes[0].Date].Type) dayOffDetail.EndDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].WeekDay] dayOffDetail.EndDayType = int32(holidaysMap[apply.ApplyTimes[len(apply.ApplyTimes)-1].Date].Type) dayOff = append(dayOff, dayOffDetail) // 调休次数 dayOffNum++ // 调休时长 if allIn { dayOffHours = dayOffHours + float64(apply.Hours) if apply.Status == e.ApprovalWorkStatusDoing { doingNum++ } } else { dayOffHours = dayOffHours + float64(hour) if apply.Status == e.ApprovalWorkStatusDoing { doingNum++ } } } return } // OrderByRecordOld 考勤记录排序 func OrderByRecordOld(records []*model.DayRecord) []*model.DayRecord { if records == nil { return records } recordsMap := make(map[string]*model.DayRecord) times := make([]string, 0) for i := 0; i < len(records); i++ { if records[i].WorkTime != "" && records[i].IsWork == oa_model.IsWork { recordsMap[records[i].WorkTime] = records[i] times = append(times, records[i].WorkTime) } else if records[i].ActionTime != "" && records[i].WorkTime == "" { recordsMap[strings.Split(records[i].ActionTime, " ")[1]] = records[i] times = append(times, strings.Split(records[i].ActionTime, " ")[1]) } else if records[i].IsWork == oa_model.IsFree { if records[i].OnOff == oa_model.OffWork { if i == len(records)-1 { recordsMap[strings.Split(records[i].ActionTime, " ")[1]] = records[i] times = append(times, strings.Split(records[i].ActionTime, " ")[1]) } continue } recordsMap[strings.Split(records[i].ActionTime, " ")[1]] = records[i] times = append(times, strings.Split(records[i].ActionTime, " ")[1]) } } sort.Strings(times) newRecords := make([]*model.DayRecord, 0) for i := 0; i < len(times); i++ { newRecords = append(newRecords, recordsMap[times[i]]) } return newRecords } // OrderByRecord 考勤记录排序 func OrderByRecord(records []*model.DayRecord) []*model.DayRecord { if records == nil { return records } recordsMap := make(map[string]*model.DayRecord) times := make([]string, 0) for i := 0; i < len(records); i++ { if records[i].WorkTime != "" && records[i].IsWork == oa_model.IsWork { recordsMap[records[i].WorkTime] = records[i] times = append(times, records[i].WorkTime) } else if records[i].ActionTime != "" && records[i].WorkTime == "" { recordsMap[strings.Replace(records[i].ActionTime, " ", "", -1)] = records[i] times = append(times, strings.Replace(records[i].ActionTime, " ", "", -1)) } else if records[i].IsWork == oa_model.IsFree { if records[i].OnOff == oa_model.OffWork { if i == len(records)-1 { recordsMap[strings.Replace(records[i].ActionTime, " ", "", -1)] = records[i] times = append(times, strings.Replace(records[i].ActionTime, " ", "", -1)) } continue } recordsMap[strings.Replace(records[i].ActionTime, " ", "", -1)] = records[i] times = append(times, strings.Replace(records[i].ActionTime, " ", "", -1)) } } sort.Strings(times) newRecords := make([]*model.DayRecord, 0) for i := 0; i < len(times); i++ { newRecords = append(newRecords, recordsMap[times[i]]) } return newRecords } func RemoveRecord(workDays []*model.WorkDayDetail) (retWorkDay []*model.WorkDayDetail) { retWorkDay = make([]*model.WorkDayDetail, 0) // 剔除 特殊情况的记录 if workDays != nil || len(workDays) > 0 { for i := 0; i < len(workDays); i++ { workDay := workDays[i] if len(workDay.Records) > 0 { missNum := 0 for j := 0; j < len(workDay.Records); j++ { if workDay.Records[j].ActionType == oa_model.TypeCommon || workDay.Records[j].ActionType == oa_model.TypeLate || workDay.Records[j].ActionType == oa_model.TypeBefore || workDay.Records[j].ActionType == oa_model.TypeMakeUpSys || workDay.Records[j].ActionType == oa_model.TypeOutWork || workDay.Records[j].ActionType == oa_model.TypeMakeUp || workDay.Records[j].ActionType == oa_model.TypeOverTime || workDay.Records[j].ActionType == oa_model.TypeOutWorkLate || workDay.Records[j].ActionType == oa_model.TypeOutWorkBefore { break } else { missNum++ } } if missNum != len(workDay.Records) { retWorkDay = append(retWorkDay, workDay) } } } } return } // MakeDefaultRecord 组装默认的考勤记录 func MakeDefaultRecord(workTimes []*model.TimeOption) (records []*model.DayRecord) { records = make([]*model.DayRecord, 0) for i := 0; i < len(workTimes); i++ { records = append(records, &model.DayRecord{ WorkTime: workTimes[i].OnWorkTime, OnOff: model.OnWork, }) records = append(records, &model.DayRecord{ WorkTime: workTimes[i].OffWorkTime, OnOff: model.OffWork, }) } return } // MakeApplyType 组装 申请记录 func MakeApplyType(apply *oa.OAApply) (applyDetail *model.ApplyDetail) { applyDetail = new(model.ApplyDetail) applyDetail = &model.ApplyDetail{ ApplyID: apply.ApprovalID, ApplyType: apply.ApplyType, ApplyTypeZhCN: common.LeaveTypeZhCN[apply.ApplyType], ApplyStatus: apply.Status, } applyDetail.ItineraryList = make([]*model.Itinerary, 0) if len(apply.ApplyTimes) > 0 { date := []string{apply.ApplyTimes[0].Date} has := false if len(apply.ApplyTimes) == 2 { date = append(date, apply.ApplyTimes[1].Date) has = true } holidaysMap, holidaysMapErr := HolidayList(date) if holidaysMapErr != nil { return } itinerary := &model.Itinerary{ ApplyStartTime: apply.ApplyTimes[0].Date + " " + apply.ApplyTimes[0].M, StartDayType: int32(holidaysMap[apply.ApplyTimes[0].Date].Type), StartDayWeekly: oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[0].Date].WeekDay], } if has { itinerary.ApplyEndTime = apply.ApplyTimes[1].Date + " " + apply.ApplyTimes[1].M itinerary.EndDayType = int32(holidaysMap[apply.ApplyTimes[1].Date].Type) itinerary.EndDayWeekly = oa_model.WeekZhCN[holidaysMap[apply.ApplyTimes[1].Date].WeekDay] } applyDetail.ItineraryList = append(applyDetail.ItineraryList) } if apply.ItineraryList != nil && len(apply.ItineraryList) > 0 { for j := 0; j < len(apply.ItineraryList); j++ { holidaysMap, holidaysMapErr := HolidayList([]string{apply.ItineraryList[j].ApplyTimes[0].Date, apply.ItineraryList[j].ApplyTimes[len(apply.ItineraryList[j].ApplyTimes)-1].Date}) if holidaysMapErr != nil { return } applyDetail.ItineraryList = append(applyDetail.ItineraryList, &model.Itinerary{ StartAddress: apply.ItineraryList[j].StartAddress, EndAddress: apply.ItineraryList[j].EndAddress, ApplyStartTime: apply.ItineraryList[j].ApplyTimes[0].Date + " " + apply.ItineraryList[j].ApplyTimes[0].M, StartDayType: int32(holidaysMap[apply.ItineraryList[j].ApplyTimes[0].Date].Type), StartDayWeekly: oa_model.WeekZhCN[holidaysMap[apply.ItineraryList[j].ApplyTimes[0].Date].WeekDay], ApplyEndTime: apply.ItineraryList[j].ApplyTimes[1].Date + " " + apply.ItineraryList[j].ApplyTimes[1].M, EndDayType: int32(holidaysMap[apply.ItineraryList[j].ApplyTimes[1].Date].Type), EndDayWeekly: oa_model.WeekZhCN[holidaysMap[apply.ItineraryList[j].ApplyTimes[1].Date].WeekDay], Days: apply.ItineraryList[j].Days, Vehicle: apply.ItineraryList[j].Vehicle, }) } } return } // CheckActionTypeAndApplyType 判断 当前考勤是否存在 action_type 和 apply_type func CheckActionTypeAndApplyType(workDay *model.WorkDayDetail) bool { if workDay.Records == nil || len(workDay.Records) == 0 { return true } missActionType := 0 for i := 0; i < len(workDay.Records); i++ { if workDay.Records[i].ActionType == "" { missActionType++ } } if missActionType == len(workDay.Records) && (workDay.ApplyTypes == nil || len(workDay.ApplyTypes) == 0) { return true } return false } func MakeOverTimeAbnormal(workDayDetail *model.WorkDayDetail, applyStartTime, applyEndTime time.Time) (startAbnormal, endAbnormal int32, startActionTime, endActionTime string) { //fmt.Println("===================== MakeOverTimeAbnormal ======================") //fmt.Printf("workDayDetail: %+v \n ", workDayDetail) //fmt.Println("applyStartTime: ", applyStartTime) //fmt.Println("applyEndTime: ", applyEndTime) //fmt.Println("===================== MakeOverTimeAbnormal ======================") if workDayDetail.Records == nil || len(workDayDetail.Records) == 0 { return 0, 0, "", "" } if workDayDetail.IsWork == model.IsWork { if workDayDetail.WorkTimes == nil || len(workDayDetail.WorkTimes) == 0 { return 0, 0, "", "" } onWorkTime := common.ConvertWorkDateAndWorkTime(workDayDetail.WorkDate, workDayDetail.WorkTimes[0].OnWorkTime) offWorkTime := common.ConvertWorkDateAndWorkTime(workDayDetail.WorkDate, workDayDetail.WorkTimes[len(workDayDetail.WorkTimes)-1].OffWorkTime) fmt.Println("================ 情况一 ======================") // 加班的 申请时间在 开始时间之前 if !applyStartTime.After(onWorkTime) && !applyEndTime.After(onWorkTime) { actionTime := common.ConvertActionTime(workDayDetail.Records[0].ActionTime) if workDayDetail.Records[0].ActionTime == "" { // 未打卡 startAbnormal = model.IsAbnormal startActionTime = workDayDetail.Records[0].ActionTime endAbnormal = model.IsAbnormal endActionTime = workDayDetail.Records[0].ActionTime } else if !applyStartTime.Before(actionTime) && !applyEndTime.Before(actionTime) { startAbnormal = model.NotAbnormal endAbnormal = model.NotAbnormal } else { startAbnormal = model.IsAbnormal startActionTime = workDayDetail.Records[0].ActionTime endAbnormal = model.IsAbnormal endActionTime = workDayDetail.Records[0].ActionTime } //fmt.Println("startAbnormal: ", startAbnormal) //fmt.Println("startActionTime: ", startActionTime) //fmt.Println("endAbnormal: ", endAbnormal) //fmt.Println("endActionTime: ", endActionTime) } fmt.Println("================ 情况一 ======================") fmt.Println("================ 情况二 ======================") // 加班的 申请时间在 开始时间之后 if !applyStartTime.Before(offWorkTime) && !applyEndTime.Before(offWorkTime) { actionTime := common.ConvertActionTime(workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime) //fmt.Println("actionTime: ", actionTime) //fmt.Println("workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime: ", workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime) if workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime == "" { // 未打卡 startAbnormal = model.IsAbnormal startActionTime = workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime endAbnormal = model.IsAbnormal endActionTime = workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime //} else if !applyEndTime.Before(actionTime) { } else if applyEndTime.After(actionTime) { //startAbnormal = model.IsAbnormal //startActionTime = workDayDetail.Records[len(workDayDetail.Records)-1].WorkTime endAbnormal = model.IsAbnormal endActionTime = workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime } else { startAbnormal = model.NotAbnormal endAbnormal = model.NotAbnormal } //fmt.Println("startAbnormal: ", startAbnormal) //fmt.Println("startActionTime: ", startActionTime) //fmt.Println("endAbnormal: ", endAbnormal) //fmt.Println("endActionTime: ", endActionTime) } fmt.Println("================ 情况二 ======================") fmt.Println("================ 情况三 ======================") // 加班的 申请时间在 开始时间 在上班时间之前 结束时间 在下班时间之 后 if !applyStartTime.After(onWorkTime) && !applyEndTime.Before(offWorkTime) { onActionTime := common.ConvertActionTime(workDayDetail.Records[0].ActionTime) offActionTime := common.ConvertActionTime(workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime) //fmt.Println("onActionTime: ", onActionTime) //fmt.Println("offActionTime: ", offActionTime) if workDayDetail.Records[0].ActionTime == "" { // 未打卡 startAbnormal = model.IsAbnormal startActionTime = workDayDetail.Records[0].ActionTime } else if !applyStartTime.Before(onActionTime) { startAbnormal = model.NotAbnormal } else { startAbnormal = model.IsAbnormal startActionTime = workDayDetail.Records[0].ActionTime } //fmt.Println("startAbnormal: ", startAbnormal) //fmt.Println("startActionTime: ", startActionTime) if workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime == "" { // 未打卡 endAbnormal = model.IsAbnormal endActionTime = workDayDetail.Records[0].ActionTime } else if !applyEndTime.After(offActionTime) { endAbnormal = model.NotAbnormal } else { endAbnormal = model.IsAbnormal endActionTime = workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime } //fmt.Println("endAbnormal: ", endAbnormal) //fmt.Println("endActionTime: ", endActionTime) } } fmt.Println("================ 情况三 ======================") fmt.Println("================ 情况四 ======================") if workDayDetail.IsWork == model.IsFree { onActionTime := common.ConvertActionTime(workDayDetail.Records[0].ActionTime) offActionTime := common.ConvertActionTime(workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime) //fmt.Println("===================== MakeOverTimeAbnormal ======================") //fmt.Println("onActionTime: ", onActionTime) //fmt.Println("offActionTime: ", offActionTime) //fmt.Println("===================== MakeOverTimeAbnormal ======================") if !applyStartTime.Before(onActionTime) { startAbnormal = model.NotAbnormal } else { startAbnormal = model.IsAbnormal startActionTime = workDayDetail.Records[0].ActionTime } if !applyEndTime.After(offActionTime) { endAbnormal = model.NotAbnormal } else { endAbnormal = model.IsAbnormal endActionTime = workDayDetail.Records[len(workDayDetail.Records)-1].ActionTime } } fmt.Println("================ 情况四 ======================") return startAbnormal, endAbnormal, startActionTime, endActionTime } type ExcelAttendanceInfo struct { Date string // 日期 Attendance string // 考勤提示信息 Colour *excelize.Style // 考勤提示信息颜色 } type ExcelAttendanceList struct { StaffUID uint64 List []*ExcelAttendanceInfo } func GenerateAttendanceInfo(workDays []*model.WorkDayDetail, staffUID uint64, Month string) []ExcelAttendanceInfo { attendanceList := &ExcelAttendanceList{ StaffUID: staffUID, List: []*ExcelAttendanceInfo{}, } // 优先级高的颜色在后面,逐渐覆盖 colourPriority := map[string]int{ "#F0E0FF": 4, // 旷工 "#FFDCE3": 3, // 请假、加班、外勤等 "#FFEECB": 2, // 迟到、早退、缺卡 "#D5E6FF": 1, // 正常 "#FFFFFF": 0, // 休息 } // 解析查询的月份 parsedMonth, err := time.Parse("2006-01", Month) if err != nil { // 处理解析错误,返回空或日志 return []ExcelAttendanceInfo{} } // 上一个月 startDate := time.Date(parsedMonth.Year(), parsedMonth.Month()-1, 26, 0, 0, 0, 0, parsedMonth.Location()) // 上一个月26号 endDate := time.Date(parsedMonth.Year(), parsedMonth.Month(), 25, 0, 0, 0, 0, parsedMonth.Location()) // 本月25号 existingDates := make(map[string]bool) beginDateFormatted := startDate.Format("20060102") endDateFormatted := endDate.Format("20060102") holidays, err := holiday.GetMultiData(beginDateFormatted, endDateFormatted, false) allDates := make(map[string]bool) for _, i := range holidays { formattedDate := fmt.Sprintf("%04d-%02d-%02d", i.Year, i.Month, i.Day) // 确保格式为 "MM-DD" allDates[formattedDate] = i.Type != 0 // 非0表示假期 } // 处理考勤记录 for _, workDay := range workDays { var attendanceInfo string var finalColour *excelize.Style // 用于存储样式 var highestPriority int = 0 // 最高优先级,初始为休息的优先级 allMiss := true // 假设当天所有记录都是缺卡 // 标记当前日期为存在 existingDates[workDay.WorkDate] = true // 判断是否存在异常考勤 allCommon := true for _, record := range workDay.Records { if record.ActionType != "common" { allCommon = false break } } if !workDay.Abnormal && allCommon { attendanceInfo = "正常" // 判断是否为休息日 if isHoliday, exists := allDates[workDay.WorkDate]; exists && isHoliday { // 如果有打卡记录,显示上下班打卡时间 if len(workDay.Records) == 1 { // 只有一次打卡,显示为单次打卡的时间 attendanceInfo = fmt.Sprintf("休息日单次打卡: %s", workDay.Records[0].ActionTime) } else if len(workDay.Records) > 1 { // 多次打卡,显示上下班时间 clockInTime := workDay.Records[0].ActionTime // 第一条记录为上班打卡时间 clockOutTime := workDay.Records[len(workDay.Records)-1].ActionTime // 最后一条记录为下班打卡时间 attendanceInfo = fmt.Sprintf("休息日打卡:\n %s - %s", clockInTime, clockOutTime) } else { attendanceInfo = "休息日" } } finalColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#D5E6FF"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 正常 allMiss = false } else { // 处理每条打卡记录 for _, record := range workDay.Records { //hasAttendanceRecord = true // 发现打卡记录或申请 shift := "未知" // 默认值 if record.OnOff == "on" { shift = "上班" } else if record.OnOff == "off" { shift = "下班" } var currentInfo string var currentColour *excelize.Style // 用于存储当前记录的样式 switch record.ActionType { case "common": currentInfo = fmt.Sprintf("%s正常打卡", shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#D5E6FF"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 正常 allMiss = false // 有正常打卡,非全缺卡 case "goOut": currentInfo = fmt.Sprintf("%s %s外出", record.ActionTime, shift) actionTime, err := time.Parse("2006-01-02 15:04", record.ActionTime) if err != nil { fmt.Println("无法解析 ActionTime:", err) break } if len(record.ApplyInfo) > 0 { for _, s := range record.ApplyInfo { if len(s.ItineraryList) > 0 { for _, m := range s.ItineraryList { applyStartDate := strings.Split(m.ApplyStartTime, " ")[0] applyEndDate := strings.Split(m.ApplyStartTime, " ")[0] // 提取 ActionTime 的日期部分 actionDate := actionTime.Format("2006-01-02") // 当 ApplyStartTime 和 ActionTime 的日期匹配时,更新出差信息 if applyStartDate == actionDate { currentInfo = fmt.Sprintf("%s %s外出至%s", actionDate, shift, applyEndDate) break // 找到匹配的记录后退出循环 } } } } } currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 正常 allMiss = false // 有正常打卡,非全缺卡 case "miss": currentInfo = fmt.Sprintf("%s %s缺卡", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFEECB"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 缺卡 //allCommon = false case "late": if record.IsExtremeLateness { currentInfo = fmt.Sprintf("%s %s严重迟到", shift, record.ActionTime) } else { currentInfo = fmt.Sprintf("%s %s迟到", shift, record.ActionTime) } currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFEECB"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 迟到 allMiss = false // 有迟到记录,非全缺卡 //allCommon = false case "before": currentInfo = fmt.Sprintf("%s %s早退", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFEECB"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 早退 allMiss = false case "overTime": currentInfo = fmt.Sprintf("%s %s加班", shift, record.ActionTime) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 加班 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "leave": currentInfo = fmt.Sprintf("%s %s事假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "sick": currentInfo = fmt.Sprintf("%s %s病假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "dayOff": currentInfo = fmt.Sprintf("%s %s调休", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "annualLeave": currentInfo = fmt.Sprintf("%s %s年假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "maritalLeave": currentInfo = fmt.Sprintf("%s %s婚假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "matingCheckLeave": currentInfo = fmt.Sprintf("%s %s孕检假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "maternityLeave": currentInfo = fmt.Sprintf("%s %s产假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "paternityLeave": currentInfo = fmt.Sprintf("%s %s陪产假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "parentalLeave": currentInfo = fmt.Sprintf("%s %s育儿假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "nursingLeave": currentInfo = fmt.Sprintf("%s %s独生子女护理假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "funeralLeave": currentInfo = fmt.Sprintf("%s %s丧假", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "makeUp": currentInfo = fmt.Sprintf("%s %s补卡", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "outWork": currentInfo = fmt.Sprintf("%s外勤", shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "makeUpSys": currentInfo = fmt.Sprintf("%s %s系统补卡", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false case "businessTrip": currentInfo = fmt.Sprintf("%s %s出差", record.ActionTime, shift) actionTime, err := time.Parse("2006-01-02 15:04", record.ActionTime) if err != nil { fmt.Println("无法解析 ActionTime:", err) break } if len(record.ApplyInfo) > 0 { for _, s := range record.ApplyInfo { if len(s.ItineraryList) > 0 { for _, m := range s.ItineraryList { applyStartDate := strings.Split(m.ApplyStartTime, " ")[0] applyEndDate := strings.Split(m.ApplyStartTime, " ")[0] // 提取 ActionTime 的日期部分 actionDate := actionTime.Format("2006-01-02") // 当 ApplyStartTime 和 ActionTime 的日期匹配时,更新出差信息 if applyStartDate == actionDate { currentInfo = fmt.Sprintf("%s %s出差至%s", actionDate, shift, applyEndDate) break // 找到匹配的记录后退出循环 } } } } } //currentInfo = fmt.Sprintf("%s %s出差", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFDCE3"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 事假 allMiss = false // 有早退记录,非全缺卡 //allCommon = false default: currentInfo = fmt.Sprintf("%s %s未知记录类型", record.ActionTime, shift) currentColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFFFFF"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 默认白色 allMiss = false // 有其他记录,非全缺卡 //allCommon = false } // 拼接考勤提示信息 if attendanceInfo == "" { attendanceInfo = currentInfo } else { attendanceInfo = fmt.Sprintf("%s\n%s", attendanceInfo, currentInfo) // 换行拼接 } // 检查颜色优先级 if priority, exists := colourPriority[currentColour.Fill.Color[0]]; exists && priority > highestPriority { highestPriority = priority finalColour = currentColour // 更新为优先级最高的颜色 } } } // 如果当天所有记录都是缺卡,将考勤信息标记为旷工 if allMiss && workDay.IsWork == 1 { attendanceInfo = "旷工" finalColour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#F0E0FF"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 旷工的颜色 } // 添加到列表中 attendanceList.List = append(attendanceList.List, &ExcelAttendanceInfo{ Date: workDay.WorkDate, Attendance: attendanceInfo, Colour: finalColour, }) } // 处理缺失日期 // 遍历日期范围 for day := startDate; day.Before(endDate) || day.Equal(endDate); day = day.AddDate(0, 0, 1) { formattedDay := day.Format("2006-01-02") // 将日期格式化为 "YYYY-MM-DD" if _, exists := existingDates[formattedDay]; !exists { isHoliday := allDates[formattedDay] // 检查当前日期是否是假期 var attendance string var colour *excelize.Style if isHoliday { // 假期处理 attendance = "休息日" colour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFFFFF"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 白色 } else { // 工作日旷工处理 attendance = "旷工" colour = &excelize.Style{Fill: excelize.Fill{Type: "pattern", Color: []string{"#F0E0FF"}, Pattern: 1}, Alignment: &excelize.Alignment{ Horizontal: "center", // 水平居中 Vertical: "center", // 垂直居中 WrapText: true, // 启用换行 }, Border: []excelize.Border{ {Type: "left", Style: 1, Color: "#000000"}, {Type: "right", Style: 1, Color: "#000000"}, {Type: "top", Style: 1, Color: "#000000"}, {Type: "bottom", Style: 1, Color: "#000000"}, }} // 旷工颜色 } // 添加到考勤列表 attendanceList.List = append(attendanceList.List, &ExcelAttendanceInfo{ Date: formattedDay, Attendance: attendance, Colour: colour, }) } } sort.Slice(attendanceList.List, func(i, j int) bool { return attendanceList.List[i].Date < attendanceList.List[j].Date }) // 将指针切片转换为值切片返回 var result []ExcelAttendanceInfo for _, info := range attendanceList.List { result = append(result, *info) // 解引用并添加到值切片 } return result }