feat: support mf ticket management

This commit is contained in:
zhangsz
2025-07-01 16:48:51 +08:00
parent 4c2200b39b
commit fe7e4d9c88
5 changed files with 258 additions and 108 deletions

View File

@@ -11,6 +11,7 @@ import (
processorMonitorSysResource "be.ems/src/modules/crontask/processor/monitor_sys_resource"
processorNeConfigBackup "be.ems/src/modules/crontask/processor/ne_config_backup"
processorNeDataUDM "be.ems/src/modules/crontask/processor/ne_data_udm"
"be.ems/src/modules/crontask/processor/psap_ticket_monitor"
"be.ems/src/modules/crontask/processor/removeFile"
)
@@ -30,4 +31,5 @@ func InitCronQueue() {
cron.CreateQueue("genNeStateAlarm", genNeStateAlarm.NewProcessor)
cron.CreateQueue("exportTable", exportTable.NewProcessor)
cron.CreateQueue("removeFile", removeFile.NewProcessor)
cron.CreateQueue("psap_ticket_monitor", psap_ticket_monitor.NewProcessor)
}

View File

@@ -4,11 +4,12 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"
ueCallBackTicket "be.ems/features/ue/mf_callback_ticket"
"be.ems/lib/email"
"be.ems/lib/log"
"be.ems/src/framework/cron"
"be.ems/src/framework/logger"
neService "be.ems/src/modules/network_element/service"
)
@@ -27,7 +28,7 @@ func (s *PsapTicketMonitor) Execute(data any) (any, error) {
s.count++ // 执行次数加一
options := data.(cron.JobData)
sysJob := options.SysJob
logger.Infof("执行工单监控任务 %v 任务ID %s", options.Repeat, sysJob.JobID)
log.Infof("执行工单监控任务 %v 任务ID %s", options.Repeat, sysJob.JobID)
// 返回结果,用于记录执行结果
result := map[string]any{
@@ -37,10 +38,10 @@ func (s *PsapTicketMonitor) Execute(data any) (any, error) {
// 处理超时的NEW状态工单 (60分钟)
newTicketsUpdated, err := s.handleTimeoutTickets(
ueCallBackTicket.TicketStatusNew.Enum(),
60*1000000, // 60分钟(微秒)
1*60*1000000, // 1分钟(微秒)
)
if err != nil {
logger.Errorf("处理NEW状态超时工单失败: %v", err)
log.Errorf("处理NEW状态超时工单失败: %v", err)
}
result["newTicketsUpdated"] = newTicketsUpdated
@@ -50,7 +51,7 @@ func (s *PsapTicketMonitor) Execute(data any) (any, error) {
60*60*1000000, // 60分钟(微秒)
)
if err != nil {
logger.Errorf("处理IN_PROGRESS状态超时工单失败: %v", err)
log.Errorf("处理IN_PROGRESS状态超时工单失败: %v", err)
}
result["inProgressTicketsUpdated"] = inProgressTicketsUpdated
@@ -60,7 +61,7 @@ func (s *PsapTicketMonitor) Execute(data any) (any, error) {
4*60*60*1000000, // 4小时(微秒)
)
if err != nil {
logger.Errorf("处理NO_ANSWER_1状态超时工单失败: %v", err)
log.Errorf("处理NO_ANSWER_1状态超时工单失败: %v", err)
}
result["noAnswer1TicketsUpdated"] = noAnswer1TicketsUpdated
@@ -70,15 +71,69 @@ func (s *PsapTicketMonitor) Execute(data any) (any, error) {
8*60*60*1000000, // 8小时(微秒)
)
if err != nil {
logger.Errorf("处理NO_ANSWER_2状态超时工单失败: %v", err)
log.Errorf("处理NO_ANSWER_2状态超时工单失败: %v", err)
}
result["noAnswer2TicketsUpdated"] = noAnswer2TicketsUpdated
// 汇总结果
totalUpdated := newTicketsUpdated + inProgressTicketsUpdated + noAnswer1TicketsUpdated + noAnswer2TicketsUpdated
totalUpdated := newTicketsUpdated + inProgressTicketsUpdated +
noAnswer1TicketsUpdated + noAnswer2TicketsUpdated
result["totalUpdated"] = totalUpdated
logger.Infof("工单监控任务完成,共处理 %d 个超时工单", totalUpdated)
log.Infof("工单监控任务完成,共处理 %d 个超时工单", totalUpdated)
// 处理超时的NEW状态工单 (60分钟)
newTicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusNew.Enum(),
60*60*1000000, // 60分钟(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
)
if err != nil {
log.Errorf("处理NEW状态超时工单失败: %v", err)
}
result["newTicketsNearlyTimeout"] = newTicketsNearlyTimeout
// 处理超时的IN_PROGRESS状态工单 (60分钟)
inProgressTicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusInProgress.Enum(),
60*60*1000000, // 60分钟(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
)
if err != nil {
log.Errorf("处理IN_PROGRESS状态超时工单失败: %v", err)
}
result["inProgressTicketsNearlyTimeout"] = inProgressTicketsNearlyTimeout
// 处理超时的NO_ANSWER_1状态工单 (4小时)
noAnswer1TicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusNoAnswer1.Enum(),
4*60*60*1000000, // 4小时(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
)
if err != nil {
log.Errorf("处理NO_ANSWER_1状态超时工单失败: %v", err)
}
result["noAnswer1TicketsNearlyTimeout"] = noAnswer1TicketsNearlyTimeout
// 处理超时的NO_ANSWER_2状态工单 (8小时)
noAnswer2TicketsNearlyTimeout, err := s.handleNearlyTimeoutTickets(
ueCallBackTicket.TicketStatusNoAnswer2.Enum(),
8*60*60*1000000, // 8小时(微秒)
10*60*1000000, // 提前10分钟提醒(微秒)
)
if err != nil {
log.Errorf("处理NO_ANSWER_2状态即将超时工单失败: %v", err)
}
result["noAnswer2TicketsNearlyTimeout"] = noAnswer2TicketsNearlyTimeout
// 汇总结果
totalTicketsNearlyTimeout := newTicketsNearlyTimeout + inProgressTicketsNearlyTimeout +
noAnswer1TicketsNearlyTimeout + noAnswer2TicketsNearlyTimeout
result["totalTicketsNearlyTimeout"] = totalTicketsNearlyTimeout
log.Infof("工单监控任务完成,共处理 %d 个即将超时工单", totalUpdated)
return result, nil
}
@@ -100,8 +155,8 @@ func (s *PsapTicketMonitor) handleTimeoutTickets(status string, timeoutMicros in
// 获取网元信息
neInfo := neService.NewNeInfo.SelectNeInfoByRmuid(ticket.RmUid)
// 构造网元MF的API地址
url := fmt.Sprintf("http://%s:%d/ne/config/data?neType=%s&neId=%s&paramName=agents",
neInfo.IP, neInfo.Port, neInfo.NeType, neInfo.NeId)
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 {
@@ -132,3 +187,65 @@ func (s *PsapTicketMonitor) handleTimeoutTickets(status string, timeoutMicros in
return updatedCount, nil
}
// handleTimeoutTickets 处理指定状态的超时工单
func (s *PsapTicketMonitor) handleNearlyTimeoutTickets(status string, timeoutMicros int64, aheadMicros int64) (int, error) {
// 查询超时的工单
tickets, err := s.callbackTicketService.FindNearlyTimeoutTickets(status, timeoutMicros, aheadMicros)
if err != nil {
return 0, err
}
if len(tickets) == 0 {
return 0, nil // 没有即将超时工单
}
// 更新超时工单状态
var updatedCount int
for _, ticket := range tickets {
if ticket.AgentEmail != "" {
subject := "工单即将超时提醒"
body := fmt.Sprintf("您负责的回拨工单(主叫号码:%s即将超时请及时处理。", ticket.CallerNumber)
go email.SendEmail(ticket.AgentEmail, subject, body)
}
}
return updatedCount, nil
}
func (s *PsapTicketMonitor) GetAgentEmail(ticket ueCallBackTicket.CallbackTicket) string {
// 获取网元信息
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)
return ""
}
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)
return ""
}
// 查找当前工单分配的座席邮箱
agentEmail := ""
for _, agent := range agentResp.Data {
if agent.Name == ticket.AgentName {
agentEmail = agent.Email
break
}
}
return agentEmail
}