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" ) // eventTypeToDevTaskType 运维事件类型 → 研发任务类型映射 var eventTypeToDevTaskType = map[string]string{ "10": "20", // 操作咨询 → 功能开发 "20": "21", // 数据处理 → 数据处理 "30": "35", // 系统BUG → BUG "40": "20", // 功能调整 → 功能开发 "50": "20", // 二开需求 → 功能开发 "90": "20", // 其他问题 → 功能开发 } type OperationService struct { *service.ContextService Dao *opsdevdao.OpsOperationEventDao RecordDao *opsdevdao.OpsOperationEventRecordDao AttachmentDao *opsdevdao.OpsOperationEventAttachmentDao DeliveryProjectAttachmentDao *opsdevdao.OpsDeliveryProjectEventAttachmentDao WorkHourDao *opsdevdao.OpsOperationWorkHourDao DeliveryProjectDao *opsdevdao.OpsDeliveryProjectDao } 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) svc.DeliveryProjectAttachmentDao = opsdevdao.NewOpsDeliveryProjectEventAttachmentDao(svc.Tenant) svc.WorkHourDao = opsdevdao.NewOpsOperationWorkHourDao(svc.Tenant) svc.DeliveryProjectDao = opsdevdao.NewOpsDeliveryProjectDao(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("运维事件不存在") } // 查询事件级附件(eventRecordId = 0 或 null) var attachments []*opsdevmodel.OpsOperationEventAttachment err = s.AttachmentDao.FieldsEx(s.AttachmentDao.Columns.DeletedTime). Where(s.AttachmentDao.Columns.EventId, req.Id). Where("(event_record_id = 0 OR event_record_id IS NULL)"). Scan(&attachments) if err != nil { g.Log().Error(err) } detail.Attachments = attachments 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"] = s.generateEventNo() data["eventStatus"] = opsdevmodel.EventStatusProcessing if _, ok := data["opsUserId"]; !ok || data["opsUserId"] == 0 { data["opsUserId"] = s.GetCxtUserId() } if _, ok := data["opsUserName"]; !ok || data["opsUserName"] == "" { 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") delete(data, "attachments") result, err := s.Dao.Data(data).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("创建运维事件失败") } eventId, err := result.LastInsertId() if err != nil { g.Log().Error(err) return myerrors.DbError("获取运维事件ID失败") } // 保存事件级附件 for _, att := range req.Attachments { attData := g.Map{ s.AttachmentDao.Columns.EventId: eventId, s.AttachmentDao.Columns.FileName: att.FileName, s.AttachmentDao.Columns.FileUrl: att.FileUrl, s.AttachmentDao.Columns.FileType: att.FileType, } service.SetCreatedInfo(attData, s.GetCxtUserId(), s.GetCxtUserName()) _, err := s.AttachmentDao.Data(attData).Insert() if err != nil { g.Log().Error(err) } } return nil } // AddWorkHour 添加工时记录 func (s *OperationService) AddWorkHour(req *opsdevmodel.OpsOperationWorkHourAddReq) 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 event.EventStatus != opsdevmodel.EventStatusProcessing && event.EventStatus != opsdevmodel.EventStatusProcessingNormal { return myerrors.TipsError("只有处理中的事件才能添加工作时长") } workDate, err := gtime.StrToTime(req.WorkDate) if err != nil { return myerrors.ValidError("工作日期格式错误") } today := gtime.Now().Format("Y-m-d") if workDate.Format("Y-m-d") > today { return myerrors.ValidError("工作日期不能晚于今天") } if req.WorkHour < 0.5 { return myerrors.ValidError("工作时长不能小于0.5小时") } opsUserId := s.GetCxtUserId() opsUserName := s.GetCxtUserName() return s.Dao.Transaction(s.Ctx, func(ctx context.Context, tx *gdb.TX) error { workHourData := g.Map{ s.WorkHourDao.Columns.EventId: req.EventId, s.WorkHourDao.Columns.OpsUserId: opsUserId, s.WorkHourDao.Columns.OpsUserName: opsUserName, s.WorkHourDao.Columns.WorkDate: req.WorkDate, s.WorkHourDao.Columns.WorkHour: req.WorkHour, s.WorkHourDao.Columns.Remark: req.Remark, } service.SetCreatedInfo(workHourData, opsUserId, opsUserName) _, err := tx.Model(s.WorkHourDao.Table).Data(workHourData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("添加工作时长失败") } _, err = tx.Exec("UPDATE ops_operation_event SET total_work_hour = total_work_hour + ? WHERE id = ?", req.WorkHour, req.EventId) 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) } if req.ContractId != "" { db = db.Where(s.Dao.Columns.ContractId, req.ContractId) } 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) } if req.ContractId != "" { db = db.Where(s.Dao.Columns.ContractId, req.ContractId) } 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 } // GetWorkHourList 获取工时登记列表 func (s *OperationService) GetWorkHourList(req *opsdevmodel.OpsOperationWorkHourListReq) ([]*opsdevmodel.OpsOperationWorkHourListRsp, error) { var entities []*opsdevmodel.OpsOperationWorkHour err := s.WorkHourDao.FieldsEx(s.WorkHourDao.Columns.DeletedTime). Where(s.WorkHourDao.Columns.EventId, req.EventId). Order(s.WorkHourDao.Columns.CreatedTime + " desc"). Scan(&entities) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询工时登记列表失败") } list := make([]*opsdevmodel.OpsOperationWorkHourListRsp, 0, len(entities)) for _, entity := range entities { workDate := "" if entity.WorkDate != nil { workDate = entity.WorkDate.Format("Y-m-d") } createdTime := "" if entity.CreatedTime != nil { createdTime = entity.CreatedTime.Format("Y-m-d H:i:s") } list = append(list, &opsdevmodel.OpsOperationWorkHourListRsp{ Id: entity.Id, WorkDate: workDate, WorkHour: entity.WorkHour, Remark: entity.Remark, CreatedName: entity.CreatedName, CreatedTime: createdTime, }) } return list, nil } // generateEventNo 生成运维事件编号 func (s *OperationService) generateEventNo() string { now := gtime.Now() prefix := "OPS" + now.Format("Ymd") seqVal, err := s.Dao.DB.GetValue("SELECT next_day_reset_val('event_no_seq')") if err == nil { return prefix + fmt.Sprintf("%04d", seqVal.Int()) } var maxNoResult struct { EventNo string } err = s.Dao.Where("event_no like ?", prefix+"%"). Order("event_no desc"). Fields("event_no"). Scan(&maxNoResult) if err != nil || maxNoResult.EventNo == "" { return prefix + "0001" } maxNoStr := maxNoResult.EventNo if len(maxNoStr) >= len(prefix)+4 { seq := maxNoStr[len(prefix):] seqNum := gconv.Int(seq) seqNum++ return prefix + fmt.Sprintf("%04d", seqNum) } return prefix + "0001" } // Process 处理运维事件(开始/转处理/转研发/挂起/关闭) func (s *OperationService) Process(ctx context.Context, req *opsdevmodel.OpsOperationEventProcessReq) error { event := new(opsdevmodel.OpsOperationEvent) err := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).WherePri(s.Dao.Columns.Id, int(req.Id)).Scan(event) if err != nil { g.Log().Error(err) return myerrors.DbError("查询运维事件失败") } if event.Id <= 0 { return myerrors.TipsError("运维事件不存在") } opsUserId := s.GetCxtUserId() opsUserName := s.GetCxtUserName() switch req.OperateType { case opsdevmodel.OperateTypeClose: return s.processClose(req, event, opsUserId, opsUserName) default: return s.processNormal(req, event, opsUserId, opsUserName) } } // processClose 关单处理(含工时调整) func (s *OperationService) processClose(req *opsdevmodel.OpsOperationEventProcessReq, event *opsdevmodel.OpsOperationEvent, opsUserId int, opsUserName string) error { return s.Dao.Transaction(s.Ctx, func(ctx context.Context, tx *gdb.TX) error { handleDate := gtime.Now() recordData := g.Map{ s.RecordDao.Columns.EventId: req.Id, s.RecordDao.Columns.HandleUserId: opsUserId, s.RecordDao.Columns.HandleUserName: opsUserName, s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: req.HandleResult, s.RecordDao.Columns.HandleDate: handleDate, s.RecordDao.Columns.OperateType: req.OperateType, } service.SetCreatedInfo(recordData, opsUserId, opsUserName) _, err := s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("创建处理记录失败") } eventUpdateData := g.Map{ s.Dao.Columns.EventStatus: opsdevmodel.EventStatusClosed, s.Dao.Columns.CompleteTime: gtime.Now(), s.Dao.Columns.CompleteDesc: req.HandleContent, s.Dao.Columns.EventResult: req.HandleResult, } service.SetUpdatedInfo(eventUpdateData, opsUserId, opsUserName) if req.AdjustWorkHour > 0 { currentTotal := event.TotalWorkHour if req.AdjustWorkHour < currentTotal { return myerrors.ValidError("工时只能增加不能减少") } if req.AdjustWorkHour > currentTotal { delta := req.AdjustWorkHour - currentTotal workHourData := g.Map{ s.WorkHourDao.Columns.EventId: int(req.Id), s.WorkHourDao.Columns.OpsUserId: opsUserId, s.WorkHourDao.Columns.OpsUserName: opsUserName, s.WorkHourDao.Columns.WorkDate: gtime.Now(), s.WorkHourDao.Columns.WorkHour: delta, s.WorkHourDao.Columns.Remark: "关单调整", } service.SetCreatedInfo(workHourData, opsUserId, opsUserName) _, err := s.WorkHourDao.TX(tx).Data(workHourData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("创建工时调整记录失败") } eventUpdateData[s.Dao.Columns.TotalWorkHour] = req.AdjustWorkHour } } _, err = s.Dao.TX(tx).FieldsEx(service.UpdateFieldEx...).Data(eventUpdateData).WherePri(s.Dao.Columns.Id, req.Id).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("关闭事件失败") } return nil }) } // getDevTaskType 根据运维事件类型获取对应的研发任务类型,未匹配时兜底返回功能开发(20) func (s *OperationService) getDevTaskType(eventType string) string { if taskType, ok := eventTypeToDevTaskType[eventType]; ok { return taskType } return opsdevmodel.TaskTypeFeatureDev } // createDevTaskFromEvent 根据运维事件自动创建研发任务(在processNormal事务完成后调用) func (s *OperationService) createDevTaskFromEvent(event *opsdevmodel.OpsOperationEvent) { var attachments []*opsdevmodel.OpsOperationEventAttachment err := s.AttachmentDao.FieldsEx(s.AttachmentDao.Columns.DeletedTime). Where(s.AttachmentDao.Columns.EventId, event.Id). Scan(&attachments) if err != nil { g.Log().Errorf("createDevTaskFromEvent: query attachments failed, eventId=%d, err=%v", event.Id, err) } taskAttachments := make([]opsdevmodel.Attachment, 0, len(attachments)) for _, att := range attachments { taskAttachments = append(taskAttachments, opsdevmodel.Attachment{ FileName: att.FileName, FileUrl: att.FileUrl, FileType: att.FileType, }) } taskType := s.getDevTaskType(event.EventType) projectId := 0 if event.ContractId > 0 { var project opsdevmodel.OpsDeliveryProject err := s.DeliveryProjectDao.FieldsEx(s.DeliveryProjectDao.Columns.DeletedTime). Where(s.DeliveryProjectDao.Columns.ContractId, event.ContractId). OrderDesc(s.DeliveryProjectDao.Columns.Id). Limit(1). Scan(&project) if err != nil { g.Log().Warningf("createDevTaskFromEvent: query project by contractId=%d failed, err=%v", event.ContractId, err) } else if project.Id > 0 { projectId = project.Id } else { g.Log().Warningf("createDevTaskFromEvent: no project found for contractId=%d", event.ContractId) } } taskReq := &opsdevmodel.OpsEventTaskAddReq{ ProjectId: projectId, TaskTitle: event.EventTitle, TaskDesc: event.EventDesc, TaskType: taskType, Priority: event.PriorityLevel, OpsUserId: event.OpsUserId, OpsUserName: event.OpsUserName, EventId: event.Id, EventType: opsdevmodel.EventTypeOps, Attachments: taskAttachments, } taskSvc, err := NewOpsEventTaskService(s.Ctx) if err != nil { g.Log().Errorf("createDevTaskFromEvent: init task service failed, eventId=%d, err=%v", event.Id, err) return } if err := taskSvc.Create(taskReq); err != nil { g.Log().Errorf("createDevTaskFromEvent: create task failed, eventId=%d, eventType=%s, taskType=%s, err=%v", event.Id, event.EventType, taskType, err) } } // processNormal 非关单处理(开始/转处理/转研发/挂起) func (s *OperationService) processNormal(req *opsdevmodel.OpsOperationEventProcessReq, event *opsdevmodel.OpsOperationEvent, opsUserId int, opsUserName string) error { handleDate := gtime.Now() recordData := g.Map{ s.RecordDao.Columns.EventId: req.Id, s.RecordDao.Columns.HandleUserId: opsUserId, s.RecordDao.Columns.HandleUserName: opsUserName, s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: req.HandleResult, s.RecordDao.Columns.HandleDate: handleDate, s.RecordDao.Columns.OperateType: req.OperateType, } service.SetCreatedInfo(recordData, opsUserId, opsUserName) newStatus := "" switch req.OperateType { case opsdevmodel.OperateTypeProcess: newStatus = opsdevmodel.EventStatusProcessing case opsdevmodel.OperateTypeResume: newStatus = opsdevmodel.EventStatusProcessing case opsdevmodel.OperateTypeTransfer: newStatus = opsdevmodel.EventStatusTransfer case opsdevmodel.OperateTypeSuspend: newStatus = opsdevmodel.EventStatusSuspended } err := s.Dao.Transaction(s.Ctx, func(ctx context.Context, tx *gdb.TX) error { _, err := s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("创建处理记录失败") } if newStatus != "" { updateData := g.Map{ s.Dao.Columns.EventStatus: newStatus, } service.SetUpdatedInfo(updateData, opsUserId, opsUserName) _, err := s.Dao.TX(tx).FieldsEx(service.UpdateFieldEx...).Data(updateData).WherePri(s.Dao.Columns.Id, req.Id).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("更新事件状态失败") } } return nil }) if err != nil { return err } if req.OperateType == opsdevmodel.OperateTypeTransfer { s.createDevTaskFromEvent(event) } return nil } // UpdateById 更新运维事件 func (s *OperationService) UpdateById(req *opsdevmodel.UpdateOpsOperationEventReq) error { if req.Id <= 0 { return myerrors.ValidError("参数有误!") } 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("运维事件不存在") } data := g.Map{} if req.EventTitle != "" { data[s.Dao.Columns.EventTitle] = req.EventTitle } if req.EventDesc != "" { data[s.Dao.Columns.EventDesc] = req.EventDesc } if req.EventType != "" { data[s.Dao.Columns.EventType] = req.EventType } if req.EventStatus != "" { data[s.Dao.Columns.EventStatus] = req.EventStatus } if req.ContractId > 0 { data[s.Dao.Columns.ContractId] = req.ContractId } if req.ContractName != "" { data[s.Dao.Columns.ContractName] = req.ContractName } if req.CustId > 0 { data[s.Dao.Columns.CustId] = req.CustId } if req.CustName != "" { data[s.Dao.Columns.CustName] = req.CustName } if req.ProductLine != "" { data[s.Dao.Columns.ProductLine] = req.ProductLine } if req.IsBig != "" { data[s.Dao.Columns.IsBig] = req.IsBig } if req.IsOps != "" { data[s.Dao.Columns.IsOps] = req.IsOps } if req.PriorityLevel != "" { data[s.Dao.Columns.PriorityLevel] = req.PriorityLevel } if req.FeedbackSource != "" { data[s.Dao.Columns.FeedbackSource] = req.FeedbackSource } if req.FeedbackReporter != "" { data[s.Dao.Columns.FeedbackReporter] = req.FeedbackReporter } if req.FeedbackDate != "" { data[s.Dao.Columns.FeedbackDate] = req.FeedbackDate } if req.OpsUserId > 0 { data[s.Dao.Columns.OpsUserId] = req.OpsUserId } if req.OpsUserName != "" { data[s.Dao.Columns.OpsUserName] = req.OpsUserName } if req.Remark != "" { data[s.Dao.Columns.Remark] = req.Remark } service.SetUpdatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.Dao.FieldsEx(service.UpdateFieldEx...).Data(data).WherePri(s.Dao.Columns.Id, req.Id).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("更新运维事件失败") } // 同步事件级附件:删除旧附件,插入新附件 if req.Attachments != nil { _, _ = s.AttachmentDao.Data(g.Map{ s.AttachmentDao.Columns.DeletedTime: gtime.Now(), }).Where(s.AttachmentDao.Columns.EventId, req.Id). Where("(event_record_id = 0 OR event_record_id IS NULL)"). Update() for _, att := range req.Attachments { attData := g.Map{ s.AttachmentDao.Columns.EventId: req.Id, s.AttachmentDao.Columns.FileName: att.FileName, s.AttachmentDao.Columns.FileUrl: att.FileUrl, s.AttachmentDao.Columns.FileType: att.FileType, } service.SetCreatedInfo(attData, s.GetCxtUserId(), s.GetCxtUserName()) _, err := s.AttachmentDao.Data(attData).Insert() if err != nil { g.Log().Error(err) } } } return nil } // DeleteByIds 根据ID批量删除运维事件(软删除) func (s *OperationService) DeleteByIds(req *comm_def.IdsReq) error { if len(req.Ids) == 0 { return myerrors.ValidError("参数有误!") } ids := make([]int, 0, len(req.Ids)) for _, id := range req.Ids { ids = append(ids, int(id)) } return s.Dao.Transaction(s.Ctx, func(ctx context.Context, tx *gdb.TX) error { // 1. 软删除事件 _, err := s.Dao.TX(tx).Data(g.Map{ s.Dao.Columns.DeletedTime: gtime.Now(), }).WhereIn(s.Dao.Columns.Id, ids).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("删除运维事件失败") } // 2. 软删除关联的处理记录 _, err = s.RecordDao.TX(tx).Data(g.Map{ s.RecordDao.Columns.DeletedTime: gtime.Now(), }).WhereIn(s.RecordDao.Columns.EventId, ids).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("删除处理记录失败") } // 3. 软删除关联的附件 _, err = s.AttachmentDao.TX(tx).Data(g.Map{ s.AttachmentDao.Columns.DeletedTime: gtime.Now(), }).WhereIn(s.AttachmentDao.Columns.EventId, ids).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("删除附件失败") } return nil }) } // GetRecords 获取事件处理记录列表(分页,含附件) func (s *OperationService) GetRecords(req *opsdevmodel.OpsOperationEventRecordSearchReq) (total int, list []*opsdevmodel.OpsOperationEventRecordWithAttachments, 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() var records []*opsdevmodel.OpsOperationEventRecord err = db.Page(pageNum, pageSize).Order(s.RecordDao.Columns.CreatedTime + " desc").Scan(&records) if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询处理记录列表失败") } result := make([]*opsdevmodel.OpsOperationEventRecordWithAttachments, 0, len(records)) for _, record := range records { recordRsp := &opsdevmodel.OpsOperationEventRecordWithAttachments{ OpsOperationEventRecord: *record, Attachments: []*opsdevmodel.OpsOperationEventAttachment{}, } if record.Id > 0 { var attachments []*opsdevmodel.OpsOperationEventAttachment err := s.AttachmentDao.FieldsEx(s.AttachmentDao.Columns.DeletedTime). Where(s.AttachmentDao.Columns.EventRecordId, record.Id). Scan(&attachments) if err != nil { g.Log().Error(err) } else { recordRsp.Attachments = attachments } } result = append(result, recordRsp) } return total, result, nil } // UploadAttachment 上传附件 func (s *OperationService) UploadAttachment(req *opsdevmodel.OpsOperationEventAttachmentReq) (*opsdevmodel.OpsOperationEventAttachment, error) { if req.EventId <= 0 { return nil, 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 nil, myerrors.DbError("查询运维事件失败") } if event.Id <= 0 { return nil, myerrors.TipsError("运维事件不存在") } 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()) result, err := s.AttachmentDao.Data(data).Insert() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("上传附件失败") } id, err := result.LastInsertId() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("获取附件ID失败") } attachment := new(opsdevmodel.OpsOperationEventAttachment) err = s.AttachmentDao.WherePri(s.AttachmentDao.Columns.Id, id).Scan(attachment) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询附件失败") } return attachment, nil } // GetAttachments 根据事件ID获取附件列表 func (s *OperationService) GetAttachments(eventId int) ([]*opsdevmodel.OpsOperationEventAttachment, error) { if eventId <= 0 { return nil, myerrors.ValidError("事件ID不能为空") } var attachments []*opsdevmodel.OpsOperationEventAttachment err := s.AttachmentDao.FieldsEx(s.AttachmentDao.Columns.DeletedTime). Where(s.AttachmentDao.Columns.EventId, eventId). Order(s.AttachmentDao.Columns.CreatedTime + " desc"). Scan(&attachments) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询附件列表失败") } return attachments, nil } // GetStats 获取运维事件统计数据 func (s *OperationService) GetStats() (g.Map, error) { stats := g.Map{} // 按状态统计 db := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime) statusList, err := db.GroupBy(s.Dao.Columns.EventStatus).Fields(s.Dao.Columns.EventStatus+", count(*) as count").All() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("统计事件状态失败") } statusCount := g.Map{} for _, row := range statusList { statusCount[gconv.String(row["event_status"])] = row["count"] } stats["statusCount"] = statusCount // 按优先级统计 priorityList, err := db.GroupBy(s.Dao.Columns.PriorityLevel).Fields(s.Dao.Columns.PriorityLevel+", count(*) as count").All() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("统计事件优先级失败") } priorityCount := g.Map{} for _, row := range priorityList { priorityCount[gconv.String(row["priority_level"])] = row["count"] } stats["priorityCount"] = priorityCount // 按类型统计 typeList, err := db.GroupBy(s.Dao.Columns.EventType).Fields(s.Dao.Columns.EventType+", count(*) as count").All() if err != nil { g.Log().Error(err) return nil, myerrors.DbError("统计事件类型失败") } typeCount := g.Map{} for _, row := range typeList { typeCount[gconv.String(row["event_type"])] = row["count"] } stats["typeCount"] = typeCount return stats, nil } // GetKanbanData 获取看板数据 func (s *OperationService) GetKanbanData(req *opsdevmodel.OpsOperationEventKanbanSearchReq) (g.Map, error) { // 查询所有非关闭状态的事件 db := s.Dao.FieldsEx(s.Dao.Columns.DeletedTime).Where(s.Dao.Columns.EventStatus+" != ?", opsdevmodel.EventStatusClosed) if req.KeyWords != "" { switch req.SearchType { case "eventNo": db = db.Where(s.Dao.Columns.EventNo, req.KeyWords) case "title": db = db.Where(s.Dao.Columns.EventTitle+" like ?", "%"+req.KeyWords+"%") case "custName": db = db.Where(s.Dao.Columns.CustName+" like ?", "%"+req.KeyWords+"%") case "feedbackReporter": db = db.Where(s.Dao.Columns.FeedbackReporter+" like ?", "%"+req.KeyWords+"%") default: db = db.Where(fmt.Sprintf("(%s like ? or %s like ? or %s like ? or %s = ?)", s.Dao.Columns.EventTitle, s.Dao.Columns.CustName, s.Dao.Columns.FeedbackReporter, s.Dao.Columns.EventNo), "%"+req.KeyWords+"%", "%"+req.KeyWords+"%", "%"+req.KeyWords+"%", 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) } // 待处理可查看全部,处理中/转研发/挂起仅查看当前登录人的 userId := s.GetCxtUserId() if userId > 0 { db = db.Where(fmt.Sprintf("(%s = ? OR %s = ?)", s.Dao.Columns.EventStatus, s.Dao.Columns.OpsUserId), opsdevmodel.EventStatusPending, userId) } // 排序 switch req.SortBy { case "feedbackDateAsc": db = db.Order(s.Dao.Columns.FeedbackDate + " asc") case "custName": db = db.Order(s.Dao.Columns.CustName + " asc") default: db = db.Order(s.Dao.Columns.FeedbackDate + " desc") } var list []*opsdevmodel.OpsOperationEvent err := db.Scan(&list) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询看板数据失败") } // 按状态分组(处理中合并 20 + 30) groups := map[string][]*opsdevmodel.OpsOperationEvent{ opsdevmodel.EventStatusPending: make([]*opsdevmodel.OpsOperationEvent, 0), // 待处理 opsdevmodel.EventStatusProcessing: make([]*opsdevmodel.OpsOperationEvent, 0), // 处理中 opsdevmodel.EventStatusTransfer: make([]*opsdevmodel.OpsOperationEvent, 0), // 转研发 opsdevmodel.EventStatusSuspended: make([]*opsdevmodel.OpsOperationEvent, 0), // 挂起 } for _, item := range list { key := item.EventStatus if key == opsdevmodel.EventStatusProcessingNormal { key = opsdevmodel.EventStatusProcessing } groups[key] = append(groups[key], item) } kanbanData := g.Map{} for key, items := range groups { kanbanData[key] = g.Map{ "list": items, "count": len(items), } } return kanbanData, nil } // AssignOpsUser 分配运维人员 func (s *OperationService) AssignOpsUser(req *opsdevmodel.AssignOpsUserReq) error { if req.Id <= 0 { return myerrors.ValidError("事件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("运维事件不存在") } data := g.Map{ s.Dao.Columns.OpsUserId: req.OpsUserId, s.Dao.Columns.OpsUserName: req.OpsUserName, s.Dao.Columns.AssignTime: gtime.Now(), } service.SetUpdatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.Dao.FieldsEx(service.UpdateFieldEx...).Data(data).WherePri(s.Dao.Columns.Id, req.Id).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("运维事件不存在") } opsUserId := s.GetCxtUserId() opsUserName := s.GetCxtUserName() recordData := g.Map{ s.RecordDao.Columns.EventId: req.EventId, s.RecordDao.Columns.HandleUserId: opsUserId, s.RecordDao.Columns.HandleUserName: opsUserName, s.RecordDao.Columns.HandleContent: req.HandleContent, s.RecordDao.Columns.HandleResult: req.HandleResult, s.RecordDao.Columns.OperateType: opsdevmodel.OperateTypeProcess, s.RecordDao.Columns.HandleDate: gtime.Now(), } service.SetCreatedInfo(recordData, opsUserId, opsUserName) return s.RecordDao.Transaction(s.Ctx, func(ctx context.Context, tx *gdb.TX) error { result, err := s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("添加处理记录失败") } recordId, err := result.LastInsertId() if err != nil { g.Log().Error(err) return myerrors.DbError("获取记录ID失败") } // 如果有附件,一并保存 for _, att := range req.Attachments { attData := g.Map{ s.AttachmentDao.Columns.EventId: req.EventId, s.AttachmentDao.Columns.EventRecordId: recordId, s.AttachmentDao.Columns.FileName: att.FileName, s.AttachmentDao.Columns.FileUrl: att.FileUrl, s.AttachmentDao.Columns.FileType: att.FileType, } service.SetCreatedInfo(attData, opsUserId, opsUserName) _, err := s.AttachmentDao.TX(tx).Data(attData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("保存附件失败") } } return nil }) }