57 lines
1.7 KiB
Go
57 lines
1.7 KiB
Go
package service
|
|
|
|
import (
|
|
"time"
|
|
|
|
"kefu-cloud/server/internal/model"
|
|
"kefu-cloud/server/internal/ws"
|
|
)
|
|
|
|
const VisitorOnlineTimeout = 45 * time.Second
|
|
|
|
// VisitorIsOnline 根据最近心跳和显式离开时间动态判断访客是否在线。
|
|
func VisitorIsOnline(session *model.Session, now time.Time) bool {
|
|
if session == nil || session.Status == "ended" || session.Status == "archived" {
|
|
return false
|
|
}
|
|
if session.LastSeenAt == nil {
|
|
return false
|
|
}
|
|
if session.VisitorLeftAt != nil && !session.LastSeenAt.After(*session.VisitorLeftAt) {
|
|
return false
|
|
}
|
|
return now.Sub(*session.LastSeenAt) <= VisitorOnlineTimeout
|
|
}
|
|
|
|
// UpdateVisitorPresence 处理 visible/hidden/leave 状态,并返回切换前后的在线状态。
|
|
func UpdateVisitorPresence(session *model.Session, state string, now time.Time) (bool, bool, error) {
|
|
wasOnline := VisitorIsOnline(session, now)
|
|
updates := map[string]interface{}{}
|
|
switch state {
|
|
case "hidden", "leave":
|
|
leftAt := now
|
|
updates["visitor_left_at"] = leftAt
|
|
session.VisitorLeftAt = &leftAt
|
|
default:
|
|
updates["last_seen_at"] = now
|
|
updates["visitor_left_at"] = nil
|
|
session.LastSeenAt = &now
|
|
session.VisitorLeftAt = nil
|
|
}
|
|
if err := model.DB.Model(session).Updates(updates).Error; err != nil {
|
|
return wasOnline, false, err
|
|
}
|
|
return wasOnline, VisitorIsOnline(session, now), nil
|
|
}
|
|
|
|
func broadcastVisitorPresence(session *model.Session, online bool) {
|
|
payload, err := ws.NewEvent("visitor_presence", session.ID, map[string]interface{}{
|
|
"visitor_online": online,
|
|
"last_seen_at": session.LastSeenAt,
|
|
"visitor_left_at": session.VisitorLeftAt,
|
|
})
|
|
if err == nil {
|
|
ws.DefaultHub.BroadcastToTenantStaff(session.TenantID, payload)
|
|
}
|
|
}
|