Compare commits
2 Commits
130f0a5ac7
...
53283b0669
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53283b0669 | ||
|
|
6e9765ceaa |
@@ -11,7 +11,7 @@
|
||||
Target Server Version : 100622 (10.6.22-MariaDB-0ubuntu0.22.04.1)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 02/07/2025 17:49:45
|
||||
Date: 11/07/2025 17:20:50
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
@@ -30,13 +30,14 @@ CREATE TABLE `mf_callback_ticket` (
|
||||
`agent_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`agent_mobile` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`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',
|
||||
`rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'MF Resource UID',
|
||||
`created_at` bigint(20) NULL DEFAULT NULL COMMENT 'created at time',
|
||||
`created_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`updated_at` bigint(20) NULL DEFAULT NULL COMMENT 'updated at time',
|
||||
`updated_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`ticket_id`) USING BTREE,
|
||||
INDEX `idx_caller_agent`(`caller_number`, `agent_name`) USING BTREE,
|
||||
INDEX `idx_created`(`created_at`, `ticket_id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3440 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 94 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
@@ -29,7 +29,6 @@ CREATE TABLE IF NOT EXISTS `mf_callback_ticket` (
|
||||
`agent_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`agent_mobile` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`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',
|
||||
`rm_uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'MF Resource UID',
|
||||
`created_at` bigint(20) NULL DEFAULT NULL COMMENT 'created at time',
|
||||
`updated_at` bigint(20) NULL DEFAULT NULL COMMENT 'updated at time',
|
||||
@@ -46,4 +45,10 @@ ALTER TABLE `mf_callback_ticket` ADD COLUMN IF NOT EXISTS `agent_mobile` varchar
|
||||
|
||||
ALTER TABLE `mf_callback_ticket` ADD INDEX IF NOT EXISTS `idx_created`(`created_at`, `ticket_id`) USING BTREE;
|
||||
|
||||
ALTER TABLE `mf_callback_ticket` DROP COLUMN IF EXISTS `msd_data`;
|
||||
|
||||
ALTER TABLE `mf_callback_ticket`
|
||||
ADD COLUMN IF NOT EXISTS `created_by` varchar(32) NULL AFTER `created_at`,
|
||||
ADD COLUMN IF NOT EXISTS `updated_by` varchar(32) NULL AFTER `updated_at`;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
@@ -127,7 +127,6 @@ func PostCDREventFrom(w http.ResponseWriter, r *http.Request) {
|
||||
AgentEmail: selectedAgent.Email,
|
||||
AgentMobile: selectedAgent.Mobile,
|
||||
Comment: "",
|
||||
MsdData: cdrEvent.CDR["msdData"].(string),
|
||||
RmUid: cdrEvent.RmUID,
|
||||
CreatedAt: time.Now().UnixMicro(),
|
||||
UpdatedAt: updatedAt,
|
||||
|
||||
@@ -31,10 +31,14 @@ func Register(r *gin.RouterGroup) {
|
||||
middleware.PreAuthorize(nil),
|
||||
m.Insert,
|
||||
)
|
||||
cbGroup.PUT("/message/:id",
|
||||
cbGroup.PUT("/message/:id/:status",
|
||||
middleware.PreAuthorize(nil),
|
||||
m.UpdateStatus,
|
||||
)
|
||||
cbGroup.PUT("/message/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
m.Update,
|
||||
)
|
||||
cbGroup.DELETE("/message/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
m.Delete,
|
||||
@@ -128,15 +132,28 @@ func (m *CBMessage) Insert(c *gin.Context) {
|
||||
func (m *CBMessage) Update(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
|
||||
// 绑定请求体
|
||||
var msg CBMessage
|
||||
if err := c.ShouldBindJSON(&msg); err != nil {
|
||||
// 获取路径参数
|
||||
messageId := c.Param("id")
|
||||
if messageId == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseInt(messageId, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
// 直接读取body为json.RawMessage
|
||||
body, err := io.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
messageJson := json.RawMessage(body)
|
||||
|
||||
service := NewCBMessageService()
|
||||
if err := service.UpdateCBMessage(msg); err != nil {
|
||||
if err := service.UpdateCBMessage(id, messageJson); err != nil {
|
||||
c.JSON(500, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
@@ -156,7 +173,7 @@ func (m *CBMessage) UpdateStatus(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
|
||||
neId := c.Param("neId")
|
||||
status := c.Query("status")
|
||||
status := c.Param("status")
|
||||
if neId == "" || status == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -175,12 +176,46 @@ func (s *CBMessageService) SelectCBMessageById(id int64) (*CBMessage, error) {
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// mfCBMessageService.UpdateCBMessage(msg)
|
||||
func (s *CBMessageService) UpdateCBMessage(msg CBMessage) error {
|
||||
func (s *CBMessageService) UpdateCBMessage(id int64, messageJson json.RawMessage) error {
|
||||
// 解析messageJson获取eventName
|
||||
var messageData map[string]interface{}
|
||||
if err := json.Unmarshal(messageJson, &messageData); err != nil {
|
||||
return fmt.Errorf("failed to parse message_json: %w", err)
|
||||
}
|
||||
// 提取eventName
|
||||
eventName, ok := messageData["eventName"].(string)
|
||||
if !ok || eventName == "" {
|
||||
return fmt.Errorf("eventName is required in message_json")
|
||||
}
|
||||
|
||||
// 检查是否已存在相同的eventName
|
||||
var msg CBMessage
|
||||
if err := s.db.Table("cb_message").
|
||||
Where("id = ?", msg.Id).
|
||||
Updates(msg).Error; err != nil {
|
||||
Where("id = ? AND JSON_EXTRACT(message_json, '$.eventName') = ?", id, eventName).
|
||||
First(&msg).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return fmt.Errorf("CB message with eventName '%s' not found for ID %d", eventName, id)
|
||||
}
|
||||
return fmt.Errorf("failed to query CB message: %w", err)
|
||||
}
|
||||
|
||||
now := time.Now().UnixMicro()
|
||||
if err := s.db.Table("cb_message").
|
||||
Where("id = ?", id).
|
||||
Updates(map[string]interface{}{
|
||||
"message_json": messageJson,
|
||||
"updated_at": now,
|
||||
}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update CB message: %w", err)
|
||||
}
|
||||
|
||||
// 如果状态是ACTIVE,发送更新请求
|
||||
if msg.Status == CBEventStatusActive {
|
||||
if err := s.sendUpdateRequest(msg); err != nil {
|
||||
return fmt.Errorf("failed to send update request: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -356,53 +391,124 @@ func (s *CBMessageService) handleStatusChange(msg CBMessage, oldStatus, newStatu
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendActivateRequest 发送激活请求 (POST)
|
||||
func (s *CBMessageService) sendActivateRequest(msg CBMessage) error {
|
||||
// 获取CBC网元信息 (这里需要根据你的实际情况获取IP和端口)
|
||||
cbcIP, cbcPort, err := s.getCBCNetworkElement(msg.NeId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get CBC network element info: %w", err)
|
||||
// getCBCNetworkElement 获取CBC网元的IP和端口信息
|
||||
// 这个方法需要根据你的实际网元管理系统来实现
|
||||
func (s *CBMessageService) getCBCNetworkElement(neId string) (string, int64, error) {
|
||||
// 查询网元信息
|
||||
neInfo := neService.NewNeInfo.SelectNeInfoByNeTypeAndNeID("CBC", neId)
|
||||
if neInfo.IP == "" {
|
||||
return "", 0, fmt.Errorf("CBC network element not found for neId: %s", neId)
|
||||
}
|
||||
return neInfo.IP, neInfo.Port, nil
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d/api/v1/cbe/message", cbcIP, cbcPort)
|
||||
// CBCHTTPClient CBC网元HTTP客户端
|
||||
type CBCHTTPClient struct {
|
||||
client *http.Client
|
||||
baseURL string
|
||||
}
|
||||
|
||||
// 直接发送message_json内容
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(msg.MessageJson))
|
||||
// NewCBCHTTPClient 创建CBC HTTP客户端
|
||||
func NewCBCHTTPClient(baseURL string) *CBCHTTPClient {
|
||||
return &CBCHTTPClient{
|
||||
client: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
baseURL: baseURL,
|
||||
}
|
||||
}
|
||||
|
||||
// PostMessage 发送POST请求创建消息
|
||||
func (c *CBCHTTPClient) PostMessage(messageData []byte) error {
|
||||
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
|
||||
return c.sendRequest("POST", url, messageData)
|
||||
}
|
||||
|
||||
// PutMessage 发送PUT请求更新消息
|
||||
func (c *CBCHTTPClient) PutMessage(messageData []byte) error {
|
||||
url := fmt.Sprintf("%s/api/v1/cbe/message", c.baseURL)
|
||||
return c.sendRequest("PUT", url, messageData)
|
||||
}
|
||||
|
||||
// DeleteMessage 发送DELETE请求删除消息
|
||||
func (c *CBCHTTPClient) DeleteMessage(eventName string, deletePayload []byte) error {
|
||||
url := fmt.Sprintf("%s/api/v1/cbe/message/%s", c.baseURL, eventName)
|
||||
return c.sendRequest("DELETE", url, deletePayload)
|
||||
}
|
||||
|
||||
// sendRequest 发送HTTP请求
|
||||
func (c *CBCHTTPClient) sendRequest(method, url string, body []byte) error {
|
||||
req, err := http.NewRequest(method, url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create POST request: %w", err)
|
||||
return fmt.Errorf("failed to create %s request: %w", method, err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send POST request: %w", err)
|
||||
return fmt.Errorf("failed to send %s request: %w", method, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("POST request failed with status: %d", resp.StatusCode)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("%s request failed with status: %d, body: %s",
|
||||
method, resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendDeactivateRequest 发送停用请求 (DELETE)
|
||||
// 在CBMessageService中添加方法
|
||||
func (s *CBMessageService) getCBCHTTPClient(neId string) (*CBCHTTPClient, error) {
|
||||
cbcIP, cbcPort, err := s.getCBCNetworkElement(neId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get CBC network element info: %w", err)
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("http://%s:%d", cbcIP, cbcPort)
|
||||
return NewCBCHTTPClient(baseURL), nil
|
||||
}
|
||||
|
||||
// 重构后的激活请求
|
||||
func (s *CBMessageService) sendActivateRequest(msg CBMessage) error {
|
||||
client, err := s.getCBCHTTPClient(msg.NeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.PostMessage(msg.MessageJson)
|
||||
}
|
||||
|
||||
// 重构后的更新请求
|
||||
func (s *CBMessageService) sendUpdateRequest(msg CBMessage) error {
|
||||
client, err := s.getCBCHTTPClient(msg.NeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.PutMessage(msg.MessageJson)
|
||||
}
|
||||
|
||||
// 重构后的停用请求
|
||||
func (s *CBMessageService) sendDeactivateRequest(msg CBMessage) error {
|
||||
// 解析message_json获取需要的字段
|
||||
client, err := s.getCBCHTTPClient(msg.NeId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析和构造删除载荷的逻辑保持不变
|
||||
var messageData map[string]interface{}
|
||||
if err := json.Unmarshal(msg.MessageJson, &messageData); err != nil {
|
||||
return fmt.Errorf("failed to parse message_json: %w", err)
|
||||
}
|
||||
|
||||
// 提取eventName (从messageJson中获取,如果没有eventName字段,可能需要从其他地方获取)
|
||||
eventName, ok := messageData["eventName"].(string)
|
||||
if !ok || eventName == "" {
|
||||
return fmt.Errorf("eventName not found in message_json")
|
||||
}
|
||||
|
||||
// 构造删除请求的payload,只包含messageIdProfile和warningAreaList
|
||||
deletePayload := make(map[string]interface{})
|
||||
if messageIdProfile, exists := messageData["messageIdProfile"]; exists {
|
||||
deletePayload["messageIdProfile"] = messageIdProfile
|
||||
@@ -416,42 +522,5 @@ func (s *CBMessageService) sendDeactivateRequest(msg CBMessage) error {
|
||||
return fmt.Errorf("failed to marshal delete payload: %w", err)
|
||||
}
|
||||
|
||||
// 获取CBC网元信息
|
||||
cbcIP, cbcPort, err := s.getCBCNetworkElement(msg.NeId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get CBC network element info: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d/api/v1/cbe/message/%s", cbcIP, cbcPort, eventName)
|
||||
|
||||
req, err := http.NewRequest("DELETE", url, bytes.NewReader(payloadBytes))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create DELETE request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send DELETE request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("DELETE request failed with status: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getCBCNetworkElement 获取CBC网元的IP和端口信息
|
||||
// 这个方法需要根据你的实际网元管理系统来实现
|
||||
func (s *CBMessageService) getCBCNetworkElement(neId string) (string, int64, error) {
|
||||
// 查询网元信息
|
||||
neInfo := neService.NewNeInfo.SelectNeInfoByNeTypeAndNeID("CBC", neId)
|
||||
if neInfo.IP == "" {
|
||||
return "", 0, fmt.Errorf("CBC network element not found for neId: %s", neId)
|
||||
}
|
||||
return neInfo.IP, neInfo.Port, nil
|
||||
return client.DeleteMessage(eventName, payloadBytes)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ func Register(r *gin.RouterGroup) {
|
||||
middleware.PreAuthorize(nil),
|
||||
m.Update,
|
||||
)
|
||||
mfCallingGroup.PATCH("/:ticketId/status",
|
||||
middleware.PreAuthorize(nil),
|
||||
m.StartProcessingTicket,
|
||||
)
|
||||
mfCallingGroup.DELETE("/:ticketId",
|
||||
middleware.PreAuthorize(nil),
|
||||
m.Delete,
|
||||
@@ -94,6 +98,69 @@ func (m *CallbackTicket) Update(c *gin.Context) {
|
||||
c.JSON(200, result.Ok(nil))
|
||||
}
|
||||
|
||||
func (m *CallbackTicket) UpdateTicketStatus(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
username := ctx.LoginUserToUserName(c)
|
||||
|
||||
// 获取路径参数
|
||||
ticketId := c.Param("ticketId")
|
||||
if ticketId == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseInt(ticketId, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 绑定请求体
|
||||
var statusUpdate struct {
|
||||
Status string `json:"status" binding:"required"`
|
||||
UpdatedBy string `json:"updatedBy"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&statusUpdate); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
statusUpdate.UpdatedBy = username
|
||||
|
||||
service := NewCallbackTicketService()
|
||||
if err := service.UpdateCallbackTicketStatus(id, statusUpdate.Status, statusUpdate.UpdatedBy); err != nil {
|
||||
c.JSON(500, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, result.Ok(nil))
|
||||
}
|
||||
|
||||
func (m *CallbackTicket) StartProcessingTicket(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
username := ctx.LoginUserToUserName(c)
|
||||
|
||||
// 获取路径参数
|
||||
ticketId := c.Param("ticketId")
|
||||
if ticketId == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseInt(ticketId, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
service := NewCallbackTicketService()
|
||||
if err := service.StartProcessingTicket(id, username); err != nil {
|
||||
c.JSON(500, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, result.Ok(nil))
|
||||
}
|
||||
|
||||
// Delete 删除回调工单
|
||||
func (m *CallbackTicket) Delete(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
|
||||
@@ -106,7 +106,6 @@ type CallbackTicket struct {
|
||||
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"` // 更新时间
|
||||
|
||||
@@ -16,6 +16,15 @@ type CallbackTicketService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func contains(slice []string, item string) bool {
|
||||
for _, s := range slice {
|
||||
if s == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 构造函数改为私有初始化方法
|
||||
func NewCallbackTicketService() *CallbackTicketService {
|
||||
return &CallbackTicketService{db: nil} // 先不初始化数据库连接
|
||||
@@ -154,6 +163,48 @@ func (s *CallbackTicketService) UpdateCallbackTicket(ticket CallbackTicket) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CallbackTicketService) UpdateCallbackTicketStatus(ticketId int64, status string, updatedBy string) error {
|
||||
if status == "" {
|
||||
return fmt.Errorf("status cannot be empty")
|
||||
}
|
||||
|
||||
// 检查状态是否合法
|
||||
validStatuses := []string{"IN_PROGRESS", "PENDING", "CLOSED"}
|
||||
if !contains(validStatuses, status) {
|
||||
return fmt.Errorf("invalid status: %s", status)
|
||||
}
|
||||
|
||||
// 获取工单当前状态
|
||||
var currentTicket CallbackTicket
|
||||
if err := s.getDB().Table("mf_callback_ticket").
|
||||
Where("ticket_id = ?", ticketId).
|
||||
First(¤tTicket).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return fmt.Errorf("callback ticket with ID %d not found", ticketId)
|
||||
}
|
||||
return fmt.Errorf("failed to find callback ticket: %w", err)
|
||||
}
|
||||
|
||||
// 如果状态没有变化,则不更新
|
||||
if currentTicket.Status == status || currentTicket.Status == "CLOSED" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新工单状态
|
||||
now := time.Now().UnixMicro()
|
||||
if err := s.getDB().Table("mf_callback_ticket").
|
||||
Where("ticket_id = ?", ticketId).
|
||||
Updates(map[string]interface{}{
|
||||
"status": status,
|
||||
"comment": fmt.Sprintf("工单状态从 %s 更新为 %s", currentTicket.Status, status),
|
||||
"updated_at": &now,
|
||||
"updated_by": updatedBy,
|
||||
}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update callback ticket status: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteCallbackTicket 删除回调工单
|
||||
// @Description 删除回调工单
|
||||
// @param ticketId 工单ID
|
||||
@@ -369,7 +420,6 @@ func (s *CallbackTicketService) UpdateTicketToTimeout(ticket *CallbackTicket, or
|
||||
AgentEmail: newAgent.Email,
|
||||
AgentMobile: newAgent.Mobile,
|
||||
Comment: fmt.Sprintf("由超时工单 %d 自动重建", ticket.TicketId),
|
||||
MsdData: ticket.MsdData,
|
||||
RmUid: ticket.RmUid,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: nil,
|
||||
@@ -458,7 +508,6 @@ func (s *CallbackTicketService) BatchUpdateTimeoutTickets(tickets []CallbackTick
|
||||
AgentEmail: newAgent.Email,
|
||||
AgentMobile: newAgent.Mobile,
|
||||
Comment: fmt.Sprintf("由超时工单 %d 自动重建", ticket.TicketId),
|
||||
MsdData: ticket.MsdData,
|
||||
RmUid: ticket.RmUid,
|
||||
CreatedAt: now + int64(i), // 确保每个工单的创建时间不同,
|
||||
UpdatedAt: nil,
|
||||
@@ -527,15 +576,34 @@ func (s *CallbackTicketService) FindNearlyTimeoutTickets(status string, timeoutM
|
||||
return tickets, nil
|
||||
}
|
||||
|
||||
// 新增方法:坐席开始处理工单
|
||||
func (s *CallbackTicketService) StartProcessingTicket(ticketId int64) error {
|
||||
// 新增方法:座席开始处理工单
|
||||
// StartProcessingTicket 将工单状态更新为正在处理,并记录开始处理的时间和座席信息
|
||||
// @Description 座席开始处理工单
|
||||
// @param ticketId 工单ID
|
||||
// @param updatedBy 更新人
|
||||
// @return error 错误信息
|
||||
// @example
|
||||
// mfCallbackTicketService.StartProcessingTicket(12345, "agent1")
|
||||
// @note 该方法会将工单状态从 NEW 更新为 IN_PROGRESS,并记录处理开始时间和座席信息
|
||||
// @note 如果工单状态不是 NEW,则返回错误
|
||||
// @note 该方法通常在座席开始处理工单时调用
|
||||
// @note 该方法会更新工单的 updated_at 和 updated_by 字段
|
||||
// @note 如果更新失败,则返回错误信息
|
||||
// @note 该方法会记录处理开始的时间戳,单位为微秒
|
||||
// @note 如果工单不存在或状态不正确,则返回错误信息
|
||||
// @note 该方法会在更新成功后返回 nil,表示操作成功
|
||||
// @note 该方法适用于座席开始处理工单的场景
|
||||
// @note 该方法会在更新成功后返回 nil,表示操作成功
|
||||
// @note 该方法会在更新失败时返回错误信息,便于调用方处理异常情况
|
||||
func (s *CallbackTicketService) StartProcessingTicket(ticketId int64, updatedBy string) error {
|
||||
now := time.Now().UnixMicro()
|
||||
if err := s.getDB().Table("mf_callback_ticket").
|
||||
Where("ticket_id = ? AND status = ?", ticketId, TicketStatusNew.Enum()).
|
||||
Updates(map[string]interface{}{
|
||||
"status": TicketStatusInProgress.Enum(),
|
||||
"comment": "座席开始处理工单",
|
||||
"updated_at": now,
|
||||
"comment": "坐席开始处理工单",
|
||||
"updated_by": updatedBy,
|
||||
}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update ticket to IN_PROGRESS: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user