From cda02d6b5cce22b41f5d82a6aa29ba0bd11603da Mon Sep 17 00:00:00 2001 From: zhangsz Date: Mon, 16 Jun 2025 11:28:45 +0800 Subject: [PATCH] feat: new --- database/install/mf_callback_ticket.sql | 10 +++--- database/install/sys_dict_data1_i18n_zh.sql | 14 ++++++-- database/install/sys_dict_data2_i18n_en.sql | 14 ++++++-- database/install/sys_dict_type.sql | 1 + features/cdr/cdrevent.go | 13 +++----- features/ue/mf_callback_ticket/model.go | 11 +++++++ features/ue/mf_callback_ticket/service.go | 32 +++++++++++++------ .../psap_ticket_monitor.go | 32 ++++++++++++++++++- .../network_element/repository/ne_info.go | 1 + 9 files changed, 99 insertions(+), 29 deletions(-) diff --git a/database/install/mf_callback_ticket.sql b/database/install/mf_callback_ticket.sql index 495d28a1..fc4acc79 100755 --- a/database/install/mf_callback_ticket.sql +++ b/database/install/mf_callback_ticket.sql @@ -11,7 +11,7 @@ Target Server Version : 100622 (10.6.22-MariaDB-0ubuntu0.22.04.1) File Encoding : 65001 - Date: 04/06/2025 10:50:08 + Date: 14/06/2025 12:30:47 */ SET NAMES utf8mb4; @@ -25,13 +25,15 @@ CREATE TABLE `mf_callback_ticket` ( `ticket_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Ticket ID', `caller_number` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT 'caller number', `callee_number` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'callee number', - `status` enum('NEW','PENDING','IN_PROGRESS','FAILED','COMPLETED','TIMEOUT','RECREATED') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'NEW', + `status` enum('NEW','IN_PROGRESS','NO_ANSWER_1','NO_ANSWER_2','TIMEOUT','PENDING','CLOSED') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'NEW' COMMENT '1:NEW/新建,2:IN_PROGRESS/处理中,3:NO_ANSWER_1/未应答1,3:NO_ANSWER_2/未应答2,4:TIMEOUT/超时,5:PENDING/挂起,6:CLOSED/关闭', `agent_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT 'agent name', `comment` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT 'comment for callback', `msd_data` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT 'MSD data', `created_at` bigint(20) NULL DEFAULT NULL COMMENT 'created at time', `updated_at` bigint(20) NULL DEFAULT NULL COMMENT 'updated at time', - PRIMARY KEY (`ticket_id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 103 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic; + PRIMARY KEY (`ticket_id`) USING BTREE, + INDEX `idx_caller_agent`(`caller_number`, `agent_name`) USING BTREE, + INDEX `idx_created`(`created_at`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 108 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1; diff --git a/database/install/sys_dict_data1_i18n_zh.sql b/database/install/sys_dict_data1_i18n_zh.sql index becaf507..43cb4229 100644 --- a/database/install/sys_dict_data1_i18n_zh.sql +++ b/database/install/sys_dict_data1_i18n_zh.sql @@ -712,8 +712,16 @@ INSERT INTO `sys_dict_data` VALUES (2201, 2201, 'table.u_auth_user', 'UDM鉴权 INSERT INTO `sys_dict_data` VALUES (2202, 2202, 'table.u_sub_user', 'UDM签约用户', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (2203, 2203, 'table.u_voip_auth', 'VoIP鉴权数据', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (2204, 2204, 'table.u_ims_user', 'IMS签约用户', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -INSERT INTO `sys_dict_data` VALUES (2300, 2300, 'menu.psap.agent', '座席', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -INSERT INTO `sys_dict_data` VALUES (2301, 2301, 'menu.psap.agent.callings', '并行话务', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -INSERT INTO `sys_dict_data` VALUES (2302, 2302, 'menu.psap.agent.callback', '回拨管理', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); + +INSERT INTO `sys_dict_data` VALUES (20000, 20000, 'menu.psap.agent', '座席', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (20001, 20000, 'menu.psap.agent.callings', '并行话务', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (20002, 20000, 'menu.psap.agent.callback', '回拨管理', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (20003, 1, 'callback.status.NEW', '新建', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784015598, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (20004, 2, 'callback.status.IN_PROGRESS', '处理中', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784045911, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (20005, 3, 'callback.status.NO_ANSWER_1', '未应答1', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784070706, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (20006, 4, 'callback.status.NO_ANSWER_2', '未应答2', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784078301, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (20007, 5, 'callback.status.TIMEOUT', '超时', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784100809, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (20008, 6, 'callback.status.PENDING', '挂起', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784115379, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (20009, 7, 'callback.status.CLOSED', '关闭', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784127612, '', 0, NULL); SET FOREIGN_KEY_CHECKS = 1; diff --git a/database/install/sys_dict_data2_i18n_en.sql b/database/install/sys_dict_data2_i18n_en.sql index 6b9bb5dd..9a09b4a5 100644 --- a/database/install/sys_dict_data2_i18n_en.sql +++ b/database/install/sys_dict_data2_i18n_en.sql @@ -712,8 +712,16 @@ INSERT INTO `sys_dict_data` VALUES (4201, 4201, 'table.u_auth_user', 'UDM Authen INSERT INTO `sys_dict_data` VALUES (4202, 4202, 'table.u_sub_user', 'UDM Subscribers', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (4203, 4203, 'table.u_voip_auth', 'VoIP Authentication', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (4204, 4204, 'table.u_ims_user', 'IMS Subscribers', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -INSERT INTO `sys_dict_data` VALUES (4300, 4300, 'menu.psap.agent', 'Agent', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -INSERT INTO `sys_dict_data` VALUES (4301, 4301, 'menu.psap.agent.callings', 'Calling Info', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -INSERT INTO `sys_dict_data` VALUES (4302, 4302, 'menu.psap.agent.callback', 'CallBack Management', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); + +INSERT INTO `sys_dict_data` VALUES (25000, 25000, 'menu.psap.agent', 'Agent', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (25001, 25000, 'menu.psap.agent.callings', 'Calling Info', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (25002, 25000, 'menu.psap.agent.callback', 'CallBack Management', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (25003, 1, 'callback.status.NEW', 'NEW', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784015598, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (25004, 2, 'callback.status.IN_PROGRESS', 'IN_PROGRESS', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784045911, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (25005, 3, 'callback.status.NO_ANSWER_1', 'NO_ANSWER_1', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784070706, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (25006, 4, 'callback.status.NO_ANSWER_2', 'NO_ANSWER_2', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784078301, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (25007, 5, 'callback.status.TIMEOUT', 'TIMEOUT', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784100809, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (25008, 6, 'callback.status.PENDING', 'PENDING', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784115379, '', 0, NULL); +INSERT INTO `sys_dict_data` VALUES (25009, 7, 'callback.status.CLOSED', 'CLOSED', 'callback_status', NULL, NULL, '1', 'supervisor', 1749784127612, '', 0, NULL); SET FOREIGN_KEY_CHECKS = 1; diff --git a/database/install/sys_dict_type.sql b/database/install/sys_dict_type.sql index bd46756b..3df6090c 100644 --- a/database/install/sys_dict_type.sql +++ b/database/install/sys_dict_type.sql @@ -56,6 +56,7 @@ INSERT INTO `sys_dict_type` VALUES (121, 'dictType.ne_host_cmd_groupId', 'ne_hos INSERT INTO `sys_dict_type` VALUES (122, 'dictType.ne_info_status', 'ne_info_status', '1', 'supervisor', 1702020000000, '', 0, ''); INSERT INTO `sys_dict_type` VALUES (123, 'dictType.ne_license_status', 'ne_license_status', '1', 'supervisor', 1702020000000, '', 0, ''); INSERT INTO `sys_dict_type` VALUES (124, 'dictType.cdr_cause_code', 'cdr_cause_code', '1', 'supervisor', 1725877564156, '', 0, ''); +INSERT INTO `sys_dict_type` VALUES (20000, 'dictType.callback_status', 'callback_status', '1', 'supervisor', 1749783964967, '', 0, NULL); UNLOCK TABLES; diff --git a/features/cdr/cdrevent.go b/features/cdr/cdrevent.go index cf223bc0..a6a58dd5 100644 --- a/features/cdr/cdrevent.go +++ b/features/cdr/cdrevent.go @@ -93,15 +93,9 @@ func PostCDREventFrom(w http.ResponseWriter, r *http.Request) { // 解析座席列表响应 var agentResp struct { - Code int `json:"code"` - Data []struct { - Domain string `json:"domain"` - Index int `json:"index"` - Name string `json:"name"` - Online bool `json:"online"` - Password string `json:"password"` - } `json:"data"` - Msg string `json:"msg"` + Code int `json:"code"` + Data []ueCallBackTicket.AgentInfo `json:"data"` + Msg string `json:"msg"` } if err := json.NewDecoder(resp.Body).Decode(&agentResp); err != nil { @@ -130,6 +124,7 @@ func PostCDREventFrom(w http.ResponseWriter, r *http.Request) { AgentName: selectedAgent, Comment: "", MsdData: cdrEvent.CDR["msdData"].(string), + RmUid: cdrEvent.RmUID, CreatedAt: time.Now().UnixMicro(), UpdatedAt: updatedAt, } diff --git a/features/ue/mf_callback_ticket/model.go b/features/ue/mf_callback_ticket/model.go index da4beb04..0d28fee1 100644 --- a/features/ue/mf_callback_ticket/model.go +++ b/features/ue/mf_callback_ticket/model.go @@ -105,10 +105,21 @@ type CallbackTicket struct { AgentName string `json:"agentName" gorm:"column:agent_name"` // 坐席名称 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 { + Index int `json:"index"` + Name string `json:"name"` + Online bool `json:"online"` + Email string `json:"email"` + Mobile string `json:"mobile"` + Domain string `json:"domain"` + Password string `json:"password"` +} + // TableName 表名称 func (*CallbackTicket) TableName() string { return "mf_callback_ticket" diff --git a/features/ue/mf_callback_ticket/service.go b/features/ue/mf_callback_ticket/service.go index 4efc7a09..013938a3 100644 --- a/features/ue/mf_callback_ticket/service.go +++ b/features/ue/mf_callback_ticket/service.go @@ -180,13 +180,7 @@ func (s *CallbackTicketService) GetLastAssignedAgent() (string, error) { // @param agents 座席列表 // @param lastAgentName 上一个座席名称 // @return string 下一个座席名称 -func (s *CallbackTicketService) SelectNextAgent(agents []struct { - Domain string `json:"domain"` - Index int `json:"index"` - Name string `json:"name"` - Online bool `json:"online"` - Password string `json:"password"` -}, lastAgentName string) string { +func (s *CallbackTicketService) SelectNextAgent(agents []AgentInfo, lastAgentName string) string { if len(agents) == 0 { return "" } @@ -330,24 +324,44 @@ func (s *CallbackTicketService) FindTimeoutTickets(status string, timeoutMicros // @param ticket 要更新的工单 // @param originalStatus 原工单状态 // @return error 错误信息 -func (s *CallbackTicketService) UpdateTicketToTimeout(ticket *CallbackTicket, originalStatus string) error { +func (s *CallbackTicketService) UpdateTicketToTimeout(ticket *CallbackTicket, originalStatus string, agents []AgentInfo) error { if ticket == nil { return fmt.Errorf("ticket cannot be nil") } now := time.Now().UnixMicro() + // 1. 更新原工单为超时 updatedTicket := CallbackTicket{ TicketId: ticket.TicketId, Status: TicketStatusTimeout.Enum(), Comment: fmt.Sprintf("%s - 工单状态为 %s 处理超时,系统自动更新为超时状态", ticket.Comment, originalStatus), UpdatedAt: &now, } - if err := s.db.Table("mf_callback_ticket"). Where("ticket_id = ?", ticket.TicketId). Updates(updatedTicket).Error; err != nil { return fmt.Errorf("更新工单 %d 状态失败: %w", ticket.TicketId, err) } + // 2. 选择新座席 + lastAgent := ticket.AgentName + newAgent := s.SelectNextAgent(agents, lastAgent) + + // 3. 创建新工单 + newTicket := CallbackTicket{ + CallerNumber: ticket.CallerNumber, + CalleeNumber: ticket.CalleeNumber, + Status: TicketStatusNew.Enum(), + AgentName: newAgent, + Comment: fmt.Sprintf("由超时工单 %d 自动重建", ticket.TicketId), + MsdData: ticket.MsdData, + RmUid: ticket.RmUid, + CreatedAt: now, + UpdatedAt: nil, + } + if err := s.db.Table("mf_callback_ticket").Create(&newTicket).Error; err != nil { + return fmt.Errorf("创建新工单失败: %w", err) + } + return nil } diff --git a/src/modules/crontask/processor/psap_ticket_monitor/psap_ticket_monitor.go b/src/modules/crontask/processor/psap_ticket_monitor/psap_ticket_monitor.go index c48cfe71..5b351581 100644 --- a/src/modules/crontask/processor/psap_ticket_monitor/psap_ticket_monitor.go +++ b/src/modules/crontask/processor/psap_ticket_monitor/psap_ticket_monitor.go @@ -1,10 +1,15 @@ package psap_ticket_monitor import ( + "encoding/json" + "fmt" + "net/http" + ueCallBackTicket "be.ems/features/ue/mf_callback_ticket" "be.ems/lib/log" "be.ems/src/framework/cron" "be.ems/src/framework/logger" + neService "be.ems/src/modules/network_element/service" ) var NewProcessor = &PsapTicketMonitor{ @@ -92,7 +97,32 @@ func (s *PsapTicketMonitor) handleTimeoutTickets(status string, timeoutMicros in // 更新超时工单状态 var updatedCount int for _, ticket := range tickets { - if err := s.callbackTicketService.UpdateTicketToTimeout(&ticket, status); err != nil { + // 获取网元信息 + neInfo := neService.NewNeInfo.SelectNeInfoByRmuid(ticket.RmUid) + // 构造网元MF的API地址 + url := fmt.Sprintf("http://%s:%d/ne/config/data?neType=%s&neId=%s¶mName=agents", + neInfo.IP, neInfo.Port, neInfo.NeType, neInfo.NeId) + // 发送HTTP请求获取座席列表 + resp, err := http.Get(url) + if err != nil { + log.Error("Failed to get MF agents", err) + continue + } + 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 } diff --git a/src/modules/network_element/repository/ne_info.go b/src/modules/network_element/repository/ne_info.go index fac0d92e..23ea4edb 100644 --- a/src/modules/network_element/repository/ne_info.go +++ b/src/modules/network_element/repository/ne_info.go @@ -19,6 +19,7 @@ func (r NeInfo) neListSort(arr []model.NeInfo) []model.NeInfo { // neListSort 网元列表预设排序 var list = []string{ "OMC", + "CBC", "MF", }