Files
wecom_it_smart_desk/docs/01-产品文档/02-会话管理/原型-REQ-会话-001-整合区方案A-v1.3.html
T

523 lines
26 KiB
HTML
Raw Normal View History

<!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>