package opsdev import ( "context" "fmt" "strings" "dashoo.cn/opms_libary/myerrors" eventdao "dashoo.cn/opms_parent/app/dao/opsdev" eventmodel "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" ) // eventTypeToAutoTaskType 交付事件类型→自动创建研发任务类型的映射 var eventTypeToAutoTaskType = map[string]string{ "31": eventmodel.TaskTypeReqReview, // 需求评审 → 需求评审 "32": eventmodel.TaskTypeFeatureDev, // 功能调整 → 功能开发 "33": eventmodel.TaskTypeFeatureDev, // 二开需求 → 功能开发 "35": eventmodel.TaskTypeFeatureDev, // 系统缺陷 → 功能开发 "38": eventmodel.TaskTypeSystemReleaseEvt, // 系统发版 → 系统发版(事件) "40": eventmodel.TaskTypeSystemReleaseEvt, // 硬件发货 → 系统发版(事件) "41": eventmodel.TaskTypeSystemReleaseEvt, // 硬件安装 → 系统发版(事件) } // DeliveryProjectEventService 交付项目事件业务逻辑实现类 type DeliveryProjectEventService struct { *service.ContextService EventDao *eventdao.OpsDeliveryProjectEventDao RecordDao *eventdao.OpsDeliveryProjectEventRecordDao AttachmentDao *eventdao.OpsDeliveryProjectEventAttachmentDao ProjectDao *eventdao.OpsDeliveryProjectDao TaskDao *eventdao.OpsEventTaskDao TaskRecordDao *eventdao.OpsEventTaskRecordDao } // NewDeliveryProjectEventService 初始化service func NewDeliveryProjectEventService(ctx context.Context) (svc *DeliveryProjectEventService, err error) { svc = new(DeliveryProjectEventService) if svc.ContextService, err = svc.Init(ctx); err != nil { return nil, err } svc.EventDao = eventdao.NewOpsDeliveryProjectEventDao(svc.Tenant) svc.RecordDao = eventdao.NewOpsDeliveryProjectEventRecordDao(svc.Tenant) svc.AttachmentDao = eventdao.NewOpsDeliveryProjectEventAttachmentDao(svc.Tenant) svc.ProjectDao = eventdao.NewOpsDeliveryProjectDao(svc.Tenant) svc.TaskDao = eventdao.NewOpsEventTaskDao(svc.Tenant) svc.TaskRecordDao = eventdao.NewOpsEventTaskRecordDao(svc.Tenant) return svc, nil } // GetList 分页查询事件列表 func (s *DeliveryProjectEventService) GetList(req *eventmodel.OpsDeliveryProjectEventSearchReq) (total int, list []*eventmodel.OpsDeliveryProjectEventRsp, err error) { db := s.EventDao.FieldsEx(s.EventDao.Columns.DeletedTime) // 项目ID筛选 if req.ProjectId > 0 { db = db.Where(s.EventDao.Columns.ProjectId, req.ProjectId) } // 事件标题模糊查询 if req.DeliveryEventTitle != "" { db = db.Where(s.EventDao.Columns.DeliveryEventTitle+" like ?", "%"+req.DeliveryEventTitle+"%") } // 事件描述模糊查询 if req.DeliveryEventDesc != "" { db = db.Where(s.EventDao.Columns.DeliveryEventDesc+" like ?", "%"+req.DeliveryEventDesc+"%") } // 事件类型筛选(多选) if len(req.DeliveryEventType) > 0 { db = db.Where(s.EventDao.Columns.DeliveryEventType+" in (?)", req.DeliveryEventType) } // 事件状态筛选(多选) if len(req.DeliveryEventStatus) > 0 { db = db.Where(s.EventDao.Columns.DeliveryEventStatus+" in (?)", req.DeliveryEventStatus) } // 事件结果筛选(多选) if len(req.DeliveryEventResult) > 0 { db = db.Where(s.EventDao.Columns.DeliveryEventResult+" in (?)", req.DeliveryEventResult) } // 反馈来源筛选 if req.FeedbackSource != "" { db = db.Where(s.EventDao.Columns.FeedbackSource, req.FeedbackSource) } // 反馈人模糊查询 if req.FeedbackReporter != "" { db = db.Where(s.EventDao.Columns.FeedbackReporter+" like ?", "%"+req.FeedbackReporter+"%") } // 负责人筛选(多选精确匹配) if len(req.OpsUserName) > 0 { db = db.Where(s.EventDao.Columns.OpsUserName+" in (?)", req.OpsUserName) } // 反馈时间范围 if req.FeedbackDateStart != "" { db = db.Where(s.EventDao.Columns.FeedbackDate+">= ?", req.FeedbackDateStart) } if req.FeedbackDateEnd != "" { db = db.Where(s.EventDao.Columns.FeedbackDate+"<= ?", req.FeedbackDateEnd) } // 处理时间范围 if req.CompleteTimeStart != "" { db = db.Where(s.EventDao.Columns.CompleteTime+">= ?", req.CompleteTimeStart) } if req.CompleteTimeEnd != "" { db = db.Where(s.EventDao.Columns.CompleteTime+"<= ?", req.CompleteTimeEnd) } // 统计总数 total, err = db.Count() if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("获取事件总数失败") } // 分页查询 pageNum, pageSize := req.GetPage() var entityList []*eventmodel.OpsDeliveryProjectEvent // 处理排序 if len(req.SortFields) > 0 { orderClauses := []string{} for _, sort := range req.SortFields { // 将前端字段名转换为数据库列名 colName := s.getSortColumnName(sort.Field) if colName != "" { orderClauses = append(orderClauses, colName+" "+strings.ToUpper(sort.Order)) } } if len(orderClauses) > 0 { db = db.Order(strings.Join(orderClauses, ", ")) } else { db = db.Order(s.EventDao.Columns.CreatedTime + " desc") } } else { db = db.Order(s.EventDao.Columns.CreatedTime + " desc") } err = db.Page(pageNum, pageSize).Scan(&entityList) if err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("查询事件列表失败") } // 转换为响应结构体 if err = gconv.Structs(entityList, &list); err != nil { g.Log().Error(err) return 0, nil, myerrors.DbError("数据转换失败") } if len(list) > 0 { projectIds := make([]int, 0, len(list)) for _, item := range list { if item.ProjectId > 0 { projectIds = append(projectIds, item.ProjectId) } } if len(projectIds) > 0 { var projects []*eventmodel.OpsDeliveryProject err := s.ProjectDao.Fields( s.ProjectDao.Columns.Id, s.ProjectDao.Columns.ProjectName, ).WhereIn(s.ProjectDao.Columns.Id, projectIds).Scan(&projects) if err != nil { g.Log().Error(err) } else { projectMap := make(map[int]string) for _, p := range projects { projectMap[p.Id] = p.ProjectName } for _, item := range list { if name, ok := projectMap[item.ProjectId]; ok { item.ProjectName = name } } } } } return } // getSortColumnName 将前端排序字段名转换为数据库列名 func (s *DeliveryProjectEventService) getSortColumnName(field string) string { // 前端字段名到数据库列名的映射 fieldMap := map[string]string{ "deliveryEventType": s.EventDao.Columns.DeliveryEventType, "deliveryEventStatus": s.EventDao.Columns.DeliveryEventStatus, "deliveryEventResult": s.EventDao.Columns.DeliveryEventResult, "opsUserName": s.EventDao.Columns.OpsUserName, "feedbackReporter": s.EventDao.Columns.FeedbackReporter, "feedbackDate": s.EventDao.Columns.FeedbackDate, "completeTime": s.EventDao.Columns.CompleteTime, } if colName, ok := fieldMap[field]; ok { return colName } return "" } // Create 新增事件,包含事务控制和过程记录、附件存储 func (s *DeliveryProjectEventService) Create(req *eventmodel.OpsDeliveryProjectEventAddReq) error { // 生成事件编码 eventNo := s.generateEventNo() // 硬件发货(40)和硬件安装(41)默认状态为处理中(20) status := "10" // 待处理 if req.DeliveryEventType == "40" || req.DeliveryEventType == "41" { status = "20" } // 构造数据,负责人默认为当前登录人,允许前端传入 opsUserId := s.GetCxtUserId() opsUserName := s.GetCxtUserName() if req.OpsUserId > 0 { opsUserId = req.OpsUserId opsUserName = req.OpsUserName } data := g.Map{ s.EventDao.Columns.ProjectId: req.ProjectId, s.EventDao.Columns.DeliveryEventNo: eventNo, s.EventDao.Columns.DeliveryEventTitle: req.DeliveryEventTitle, s.EventDao.Columns.DeliveryEventDesc: req.DeliveryEventDesc, s.EventDao.Columns.DeliveryEventType: req.DeliveryEventType, s.EventDao.Columns.DeliveryEventStatus: status, s.EventDao.Columns.FeedbackSource: req.FeedbackSource, s.EventDao.Columns.FeedbackReporter: req.FeedbackReporter, s.EventDao.Columns.FeedbackDate: gtime.Now(), s.EventDao.Columns.OnSite: req.OnSite, s.EventDao.Columns.OpsUserId: opsUserId, s.EventDao.Columns.OpsUserName: opsUserName, } if req.Attribute1 != "" { data[s.EventDao.Columns.Attribute1] = req.Attribute1 } if req.CompleteTime != "" { data[s.EventDao.Columns.CompleteTime] = req.CompleteTime } if req.ActualWorkHour > 0 { data[s.EventDao.Columns.ActualWorkHour] = req.ActualWorkHour } // 补齐审计字段 service.SetCreatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) // 使用事务控制 return s.EventDao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { // 1. 创建事件记录 result, err := s.EventDao.TX(tx).Data(data).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("新增事件失败") } // 获取新创建的事件ID eventId, err := result.LastInsertId() if err != nil { g.Log().Error(err) return myerrors.DbError("获取事件ID失败") } // 2. 创建事件过程记录 recordData := g.Map{ s.RecordDao.Columns.DeliveryEventId: eventId, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: "创建事件
事件标题: " + req.DeliveryEventTitle, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) recordResult, err := s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("新增事件过程记录失败") } recordId, err := recordResult.LastInsertId() if err != nil { g.Log().Error(err) return myerrors.DbError("获取过程记录ID失败") } // 3. 保存附件信息 if len(req.Attachments) > 0 { for _, att := range req.Attachments { attData := g.Map{ s.AttachmentDao.Columns.DeliveryEventId: eventId, s.AttachmentDao.Columns.EventId: 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, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.AttachmentDao.TX(tx).Data(attData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("保存附件信息失败") } } } // 4. 特定事件类型自动创建研发任务 if taskType, ok := eventTypeToAutoTaskType[req.DeliveryEventType]; ok { taskNo := s.generateTaskNo() taskData := g.Map{ s.TaskDao.Columns.TaskNo: taskNo, s.TaskDao.Columns.ProjectId: req.ProjectId, s.TaskDao.Columns.ProjectName: s.getProjectName(req.ProjectId), s.TaskDao.Columns.TaskTitle: req.DeliveryEventTitle, s.TaskDao.Columns.TaskDesc: req.DeliveryEventDesc, s.TaskDao.Columns.FunctionName: req.DeliveryEventTitle, s.TaskDao.Columns.TaskType: taskType, s.TaskDao.Columns.TaskStatus: eventmodel.TaskStatusTodo, s.TaskDao.Columns.Priority: "20", s.TaskDao.Columns.EventId: int(eventId), s.TaskDao.Columns.EventType: eventmodel.EventTypeDelivery, } service.SetCreatedInfo(taskData, s.GetCxtUserId(), s.GetCxtUserName()) taskResult, err := s.TaskDao.TX(tx).Data(taskData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("自动创建研发任务失败") } taskId, _ := taskResult.LastInsertId() taskRecordData := g.Map{ s.TaskRecordDao.Columns.TaskId: taskId, s.TaskRecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.TaskRecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.TaskRecordDao.Columns.HandleContent: "自动创建任务
说明: 由交付事件自动创建 (" + req.DeliveryEventTitle + ")", } service.SetCreatedInfo(taskRecordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.TaskRecordDao.TX(tx).Data(taskRecordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("新增任务过程记录失败") } } return nil }) } // UpdateById 根据ID更新事件 func (s *DeliveryProjectEventService) UpdateById(req *eventmodel.OpsDeliveryProjectEventUpdateReq) error { // 校验数据是否存在 var entity eventmodel.OpsDeliveryProjectEvent err := s.EventDao.FieldsEx(s.EventDao.Columns.DeletedTime).WherePri(s.EventDao.Columns.Id, req.Id).Scan(&entity) if err != nil { g.Log().Error(err) return myerrors.DbError("查询事件数据失败") } if entity.Id <= 0 { return myerrors.TipsError("事件数据不存在") } // 构造更新数据 - 从请求中动态构建,支持前端传来的任何有效字段 data := g.Map{} // 基础字段(编辑时可能更新,但关闭/处理事件时不传这些字段) if req.DeliveryEventTitle != "" { data[s.EventDao.Columns.DeliveryEventTitle] = req.DeliveryEventTitle } if req.DeliveryEventDesc != "" { data[s.EventDao.Columns.DeliveryEventDesc] = req.DeliveryEventDesc } if req.DeliveryEventType != "" { data[s.EventDao.Columns.DeliveryEventType] = req.DeliveryEventType } if req.FeedbackSource != "" { data[s.EventDao.Columns.FeedbackSource] = req.FeedbackSource } if req.FeedbackReporter != "" { data[s.EventDao.Columns.FeedbackReporter] = req.FeedbackReporter } if req.OnSite != "" { data[s.EventDao.Columns.OnSite] = req.OnSite } // 处理状态和结果字段(关闭事件时传入) if req.DeliveryEventStatus != "" { data[s.EventDao.Columns.DeliveryEventStatus] = req.DeliveryEventStatus } if req.DeliveryEventResult != "" { data[s.EventDao.Columns.DeliveryEventResult] = req.DeliveryEventResult } // 处理完成相关字段(处理/关闭事件时传入) if req.CompleteDesc != "" { data[s.EventDao.Columns.CompleteDesc] = req.CompleteDesc } if req.CompleteTime != "" { data[s.EventDao.Columns.CompleteTime] = req.CompleteTime } if req.ActualWorkHour > 0 { data[s.EventDao.Columns.ActualWorkHour] = req.ActualWorkHour } // 处理负责人相关字段(分配时传入) if req.OpsUserId > 0 { data[s.EventDao.Columns.OpsUserId] = req.OpsUserId data[s.EventDao.Columns.OpsUserName] = req.OpsUserName } // 物流单号 if req.Attribute1 != "" { data[s.EventDao.Columns.Attribute1] = req.Attribute1 } // 补齐审计字段 service.SetUpdatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) // 更新操作,排除不可改字段 _, err = s.EventDao.FieldsEx(service.UpdateFieldEx...).Data(data).WherePri(s.EventDao.Columns.Id, req.Id).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("更新事件失败") } return nil } // DeleteByIds 根据ID批量删除 func (s *DeliveryProjectEventService) DeleteByIds(ids []int64) error { if len(ids) == 0 { return myerrors.TipsError("请选择需要删除的事件") } return s.EventDao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { // 1. 删除事件 _, err := s.EventDao.TX(tx).WhereIn(s.EventDao.Columns.Id, ids).Delete() if err != nil { g.Log().Error(err) return myerrors.DbError("删除事件失败") } // 2. 删除关联的过程记录 _, err = s.RecordDao.TX(tx).WhereIn(s.RecordDao.Columns.DeliveryEventId, ids).Delete() if err != nil { g.Log().Error(err) return myerrors.DbError("删除事件过程记录失败") } // 3. 删除关联的附件 _, err = s.AttachmentDao.TX(tx).WhereIn(s.AttachmentDao.Columns.DeliveryEventId, ids).Delete() if err != nil { g.Log().Error(err) return myerrors.DbError("删除事件附件失败") } return nil }) } // Cancel 作废事件 func (s *DeliveryProjectEventService) Cancel(req *eventmodel.OpsDeliveryProjectEventCancelReq) error { // 校验数据是否存在 var entity eventmodel.OpsDeliveryProjectEvent err := s.EventDao.FieldsEx(s.EventDao.Columns.DeletedTime).WherePri(s.EventDao.Columns.Id, req.Id).Scan(&entity) if err != nil { g.Log().Error(err) return myerrors.DbError("查询事件数据失败") } if entity.Id <= 0 { return myerrors.TipsError("事件数据不存在") } // 已关闭的事件不能作废 if entity.DeliveryEventStatus == eventmodel.DeliveryEventStatusClosed { return myerrors.TipsError("已关闭的事件不能作废") } // 已作废的事件不能再次作废 if entity.DeliveryEventStatus == eventmodel.DeliveryEventStatusCancelled { return myerrors.TipsError("该事件已作废") } return s.EventDao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { // 1. 更新事件状态为已作废 data := g.Map{ s.EventDao.Columns.DeliveryEventStatus: eventmodel.DeliveryEventStatusCancelled, s.EventDao.Columns.Remark: req.CancelReason, } service.SetUpdatedInfo(data, s.GetCxtUserId(), s.GetCxtUserName()) _, err := s.EventDao.TX(tx).FieldsEx(service.UpdateFieldEx...).Data(data).WherePri(s.EventDao.Columns.Id, req.Id).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("作废事件失败") } // 2. 添加作废过程记录 recordContent := "作废事件
作废原因: " + req.CancelReason recordData := g.Map{ s.RecordDao.Columns.DeliveryEventId: req.Id, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: recordContent, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) recordResult, err := s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("新增过程记录失败") } recordId, _ := recordResult.LastInsertId() // 3. 保存附件 if len(req.Attachments) > 0 { for _, att := range req.Attachments { attData := g.Map{ s.AttachmentDao.Columns.DeliveryEventId: req.Id, s.AttachmentDao.Columns.EventId: req.Id, 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, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.AttachmentDao.TX(tx).Data(attData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("保存附件信息失败") } } } _ = recordId // 避免未使用变量警告 // 4. 查询关联的任务并作废 var tasks []*eventmodel.OpsEventTask err = s.TaskDao.TX(tx).Where(s.TaskDao.Columns.EventId, req.Id). Where(s.TaskDao.Columns.EventType, eventmodel.EventTypeDelivery). Scan(&tasks) if err != nil { g.Log().Error(err) return myerrors.DbError("查询关联任务失败") } // 5. 作废关联的任务 for _, task := range tasks { // 已完成的任务不能作废 if task.TaskStatus == "30" { continue } // 已作废的任务不需要再次作废 if task.TaskStatus == "90" { continue } // 更新任务状态为作废 taskData := g.Map{ s.TaskDao.Columns.TaskStatus: "90", } service.SetUpdatedInfo(taskData, s.GetCxtUserId(), s.GetCxtUserName()) _, err := s.TaskDao.TX(tx).FieldsEx(service.UpdateFieldEx...).Data(taskData). WherePri(s.TaskDao.Columns.Id, task.Id).Update() if err != nil { g.Log().Error(err) return myerrors.DbError("作废关联任务失败") } // 添加任务作废过程记录 taskRecordData := g.Map{ s.TaskRecordDao.Columns.TaskId: task.Id, s.TaskRecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.TaskRecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.TaskRecordDao.Columns.HandleContent: "作废任务
作废原因: 关联事件被作废 - " + req.CancelReason, } service.SetCreatedInfo(taskRecordData, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.TaskRecordDao.TX(tx).Data(taskRecordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("新增任务过程记录失败") } } return nil }) } // GetById 根据ID查询单条(关联项目信息) func (s *DeliveryProjectEventService) GetById(id int) (*eventmodel.OpsDeliveryProjectEventRsp, error) { var entity eventmodel.OpsDeliveryProjectEvent err := s.EventDao.FieldsEx(s.EventDao.Columns.DeletedTime).WherePri(s.EventDao.Columns.Id, id).Scan(&entity) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询事件数据失败") } if entity.Id <= 0 { return nil, myerrors.TipsError("事件数据不存在") } var rsp eventmodel.OpsDeliveryProjectEventRsp if err := gconv.Struct(entity, &rsp); err != nil { g.Log().Error(err) return nil, myerrors.DbError("数据转换失败") } // 查询关联的项目信息 if entity.ProjectId > 0 { var project eventmodel.OpsDeliveryProject err := s.ProjectDao.FieldsEx(s.ProjectDao.Columns.DeletedTime). WherePri(s.ProjectDao.Columns.Id, entity.ProjectId). Scan(&project) if err != nil { g.Log().Error(err) } else if project.Id > 0 { // 填充项目信息 rsp.ProjectName = project.ProjectName rsp.ContractNo = project.ContractNo rsp.CustName = project.CustName rsp.ProductLine = project.ProductLine rsp.SalesUserName = project.SalesUserName // 填充关键节点时间 if project.InternalKickoffTime != nil { rsp.InternalKickoffTime = project.InternalKickoffTime.Format("Y-m-d H:i:s") } if project.ExternalKickoffTime != nil { rsp.ExternalKickoffTime = project.ExternalKickoffTime.Format("Y-m-d H:i:s") } if project.DeliveryPlanSubmitTime != nil { rsp.DeliveryPlanSubmitTime = project.DeliveryPlanSubmitTime.Format("Y-m-d H:i:s") } if project.DeploymentTime != nil { rsp.DeploymentTime = project.DeploymentTime.Format("Y-m-d H:i:s") } if project.TrialRunTime != nil { rsp.TrialRunTime = project.TrialRunTime.Format("Y-m-d H:i:s") } if project.GoLiveTime != nil { rsp.GoLiveTime = project.GoLiveTime.Format("Y-m-d H:i:s") } } } return &rsp, nil } // GetAttachments 获取事件附件列表 func (s *DeliveryProjectEventService) GetAttachments(eventId int) ([]*eventmodel.OpsDeliveryProjectEventAttachment, error) { var list []*eventmodel.OpsDeliveryProjectEventAttachment err := s.AttachmentDao.Where(s.AttachmentDao.Columns.DeliveryEventId, eventId).Scan(&list) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询附件列表失败") } return list, nil } // GetRecords 获取事件过程记录列表(包含附件) func (s *DeliveryProjectEventService) GetRecords(req *eventmodel.OpsDeliveryProjectEventRecordSearchReq) ([]*eventmodel.OpsDeliveryProjectEventRecordWithAttachments, error) { var records []*eventmodel.OpsDeliveryProjectEventRecord err := s.RecordDao.Where(s.RecordDao.Columns.DeliveryEventId, req.DeliveryEventId). Order(s.RecordDao.Columns.CreatedTime + " desc"). Scan(&records) if err != nil { g.Log().Error(err) return nil, myerrors.DbError("查询过程记录失败") } result := make([]*eventmodel.OpsDeliveryProjectEventRecordWithAttachments, 0, len(records)) for _, record := range records { recordRsp := &eventmodel.OpsDeliveryProjectEventRecordWithAttachments{ OpsDeliveryProjectEventRecord: *record, Attachments: []*eventmodel.OpsDeliveryProjectEventAttachment{}, } // 查询该记录关联的附件 if record.Id > 0 { var attachments []*eventmodel.OpsDeliveryProjectEventAttachment err := s.AttachmentDao.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 result, nil } // AddRecord 添加事件过程记录(带附件) func (s *DeliveryProjectEventService) AddRecord(req *eventmodel.OpsDeliveryProjectEventRecordAddReqWithAttachments) error { return s.EventDao.Transaction(context.TODO(), func(ctx context.Context, tx *gdb.TX) error { // 1. 创建过程记录 recordData := g.Map{ s.RecordDao.Columns.DeliveryEventId: req.DeliveryEventId, s.RecordDao.Columns.HandleUserId: s.GetCxtUserId(), s.RecordDao.Columns.HandleUserName: s.GetCxtUserName(), s.RecordDao.Columns.HandleContent: req.HandleContent, } service.SetCreatedInfo(recordData, s.GetCxtUserId(), s.GetCxtUserName()) result, err := s.RecordDao.TX(tx).Data(recordData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("新增过程记录失败") } // 获取记录ID recordId, err := result.LastInsertId() if err != nil { g.Log().Error(err) return myerrors.DbError("获取记录ID失败") } // 2. 保存附件 if len(req.Attachments) > 0 { for _, att := range req.Attachments { attData := g.Map{ s.AttachmentDao.Columns.DeliveryEventId: req.DeliveryEventId, s.AttachmentDao.Columns.EventId: req.DeliveryEventId, 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, s.GetCxtUserId(), s.GetCxtUserName()) _, err = s.AttachmentDao.TX(tx).Data(attData).Insert() if err != nil { g.Log().Error(err) return myerrors.DbError("保存附件信息失败") } } } return nil }) } // generateTaskNo 生成任务编号(与OpsEventTaskService保持统一格式) func (s *DeliveryProjectEventService) generateTaskNo() string { now := gtime.Now() prefix := "TSK" + now.Format("Ymd") var maxNoResult struct { TaskNo string } err := s.TaskDao.Where(s.TaskDao.Columns.TaskNo+" like ?", prefix+"%"). Order(s.TaskDao.Columns.TaskNo + " desc"). Fields(s.TaskDao.Columns.TaskNo). Scan(&maxNoResult) if err != nil || maxNoResult.TaskNo == "" { return prefix + "0001" } maxNoStr := maxNoResult.TaskNo if len(maxNoStr) >= len(prefix)+4 { seq := maxNoStr[len(prefix):] seqNum := gconv.Int(seq) seqNum++ return prefix + fmt.Sprintf("%04d", seqNum) } return prefix + "0001" } // getProjectName 根据项目ID获取项目名称 func (s *DeliveryProjectEventService) getProjectName(projectId int) string { if projectId <= 0 { return "" } var project eventmodel.OpsDeliveryProject err := s.ProjectDao.FieldsEx(s.ProjectDao.Columns.DeletedTime). WherePri(s.ProjectDao.Columns.Id, projectId). Scan(&project) if err != nil { g.Log().Error(err) return "" } return project.ProjectName } // generateEventNo 生成事件编码 func (s *DeliveryProjectEventService) generateEventNo() string { // 格式: EVT + 年月日 + 4位序号 now := gtime.Now() prefix := "EVT" + now.Format("Ymd") // 查询当天最大序号 var maxNoResult struct { DeliveryEventNo string } err := s.EventDao.Where(s.EventDao.Columns.DeliveryEventNo+" like ?", prefix+"%"). Order(s.EventDao.Columns.DeliveryEventNo + " desc"). Fields(s.EventDao.Columns.DeliveryEventNo). Scan(&maxNoResult) if err != nil || maxNoResult.DeliveryEventNo == "" { return prefix + "0001" } // 提取序号并+1 maxNoStr := maxNoResult.DeliveryEventNo if len(maxNoStr) >= len(prefix)+4 { seq := maxNoStr[len(prefix):] seqNum := gconv.Int(seq) seqNum++ return prefix + fmt.Sprintf("%04d", seqNum) } return prefix + "0001" }