package crontab import ( "fmt" "kpt-pasture/model" "kpt-pasture/util" "sort" "strconv" "strings" "time" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "go.uber.org/zap" ) func (e *Entry) UpdateMilkOriginal() error { pastureList := e.FindPastureList() if pastureList == nil || len(pastureList) == 0 { return nil } for _, pasture := range pastureList { e.ProcessMilkOriginal(pasture.Id) } return nil } func (e *Entry) ProcessMilkOriginal(pastureId int64) { milkConfigList, err := e.FindMilkConfigure(pastureId) if err != nil { zaplog.Error("MilkOriginal", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } milkClassConfig := &MilkClassConfig{} for _, v := range milkConfigList { switch v.Name { case model.FirstClassMilkTime: milkClassConfig.FirstClassMilkTime = v.Value case model.SecondClassMilkTime: milkClassConfig.SecondClassMilkTime = v.Value case model.ThirdClassMilkTime: milkClassConfig.ThirdClassMilkTime = v.Value case model.FourthClassMilkTime: milkClassConfig.FourthClassMilkTime = v.Value case model.UpdateMilkOriginalMaxId: maxId, _ := strconv.ParseInt(v.Value, 10, 64) milkClassConfig.OldUpdateMaxId = maxId } } xDBeg, xBeg1, xBeg2, xBeg3, xBeg4 := parseXBeg(milkClassConfig) e.UpdateShifts(pastureId, xBeg1, xBeg2, xBeg3, xBeg4) e.UpdateMilkDate(pastureId, xDBeg) // 获取当前最大Id var currentMaxId int64 if err = e.DB.Model(new(model.MilkOriginal)). Select("MAX(id)"). Where("pasture_id = ?", pastureId). Where("id > ?", milkClassConfig.OldUpdateMaxId). Scan(¤tMaxId).Error; err != nil { zaplog.Error("DeleteRepeatMilkData GetOriWid", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } milkClassConfig.CurrentMaxId = currentMaxId // 获取时间范围和ID范围 deleteModel := &DeleteMilkOriginal{} selectSql := fmt.Sprintf(`MIN(DATE(TIMESTAMPADD(HOUR, -%d, attach_time))) as x_mind, MAX(DATE(TIMESTAMPADD(HOUR, -%d, attach_time))) as x_max_d2, MIN(id) as x_min_wid, MAX(id) as x_max_wid`, xDBeg, xDBeg) if err = e.DB.Model(new(model.MilkOriginal)). Select(selectSql). Where("pasture_id = ?", pastureId). Where("id > ?", milkClassConfig.OldUpdateMaxId). First(deleteModel).Error; err != nil { zaplog.Error("DeleteRepeatMilkData", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } milkOriginalList := make([]*model.MilkOriginal, 0) if err = e.DB.Model(new(model.MilkOriginal)). Where("pasture_id = ?", pastureId). Where("id BETWEEN ? AND ?", milkClassConfig.OldUpdateMaxId+1, milkClassConfig.CurrentMaxId). Find(&milkOriginalList).Error; err != nil { zaplog.Error("DeleteRepeatMilkData", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } e.DeleteRepeatMilkData(pastureId, deleteModel, milkClassConfig, milkOriginalList) e.MilkHallData(pastureId) e.UpdateRepeatCupSet1(milkOriginalList) e.UpdateMilkOriginCowInfo(milkOriginalList) e.UpdateRepeatCupSet2(milkOriginalList) } // UpdateShifts 更新班次 func (e *Entry) UpdateShifts(pastureId int64, xBeg1, xBeg2, xBeg3, xBeg4 int) { milkOriginalList := make([]*model.MilkOriginal, 0) if err := e.DB.Model(new(model.MilkOriginal)). Where("pasture_id = ?", pastureId). Where("shifts = ?", 0). Find(&milkOriginalList).Error; err != nil { zaplog.Error("UpdateShifts", zap.Any("pastureId", pastureId), zap.Any("err", err)) } for _, v := range milkOriginalList { subDetachTime1 := util.Substr(v.DetacherTime, 11, 2) subDetachTime2 := util.Substr(v.DetacherTime, 14, 2) subDetachTime1Int, _ := strconv.ParseInt(subDetachTime1, 10, 64) subDetachTime2Int, _ := strconv.ParseInt(subDetachTime2, 10, 64) allDetachTime := int(subDetachTime1Int*100 + subDetachTime2Int) // 更新第一班 if xBeg2 > xBeg1 { if allDetachTime >= xBeg1 && allDetachTime <= xBeg2 { v.Shifts = 1 } } else { if allDetachTime >= xBeg1 || allDetachTime <= xBeg2 { v.Shifts = 1 } } // 更新第二班 if xBeg3 > xBeg2 { if allDetachTime >= xBeg2 && allDetachTime <= xBeg3 { v.Shifts = 2 } } else { if allDetachTime >= xBeg2 || allDetachTime <= xBeg3 { v.Shifts = 2 } } // 更新第四班(如果有) if xBeg4 > 0 && xBeg4 != xBeg1 { if xBeg1 > xBeg4 { if allDetachTime >= xBeg4 && allDetachTime <= xBeg1 { v.Shifts = 4 } } else { if allDetachTime >= xBeg4 || allDetachTime <= xBeg1 { v.Shifts = 4 } } } // 如果还没有分配班次,则分配到第三班 if v.Shifts == 0 { v.Shifts = 3 } // 批量更新数据库 if err := e.DB.Model(new(model.MilkOriginal)). Select("shifts"). Where("id = ?", v.Id). Updates(v).Error; err != nil { zaplog.Error("UpdateShifts Save", zap.Any("pastureId", pastureId), zap.Any("err", err)) } } } // UpdateMilkDate 更换挤奶时间 func (e *Entry) UpdateMilkDate(pastureId int64, xDBeg int) { milkOriginalList := make([]*model.MilkOriginal, 0) if err := e.DB.Model(new(model.MilkOriginal)). Where("pasture_id = ?", pastureId). Where("milk_date = ?", ""). Find(&milkOriginalList).Error; err != nil { zaplog.Error("UpdateMilkDate", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } for _, v := range milkOriginalList { // 获取结束时间,如果为空则使用默认时间 var endTime time.Time if v.EndTime == "" { endTime = time.Date(1999, 12, 31, 23, 0, 0, 0, time.Local) } // 比较挤奶时间和结束时间,取较晚的时间 detacherTime, _ := util.TimeParseLocal(model.LayoutTime, v.DetacherTime) latestTime := detacherTime if endTime.After(detacherTime) { latestTime = endTime } // 减去xDBeg小时并获取日期 milkDate := latestTime.Add(time.Duration(-xDBeg) * time.Hour).Format(model.LayoutDate2) // 更新数据库 if err := e.DB.Model(new(model.MilkOriginal)). Select("milk_date"). Where("id = ?", v.Id). Update("milk_date", milkDate).Error; err != nil { zaplog.Error("UpdateMilkDate", zap.Any("err", err), zap.Any("milkDate", milkDate)) } } } // DeleteRepeatMilkData 删除重复数据 func (e *Entry) DeleteRepeatMilkData(pastureId int64, deleteModel *DeleteMilkOriginal, cfg *MilkClassConfig, milkOriginalList []*model.MilkOriginal) { // 获取最小日期对应的最小wid var oriWid int64 if err := e.DB.Model(new(model.MilkOriginal)). Select("MIN(id)"). Where("pasture_id = ?", pastureId). Where("milk_date = ?", deleteModel.XMind). Scan(&oriWid).Error; err != nil { zaplog.Error("DeleteRepeatMilkData GetOriWid", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } for _, v := range milkOriginalList { e.delete1(v, deleteModel.XMind, cfg) e.delete2(v, deleteModel.XMind, cfg) e.delete3(v, deleteModel.XMind, cfg) e.delete4(v, deleteModel.XMind, cfg) } } func (e *Entry) MilkHallData(pastureId int64) { milkHallList := e.FindMilkHallList(pastureId) if len(milkHallList) == 0 { return } for _, v := range milkHallList { e.UpdateRecognitionTime(pastureId, v) } } // UpdateRecognitionTime 识别时间超过40分钟未套杯牛只,识别改为未识别 func (e *Entry) UpdateRecognitionTime(pastureId int64, hall *model.MilkHall) { milkOriginalList := make([]*model.MilkOriginal, 0) if err := e.DB.Model(new(model.MilkOriginal)). Where("pasture_id = ?", pastureId). Where("milk_hall_number = ?", hall.Name). Where("milk_hall_brand = ?", hall.Brand). Where("load = ?", 0). Find(&milkOriginalList).Error; err != nil { zaplog.Error("MilkHallData", zap.Any("err", err)) } for _, v := range milkOriginalList { t1, _ := util.TimeParseLocal(model.LayoutTime, v.AttachTime) t2, _ := util.TimeParseLocal(model.LayoutTime, v.RecognitionTime) diff := t1.Sub(t2) minute := int(diff.Minutes()) if util.Substr(v.RecognitionTime, -1, 8) != "00:00:00" && minute > 40 { if err := e.DB.Model(new(model.MilkOriginal)). Where("id = ?", v.Id). Updates(map[string]interface{}{ "cow_id": 0, "ele_ear_number": "", "recognition_time": fmt.Sprintf("%s 00:00:00", util.Substr(v.RecognitionTime, 0, 10)), }).Error; err != nil { zaplog.Error("MilkHallData", zap.Any("err", err)) } } } } // UpdateRepeatCupSet1 更新重复套杯1, 识别时间相同,且不为0为重复套杯 func (e *Entry) UpdateRepeatCupSet1(milkOriginalList []*model.MilkOriginal) { if len(milkOriginalList) == 0 { return } milkOriginalMap := make(map[string][]*model.MilkOriginal) for _, v := range milkOriginalList { if strings.HasSuffix(v.RecognitionTime, "00:00:00") { continue } key := fmt.Sprintf("%s_%d_%d_%s", v.MilkDate, v.Shifts, v.DetacherAddress, v.RecognitionTime) milkOriginalMap[key] = append(milkOriginalMap[key], v) } for _, originalList := range milkOriginalMap { if len(originalList) >= 2 { // 按照Id升序排序(保留第一条) sort.Slice(originalList, func(i, j int) bool { return originalList[i].Id < originalList[j].Id }) for i, v := range originalList { if i == 0 { continue } if err := e.DB.Model(new(model.MilkOriginal)). Select("").Where("id = ?", v.Id). Update("nattach", 2).Error; err != nil { zaplog.Error("UpdateRepeatCupSet1", zap.Any("err", err)) } } } } } func (e *Entry) UpdateMilkOriginCowInfo(milkOriginalList []*model.MilkOriginal) { } // UpdateRepeatCupSet2 非标准重复套杯 func (e *Entry) UpdateRepeatCupSet2(milkOriginalList []*model.MilkOriginal) { for _, v := range milkOriginalList { if v.AttachTime == "" || v.InitialTime == "" { continue } attchTime, _ := util.TimeParseLocal(model.LayoutTime, v.AttachTime) initialTime, _ := util.TimeParseLocal(model.LayoutTime, v.InitialTime) if util.Substr(v.InitialTime, -1, 5) != "00:00" && v.Nattach == 0 && attchTime.Sub(initialTime).Minutes() <= 1 { if err := e.DB.Model(new(model.MilkOriginal)). Select("nattach"). Where("id = ?", v.Id). Update("nattach", 2).Error; err != nil { zaplog.Error("UpdateRepeatCupSet2", zap.Any("err", err)) } } } } func (e *Entry) delete1(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) { // 1. 删除attach_time为00:00:00的记录 acctchStr := util.Substr(data.AttachTime, -1, 8) if data.MilkDate < xMinD || acctchStr != "00:00:00" { return } // 2. 检查是否存在符合条件的m2记录 var count int64 if err := e.DB.Model(new(model.MilkOriginal)). Where("wid BETWEEN ? AND ?", cfg.OldUpdateMaxId+1, cfg.CurrentMaxId). Where("milk_date = ?", data.MilkDate). Where("detacher_address = ?", data.DetacherAddress). Where("ABS(TIMESTAMPDIFF(SECOND, detach_time, ?)) < 10", data.DetacherTime). Where("milk_weight = ?", data.MilkWeight). Where("pasture_id = ?", data.PastureId). Where("RIGHT(attach_time, 8) != '00:00:00'"). Count(&count).Error; err != nil { zaplog.Error("Delete1", zap.Any("err", err)) return } if count > 0 { if err := e.DB.Model(new(model.MilkOriginal)). Where("id = ?", data.Id). Delete(data).Error; err != nil { zaplog.Error("Delete1", zap.Any("err", err), zap.Any("data", data)) } } } func (e *Entry) delete2(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) { // 1. 检查记录是否在时间范围内 if data.MilkDate < xMinD { return } // 2. 检查是否存在重复记录(除第一条外) var count int64 if err := e.DB.Model(new(model.MilkOriginal)). Where("id BETWEEN ? AND ?", cfg.OldUpdateMaxId+1, cfg.CurrentMaxId). Where("milk_date = ?", data.MilkDate). Where("shifts = ?", data.Shifts). Where("detacher_address = ?", data.DetacherAddress). Where("attach_time = ?", data.AttachTime). Where("milk_weight = ?", data.MilkWeight). Where("pasture_id = ?", data.PastureId). Where("id < ?", data.Id). // 只查找比当前记录更早的记录 Count(&count).Error; err != nil { zaplog.Error("Delete2", zap.Any("err", err)) return } // 3. 如果存在重复记录,则删除当前记录 if count > 0 { if err := e.DB.Model(new(model.MilkOriginal)). Where("id = ?", data.Id). Delete(data).Error; err != nil { zaplog.Error("Delete2", zap.Any("err", err), zap.Any("data", data)) } } } func (e *Entry) delete3(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) { // 1. 检查记录是否在时间范围内 if data.MilkDate < xMinD { return } // 2. 检查是否为班次开始且无奶量记录 var isFirstInShift bool if err := e.DB.Raw(` SELECT 1 FROM ( SELECT m.id, m.milk_date, m.shifts, m.milk_weight, @tot := IF(@tot + m.milk_weight > 100, 100, IF(m.shifts = @shifts, @tot, 0) + m.milk_weight) m_tot, @shifts := m.shifts FROM milk_original m, (SELECT @tot := 0, @shifts := 0) vars WHERE m.id BETWEEN ? AND ? AND m.milk_date >= ? AND m.pasture_id = ? ORDER BY m.milk_date, m.shifts, m.attach_time ) t WHERE t.id = ? AND t.m_tot = 0`, cfg.OldUpdateMaxId+1, cfg.CurrentMaxId, xMinD, data.PastureId, data.Id). Scan(&isFirstInShift).Error; err != nil { zaplog.Error("Delete3", zap.Any("err", err)) return } // 3. 如果是班次开始且无奶量记录,则删除 if isFirstInShift { if err := e.DB.Model(new(model.MilkOriginal)). Where("id = ?", data.Id). Delete(data).Error; err != nil { zaplog.Error("Delete3", zap.Any("err", err), zap.Any("data", data)) } } } func (e *Entry) delete4(data *model.MilkOriginal, xMinD string, cfg *MilkClassConfig) { // 1. 检查记录是否在时间范围内 if data.MilkDate < "2020-10-01" { return } // 2. 检查是否为时间异常记录 var isAbnormal bool if err := e.DB.Model(new(model.MilkOriginal)). Where("id = ?", data.Id). Where("milk_date >= ?", "2020-10-01"). Where("recognition_time > detacher_time"). Where("attach_time > detacher_time"). Where("SUBSTRING(attach_time, 12, 2) = ?", "23"). Where("pasture_id = ?", data.PastureId). Select("1"). Scan(&isAbnormal).Error; err != nil { zaplog.Error("Delete4", zap.Any("err", err)) return } // 3. 如果是时间异常记录,则删除 if isAbnormal { if err := e.DB.Model(new(model.MilkOriginal)). Where("id = ?", data.Id). Delete(data).Error; err != nil { zaplog.Error("Delete4", zap.Any("err", err), zap.Any("data", data)) } } } func parseXBeg(cfg *MilkClassConfig) (xBeg, xBeg1, xBeg2, xBeg3, xBeg4 int) { xBeg1Parts := strings.Split(cfg.FirstClassMilkTime, ":") if len(xBeg1Parts) < 2 { return } // 提取最后一部分 xBeg1LastPart, _ := strconv.Atoi(xBeg1Parts[len(xBeg1Parts)-1]) xBeg, _ = strconv.Atoi(xBeg1Parts[0]) xBeg1, _ = strconv.Atoi(xBeg1Parts[1]) xBeg1 = xBeg1*100 + xBeg1LastPart xBeg2Parts := strings.Split(cfg.SecondClassMilkTime, ":") if len(xBeg2Parts) < 2 { return } xBeg2LastPart, _ := strconv.Atoi(xBeg2Parts[len(xBeg2Parts)-1]) xBeg2, _ = strconv.Atoi(xBeg2Parts[0]) xBeg2 = xBeg2*100 + xBeg2LastPart xBeg3Parts := strings.Split(cfg.ThirdClassMilkTime, ":") if len(xBeg3Parts) < 2 { return } xBeg3LastPart, _ := strconv.Atoi(xBeg3Parts[len(xBeg3Parts)-1]) xBeg3, _ = strconv.Atoi(xBeg3Parts[0]) xBeg3 = xBeg3*100 + xBeg3LastPart xBeg4Parts := strings.Split(cfg.FourthClassMilkTime, ":") if len(xBeg4Parts) < 2 { return } xBeg4LastPart, _ := strconv.Atoi(xBeg4Parts[len(xBeg4Parts)-1]) xBeg4, _ = strconv.Atoi(xBeg4Parts[0]) xBeg4 = xBeg4*100 + xBeg4LastPart return }