Files
baiyue-logistics-chat/templates/admin.html
T
2026-11-02 17:51:10 +08:00

134 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="staff-csrf-token" content="{{ g.staff.csrf_token }}">
<meta name="staff-username" content="{{ g.staff.username }}">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>客服工作台 · 柏悦物流</title>
<link rel="icon" href="{{ url_for('static', filename='fa.jpg') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/theme.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/admin.css') }}">
</head>
<body>
<header class="topbar">
<div class="app-identity">
<a class="brand" href="/admin/dashboard"><span class="brand-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m4 7 8-4 8 4v10l-8 4-8-4Z"/><path d="m4 7 8 4 8-4M12 11v10M8 5l8 4"/></svg></span><span class="brand-name">柏悦物流</span></a>
<span class="nav-divider" aria-hidden="true"></span><h1>客服工作台</h1>
</div>
<div class="topbar-actions">
<span id="nightBadge" class="night-badge" hidden>非工作时段</span>
<button id="ticket-inbox-toggle" class="ticket-inbox-toggle" type="button" aria-label="查看待处理留言" aria-controls="service-tools">留言 <span id="ticket-pending-count">—</span></button>
<button id="ticket-overdue-toggle" class="ticket-overdue-toggle" type="button" aria-label="查看超时留言" aria-controls="service-tools">超时 <span id="ticket-overdue-count">—</span></button>
<button id="notifications-toggle" class="icon-button" type="button" aria-label="开启浏览器通知" title="开启浏览器通知" aria-pressed="false">🔔</button>
<a class="workspace-link" href="/">客户入口 ↗</a>
<details class="data-overview" id="data-overview">
<summary><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M4 4v16h17M8 16v-5M13 16V7M18 16V3"/></svg>数据概览</summary>
<div class="stats" aria-label="历史对话统计">
<h2>历史对话与反馈</h2>
<div class="stat"><span>历史对话</span><b id="s1">—</b></div>
<div class="stat"><span>历史消息</span><b id="s2">—</b></div>
<div class="stat"><span>今日新对话</span><b id="s3">—</b></div>
<div class="stat"><span>有帮助</span><b id="s4">—</b></div>
<div class="stat"><span>需改进</span><b id="s5">—</b></div>
<div class="stat"><span>服务评价</span><b id="s6">—</b></div>
<a class="export-link" href="/api/export_chat">导出 Excel ↗</a>
</div>
</details>
<button id="staff-logout" class="staff-logout" type="button">退出登录</button>
</div>
</header>
<div id="staff-logout-status" class="sync-status" role="alert" hidden></div>
<div id="sync-status" class="sync-status" role="status" hidden>会话连接中断,正在重试…</div>
<div id="ticket-alert" class="ticket-alert" role="status" aria-live="polite" hidden><span id="ticket-alert-text"></span><button id="ticket-alert-view" type="button" class="ticket-action">查看待处理留言</button></div>
<main class="layout">
<aside class="conv-list" id="session-browser" aria-label="会话列表">
<div class="list-heading">
<h2>客户会话</h2><p>查看咨询,及时接待与回复</p>
<div class="session-search-wrap"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 4 4"/></svg><input id="session-search" type="search" aria-label="搜索客户会话" placeholder="搜索会话或消息" autocomplete="off"></div>
<button id="history-search-toggle" class="text-button" type="button">搜索历史记录 ↗</button>
</div>
<div class="session-tabs" role="tablist" aria-label="会话状态">
<button id="tab-active" type="button" role="tab" aria-selected="true" aria-controls="sessionList">接待中 <span id="active-count" class="section-count">0</span></button>
<button id="tab-queue" type="button" role="tab" aria-selected="false" aria-controls="queue" tabindex="-1">排队中 <span id="queue-count" class="section-count">0</span><span id="queue-overdue-count" class="queue-overdue-count">超时 0</span></button>
</div>
<div class="session-scroll">
<div id="sessionList" role="tabpanel" aria-labelledby="tab-active"><div class="list-empty">暂无进行中的会话</div></div>
<div id="queue" role="tabpanel" aria-labelledby="tab-queue" hidden><div class="list-empty">正在加载会话…</div></div>
</div>
<div class="list-footer"><span><span class="list-footer-mark" aria-hidden="true"></span>柏悦物流 · 客户服务</span><button id="tools-from-list" type="button" aria-controls="service-tools" aria-expanded="false">服务资料</button></div>
</aside>
<section class="chat-area" id="chatArea" aria-label="会话内容">
<header class="chat-header">
<button id="sessions-back" class="sessions-back" type="button" aria-label="返回会话列表">‹</button>
<div class="participant-avatar" aria-hidden="true">客</div>
<div class="participant-copy"><h2 id="chatTitle">会话接待</h2><p id="chat-subtitle">选择一段会话,开始回复客户</p></div>
<div class="chat-header-actions">
<button id="tools-toggle" class="tools-toggle" type="button" aria-label="资料与快捷回复" aria-controls="service-tools" aria-expanded="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><rect x="4" y="3" width="16" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="M6 16a3 3 0 0 1 6 0M14 8h3M14 12h3M14 16h3"/></svg><span>资料与回复</span></button>
<button id="transfer-session" class="close" type="button" onclick="transferSession()">转接</button>
<button id="close-session" class="close" type="button" onclick="closeSession()">结束会话</button>
</div>
</header>
<div class="empty" id="emptyTip"><div>
<div class="empty-illustration"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m4 7 8-4 8 4v10l-8 4-8-4Z"/><path d="m4 7 8 4 8-4M12 11v10M8 5l8 4"/></svg></div>
<h2>选择会话,开始接待</h2><p>在会话列表查看客户咨询,<br>新咨询可从「排队中」接入。</p>
</div></div>
<div id="chatContent" class="session-panel" style="display:none">
<div id="chatBox" role="log" aria-live="polite" aria-label="会话消息"></div>
<footer class="agent-composer">
<div class="composer-heading"><label for="replyText">回复客户</label><div class="emoji-control"><button id="agent-emoji-toggle" class="text-button" type="button" aria-label="选择表情" aria-expanded="false" aria-controls="agent-emoji-panel">😊 表情</button><div id="agent-emoji-panel" class="emoji-picker" hidden></div></div><span>Shift + Enter 换行</span></div>
<div class="input-bar">
<textarea id="replyText" rows="2" aria-label="回复客户" placeholder="输入回复内容,按 Enter 发送…"></textarea>
<div class="input-actions"><span>常用回复可在「资料与回复」中选择</span><button id="reply-send" type="button" onclick="sendReply()">发送</button></div>
</div>
<p id="reply-status" class="reply-status" role="status" hidden></p>
</footer>
</div>
</section>
<aside class="side" id="service-tools" aria-label="客户信息与回复" aria-hidden="true" inert>
<header class="side-heading"><h2>服务资料</h2><button id="tools-close" type="button" class="icon-button" aria-label="关闭服务资料">×</button></header>
<section class="card"><h3>客户信息</h3><div class="info-row" id="cInfo">选择会话后查看客户信息</div><p class="info-hint">咨询运费时,可先确认运单号、货物重量、尺寸与目的地。</p></section>
<section class="card"><h3><label for="noteInput">会话备注</label></h3><textarea id="noteInput" class="note-input" rows="3" placeholder="填写本次会话的跟进事项" disabled></textarea><button id="note-save" type="button" class="quick" disabled>保存备注</button></section>
<section class="card"><h3>常用回复</h3>
<p class="card-caption">点击填入草稿,编辑后再发送</p>
<button type="button" class="quick" onclick="quickReply('您好,请问有什么可以帮您?')">您好,有什么可以帮您?</button>
<button type="button" class="quick" onclick="quickReply('请提供运单号,我帮您查询。')">请提供运单号,我帮您查询</button>
<button type="button" class="quick" onclick="quickReply('已为您催促,请稍候。')">已为您催促,请稍候</button>
<button type="button" class="quick" onclick="quickReply('感谢您的咨询,祝您生活愉快!')">感谢咨询,祝您生活愉快</button>
</section>
<section class="card ticket-workspace" aria-labelledby="tickets-title">
<div class="ticket-row"><h3 id="tickets-title">离线留言</h3><span id="ticket-section-count" class="ticket-section-count">待处理 —</span></div>
<p id="ticket-summary-status" class="ticket-summary-status" role="status"></p>
<p class="ticket-timing-rule">超时提醒:30 分钟未领取,或领取后 20 分钟未完成。</p>
<form id="ticket-search-form" class="ticket-search-form" role="search" aria-label="搜索离线留言">
<label for="ticket-search">搜索留言</label><input id="ticket-search" type="search" maxlength="100" placeholder="手机号、关键词、负责人或备注" autocomplete="off">
<div class="ticket-search-actions"><button id="ticket-search-submit" type="submit" class="ticket-action ticket-primary">搜索</button><button id="ticket-search-clear" type="button" class="ticket-action" hidden>清除搜索</button></div>
</form>
<div class="ticket-toolbar"><label for="ticket-filter">状态</label><select id="ticket-filter"><option value="all">全部</option><option value="pending">待处理</option><option value="processing">处理中</option><option value="completed">已完成</option></select><label class="ticket-overdue-filter"><input id="ticket-overdue-filter" type="checkbox"> 只看超时</label><button id="ticket-refresh" type="button" class="ticket-action">刷新</button></div>
<div id="ticketList"><div class="list-empty">正在加载留言…</div></div>
<button id="ticket-more" type="button" class="ticket-action" hidden>加载更早留言</button>
<div id="ticket-selected" class="ticket-detail" hidden>
<div class="ticket-row"><h4>留言详情</h4><span id="ticket-state" class="ticket-state"></span></div>
<p id="ticket-meta" class="ticket-meta"></p><p id="ticket-content" class="ticket-content"></p>
<p id="ticket-owner" class="ticket-owner"></p><p id="ticket-overdue-hint" class="ticket-overdue-hint" hidden></p>
<label for="ticket-note" class="ticket-note-label">处理备注</label>
<textarea id="ticket-note" rows="4" maxlength="2000" placeholder="记录联系情况、处理结果或后续跟进事项" readonly></textarea>
<p id="ticket-server-note" class="ticket-server-note" hidden></p>
<button id="ticket-rebase" type="button" class="ticket-action" hidden>已核对,使用我的备注</button>
<div class="ticket-actions"><button id="ticket-claim" type="button" class="ticket-action ticket-primary" hidden>领取留言</button><button id="ticket-save" type="button" class="ticket-action" hidden>保存备注</button><button id="ticket-complete" type="button" class="ticket-action ticket-primary" hidden>标记已完成</button></div>
<p id="ticket-activity" class="ticket-meta"></p>
<section id="ticket-history" class="ticket-history" aria-labelledby="ticket-history-title"><div class="ticket-row"><h4 id="ticket-history-title">处理记录</h4><button id="ticket-history-reload" type="button" class="ticket-action">刷新记录</button></div><p id="ticket-history-status" class="ticket-meta" role="status"></p><ol id="ticket-history-list" class="ticket-history-list"></ol><button id="ticket-history-more" type="button" class="ticket-action" hidden>加载更早记录</button></section>
</div>
<p id="ticket-status-message" class="ticket-feedback" role="status" aria-live="polite"></p>
</section>
</aside>
</main>
<button class="tools-backdrop" id="tools-backdrop" type="button" aria-label="关闭服务资料"></button>
<dialog id="searchResult" class="search-dialog" aria-labelledby="search-title"><header><h2 id="search-title">搜索历史记录</h2><button id="search-close" class="icon-button" type="button" aria-label="关闭搜索">×</button></header><form id="history-search-form"><label class="sr-only" for="searchBox">历史消息关键词</label><input id="searchBox" type="search" placeholder="输入关键词搜索聊天记录" required><button type="submit" class="quick">搜索</button></form><div id="searchBody" aria-live="polite">请输入关键词搜索历史消息</div></dialog>
<script src="{{ url_for('static', filename='js/support.js') }}"></script>
<script src="{{ url_for('static', filename='js/admin_tools.js') }}"></script>
<script src="{{ url_for('static', filename='js/admin_tickets.js') }}"></script>
<script src="{{ url_for('static', filename='js/admin.js') }}"></script>
</body>
</html>