Files
wecom_it_smart_desk/docs/01-产品文档/02-会话管理/原型-REQ-会话-001-工具栏统一设计v0.3.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

555 lines
23 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>工具栏统一设计 v0.3 - 4 按钮 + 高级拟人</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", -apple-system, sans-serif;
background: #f9fafb;
color: #111827;
padding: 32px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
h1 { font-size: 24px; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 8px; color: #111827; }
h2 { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; margin: 40px 0 12px; color: #1f2937; }
h3 { font-size: 14px; font-weight: 600; margin: 16px 0 8px; color: #374151; }
.meta { color: #6b7280; font-size: 12.5px; margin-bottom: 24px; }
/* === 设计 token === */
:root {
--c-bg-page: #f9fafb;
--c-bg-surface: #ffffff;
--c-bg-hover: #f3f4f6;
--c-border-default: #e5e7eb;
--c-border-hover: #d1d5db;
--c-text-primary: #111827;
--c-text-secondary: #6b7280;
--c-text-tertiary: #9ca3af;
--c-accent: #2563eb;
--c-accent-soft: #eff6ff;
--c-success: #059669;
--c-success-soft: #ecfdf5;
--c-warning: #d97706;
--c-warning-soft: #fef3c7;
--c-danger: #dc2626;
--c-danger-soft: #fef2f2;
--c-info: #4f46e5;
--c-info-soft: #eef2ff;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
--shadow-md: 0 2px 4px rgba(0, 0, 0, 0.06);
}
/* === 4 按钮统一容器(模拟 InputBar 工具栏) === */
.toolbar {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: var(--c-bg-surface);
border: 1px solid var(--c-border-default);
border-radius: 12px;
box-shadow: var(--shadow-sm);
}
.toolbar-section {
display: flex;
align-items: center;
gap: 4px;
}
.toolbar-divider {
width: 1px;
height: 20px;
background: var(--c-border-default);
margin: 0 4px;
}
/* === 统一按钮基础(35×35,8px 圆角,克制) === */
.tool-btn {
width: 35px;
height: 35px;
border: 1px solid var(--c-border-default);
background: var(--c-bg-surface);
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.18s cubic-bezier(0.4, 0, 0.2, 1);
-webkit-tap-highlight-color: transparent;
position: relative;
color: var(--c-text-secondary);
}
.tool-btn:hover {
background: var(--c-bg-hover);
border-color: var(--c-border-hover);
color: var(--c-text-primary);
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
.tool-btn:active { transform: translateY(0) scale(0.96); }
.tool-btn svg { width: 18px; height: 18px; }
/* === 高级拟人 SVG 角色(克制) === */
/* 表情:抽象圆形笑脸 */
.ico-emoji circle.face { fill: none; stroke: currentColor; stroke-width: 1.5; }
.ico-emoji circle.eye { fill: currentColor; }
.ico-emoji path.mouth { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
/* 文件:纸夹 + 折角 */
.ico-file path { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.ico-file path.fold { fill: var(--c-bg-hover); stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
/* 语音:麦克风(柱形 + 弧线底座) */
.ico-voice rect { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
.ico-voice path { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
/* 客服:戴耳机拟人 */
.ico-agent circle.head { fill: var(--c-bg-hover); stroke: currentColor; stroke-width: 1.5; }
.ico-agent circle.ear { fill: currentColor; }
.ico-agent path { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.ico-agent .mouth { fill: currentColor; }
.ico-agent .eye { fill: currentColor; }
/* === 客服按钮 6 态(克制高级) === */
.agent-btn.is-disabled { opacity: 0.45; cursor: not-allowed; color: var(--c-text-tertiary); }
.agent-btn.is-disabled:hover { transform: none; box-shadow: none; background: var(--c-bg-surface); border-color: var(--c-border-default); }
.agent-btn.is-disabled .ico-agent .mouth { display: none; }
.agent-btn.is-active { border-color: var(--c-accent); color: var(--c-accent); background: var(--c-accent-soft); }
.agent-btn.is-urgent {
border-color: var(--c-danger);
color: var(--c-danger);
background: var(--c-danger-soft);
animation: agentBreathe 1.6s ease-in-out infinite;
}
@keyframes agentBreathe {
0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
50% { box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.12); }
}
.agent-btn.is-waiting { border-color: var(--c-warning); color: var(--c-warning); background: var(--c-warning-soft); }
.agent-btn.is-waiting .ico-agent .mouth { fill: var(--c-warning); }
.agent-btn.is-end { border-color: var(--c-success); color: var(--c-success); background: var(--c-success-soft); }
.agent-btn.is-reopen { border-color: var(--c-info); color: var(--c-info); background: var(--c-info-soft); }
/* === 演示容器 === */
.demo-block {
background: var(--c-bg-surface);
border: 1px solid var(--c-border-default);
border-radius: 12px;
padding: 24px;
margin-bottom: 20px;
box-shadow: var(--shadow-sm);
}
.demo-label { font-size: 11.5px; color: var(--c-text-secondary); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 12px; font-weight: 500; }
/* === 状态切换 tab === */
.state-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 20px; padding-bottom: 16px; border-bottom: 1px solid var(--c-border-default); }
.state-tab {
padding: 6px 12px;
border: 1px solid var(--c-border-default);
background: var(--c-bg-surface);
border-radius: 6px;
cursor: pointer;
font-size: 12.5px;
color: var(--c-text-secondary);
transition: all 0.15s;
font-family: inherit;
}
.state-tab:hover { background: var(--c-bg-hover); }
.state-tab.active { background: var(--c-text-primary); color: #fff; border-color: var(--c-text-primary); }
.state-stage {
min-height: 100px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #fafbfc 0%, #f5f7fa 100%);
border-radius: 8px;
padding: 32px;
}
.state-desc { color: var(--c-text-secondary); font-size: 12.5px; line-height: 1.7; background: #fafbfc; padding: 12px 14px; border-radius: 6px; border-left: 2px solid var(--c-accent); margin-top: 12px; }
.state-desc strong { color: var(--c-text-primary); }
/* === 4 按钮并排展示 === */
.four-btns {
display: flex;
gap: 8px;
align-items: center;
padding: 16px;
background: #fafbfc;
border: 1px solid var(--c-border-default);
border-radius: 10px;
margin: 12px 0;
}
/* === 对比表 === */
.cmp-table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 12.5px; }
.cmp-table th, .cmp-table td { border: 1px solid var(--c-border-default); padding: 8px 10px; text-align: left; }
.cmp-table th { background: #fafbfc; font-weight: 600; }
.yes { color: #059669; }
.no { color: #dc2626; }
.partial { color: #d97706; }
.palette { display: flex; gap: 6px; flex-wrap: wrap; }
.palette-item { width: 48px; height: 48px; border-radius: 6px; display: flex; align-items: flex-end; padding: 4px; font-size: 9.5px; color: #fff; font-weight: 500; }
.note { background: #fef3c7; border-left: 3px solid #d97706; padding: 12px 16px; border-radius: 4px; font-size: 12.5px; color: #78350f; margin: 16px 0; }
</style>
</head>
<body>
<h1>工具栏统一设计 v0.3</h1>
<p class="meta">4 按钮(😊📎🎤🎧)统一设计 + 高级拟人角色 + 克制 B 端配色 · 2026-08-04 凌晨</p>
<div class="note">
📌 本版核心改动(对比 v0.1 / v0.2):<br>
• 4 个按钮**统一规格** + **统一设计语言**(35×35, 8px 圆角, 1px 边框, 浅色背景, 高级拟人 SVG 角色)<br>
• 角色设计**克制**:几何抽象拟人(不夸张),符合 B 端 SaaS 工具审美(对标 Linear / Notion / Cursor)<br>
• 配色**高级**:中性灰 + 点缀色(蓝/橙/红/绿/紫),不刺眼、有质感<br>
• 动画**克制**:仅微动效(hover 浮起 + scale 0.96,6 态无夸张抖动/招手)
</div>
<h2>🎨 设计 token(可复用到全局)</h2>
<div class="demo-block">
<h3>配色色板</h3>
<div class="palette">
<div class="palette-item" style="background: #f9fafb; color: #111827;">#f9fafb page</div>
<div class="palette-item" style="background: #ffffff; color: #111827; border: 1px solid #e5e7eb;">#ffffff surface</div>
<div class="palette-item" style="background: #f3f4f6; color: #111827;">#f3f4f6 hover</div>
<div class="palette-item" style="background: #e5e7eb; color: #111827;">#e5e7eb border</div>
<div class="palette-item" style="background: #6b7280;">#6b7280 text-2</div>
<div class="palette-item" style="background: #1f2937;">#1f2937 text-1</div>
<div class="palette-item" style="background: #2563eb;">#2563eb accent</div>
<div class="palette-item" style="background: #059669;">#059669 success</div>
<div class="palette-item" style="background: #d97706;">#d97706 warning</div>
<div class="palette-item" style="background: #dc2626;">#dc2626 danger</div>
<div class="palette-item" style="background: #4f46e5;">#4f46e5 info</div>
</div>
<h3>圆角与阴影</h3>
<p style="font-size: 12.5px; color: var(--c-text-secondary);">
圆角: 8px(按钮)/ 12px(容器)/ 6px(tab)<br>
阴影: 0 1px 2px rgba(0,0,0,0.04)(静态) / 0 2px 4px rgba(0,0,0,0.06)(hover 微浮)
</p>
</div>
<h2>🎭 4 按钮统一设计(角色图谱)</h2>
<div class="demo-block">
<div class="demo-label">工具栏并排展示(模拟 InputBar 工具栏位置)</div>
<div class="four-btns">
<!-- 表情 -->
<button class="tool-btn" title="表情">
<svg class="ico-emoji" viewBox="0 0 18 18" fill="none">
<circle class="face" cx="9" cy="9" r="6.5"/>
<circle class="eye" cx="6.5" cy="8" r="0.8"/>
<circle class="eye" cx="11.5" cy="8" r="0.8"/>
<path class="mouth" d="M6 11.5 Q9 13.5 12 11.5"/>
</svg>
</button>
<!-- 文件 -->
<button class="tool-btn" title="文件">
<svg class="ico-file" viewBox="0 0 18 18" fill="none">
<path d="M3 2 L11 2 L15 6 L15 16 L3 16 Z"/>
<path class="fold" d="M11 2 L11 6 L15 6"/>
<line x1="6" y1="10" x2="12" y2="10"/>
<line x1="6" y1="13" x2="10" y2="13"/>
</svg>
</button>
<!-- 分隔 -->
<div class="toolbar-divider"></div>
<!-- 语音 -->
<button class="tool-btn" title="语音">
<svg class="ico-voice" viewBox="0 0 18 18" fill="none">
<rect x="6" y="2" width="6" height="9" rx="3"/>
<path d="M3 9 Q3 13 9 13 Q15 13 15 9"/>
<line x1="9" y1="13" x2="9" y2="16"/>
</svg>
</button>
<!-- 客服(默认 active 态) -->
<button class="tool-btn agent-btn is-active" title="客服在线 · 点击呼叫">
<svg class="ico-agent" viewBox="0 0 18 18" fill="none">
<circle class="head" cx="9" cy="8" r="4"/>
<circle class="ear" cx="3.5" cy="8" r="1.2"/>
<circle class="ear" cx="14.5" cy="8" r="1.2"/>
<path d="M2.5 8 Q2.5 6 4 6 L4 10 Q2.5 10 2.5 8 Z" fill="currentColor" opacity="0.85"/>
<path d="M15.5 8 Q15.5 6 14 6 L14 10 Q15.5 10 15.5 8 Z" fill="currentColor" opacity="0.85"/>
<circle class="eye" cx="7" cy="8" r="0.7"/>
<circle class="eye" cx="11" cy="8" r="0.7"/>
<path class="mouth" d="M7 10.5 Q9 12 11 10.5"/>
</svg>
</button>
</div>
<p style="font-size: 12px; color: var(--c-text-secondary); margin-top: 8px;">
视觉特点: 35×35 统一尺寸, 8px 圆角, 1px 边框, 18px SVG 几何抽象拟人, 中性灰 + 蓝色点缀(active)
</p>
</div>
<h2>👤 角色详细设计(4 按钮的"角色")</h2>
<div class="demo-block">
<h3>1. 表情(😊) — 抽象圆形笑脸</h3>
<div style="display: flex; align-items: center; gap: 16px; padding: 16px; background: #fafbfc; border-radius: 8px;">
<button class="tool-btn">
<svg class="ico-emoji" viewBox="0 0 18 18" fill="none">
<circle class="face" cx="9" cy="9" r="6.5"/>
<circle class="eye" cx="6.5" cy="8" r="0.8"/>
<circle class="eye" cx="11.5" cy="8" r="0.8"/>
<path class="mouth" d="M6 11.5 Q9 13.5 12 11.5"/>
</svg>
</button>
<div style="font-size: 12.5px; color: var(--c-text-secondary); line-height: 1.6;">
<strong style="color: var(--c-text-primary);">设计</strong>: 圆形轮廓 + 两个点状眼睛 + 弧形嘴<br>
<strong style="color: var(--c-text-primary);">意图</strong>: 极简笑脸,中性、克制、专业(不用 emoji 圆形笑脸)
</div>
</div>
<h3>2. 文件(📎) — 纸夹 + 折角</h3>
<div style="display: flex; align-items: center; gap: 16px; padding: 16px; background: #fafbfc; border-radius: 8px;">
<button class="tool-btn">
<svg class="ico-file" viewBox="0 0 18 18" fill="none">
<path d="M3 2 L11 2 L15 6 L15 16 L3 16 Z"/>
<path class="fold" d="M11 2 L11 6 L15 6"/>
<line x1="6" y1="10" x2="12" y2="10"/>
<line x1="6" y1="13" x2="10" y2="13"/>
</svg>
</button>
<div style="font-size: 12.5px; color: var(--c-text-secondary); line-height: 1.6;">
<strong style="color: var(--c-text-primary);">设计</strong>: 文档轮廓 + 右上折角(阴影) + 2 行文字线<br>
<strong style="color: var(--c-text-primary);">意图</strong>: 拟人化的"文档",比回形针(📎)更明确表达"文件/附件"语义
</div>
</div>
<h3>3. 语音(🎤) — 麦克风(柱形 + 弧线底座)</h3>
<div style="display: flex; align-items: center; gap: 16px; padding: 16px; background: #fafbfc; border-radius: 8px;">
<button class="tool-btn">
<svg class="ico-voice" viewBox="0 0 18 18" fill="none">
<rect x="6" y="2" width="6" height="9" rx="3"/>
<path d="M3 9 Q3 13 9 13 Q15 13 15 9"/>
<line x1="9" y1="13" x2="9" y2="16"/>
</svg>
</button>
<div style="font-size: 12.5px; color: var(--c-text-secondary); line-height: 1.6;">
<strong style="color: var(--c-text-primary);">设计</strong>: 圆角麦克风柱 + 弧形底座 + 支柱<br>
<strong style="color: var(--c-text-primary);">意图</strong>: 经典麦克风几何,清晰表达"语音输入"
</div>
</div>
<h3>4. 客服(🎧) — 戴耳机的拟人客服</h3>
<div style="display: flex; align-items: center; gap: 16px; padding: 16px; background: #fafbfc; border-radius: 8px;">
<button class="tool-btn agent-btn is-active">
<svg class="ico-agent" viewBox="0 0 18 18" fill="none">
<circle class="head" cx="9" cy="8" r="4"/>
<circle class="ear" cx="3.5" cy="8" r="1.2"/>
<circle class="ear" cx="14.5" cy="8" r="1.2"/>
<path d="M2.5 8 Q2.5 6 4 6 L4 10 Q2.5 10 2.5 8 Z" fill="currentColor" opacity="0.85"/>
<path d="M15.5 8 Q15.5 6 14 6 L14 10 Q15.5 10 15.5 8 Z" fill="currentColor" opacity="0.85"/>
<circle class="eye" cx="7" cy="8" r="0.7"/>
<circle class="eye" cx="11" cy="8" r="0.7"/>
<path class="mouth" d="M7 10.5 Q9 12 11 10.5"/>
</svg>
</button>
<div style="font-size: 12.5px; color: var(--c-text-secondary); line-height: 1.6;">
<strong style="color: var(--c-text-primary);">设计</strong>: 圆形头部(背景填充) + 两侧椭圆耳罩 + 简单眼睛弧形嘴<br>
<strong style="color: var(--c-text-primary);">意图</strong>: 戴耳机的拟人客服,克制专业(不夸张卡通)<br>
<strong style="color: var(--c-text-primary);">与之前对比</strong>: v0.2 卡通是"全身小人",v0.3 改为"头像 + 耳罩",更克制专业
</div>
</div>
</div>
<h2>🎬 客服按钮 6 态(克制设计)</h2>
<div class="demo-block">
<div class="state-tabs">
<button class="state-tab active" data-state="active">active</button>
<button class="state-tab" data-state="disabled">disabled</button>
<button class="state-tab" data-state="urgent">urgent</button>
<button class="state-tab" data-state="waiting">waiting</button>
<button class="state-tab" data-state="end">end</button>
<button class="state-tab" data-state="reopen">reopen</button>
</div>
<div class="state-stage" id="stage"></div>
<div class="state-desc" id="desc"></div>
</div>
<h2>📊 4 按钮 hover 状态对比</h2>
<div class="demo-block">
<div class="four-btns">
<button class="tool-btn" style="background: #f3f4f6; border-color: #d1d5db; color: #111827; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.06);">
<svg class="ico-emoji" viewBox="0 0 18 18" fill="none">
<circle class="face" cx="9" cy="9" r="6.5"/>
<circle class="eye" cx="6.5" cy="8" r="0.8"/>
<circle class="eye" cx="11.5" cy="8" r="0.8"/>
<path class="mouth" d="M6 11.5 Q9 13.5 12 11.5"/>
</svg>
</button>
<button class="tool-btn" style="background: #f3f4f6; border-color: #d1d5db; color: #111827; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.06);">
<svg class="ico-file" viewBox="0 0 18 18" fill="none">
<path d="M3 2 L11 2 L15 6 L15 16 L3 16 Z"/>
<path class="fold" d="M11 2 L11 6 L15 6"/>
<line x1="6" y1="10" x2="12" y2="10"/>
<line x1="6" y1="13" x2="10" y2="13"/>
</svg>
</button>
<div class="toolbar-divider"></div>
<button class="tool-btn" style="background: #f3f4f6; border-color: #d1d5db; color: #111827; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.06);">
<svg class="ico-voice" viewBox="0 0 18 18" fill="none">
<rect x="6" y="2" width="6" height="9" rx="3"/>
<path d="M3 9 Q3 13 9 13 Q15 13 15 9"/>
<line x1="9" y1="13" x2="9" y2="16"/>
</svg>
</button>
<button class="tool-btn" style="background: #f3f4f6; border-color: #d1d5db; color: #111827; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.06);">
<svg class="ico-agent" viewBox="0 0 18 18" fill="none">
<circle class="head" cx="9" cy="8" r="4"/>
<circle class="ear" cx="3.5" cy="8" r="1.2"/>
<circle class="ear" cx="14.5" cy="8" r="1.2"/>
<path d="M2.5 8 Q2.5 6 4 6 L4 10 Q2.5 10 2.5 8 Z" fill="currentColor" opacity="0.85"/>
<path d="M15.5 8 Q15.5 6 14 6 L14 10 Q15.5 10 15.5 8 Z" fill="currentColor" opacity="0.85"/>
<circle class="eye" cx="7" cy="8" r="0.7"/>
<circle class="eye" cx="11" cy="8" r="0.7"/>
<path class="mouth" d="M7 10.5 Q9 12 11 10.5"/>
</svg>
</button>
</div>
<p style="font-size: 12px; color: var(--c-text-secondary); margin-top: 8px;">
hover 状态: 背景 #f3f4f6 + 边框 #d1d5db + 文字色 #111827 + translateY(-1px) 微浮 + shadow-md
</p>
</div>
<h2>📊 与之前版本对比(为什么改方向)</h2>
<table class="cmp-table">
<thead>
<tr>
<th>维度</th>
<th>v0.1 方块按钮</th>
<th>v0.2 灵动岛卡通</th>
<th>v0.3 统一克制拟人 ⭐</th>
</tr>
</thead>
<tbody>
<tr>
<td>4 按钮统一</td>
<td class="no">× (只设计 1 个按钮)</td>
<td class="no">× (只设计 1 个按钮)</td>
<td class="yes">✓ 4 按钮统一规格 + 统一设计语言</td>
</tr>
<tr>
<td>角色设计</td>
<td class="no">emoji(无设计)</td>
<td class="partial">夸张卡通小黄人(低龄)</td>
<td class="yes">克制几何拟人头像(Linear/Notion 风)</td>
</tr>
<tr>
<td>配色</td>
<td class="partial">朴素(单调)</td>
<td class="partial">卡通色(刺眼)</td>
<td class="yes">中性灰 + 点缀色(高级 SaaS)</td>
</tr>
<tr>
<td>动画克制度</td>
<td class="yes">无动画</td>
<td class="no">抖动/招手/摇头(夸张)</td>
<td class="yes">hover 微浮 + 状态边框变色(克制)</td>
</tr>
<tr>
<td>尺寸</td>
<td class="partial">36×36 / 8px</td>
<td class="no">36×36 / 18px(不一致)</td>
<td class="yes">35×35 / 8px / 18px SVG(与现有对齐)</td>
</tr>
<tr>
<td>与现有工具按钮风格</td>
<td class="yes">★★★★★</td>
<td class="no"></td>
<td class="yes">★★★★★(统一规格 + 统一语言)</td>
</tr>
<tr>
<td>B 端专业感</td>
<td class="partial">★★★</td>
<td class="no"></td>
<td class="yes">★★★★★(对标 Linear/Notion)</td>
</tr>
</tbody>
</table>
<h2>❓ 待你拍板</h2>
<ol style="margin-left: 20px; line-height: 1.8;">
<li><strong>整体方向 OK 吗</strong>?克制拟人 + 4 按钮统一 + Linear/Notion 风</li>
<li><strong>客服角色</strong>:当前是"戴耳机圆形头像",可以吗?如需更精致,可以请设计师重画 SVG</li>
<li><strong>客服按钮 6 态</strong>的"克制版"设计(仅边框/底色变化,无夸张动画)符合你的预期吗?</li>
<li><strong>大小</strong>用 35×35 还是回归 36×36(与现有一致)?</li>
</ol>
<p style="margin-top: 32px; padding-top: 16px; border-top: 1px solid #e5e7eb; color: #6b7280; font-size: 11.5px;">
v0.3 工具栏统一设计 · 2026-08-04 · Duckula 主理人 · 等待用户拍板
</p>
<script>
const states = {
active: {
cls: 'is-active',
desc: '<strong>active</strong>: 蓝色边框 + 浅蓝背景 + 蓝色图标 — 默认"客服在线,等待呼叫"'
},
disabled: {
cls: 'is-disabled',
desc: '<strong>disabled</strong>: 灰色 + opacity 0.45 + 嘴隐藏(无表情) — 表达"不可用",无动画'
},
urgent: {
cls: 'is-urgent',
desc: '<strong>urgent</strong>: 红色边框 + 浅红背景 + 红色图标 + 1.6s 呼吸(box-shadow 扩散) — 表达"紧急,需关注"'
},
waiting: {
cls: 'is-waiting',
desc: '<strong>waiting</strong>: 橙色边框 + 浅橙背景 + 橙色图标 + 嘴变色 — 表达"排队中"'
},
end: {
cls: 'is-end',
desc: '<strong>end</strong>: 绿色边框 + 浅绿背景 + 绿色图标 — 表达"已接入坐席,通话中"'
},
reopen: {
cls: 'is-reopen',
desc: '<strong>reopen</strong>: 紫色边框 + 浅紫背景 + 紫色图标 — 表达"会话已关闭,可重新打开"'
}
};
const svgHTML = `<svg class="ico-agent" viewBox="0 0 18 18" fill="none">
<circle class="head" cx="9" cy="8" r="4"/>
<circle class="ear" cx="3.5" cy="8" r="1.2"/>
<circle class="ear" cx="14.5" cy="8" r="1.2"/>
<path d="M2.5 8 Q2.5 6 4 6 L4 10 Q2.5 10 2.5 8 Z" fill="currentColor" opacity="0.85"/>
<path d="M15.5 8 Q15.5 6 14 6 L14 10 Q15.5 10 15.5 8 Z" fill="currentColor" opacity="0.85"/>
<circle class="eye" cx="7" cy="8" r="0.7"/>
<circle class="eye" cx="11" cy="8" r="0.7"/>
<path class="mouth" d="M7 10.5 Q9 12 11 10.5"/>
</svg>`;
const stage = document.getElementById('stage');
const descEl = document.getElementById('desc');
const tabs = document.querySelectorAll('.state-tab');
function render(state) {
const s = states[state];
stage.innerHTML = `<button class="tool-btn agent-btn ${s.cls}">${svgHTML}</button>`;
descEl.innerHTML = s.desc;
}
tabs.forEach(tab => {
tab.addEventListener('click', () => {
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
render(tab.dataset.state);
});
});
render('active');
</script>
</body>
</html>