| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416 |
- 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, req *opsdevmodel.OpsOperationEventProcessReq) {
- 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: req.OpsUserId,
- OpsUserName: req.OpsUserName,
- PlanStartTime: req.PlanStartTime,
- PlanEndTime: req.PlanEndTime,
- 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, req)
- }
- 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
- })
- }
|