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"
}