// 状态 let currentUser = ""; let conversations = []; let currentKfid = ""; // 初始化 document.addEventListener("DOMContentLoaded", () => { fetchAccounts(); loadConversations(); }); // Toast function showToast(msg, type = "success") { const el = document.getElementById("toast"); el.textContent = msg; el.className = "toast toast-" + type; el.style.display = "block"; el.style.opacity = "1"; setTimeout(() => { el.style.opacity = "0"; setTimeout(() => el.style.display = "none", 300); }, 2000); } // 获取客服账号列表 async function fetchAccounts() { try { const resp = await fetch("/api/accounts"); const data = await resp.json(); const el = document.getElementById("currentKfid"); if (data.errcode === 0 && data.account_list && data.account_list.length > 0) { const accounts = data.account_list; currentKfid = accounts[0].open_kfid; el.textContent = currentKfid; el.style.color = "#07c160"; if (accounts.length > 1) { showToast(`共 ${accounts.length} 个客服账号,默认使用: ${accounts[0].name || currentKfid}`); } } else { el.textContent = "获取失败"; el.style.color = "#f44336"; showToast("获取账号列表失败: " + (data.errmsg || "未知"), "error"); } } catch (e) { document.getElementById("currentKfid").textContent = "请求失败"; showToast("获取账号列表失败: " + e.message, "error"); } } // 加载会话列表 async function loadConversations() { try { const resp = await fetch("/api/conversations"); const data = await resp.json(); conversations = data.conversations || []; renderConversations(); if (conversations.length === 0) { showToast('暂无会话,请先点击 同步拉取 获取消息', "error"); } } catch (e) { showToast("加载会话失败: " + e.message, "error"); } } // 渲染会话列表 function renderConversations() { const list = document.getElementById("conversationList"); if (conversations.length === 0) { list.innerHTML = '
暂无会话
'; return; } list.innerHTML = conversations.map(c => `
${c.external_userid}
${escapeHtml(c.latest_content || '[非文本消息]')}
${formatTime(c.latest_time)}
`).join(""); } // 选择会话 async function selectConversation(userid) { currentUser = userid; document.getElementById("msgHeader").textContent = "客户: " + userid; document.getElementById("sendBtn").disabled = false; document.getElementById("msgInput").disabled = false; renderConversations(); await loadMessages(userid); } // 加载消息 async function loadMessages(userid) { try { const resp = await fetch(`/api/messages?external_userid=${userid}`); const data = await resp.json(); const msgs = data.messages || []; renderMessages(msgs); } catch (e) { showToast("加载消息失败: " + e.message, "error"); } } // 渲染消息 function renderMessages(msgs) { const container = document.getElementById("messageList"); if (msgs.length === 0) { container.innerHTML = '
暂无消息
'; return; } container.innerHTML = msgs.map(m => `
${escapeHtml(m.content || `[${m.msgtype}]`)}
${formatTime(m.send_time)}
`).join(""); container.scrollTop = container.scrollHeight; } // 发送消息 async function sendMessage() { if (!currentUser) return; const input = document.getElementById("msgInput"); const content = input.value.trim(); if (!content) return; const btn = document.getElementById("sendBtn"); btn.disabled = true; btn.textContent = "发送中..."; try { const resp = await fetch("/api/send", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ external_userid: currentUser, content }), }); const result = await resp.json(); if (result.errcode === 0) { input.value = ""; showToast("发送成功"); await loadMessages(currentUser); } else { showToast("发送失败: " + (result.errmsg || JSON.stringify(result)), "error"); } } catch (e) { showToast("发送失败: " + e.message, "error"); } finally { btn.disabled = false; btn.textContent = "发送"; } } // 同步拉取 async function syncMessages() { const statusEl = document.getElementById("syncStatus"); statusEl.textContent = "同步中..."; try { const resp = await fetch("/api/sync", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ open_kfid: currentKfid }), }); const data = await resp.json(); if (data.errcode === 0) { showToast(`同步成功,获取 ${data.total} 条消息,新增入库 ${data.saved} 条`); await loadConversations(); if (currentUser) await loadMessages(currentUser); } else { showToast("同步失败: " + (data.errmsg || JSON.stringify(data)), "error"); } } catch (e) { showToast("同步失败: " + e.message, "error"); } finally { statusEl.textContent = ""; } } // 格式化时间 function formatTime(iso) { if (!iso) return ""; const d = new Date(iso); const pad = (n) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; } // HTML 转义 function escapeHtml(text) { const div = document.createElement("div"); div.textContent = text; return div.innerHTML; }