feat(admin): 添加客服手动接入会话功能并修复时长计算

- 新增 acceptSession 接口支持客服手动接入待分配会话
- 待接入列表显示"接入"按钮,点击后自动分配给当前客服
- 接入前检查客服会话数上限,防止超载
- 修复会话时长计算错误:Unix 时间戳需乘以 1000 转换为毫秒

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
li
2026-01-29 03:20:17 +08:00
co-authored by Claude Opus 4.5
parent a49f5e8de6
commit 626b428db1
2 changed files with 524 additions and 8 deletions
+61 -8
View File
@@ -162,6 +162,21 @@
color: #ddd;
margin-bottom: 10px;
}
.accept-btn {
padding: 4px 10px;
background: #009688;
color: #fff;
border: none;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
flex-shrink: 0;
margin-left: 8px;
transition: background 0.2s;
}
.accept-btn:hover {
background: #00796b;
}
/* 中间聊天区域 */
.chat-main {
@@ -766,7 +781,7 @@ layui.use(['layer', 'upload'], function(){
$.get('/chat/sessions', {status: 1}, function(res) {
if (res.code === 0) {
$('#active-count').text(res.data.length);
renderSessionList(res.data, '#session-list');
renderSessionList(res.data, '#session-list', false);
}
});
}
@@ -776,13 +791,13 @@ layui.use(['layer', 'upload'], function(){
$.get('/chat/pending', function(res) {
if (res.code === 0) {
$('#pending-count').text(res.data.length);
renderSessionList(res.data, '#pending-list');
renderSessionList(res.data, '#pending-list', true);
}
});
}
// 渲染会话列表
function renderSessionList(sessions, container) {
function renderSessionList(sessions, container, isPending) {
var html = '';
if (sessions.length === 0) {
html = '<div class="sessions-empty">';
@@ -803,20 +818,57 @@ layui.use(['layer', 'upload'], function(){
html += ' <div class="session-info">';
html += ' <div class="name-row">';
html += ' <span class="username">' + username + '</span>';
html += ' <span class="time">' + (session.last_msg_time_fmt || '') + '</span>';
html += ' <span class="time">' + (session.last_msg_time_fmt || session.create_time_fmt || '') + '</span>';
html += ' </div>';
html += ' <div class="last-msg">' + lastMsg + '</div>';
html += ' </div>';
html += unreadBadge;
if (isPending) {
html += ' <button class="accept-btn" data-id="' + session.id + '">接入</button>';
} else {
html += unreadBadge;
}
html += '</div>';
});
}
$(container).html(html);
// 绑定点击事件
$(container + ' .session-item').click(function() {
$(container + ' .session-item').click(function(e) {
// 如果点击的是接入按钮,不触发打开会话
if ($(e.target).hasClass('accept-btn')) return;
var sessionId = $(this).data('id');
openSession(sessionId);
if (!isPending) {
openSession(sessionId);
}
});
// 绑定接入按钮事件
if (isPending) {
$(container + ' .accept-btn').click(function(e) {
e.stopPropagation();
var sessionId = $(this).data('id');
acceptSession(sessionId);
});
}
}
// 接入会话
function acceptSession(sessionId) {
$.post('/chat/acceptSession', {session_id: sessionId}, function(res) {
if (res.code === 0) {
layer.msg('接入成功', {icon: 1, time: 1500});
loadSessions();
loadPendingSessions();
// 自动打开刚接入的会话
setTimeout(function() {
openSession(sessionId);
// 切换到进行中标签
$('.sessions-tabs .tab-item[data-status="1"]').click();
}, 500);
} else {
layer.msg(res.msg || '接入失败', {icon: 2});
loadPendingSessions();
}
});
}
@@ -877,7 +929,8 @@ layui.use(['layer', 'upload'], function(){
// 会话时长计时器
function startDurationTimer(startTime) {
if (durationTimer) clearInterval(durationTimer);
sessionStartTime = new Date(startTime).getTime();
// startTime 是 Unix 时间戳(秒),需要转换为毫秒
sessionStartTime = startTime * 1000;
function updateDuration() {
var now = Date.now();