package backend import ( "context" "errors" "fmt" "kpt-pasture/model" "kpt-pasture/util" "net/http" "strings" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "gitee.com/xuyiping_admin/pkg/xerr" "go.uber.org/zap" "gorm.io/gorm" ) func (s *StoreEntry) OrderList(ctx context.Context, req *pasturePb.SearchWorkOrderRequest, pagination *pasturePb.PaginationModel) (*pasturePb.SearchWorkOrderResponse, error) { workOrderList := make([]*model.WorkOrderMaster, 0) var count int64 = 0 pref := s.DB.Model(new(model.WorkOrderMaster)) if req.Name != "" { pref.Where("name like ?", fmt.Sprintf("%s%s%s", "%", req.Name, "%")) } if req.Frequency > 0 { pref.Where("frequency = ?", req.Frequency) } if req.Priority > 0 { pref.Where("priority = ?", req.Priority) } if req.IsShow > 0 { pref.Where("is_show = ?", req.IsShow) } if req.SubscribeUnit > 0 { pref.Where("subscribe_unit = ?", req.SubscribeUnit) } if req.CategoryId > 0 { pref.Where("category_id = ?", req.CategoryId) } if err := pref.Order("id desc").Count(&count).Limit(int(pagination.PageSize)).Offset(int(pagination.PageOffset)). Find(&workOrderList).Error; err != nil { return nil, xerr.WithStack(err) } priorityMap := s.WorkOrderPriorityMap() frequencyMap := s.WorkOrderFrequencyMap() subscribeUnitMap := s.WorkOrderSubUnitMap() weekMap := s.WeekMap() monthMap := s.MonthMap() return &pasturePb.SearchWorkOrderResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.SearchWorkOrderData{ List: model.WorkOrderMasterSlice(workOrderList).ToPB(priorityMap, frequencyMap, subscribeUnitMap, weekMap, monthMap), Total: int32(count), PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil } // OrderCreateOrUpdate 创建和更新工单 // 周期性工单【包括每天,每周,每月】一次性生成符合本月日期所有工单 // 更新工单的时候需要重新维护子工单 func (s *StoreEntry) OrderCreateOrUpdate(ctx context.Context, req *pasturePb.WorkOrderList) error { userModel, err := s.GetUserModel(ctx) if err != nil { return xerr.WithStack(err) } workOrderCategoryMap := s.WorkOrderCategoryMap() systemUserList, _ := s.SystemUserList(ctx) newWorkOrderMaster := model.NewWorkOrderMaster(userModel.AppPasture.Id, req, userModel.SystemUser, systemUserList, workOrderCategoryMap) if req.Id <= 0 { if err := s.DB.Transaction(func(tx *gorm.DB) error { if err := tx.Create(newWorkOrderMaster).Error; err != nil { return xerr.WithStack(err) } newWorkOrderSubList := model.NewWorkOrderSub(newWorkOrderMaster) if len(newWorkOrderSubList) > 0 { if err := tx.Create(&newWorkOrderSubList).Error; err != nil { return xerr.WithStack(err) } } return nil }); err != nil { return xerr.WithStack(err) } } else { if err := s.DB.Transaction(func(tx *gorm.DB) error { if err := tx.Model(newWorkOrderMaster).Where("id = ?", req.Id).Updates(map[string]interface{}{ "name": newWorkOrderMaster.Name, "frequency": newWorkOrderMaster.Frequency, "priority": newWorkOrderMaster.Priority, "subscribe_unit": newWorkOrderMaster.SubscribeUnit, "category_id": newWorkOrderMaster.CategoryId, "exec_time": newWorkOrderMaster.ExecTime, "exec_persons": newWorkOrderMaster.ExecPersons, "exec_person_names": newWorkOrderMaster.ExecPersonNames, "week_month_value": newWorkOrderMaster.WeekMonthValue, "remarks": newWorkOrderMaster.Remarks, "photos": newWorkOrderMaster.Photos, }).Error; err != nil { return xerr.WithStack(err) } if err := s.WorkOrderSubUpdate(tx, newWorkOrderMaster); err != nil { return xerr.WithStack(err) } return nil }); err != nil { return xerr.WithStack(err) } } return nil } // OrderIsShow 工单的开启和关闭 func (s *StoreEntry) OrderIsShow(ctx context.Context, id int64) error { workOrderMaster := &model.WorkOrderMaster{Id: id} if err := s.DB.First(workOrderMaster).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return xerr.Custom("该工单不存在") } return xerr.WithStack(err) } isShow := pasturePb.IsShow_No if workOrderMaster.IsShow == pasturePb.IsShow_No { isShow = pasturePb.IsShow_Ok } if err := s.DB.Transaction(func(tx *gorm.DB) error { if err := tx.Model(workOrderMaster).Where("id = ?", id).Update("is_show", isShow).Error; err != nil { return xerr.WithStack(err) } workOrderMaster.IsShow = isShow if err := s.WorkOrderSubUpdate(tx, workOrderMaster); err != nil { return xerr.WithStack(err) } return nil }); err != nil { return xerr.WithStack(err) } return nil } // WorkOrderSubUpdate 子工单重新维护 // 如果工单是开启状态,则重新生成子工单,如果工单是关闭状态,则取消子工单 func (s *StoreEntry) WorkOrderSubUpdate(tx *gorm.DB, workOrderMaster *model.WorkOrderMaster) error { if workOrderMaster.IsShow == pasturePb.IsShow_Ok { newWorkOrderSubList := model.NewWorkOrderSub(workOrderMaster) if len(newWorkOrderSubList) <= 0 { return nil } if err := tx.Create(&newWorkOrderSubList).Error; err != nil { return xerr.WithStack(err) } } else { // 获取当天的零点时间 zeroTime := util.TimeParseLocalUnix(time.Now().Format("2006-01-02")) // 先检查是否存在符合条件的记录 var count int64 if err := tx.Model(&model.WorkOrderSub{}). Where("work_order_master_id = ?", workOrderMaster.Id). Where("is_show = ?", pasturePb.IsShow_Ok). Where("exec_time > ?", zeroTime). Where("status = ?", pasturePb.WorkOrderStatus_Distribute). Count(&count).Error; err != nil { return xerr.WithStack(err) } if count <= 0 { return nil } if err := tx.Model(new(model.WorkOrderSub)). Where("work_order_master_id = ?", workOrderMaster.Id). Where("is_show = ?", pasturePb.IsShow_Ok). Where("exec_time > ?", zeroTime). Where("status = ?", pasturePb.WorkOrderStatus_Distribute). Update("status", pasturePb.WorkOrderStatus_Canceled).Error; err != nil { return xerr.WithStack(err) } } return nil } func (s *StoreEntry) SendAsynqWorkOrder(ctx context.Context, workOrder *model.WorkOrderMaster) { if workOrder.IsShow == pasturePb.IsShow_No { return } timeUnix, _ := util.ConvertParseLocalUnix(workOrder.ExecTime) nowTime := time.Now() // 过滤掉10秒内要执行的任务 if timeUnix <= nowTime.Unix()+10 { return } // 判断是否是周任务,并且当前周不在执行周期内,则不执行任务 if workOrder.WeekMonthValue != "" { execWeekMonth := strings.Split(workOrder.WeekMonthValue, ",") currentWeekMonth := "" if workOrder.Frequency == pasturePb.WorkOrderFrequency_Weekly { currentWeekMonth = fmt.Sprintf("%d", nowTime.Weekday()) } if workOrder.Frequency == pasturePb.WorkOrderFrequency_Monthly { currentWeekMonth = fmt.Sprintf("%d", nowTime.Day()) } var info bool for _, weekMonth := range execWeekMonth { if currentWeekMonth == weekMonth { info = true break } } // 如果有,则不执行任务 if info { return } } execTime := time.Now().Unix() - timeUnix if _, err := s.AsynqClient.CtxEnqueue( ctx, model.NewTaskWorkOrderPayload(workOrder.Id, time.Duration(execTime)*time.Second), ); err != nil { zaplog.Error("PushMessage CtxEnqueue", zap.Any("Err", err)) } } // UserWorkOrderList 用户工单列表 func (s *StoreEntry) UserWorkOrderList(ctx context.Context, workOrderStatus pasturePb.WorkOrderStatus_Kind, pagination *pasturePb.PaginationModel) (*pasturePb.UserWorkOrderResponse, error) { userModel, err := s.GetUserModel(ctx) if err != nil { return nil, xerr.WithStack(err) } var count int64 = 0 userWorkOrderList := make([]*model.WorkOrderSub, 0) pref := s.DB.Model(userWorkOrderList). Where("is_show = ?", pasturePb.IsShow_Ok) if workOrderStatus != pasturePb.WorkOrderStatus_Invalid { pref.Where("status = ?", workOrderStatus) } if err = pref.Where( s.DB.Where("exec_user_id = ?", userModel.SystemUser.Id). Or("FIND_IN_SET(?, set_user_ids) > 0", userModel.SystemUser.Id), ). Order("id desc"). Count(&count). Limit(int(pagination.PageSize)). Offset(int(pagination.PageOffset)). Find(&userWorkOrderList).Error; err != nil { return nil, xerr.WithStack(err) } mMap := make(map[int64]*model.WorkOrderMaster) workOderMasterList := make([]*model.WorkOrderMaster, 0) if err = s.DB.Model(&model.WorkOrderMaster{}).Find(&workOderMasterList).Error; err != nil { return nil, xerr.WithStack(err) } for _, workOrderMaster := range workOderMasterList { mMap[workOrderMaster.Id] = workOrderMaster } priorityMap := s.WorkOrderPriorityMap() return &pasturePb.UserWorkOrderResponse{ Code: http.StatusOK, Msg: "ok", Data: &pasturePb.UserWorkOrderData{ List: model.WorkOrderSubSlice(userWorkOrderList).ToPB(mMap, priorityMap), Total: 0, PageSize: pagination.PageSize, Page: pagination.Page, }, }, nil }