| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414 |
- 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
- })
- }
|