feat: ticket enhancemnet
This commit is contained in:
@@ -98,18 +98,18 @@ type CallbackTicketQuery struct {
|
||||
|
||||
// @Description VoLTE用户信息
|
||||
type CallbackTicket struct {
|
||||
TicketId int64 `json:"ticketId" gorm:"column:ticket_id"` // 工单ID
|
||||
CallerNumber string `json:"callerNumber" gorm:"column:caller_number"` // 主叫号码
|
||||
CalleeNumber string `json:"calleeNumber" gorm:"column:callee_number"` // 被叫号码
|
||||
Status string `json:"status" gorm:"column:status"` // 工单状态
|
||||
AgentName string `json:"agentName" gorm:"column:agent_name"` // 座席名称
|
||||
AgentEmail string `json:"agentEmail" gorm:"column:agent_email"` // 座席邮箱
|
||||
AgentMobile string `json:"agentMobile" gorm:"column:agent_mobile"` // 座席手机号码
|
||||
Comment string `json:"comment" gorm:"column:comment"` // 工单备注
|
||||
MsdData string `json:"msdData" gorm:"column:msd_data"` // MSD数据
|
||||
RmUid string `json:"rmUid" gorm:"column:rm_uid"` // RM用户ID
|
||||
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 创建时间
|
||||
UpdatedAt *int64 `json:"updatedAt" gorm:"column:updated_at;autoUpdateTime:false"` // 更新时间
|
||||
TicketId int64 `json:"ticketId" gorm:"column:ticket_id;primaryKey;autoIncrement"` // 工单ID
|
||||
CallerNumber string `json:"callerNumber" gorm:"column:caller_number"` // 主叫号码
|
||||
CalleeNumber string `json:"calleeNumber" gorm:"column:callee_number"` // 被叫号码
|
||||
Status string `json:"status" gorm:"column:status"` // 工单状态
|
||||
AgentName string `json:"agentName" gorm:"column:agent_name"` // 座席名称
|
||||
AgentEmail string `json:"agentEmail" gorm:"column:agent_email"` // 座席邮箱
|
||||
AgentMobile string `json:"agentMobile" gorm:"column:agent_mobile"` // 座席手机号码
|
||||
Comment string `json:"comment" gorm:"column:comment"` // 工单备注
|
||||
MsdData string `json:"msdData" gorm:"column:msd_data"` // MSD数据
|
||||
RmUid string `json:"rmUid" gorm:"column:rm_uid"` // RM用户ID
|
||||
CreatedAt int64 `json:"createdAt" gorm:"column:created_at"` // 创建时间
|
||||
UpdatedAt *int64 `json:"updatedAt" gorm:"column:updated_at;autoUpdateTime:false"` // 更新时间
|
||||
}
|
||||
|
||||
type AgentInfo struct {
|
||||
|
||||
@@ -4,8 +4,10 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"be.ems/lib/config"
|
||||
"be.ems/lib/dborm"
|
||||
"be.ems/lib/email"
|
||||
"be.ems/lib/log"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -97,7 +99,7 @@ func (s *CallbackTicketService) SelectCallbackTicketByPage(pageNum int, pageSize
|
||||
return tickets, int(total), nil
|
||||
}
|
||||
|
||||
func (s *CallbackTicketService) InsertCallbackTicket(ticket CallbackTicket) error {
|
||||
func (s *CallbackTicketService) InsertCallbackTicket(ticket *CallbackTicket) error {
|
||||
// 判断主叫号码是否已存在未处理完的工单
|
||||
var existingCount int64
|
||||
if err := s.getDB().Table("mf_callback_ticket").
|
||||
@@ -110,7 +112,7 @@ func (s *CallbackTicketService) InsertCallbackTicket(ticket CallbackTicket) erro
|
||||
return fmt.Errorf("caller %s already has a pending ticket", ticket.CallerNumber)
|
||||
}
|
||||
// 这里可以使用ORM或其他方式将ticket插入到数据库中
|
||||
if err := s.getDB().Table("mf_callback_ticket").Create(&ticket).Error; err != nil {
|
||||
if err := s.getDB().Table("mf_callback_ticket").Create(ticket).Error; err != nil {
|
||||
return fmt.Errorf("failed to insert callback ticket: %w", err)
|
||||
}
|
||||
return nil
|
||||
@@ -174,7 +176,7 @@ func (s *CallbackTicketService) GetLastAssignedAgent() (string, error) {
|
||||
var lastTicket CallbackTicket
|
||||
if err := s.getDB().Table("mf_callback_ticket").
|
||||
Where("agent_name <> ''").
|
||||
Order("created_at DESC").
|
||||
Order("created_at DESC, ticket_id DESC").
|
||||
First(&lastTicket).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
// 没有记录属于正常情况,返回空字符串
|
||||
@@ -377,14 +379,137 @@ func (s *CallbackTicketService) UpdateTicketToTimeout(ticket *CallbackTicket, or
|
||||
|
||||
// 新工单分配后发送邮件通知
|
||||
if newAgent.Email != "" {
|
||||
subject := "新工单自动重建通知"
|
||||
body := fmt.Sprintf("您被分配了一个自动重建的回拨工单,主叫号码:%s", newTicket.CallerNumber)
|
||||
go email.SendEmail(newAgent.Email, subject, body)
|
||||
// 发送邮件通知
|
||||
// 获取SMTP配置
|
||||
emailConfig := config.GetSMTPConfig()
|
||||
if emailConfig != nil && emailConfig.Enabled {
|
||||
// 创建配置副本,避免修改全局配置
|
||||
emailCopy := *emailConfig // 浅拷贝结构体
|
||||
|
||||
// 合并配置中的To地址和当前工单的座席邮箱
|
||||
var recipients []string
|
||||
|
||||
// 添加配置中的原始收件人(如管理员、监控人员等)
|
||||
if len(emailConfig.To) > 0 {
|
||||
recipients = append(recipients, emailConfig.To...)
|
||||
}
|
||||
|
||||
// 添加当前工单的座席邮箱
|
||||
recipients = append(recipients, ticket.AgentEmail)
|
||||
|
||||
// 去重处理(避免重复邮箱)
|
||||
emailCopy.To = email.RemoveDuplicateEmails(recipients)
|
||||
|
||||
// 设置邮件主题和内容
|
||||
emailCopy.Subject = "新工单自动重建通知"
|
||||
emailCopy.Body = fmt.Sprintf("您被分配了一个自动重建的回拨工单,ID: %d, 主叫号码:%s, 请及时处理。",
|
||||
newTicket.TicketId, newTicket.CallerNumber)
|
||||
go email.SendEmailWithGomail(emailCopy)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchUpdateTimeoutTickets 批量处理超时工单
|
||||
func (s *CallbackTicketService) BatchUpdateTimeoutTickets(tickets []CallbackTicket, originalStatus string, agents []AgentInfo) error {
|
||||
if len(tickets) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取当前最后分配的座席
|
||||
lastAssignedAgent, err := s.GetLastAssignedAgent()
|
||||
if err != nil {
|
||||
log.Errorf("获取最后分配座席失败: %v", err)
|
||||
lastAssignedAgent = ""
|
||||
}
|
||||
|
||||
now := time.Now().UnixMicro()
|
||||
var successCount int
|
||||
for i, ticket := range tickets {
|
||||
// 1. 更新原工单为超时
|
||||
updatedTicket := CallbackTicket{
|
||||
TicketId: ticket.TicketId,
|
||||
Status: TicketStatusTimeout.Enum(),
|
||||
Comment: fmt.Sprintf("%s - 工单状态为 %s 处理超时,系统自动更新为超时状态", ticket.Comment, originalStatus),
|
||||
UpdatedAt: &now,
|
||||
}
|
||||
if err := s.getDB().Table("mf_callback_ticket").
|
||||
Where("ticket_id = ?", ticket.TicketId).
|
||||
Updates(updatedTicket).Error; err != nil {
|
||||
log.Errorf("更新工单 %d 状态失败: %v", ticket.TicketId, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 2. 选择下一个座席(使用批处理中维护的lastAssignedAgent)
|
||||
newAgent := s.SelectNextAgent(agents, lastAssignedAgent)
|
||||
if newAgent == nil {
|
||||
log.Errorf("没有可用的座席分配给工单 %d", ticket.TicketId)
|
||||
continue
|
||||
}
|
||||
|
||||
// 3. 创建新工单
|
||||
newTicket := CallbackTicket{
|
||||
CallerNumber: ticket.CallerNumber,
|
||||
CalleeNumber: ticket.CalleeNumber,
|
||||
Status: TicketStatusNew.Enum(),
|
||||
AgentName: newAgent.Name,
|
||||
AgentEmail: newAgent.Email,
|
||||
AgentMobile: newAgent.Mobile,
|
||||
Comment: fmt.Sprintf("由超时工单 %d 自动重建", ticket.TicketId),
|
||||
MsdData: ticket.MsdData,
|
||||
RmUid: ticket.RmUid,
|
||||
CreatedAt: now + int64(i), // 确保每个工单的创建时间不同,
|
||||
UpdatedAt: nil,
|
||||
}
|
||||
if err := s.getDB().Table("mf_callback_ticket").Create(&newTicket).Error; err != nil {
|
||||
log.Errorf("创建新工单失败: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 4. 更新最后分配的座席
|
||||
lastAssignedAgent = newAgent.Name
|
||||
|
||||
// 5. 发送邮件通知
|
||||
if newAgent.Email != "" {
|
||||
// 发送邮件通知
|
||||
// 获取SMTP配置
|
||||
emailConfig := config.GetSMTPConfig()
|
||||
if emailConfig != nil && emailConfig.Enabled {
|
||||
// 创建配置副本,避免修改全局配置
|
||||
emailCopy := *emailConfig // 浅拷贝结构体
|
||||
|
||||
// 合并配置中的To地址和当前工单的座席邮箱
|
||||
var recipients []string
|
||||
|
||||
// 添加配置中的原始收件人(如管理员、监控人员等)
|
||||
if len(emailConfig.To) > 0 {
|
||||
recipients = append(recipients, emailConfig.To...)
|
||||
}
|
||||
|
||||
// 添加当前工单的座席邮箱
|
||||
recipients = append(recipients, ticket.AgentEmail)
|
||||
|
||||
// 去重处理(避免重复邮箱)
|
||||
emailCopy.To = email.RemoveDuplicateEmails(recipients)
|
||||
|
||||
// 设置邮件主题和内容
|
||||
emailCopy.Subject = "新工单自动重建通知"
|
||||
emailCopy.Body = fmt.Sprintf("您被分配了一个自动重建的回拨工单,ID: %d, 主叫号码:%s, 请及时处理。",
|
||||
newTicket.TicketId, newTicket.CallerNumber)
|
||||
go email.SendEmailWithGomail(emailCopy)
|
||||
}
|
||||
}
|
||||
|
||||
successCount++
|
||||
log.Infof("工单 %d 已重建为新工单 %d,分配给座席 %s (第%d个处理)",
|
||||
ticket.TicketId, newTicket.TicketId, newAgent.Name, i+1)
|
||||
}
|
||||
|
||||
log.Infof("批量处理完成,成功处理 %d/%d 个超时工单", successCount, len(tickets))
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindNearlyTimeoutTickets 查询即将超时的工单
|
||||
func (s *CallbackTicketService) FindNearlyTimeoutTickets(status string, timeoutMicros int64, aheadMicros int64) ([]CallbackTicket, error) {
|
||||
nowMicros := time.Now().UnixMicro()
|
||||
|
||||
Reference in New Issue
Block a user