feat(widget): 优化访客在线轨迹、GeoIP与多站点渠道
CI / Frontend (typecheck + lint + build) (push) Successful in 2m5s
CI / Backend (go vet + test) (push) Failing after 5m20s

This commit is contained in:
yml2213
2026-11-06 18:21:30 +08:00
parent 24fac1bcf1
commit 38d6fc1684
37 changed files with 1071 additions and 123 deletions
+10 -1
View File
@@ -28,6 +28,7 @@ type SessionListItem struct {
AgentName string `json:"agent_name"`
ChannelName string `json:"channel_name"`
ChannelType string `json:"channel_type"`
ChannelDomain string `json:"channel_domain"`
}
// AgentItem 可转接/筛选坐席项。
@@ -60,6 +61,7 @@ func LoadTenantSession(id string, tenantID uint) (*model.Session, error) {
if session.TenantID != tenantID {
return nil, Forbidden("无权访问其他租户会话")
}
session.VisitorOnline = VisitorIsOnline(&session, time.Now())
return &session, nil
}
@@ -225,6 +227,7 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
items := make([]SessionListItem, 0, len(sessions))
for _, session := range sessions {
item := SessionListItem{Session: session, MessageCount: msgCountMap[session.ID]}
item.VisitorOnline = VisitorIsOnline(&session, time.Now())
if !actor.SessionAll && session.AgentID != nil && *session.AgentID == actor.UserID {
item.UnreadCount = unreadCount(session)
}
@@ -239,6 +242,7 @@ func ListSessions(actor Actor, tenantID uint, f SessionFilter) ([]SessionListIte
if ch, ok := channelMap[session.ChannelID]; ok {
item.ChannelName = ch.Name
item.ChannelType = ch.Type
item.ChannelDomain = ch.SiteDomain
}
var lastMsg model.Message
if err := model.DB.Where("session_id = ?", session.ID).Order("seq desc").First(&lastMsg).Error; err == nil {
@@ -529,7 +533,9 @@ func EndSession(session *model.Session, operatorID uint, reason string) error {
result := model.DB.Model(&model.Session{}).
Where("id = ? AND tenant_id = ? AND status <> ?", session.ID, session.TenantID, "ended").
Updates(map[string]interface{}{"status": "ended", "end_reason": reason, "ended_at": now})
Updates(map[string]interface{}{
"status": "ended", "end_reason": reason, "ended_at": now, "visitor_left_at": now,
})
if result.RowsAffected == 0 {
return NotFound("会话不存在")
@@ -543,6 +549,9 @@ func EndSession(session *model.Session, operatorID uint, reason string) error {
})
session.Status = "ended"
session.EndedAt = &now
session.VisitorLeftAt = &now
session.VisitorOnline = false
_ = CloseCurrentPageView(session, now)
BroadcastSessionUpdate(session)
return nil