package opsdev import ( "context" "fmt" "regexp" "strings" "dashoo.cn/common_definition/comm_def" "dashoo.cn/opms_libary/myerrors" opsdevdao "dashoo.cn/opms_parent/app/dao/opsdev" opsdevmodel "dashoo.cn/opms_parent/app/model/opsdev" "dashoo.cn/opms_parent/app/service" "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/gvalid" ) type OperationService struct { *service.ContextService Dao *opsdevdao.OpsOperationEventDao RecordDao *opsdevdao.OpsOperationEventRecordDao AttachmentDao *opsdevdao.OpsOperationEventAttachmentDao } func NewOperationService(ctx context.Context) (svc *OperationService, err error) { svc = new(OperationService) if svc.ContextService, err = svc.Init(ctx); err != nil { return nil, err } svc.Dao = opsdevdao.NewOpsOperationEventDao(svc.Tenant) svc.RecordDao = opsdevdao.NewOpsOperationEventRecordDao(svc.Tenant) svc.AttachmentDao = opsdevdao.NewOpsOperationEventAttachmentDao(svc.Tenant) return svc, nil } // GetList 运维事件列表 func (s *OperationService) GetList(req *opsdevmodel.OpsOperationEventSearchReq) (total int, list []*opsdevmodel.OpsOperationEvent, err error) { db := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).Where(s.Dao.Columns.EventStatus+" != ?", opsdevmodel.EventStatusClosed) if req.EventNo != "" { db = db.Where(s.Dao.Columns.EventNo, req.EventNo) } if req.EventTitle != "" { db = db.Where(s.Dao.Columns.EventTitle+" like ?", "%"+req.EventTitle+"%") } if req.EventStatus != "" { db = db.Where(s.Dao.Columns.EventStatus, req.EventStatus) } if req.EventType != "" { db = db.Where(s.Dao.Columns.EventType, req.EventType) } if req.PriorityLevel != "" { db = db.Where(s.Dao.Columns.PriorityLevel, req.PriorityLevel) } if req.IsBig != "" { db = db.Where(s.Dao.Columns.IsBig, req.IsBig) } if req.IsOps != "" { db = db.Where(s.Dao.Columns.IsOps, req.IsOps) } if req.CustName != "" { db = db.Where(s.Dao.Columns.CustName+" like ?", "%"+req.CustName+"%") } if req.OpsUserName != "" { db = db.Where(s.Dao.Columns.OpsUserName+" like ?", "%"+req.OpsUserName+"%") } if req.ContractName != "" { db = db.Where(s.Dao.Columns.ContractName+" like ?", "%"+req.ContractName+"%") } if req.ProductLine != "" { db = db.Where(s.Dao.Columns.ProductLine, req.ProductLine) } if req.BeginTime != "" { db = db.Where(s.Dao.Columns.CreatedTime+" >= ?", req.BeginTime) } if req.EndTime != "" { db = db.Where(s.Dao.Columns.CreatedTime+" <= ?", req.EndTime) } total, err = db.Count() if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询运维事件数量失败") } pageNum, pageSize := req.GetPage() err = db.Page(pageNum, pageSize).Order(s.Dao.Columns.CreatedTime + " desc").Scan(&list) if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询运维事件列表失败") } return total, list, nil } // GetEntityById 运维事件详情 func (s *OperationService) GetEntityById(req *comm_def.IdReq) (detail *opsdevmodel.OpsOperationEvent, err error) { if req.Id <= 0 { return nil, myerrors.ValidError("参数有误!") } detail = new(opsdevmodel.OpsOperationEvent) err = s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).WherePri(s.Dao.Columns.Id, req.Id).Scan(detail) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询运维事件详情失败") } if detail.Id <= 0 { return nil, myerrors.TipsError("运维事件不存在") } return detail, nil } // Create 创建运维事件 func (s *OperationService) Create(req *opsdevmodel.OpsOperationEventReq) (err error) { if err = gvalid.CheckStruct(s.Ctx, req, nil); err != nil { return myerrors.ValidError(err.Error()) } data := gconv.Map(req) service.SetCreatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) data["eventNo"] = generateEventNo() data["eventStatus"] = opsdevmodel.EventStatusProcessing data["opsUserId"] = s.GetCxtUserId() data["opsUserName"] = s.GetCxtUserName() if v, ok := data["feedbackDate"]; ok && v == "" { data["feedbackDate"] = gtime.Now() } if v, ok := data["assignTime"]; ok && v == "" { data["assignTime"] = gtime.Now() } delete(data, "completeTime") result, err := s.Dao.Data(data).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("创建运维事件失败") } id, err := result.LastInsertId() if err != nil { g.Log().Error(err) return nil } recordData := g.Map{ s.RecordDao.Columns.EventId: id, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: "创建运维事件", s.RecordDao.Columns.HandleResult: opsdevmodel.HandleResultUnresolved, s.RecordDao.Columns.HandleDate: gtime.Now(), s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeProcess, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.RecordDao.Data(recordData).Insert() if err != nil { g.Log().Error(err) } return nil } // UpdateById 更新运维事件 func (s *OperationService) UpdateById(req *opsdevmodel.UpdateOpsOperationEventReq) (err error) { if err = gvalid.CheckStruct(s.Ctx, req, nil); err != nil { return myerrors.ValidError(err.Error()) } event := new(opsdevmodel.OpsOperationEvent) err = s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).WherePri(s.Dao.Columns.Id, req.Id).Scan(event) if err != nil { g.Log().Error(err) return myerrors.DbError("查询运维事件失败") } if event.Id <= 0 { return myerrors.TipsError("运维事件不存在") } if err = s.checkNotClosed(event); err != nil { return err } data := gconv.Map(req.OpsOperationEventReq) if v, ok := data["feedbackDate"]; ok && v == "" { delete(data, "feedbackDate") } delete(data, "assignTime") delete(data, "completeTime") service.SetUpdatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.Dao.FieldsEx(service.UpdateFieldEx...).WherePri(s.Dao.Columns.Id, req.Id).Data(data).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("更新运维事件失败") } return nil } // DeleteByIds 批量删除运维事件 func (s *OperationService) DeleteByIds(req *comm_def.IdsReq) (err error) { if len(req.Ids) == 0 { return myerrors.ValidError("参数有误!") } _, err = s.Dao.WherePri(req.Ids).Data(g.Map{ s.Dao.Columns.DeletedTime: gtime.Now(), s.Dao.Columns.UpdatedBy: s.GetCxtUserId(), s.Dao.Columns.UpdatedName: s.GetCxtUserName(), }).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("删除运维事件失败") } return nil } // checkNotClosed 校验事件未关闭,已关闭的事件不允许操作 func (s *OperationService) checkNotClosed(event *opsdevmodel.OpsOperationEvent) error { if event.EventStatus == opsdevmodel.EventStatusClosed { return myerrors.TipsError("该事件已关闭,无法进行操作") } return nil } // Process 处理运维事件 func (s *OperationService) Process(ctx context.Context, req *opsdevmodel.OpsOperationEventProcessReq) error { if req.Id <= 0 { return myerrors.TipsError("任务ID不能为空") } event := new(opsdevmodel.OpsOperationEvent) err := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).WherePri(s.Dao.Columns.Id, req.Id).Scan(event) if err != nil { g.Log().Error(err) return myerrors.DbError("查询运维事件失败") } if event.Id <= 0 { return myerrors.TipsError("运维事件不存在") } if err := s.checkNotClosed(event); err != nil { return err } switch req.OperateType { case opsdevmodel.OperateTypeProcess: return s.processStart(ctx, event, req) case opsdevmodel.OperateTypeResume: return s.processResume(ctx, event, req) case opsdevmodel.OperateTypeTransfer: return s.processTransfer(ctx, event, req) case opsdevmodel.OperateTypeSuspend: return s.processSuspend(ctx, event, req) case opsdevmodel.OperateTypeClose: return s.processClose(ctx, event, req) default: return myerrors.TipsError("未知的操作类型") } } func (s *OperationService) processStart(ctx context.Context, event *opsdevmodel.OpsOperationEvent, req *opsdevmodel.OpsOperationEventProcessReq) error { if event.EventStatus != opsdevmodel.EventStatusPending { return myerrors.TipsError("当前事件状态不能进行此操作") } return s.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err := s.Dao.TX(tx).FieldsEx(service.UpdateFieldEx...).WherePri(s.Dao.Columns.Id, event.Id).Data(g.Map{ s.Dao.Columns.EventStatus: opsdevmodel.EventStatusProcessing, s.Dao.Columns.OpsUserId: s.GetCxtUserId(), s.Dao.Columns.OpsUserName: s.GetCxtUserName(), s.Dao.Columns.AssignTime: gtime.Now(), s.Dao.Columns.UpdatedBy: s.GetCxtUserId(), s.Dao.Columns.UpdatedName: s.GetCxtUserName(), s.Dao.Columns.UpdatedTime: gtime.Now(), }).Update() if err != nil { return err } recordData := g.Map{ s.RecordDao.Columns.EventId: event.Id, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: opsdevmodel.HandleResultUnresolved, s.RecordDao.Columns.HandleDate: gtime.Now(), s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeProcess, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { return err } return nil }) } func (s *OperationService) processClose(ctx context.Context, event *opsdevmodel.OpsOperationEvent, req *opsdevmodel.OpsOperationEventProcessReq) error { if event.EventStatus == opsdevmodel.EventStatusPending { return myerrors.TipsError("待处理状态不能直接关闭,请先接收") } if event.EventStatus == opsdevmodel.EventStatusSuspended { return myerrors.TipsError("挂起状态不允许关闭事件,请先转处理") } return s.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err := s.Dao.TX(tx).FieldsEx(service.UpdateFieldEx...).WherePri(s.Dao.Columns.Id, event.Id).Data(g.Map{ s.Dao.Columns.EventStatus: opsdevmodel.EventStatusClosed, s.Dao.Columns.CompleteTime: gtime.Now(), s.Dao.Columns.CompleteDesc: req.HandleContent, s.Dao.Columns.UpdatedBy: s.GetCxtUserId(), s.Dao.Columns.UpdatedName: s.GetCxtUserName(), s.Dao.Columns.UpdatedTime: gtime.Now(), }).Update() if err != nil { return err } recordData := g.Map{ s.RecordDao.Columns.EventId: event.Id, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: req.HandleResult, s.RecordDao.Columns.HandleDate: gtime.Now(), s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeClose, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { return err } return nil }) } func (s *OperationService) processTransfer(ctx context.Context, event *opsdevmodel.OpsOperationEvent, req *opsdevmodel.OpsOperationEventProcessReq) error { if event.EventStatus != opsdevmodel.EventStatusProcessing && event.EventStatus != opsdevmodel.EventStatusProcessingNormal { return myerrors.TipsError("当前事件状态不能转研发") } return s.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err := s.Dao.TX(tx).FieldsEx(service.UpdateFieldEx...).WherePri(s.Dao.Columns.Id, event.Id).Data(g.Map{ s.Dao.Columns.EventStatus: opsdevmodel.EventStatusTransfer, s.Dao.Columns.UpdatedBy: s.GetCxtUserId(), s.Dao.Columns.UpdatedName: s.GetCxtUserName(), s.Dao.Columns.UpdatedTime: gtime.Now(), }).Update() if err != nil { return err } recordData := g.Map{ s.RecordDao.Columns.EventId: event.Id, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: opsdevmodel.HandleResultUnresolved, s.RecordDao.Columns.HandleDate: gtime.Now(), s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeTransfer, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { return err } return nil }) } func (s *OperationService) processSuspend(ctx context.Context, event *opsdevmodel.OpsOperationEvent, req *opsdevmodel.OpsOperationEventProcessReq) error { if event.EventStatus != opsdevmodel.EventStatusProcessing && event.EventStatus != opsdevmodel.EventStatusProcessingNormal && event.EventStatus != opsdevmodel.EventStatusTransfer { return myerrors.TipsError("当前事件状态不能挂起") } return s.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err := s.Dao.TX(tx).FieldsEx(service.UpdateFieldEx...).WherePri(s.Dao.Columns.Id, event.Id).Data(g.Map{ s.Dao.Columns.EventStatus: opsdevmodel.EventStatusSuspended, s.Dao.Columns.UpdatedBy: s.GetCxtUserId(), s.Dao.Columns.UpdatedName: s.GetCxtUserName(), s.Dao.Columns.UpdatedTime: gtime.Now(), }).Update() if err != nil { return err } recordData := g.Map{ s.RecordDao.Columns.EventId: event.Id, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: opsdevmodel.HandleResultUnresolved, s.RecordDao.Columns.HandleDate: gtime.Now(), s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeSuspend, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { return err } return nil }) } func (s *OperationService) processResume(ctx context.Context, event *opsdevmodel.OpsOperationEvent, req *opsdevmodel.OpsOperationEventProcessReq) error { if event.EventStatus != opsdevmodel.EventStatusSuspended { return myerrors.TipsError("当前事件状态不能转处理") } return s.Dao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { _, err := s.Dao.TX(tx).FieldsEx(service.UpdateFieldEx...).WherePri(s.Dao.Columns.Id, event.Id).Data(g.Map{ s.Dao.Columns.EventStatus: opsdevmodel.EventStatusProcessing, s.Dao.Columns.UpdatedBy: s.GetCxtUserId(), s.Dao.Columns.UpdatedName: s.GetCxtUserName(), s.Dao.Columns.UpdatedTime: gtime.Now(), }).Update() if err != nil { return err } recordData := g.Map{ s.RecordDao.Columns.EventId: event.Id, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: opsdevmodel.HandleResultUnresolved, s.RecordDao.Columns.HandleDate: gtime.Now(), s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeResume, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { return err } return nil }) } // GetRecords 获取运维事件处理记录 func (s *OperationService) GetRecords(req *opsdevmodel.OpsOperationEventRecordSearchReq) (total int, list []*opsdevmodel.OpsOperationEventRecord, err error) { if req.EventId <= 0 { return 0, nil, myerrors.ValidError("事件ID不能为空") } db := s.RecordDao.FieldsEx(s.RecordDao.Columns.DeletedTime).Where(s.RecordDao.Columns.EventId, req.EventId) total, err = db.Count() if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询处理记录数量失败") } pageNum, pageSize := req.GetPage() err = db.Page(pageNum, pageSize).Order(s.RecordDao.Columns.CreatedTime + " desc").Scan(&list) if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询处理记录列表失败") } return total, list, nil } // UploadAttachment 上传附件 func (s *OperationService) UploadAttachment(req *opsdevmodel.OpsOperationEventAttachmentReq) (attachment *opsdevmodel.OpsOperationEventAttachment, err error) { if req.EventId <= 0 { return nil, myerrors.ValidError("事件ID不能为空") } if req.FileName == "" { return nil, myerrors.ValidError("文件名不能为空") } if req.FileUrl == "" { return nil, myerrors.ValidError("文件地址不能为空") } event := new(opsdevmodel.OpsOperationEvent) err = s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).WherePri(s.Dao.Columns.Id, req.EventId).Scan(event) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询运维事件失败") } if err := s.checkNotClosed(event); err != nil { return nil, err } data := g.Map{ s.AttachmentDao.Columns.EventId: req.EventId, s.AttachmentDao.Columns.EventRecordId: req.EventRecordId, s.AttachmentDao.Columns.FileName: req.FileName, s.AttachmentDao.Columns.FileUrl: req.FileUrl, s.AttachmentDao.Columns.FileType: req.FileType, s.AttachmentDao.Columns.Remark: req.Remark, } service.SetCreatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.AttachmentDao.Data(data).Insert() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("上传附件失败") } // 查询刚插入的记录 attachment = new(opsdevmodel.OpsOperationEventAttachment) err = s.AttachmentDao.Where(s.AttachmentDao.Columns.EventId, req.EventId). Order(s.AttachmentDao.Columns.Id + " desc").Scan(attachment) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询附件失败") } return attachment, nil } // GetAttachments 获取事件附件列表 func (s *OperationService) GetAttachments(eventId int) (list []*opsdevmodel.OpsOperationEventAttachment, err error) { if eventId <= 0 { return nil, myerrors.ValidError("事件ID不能为空") } err = s.AttachmentDao.FieldsEx(s.AttachmentDao.Columns.DeletedTime). Where(s.AttachmentDao.Columns.EventId, eventId). Order(s.AttachmentDao.Columns.CreatedTime + " desc").Scan(&list) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询附件列表失败") } return list, nil } // GetStats 运维事件统计 func (s *OperationService) GetStats() (result g.Map, err error) { result = g.Map{} statusCounts := []struct { key string status string }{ {"pending", opsdevmodel.EventStatusPending}, {"processingKey", opsdevmodel.EventStatusProcessing}, {"processingNormal", opsdevmodel.EventStatusProcessingNormal}, {"transfer", opsdevmodel.EventStatusTransfer}, {"suspended", opsdevmodel.EventStatusSuspended}, {"closed", opsdevmodel.EventStatusClosed}, } for _, sc := range statusCounts { count, err := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).Where(s.Dao.Columns.EventStatus, sc.status).Count() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询运维事件统计失败") } result[sc.key] = count } today := gtime.Now().Format("Y-m-d") todayNewCount, err := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).Where(s.Dao.Columns.CreatedTime+" >= ?", today+" 00:00:00").Count() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询今日新增数量失败") } result["todayNew"] = todayNewCount return result, nil } // generateEventNo 生成事件编号 func generateEventNo() string { return fmt.Sprintf("OPS%s", gtime.Now().Format("YmdHis")) } // GetKanbanData 看板数据 func (s *OperationService) GetKanbanData(req *opsdevmodel.OpsOperationEventKanbanSearchReq) (result g.Map, err error) { result = g.Map{} columns := []struct { Status string Name string Key string }{ {opsdevmodel.EventStatusPending, "待处理", "10"}, {opsdevmodel.EventStatusProcessing, "处理中(重点)", "20"}, {opsdevmodel.EventStatusProcessingNormal, "处理中(普通)", "30"}, {opsdevmodel.EventStatusTransfer, "转研发", "40"}, {opsdevmodel.EventStatusSuspended, "挂起", "70"}, } for _, col := range columns { db := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).Where(s.Dao.Columns.EventStatus, col.Status) if req.KeyWords != "" { switch req.SearchType { case "custName": db = db.Where(s.Dao.Columns.CustName+" like ?", "%"+req.KeyWords+"%") case "feedbackReporter": db = db.Where(s.Dao.Columns.FeedbackReporter+" like ?", "%"+req.KeyWords+"%") case "eventNo": db = db.Where(s.Dao.Columns.EventNo+" like ?", "%"+req.KeyWords+"%") default: db = db.Where(s.Dao.Columns.EventTitle+" like ?", "%"+req.KeyWords+"%") } } if req.EventType != "" { db = db.Where(s.Dao.Columns.EventType, req.EventType) } if req.PriorityLevel != "" { db = db.Where(s.Dao.Columns.PriorityLevel, req.PriorityLevel) } count, err := db.Count() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询看板数据失败") } var list []*opsdevmodel.OpsOperationEvent err = db.Scan(&list) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询看板数据失败") } result[col.Key] = g.Map{ "status": col.Key, "name": col.Name, "count": count, "list": list, } } return result, nil } // AssignOpsUser 接收/分配运维人员 func (s *OperationService) AssignOpsUser(req *opsdevmodel.AssignOpsUserReq) error { event := new(opsdevmodel.OpsOperationEvent) err := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).WherePri(s.Dao.Columns.Id, req.Id).Scan(event) if err != nil { g.Log().Error(err) return myerrors.DbError("查询运维事件失败") } if event.Id <= 0 { return myerrors.TipsError("运维事件不存在") } if err := s.checkNotClosed(event); err != nil { return err } if event.EventStatus != opsdevmodel.EventStatusPending { return myerrors.TipsError("只有待处理状态的事件才能分配运维人员") } opsUserId := req.OpsUserId opsUserName := req.OpsUserName if opsUserId <= 0 { opsUserId = s.GetCxtUserId() } if opsUserName == "" { opsUserName = s.GetCxtUserName() } _, err = s.Dao.FieldsEx(service.UpdateFieldEx...).WherePri(s.Dao.Columns.Id, req.Id).Data(g.Map{ s.Dao.Columns.EventStatus: opsdevmodel.EventStatusProcessing, s.Dao.Columns.OpsUserId: opsUserId, s.Dao.Columns.OpsUserName: opsUserName, s.Dao.Columns.AssignTime: gtime.Now(), s.Dao.Columns.UpdatedBy: s.GetCxtUserId(), s.Dao.Columns.UpdatedName: s.GetCxtUserName(), s.Dao.Columns.UpdatedTime: gtime.Now(), }).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("分配运维人员失败") } return nil } // AddRecord 添加处理记录 func (s *OperationService) AddRecord(req *opsdevmodel.AddRecordReq) error { if req.EventId <= 0 { return myerrors.ValidError("事件ID不能为空") } event := new(opsdevmodel.OpsOperationEvent) err := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).WherePri(s.Dao.Columns.Id, req.EventId).Scan(event) if err != nil { g.Log().Error(err) return myerrors.DbError("查询运维事件失败") } if event.Id <= 0 { return myerrors.TipsError("运维事件不存在") } if err := s.checkNotClosed(event); err != nil { return err } data := g.Map{ s.RecordDao.Columns.EventId: req.EventId, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: req.HandleResult, s.RecordDao.Columns.HandleDate: gtime.Now(), s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeProcess, } service.SetCreatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.RecordDao.Data(data).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("添加处理记录失败") } return nil } // DeleteAttachment 删除附件 func (s *OperationService) DeleteAttachment(req *comm_def.IdReq) error { if req.Id <= 0 { return myerrors.ValidError("参数有误!") } attachment := new(opsdevmodel.OpsOperationEventAttachment) err := s.AttachmentDao.WherePri(s.AttachmentDao.Columns.Id, req.Id).Scan(attachment) if err != nil { g.Log().Error(err) return myerrors.DbError("查询附件失败") } if attachment.Id <= 0 { return myerrors.TipsError("附件不存在") } _, err = s.AttachmentDao.WherePri(s.AttachmentDao.Columns.Id, req.Id).Data(g.Map{ s.AttachmentDao.Columns.DeletedTime: gtime.Now(), s.AttachmentDao.Columns.UpdatedBy: s.GetCxtUserId(), s.AttachmentDao.Columns.UpdatedName: s.GetCxtUserName(), }).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("删除附件失败") } return nil } // GetHistoryList 运维历史列表 func (s *OperationService) GetHistoryList(req *opsdevmodel.OpsOperationEventHistorySearchReq) (total int, list []*opsdevmodel.OpsOperationEvent, err error) { db := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime) if !req.IncludeClosed { db = db.Where(s.Dao.Columns.EventStatus, opsdevmodel.EventStatusClosed) } if req.ScopeType == "my" { db = db.Where(s.Dao.Columns.OpsUserId, s.GetCxtUserId()) } if req.EventTitle != "" { db = db.Where(s.Dao.Columns.EventTitle+" like ?", "%"+req.EventTitle+"%") } if req.CustName != "" { db = db.Where(s.Dao.Columns.CustName+" like ?", "%"+req.CustName+"%") } if req.FeedbackReporter != "" { db = db.Where(s.Dao.Columns.FeedbackReporter+" like ?", "%"+req.FeedbackReporter+"%") } if req.OpsUserName != "" { db = db.Where(s.Dao.Columns.OpsUserName+" like ?", "%"+req.OpsUserName+"%") } if req.BeginTime != "" { db = db.Where(s.Dao.Columns.FeedbackDate+" >= ?", req.BeginTime) } if req.EndTime != "" { db = db.Where(s.Dao.Columns.FeedbackDate+" <= ?", req.EndTime) } total, err = db.Count() if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询运维历史数量失败") } pageNum, pageSize := req.GetPage() err = db.Page(pageNum, pageSize).Order(s.Dao.Columns.CompleteTime + " desc").Scan(&list) if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询运维历史列表失败") } return total, list, nil } // Export 导出运维历史 func (s *OperationService) Export(ctx context.Context, req *opsdevmodel.OpsOperationEventHistoryExport) (content *opsdevmodel.OpsOperationEventHistoryExportContent, err error) { db := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime) if !req.IncludeClosed { db = db.Where(s.Dao.Columns.EventStatus, opsdevmodel.EventStatusClosed) } if req.ScopeType == "my" { db = db.Where(s.Dao.Columns.OpsUserId, s.GetCxtUserId()) } if req.EventTitle != "" { db = db.Where(s.Dao.Columns.EventTitle+" like ?", "%"+req.EventTitle+"%") } if req.CustName != "" { db = db.Where(s.Dao.Columns.CustName+" like ?", "%"+req.CustName+"%") } if req.FeedbackReporter != "" { db = db.Where(s.Dao.Columns.FeedbackReporter+" like ?", "%"+req.FeedbackReporter+"%") } if req.OpsUserName != "" { db = db.Where(s.Dao.Columns.OpsUserName+" like ?", "%"+req.OpsUserName+"%") } if req.BeginTime != "" { db = db.Where(s.Dao.Columns.FeedbackDate+" >= ?", req.BeginTime) } if req.EndTime != "" { db = db.Where(s.Dao.Columns.FeedbackDate+" <= ?", req.EndTime) } var list []*opsdevmodel.OpsOperationEvent err = db.Order(s.Dao.Columns.CompleteTime + " desc").Scan(&list) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询运维历史失败") } // 获取所有事件ID var eventIds []int for _, item := range list { eventIds = append(eventIds, item.Id) } // 获取所有事件的处理记录 var records []*opsdevmodel.OpsOperationEventRecord if len(eventIds) > 0 { err = s.RecordDao.WhereIn(s.RecordDao.Columns.EventId, eventIds).Order(s.RecordDao.Columns.HandleDate + " desc").Scan(&records) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询处理记录失败") } } // 构建记录Map recordMap := make(map[int][]*opsdevmodel.OpsOperationEventRecord) for _, record := range records { recordMap[record.EventId] = append(recordMap[record.EventId], record) } // 构建状态Map statusMap := map[string]string{ opsdevmodel.EventStatusPending: "待处理", opsdevmodel.EventStatusProcessing: "处理中(重点)", opsdevmodel.EventStatusProcessingNormal: "处理中(普通)", opsdevmodel.EventStatusTransfer: "转研发", opsdevmodel.EventStatusSuspended: "挂起", opsdevmodel.EventStatusClosed: "已关闭", } // 构建操作类型Map operateTypeMap := map[string]string{ opsdevmodel.OperateTypeProcess: "处理", opsdevmodel.OperateTypeResume: "转处理", opsdevmodel.OperateTypeTransfer: "转研发", opsdevmodel.OperateTypeSuspend: "挂起", opsdevmodel.OperateTypeClose: "关闭", } // 构建处理结果Map handleResultMap := map[string]string{ opsdevmodel.HandleResultResolved: "已解决", opsdevmodel.HandleResultPartially: "部分解决", opsdevmodel.HandleResultUnresolved: "未解决", } // 构建导出数据 exportDataList := make([]map[string]interface{}, 0) for _, item := range list { // 构建处理过程 processBuilder := "" if itemRecords, ok := recordMap[item.Id]; ok && len(itemRecords) > 0 { for i, record := range itemRecords { // 处理时间(仅年月) handleDate := "" if record.HandleDate != nil { handleDate = record.HandleDate.Format("Y-m-d H:i:s") } // 操作类型描述 operateTypeStr := operateTypeMap[record.OperateType] if operateTypeStr == "" { operateTypeStr = record.OperateType } // 处理结果描述 handleResultStr := handleResultMap[record.HandleResult] if handleResultStr == "" { handleResultStr = record.HandleResult } // 清理处理内容中的HTML标签 cleanContent := cleanHtmlTags(record.HandleContent) recordStr := fmt.Sprintf("%s-%s-%s-%s-%s", handleDate, record.HandleUserName, operateTypeStr, handleResultStr, cleanContent) if i > 0 { processBuilder += "\n" + recordStr } else { processBuilder = recordStr } } } closedTime := "" if item.CompleteTime != nil { closedTime = item.CompleteTime.Format("Y-m-d") } feedbackDate := "" if item.FeedbackDate != nil { feedbackDate = item.FeedbackDate.Format("Y-m-d") } exportData := map[string]interface{}{ "eventNo": item.EventNo, "eventTitle": item.EventTitle, "eventStatus": statusMap[item.EventStatus], "eventType": item.EventType, "custName": item.CustName, "opsUserName": item.OpsUserName, "feedbackDate": feedbackDate, "priorityLevel": item.PriorityLevel, "handleProcess": processBuilder, "closedTime": closedTime, } exportDataList = append(exportDataList, exportData) } // 调用公共导出方法 exportContent := new(opsdevmodel.OpsOperationEventHistoryExportContent) contentBase64, err := service.CommonExportExcel(ctx, "运维历史", opsdevmodel.OpsOperationEventHistoryExportData{}, exportDataList) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("导出运维历史失败") } exportContent.Content = contentBase64 return exportContent, nil } func (s *OperationService) ExportNonClosed(ctx context.Context, req *opsdevmodel.OpsOperationEventExport) (content *opsdevmodel.OpsOperationEventHistoryExportContent, err error) { db := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).Where(s.Dao.Columns.EventStatus+" != ?", opsdevmodel.EventStatusClosed) var list []*opsdevmodel.OpsOperationEvent err = db.Order(s.Dao.Columns.FeedbackDate + " desc").Scan(&list) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询运维事件失败") } var eventIds []int for _, item := range list { eventIds = append(eventIds, item.Id) } var records []*opsdevmodel.OpsOperationEventRecord if len(eventIds) > 0 { err = s.RecordDao.WhereIn(s.RecordDao.Columns.EventId, eventIds).Order(s.RecordDao.Columns.HandleDate + " desc").Scan(&records) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询处理记录失败") } } recordMap := make(map[int][]*opsdevmodel.OpsOperationEventRecord) for _, record := range records { recordMap[record.EventId] = append(recordMap[record.EventId], record) } statusMap := map[string]string{ opsdevmodel.EventStatusPending: "待处理", opsdevmodel.EventStatusProcessing: "处理中(重点)", opsdevmodel.EventStatusProcessingNormal: "处理中(普通)", opsdevmodel.EventStatusTransfer: "转研发", opsdevmodel.EventStatusSuspended: "挂起", opsdevmodel.EventStatusClosed: "已关闭", } operateTypeMap := map[string]string{ opsdevmodel.OperateTypeProcess: "处理", opsdevmodel.OperateTypeResume: "转处理", opsdevmodel.OperateTypeTransfer: "转研发", opsdevmodel.OperateTypeSuspend: "挂起", opsdevmodel.OperateTypeClose: "关闭", } handleResultMap := map[string]string{ opsdevmodel.HandleResultResolved: "已解决", opsdevmodel.HandleResultPartially: "部分解决", opsdevmodel.HandleResultUnresolved: "未解决", } exportDataList := make([]map[string]interface{}, 0) for _, item := range list { processBuilder := "" if itemRecords, ok := recordMap[item.Id]; ok && len(itemRecords) > 0 { for i, record := range itemRecords { handleDate := "" if record.HandleDate != nil { handleDate = record.HandleDate.Format("Y-m-d H:i:s") } operateTypeStr := operateTypeMap[record.OperateType] if operateTypeStr == "" { operateTypeStr = record.OperateType } handleResultStr := handleResultMap[record.HandleResult] if handleResultStr == "" { handleResultStr = record.HandleResult } cleanContent := cleanHtmlTags(record.HandleContent) recordStr := fmt.Sprintf("%s-%s-%s-%s-%s", handleDate, record.HandleUserName, operateTypeStr, handleResultStr, cleanContent) if i > 0 { processBuilder += "\n" + recordStr } else { processBuilder = recordStr } } } feedbackDate := "" if item.FeedbackDate != nil { feedbackDate = item.FeedbackDate.Format("Y-m-d") } exportData := map[string]interface{}{ "eventNo": item.EventNo, "eventTitle": item.EventTitle, "eventStatus": statusMap[item.EventStatus], "eventType": item.EventType, "custName": item.CustName, "opsUserName": item.OpsUserName, "feedbackDate": feedbackDate, "priorityLevel": item.PriorityLevel, "handleProcess": processBuilder, } exportDataList = append(exportDataList, exportData) } exportContent := new(opsdevmodel.OpsOperationEventHistoryExportContent) contentBase64, err := service.CommonExportExcel(ctx, "运维事件", opsdevmodel.OpsOperationEventExportData{}, exportDataList) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("导出运维事件失败") } exportContent.Content = contentBase64 return exportContent, nil } func cleanHtmlTags(content string) string { if content == "" { return "" } imgPattern := regexp.MustCompile(`src=["']([^"']+)["']`) imgMatches := imgPattern.FindAllStringSubmatch(content, -1) seen := make(map[string]bool) var imgUrls []string for _, match := range imgMatches { if len(match) > 1 && !seen[match[1]] { seen[match[1]] = true imgUrls = append(imgUrls, match[1]) } } htmlTagPattern := regexp.MustCompile(`<[^>]*>`) result := htmlTagPattern.ReplaceAllString(content, "") result = strings.ReplaceAll(result, " ", " ") result = strings.ReplaceAll(result, "&", "&") result = strings.ReplaceAll(result, "<", "<") result = strings.ReplaceAll(result, ">", ">") result = strings.ReplaceAll(result, """, "\"") result = strings.ReplaceAll(result, "'", "'") result = strings.TrimSpace(result) if len(imgUrls) > 0 { result += "\n图片: " for i, url := range imgUrls { if i > 0 { result += ", " } result += url } } return result }