diff --git a/controller/offline_message.go b/controller/offline_message.go index 674cf3c..e4a87da 100644 --- a/controller/offline_message.go +++ b/controller/offline_message.go @@ -6,7 +6,6 @@ import ( "github.com/gin-gonic/gin" "goflylivechat/models" "goflylivechat/tools" - "goflylivechat/ws" "log" "strconv" "time" @@ -420,44 +419,6 @@ func BatchMarkOfflineMessagesAsRead(c *gin.Context) { }) } -func CheckKefuOnline(c *gin.Context) { - kefuId := c.Query("kefu_id") - if kefuId == "" { - c.JSON(200, gin.H{ - "code": 400, - "msg": "客服ID不能为空", - }) - return - } - - kefuInfo := models.FindUser(kefuId) - if kefuInfo.ID == 0 { - c.JSON(200, gin.H{ - "code": 404, - "msg": "客服不存在", - }) - return - } - - isOnline := false - for name := range ws.KefuList { - if name == kefuId { - isOnline = true - break - } - } - - c.JSON(200, gin.H{ - "code": 200, - "msg": "ok", - "result": gin.H{ - "kefu_id": kefuId, - "nickname": kefuInfo.Nickname, - "avator": kefuInfo.Avator, - "is_online": isOnline, - }, - }) -} func SendOfflineMessageNotice(kefuName, visitorName, content string) { smtp := models.FindConfig("NoticeEmailSmtp") diff --git a/goflylivechat.exe b/goflylivechat.exe index 9b335fe..ecb8d45 100644 Binary files a/goflylivechat.exe and b/goflylivechat.exe differ diff --git a/router/api.go b/router/api.go index ee038e0..d151cb7 100644 --- a/router/api.go +++ b/router/api.go @@ -93,8 +93,7 @@ func InitApiRouter(engine *gin.Engine) { } //离线留言接口 - 访客端 engine.POST("/offline_message", middleware.Ipblack, controller.SubmitOfflineMessage) - engine.GET("/kefu/online", controller.CheckKefuOnline) - + //离线留言接口 - 客服端(需要认证) offlineMessageGroup := engine.Group("/offline_messages") offlineMessageGroup.Use(middleware.JwtApiMiddleware) diff --git a/static/templates/chat_page.html b/static/templates/chat_page.html index 16e64b7..eabd08d 100644 --- a/static/templates/chat_page.html +++ b/static/templates/chat_page.html @@ -232,6 +232,14 @@ this.socketClosed=false; this.focusSendConn=false; const redata = JSON.parse(e.data); + if (redata.type == "kefu_status") { + let data = redata.data; + this.handleKefuStatus(data); + } + if (redata.type == "kefu_status_change") { + let data = redata.data; + this.handleKefuStatus(data); + } if (redata.type == "kfOnline") { let msg = redata.data if(this.showKfonline && this.visitor.to_id==msg.id){ @@ -305,6 +313,19 @@ } window.parent.postMessage(redata,"*"); }, + handleKefuStatus:function(data) { + if(data && data.is_online) { + this.showOfflineMessageForm = false; + if(data.avator) { + this.kefuInfo.avatar = data.avator; + } + } else { + this.showOfflineMessageForm = true; + if(data && data.avator) { + this.kefuInfo.avatar = data.avator; + } + } + }, chatToUser:function() { var messageContent=this.messageContent.trim("\r\n"); messageContent=messageContent.replace("\n",""); @@ -667,24 +688,6 @@ $(".chatBox").append("
"+title+"
"); this.scrollBottom(); }, - checkKefuOnline:function() { - let _this = this; - $.get("/kefu/online?kefu_id="+KEFU_ID, function(res) { - if(res.code == 200 && res.result) { - if(res.result.is_online) { - _this.showOfflineMessageForm = false; - _this.getUserInfo(); - } else { - _this.showOfflineMessageForm = true; - _this.kefuInfo.avatar = res.result.avator; - } - } else { - _this.showOfflineMessageForm = true; - } - }).fail(function() { - _this.showOfflineMessageForm = true; - }); - }, submitOfflineMessage:function() { let _this = this; this.$refs.offlineMessageForm.validate(function(valid) { @@ -742,7 +745,15 @@ message: '正在尝试重新连接...', type: 'info' }); - this.checkKefuOnline(); + if(this.socket && this.socket.readyState === WebSocket.OPEN) { + let msg = { + type: "check_kefu_status", + data: KEFU_ID + }; + this.socket.send(JSON.stringify(msg)); + } else { + this.initConn(); + } }, }, mounted:function() { @@ -751,7 +762,7 @@ }, created: function () { this.init(); - this.checkKefuOnline(); + this.getUserInfo(); } }) diff --git a/ws/user.go b/ws/user.go index 37e1c9a..16cfb80 100644 --- a/ws/user.go +++ b/ws/user.go @@ -41,6 +41,7 @@ func NewKefuServer(c *gin.Context) { messageType, receive, err := conn.ReadMessage() if err != nil { log.Println("ws/user.go ", err) + RemoveKefuFromList(kefuInfo.Name) conn.Close() return } @@ -66,6 +67,18 @@ func AddKefuToList(kefu *User) { } } KefuList[kefu.Id] = kefu + + // 广播客服上线状态给所有该客服的访客 + BroadcastKefuOnlineStatus(kefu.Id, true) +} + +func RemoveKefuFromList(kefuId string) { + _, ok := KefuList[kefuId] + if ok { + delete(KefuList, kefuId) + // 广播客服离线状态给所有该客服的访客 + BroadcastKefuOnlineStatus(kefuId, false) + } } // 给指定客服发消息 @@ -103,16 +116,26 @@ func SendPingToKefuClient() { Type: "many pong", } str, _ := json.Marshal(msg) + + // 收集需要删除的客服ID + var toRemove []string + for kefuId, kefu := range KefuList { if kefu == nil { + toRemove = append(toRemove, kefuId) continue } kefu.Mux.Lock() - defer kefu.Mux.Unlock() err := kefu.Conn.WriteMessage(websocket.TextMessage, str) + kefu.Mux.Unlock() if err != nil { log.Println("定时发送ping给客服,失败", err.Error()) - delete(KefuList, kefuId) + toRemove = append(toRemove, kefuId) } } + + // 从列表中移除并广播离线状态 + for _, kefuId := range toRemove { + RemoveKefuFromList(kefuId) + } } diff --git a/ws/visitor.go b/ws/visitor.go index 2cc3d6e..b3c55ff 100644 --- a/ws/visitor.go +++ b/ws/visitor.go @@ -79,6 +79,10 @@ func AddVisitorToList(user *User) { } } ClientList[user.Id] = user + + // 发送客服在线状态给访客 + SendKefuStatusToVisitor(user, user.To_id) + lastMessage := models.FindLastMessageByVisitorId(user.Id) userInfo := make(map[string]string) userInfo["uid"] = user.Id @@ -203,3 +207,72 @@ func CleanVisitorExpire() { } }() } + +func SendKefuStatusToVisitor(visitor *User, kefuId string) { + if visitor == nil || visitor.Conn == nil { + return + } + _, online := KefuList[kefuId] + kefuInfo := models.FindUser(kefuId) + msg := TypeMessage{ + Type: "kefu_status", + Data: map[string]interface{}{ + "kefu_id": kefuId, + "is_online": online, + "nickname": kefuInfo.Nickname, + "avator": kefuInfo.Avator, + }, + } + str, _ := json.Marshal(msg) + visitor.Conn.WriteMessage(websocket.TextMessage, str) +} + +func BroadcastKefuOnlineStatus(kefuId string, isOnline bool) { + kefuInfo := models.FindUser(kefuId) + msg := TypeMessage{ + Type: "kefu_status_change", + Data: map[string]interface{}{ + "kefu_id": kefuId, + "is_online": isOnline, + "nickname": kefuInfo.Nickname, + "avator": kefuInfo.Avator, + }, + } + str, _ := json.Marshal(msg) + + for _, visitor := range ClientList { + if visitor.To_id == kefuId && visitor.Conn != nil { + visitor.Conn.WriteMessage(websocket.TextMessage, str) + } + } +} + +func HandleCheckKefuStatus(conn *websocket.Conn, data interface{}) { + var kefuId string + switch v := data.(type) { + case string: + kefuId = v + case map[string]interface{}: + if id, ok := v["kefu_id"].(string); ok { + kefuId = id + } + } + + if kefuId == "" { + return + } + + _, online := KefuList[kefuId] + kefuInfo := models.FindUser(kefuId) + msg := TypeMessage{ + Type: "kefu_status", + Data: map[string]interface{}{ + "kefu_id": kefuId, + "is_online": online, + "nickname": kefuInfo.Nickname, + "avator": kefuInfo.Avator, + }, + } + str, _ := json.Marshal(msg) + conn.WriteMessage(websocket.TextMessage, str) +} diff --git a/ws/ws.go b/ws/ws.go index e207e57..80cec2f 100644 --- a/ws/ws.go +++ b/ws/ws.go @@ -134,6 +134,8 @@ func WsServerBackend() { if tools.LimitFreqSingle("inputing:"+from, 1, 2) { OneKefuMessage(to, message.content) } + case "check_kefu_status": + HandleCheckKefuStatus(conn, typeMsg.Data) } }