427 lines
21 KiB
HTML
427 lines
21 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>柏悦物流 - 客服工作台</title>
|
||
<style>
|
||
*{box-sizing:border-box;margin:0;padding:0;}
|
||
body{font-family:-apple-system,"Microsoft YaHei",sans-serif;background:#f0f2f5;height:100vh;display:flex;flex-direction:column;}
|
||
.topbar{background:#fff;padding:10px 20px;display:flex;align-items:center;gap:16px;box-shadow:0 1px 4px rgba(0,0,0,0.08);z-index:10;}
|
||
.topbar .logo{font-size:18px;font-weight:bold;color:#18479c;}
|
||
.topbar .stats{display:flex;gap:20px;font-size:13px;color:#666;margin-left:20px;}
|
||
.topbar .stats b{color:#2978e8;font-size:16px;}
|
||
.topbar .status{margin-left:auto;display:flex;align-items:center;gap:6px;font-size:13px;color:#666;}
|
||
.topbar .dot{width:8px;height:8px;border-radius:50%;background:#22c55e;}
|
||
.layout{flex:1;display:grid;grid-template-columns:260px 1fr 240px;overflow:hidden;}
|
||
/* 左栏:对话列表 */
|
||
.conv-list{background:#fff;border-right:1px solid #e8e8e8;overflow-y:auto;}
|
||
.conv-list h3{padding:12px 14px;font-size:13px;color:#999;border-bottom:1px solid #f0f0f0;}
|
||
.conv-item{padding:12px 14px;cursor:pointer;border-bottom:1px solid #f5f5f5;display:flex;align-items:center;gap:10px;}
|
||
.conv-item:hover{background:#f5f8fc;}
|
||
.conv-item.active{background:#e8f0ff;border-left:3px solid #2978e8;}
|
||
.conv-item .avatar{width:36px;height:36px;border-radius:50%;background:#dbeafe;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;}
|
||
.conv-item .info{flex:1;min-width:0;}
|
||
.conv-item .name{font-size:14px;font-weight:500;}
|
||
.conv-item .preview{font-size:12px;color:#999;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
||
.conv-item .badge{background:#dc2626;color:#fff;border-radius:10px;padding:1px 7px;font-size:11px;}
|
||
.queue-item{padding:10px 14px;background:#fff7ed;border-bottom:1px solid #ffedd5;}
|
||
.queue-item .qt{font-size:13px;color:#ea580c;font-weight:500;}
|
||
.queue-item button{margin-top:6px;width:100%;background:#ea580c;color:#fff;border:none;padding:5px;border-radius:4px;cursor:pointer;font-size:12px;}
|
||
/* 中间:聊天 */
|
||
.chat-area{display:flex;flex-direction:column;background:#f8fafc;}
|
||
.chat-header{background:#fff;padding:12px 20px;border-bottom:1px solid #e8e8e8;display:flex;align-items:center;justify-content:space-between;}
|
||
.chat-header .ct{font-size:15px;font-weight:500;}
|
||
.chat-header .close{background:#dc2626;color:#fff;border:none;padding:6px 14px;border-radius:4px;cursor:pointer;font-size:13px;}
|
||
#chatBox{flex:1;overflow-y:auto;padding:20px;}
|
||
.msg{margin-bottom:12px;display:flex;}
|
||
.msg .bubble{max-width:60%;padding:10px 14px;border-radius:12px;font-size:14px;line-height:1.5;overflow-wrap:break-word;}
|
||
.msg.cust{justify-content:flex-start;}
|
||
.msg.cust .bubble{background:#fff;border:1px solid #e8e8e8;border-top-left-radius:4px;}
|
||
.msg.agent{justify-content:flex-end;}
|
||
.msg.agent .bubble{background:#2978e8;color:#fff;border-top-right-radius:4px;}
|
||
.msg .meta{font-size:11px;color:#aaa;margin-top:3px;}
|
||
.input-bar{background:#fff;border-top:1px solid #e8e8e8;padding:12px 20px;display:flex;gap:10px;}
|
||
.input-bar input{flex:1;border:1px solid #ddd;border-radius:6px;padding:10px 12px;font-size:14px;outline:none;}
|
||
.input-bar input:focus{border-color:#2978e8;}
|
||
.input-bar button{background:#2978e8;color:#fff;border:none;padding:0 20px;border-radius:6px;cursor:pointer;font-size:14px;}
|
||
/* 右栏:客户信息+快捷回复 */
|
||
.side{background:#fff;border-left:1px solid #e8e8e8;overflow-y:auto;}
|
||
.side .card{padding:16px;border-bottom:1px solid #f0f0f0;}
|
||
.side h4{font-size:13px;color:#999;margin-bottom:10px;}
|
||
.side .info-row{font-size:13px;padding:4px 0;color:#333;}
|
||
.side .quick{padding:8px 12px;background:#f5f8fc;border-radius:6px;margin-bottom:6px;font-size:13px;cursor:pointer;}
|
||
.side .quick:hover{background:#e8f0ff;}
|
||
.empty{display:flex;align-items:center;justify-content:center;height:100%;color:#bbb;font-size:14px;}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="topbar">
|
||
<div class="logo">🎧 柏悦客服工作台</div>
|
||
<div class="stats">
|
||
<span>对话 <b id="s1">-</b></span>
|
||
<span>消息 <b id="s2">-</b></span>
|
||
<span>今日 <b id="s3">-</b></span>
|
||
<span>👍 <b id="s4">-</b></span>
|
||
<span>👎 <b id="s5">-</b></span>
|
||
<span>⭐ <b id="s6">-</b></span>
|
||
</div>
|
||
<div class="status">
|
||
<span id="nightBadge" style="display:none;font-size:12px;background:#1e3a5f;color:#fbbf24;padding:3px 10px;border-radius:10px;margin-right:12px;">🌙 夜间时段</span>
|
||
<a href="/api/export_chat" style="font-size:13px;color:#2978e8;text-decoration:none;margin-right:16px;">导出Excel</a>
|
||
<span class="dot"></span> 在线
|
||
</div>
|
||
</div>
|
||
|
||
<div class="layout">
|
||
<div class="conv-list">
|
||
<div style="padding:10px;border-bottom:1px solid #f0f0f0;">
|
||
<input id="searchBox" placeholder="搜索聊天记录..." style="width:100%;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:12px;box-sizing:border-box;" onkeydown="if(event.key==='Enter')doSearch()">
|
||
</div>
|
||
<div id="searchResult" style="position:fixed;top:70px;right:20px;background:#fff;border:2px solid #dc2626;border-radius:8px;max-height:500px;overflow-y:auto;z-index:9999;display:none;width:500px;box-shadow:0 4px 16px rgba(0,0,0,0.2);resize:both;overflow:auto;min-width:300px;min-height:200px;">
|
||
<button onclick="this.parentElement.style.display='none';document.getElementById('searchBox').value='';" style="position:absolute;top:8px;right:12px;border:none;background:#fff;color:#dc2626;border-radius:50%;width:30px;height:30px;font-size:16px;cursor:pointer;z-index:10;font-weight:bold;">✕</button>
|
||
<div id="searchHeader" style="padding:12px;background:#dc2626;color:#fff;font-weight:bold;cursor:move;">搜索结果</div>
|
||
<div id="searchBody"></div>
|
||
</div>
|
||
<h3>待接入</h3>
|
||
<div id="queue"></div>
|
||
<h3>进行中</h3>
|
||
<div id="sessionList"></div>
|
||
</div>
|
||
|
||
<div class="chat-area" id="chatArea">
|
||
<div class="empty" id="emptyTip">← 选择左侧对话开始服务</div>
|
||
<div id="chatContent" style="display:none;flex:1;display:flex;flex-direction:column;overflow:hidden;">
|
||
<div class="chat-header">
|
||
<span class="ct" id="chatTitle">对话</span>
|
||
<div style="display:flex;gap:8px;">
|
||
<button onclick="transferSession()" style="background:#f59e0b;color:#fff;border:none;padding:6px 14px;border-radius:4px;cursor:pointer;font-size:13px;">转接</button>
|
||
<button class="close" onclick="closeSession()">结束会话</button>
|
||
</div>
|
||
</div>
|
||
<div id="chatBox"></div>
|
||
<div class="input-bar">
|
||
<button onclick="document.getElementById('emojiPanel2').style.display=document.getElementById('emojiPanel2').style.display==='block'?'none':'block'" style="font-size:20px;background:none;border:none;cursor:pointer;">😊</button>
|
||
<div id="emojiPanel2" style="display:none;position:absolute;bottom:60px;left:10px;background:#fff;border:1px solid #ddd;border-radius:8px;padding:10px;box-shadow:0 2px 8px rgba(0,0,0,0.15);z-index:99;">
|
||
<span onclick="insertEmoji2('😊')" style="cursor:pointer;font-size:20px;margin:2px;">😊</span>
|
||
<span onclick="insertEmoji2('😂')" style="cursor:pointer;font-size:20px;margin:2px;">😂</span>
|
||
<span onclick="insertEmoji2('👍')" style="cursor:pointer;font-size:20px;margin:2px;">👍</span>
|
||
<span onclick="insertEmoji2('❤️')" style="cursor:pointer;font-size:20px;margin:2px;">❤️</span>
|
||
<span onclick="insertEmoji2('🙏')" style="cursor:pointer;font-size:20px;margin:2px;">🙏</span>
|
||
<span onclick="insertEmoji2('😅')" style="cursor:pointer;font-size:20px;margin:2px;">😅</span>
|
||
<span onclick="insertEmoji2('😢')" style="cursor:pointer;font-size:20px;margin:2px;">😢</span>
|
||
<span onclick="insertEmoji2('🎉')" style="cursor:pointer;font-size:20px;margin:2px;">🎉</span>
|
||
</div>
|
||
<input type="text" id="replyText" placeholder="输入回复,Enter发送">
|
||
<button onclick="sendReply()">发送</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="side">
|
||
<div class="card">
|
||
<h4>客户信息</h4>
|
||
<div class="info-row" id="cInfo">选择对话后显示</div>
|
||
</div>
|
||
<div class="card">
|
||
<h4>会话备注</h4>
|
||
<textarea id="noteInput" placeholder="给这个对话加备注..." style="width:100%;height:60px;border:1px solid #ddd;border-radius:4px;padding:6px;font-size:12px;resize:none;box-sizing:border-box;"></textarea>
|
||
<button onclick="saveNote()" style="width:100%;margin-top:6px;background:#2978e8;color:#fff;border:none;padding:5px;border-radius:4px;cursor:pointer;font-size:12px;">保存备注</button>
|
||
</div>
|
||
<div class="card">
|
||
<h4>快捷回复</h4>
|
||
<div class="quick" onclick="quickReply('您好,请问有什么可以帮您?')">您好,请问有什么可以帮您?</div>
|
||
<div class="quick" onclick="quickReply('请提供运单号,我帮您查询。')">请提供运单号</div>
|
||
<div class="quick" onclick="quickReply('已为您催促,请稍候。')">已催促,请稍候</div>
|
||
<div class="quick" onclick="quickReply('感谢您的咨询,祝您生活愉快!')">感谢咨询</div>
|
||
</div>
|
||
<div class="card">
|
||
<h4>离线留言</h4>
|
||
<div id="ticketList"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
var curSid = 0;
|
||
var sessions = {};
|
||
|
||
// 浏览器通知权限
|
||
if("Notification" in window && Notification.permission === "default"){
|
||
Notification.requestPermission();
|
||
}
|
||
function notify(title, body){
|
||
if(!("Notification" in window) || Notification.permission !== "granted") return;
|
||
if(!document.hidden) return; // 页面可见时不弹
|
||
var n = new Notification(title, {body: body, icon: "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🎧</text></svg>"});
|
||
n.onclick = function(){ window.focus(); n.close(); };
|
||
}
|
||
|
||
// 夜间时段提示(22:00-8:00)
|
||
(function checkNight(){
|
||
var h = new Date().getHours();
|
||
var badge = document.getElementById("nightBadge");
|
||
if(h >= 22 || h < 8){ badge.style.display = "inline-block"; }
|
||
setInterval(checkNight, 60000);
|
||
})();
|
||
|
||
fetch("/api/admin/stats").then(function(r){return r.json()}).then(function(d){
|
||
s1.textContent=d.total_conv; s2.textContent=d.total_msg;
|
||
s3.textContent=d.today_conv; s4.textContent=d.good; s5.textContent=d.bad;
|
||
s6.textContent=d.rating_avg+"("+d.rating_count+")";
|
||
});
|
||
|
||
// 拖拽搜索弹窗
|
||
(function(){
|
||
var header = document.getElementById("searchHeader");
|
||
var box = document.getElementById("searchResult");
|
||
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
||
header.onmousedown = dragMouseDown;
|
||
function dragMouseDown(e){
|
||
e = e || window.event;
|
||
e.preventDefault();
|
||
pos3 = e.clientX;
|
||
pos4 = e.clientY;
|
||
document.onmouseup = closeDragElement;
|
||
document.onmousemove = elementDrag;
|
||
}
|
||
function elementDrag(e){
|
||
e = e || window.event;
|
||
e.preventDefault();
|
||
pos1 = pos3 - e.clientX;
|
||
pos2 = pos4 - e.clientY;
|
||
pos3 = e.clientX;
|
||
pos4 = e.clientY;
|
||
box.style.right = "auto";
|
||
box.style.left = (box.offsetLeft - pos1) + "px";
|
||
box.style.top = (box.offsetTop - pos2) + "px";
|
||
}
|
||
function closeDragElement(){
|
||
document.onmouseup = null;
|
||
document.onmousemove = null;
|
||
}
|
||
})();
|
||
|
||
function doSearch(){
|
||
var q = document.getElementById("searchBox").value.trim();
|
||
if(!q) return;
|
||
fetch("/api/search_chat?q="+encodeURIComponent(q)).then(function(r){return r.json()}).then(function(list){
|
||
document.getElementById("searchResult").style.display = "block";
|
||
var body = document.getElementById("searchBody");
|
||
if(!list.length){ body.innerHTML = '<div style="padding:10px;color:#999;">无结果</div>'; return; }
|
||
body.innerHTML = list.map(function(r){
|
||
return '<div style="padding:8px 12px;border-bottom:1px solid #f0f0f0;font-size:12px;"><b>'+r.title+'</b> ['+r.role+']<br>'+r.content+'<br><span style="color:#999;">'+r.ctime+'</span></div>';
|
||
}).join("");
|
||
});
|
||
}
|
||
|
||
function loadQueue(){
|
||
fetch("/api/human/queue").then(function(r){return r.json()}).then(function(list){
|
||
var prevCount = document.getElementById("queue").dataset.count || 0;
|
||
var curCount = list.length;
|
||
document.getElementById("queue").dataset.count = curCount;
|
||
if(curCount > prevCount && document.hidden){
|
||
notify("新客户排队", "有 " + curCount + " 位客户等待接入");
|
||
}
|
||
document.getElementById("queue").innerHTML = list.length
|
||
? list.map(function(x){return '<div class="queue-item"><div class="qt">#'+x.id+' '+x.ctime+'</div><button onclick="accept('+x.id+')">接入</button></div>'}).join("")
|
||
: '<div style="padding:10px 14px;font-size:12px;color:#ccc;">暂无排队</div>';
|
||
});
|
||
}
|
||
setInterval(loadQueue, 3000);
|
||
|
||
function loadTickets(){
|
||
fetch("/api/tickets").then(function(r){return r.json()}).then(function(list){
|
||
var el = document.getElementById("ticketList");
|
||
if(!list.length){ el.innerHTML = '<div style="font-size:12px;color:#ccc;">暂无留言</div>'; return; }
|
||
el.innerHTML = list.map(function(t){
|
||
return '<div style="padding:6px;background:#fff7ed;border-radius:6px;margin-bottom:6px;font-size:12px;">'+t.content+'<br><span style="color:#999;">'+t.ctime+'</span></div>';
|
||
}).join("");
|
||
});
|
||
}
|
||
setInterval(loadTickets, 5000);
|
||
loadTickets();
|
||
|
||
function accept(sid){
|
||
sid = String(sid);
|
||
if(sessions[sid]) return;
|
||
fetch("/api/human/accept",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(sid)})}).then(function(){
|
||
sessions[sid] = {lastId:0, msgs:[], unread:0};
|
||
switchSession(sid);
|
||
});
|
||
}
|
||
|
||
function switchSession(sid){
|
||
curSid = String(sid);
|
||
document.getElementById("emptyTip").style.display="none";
|
||
document.getElementById("chatContent").style.display="flex";
|
||
document.getElementById("chatTitle").textContent="对话 #"+sid;
|
||
document.getElementById("cInfo").innerHTML="会话编号:#"+sid;
|
||
document.getElementById("chatBox").innerHTML="";
|
||
sessions[sid].msgs.forEach(function(m){ appendMsg(m); });
|
||
sessions[sid].unread = 0;
|
||
renderList();
|
||
// 从后端拉备注
|
||
document.getElementById("noteInput").value = "加载中...";
|
||
fetch("/api/human/poll?sid="+parseInt(sid)+"&after=0").then(function(r){return r.json()}).then(function(d){
|
||
document.getElementById("noteInput").value = d.note || "";
|
||
});
|
||
fetch("/api/human/read",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(sid)})});
|
||
}
|
||
|
||
function saveNote(){
|
||
if(!curSid){ alert("请先选择一个对话"); return; }
|
||
var note = document.getElementById("noteInput").value;
|
||
sessions[curSid].note = note;
|
||
fetch("/api/human/note",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(curSid), note:note})}).then(function(){
|
||
var btn = event.target;
|
||
var old = btn.textContent;
|
||
btn.textContent = "已保存 ✓";
|
||
btn.style.background = "#22c55e";
|
||
setTimeout(function(){ btn.textContent = old; btn.style.background = "#2978e8"; }, 1500);
|
||
});
|
||
}
|
||
|
||
function appendMsg(m){
|
||
var div=document.createElement("div");
|
||
if(m.side==="system"){
|
||
div.className="msg system-msg";
|
||
div.innerHTML='<div style="text-align:center;font-size:12px;color:#999;padding:4px 0;">'+m.content+'</div>';
|
||
document.getElementById("chatBox").appendChild(div);
|
||
document.getElementById("chatBox").scrollTop=999999;
|
||
return;
|
||
}
|
||
div.className="msg "+(m.side==="customer"?"cust":"agent");
|
||
var c = m.content.replace(/</g,"<");
|
||
var imgMatch = c.match(/\[图片\](\/uploads\/\S+)/);
|
||
if(imgMatch){
|
||
c = c.replace(imgMatch[0], '<img src="'+imgMatch[1]+'" style="max-width:200px;border-radius:6px;display:block;">');
|
||
}
|
||
var recallBtn = m.side==="agent" ? '<span onclick="recallMsg('+m.id+',this)" style="font-size:11px;color:#999;cursor:pointer;margin-left:6px;">撤回</span>' : '';
|
||
div.innerHTML='<div><div class="bubble">'+c+'</div><div class="meta">'+(m.side==="customer"?"客户":"客服")+recallBtn+'</div></div>';
|
||
document.getElementById("chatBox").appendChild(div);
|
||
document.getElementById("chatBox").scrollTop=999999;
|
||
}
|
||
|
||
function recallMsg(mid, el){
|
||
fetch("/api/human/recall",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mid:mid})}).then(function(){
|
||
var msgDiv = el.closest(".msg");
|
||
if(msgDiv){
|
||
var bubble = msgDiv.querySelector(".bubble");
|
||
if(bubble) bubble.innerHTML = "";
|
||
var meta = msgDiv.querySelector(".meta");
|
||
if(meta) meta.innerHTML = "";
|
||
}
|
||
});
|
||
}
|
||
|
||
function renderList(){
|
||
var el=document.getElementById("sessionList");
|
||
el.innerHTML="";
|
||
Object.keys(sessions).forEach(function(sid){
|
||
var last = sessions[sid].msgs[sessions[sid].msgs.length-1];
|
||
var preview = last ? last.content.substring(0,20) : "等待中...";
|
||
var unread = sessions[sid].unread || 0;
|
||
var div=document.createElement("div");
|
||
div.className="conv-item"+(sid==curSid?" active":"");
|
||
div.innerHTML='<div class="avatar">'+(sid==curSid?"🟢":"👤")+'</div><div class="info"><div class="name">对话 #'+sid+'</div><div class="preview">'+preview+'</div></div>'+(unread>0?'<span class="badge">'+unread+'</span>':"");
|
||
div.onclick=function(){ switchSession(sid); };
|
||
el.appendChild(div);
|
||
});
|
||
}
|
||
|
||
function poll(){
|
||
fetch("/api/human/active").then(function(r){return r.json()}).then(function(list){
|
||
list.forEach(function(s){
|
||
if(!sessions[String(s.id)]) sessions[String(s.id)] = {lastId:0, msgs:[], unread:0};
|
||
});
|
||
renderList();
|
||
}).then(function(){
|
||
Object.keys(sessions).forEach(function(sid){
|
||
fetch("/api/human/poll?sid="+parseInt(sid)+"&after="+sessions[sid].lastId)
|
||
.then(function(r){return r.json()})
|
||
.then(function(d){
|
||
if(d.status==="closed"){
|
||
delete sessions[sid];
|
||
if(sid==curSid){ curSid=0; document.getElementById("chatContent").style.display="none"; document.getElementById("emptyTip").style.display="flex"; }
|
||
renderList(); return;
|
||
}
|
||
// 客户正在输入
|
||
var t = document.getElementById("typing-ind");
|
||
if(d.typing && sid==curSid){ if(!t){ t=document.createElement("div"); t.id="typing-ind"; t.style.cssText="font-size:12px;color:#999;padding:4px 0;"; t.textContent="客户正在输入..."; document.getElementById("chatBox").appendChild(t); } }
|
||
else if(t){ t.remove(); }
|
||
d.messages.forEach(function(m){
|
||
var exists = sessions[sid].msgs.some(function(x){return x.id===m.id});
|
||
if(exists) return;
|
||
sessions[sid].lastId=m.id;
|
||
sessions[sid].msgs.push(m);
|
||
if(m.side==="customer" && sid!=curSid){ sessions[sid].unread=(sessions[sid].unread||0)+1; renderList(); }
|
||
if(m.side==="customer" && document.hidden){
|
||
notify("客户消息 #"+sid, m.content.substring(0, 50));
|
||
}
|
||
if(sid==curSid) appendMsg(m);
|
||
});
|
||
}).catch(function(){});
|
||
});
|
||
});
|
||
}
|
||
setInterval(poll, 1000);
|
||
|
||
function insertEmoji2(e){
|
||
document.getElementById("replyText").value += e;
|
||
document.getElementById("replyText").focus();
|
||
document.getElementById("emojiPanel2").style.display = "none";
|
||
}
|
||
|
||
function sendReply(){
|
||
var t=document.getElementById("replyText").value.trim();
|
||
if(!t || !curSid) return;
|
||
fetch("/api/human/send",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(curSid),side:"agent",content:t})});
|
||
document.getElementById("replyText").value="";
|
||
document.getElementById("replyText").focus();
|
||
}
|
||
|
||
function quickReply(t){
|
||
document.getElementById("replyText").value=t;
|
||
sendReply();
|
||
}
|
||
|
||
function closeSession(){
|
||
fetch("/api/human/close",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(curSid)})});
|
||
delete sessions[curSid];
|
||
curSid=0;
|
||
document.getElementById("chatContent").style.display="none";
|
||
document.getElementById("emptyTip").style.display="flex";
|
||
renderList();
|
||
}
|
||
|
||
function transferSession(){
|
||
if(!curSid) return;
|
||
if(!confirm("确定转接这个对话?转接后其他客服可在排队列表接入。")) return;
|
||
fetch("/api/human/transfer",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(curSid)})}).then(function(){
|
||
delete sessions[curSid];
|
||
curSid=0;
|
||
document.getElementById("chatContent").style.display="none";
|
||
document.getElementById("emptyTip").style.display="flex";
|
||
renderList();
|
||
});
|
||
}
|
||
|
||
document.getElementById("replyText").addEventListener("keydown", function(e){
|
||
if(e.key==="Enter"){ e.preventDefault(); sendReply(); }
|
||
});
|
||
|
||
// 客服正在输入通知客户
|
||
var typeTimer = null;
|
||
document.getElementById("replyText").addEventListener("input", function(){
|
||
if(!curSid) return;
|
||
fetch("/api/human/typing",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(curSid)})});
|
||
clearTimeout(typeTimer);
|
||
typeTimer = setTimeout(function(){
|
||
fetch("/api/human/stop_typing",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sid:parseInt(curSid)})});
|
||
}, 3000);
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|