Files
wecom_it_smart_desk/docs/01-产品文档/02-会话管理/原型-REQ-会话-001-整合区方案A-v1.3.html
T
Simon 44e77dcb0e chore(docs): docs/ 目录全面重新编号 + 重组
**重构前**(旧编号 02-11):
- docs/02-产品需求/      → 00 产品规划/PRD
- docs/03-技术架构/      → 01-05 子目录散落
- docs/04-原型设计/      → 01-02 产品设计(HTML 原型)
- docs/05-原型设计/      → screens/
- docs/06-测试素材/      → 02-E2E / 03-功能 / 04-版本测试
- docs/07-项目管理/      → 任务说明书/日报/计划
- docs/08-安全审计/      → 审计报告
- docs/09-堡垒运维/      → toolbox / deploy
- docs/10-项目管理/      → 任务说明书(重复)
- docs/11-历史归档/      → deploy-nas-archived

**重构后**(新编号 00-07,语义化):
- docs/00-产品开发流程与文档管理规范.md
- docs/00-版本迭代总览.md
- docs/01-产品文档/      (PRD/原型/认证/会话/AI 服务/坐席/集成)
- docs/02-技术文档/      (技术方案/架构图/重构记录/前端改造/实现配置)
- docs/03-测试文档/      (E2E/功能用例/版本报告/缺陷单)
- docs/04-运维文档/      (部署运维/运维指南)
- docs/05-运营文档/      (品牌推广/用户手册)
- docs/06-安全审计/      (审计报告)
- docs/07-项目管理/      (任务说明书/日报/计划/看板)

**净收益**:
- 目录编号与产品文档管理规范对齐(按文档阶段 01-07 编号)
- 消除 02-产品需求 与 10-项目管理 的编号重叠
- 子目录按文档类型分组(如 01-产品文档/00-产品规划、01-产品文档/01-认证与登录)
- 把运维/安全/项目管理从 0X 散落改为 04/06/07

合计 494 文件 + 78495 行 / - 14076 行
2026-08-03 18:46:55 +08:00

523 lines
26 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="viewport" content="width=device-width, initial-scale=1.0" />
<title>方案 A · 整合至 QueueCapsule 区域 · REQ-会话-001 v1.3</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body { font-family: -apple-system, "PingFang SC", "Helvetica Neue", Arial, sans-serif; }
.phone-frame {
width: 360px; height: 720px; border-radius: 32px;
border: 8px solid #1f2937; box-shadow: 0 10px 30px rgba(0,0,0,0.15);
overflow: hidden; background: #f3f4f6; position: relative;
}
.phone-status { height: 28px; background: #f3f4f6; display: flex; align-items: center; justify-content: space-between; padding: 0 16px; font-size: 11px; font-weight: 600; color: #1f2937; }
.header { height: 56px; background: white; display: flex; align-items: center; justify-content: space-between; padding: 0 16px; border-bottom: 1px solid #e5e7eb; }
.messages { height: calc(100% - 56px - 200px); overflow-y: auto; padding: 12px; background: #f9fafb; }
.msg-bubble { max-width: 70%; padding: 8px 12px; border-radius: 12px; margin-bottom: 8px; font-size: 13px; line-height: 1.5; }
.msg-ai { background: white; border: 1px solid #e5e7eb; margin-right: auto; }
.msg-user { background: #2563eb; color: white; margin-left: auto; }
.msg-system { background: #f3f4f6; color: #6b7280; text-align: center; margin: 8px auto; max-width: 90%; font-size: 12px; }
.integration-zone {
background: white; border-top: 1px solid #e5e7eb; padding: 12px;
display: flex; flex-direction: column; gap: 8px;
}
.status-strip {
display: flex; align-items: center; justify-content: space-between;
padding: 6px 10px; border-radius: 8px; font-size: 12px;
}
.status-online { background: #f0fdf4; color: #166534; }
.status-busy { background: #fff7ed; color: #9a3412; }
.status-offline { background: #f3f4f6; color: #6b7280; }
.call-btn {
display: flex; align-items: center; justify-content: center; gap: 6px;
padding: 10px 14px; border-radius: 8px; font-weight: 600; font-size: 14px;
border: none; cursor: pointer; transition: all 0.2s;
}
.btn-active { background: #22c55e; color: white; }
.btn-urgent { background: #dc2626; color: white; animation: pulse 1.5s infinite; }
.btn-disabled { background: #e5e7eb; color: #9ca3af; cursor: not-allowed; }
.btn-waiting { background: #f59e0b; color: white; }
.btn-end { background: #dc2626; color: white; }
.btn-reopen { background: #3b82f6; color: white; }
@keyframes pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(220,38,38,0.5); } 50% { box-shadow: 0 0 0 6px rgba(220,38,38,0); } }
.progress-capsule {
display: flex; align-items: center; gap: 8px; padding: 6px 12px;
border-radius: 999px; font-size: 12px; font-weight: 500;
}
.capsule-queued { background: #fef3c7; color: #92400e; }
.capsule-serving { background: #d1fae5; color: #065f46; }
.capsule-resolved { background: #f3f4f6; color: #6b7280; }
.inputbar {
background: white; border-top: 1px solid #e5e7eb; padding: 10px 12px;
display: flex; align-items: center; gap: 8px;
}
.input-bar-input {
flex: 1; padding: 8px 12px; border: 1px solid #e5e7eb; border-radius: 8px; font-size: 13px;
}
.send-btn {
background: #2563eb; color: white; padding: 8px 14px; border-radius: 8px; font-weight: 600; font-size: 13px;
border: none; cursor: pointer;
}
.tab-btn {
padding: 8px 14px; border-radius: 8px; font-size: 13px; cursor: pointer; border: 1px solid #e5e7eb;
background: white; transition: all 0.15s;
}
.tab-btn.active { background: #2563eb; color: white; border-color: #2563eb; }
.scene-title { font-size: 14px; font-weight: 600; color: #374151; }
.annotation {
background: #fef3c7; border-left: 3px solid #f59e0b; padding: 8px 12px;
font-size: 12px; color: #78350f; border-radius: 4px; margin-top: 8px;
}
.annotation-blue {
background: #eff6ff; border-left: 3px solid #3b82f6; padding: 8px 12px;
font-size: 12px; color: #1e3a8a; border-radius: 4px; margin-top: 8px;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="max-w-7xl mx-auto px-6 py-8">
<!-- Header -->
<div class="mb-8">
<div class="text-xs text-blue-600 font-semibold mb-2">REQ-会话-001 · v1.3 增量优化</div>
<h1 class="text-3xl font-bold text-gray-900 mb-3">方案 A · 人工服务整合区设计</h1>
<p class="text-sm text-gray-600 max-w-3xl">
将"坐席状态 + 操作按钮 + 进度消息"三件套统一整合至消息流与 InputBar 之间的整合区。
标题栏去除坐席徽章(瘦身);InputBar 移除操作按钮(释放工具栏空间)。
</p>
<div class="mt-3 flex flex-wrap gap-2 text-xs">
<span class="px-2 py-1 bg-green-100 text-green-700 rounded">🆕 新增:整合区永久状态条</span>
<span class="px-2 py-1 bg-blue-100 text-blue-700 rounded">🔄 迁移:操作按钮从 InputBar 移至整合区</span>
<span class="px-2 py-1 bg-purple-100 text-purple-700 rounded">✂️ 简化:标题栏移除坐席徽章</span>
<span class="px-2 py-1 bg-orange-100 text-orange-700 rounded">⚡ 优化:InputBar 工具栏更简洁</span>
</div>
</div>
<!-- 场景 Tab -->
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<div class="flex flex-wrap gap-2 mb-6" id="tabs">
<button class="tab-btn active" data-scene="0">🆕 无会话</button>
<button class="tab-btn" data-scene="1">💬 AI < 3 </button>
<button class="tab-btn" data-scene="2">✅ AI ≥ 3 轮</button>
<button class="tab-btn" data-scene="3">🚨 紧急关键词</button>
<button class="tab-btn" data-scene="4">🔴 坐席离线</button>
<button class="tab-btn" data-scene="5">⏳ 排队中</button>
<button class="tab-btn" data-scene="6">📞 已接入</button>
<button class="tab-btn" data-scene="7">🔄 重新打开</button>
<button class="tab-btn" data-scene="8">⏰ 会话过期</button>
</div>
<!-- 当前场景标题 -->
<div class="mb-4">
<div class="scene-title" id="scene-title">场景 1:无会话(刚打开应用)</div>
<div class="text-xs text-gray-500 mt-1" id="scene-desc"></div>
</div>
<!-- Mockup Container -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- 手机框 -->
<div class="lg:col-span-1 flex justify-center">
<div class="phone-frame">
<div class="phone-status">
<span>9:41</span>
<span>📶 📡 🔋</span>
</div>
<!-- Header -->
<div class="header">
<div class="flex items-center gap-2">
<span class="bg-blue-600 text-white text-xs font-bold px-2 py-0.5 rounded">IT</span>
<span class="font-semibold text-sm text-gray-900">智能IT服务</span>
</div>
<div class="flex items-center gap-3">
<button class="text-lg">☀️🌙</button>
<div class="w-6 h-6 rounded-full bg-gray-300"></div>
</div>
</div>
<!-- Messages -->
<div class="messages" id="messages">
<!-- dynamic -->
</div>
<!-- 整合区(人工服务专区) -->
<div class="integration-zone" id="integration-zone">
<!-- dynamic -->
</div>
<!-- InputBar(已简化:无人工坐席按钮) -->
<div class="inputbar">
<button class="text-xl">😊</button>
<button class="text-xl">📎</button>
<input class="input-bar-input" placeholder="输入消息..." readonly />
<button class="send-btn">发送</button>
</div>
</div>
</div>
<!-- 右侧:场景描述 + 交互细节 -->
<div class="lg:col-span-2 space-y-4">
<div class="bg-gray-50 rounded-lg p-5">
<div class="text-xs font-semibold text-gray-500 uppercase mb-2">整合区结构</div>
<div class="text-sm text-gray-700 leading-relaxed" id="zone-structure">
<!-- dynamic -->
</div>
</div>
<div class="bg-gray-50 rounded-lg p-5">
<div class="text-xs font-semibold text-gray-500 uppercase mb-2">交互逻辑</div>
<div class="text-sm text-gray-700 leading-relaxed" id="interaction-logic">
<!-- dynamic -->
</div>
</div>
<div class="bg-blue-50 border-l-4 border-blue-500 rounded p-4">
<div class="text-xs font-semibold text-blue-700 uppercase mb-2">💡 设计原则</div>
<ul class="text-sm text-gray-700 space-y-1 leading-relaxed">
<li><b>三件套垂直堆叠</b>:状态条(永久)+ 操作按钮(核心 CTA)+ 进度消息(按需)</li>
<li><b>状态条保底可见</b>:永远告诉用户"现在能不能叫到人",减少焦虑</li>
<li><b>按钮位置迁移</b>:从 InputBar 工具栏搬到整合区,避免工具栏拥挤</li>
<li><b>标题栏瘦身</b>:移除坐席徽章,主标题 + 主题 + 头像 + 退出 更简洁</li>
<li><b>不动 v1.2y 已 PASS</b>:6 态按钮、引导语、坐席离线拦截、取消入口合并、淡出 全部保持</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 移动端适配 -->
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mt-6">
<h2 class="text-lg font-bold text-gray-900 mb-4">📱 移动端适配</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<div class="text-xs font-semibold text-gray-500 uppercase mb-2">≥500px(桌面/横屏)</div>
<div class="bg-gray-50 rounded p-3 text-xs text-gray-700">
<div class="bg-white border border-gray-300 rounded px-3 py-2 mb-1 flex justify-between">
<span>🟢 客服在线 · 3人空闲</span>
<span class="text-gray-400">●●●</span>
</div>
<div class="bg-green-500 text-white rounded-lg px-3 py-2 mb-1 text-center font-semibold">
🎧 呼叫人工坐席
</div>
<div class="bg-orange-100 text-orange-800 rounded-full px-3 py-1 text-center text-xs">
🟠 排队中 · 前面 2 人 · 预计约 1 分钟
</div>
</div>
<div class="annotation mt-2">整合区与消息流等宽,所有元素水平居中</div>
</div>
<div>
<div class="text-xs font-semibold text-gray-500 uppercase mb-2">&lt;500px(手机)</div>
<div class="bg-gray-50 rounded p-3 text-xs text-gray-700 max-w-[280px]">
<div class="bg-white border border-gray-300 rounded px-3 py-2 mb-1 flex justify-between">
<span class="text-xs">🟢 客服在线 · 3人空闲</span>
</div>
<div class="bg-green-500 text-white rounded-lg px-3 py-2 mb-1 text-center font-semibold text-sm">
🎧 呼叫人工坐席
</div>
<div class="bg-orange-100 text-orange-800 rounded-full px-3 py-1 text-center text-xs">
🟠 排队中 · 前面 2 人
</div>
</div>
<div class="annotation-blue mt-2">文字精简("3 人空闲"→"空闲"),进度文案缩短(去预计时长)</div>
</div>
</div>
</div>
<!-- 与 v1.2y 对比 -->
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mt-6">
<h2 class="text-lg font-bold text-gray-900 mb-4">🔄 方案 A vs v1.2y 当前状态对比</h2>
<table class="w-full text-sm">
<thead class="bg-gray-50">
<tr>
<th class="text-left px-3 py-2">位置</th>
<th class="text-left px-3 py-2">v1.2y 现状</th>
<th class="text-left px-3 py-2">v1.3 方案 A</th>
<th class="text-left px-3 py-2">变化</th>
</tr>
</thead>
<tbody class="divide-y">
<tr>
<td class="px-3 py-2">标题栏</td>
<td class="px-3 py-2">logo + 标题 + 🟢坐席状态 + 主题 + 头像 + 退出</td>
<td class="px-3 py-2">logo + 标题 + 主题 + 头像 + 退出</td>
<td class="px-3 py-2 text-green-600">- 1 元素(坐席状态)</td>
</tr>
<tr>
<td class="px-3 py-2">整合区(永久)</td>
<td class="px-3 py-2"></td>
<td class="px-3 py-2">🟢 客服在线 · 3人空闲 状态条</td>
<td class="px-3 py-2 text-blue-600">+ 1 永久元素</td>
</tr>
<tr>
<td class="px-3 py-2">整合区(按钮)</td>
<td class="px-3 py-2"></td>
<td class="px-3 py-2">🎧 人工坐席 6 态按钮(从 InputBar 搬过来)</td>
<td class="px-3 py-2 text-blue-600">+ 1 按钮(迁移)</td>
</tr>
<tr>
<td class="px-3 py-2">整合区(按需)</td>
<td class="px-3 py-2">QueueCapsule 4 态独立显示</td>
<td class="px-3 py-2">QueueCapsule 4 态整合到整合区</td>
<td class="px-3 py-2 text-purple-600">位置迁移</td>
</tr>
<tr>
<td class="px-3 py-2">InputBar 工具栏</td>
<td class="px-3 py-2">😊📎[输入框][🎧人工坐席][发送]</td>
<td class="px-3 py-2">😊📎[输入框][发送]</td>
<td class="px-3 py-2 text-orange-600">- 1 元素(按钮)</td>
</tr>
</tbody>
</table>
</div>
<!-- 关键交互细节 -->
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mt-6">
<h2 class="text-lg font-bold text-gray-900 mb-4">⚙️ 关键交互细节</h2>
<div class="space-y-3 text-sm text-gray-700">
<div class="flex items-start gap-3">
<span class="px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded font-semibold mt-0.5">R1</span>
<div>
<b>状态条保底可见</b>:无论 AI 对话进度、坐席在线状态、操作按钮态如何变化,状态条始终显示。
文案分三态:🟢 客服在线 · N 人空闲 / 🔴 客服暂休 · HH:MM 开放 / 🟡 客服繁忙 · 预计 N 分钟
</div>
</div>
<div class="flex items-start gap-3">
<span class="px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded font-semibold mt-0.5">R2</span>
<div>
<b>操作按钮 6 态保持</b>disabled / active / urgent / waiting / end / reopen
waiting 态文案"排队取消"v1.2y 已拍板);end 态文案"结束咨询"reopen 态文案"重新打开"
</div>
</div>
<div class="flex items-start gap-3">
<span class="px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded font-semibold mt-0.5">R3</span>
<div>
<b>进度消息按需显示</b>:无排队时隐藏;queued 显示"🟠 排队中 · 前面 N 人"serving 显示"🟢 已接入"3 秒淡出);resolved 显示"会话已关闭"
</div>
</div>
<div class="flex items-start gap-3">
<span class="px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded font-semibold mt-0.5">R4</span>
<div>
<b>引导语去哪了?</b>v1.2y 在 InputBar 显示的 4 种引导语(无会话/AI<3轮/坐席离线/会话过期
整合到整合区底部作为按钮下方的灰色小字"再多说几句""坐席当前离线"
</div>
</div>
<div class="flex items-start gap-3">
<span class="px-2 py-0.5 bg-blue-100 text-blue-700 text-xs rounded font-semibold mt-0.5">R5</span>
<div>
<b>InputBar 引导语移除</b>:原 InputBar 的 `input-bar__guide` 提示改为整合区的灰色小字,避免与按钮态视觉冲突
</div>
</div>
</div>
</div>
<!-- 待用户决策 -->
<div class="bg-yellow-50 border-l-4 border-yellow-500 rounded-lg p-5 mt-6">
<div class="text-sm font-semibold text-yellow-800 mb-2">⏳ 待你拍板的细节</div>
<ul class="text-sm text-gray-700 space-y-1">
<li>1. 状态条永久显示是否 OK?还是要"轻量"只在必要时显示?</li>
<li>2. 状态条文案要不要"空闲人数"(如"3 人空闲")?还是只显示"客服在线"?</li>
<li>3. 整合区背景色用浅灰还是浅蓝?或透明无背景?</li>
<li>4. 引导语(4 种场景文案)放整合区按钮下方,还是继续放 InputBar?</li>
<li>5. 整合区在移动端是否需要抽屉式折叠?(空间紧张时)</li>
</ul>
</div>
</div>
<script>
// 场景配置
const scenes = [
{
title: '场景 1:无会话(刚打开应用)',
desc: '用户首次打开 H5,未与 AI 对话过',
messages: '<div class="msg-bubble msg-system">💡 开始新对话</div>',
zone: {
status: { tone: 'offline', text: '⚪ 客服暂休 · 9:00 开放' },
btn: { state: 'disabled', icon: '🔒', text: '人工坐席' },
guide: '请描述你遇到的问题,AI 助手会先帮你看看',
capsule: null,
},
structure: '状态条(暂休)→ 按钮(disabled 灰色)→ 引导语',
logic: '按钮 disabled 但仍可见(v1.2 设计原则:按钮永不下沉)。引导语引导用户先说问题。',
},
{
title: '场景 2AI 对话 < 3 轮',
desc: '用户已发 2 条消息,AI 回复了 2 轮',
messages: `
<div class="msg-bubble msg-user">电脑无法启动</div>
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>请尝试以下步骤:<br/>1. 检查电源线...<br/>2. 拔掉电池...</div>
<div class="msg-bubble msg-user">试过了没用</div>
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>好的,请问屏幕有显示吗?</div>
`,
zone: {
status: { tone: 'online', text: '🟢 客服在线 · 3 人空闲' },
btn: { state: 'disabled', icon: '🔒', text: '人工坐席' },
guide: '请继续描述您的问题或需求',
capsule: null,
},
structure: '状态条(在线)→ 按钮(disabled 灰色)→ 引导语(继续描述)',
logic: '坐席在线但按钮仍 disabled< 3 轮 AI 回复不足),引导语鼓励用户继续与 AI 对话',
},
{
title: '场景 3AI 对话 ≥ 3 轮',
desc: 'AI 已回复 3 轮,可以呼叫人工',
messages: `
<div class="msg-bubble msg-user">电脑无法启动</div>
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>请尝试以下步骤:...</div>
<div class="msg-bubble msg-user">试过了没用</div>
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>屏幕有显示吗?</div>
<div class="msg-bubble msg-user">没有</div>
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>好的,请问是笔记本还是台式机?</div>
<div class="msg-bubble msg-user">笔记本</div>
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>看起来可能是主板问题,建议呼叫人工坐席处理</div>
`,
zone: {
status: { tone: 'online', text: '🟢 客服在线 · 3 人空闲' },
btn: { state: 'active', icon: '🎧', text: '呼叫人工坐席' },
guide: null,
capsule: null,
},
structure: '状态条(在线)→ 按钮(active 绿色,可点击)',
logic: 'AI 达到 3 轮后按钮变为可点击的 active 态,引导语消失(不需要催促)',
},
{
title: '场景 4:紧急关键词触发',
desc: '用户输入"开不了机""上不了网"等紧急关键词',
messages: `
<div class="msg-bubble msg-user">无法上网,全公司断网</div>
<div class="msg-bubble msg-system">🚨 检测到紧急关键词,已为您直接呼叫人工</div>
`,
zone: {
status: { tone: 'online', text: '🟢 客服在线 · 3 人空闲' },
btn: { state: 'urgent', icon: '🚨', text: '紧急呼叫' },
guide: null,
capsule: null,
},
structure: '状态条(在线)→ 按钮(urgent 红色脉冲)',
logic: '检测到紧急关键词后直接呼叫(绕过 3 轮限制),按钮红色脉冲提示紧急性',
},
{
title: '场景 5:坐席离线',
desc: '客服下班或全部离线',
messages: `
<div class="msg-bubble msg-user">电脑无法启动</div>
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>请尝试以下步骤:...</div>
`,
zone: {
status: { tone: 'offline', text: '🔴 客服离线 · 9:00 上班' },
btn: { state: 'disabled', icon: '🔒', text: '人工坐席' },
guide: '⚠️ 客服当前离线,建议先用 AI 解答',
capsule: null,
},
structure: '状态条(离线)→ 按钮(disabled 灰色)→ 引导语(建议 AI',
logic: '即使点按钮也会被 shakeAgent agentOnline=false 拦截(v1.2y 已修),引导语解释原因',
},
{
title: '场景 6:排队等待中',
desc: '用户点击呼叫后进入排队',
messages: `
<div class="msg-bubble msg-ai">🤖 AI 助手<br/>已为您接入队列,请耐心等待...</div>
<div class="msg-bubble msg-system">⏳ 您已进入排队队列,位置 #5</div>
`,
zone: {
status: { tone: 'online', text: '🟢 客服在线 · 2 人空闲' },
btn: { state: 'waiting', icon: '⏳', text: '排队取消' },
guide: null,
capsule: { tone: 'queued', text: '🟠 排队中 · 前面 2 人 · 预计 1 分钟' },
},
structure: '状态条 → 按钮(waiting 橙色)→ 进度胶囊(queued',
logic: '按钮文案"排队取消"(v1.2y 已拍板);胶囊不可点击(v1.2y 优化);取消只能通过按钮',
},
{
title: '场景 7:已接入(坐席服务中)',
desc: '坐席小王接听,进入人工服务',
messages: `
<div class="msg-bubble msg-system">📞 客服小王已接入服务</div>
<div class="msg-bubble msg-ai">👤 客服小王<br/>您好,我是小王,请问电脑具体什么问题?</div>
`,
zone: {
status: { tone: 'online', text: '🟢 客服在线 · 2 人空闲' },
btn: { state: 'end', icon: '📴', text: '结束咨询' },
guide: null,
capsule: { tone: 'serving', text: '🟢 已接入 · 客服小王' },
},
structure: '状态条 → 按钮(end 红色)→ 进度胶囊(serving 绿色,3 秒后淡出)',
logic: '按钮"结束咨询"v1.2y 恢复 end 态);胶囊 3 秒后自动淡出(v1.2x 已修)',
},
{
title: '场景 8:会话已关闭(24h 内)',
desc: '用户结束会话后 5 小时重新进入',
messages: `
<div class="msg-bubble msg-system">会话已关闭。24 小时内可重新打开。</div>
`,
zone: {
status: { tone: 'online', text: '🟢 客服在线 · 3 人空闲' },
btn: { state: 'reopen', icon: '🔄', text: '重新打开' },
guide: null,
capsule: { tone: 'resolved', text: '会话已关闭(5 小时前)' },
},
structure: '状态条 → 按钮(reopen 蓝色)→ 进度胶囊(resolved 灰色)',
logic: '按钮点击触发 store.reopenCurrentConversation;胶囊点击也能 reopen(双入口)',
},
{
title: '场景 9:会话过期(>24h',
desc: '上次会话结束已超过 24h',
messages: `
<div class="msg-bubble msg-system">💡 开始新对话</div>
`,
zone: {
status: { tone: 'online', text: '🟢 客服在线 · 3 人空闲' },
btn: { state: 'disabled', icon: '🔒', text: '人工坐席' },
guide: '⏰ 上一会话已过期,开始新对话吧',
capsule: null,
},
structure: '状态条 → 按钮(disabled 灰色)→ 引导语(过期)',
logic: '按钮 disabled(无会话),引导语告知会话过期',
},
];
let currentScene = 0;
function renderScene(idx) {
const s = scenes[idx];
document.getElementById('scene-title').textContent = s.title;
document.getElementById('scene-desc').textContent = s.desc;
document.getElementById('messages').innerHTML = s.messages;
// Zone
let zoneHtml = '';
// Status strip
const statusToneMap = { online: 'status-online', busy: 'status-busy', offline: 'status-offline' };
zoneHtml += `<div class="status-strip ${statusToneMap[s.zone.status.tone]}"><span>${s.zone.status.text}</span><span class="text-gray-400 text-xs">●●●</span></div>`;
// Button
const btnClassMap = {
active: 'btn-active', urgent: 'btn-urgent', disabled: 'btn-disabled',
waiting: 'btn-waiting', end: 'btn-end', reopen: 'btn-reopen'
};
zoneHtml += `<button class="call-btn ${btnClassMap[s.zone.btn.state]}">${s.zone.btn.icon} ${s.zone.btn.text}</button>`;
// Guide (if any)
if (s.zone.guide) {
zoneHtml += `<div class="text-xs text-gray-500 px-2">${s.zone.guide}</div>`;
}
// Capsule (if any)
if (s.zone.capsule) {
const capsuleToneMap = { queued: 'capsule-queued', serving: 'capsule-serving', resolved: 'capsule-resolved' };
zoneHtml += `<div class="progress-capsule ${capsuleToneMap[s.zone.capsule.tone]}"><span class="w-2 h-2 rounded-full bg-current opacity-60"></span>${s.zone.capsule.text}</div>`;
}
document.getElementById('integration-zone').innerHTML = zoneHtml;
// Right side
document.getElementById('zone-structure').innerHTML = s.structure;
document.getElementById('interaction-logic').innerHTML = s.logic;
// Update tab active
document.querySelectorAll('.tab-btn').forEach((btn, i) => {
btn.classList.toggle('active', i === idx);
});
}
document.querySelectorAll('.tab-btn').forEach((btn, i) => {
btn.addEventListener('click', () => {
currentScene = i;
renderScene(i);
});
});
renderScene(0);
</script>
</body>
</html>