Files
wecom_it_smart_desk/docs/01-产品文档/02-会话管理/原型-REQ-会话-001-工具栏统一设计v1.8-融合会话窗口圆润顶端.html
T
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交
(5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。

一、docs 结构整改(整改 #14)
根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入,
随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录
树并存于 docs/,共 791 文件、双分类体系冲突。

修复动作:
- b2 同名异主题文件改名迁移保全 9 个
- C 类 39 个孤立文件按主题正确归类
- A/B1 类 222 个重复文件删除(新结构已有内容副本)
- 9 个旧独有空目录删除
- 270 处内部引用按 verified 映射改写
- 整改记录 #14 登记于 04-运维文档/部署运维

结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。
残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。

二、compose 双目录对齐(消除踩坑 A)
- docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist
  改为 src/frontend-*/dist(h5 / agent / admin / terminal)
- docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/
- 效果:本地 docker compose up 不再把根目录 stale dist 挂回,
  与线上一致,分叉隐患消除(已 docker compose config 校验通过)

防复发铁律:
- 重构须提交;仓库修复须 git stash -u 或先 commit
- 新结构须 git add 并提交,避免再次 untracked 复活
- H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
2026-08-07 22:31:32 +08:00

421 lines
19 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">
<title>工具栏统一设计 v1.8 - 融合会话窗口 · 圆润顶端</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
background: linear-gradient(135deg, #e0e7ff 0%, #f3e8ff 50%, #fce7f3 100%);
color: #1a1a1a;
padding: 24px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
min-height: 100vh;
}
h1 { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 8px; color: #1a1a1a; }
h2 { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; margin: 32px 0 12px; color: #1a1a1a; }
.meta { color: #6b7280; font-size: 12.5px; margin-bottom: 20px; }
/* === ChatPanel 整体(员工端会话窗口容器) === */
.chatpanel-mock {
width: 100%;
max-width: 720px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.9);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(99, 102, 241, 0.1);
overflow: hidden;
position: relative;
}
.chatpanel-mock-header {
padding: 12px 16px;
border-bottom: 1px solid rgba(99, 102, 241, 0.1);
background: rgba(255, 255, 255, 0.5);
font-size: 13px;
color: #374151;
display: flex;
align-items: center;
gap: 8px;
}
.chatpanel-mock-header .dot { width: 8px; height: 8px; border-radius: 50%; background: #10b981; }
.chatpanel-mock-header .title { font-weight: 600; }
.chatpanel-mock-header .sub { color: #9ca3af; font-size: 11.5px; }
/* === 消息流区域(会话窗口) === */
.chatpanel-mock-messages {
min-height: 260px;
padding: 20px 16px;
background: linear-gradient(180deg, #fafbfc 0%, #f5f7fa 100%);
display: flex;
flex-direction: column;
gap: 10px;
}
.mock-msg {
max-width: 74%;
padding: 9px 13px;
border-radius: 14px;
font-size: 13px;
line-height: 1.55;
}
.mock-msg .who { font-size: 10.5px; opacity: 0.65; margin-bottom: 3px; }
.mock-msg.user {
align-self: flex-end;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
color: #fff;
border-bottom-right-radius: 4px;
}
.mock-msg.ai {
align-self: flex-start;
background: rgba(255, 255, 255, 0.9);
color: #1a1a1a;
border: 1px solid rgba(99, 102, 241, 0.12);
border-bottom-left-radius: 4px;
}
.mock-msg.ai .quick {
margin-top: 8px; display: flex; gap: 6px; flex-wrap: wrap;
}
.mock-msg.ai .quick span {
font-size: 11.5px; padding: 4px 10px; border-radius: 12px;
background: rgba(99, 102, 241, 0.08); color: #4f46e5; border: 1px solid rgba(99, 102, 241, 0.15);
}
/* === gem 工具栏 band(位于会话窗口与消息窗口之间) === */
.gem-band {
background: rgba(255, 255, 255, 0.35);
border-top: 1px solid rgba(99, 102, 241, 0.1);
border-bottom: 1px solid rgba(99, 102, 241, 0.1);
padding: 6px 0 10px;
display: flex;
justify-content: center;
}
.gem-toolbar {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 0 16px;
width: fit-content;
height: 84px;
}
.gem-toolbar-bg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
z-index: 0;
pointer-events: none;
overflow: visible;
}
.gem-row { position: relative; z-index: 2; display: flex; align-items: center; justify-content: center; gap: 12px; }
.gem-toolbar .agent-btn.gem {
width: 60px; height: 60px; margin: 0 6px; z-index: 3; box-shadow: none;
}
.gem-toolbar .glass-btn { z-index: 2; }
/* === InputBar(消息窗口) === */
.inputbar-mock {
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
border-top: 1px solid rgba(99, 102, 241, 0.15);
padding: 12px 16px 16px;
position: relative;
}
.inputbar-mock-field {
width: 100%;
min-height: 56px;
background: rgba(255, 255, 255, 0.5);
border: 1px solid rgba(99, 102, 241, 0.12);
border-radius: 12px;
padding: 10px 14px;
font-size: 13px;
color: #9ca3af;
line-height: 1.6;
display: flex;
align-items: center;
justify-content: space-between;
}
.inputbar-mock-field .send {
margin-left: 12px;
padding: 7px 18px;
border-radius: 10px;
background: linear-gradient(135deg, #6366f1, #8b5cf6);
color: #fff; font-size: 13px; font-weight: 600;
box-shadow: 0 2px 6px rgba(99,102,241,0.25);
}
/* === 通用按钮样式(玻璃圆形 + 坐席头像) === */
.glass-btn {
width: 40px; height: 40px;
border: 1px solid rgba(255, 255, 255, 0.6);
background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
border-radius: 50%;
cursor: pointer;
display: flex; align-items: center; justify-content: center;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
-webkit-tap-highlight-color: transparent;
position: relative; z-index: 2;
box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 2px 4px rgba(0,0,0,0.04);
}
.glass-btn:hover { background: rgba(255,255,255,0.75); transform: translateY(-1px) scale(1.06); }
.glass-btn:active { transform: translateY(0) scale(0.95); }
.glass-btn svg { width: 22px; height: 22px; display: block; }
.agent-btn {
border-radius: 50%;
border: 2px solid transparent;
cursor: pointer;
position: relative; z-index: 2;
padding: 0;
background: linear-gradient(135deg, #6366f1 0%, #a855f7 50%, #ec4899 100%) padding-box;
}
.agent-btn::before {
content: ""; position: absolute; inset: -2px; border-radius: 50%;
background: linear-gradient(135deg, #6366f1 0%, #a855f7 50%, #ec4899 100%); z-index: -1;
}
.agent-btn img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; object-position: center 15%; display: block; }
.agent-badge { position: absolute; bottom: 0; right: 0; width: 12px; height: 12px; border-radius: 50%; border: 2px solid white; z-index: 3; box-shadow: 0 1px 2px rgba(0,0,0,0.2); }
.agent-badge.is-online { background: #10b981; }
/* === 演示容器 / 提示块 === */
.demo-block {
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.7);
border-radius: 18px;
padding: 24px;
margin-bottom: 20px;
box-shadow: 0 1px 0 rgba(255,255,255,0.9) inset, 0 8px 16px rgba(99,102,241,0.06);
}
.note { background: rgba(254, 243, 199, 0.6); border-left: 3px solid #d97706; padding: 12px 16px; border-radius: 4px; font-size: 12.5px; color: #78350f; margin: 16px 0; backdrop-filter: blur(10px); }
.note-success { background: rgba(209, 250, 229, 0.6); border-left: 3px solid #10b981; padding: 12px 16px; border-radius: 4px; font-size: 12.5px; color: #064e3b; margin: 16px 0; backdrop-filter: blur(10px); }
.note-info { background: rgba(219, 234, 254, 0.6); border-left: 3px solid #3b82f6; padding: 12px 16px; border-radius: 4px; font-size: 12.5px; color: #1e3a8a; margin: 16px 0; backdrop-filter: blur(10px); }
.arch-compare { display: flex; gap: 24px; flex-wrap: wrap; margin: 12px 0; }
.arch-compare figure { text-align: center; font-size: 11.5px; color: #6b7280; }
.arch-compare svg { background: rgba(255,255,255,0.5); border: 1px solid rgba(99,102,241,0.12); border-radius: 10px; }
table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12.5px; }
thead tr { background: rgba(255, 255, 255, 0.6); }
th { border: 1px solid rgba(99, 102, 241, 0.15); padding: 8px; text-align: left; font-weight: 600; }
td { border: 1px solid rgba(99, 102, 241, 0.15); padding: 8px; }
</style>
</head>
<body>
<svg width="0" height="0" style="position: absolute;">
<defs>
<linearGradient id="g-emoji" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#fde68a"/><stop offset="60%" stop-color="#fbbf24"/><stop offset="100%" stop-color="#d97706"/>
</linearGradient>
<radialGradient id="g-emoji-blush" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="rgba(244, 63, 94, 0.4)"/>
<stop offset="100%" stop-color="rgba(244, 63, 94, 0)"/>
</radialGradient>
<linearGradient id="g-highlight" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="white" stop-opacity="0.7"/>
<stop offset="100%" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="g-doc-body" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="#ffffff"/><stop offset="100%" stop-color="#dbeafe"/>
</linearGradient>
<linearGradient id="g-doc-fold" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="#c7d2fe"/><stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
<linearGradient id="g-doc-text" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#6366f1"/><stop offset="100%" stop-color="#a855f7"/>
</linearGradient>
<linearGradient id="g-mic-body" x1="50%" y1="0%" x2="50%" y2="100%">
<stop offset="0%" stop-color="#c4b5fd"/><stop offset="50%" stop-color="#8b5cf6"/><stop offset="100%" stop-color="#6d28d9"/>
</linearGradient>
<linearGradient id="g-group" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#a5b4fc"/><stop offset="100%" stop-color="#c4b5fd"/>
</linearGradient>
<linearGradient id="g-group-strong" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#6366f1"/><stop offset="50%" stop-color="#a855f7"/><stop offset="100%" stop-color="#ec4899"/>
</linearGradient>
<!-- 圆角长方形轨道渐变 -->
<linearGradient id="g-rail" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8" stop-opacity="0.5"/>
<stop offset="50%" stop-color="#c4b5fd" stop-opacity="0.9"/>
<stop offset="100%" stop-color="#818cf8" stop-opacity="0.5"/>
</linearGradient>
</defs>
</svg>
<h1>工具栏统一设计 v1.8 — 融合会话窗口 · 圆润顶端</h1>
<p class="meta">v1.7 演进:① 顶端拱肩水平缓出 + 顶点大半径圆顶(更圆润);② 将 gem 工具栏作为独立 band 融入员工端「会话消息区 ↔ 消息输入区」之间 · 2026-08-05</p>
<div class="note-info">
📐 <strong>v1.8 两处改动</strong><br>
<strong>顶端更圆润</strong>:拱肩由「直线段立刻上抬(控制点 120,14)」改为「先水平缓出、再均匀升起(控制点 128,16)」,消除直线段与拱之间的折角;顶点控制点由 (144,8)/(168,8) 外推至 (138,9)/(174,9),顶点曲率半径更大 → 顶端更圆、更柔<br>
<strong>融入会话窗口</strong>:gem 工具栏作为一条独立 band,置于「会话消息区」与「消息输入区(InputBar)」之间,配真实 IT 工单对话气泡,呈现实际融合效果(不再孤立展示)
</div>
<h2>🎯 v1.8 实战融合效果(员工端会话窗口)</h2>
<div class="demo-block">
<!-- 完整员工端会话窗口 -->
<div class="chatpanel-mock">
<!-- 头部 -->
<div class="chatpanel-mock-header">
<span class="dot"></span>
<span class="title">IT 智能服务台</span>
<span class="sub">· 在线 · 工单 #SR-20260805-0392</span>
</div>
<!-- 会话窗口:消息流 -->
<div class="chatpanel-mock-messages">
<div class="mock-msg user">
<div class="who"></div>
你好,我的 VPN 连不上,提示 691 错误,影响今天远程办公。
</div>
<div class="mock-msg ai">
<div class="who">智能助手</div>
您好,VPN 691 通常是账号密码错误或账号被锁定。已为您查询:账号状态正常、未过期。<br>
建议先自助排查:① 确认密码未过期;② 在 portal 重置密码后重试。
<div class="quick">
<span>重置 VPN 密码</span><span>查看排障指引</span><span>转人工坐席</span>
</div>
</div>
<div class="mock-msg user">
<div class="who"></div>
重置了还是不行,麻烦转人工。
</div>
<div class="mock-msg ai">
<div class="who">智能助手</div>
已为您转接人工坐席,请稍候。也可点击下方工具栏「人工坐席」按钮随时发起通话。
</div>
</div>
<!-- gem 工具栏 band(位于会话窗口与消息窗口之间) -->
<div class="gem-band">
<div class="gem-toolbar">
<svg class="gem-toolbar-bg" viewBox="0 0 312 84" preserveAspectRatio="xMidYMid meet">
<!-- 圆角长方形轨道:两端(两侧图标处)保持直线,仅中央坐席处连续圆顶拱起;顶端圆肩缓出、顶点大半径更圆润 -->
<path d="M 18 18
L 108 18
C 128 16, 138 9, 156 6
C 174 9, 184 16, 204 18
L 294 18
C 302 18, 312 26, 312 34
L 312 50
C 312 58, 302 66, 294 66
L 204 66
C 184 68, 174 75, 156 78
C 138 75, 128 68, 108 66
L 18 66
C 0 66, 0 58, 0 50
L 0 34
C 0 26, 10 18, 18 18 Z"
fill="url(#g-rail)" stroke="rgba(255,255,255,0.85)" stroke-width="1.2"/>
</svg>
<div class="gem-row">
<button class="glass-btn" title="表情">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="9" fill="url(#g-emoji)"/>
<ellipse cx="12" cy="6" rx="6" ry="2.5" fill="url(#g-highlight)"/>
<ellipse cx="6.5" cy="14" rx="1.5" ry="1" fill="url(#g-emoji-blush)"/>
<ellipse cx="17.5" cy="14" rx="1.5" ry="1" fill="url(#g-emoji-blush)"/>
<ellipse cx="8.5" cy="11" rx="1.4" ry="1.6" fill="#1e1b4b"/>
<ellipse cx="15.5" cy="11" rx="1.4" ry="1.6" fill="#1e1b4b"/>
<circle cx="8.9" cy="10.4" r="0.5" fill="white"/>
<circle cx="15.9" cy="10.4" r="0.5" fill="white"/>
<path d="M8 15 Q12 18 16 15" fill="none" stroke="#1e1b4b" stroke-width="1.6" stroke-linecap="round"/>
</svg>
</button>
<button class="glass-btn" title="文件">
<svg viewBox="0 0 24 24" fill="none">
<path d="M4 2 L14 2 L20 8 L20 20 L4 20 Z" fill="url(#g-doc-body)" stroke="#818cf8" stroke-width="0.8"/>
<path d="M14 2 L14 8 L20 8" fill="url(#g-doc-fold)" stroke="#818cf8" stroke-width="0.8"/>
<rect x="7" y="11.5" width="10" height="0.8" rx="0.4" fill="url(#g-doc-text)"/>
</svg>
</button>
<!-- 人工坐席按钮:增大 50%(60px),居中,不探出,无光晕 -->
<button class="agent-btn gem" title="人工坐席">
<img src="./agent-avatar-v0.8.jpg" alt="人工坐席"/>
<span class="agent-badge is-online"></span>
</button>
<button class="glass-btn" title="语音输入">
<svg viewBox="0 0 24 24" fill="none">
<rect x="8" y="2" width="8" height="13" rx="4" fill="url(#g-mic-body)"/>
<path d="M3 12 Q3 18 12 18 Q21 18 21 12" fill="none" stroke="url(#g-mic-body)" stroke-width="2"/>
<line x1="12" y1="18" x2="12" y2="22" stroke="url(#g-mic-body)" stroke-width="2"/>
</svg>
</button>
<button class="glass-btn" title="群聊">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="8" cy="9" r="2.2" fill="url(#g-group)"/>
<path d="M5 16 Q5 13 8 13 Q11 13 11 16 Z" fill="url(#g-group)"/>
<circle cx="16" cy="9" r="2.2" fill="url(#g-group)"/>
<path d="M13 16 Q13 13 16 13 Q19 13 19 16 Z" fill="url(#g-group)"/>
<circle cx="12" cy="10.5" r="2.8" fill="url(#g-group-strong)"/>
<path d="M8.5 18.5 Q8.5 14 12 14 Q15.5 14 15.5 18.5 Z" fill="url(#g-group-strong)"/>
</svg>
</button>
</div>
</div>
</div>
<!-- 消息窗口:InputBar -->
<div class="inputbar-mock">
<div class="inputbar-mock-field">
<span>描述您的问题,或点击上方工具栏发起操作…</span>
<span class="send">发送</span>
</div>
</div>
</div>
</div>
<h2>🔍 顶端弧度对比(v1.7 → v1.8)</h2>
<div class="note">
左为 v1.7「渐升圆顶」、右为 v1.8「圆润顶端」:v1.8 的拱肩从直线段水平缓出(不再立刻上抬),顶点控制点外推加宽、曲率半径更大,肉眼可见顶端更圆、与直线段衔接更柔。
</div>
<div class="arch-compare">
<figure>
<svg width="312" height="84" viewBox="0 0 312 84">
<path d="M 18 18 L 108 18 C 120 14, 144 8, 156 6 C 168 8, 192 14, 204 18 L 294 18 C 302 18, 312 26, 312 34 L 312 50 C 312 58, 302 66, 294 66 L 204 66 C 192 70, 168 76, 156 78 C 144 76, 120 70, 108 66 L 18 66 C 0 66, 0 58, 0 50 L 0 34 C 0 26, 10 18, 18 18 Z"
fill="none" stroke="#f59e0b" stroke-width="1.4"/>
</svg>
<div>v1.7(拱肩直抬 · 顶点较尖)</div>
</figure>
<figure>
<svg width="312" height="84" viewBox="0 0 312 84">
<path d="M 18 18 L 108 18 C 128 16, 138 9, 156 6 C 174 9, 184 16, 204 18 L 294 18 C 302 18, 312 26, 312 34 L 312 50 C 312 58, 302 66, 294 66 L 204 66 C 184 68, 174 75, 156 78 C 138 75, 128 68, 108 66 L 18 66 C 0 66, 0 58, 0 50 L 0 34 C 0 26, 10 18, 18 18 Z"
fill="none" stroke="#10b981" stroke-width="1.4"/>
</svg>
<div>v1.8(圆肩缓出 · 顶点更圆)</div>
</figure>
</div>
<h2>📊 v1.7 vs v1.8</h2>
<table>
<thead>
<tr><th>维度</th><th>v1.7</th><th><strong>v1.8</strong></th></tr>
</thead>
<tbody>
<tr><td>顶端弧度</td><td>渐升圆顶(拱肩直抬,顶点中等半径)</td><td><strong>圆润顶端(拱肩水平缓出,顶点大半径更圆)</strong></td></tr>
<tr><td>顶部首控制点</td><td>120,14(立刻上抬)</td><td><strong>128,16(水平缓出)</strong></td></tr>
<tr><td>顶点控制点</td><td>144,8 / 168,8</td><td><strong>138,9 / 174,9(外推加宽、更圆)</strong></td></tr>
<tr><td>融合场景</td><td>孤立展示工具栏</td><td><strong>嵌入员工端会话窗口(消息区 ↔ 输入区之间)</strong></td></tr>
<tr><td>坐席按钮 / 两端直线 / 不探出 / 无光晕</td><td>60px / 保持 / 保持 / 保持</td><td><strong>60px / 保持 / 保持 / 保持(不变)</strong></td></tr>
</tbody>
</table>
<h2>⚠️ 注意事项与待确认点</h2>
<ol style="margin-left: 20px; line-height: 1.8; font-size: 13px;">
<li><strong>顶端圆润度</strong>:若还嫌顶点偏尖,可继续外推顶点控制点(如 134,10 / 178,10)或略降顶点(y 6→8)让拱更扁更圆;若觉得过圆想更挺,回收即可</li>
<li><strong>50% 口径</strong>:坐席按「较 40px 工具图标大 50%」= 60px。若指 v1.6 的 54px 再 +50%=81px),告知即改</li>
<li><strong>融合位置</strong>:当前 gem 工具栏是介于「消息区」与「InputBar」之间的独立 band。若你想让它直接嵌进 InputBar 顶部(如 v1.3 那样),也可调整</li>
<li><strong>头像占位图</strong><code>./agent-avatar-v0.8.jpg</code> 为占位路径,实际集成时替换</li>
</ol>
<p style="margin-top: 32px; padding-top: 16px; border-top: 1px solid rgba(99, 102, 241, 0.15); color: #6b7280; font-size: 11.5px;">
v1.8 融合会话窗口 · 圆润顶端 · 2026-08-05 · Duckula 主理人 · 等待用户拍板进入开发
</p>
</body>
</html>