Files
ai-agent/internal/services/ticket_relation_service.go
T
mlogclub efe801b8bf Init
2026-04-09 10:01:23 +08:00

213 lines
7.5 KiB
Go

package services
import (
"cs-agent/internal/models"
"cs-agent/internal/pkg/dto"
"cs-agent/internal/pkg/enums"
"cs-agent/internal/pkg/errorsx"
"cs-agent/internal/repositories"
"strings"
"time"
"github.com/mlogclub/simple/sqls"
"github.com/mlogclub/simple/web/params"
)
var TicketRelationService = newTicketRelationService()
func newTicketRelationService() *ticketRelationService {
return &ticketRelationService{}
}
type ticketRelationService struct {
}
func (s *ticketRelationService) Get(id int64) *models.TicketRelation {
return repositories.TicketRelationRepository.Get(sqls.DB(), id)
}
func (s *ticketRelationService) Take(where ...interface{}) *models.TicketRelation {
return repositories.TicketRelationRepository.Take(sqls.DB(), where...)
}
func (s *ticketRelationService) Find(cnd *sqls.Cnd) []models.TicketRelation {
return repositories.TicketRelationRepository.Find(sqls.DB(), cnd)
}
func (s *ticketRelationService) FindOne(cnd *sqls.Cnd) *models.TicketRelation {
return repositories.TicketRelationRepository.FindOne(sqls.DB(), cnd)
}
func (s *ticketRelationService) FindPageByParams(params *params.QueryParams) (list []models.TicketRelation, paging *sqls.Paging) {
return repositories.TicketRelationRepository.FindPageByParams(sqls.DB(), params)
}
func (s *ticketRelationService) FindPageByCnd(cnd *sqls.Cnd) (list []models.TicketRelation, paging *sqls.Paging) {
return repositories.TicketRelationRepository.FindPageByCnd(sqls.DB(), cnd)
}
func (s *ticketRelationService) Count(cnd *sqls.Cnd) int64 {
return repositories.TicketRelationRepository.Count(sqls.DB(), cnd)
}
func (s *ticketRelationService) Create(t *models.TicketRelation) error {
return repositories.TicketRelationRepository.Create(sqls.DB(), t)
}
func (s *ticketRelationService) Update(t *models.TicketRelation) error {
return repositories.TicketRelationRepository.Update(sqls.DB(), t)
}
func (s *ticketRelationService) Updates(id int64, columns map[string]interface{}) error {
return repositories.TicketRelationRepository.Updates(sqls.DB(), id, columns)
}
func (s *ticketRelationService) UpdateColumn(id int64, name string, value interface{}) error {
return repositories.TicketRelationRepository.UpdateColumn(sqls.DB(), id, name, value)
}
func (s *ticketRelationService) Delete(id int64) {
repositories.TicketRelationRepository.Delete(sqls.DB(), id)
}
func (s *ticketRelationService) AddRelation(ticketID, relatedTicketID int64, relationType enums.TicketRelationType, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
}
if ticketID <= 0 || relatedTicketID <= 0 {
return errorsx.InvalidParam("工单不存在")
}
if ticketID == relatedTicketID {
return errorsx.InvalidParam("不能关联自己")
}
if !isValidTicketRelationType(relationType) {
return errorsx.InvalidParam("关联类型不合法")
}
ticket := TicketService.Get(ticketID)
if ticket == nil {
return errorsx.InvalidParam("工单不存在")
}
relatedTicket := TicketService.Get(relatedTicketID)
if relatedTicket == nil {
return errorsx.InvalidParam("关联工单不存在")
}
if repositories.TicketRelationRepository.Take(sqls.DB(), "ticket_id = ? AND related_ticket_id = ? AND relation_type = ?", ticketID, relatedTicketID, relationType) != nil {
return errorsx.InvalidParam("该关联已存在")
}
now := time.Now()
inverseType := inverseTicketRelationType(relationType)
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
if err := repositories.TicketRelationRepository.Create(ctx.Tx, &models.TicketRelation{
TicketID: ticketID,
RelatedTicketID: relatedTicketID,
RelationType: relationType,
CreatedAt: now,
}); err != nil {
return err
}
if repositories.TicketRelationRepository.Take(ctx.Tx, "ticket_id = ? AND related_ticket_id = ? AND relation_type = ?", relatedTicketID, ticketID, inverseType) == nil {
if err := repositories.TicketRelationRepository.Create(ctx.Tx, &models.TicketRelation{
TicketID: relatedTicketID,
RelatedTicketID: ticketID,
RelationType: inverseType,
CreatedAt: now,
}); err != nil {
return err
}
}
if err := repositories.TicketEventLogRepository.Create(ctx.Tx, &models.TicketEventLog{
TicketID: ticketID,
EventType: enums.TicketEventTypeUpdated,
OperatorType: enums.IMSenderTypeAgent,
OperatorID: operator.UserID,
Content: "新增关联工单",
Payload: strings.TrimSpace(string(relationType) + ":" + relatedTicket.TicketNo),
CreatedAt: now,
}); err != nil {
return err
}
return repositories.TicketEventLogRepository.Create(ctx.Tx, &models.TicketEventLog{
TicketID: relatedTicketID,
EventType: enums.TicketEventTypeUpdated,
OperatorType: enums.IMSenderTypeAgent,
OperatorID: operator.UserID,
Content: "新增关联工单",
Payload: strings.TrimSpace(string(inverseType) + ":" + ticket.TicketNo),
CreatedAt: now,
})
})
}
func (s *ticketRelationService) DeleteRelation(ticketID, relationID int64, operator *dto.AuthPrincipal) error {
if operator == nil {
return errorsx.Unauthorized("未登录或登录已过期")
}
relation := s.Get(relationID)
if relation == nil || relation.TicketID != ticketID {
return errorsx.InvalidParam("关联关系不存在")
}
ticket := TicketService.Get(relation.TicketID)
relatedTicket := TicketService.Get(relation.RelatedTicketID)
now := time.Now()
return sqls.WithTransaction(func(ctx *sqls.TxContext) error {
if err := repositories.TicketRelationRepository.DeleteByTicketRelation(ctx.Tx, relation.TicketID, relation.RelatedTicketID, string(relation.RelationType)); err != nil {
return err
}
if err := repositories.TicketRelationRepository.DeleteByTicketRelation(ctx.Tx, relation.RelatedTicketID, relation.TicketID, string(inverseTicketRelationType(relation.RelationType))); err != nil {
return err
}
if ticket != nil {
if err := repositories.TicketEventLogRepository.Create(ctx.Tx, &models.TicketEventLog{
TicketID: ticket.ID,
EventType: enums.TicketEventTypeUpdated,
OperatorType: enums.IMSenderTypeAgent,
OperatorID: operator.UserID,
Content: "移除关联工单",
Payload: strings.TrimSpace(string(relation.RelationType) + ":" + relationTicketNo(relatedTicket)),
CreatedAt: now,
}); err != nil {
return err
}
}
if relatedTicket != nil {
return repositories.TicketEventLogRepository.Create(ctx.Tx, &models.TicketEventLog{
TicketID: relatedTicket.ID,
EventType: enums.TicketEventTypeUpdated,
OperatorType: enums.IMSenderTypeAgent,
OperatorID: operator.UserID,
Content: "移除关联工单",
Payload: strings.TrimSpace(string(inverseTicketRelationType(relation.RelationType)) + ":" + relationTicketNo(ticket)),
CreatedAt: now,
})
}
return nil
})
}
func isValidTicketRelationType(relationType enums.TicketRelationType) bool {
switch relationType {
case enums.TicketRelationTypeDuplicate, enums.TicketRelationTypeRelated, enums.TicketRelationTypeParent, enums.TicketRelationTypeChild:
return true
default:
return false
}
}
func inverseTicketRelationType(relationType enums.TicketRelationType) enums.TicketRelationType {
switch relationType {
case enums.TicketRelationTypeParent:
return enums.TicketRelationTypeChild
case enums.TicketRelationTypeChild:
return enums.TicketRelationTypeParent
default:
return relationType
}
}
func relationTicketNo(ticket *models.Ticket) string {
if ticket == nil {
return ""
}
return ticket.TicketNo
}