feat: ticket enhancemnet

This commit is contained in:
zhangsz
2025-07-02 17:22:35 +08:00
parent 24ed4e874a
commit 758276ecfc
11 changed files with 577 additions and 108 deletions

View File

@@ -7,6 +7,7 @@ import (
"strings"
ueCallBackTicket "be.ems/features/ue/mf_callback_ticket"
"be.ems/lib/config"
"be.ems/lib/email"
"be.ems/lib/log"
"be.ems/src/framework/cron"
@@ -35,40 +36,40 @@ func (s *PsapTicketMonitor) Execute(data any) (any, error) {
"count": s.count,
}
// 处理超时的NEW状态工单 (60分钟)
// 处理超时的NEW状态工单
newTicketsUpdated, err := s.handleTimeoutTickets(
ueCallBackTicket.TicketStatusNew.Enum(),
1*60*1000000, // 1分钟(微秒)
config.GetNewTicketTimeoutMicros(),
)
if err != nil {
log.Errorf("处理NEW状态超时工单失败: %v", err)
}
result["newTicketsUpdated"] = newTicketsUpdated
// 处理超时的IN_PROGRESS状态工单 (60分钟)
// 处理超时的IN_PROGRESS状态工单
inProgressTicketsUpdated, err := s.handleTimeoutTickets(
ueCallBackTicket.TicketStatusInProgress.Enum(),
60*60*1000000, // 60分钟(微秒)
config.GetInProgressTicketTimeoutMicros(),
)
if err != nil {
log.Errorf("处理IN_PROGRESS状态超时工单失败: %v", err)
}
result["inProgressTicketsUpdated"] = inProgressTicketsUpdated
// 处理超时的NO_ANSWER_1状态工单 (4小时)
// 处理超时的NO_ANSWER_1状态工单
noAnswer1TicketsUpdated, err := s.handleTimeoutTickets(
ueCallBackTicket.TicketStatusNoAnswer1.Enum(),
4*60*60*1000000, // 4小时(微秒)
config.GetNoAnswer1TicketTimeoutMicros(),
)
if err != nil {
log.Errorf("处理NO_ANSWER_1状态超时工单失败: %v", err)
}
result["noAnswer1TicketsUpdated"] = noAnswer1TicketsUpdated
// 处理超时的NO_ANSWER_2状态工单 (8小时)
// 处理超时的NO_ANSWER_2状态工单
noAnswer2TicketsUpdated, err := s.handleTimeoutTickets(
ueCallBackTicket.TicketStatusNoAnswer2.Enum(),
8*60*60*1000000, // 8小时(微秒)
config.GetNoAnswer2TicketTimeoutMicros(),
)
if err != nil {
log.Errorf("处理NO_ANSWER_2状态超时工单失败: %v", err)
@@ -82,44 +83,44 @@ func (s *PsapTicketMonitor) Execute(data any) (any, error) {
log.Infof("工单监控任务完成,共处理 %d 个超时工单", totalUpdated)
// 处理超时的NEW状态工单 (60分钟)
// 处理超时的NEW状态工单
newTicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusNew.Enum(),
60*60*1000000, // 60分钟(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
config.GetNewTicketTimeoutMicros(),
config.GetNearlyTimeoutMicros(),
)
if err != nil {
log.Errorf("处理NEW状态超时工单失败: %v", err)
}
result["newTicketsNearlyTimeout"] = newTicketsNearlyTimeout
// 处理超时的IN_PROGRESS状态工单 (60分钟)
// 处理超时的IN_PROGRESS状态工单
inProgressTicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusInProgress.Enum(),
60*60*1000000, // 60分钟(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
config.GetInProgressTicketTimeoutMicros(),
config.GetNearlyTimeoutMicros(),
)
if err != nil {
log.Errorf("处理IN_PROGRESS状态超时工单失败: %v", err)
}
result["inProgressTicketsNearlyTimeout"] = inProgressTicketsNearlyTimeout
// 处理超时的NO_ANSWER_1状态工单 (4小时)
// 处理超时的NO_ANSWER_1状态工单
noAnswer1TicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusNoAnswer1.Enum(),
4*60*60*1000000, // 4小时(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
config.GetNoAnswer1TicketTimeoutMicros(),
config.GetNearlyTimeoutMicros(),
)
if err != nil {
log.Errorf("处理NO_ANSWER_1状态超时工单失败: %v", err)
}
result["noAnswer1TicketsNearlyTimeout"] = noAnswer1TicketsNearlyTimeout
// 处理超时的NO_ANSWER_2状态工单 (8小时)
// 处理超时的NO_ANSWER_2状态工单
noAnswer2TicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusNoAnswer2.Enum(),
8*60*60*1000000, // 8小时(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
config.GetNoAnswer2TicketTimeoutMicros(),
config.GetNearlyTimeoutMicros(),
)
if err != nil {
log.Errorf("处理NO_ANSWER_2状态即将超时工单失败: %v", err)
@@ -149,43 +150,37 @@ func (s *PsapTicketMonitor) handleTimeoutTickets(status string, timeoutMicros in
return 0, nil // 没有超时工单
}
// 更新超时工单状态
var updatedCount int
for _, ticket := range tickets {
// 获取网元信息
neInfo := neService.NewNeInfo.SelectNeInfoByRmuid(ticket.RmUid)
// 构造网元MF的API地址
url := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/agents",
neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType))
// 发送HTTP请求获取座席列表
resp, err := http.Get(url)
if err != nil {
log.Error("Failed to get MF agents", err)
continue
}
defer resp.Body.Close()
// 获取网元信息
neInfo := neService.NewNeInfo.SelectNeInfoByRmuid(tickets[0].RmUid)
// 构造网元MF的API地址
url := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/agents",
neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType))
// 发送HTTP请求获取座席列表
resp, err := http.Get(url)
if err != nil {
log.Error("Failed to get MF agents", err)
return 0, err
}
defer resp.Body.Close()
// 解析座席列表响应
var agentResp struct {
Code int `json:"code"`
Data []ueCallBackTicket.AgentInfo `json:"data"`
Msg string `json:"msg"`
}
if err := json.NewDecoder(resp.Body).Decode(&agentResp); err != nil {
log.Error("Failed to decode MF agents response", err)
continue
}
if err := s.callbackTicketService.UpdateTicketToTimeout(&ticket, status, agentResp.Data); err != nil {
log.Errorf("更新工单 %d 状态失败: %v", ticket.TicketId, err)
continue
}
updatedCount++
log.Infof("工单 %d 已更新为超时状态 (原状态: %s)", ticket.TicketId, status)
// 解析座席列表响应
var agentResp struct {
Code int `json:"code"`
Data []ueCallBackTicket.AgentInfo `json:"data"`
Msg string `json:"msg"`
}
return updatedCount, nil
if err := json.NewDecoder(resp.Body).Decode(&agentResp); err != nil {
log.Error("Failed to decode MF agents response", err)
return 0, err
}
if err := s.callbackTicketService.BatchUpdateTimeoutTickets(tickets, status, agentResp.Data); err != nil {
log.Errorf("Faild to batch update tickets: %v", err)
return 0, err
}
return len(tickets), nil
}
// handleTimeoutTickets 处理指定状态的超时工单
@@ -204,10 +199,33 @@ func (s *PsapTicketMonitor) handleNearlyTimeoutTickets(status string, timeoutMic
var updatedCount int
for _, ticket := range tickets {
if ticket.AgentEmail != "" {
subject := "工单即将超时提醒"
body := fmt.Sprintf("您负责的回拨工单(主叫号码:%s即将超时请及时处理。", ticket.CallerNumber)
go email.SendEmail(ticket.AgentEmail, subject, body)
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("您负责的回拨工单(编号:%d, 主叫号码:%s即将在(%d分钟)超时,请及时处理。",
ticket.TicketId, ticket.CallerNumber, aheadMicros/1000/1000/60)
go email.SendEmailWithGomail(emailCopy)
}
}
updatedCount++
}
return updatedCount, nil