feat: add customer online status to conversation response and update UI accordingly
This commit is contained in:
@@ -37,6 +37,7 @@ func BuildConversation(item *models.Conversation) response.ConversationResponse
|
|||||||
AgentLastReadMessageID: readStateMessageID(agentReadState),
|
AgentLastReadMessageID: readStateMessageID(agentReadState),
|
||||||
AgentLastReadSeqNo: readStateSeqNo(agentReadState),
|
AgentLastReadSeqNo: readStateSeqNo(agentReadState),
|
||||||
AgentLastReadAt: readStateAt(agentReadState),
|
AgentLastReadAt: readStateAt(agentReadState),
|
||||||
|
CustomerOnline: services.WsService.IsVisitorOnline(item.ExternalID),
|
||||||
ClosedAt: utils.FormatTimePtr(item.ClosedAt),
|
ClosedAt: utils.FormatTimePtr(item.ClosedAt),
|
||||||
ClosedBy: item.ClosedBy,
|
ClosedBy: item.ClosedBy,
|
||||||
CloseReason: item.CloseReason,
|
CloseReason: item.CloseReason,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ type ConversationResponse struct {
|
|||||||
AgentLastReadMessageID int64 `json:"agentLastReadMessageId"`
|
AgentLastReadMessageID int64 `json:"agentLastReadMessageId"`
|
||||||
AgentLastReadSeqNo int64 `json:"agentLastReadSeqNo"`
|
AgentLastReadSeqNo int64 `json:"agentLastReadSeqNo"`
|
||||||
AgentLastReadAt string `json:"agentLastReadAt,omitempty"`
|
AgentLastReadAt string `json:"agentLastReadAt,omitempty"`
|
||||||
|
CustomerOnline bool `json:"customerOnline"`
|
||||||
ClosedAt string `json:"closedAt,omitempty"`
|
ClosedAt string `json:"closedAt,omitempty"`
|
||||||
ClosedBy int64 `json:"closedBy"`
|
ClosedBy int64 `json:"closedBy"`
|
||||||
ClosedByName string `json:"closedByName,omitempty"`
|
ClosedByName string `json:"closedByName,omitempty"`
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ func (m *WsConnectionManager) FindByTopics(topics []string) []*ClientSession {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *WsConnectionManager) HasTopic(topic string) bool {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
|
||||||
|
sessions := m.topics[topic]
|
||||||
|
return len(sessions) > 0
|
||||||
|
}
|
||||||
|
|
||||||
func (m *WsConnectionManager) subscribeLocked(session *ClientSession, topic string) {
|
func (m *WsConnectionManager) subscribeLocked(session *ClientSession, topic string) {
|
||||||
if _, exists := session.Topics[topic]; exists {
|
if _, exists := session.Topics[topic]; exists {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -386,6 +386,14 @@ func (s *wsService) PublishToTopics(topics []string, event RealtimeEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *wsService) IsVisitorOnline(visitorID string) bool {
|
||||||
|
visitorID = strings.TrimSpace(visitorID)
|
||||||
|
if visitorID == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s.manager.HasTopic(s.visitorTopic(visitorID))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *wsService) routeConversationTopics(conversation *models.Conversation) []string {
|
func (s *wsService) routeConversationTopics(conversation *models.Conversation) []string {
|
||||||
if conversation == nil {
|
if conversation == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -270,9 +270,27 @@ export default function ConversationsPage() {
|
|||||||
<AvatarFallback>客</AvatarFallback>
|
<AvatarFallback>客</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="min-w-0 truncate font-medium leading-tight">
|
<div className="flex items-center gap-2">
|
||||||
{conversation.subject}
|
<p className="min-w-0 truncate font-medium leading-tight">
|
||||||
</p>
|
{conversation.subject}
|
||||||
|
</p>
|
||||||
|
<span
|
||||||
|
className={`inline-flex shrink-0 items-center gap-1 rounded-full border px-2 text-[11px] ${
|
||||||
|
conversation.customerOnline
|
||||||
|
? "border-emerald-200 bg-emerald-50 text-emerald-700"
|
||||||
|
: "border-slate-200 bg-slate-100 text-slate-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`size-1.5 rounded-full ${
|
||||||
|
conversation.customerOnline
|
||||||
|
? "bg-emerald-500"
|
||||||
|
: "bg-slate-400"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
{conversation.customerOnline ? "用户在线" : "用户离线"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<p className="mt-0.5 truncate text-xs text-muted-foreground sm:text-sm">
|
<p className="mt-0.5 truncate text-xs text-muted-foreground sm:text-sm">
|
||||||
<span>{conversation.externalSource}</span>
|
<span>{conversation.externalSource}</span>
|
||||||
<span className="text-muted-foreground/60"> / </span>
|
<span className="text-muted-foreground/60"> / </span>
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export type AgentConversation = {
|
|||||||
agentLastReadMessageId: number
|
agentLastReadMessageId: number
|
||||||
agentLastReadSeqNo: number
|
agentLastReadSeqNo: number
|
||||||
agentLastReadAt?: string
|
agentLastReadAt?: string
|
||||||
|
customerOnline: boolean
|
||||||
closedAt?: string
|
closedAt?: string
|
||||||
tags?: AgentConversationTag[]
|
tags?: AgentConversationTag[]
|
||||||
participants?: AgentConversationParticipant[]
|
participants?: AgentConversationParticipant[]
|
||||||
|
|||||||
Reference in New Issue
Block a user