Files
wecom_it_smart_desk/docs/01-产品文档/05-用户端H5/原型-REQ-用户-006-智能推荐重构-v1.0.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

990 lines
37 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" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能推荐重构原型 v1.0 · REQ-用户-006</title>
<style>
/* ============================================================================
CSS 变量(沿用 H5 用户端原型 v2.0 风格)
============================================================================ */
:root {
--accent: #3b82f6;
--accent-soft: rgba(59, 130, 246, 0.12);
--bg-primary: #f5f6fa;
--bg-secondary: #ffffff;
--bg-tertiary: #eef0f5;
--text-primary: #1a1a2e;
--text-secondary: #555770;
--text-tertiary: #9ca3af;
--border-color: #e5e7eb;
--shadow: 0 1px 4px rgba(0,0,0,0.06);
--radius: 12px;
/* v1.0 新增:layer 边框颜色(PRD §4.5 UI 规范)*/
--color-layer-l1-border: #22c55e; /* L1 相关推荐:绿色 */
--color-layer-l2-border: #f97316; /* L2 运维提醒:橙色 */
--color-layer-l3-border: #94a3b8; /* L3 常用资源:灰色 */
--color-layer-a-border: #3b82f6; /* 来源 A Dify action:蓝色 */
--color-progress-border: #8b5cf6; /* 审批进度:紫色 */
}
[data-theme="dark"] {
--accent: #3b82f6;
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-tertiary: #162032;
--text-primary: #e2e8f0;
--text-secondary: #94a3b8;
--text-tertiary: #64748b;
--border-color: #334155;
--shadow: 0 1px 4px rgba(0,0,0,0.3);
--color-layer-l1-border: #4ade80;
--color-layer-l2-border: #fb923c;
--color-layer-l3-border: #64748b;
--color-layer-a-border: #60a5fa;
--color-progress-border: #a78bfa;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
padding: 20px;
}
/* ============================================================================
顶部导航
============================================================================ */
.topbar {
max-width: 1400px;
margin: 0 auto 20px;
background: var(--bg-secondary);
border-radius: var(--radius);
padding: 16px 24px;
box-shadow: var(--shadow);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 12px;
}
.topbar h1 { font-size: 18px; color: var(--accent); }
.topbar .meta { color: var(--text-secondary); font-size: 13px; }
.topbar .actions button {
background: var(--accent-soft);
color: var(--accent);
border: none;
padding: 6px 14px;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
margin-left: 8px;
}
/* ============================================================================
场景标签页
============================================================================ */
.scene-tabs {
max-width: 1400px;
margin: 0 auto 20px;
background: var(--bg-secondary);
border-radius: var(--radius);
padding: 12px 16px;
box-shadow: var(--shadow);
display: flex;
gap: 8px;
overflow-x: auto;
}
.scene-tab {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-secondary);
padding: 8px 14px;
border-radius: 8px;
cursor: pointer;
font-size: 13px;
white-space: nowrap;
transition: all 0.2s;
}
.scene-tab.active {
background: var(--accent);
color: white;
border-color: var(--accent);
}
/* ============================================================================
场景内容区
============================================================================ */
.scene {
max-width: 1400px;
margin: 0 auto;
background: var(--bg-secondary);
border-radius: var(--radius);
padding: 24px;
box-shadow: var(--shadow);
display: none;
}
.scene.active { display: block; }
.scene h2 {
font-size: 18px;
margin-bottom: 8px;
color: var(--text-primary);
}
.scene .subtitle {
color: var(--text-secondary);
font-size: 13px;
margin-bottom: 20px;
}
/* ============================================================================
对比布局(重构前 vs 重构后)
============================================================================ */
.compare {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
@media (max-width: 900px) { .compare { grid-template-columns: 1fr; } }
.compare-col h3 {
font-size: 14px;
margin-bottom: 12px;
color: var(--text-secondary);
display: flex;
align-items: center;
gap: 8px;
}
.compare-col.old h3::before {
content: "重构前";
background: #fee2e2;
color: #dc2626;
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
}
.compare-col.new h3::before {
content: "重构后";
background: #dcfce7;
color: #16a34a;
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
}
/* ============================================================================
H5 模拟容器
============================================================================ */
.h5-mock {
background: var(--bg-tertiary);
border-radius: 8px;
padding: 12px;
display: grid;
grid-template-columns: 1fr 280px;
gap: 12px;
min-height: 500px;
}
.h5-mock.single-col { grid-template-columns: 1fr; }
.h5-chat, .h5-right {
background: var(--bg-secondary);
border-radius: 8px;
padding: 12px;
overflow-y: auto;
max-height: 600px;
}
/* ============================================================================
气泡样式
============================================================================ */
.bubble {
max-width: 75%;
padding: 10px 14px;
border-radius: 10px;
margin-bottom: 8px;
font-size: 13px;
}
.bubble.user {
background: var(--accent);
color: white;
margin-left: auto;
border-bottom-right-radius: 2px;
}
.bubble.ai {
background: var(--bg-tertiary);
color: var(--text-primary);
border-bottom-left-radius: 2px;
}
.bubble.system {
background: transparent;
color: var(--text-tertiary);
font-size: 12px;
text-align: center;
margin: 8px auto;
}
/* ============================================================================
推荐卡片(核心:4 类卡片样式)
============================================================================ */
.rec-card {
background: var(--bg-secondary);
border-left: 4px solid;
border-radius: 8px;
padding: 12px;
margin-bottom: 10px;
position: relative;
box-shadow: 0 1px 2px rgba(0,0,0,0.04);
font-size: 13px;
}
.rec-card.layer-L1, .rec-card.source-keyword { border-left-color: var(--color-layer-l1-border); }
.rec-card.layer-L2, .rec-card.source-profile { border-left-color: var(--color-layer-l2-border); }
.rec-card.layer-L3, .rec-card.source-role { border-left-color: var(--color-layer-l3-border); }
.rec-card.layer-A, .rec-card.source-dify { border-left-color: var(--color-layer-a-border); }
.rec-card.layer-progress, .rec-card.source-approval { border-left-color: var(--color-progress-border); }
.rec-card .rec-title {
font-weight: 600;
color: var(--text-primary);
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 6px;
}
.rec-card .rec-icon { font-size: 16px; }
.rec-card .rec-desc {
color: var(--text-secondary);
font-size: 12px;
margin-bottom: 8px;
line-height: 1.5;
}
.rec-card .rec-items {
list-style: none;
display: flex;
flex-direction: column;
gap: 4px;
}
.rec-card .rec-items li {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 0;
font-size: 12px;
color: var(--text-secondary);
}
.rec-card .rec-items li::before {
content: "•";
color: var(--accent);
}
.rec-card .rec-items a {
color: var(--accent);
text-decoration: none;
}
.rec-card .rec-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 8px;
padding-top: 8px;
border-top: 1px dashed var(--border-color);
font-size: 11px;
color: var(--text-tertiary);
}
.rec-card .rec-source-tag {
background: var(--bg-tertiary);
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
}
.rec-card .rec-dismiss {
position: absolute;
top: 6px;
right: 8px;
background: transparent;
border: none;
color: var(--text-tertiary);
cursor: pointer;
font-size: 14px;
line-height: 1;
}
/* 操作步骤可展开样式 */
.rec-card.expandable .rec-steps {
display: none;
margin-top: 8px;
padding-top: 8px;
border-top: 1px dashed var(--border-color);
}
.rec-card.expandable.open .rec-steps { display: block; }
.rec-card .rec-toggle {
background: transparent;
border: 1px solid var(--border-color);
color: var(--accent);
font-size: 11px;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
margin-top: 4px;
}
.rec-card .step-item {
padding: 6px 0;
border-bottom: 1px solid var(--border-color);
font-size: 12px;
}
.rec-card .step-item:last-child { border-bottom: none; }
.rec-card .step-num {
background: var(--accent);
color: white;
border-radius: 50%;
width: 18px;
height: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 10px;
margin-right: 6px;
}
/* 联系人/联系窗口卡片样式 */
.rec-card .contact-window-btn, .rec-card .contact-card-btn {
display: inline-block;
background: var(--accent-soft);
color: var(--accent);
padding: 4px 10px;
border-radius: 6px;
font-size: 12px;
text-decoration: none;
margin-top: 6px;
}
/* 审批进度卡片样式 */
.rec-card.layer-progress .progress-bar {
height: 4px;
background: var(--bg-tertiary);
border-radius: 2px;
margin-top: 6px;
overflow: hidden;
}
.rec-card.layer-progress .progress-fill {
height: 100%;
background: var(--color-progress-border);
border-radius: 2px;
transition: width 0.3s;
}
.rec-card.layer-progress .progress-status {
display: inline-block;
padding: 2px 8px;
border-radius: 10px;
font-size: 10px;
font-weight: 600;
margin-top: 4px;
}
.rec-card.layer-progress .progress-status.pending {
background: rgba(251, 146, 60, 0.15);
color: #ea580c;
}
.rec-card.layer-progress .progress-status.approved {
background: rgba(34, 197, 94, 0.15);
color: #16a34a;
}
/* ============================================================================
旧的"重构前"样式(保留做对比)
============================================================================ */
.rec-section-title {
font-size: 12px;
color: var(--text-tertiary);
margin-bottom: 8px;
padding: 0 4px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.rec-card-old {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 10px;
margin-bottom: 10px;
font-size: 13px;
}
/* ============================================================================
注释说明区
============================================================================ */
.notes {
background: var(--bg-tertiary);
border-left: 3px solid var(--accent);
padding: 12px 16px;
border-radius: 6px;
margin-top: 16px;
font-size: 13px;
color: var(--text-secondary);
}
.notes strong { color: var(--text-primary); }
.notes ul { padding-left: 20px; margin-top: 6px; }
.notes li { margin-bottom: 4px; }
/* ============================================================================
冷启动空状态
============================================================================ */
.empty-state {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
min-height: 400px;
color: var(--text-tertiary);
font-size: 13px;
font-style: italic;
}
</style>
</head>
<body>
<!-- 顶部导航 -->
<div class="topbar">
<div>
<h1>智能推荐重构原型 v1.0</h1>
<div class="meta">REQ-用户-006 · 基于 PRD v1.0-Frozen + 技术方案 v1.0 · 2026-07-28</div>
</div>
<div class="actions">
<button onclick="toggleTheme()">🌓 切换主题</button>
</div>
</div>
<!-- 场景标签 -->
<div class="scene-tabs">
<button class="scene-tab active" onclick="showScene(0)">1. 重构前 vs 重构后</button>
<button class="scene-tab" onclick="showScene(1)">2. 冷启动空状态(决策 ① A</button>
<button class="scene-tab" onclick="showScene(2)">3. AI 回复瞬间 FIFO 插入</button>
<button class="scene-tab" onclick="showScene(3)">4. 4 类卡片样式</button>
<button class="scene-tab" onclick="showScene(4)">5. 跨会话持久化</button>
<button class="scene-tab" onclick="showScene(5)">6. 话题切换</button>
<button class="scene-tab" onclick="showScene(6)">7. 触发失败降级</button>
</div>
<!-- 场景 1:重构前 vs 重构后 -->
<div class="scene active" id="scene-0">
<h2>场景 1:重构前 vs 重构后 整体对比</h2>
<div class="subtitle">核心改动:移除"智能推荐"分类标题 + 边框颜色区分 layer + FIFO 插入</div>
<div class="compare">
<!-- 重构前 -->
<div class="compare-col old">
<h3>v2.3 现状(有标题 + 分组)</h3>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">VPN 连不上怎么办?</div>
<div class="bubble ai">请尝试以下步骤:1. 检查网络 2. 重启 aTrust</div>
</div>
<div class="h5-right">
<div class="rec-section-title">⚡ 相关推荐</div>
<div class="rec-card-old">
<div style="font-weight:600">VPN 相关信息</div>
<div style="font-size:12px;color:#555770">客户端下载、服务器地址...</div>
</div>
<div class="rec-section-title" style="margin-top:12px">🔔 运维提醒</div>
<div class="rec-card-old">
<div style="font-weight:600">火绒病毒库过期</div>
<div style="font-size:12px;color:#555770">病毒库已 7 天未更新</div>
</div>
<div class="rec-section-title" style="margin-top:12px">💼 常用资源</div>
<div class="rec-card-old">
<div style="font-weight:600">开发者资源</div>
<div style="font-size:12px;color:#555770">代码仓库、API 文档...</div>
</div>
</div>
</div>
<div class="notes">
<strong>问题:</strong>
<ul>
<li>三个分类标题占据空间,视觉杂乱</li>
<li>无 FIFO,新旧卡片位置固定</li>
<li>分组标题强化"分类"概念,用户误以为必须点击分类切换</li>
<li>卡片样式无 layer 区分,仅靠标题文字</li>
</ul>
</div>
</div>
<!-- 重构后 -->
<div class="compare-col new">
<h3>v1.0 重构后(无标题 + 边框颜色 + FIFO)</h3>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">VPN 连不上怎么办?</div>
<div class="bubble ai">请尝试以下步骤:1. 检查网络 2. 重启 aTrust<br><span style="font-size:11px;color:#9ca3af">📋💻</span></div>
</div>
<div class="h5-right">
<!-- v1.0 重构后:无任何分类标题 -->
<!-- v1.0 重构后:FIFO 顺序,最新在最上 -->
<div class="rec-card source-keyword">
<div class="rec-title"><span class="rec-icon">🔐</span>VPN 相关信息</div>
<div class="rec-desc">VPN 连接所需资源</div>
<ul class="rec-items">
<li>客户端下载(支持 Windows/macOS</li>
<li>服务器地址:vpn.servyou-it.com</li>
<li>申请审批 → <a>去申请</a></li>
</ul>
<div class="rec-meta">
<span class="rec-source-tag">L1 · 关键词命中</span>
<span>2 秒前</span>
</div>
</div>
<div class="rec-card source-profile">
<div class="rec-title"><span class="rec-icon">🦠</span>火绒病毒库过期</div>
<div class="rec-desc">病毒库已 7 天未更新,建议立即升级</div>
<div class="rec-meta">
<span class="rec-source-tag">L2 · 画像触发</span>
<span>2 秒前</span>
</div>
</div>
<div class="rec-card source-role">
<div class="rec-title"><span class="rec-icon">💻</span>开发者资源</div>
<div class="rec-desc">代码仓库、API 文档、测试环境申请</div>
<div class="rec-meta">
<span class="rec-source-tag">L3 · 角色匹配</span>
<span>2 秒前</span>
</div>
</div>
</div>
</div>
<div class="notes">
<strong>改进:</strong>
<ul>
<li>✅ 移除所有分类标题("⚡ 相关推荐"/"🔔 运维提醒"/"💼 常用资源"),视觉更清爽</li>
<li>✅ 边框颜色区分 layer:🟢 L1 / 🟠 L2 / ⚪ L3 / 🔵 A / 🟣 progress</li>
<li>✅ FIFO:新卡片插入最上方(最新在上)</li>
<li>✅ 来源标签在卡片底部可查(L1/L2/L3 + 来源类型)</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 场景 2:冷启动空状态 -->
<div class="scene" id="scene-1">
<h2>场景 2:冷启动空状态(PRD §4.7.4 决策 ① A</h2>
<div class="subtitle">用户进入会话但未发言 / AI 还未回复 → 右侧栏完全空白(不强求兜底)</div>
<div class="h5-mock single-col">
<div class="h5-chat">
<div class="bubble user">VPN 连不上怎么办?</div>
<div class="bubble system">(消息已发送,等待 AI 回复...</div>
</div>
</div>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">VPN 连不上怎么办?</div>
<div class="bubble system">AI 正在思考...</div>
</div>
<div class="h5-right">
<!-- 冷启动空状态:完全空白 -->
<div class="empty-state">
<!-- 不显示任何卡片 -->
<!-- 不显示"暂无推荐"提示卡 -->
<!-- 不显示"试试问 XXX"引导 -->
<!-- 完全空白,等待 AI 回复到达 -->
</div>
</div>
</div>
<div class="notes">
<strong>PRD §4.7.4 决策 ① A 落地:</strong>
<ul>
<li>✅ 进会话 5s 内无任何消息:右侧栏空白</li>
<li>✅ 首条消息刚发出、AI 未回复:右侧栏空白</li>
<li>✅ AI 回复到达瞬间:按 §4.7.3 合并规则填充真实推荐</li>
<li>✅ 完全无数据:右侧栏空白(不显示兜底提示)</li>
<li>❌ 重构前(旧方案):进会话就显示"⚡ 相关推荐"占位</li>
<li>❌ 重构前(旧方案):无消息时显示"VPN/Outlook/打印机"等假数据</li>
</ul>
</div>
</div>
<!-- 场景 3:AI 回复瞬间 FIFO 插入 -->
<div class="scene" id="scene-2">
<h2>场景 3:AI 回复瞬间 FIFO 插入</h2>
<div class="subtitle">新生成的卡片插入到右侧栏最上方(最新优先)</div>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">VPN 连不上怎么办?</div>
<div class="bubble ai">
请尝试以下步骤:<br>
1. 检查网络连接<br>
2. 重启 aTrust 客户端<br>
3. 如仍无法连接,<strong>右侧已为您准备好重连步骤</strong>
<div style="font-size:11px;color:#9ca3af;margin-top:4px">📋💻</div>
</div>
<div class="bubble user">顺便帮我看下电脑补丁情况</div>
<div class="bubble ai">
您的电脑有 12 个安全补丁未安装,<strong>右侧已准备好补丁列表</strong>
<div style="font-size:11px;color:#9ca3af;margin-top:4px">💻⚠️</div>
</div>
</div>
<div class="h5-right">
<!-- FIFO:新卡片在最上方 -->
<!-- 最新:补丁缺失提醒(刚生成的 L1 推荐)-->
<div class="rec-card source-keyword">
<div class="rec-title"><span class="rec-icon">🔧</span>系统补丁缺失</div>
<div class="rec-desc">您的电脑有 12 个安全补丁未安装,可能存在安全风险</div>
<div class="rec-meta">
<span class="rec-source-tag">L1 · 关键词"补丁"</span>
<span>刚刚</span>
</div>
</div>
<!-- 之前:VPN 步骤 -->
<div class="rec-card source-dify expandable open">
<div class="rec-title"><span class="rec-icon">🔐</span>VPN 重连步骤</div>
<div class="rec-desc">完整操作步骤,点击展开</div>
<button class="rec-toggle" onclick="toggleExpand(this)">收起 ▲</button>
<div class="rec-steps">
<div class="step-item"><span class="step-num">1</span>打开 aTrust 客户端</div>
<div class="step-item"><span class="step-num">2</span>点击"重新连接"</div>
<div class="step-item"><span class="step-num">3</span>输入账号密码</div>
<div class="step-item"><span class="step-num">4</span>如失败,重启客户端</div>
</div>
<div class="rec-meta">
<span class="rec-source-tag">A · Dify 步骤卡</span>
<span>5 秒前</span>
</div>
</div>
</div>
</div>
<div class="notes">
<strong>FIFO 规则(PRD §4.7.3):</strong>
<ul>
<li>✅ 新卡片插入最上方("刚刚"在最上)</li>
<li>✅ 旧卡片往下排("5 秒前"在下)</li>
<li>✅ 上限 3 张:超出部分自动滚出(用户看不见)</li>
<li>✅ 来源 A(Dify 步骤卡)用蓝色边框 + 可展开/收起</li>
</ul>
</div>
</div>
<!-- 场景 44 类卡片样式 -->
<div class="scene" id="scene-3">
<h2>场景 44 类卡片样式</h2>
<div class="subtitle">基于 PRD §4.5 + §4.6 决策的完整卡片类型展示</div>
<!-- 4.1 操作步骤(A 来源,可展开) -->
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">① 操作步骤(来自 Dify action · 可展开)</h3>
<div class="rec-card source-dify expandable">
<div class="rec-title"><span class="rec-icon">🔐</span>VPN 重连操作步骤</div>
<div class="rec-desc">点击展开查看完整步骤</div>
<button class="rec-toggle" onclick="toggleExpand(this)">展开 ▼</button>
<div class="rec-steps">
<div class="step-item"><span class="step-num">1</span>打开 aTrust 客户端</div>
<div class="step-item"><span class="step-num">2</span>点击"重新连接"</div>
<div class="step-item"><span class="step-num">3</span>输入账号密码</div>
<div class="step-item"><span class="step-num">4</span>如失败,重启客户端</div>
</div>
<div class="rec-meta">
<span class="rec-source-tag">A · Dify 步骤卡</span>
<span>点击操作按钮 → aTrust 重连</span>
</div>
</div>
<!-- 4.2 联系窗口(来自 Dify action · 仅左侧栏) -->
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">② 联系窗口(仅左侧栏出现,右侧栏不显示)</h3>
<div style="background:var(--bg-tertiary);padding:12px;border-radius:8px;color:var(--text-secondary);font-size:13px">
位置:左侧气泡 / 右侧栏不出现<br>
关联:员工服务窗口链接(chat_id / openid<br>
示例气泡(左侧):<br>
<div class="rec-card source-dify" style="margin-top:8px;max-width:50%">
<div class="rec-title"><span class="rec-icon">💬</span>IT 服务窗口</div>
<div class="rec-desc">需要人工帮助?点击下方按钮跳转 IT 服务窗口</div>
<a class="contact-window-btn" href="javascript:void(0)">打开 IT 服务窗口</a>
<div class="rec-meta">
<span class="rec-source-tag">A · Dify action</span>
</div>
</div>
</div>
<!-- 4.3 联系人名片(来自 Dify action · 仅左侧栏) -->
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">③ 联系人名片(仅左侧栏出现,右侧栏不显示)</h3>
<div style="background:var(--bg-tertiary);padding:12px;border-radius:8px;color:var(--text-secondary);font-size:13px">
位置:左侧气泡 / 右侧栏不出现<br>
关联:员工名片(user_id)<br>
示例气泡(左侧):<br>
<div class="rec-card source-dify" style="margin-top:8px;max-width:50%">
<div class="rec-title"><span class="rec-icon">👤</span>联系:财务部 张三</div>
<div class="rec-desc">财务部经理 · 工号 10086</div>
<a class="contact-card-btn" href="javascript:void(0)">查看名片</a>
<div class="rec-meta">
<span class="rec-source-tag">A · Dify 路由名片</span>
</div>
</div>
</div>
<!-- 4.4 下载/链接(来自 Dify action · 仅左侧栏) -->
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">④ 下载/链接(仅左侧栏出现,右侧栏不显示)</h3>
<div style="background:var(--bg-tertiary);padding:12px;border-radius:8px;color:var(--text-secondary);font-size:13px">
位置:左侧气泡 / 右侧栏不出现<br>
关联:直接下载链接(exe/pdf/zip<br>
示例气泡(左侧):<br>
<div class="rec-card source-dify" style="margin-top:8px;max-width:50%">
<div class="rec-title"><span class="rec-icon">📦</span>VPN 客户端下载</div>
<div class="rec-desc">Windows 10/11 / macOS · 32.5 MB</div>
<a class="contact-card-btn" href="javascript:void(0)">立即下载</a>
<div class="rec-meta">
<span class="rec-source-tag">A · Dify 资源链接</span>
</div>
</div>
</div>
<!-- 4.5 常用资源 L3(来自角色匹配 · 仅左侧栏) -->
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">⑤ 常用资源 L3(来自角色匹配 · 仅左侧栏出现)</h3>
<div style="background:var(--bg-tertiary);padding:12px;border-radius:8px;color:var(--text-secondary);font-size:13px">
位置:左侧气泡("试试问:xxx"形式) / 右侧栏不出现<br>
触发:profile.position 匹配 role_assets<br>
示例气泡(左侧):<br>
<div class="rec-card source-role" style="margin-top:8px;max-width:50%">
<div class="rec-title"><span class="rec-icon">💻</span>开发者常用资源</div>
<div class="rec-desc">代码仓库 · API 文档 · 测试环境申请</div>
<ul class="rec-items">
<li>git.servyou-it.com</li>
<li>api-docs.servyou-it.com</li>
<li>测试环境申请 → <a>去申请</a></li>
</ul>
<div class="rec-meta">
<span class="rec-source-tag">L3 · 角色"开发"</span>
</div>
</div>
</div>
<!-- 4.6 审批进度(来自 T2 webhook · 右侧栏回流) -->
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">⑥ 审批进度回流(来自 T2 webhook · 右侧栏顶部插入)</h3>
<div class="rec-card layer-progress">
<div class="rec-title"><span class="rec-icon">📋</span>VPN 申请进度</div>
<div class="rec-desc">您发起的 VPN 权限申请</div>
<div class="progress-bar"><div class="progress-fill" style="width:60%"></div></div>
<div style="display:flex;justify-content:space-between;margin-top:4px">
<span class="progress-status approved">已审批</span>
<span style="font-size:11px;color:var(--text-tertiary)">60% · 等待 IT 开通</span>
</div>
<div class="rec-meta">
<span class="rec-source-tag">progress · T2 事件触发</span>
<span>2 分钟前更新</span>
</div>
</div>
</div>
<!-- 场景 5:跨会话持久化 -->
<div class="scene" id="scene-4">
<h2>场景 5:跨会话持久化(PRD §4.7.7 决策 ⑤ B</h2>
<div class="subtitle">L2/L3/progress 持久化到 localStorageL1/A 不持久</div>
<h3 style="margin-top:12px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">会话 1(首次打开,3 张卡都已生成)</h3>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">帮我看看电脑情况</div>
<div class="bubble ai">已检测,您的电脑有 12 个补丁待安装,病毒库已过期 7 天</div>
</div>
<div class="h5-right">
<div class="rec-card source-profile">
<div class="rec-title"><span class="rec-icon">🦠</span>火绒病毒库过期</div>
<div class="rec-desc">病毒库已 7 天未更新</div>
<div class="rec-meta">
<span class="rec-source-tag">L2 · 持久化</span>
<span>✅ 已存 localStorage</span>
</div>
</div>
<div class="rec-card layer-progress">
<div class="rec-title"><span class="rec-icon">📋</span>VPN 申请进度</div>
<div class="rec-desc">已审批 · 等待 IT 开通</div>
<div class="progress-bar"><div class="progress-fill" style="width:60%"></div></div>
<div class="rec-meta">
<span class="rec-source-tag">progress · 持久化直到完结</span>
<span>✅ 已存 localStorage</span>
</div>
</div>
<div class="rec-card source-keyword">
<div class="rec-title"><span class="rec-icon">🔧</span>系统补丁缺失</div>
<div class="rec-desc">12 个安全补丁未安装</div>
<div class="rec-meta">
<span class="rec-source-tag">L1 · ❌ 不持久</span>
<span>会话结束即清</span>
</div>
</div>
</div>
</div>
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">会话 2(用户关闭浏览器后再次打开,localStorage 加载)</h3>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">(新会话,用户未发言)</div>
</div>
<div class="h5-right">
<!-- 跨会话持久化的 L2 + progress 仍在 -->
<!-- L1 已自动清空(不持久) -->
<div class="rec-card source-profile">
<div class="rec-title"><span class="rec-icon">🦠</span>火绒病毒库过期</div>
<div class="rec-desc">病毒库已 7 天未更新(来自 localStorage</div>
<div class="rec-meta">
<span class="rec-source-tag">L2 · 跨会话持久</span>
<span>30 天后过期</span>
</div>
</div>
<div class="rec-card layer-progress">
<div class="rec-title"><span class="rec-icon">📋</span>VPN 申请进度</div>
<div class="rec-desc">已审批 · 等待 IT 开通(来自 localStorage</div>
<div class="progress-bar"><div class="progress-fill" style="width:60%"></div></div>
<div class="rec-meta">
<span class="rec-source-tag">progress · 跨会话持久</span>
<span>完结后清除</span>
</div>
</div>
<!-- L1 不在(已被清空) -->
</div>
</div>
<div class="notes">
<strong>持久化规则(PRD §4.7.7):</strong>
<table style="margin-top:8px;width:100%;border-collapse:collapse">
<tr style="background:var(--bg-tertiary)">
<th style="padding:6px;text-align:left;font-size:12px">类型</th>
<th style="padding:6px;text-align:left;font-size:12px">持久化</th>
<th style="padding:6px;text-align:left;font-size:12px">过期规则</th>
</tr>
<tr><td style="padding:6px;font-size:12px">L1 关键词</td><td style="padding:6px;font-size:12px"></td><td style="padding:6px;font-size:12px">话题切换 / 会话结束即清</td></tr>
<tr><td style="padding:6px;font-size:12px">L2 画像</td><td style="padding:6px;font-size:12px">✅ 30 天</td><td style="padding:6px;font-size:12px">30 天后或画像更新时清</td></tr>
<tr><td style="padding:6px;font-size:12px">L3 角色</td><td style="padding:6px;font-size:12px"></td><td style="padding:6px;font-size:12px">角色变更时清(极少)</td></tr>
<tr><td style="padding:6px;font-size:12px">来源 A 步骤</td><td style="padding:6px;font-size:12px"></td><td style="padding:6px;font-size:12px">话题切换 / 会话结束即清</td></tr>
<tr><td style="padding:6px;font-size:12px">progress</td><td style="padding:6px;font-size:12px"></td><td style="padding:6px;font-size:12px">审批完结时清</td></tr>
</table>
</div>
</div>
<!-- 场景 6:话题切换 -->
<div class="scene" id="scene-5">
<h2>场景 6:话题切换(PRD §4.7.6 决策 ④ B</h2>
<div class="subtitle">用户切换话题后,L1 推荐清空;L2/L3/progress 保留</div>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">VPN 连不上</div>
<div class="bubble ai">请尝试重连 aTrust 客户端</div>
<div class="bubble user" style="background:#22c55e">顺便帮我预约一下会议室</div>
<!-- v1.0Jaccard 相似度 < 0.3,触发话题切换 -->
<div class="bubble system" style="margin-top:8px;color:#22c55e">话题已切换,旧的 L1 推荐已清空 ✅</div>
<div class="bubble ai">好的,您要预约哪个会议室?</div>
</div>
<div class="h5-right">
<!-- L1 已清空(VPN 卡消失)-->
<!-- L2/L3/progress 保留(与话题无关)-->
<div class="rec-card source-profile">
<div class="rec-title"><span class="rec-icon">🦠</span>火绒病毒库过期</div>
<div class="rec-desc">病毒库已 7 天未更新</div>
<div class="rec-meta">
<span class="rec-source-tag">L2 · 保留</span>
<span>画像无关</span>
</div>
</div>
<div class="rec-card layer-progress">
<div class="rec-title"><span class="rec-icon">📋</span>VPN 申请进度</div>
<div class="rec-desc">已审批 · 等待 IT 开通</div>
<div class="progress-bar"><div class="progress-fill" style="width:60%"></div></div>
<div class="rec-meta">
<span class="rec-source-tag">progress · 保留</span>
<span>跨会话持久</span>
</div>
</div>
</div>
</div>
<div class="notes">
<strong>话题切换检测(PRD §4.7.6):</strong>
<ul>
<li>✅ 关键词突变:新消息与最近 3 条消息的 Jaccard 相似度 &lt; 0.3 → 清空 L1</li>
<li>✅ 意图突变:Dify 返回的 intent_type 与上一条不同 → 清空对应 layer</li>
<li>✅ 会话分隔:用户点"结束会话"或新建会话 → 清空所有跨会话推荐</li>
<li>✅ L2/L3/progress 不清(与当前话题无关)</li>
</ul>
</div>
</div>
<!-- 场景 7:触发失败降级 -->
<div class="scene" id="scene-6">
<h2>场景 7:触发失败降级(PRD §4.7.5 决策 ③ B</h2>
<div class="subtitle">C 失败 → D 降级;全部失败 → 右侧栏空</div>
<h3 style="margin-top:12px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">7.1 画像 API 故障(C 失败 → D 降级)</h3>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">我要申请 VPN</div>
<div class="bubble ai">好的,请填写 VPN 申请表单</div>
</div>
<div class="h5-right">
<!-- L1 关键词命中 -->
<div class="rec-card source-keyword">
<div class="rec-title"><span class="rec-icon">🔐</span>VPN 相关信息</div>
<div class="rec-desc">VPN 连接所需资源</div>
<div class="rec-meta">
<span class="rec-source-tag">L1 · 正常</span>
<span></span>
</div>
</div>
<!-- C 失败 → 降级到 D -->
<div class="rec-card source-role" style="opacity:0.8">
<div class="rec-title"><span class="rec-icon">⚠️</span>开发者资源(降级展示)</div>
<div class="rec-desc">画像 API 故障,降级使用 L3 角色通用资源</div>
<div class="rec-meta">
<span class="rec-source-tag">L3 · C→D 降级</span>
<span style="color:#f97316">画像不可用</span>
</div>
</div>
</div>
</div>
<h3 style="margin-top:20px;margin-bottom:8px;color:var(--text-secondary);font-size:14px">7.2 全部失败(右侧栏空)</h3>
<div class="h5-mock">
<div class="h5-chat">
<div class="bubble user">xxx(无关内容)</div>
<div class="bubble ai">您好,请问需要什么帮助?</div>
</div>
<div class="h5-right">
<div class="empty-state">
<!-- 全部失败:右侧栏空 -->
</div>
</div>
</div>
<div class="notes">
<strong>降级链路(PRD §4.7.5):</strong>
<ul>
<li>[A 失败] → [B + C + D]</li>
<li>[B 失败] → [C + D]</li>
<li>[C 失败] → [D] ★ 关键降级(保证有内容)</li>
<li>[D 失败] → []</li>
<li>[全部失败] → [] (按 §4.7.4 走空状态,与决策 ① A 保持一致)</li>
</ul>
</div>
</div>
<script>
// 场景切换
function showScene(idx) {
document.querySelectorAll('.scene').forEach(s => s.classList.remove('active'));
document.querySelectorAll('.scene-tab').forEach(t => t.classList.remove('active'));
document.getElementById('scene-' + idx).classList.add('active');
document.querySelectorAll('.scene-tab')[idx].classList.add('active');
}
// 主题切换
function toggleTheme() {
const html = document.documentElement;
const current = html.getAttribute('data-theme');
html.setAttribute('data-theme', current === 'light' ? 'dark' : 'light');
}
// 操作步骤可展开
function toggleExpand(btn) {
const card = btn.closest('.rec-card');
card.classList.toggle('open');
btn.textContent = card.classList.contains('open') ? '收起 ▲' : '展开 ▼';
}
</script>
</body>
</html>