Implementa sistema de chat em tempo real entre agente e cliente
- Adiciona tabela liveChatSessions no schema Convex - Cria convex/liveChat.ts com mutations e queries para chat - Adiciona API routes para maquinas (sessions, messages, poll) - Cria modulo chat.rs no Tauri com ChatRuntime e polling - Adiciona comandos de chat no lib.rs (start/stop polling, open/close window) - Cria componentes React do chat widget (ChatWidget, types) - Adiciona botao "Iniciar Chat" no dashboard (ticket-chat-panel) - Implementa menu de chat no system tray - Polling de 2 segundos para maior responsividade - Janela de chat flutuante, frameless, always-on-top 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
0c8d53c0b6
commit
ba91c1e0f5
15 changed files with 2004 additions and 15 deletions
|
|
@ -2956,12 +2956,59 @@ export const listChatMessages = query({
|
|||
.withIndex("by_ticket_created", (q) => q.eq("ticketId", ticketId))
|
||||
.collect()
|
||||
|
||||
// Verificar maquina e sessao de chat ao vivo
|
||||
let liveChat: {
|
||||
hasMachine: boolean
|
||||
machineOnline: boolean
|
||||
machineHostname: string | null
|
||||
activeSession: {
|
||||
sessionId: Id<"liveChatSessions">
|
||||
agentId: Id<"users">
|
||||
agentName: string | null
|
||||
startedAt: number
|
||||
unreadByAgent: number
|
||||
} | null
|
||||
} = {
|
||||
hasMachine: false,
|
||||
machineOnline: false,
|
||||
machineHostname: null,
|
||||
activeSession: null,
|
||||
}
|
||||
|
||||
if (ticketDoc.machineId) {
|
||||
const machine = await ctx.db.get(ticketDoc.machineId)
|
||||
if (machine) {
|
||||
const fiveMinutesAgo = now - 5 * 60 * 1000
|
||||
liveChat.hasMachine = true
|
||||
liveChat.machineOnline = Boolean(machine.lastHeartbeatAt && machine.lastHeartbeatAt > fiveMinutesAgo)
|
||||
liveChat.machineHostname = machine.hostname
|
||||
|
||||
// Verificar sessao ativa
|
||||
const activeSession = await ctx.db
|
||||
.query("liveChatSessions")
|
||||
.withIndex("by_ticket", (q) => q.eq("ticketId", ticketId))
|
||||
.filter((q) => q.eq(q.field("status"), "ACTIVE"))
|
||||
.first()
|
||||
|
||||
if (activeSession) {
|
||||
liveChat.activeSession = {
|
||||
sessionId: activeSession._id,
|
||||
agentId: activeSession.agentId,
|
||||
agentName: activeSession.agentSnapshot?.name ?? null,
|
||||
startedAt: activeSession.startedAt,
|
||||
unreadByAgent: activeSession.unreadByAgent ?? 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ticketId: String(ticketId),
|
||||
chatEnabled,
|
||||
status,
|
||||
canPost,
|
||||
reopenDeadline: ticketDoc.reopenDeadline ?? null,
|
||||
liveChat,
|
||||
messages: messages
|
||||
.sort((a, b) => a.createdAt - b.createdAt)
|
||||
.map((message) => ({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue