555 lines
23 KiB
HTML
555 lines
23 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<title>人工坐席按钮 - 灵动岛风格 v0.1</title>
|
|||
|
|
<style>
|
|||
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|||
|
|
body {
|
|||
|
|
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
|
|||
|
|
background: #f5f5f5;
|
|||
|
|
color: #1f2937;
|
|||
|
|
padding: 24px;
|
|||
|
|
line-height: 1.5;
|
|||
|
|
}
|
|||
|
|
h1 { font-size: 22px; font-weight: 600; margin-bottom: 8px; }
|
|||
|
|
h2 { font-size: 18px; font-weight: 600; margin: 32px 0 12px; padding-bottom: 6px; border-bottom: 1px solid #e5e7eb; }
|
|||
|
|
.meta { color: #6b7280; font-size: 13px; margin-bottom: 24px; }
|
|||
|
|
|
|||
|
|
/* === 现有工具按钮(基准) === */
|
|||
|
|
.baseline { background: #fff; border: 1px solid #e5e7eb; border-radius: 10px; padding: 20px; margin-bottom: 20px; }
|
|||
|
|
.baseline-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; }
|
|||
|
|
.baseline-row .name { width: 100px; font-size: 12px; color: #6b7280; }
|
|||
|
|
.input-bar__tool-btn {
|
|||
|
|
width: 36px; height: 36px; border-radius: 8px;
|
|||
|
|
border: 1px solid #e5e7eb; background: #ffffff;
|
|||
|
|
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
|||
|
|
font-size: 18px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* === 灵动岛按钮(核心) === */
|
|||
|
|
.island-stage {
|
|||
|
|
background: linear-gradient(135deg, #f0f4ff 0%, #fef7ff 100%);
|
|||
|
|
border: 1px solid #e5e7eb;
|
|||
|
|
border-radius: 12px;
|
|||
|
|
padding: 32px 24px;
|
|||
|
|
margin: 16px 0;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
.island-title { font-size: 12px; color: #6b7280; margin-bottom: 16px; }
|
|||
|
|
|
|||
|
|
/* 灵动岛主按钮 - 黑色胶囊 */
|
|||
|
|
.island-btn {
|
|||
|
|
display: inline-flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
gap: 6px;
|
|||
|
|
height: 36px;
|
|||
|
|
min-width: 36px;
|
|||
|
|
padding: 0 12px;
|
|||
|
|
background: #000;
|
|||
|
|
color: #fff;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 18px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
font-family: inherit;
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
position: relative;
|
|||
|
|
overflow: hidden;
|
|||
|
|
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|||
|
|
-webkit-tap-highlight-color: transparent;
|
|||
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|||
|
|
}
|
|||
|
|
.island-btn:hover { transform: scale(1.05); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); }
|
|||
|
|
.island-btn:active { transform: scale(0.96); }
|
|||
|
|
|
|||
|
|
/* 灵动岛状态标签 */
|
|||
|
|
.island-label {
|
|||
|
|
display: inline-block;
|
|||
|
|
max-width: 0;
|
|||
|
|
overflow: hidden;
|
|||
|
|
white-space: nowrap;
|
|||
|
|
opacity: 0;
|
|||
|
|
transition: max-width 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s ease;
|
|||
|
|
}
|
|||
|
|
.island-btn:hover .island-label,
|
|||
|
|
.island-btn.show-label .island-label {
|
|||
|
|
max-width: 100px;
|
|||
|
|
opacity: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* SVG 拟人客服容器 */
|
|||
|
|
.island-char {
|
|||
|
|
width: 24px;
|
|||
|
|
height: 24px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
flex-shrink: 0;
|
|||
|
|
}
|
|||
|
|
.island-char svg { width: 100%; height: 100%; }
|
|||
|
|
|
|||
|
|
/* === 6 态特定样式 + 动画 === */
|
|||
|
|
|
|||
|
|
/* disabled 态:灰色 + 闭眼 */
|
|||
|
|
.island-btn.is-disabled {
|
|||
|
|
background: #6b7280;
|
|||
|
|
cursor: not-allowed;
|
|||
|
|
opacity: 0.7;
|
|||
|
|
}
|
|||
|
|
.island-btn.is-disabled:hover { transform: none; }
|
|||
|
|
.island-btn.is-disabled .island-char { animation: sleepBreath 3s ease-in-out infinite; }
|
|||
|
|
@keyframes sleepBreath {
|
|||
|
|
0%, 100% { transform: translateY(0) scale(1); }
|
|||
|
|
50% { transform: translateY(-2px) scale(0.95); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* active 态:默认 + 站立 */
|
|||
|
|
.island-btn.is-active {
|
|||
|
|
background: #1f2937;
|
|||
|
|
}
|
|||
|
|
.island-btn.is-active .island-char { animation: idleBounce 2s ease-in-out infinite; }
|
|||
|
|
@keyframes idleBounce {
|
|||
|
|
0%, 100% { transform: translateY(0); }
|
|||
|
|
50% { transform: translateY(-1.5px); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* urgent 态:红色 + 抖动 + 脉冲 */
|
|||
|
|
.island-btn.is-urgent {
|
|||
|
|
background: #dc2626;
|
|||
|
|
animation: urgentShake 0.4s ease-in-out infinite, urgentPulse 1.2s ease-in-out infinite;
|
|||
|
|
}
|
|||
|
|
@keyframes urgentShake {
|
|||
|
|
0%, 100% { transform: translateX(0) rotate(0deg); }
|
|||
|
|
25% { transform: translateX(-1.5px) rotate(-3deg); }
|
|||
|
|
75% { transform: translateX(1.5px) rotate(3deg); }
|
|||
|
|
}
|
|||
|
|
@keyframes urgentPulse {
|
|||
|
|
0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.6), 0 2px 8px rgba(0, 0, 0, 0.15); }
|
|||
|
|
50% { box-shadow: 0 0 0 8px rgba(220, 38, 38, 0), 0 2px 8px rgba(0, 0, 0, 0.15); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* waiting 态:橙色 + 摇头 */
|
|||
|
|
.island-btn.is-waiting {
|
|||
|
|
background: #ea580c;
|
|||
|
|
}
|
|||
|
|
.island-btn.is-waiting .island-char { animation: waitingThink 2.5s ease-in-out infinite; }
|
|||
|
|
@keyframes waitingThink {
|
|||
|
|
0%, 100% { transform: rotate(0deg); }
|
|||
|
|
20% { transform: rotate(-8deg); }
|
|||
|
|
40% { transform: rotate(8deg); }
|
|||
|
|
60% { transform: rotate(-6deg); }
|
|||
|
|
80% { transform: rotate(6deg); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* end 态:绿色 + 电话中 */
|
|||
|
|
.island-btn.is-end {
|
|||
|
|
background: #16a34a;
|
|||
|
|
}
|
|||
|
|
.island-btn.is-end .island-char { animation: phoneTalk 1s ease-in-out infinite; }
|
|||
|
|
@keyframes phoneTalk {
|
|||
|
|
0%, 100% { transform: scale(1); }
|
|||
|
|
50% { transform: scale(1.15); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* reopen 态:蓝色 + 招手 */
|
|||
|
|
.island-btn.is-reopen {
|
|||
|
|
background: #2563eb;
|
|||
|
|
}
|
|||
|
|
.island-btn.is-reopen .island-char { animation: reopenWave 1.5s ease-in-out infinite; }
|
|||
|
|
@keyframes reopenWave {
|
|||
|
|
0%, 100% { transform: rotate(0deg) translateX(0); }
|
|||
|
|
25% { transform: rotate(-15deg) translateX(-1px); }
|
|||
|
|
75% { transform: rotate(15deg) translateX(1px); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* === 演示区:状态切换 === */
|
|||
|
|
.state-demo {
|
|||
|
|
background: #fff;
|
|||
|
|
border: 1px solid #e5e7eb;
|
|||
|
|
border-radius: 10px;
|
|||
|
|
padding: 24px;
|
|||
|
|
margin: 16px 0;
|
|||
|
|
}
|
|||
|
|
.state-tabs {
|
|||
|
|
display: flex;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
gap: 8px;
|
|||
|
|
margin-bottom: 24px;
|
|||
|
|
padding-bottom: 16px;
|
|||
|
|
border-bottom: 1px solid #e5e7eb;
|
|||
|
|
}
|
|||
|
|
.state-tab {
|
|||
|
|
padding: 6px 14px;
|
|||
|
|
border: 1px solid #e5e7eb;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
font-size: 13px;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
}
|
|||
|
|
.state-tab.active {
|
|||
|
|
background: #1f2937;
|
|||
|
|
color: #fff;
|
|||
|
|
border-color: #1f2937;
|
|||
|
|
}
|
|||
|
|
.state-tab:hover:not(.active) { background: #f3f4f6; }
|
|||
|
|
|
|||
|
|
.state-stage {
|
|||
|
|
min-height: 140px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
background: linear-gradient(135deg, #f0f4ff 0%, #fef7ff 100%);
|
|||
|
|
border-radius: 12px;
|
|||
|
|
padding: 32px;
|
|||
|
|
margin-bottom: 16px;
|
|||
|
|
}
|
|||
|
|
.state-desc {
|
|||
|
|
color: #4b5563;
|
|||
|
|
font-size: 13px;
|
|||
|
|
line-height: 1.7;
|
|||
|
|
background: #f9fafb;
|
|||
|
|
padding: 12px 16px;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
}
|
|||
|
|
.state-desc strong { color: #1f2937; }
|
|||
|
|
|
|||
|
|
/* === 对比表 === */
|
|||
|
|
.cmp-table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 13px; }
|
|||
|
|
.cmp-table th, .cmp-table td { border: 1px solid #e5e7eb; padding: 8px 10px; text-align: left; }
|
|||
|
|
.cmp-table th { background: #f9fafb; font-weight: 500; }
|
|||
|
|
.cmp-table .yes { color: #16a34a; }
|
|||
|
|
.cmp-table .no { color: #dc2626; }
|
|||
|
|
.cmp-table .partial { color: #f59e0b; }
|
|||
|
|
|
|||
|
|
.divider { border: 0; border-top: 1px dashed #d1d5db; margin: 24px 0; }
|
|||
|
|
.note { background: #fef3c7; border-left: 3px solid #f59e0b; padding: 12px 16px; border-radius: 4px; font-size: 13px; color: #78350f; margin: 12px 0; }
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<h1>🎧 人工坐席按钮 - 灵动岛风格 v0.1</h1>
|
|||
|
|
<p class="meta">参考 iPhone 灵动岛(Dynamic Island)动画 + 拟人卡通客服 · 设计时间: 2026-08-04 凌晨</p>
|
|||
|
|
|
|||
|
|
<div class="note">
|
|||
|
|
⚠️ 这是新方向(灵动岛)的概念原型,只做 1 套主方案。如认可,再扩成 2-3 套横向对比(不同卡通风格/不同灵动岛形状)。
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<h2>📐 与现有工具按钮对比(尺寸/位置)</h2>
|
|||
|
|
<div class="baseline">
|
|||
|
|
<div class="baseline-row">
|
|||
|
|
<span class="name">现有工具按钮</span>
|
|||
|
|
<button class="input-bar__tool-btn">😊</button>
|
|||
|
|
<button class="input-bar__tool-btn">📎</button>
|
|||
|
|
<button class="input-bar__tool-btn">🎤</button>
|
|||
|
|
<span style="color: #9ca3af; font-size: 12px;">36×36 / 8px 圆角 / 1px 浅灰边框 / 18px 图标</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="baseline-row">
|
|||
|
|
<span class="name">灵动岛按钮</span>
|
|||
|
|
<button class="island-btn is-active">
|
|||
|
|
<span class="island-char">
|
|||
|
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<circle cx="12" cy="9" r="3" fill="#fbbf24"/>
|
|||
|
|
<path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/>
|
|||
|
|
<circle cx="9" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
<circle cx="15" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
</svg>
|
|||
|
|
</span>
|
|||
|
|
<span class="island-label">客服在线</span>
|
|||
|
|
</button>
|
|||
|
|
<span style="color: #6b7280; font-size: 12px;">36×36 / 18px 圆角胶囊 / 纯黑背景 / 24px SVG 卡通</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<h2>🎮 6 态实时切换(点击下方 tab 切换)</h2>
|
|||
|
|
<div class="state-demo">
|
|||
|
|
<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">
|
|||
|
|
<div id="stage"></div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="state-desc" id="desc"></div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<h2>🎨 6 态设计详解</h2>
|
|||
|
|
|
|||
|
|
<div class="state-demo">
|
|||
|
|
<h3 style="margin-bottom: 16px;">disabled(无会话/坐席离线)</h3>
|
|||
|
|
<div class="state-stage" style="background: #f3f4f6;">
|
|||
|
|
<button class="island-btn is-disabled">
|
|||
|
|
<span class="island-char">
|
|||
|
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<circle cx="12" cy="9" r="3" fill="#d1d5db"/>
|
|||
|
|
<path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#d1d5db"/>
|
|||
|
|
<path d="M9 9.5l2 1 2-1" stroke="#1f2937" stroke-width="0.5" stroke-linecap="round"/>
|
|||
|
|
<path d="M7 7l4 2 4-2" stroke="#6b7280" stroke-width="0.8" stroke-linecap="round"/>
|
|||
|
|
</svg>
|
|||
|
|
</span>
|
|||
|
|
<span class="island-label">无会话</span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="state-desc">
|
|||
|
|
<strong>视觉</strong>: 灰色 (#6b7280) 背景 + 灰色卡通闭眼/打盹姿态<br>
|
|||
|
|
<strong>动画</strong>: sleepBreath 3s 呼吸(微缩放 0.95-1.0),表达"睡着了/不在"<br>
|
|||
|
|
<strong>交互</strong>: cursor: not-allowed + opacity 0.7,点击无响应
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="state-demo">
|
|||
|
|
<h3 style="margin-bottom: 16px;">active(可呼叫人工坐席)</h3>
|
|||
|
|
<div class="state-stage">
|
|||
|
|
<button class="island-btn is-active">
|
|||
|
|
<span class="island-char">
|
|||
|
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<circle cx="12" cy="9" r="3" fill="#fbbf24"/>
|
|||
|
|
<path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/>
|
|||
|
|
<circle cx="9" cy="9" r="0.6" fill="#1f2937"/>
|
|||
|
|
<circle cx="15" cy="9" r="0.6" fill="#1f2937"/>
|
|||
|
|
<path d="M10 11c0.5 0.5 3 0.5 4 0" stroke="#1f2937" stroke-width="0.5" stroke-linecap="round"/>
|
|||
|
|
</svg>
|
|||
|
|
</span>
|
|||
|
|
<span class="island-label">客服在线</span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="state-desc">
|
|||
|
|
<strong>视觉</strong>: 深灰 (#1f2937) 背景 + 卡通标准姿态(眼睛+微笑)<br>
|
|||
|
|
<strong>动画</strong>: idleBounce 2s 微弹跳(上下 1.5px),表达"待机/有活力"<br>
|
|||
|
|
<strong>交互</strong>: hover 弹出文字标签"客服在线",点击触发 shakeAgent
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="state-demo">
|
|||
|
|
<h3 style="margin-bottom: 16px;">urgent(检测到紧急关键词)</h3>
|
|||
|
|
<div class="state-stage" style="background: #fef2f2;">
|
|||
|
|
<button class="island-btn is-urgent">
|
|||
|
|
<span class="island-char">
|
|||
|
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<circle cx="12" cy="9" r="3" fill="#fbbf24"/>
|
|||
|
|
<path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/>
|
|||
|
|
<circle cx="9" cy="8" r="0.8" fill="#1f2937"/>
|
|||
|
|
<circle cx="15" cy="8" r="0.8" fill="#1f2937"/>
|
|||
|
|
<ellipse cx="12" cy="12" rx="1.5" ry="0.8" fill="#1f2937"/>
|
|||
|
|
</svg>
|
|||
|
|
</span>
|
|||
|
|
<span class="island-label">紧急!</span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="state-desc">
|
|||
|
|
<strong>视觉</strong>: 红色 (#dc2626) 背景 + 卡通惊恐表情(大眼睛+张嘴)<br>
|
|||
|
|
<strong>动画</strong>: urgentShake 0.4s 抖动(左右摇) + urgentPulse 1.2s 脉冲(box-shadow 扩散)<br>
|
|||
|
|
<strong>交互</strong>: hover 弹出"紧急!"提示,点击直接 shakeAgent(跳过 AI 拦截)
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="state-demo">
|
|||
|
|
<h3 style="margin-bottom: 16px;">waiting(排队等待中)</h3>
|
|||
|
|
<div class="state-stage" style="background: #fff7ed;">
|
|||
|
|
<button class="island-btn is-waiting">
|
|||
|
|
<span class="island-char">
|
|||
|
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<circle cx="12" cy="9" r="3" fill="#fbbf24"/>
|
|||
|
|
<path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/>
|
|||
|
|
<circle cx="9" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
<circle cx="15" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
<path d="M8 4l-1 2 2-1" stroke="#1f2937" stroke-width="0.8" stroke-linecap="round" fill="none"/>
|
|||
|
|
</svg>
|
|||
|
|
</span>
|
|||
|
|
<span class="island-label">排队中</span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="state-desc">
|
|||
|
|
<strong>视觉</strong>: 橙色 (#ea580c) 背景 + 卡通思考姿态(问号/挠头)<br>
|
|||
|
|
<strong>动画</strong>: waitingThink 2.5s 摇头(左右 8°-6°-8°),表达"思考/等待"<br>
|
|||
|
|
<strong>交互</strong>: hover 弹出"排队中 · 前面 N 人",点击取消排队
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="state-demo">
|
|||
|
|
<h3 style="margin-bottom: 16px;">end(已接入坐席)</h3>
|
|||
|
|
<div class="state-stage" style="background: #f0fdf4;">
|
|||
|
|
<button class="island-btn is-end">
|
|||
|
|
<span class="island-char">
|
|||
|
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<circle cx="12" cy="9" r="3" fill="#fbbf24"/>
|
|||
|
|
<path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/>
|
|||
|
|
<path d="M6 11 Q4 11 4 13 Q4 15 6 15 L7 14" stroke="#16a34a" stroke-width="1.5" fill="none" stroke-linecap="round"/>
|
|||
|
|
<circle cx="9" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
<circle cx="15" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
<path d="M10 11.5c0.5 0.4 3 0.4 4 0" stroke="#1f2937" stroke-width="0.5" stroke-linecap="round"/>
|
|||
|
|
</svg>
|
|||
|
|
</span>
|
|||
|
|
<span class="island-label">通话中</span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="state-desc">
|
|||
|
|
<strong>视觉</strong>: 绿色 (#16a34a) 背景 + 卡通+耳机图标(电话通话中)<br>
|
|||
|
|
<strong>动画</strong>: phoneTalk 1s 缩放脉冲(1.0-1.15),表达"对话/活跃"<br>
|
|||
|
|
<strong>交互</strong>: hover 弹出"通话中 · 客服小王",点击结束会话
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="state-demo">
|
|||
|
|
<h3 style="margin-bottom: 16px;">reopen(会话已关闭,可重新打开)</h3>
|
|||
|
|
<div class="state-stage" style="background: #eff6ff;">
|
|||
|
|
<button class="island-btn is-reopen">
|
|||
|
|
<span class="island-char">
|
|||
|
|
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|||
|
|
<circle cx="12" cy="9" r="3" fill="#fbbf24"/>
|
|||
|
|
<path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/>
|
|||
|
|
<circle cx="9" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
<circle cx="15" cy="9" r="0.5" fill="#1f2937"/>
|
|||
|
|
<path d="M9 11 Q9 13 12 13 Q15 13 15 11" stroke="#1f2937" stroke-width="0.5" fill="none"/>
|
|||
|
|
<path d="M5 4 Q4 3 5 2" stroke="#2563eb" stroke-width="1" fill="none" stroke-linecap="round"/>
|
|||
|
|
</svg>
|
|||
|
|
</span>
|
|||
|
|
<span class="island-label">重新打开</span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="state-desc">
|
|||
|
|
<strong>视觉</strong>: 蓝色 (#2563eb) 背景 + 卡通招手姿态(嘴笑+招手)<br>
|
|||
|
|
<strong>动画</strong>: reopenWave 1.5s 招手(左右 15° 旋转)<br>
|
|||
|
|
<strong>交互</strong>: hover 弹出"重新打开 · 24h 内有效",点击 reopenCurrentConversation
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<hr class="divider">
|
|||
|
|
|
|||
|
|
<h2>📊 与之前方案对比(为什么改方向)</h2>
|
|||
|
|
<table class="cmp-table">
|
|||
|
|
<thead>
|
|||
|
|
<tr><th>维度</th><th>v0.1(4 套方块按钮)</th><th>v0.2(灵动岛 + 卡通)</th></tr>
|
|||
|
|
</thead>
|
|||
|
|
<tbody>
|
|||
|
|
<tr>
|
|||
|
|
<td>视觉</td>
|
|||
|
|
<td class="partial">方块按钮 + emoji</td>
|
|||
|
|
<td class="yes">黑色胶囊 + 拟人卡通</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>动画</td>
|
|||
|
|
<td class="no">静态 6 态切换,无过渡</td>
|
|||
|
|
<td class="yes">每态有专属动画(呼吸/抖动/摇头/招手)+ 状态间过渡</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>iPhone 灵动岛感</td>
|
|||
|
|
<td class="no">无</td>
|
|||
|
|
<td class="yes">黑色胶囊 + 弹性动画 + label 弹出</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>视觉吸引力</td>
|
|||
|
|
<td class="partial">功能可见,情感弱</td>
|
|||
|
|
<td class="yes">卡通表情 + 动作,情感化(用户会"喜欢"这按钮)</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>与现有工具按钮统一性</td>
|
|||
|
|
<td class="yes">★★★★★(同尺寸/同边框)</td>
|
|||
|
|
<td class="partial">★★★(尺寸 36×36 一致,但黑色胶囊 + 圆角 18px 与方块 8px 不同)</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>hover 反馈</td>
|
|||
|
|
<td class="partial">背景变灰</td>
|
|||
|
|
<td class="yes">scale 1.05 + label 弹出文字"客服在线"等</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>6 态区分度</td>
|
|||
|
|
<td class="partial">靠颜色(普通)</td>
|
|||
|
|
<td class="yes">颜色 + 卡通表情 + 动画(强区分)</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>技术实现</td>
|
|||
|
|
<td class="yes">纯 CSS 简单</td>
|
|||
|
|
<td class="partial">CSS + SVG 卡通(中等)</td>
|
|||
|
|
</tr>
|
|||
|
|
</tbody>
|
|||
|
|
</table>
|
|||
|
|
|
|||
|
|
<h2>❓ 待你拍板</h2>
|
|||
|
|
<ol style="margin-left: 20px; line-height: 1.8;">
|
|||
|
|
<li>这个 <strong>灵动岛 + 拟人小客服</strong> 方向 OK 吗?(如 OK,我会做 2-3 套不同卡通风格对比)</li>
|
|||
|
|
<li>卡通角色是 <strong>拟人客服(戴耳机小黄人风格)</strong> 还是其他?(动物?机器人?抽象图形?)</li>
|
|||
|
|
<li>hover 时是否要 <strong>弹出文字标签</strong>?("客服在线" / "排队中" 等)——这与"图标 only"工具有冲突</li>
|
|||
|
|
<li>如整体 OK,要 <strong>画 2-3 个不同卡通风格</strong> 让你挑,还是先微调当前这套?</li>
|
|||
|
|
</ol>
|
|||
|
|
|
|||
|
|
<p style="margin-top: 32px; padding-top: 16px; border-top: 1px solid #e5e7eb; color: #6b7280; font-size: 12px;">
|
|||
|
|
v0.1 高保真原型 · 2026-08-04 · Duckula 主理人 · 等待用户拍板方向
|
|||
|
|
</p>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// 6 态实时切换逻辑
|
|||
|
|
const states = {
|
|||
|
|
active: {
|
|||
|
|
cls: 'is-active',
|
|||
|
|
label: '客服在线',
|
|||
|
|
char: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="9" r="3" fill="#fbbf24"/><path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/><circle cx="9" cy="9" r="0.6" fill="#1f2937"/><circle cx="15" cy="9" r="0.6" fill="#1f2937"/><path d="M10 11c0.5 0.5 3 0.5 4 0" stroke="#1f2937" stroke-width="0.5" stroke-linecap="round"/></svg>',
|
|||
|
|
desc: '<strong>视觉</strong>: 深灰背景 + 卡通标准姿态(眼睛+微笑) | <strong>动画</strong>: idleBounce 2s 微弹跳 | <strong>交互</strong>: hover 弹出文字"客服在线",点击呼叫人工坐席'
|
|||
|
|
},
|
|||
|
|
disabled: {
|
|||
|
|
cls: 'is-disabled',
|
|||
|
|
label: '无会话',
|
|||
|
|
char: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="9" r="3" fill="#d1d5db"/><path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#d1d5db"/><path d="M9 9.5l2 1 2-1" stroke="#1f2937" stroke-width="0.5" stroke-linecap="round"/><path d="M7 7l4 2 4-2" stroke="#6b7280" stroke-width="0.8" stroke-linecap="round"/></svg>',
|
|||
|
|
desc: '<strong>视觉</strong>: 灰色背景 + 卡通闭眼/打盹 | <strong>动画</strong>: sleepBreath 3s 呼吸(微缩放 0.95-1.0) | <strong>交互</strong>: cursor not-allowed,点击无响应'
|
|||
|
|
},
|
|||
|
|
urgent: {
|
|||
|
|
cls: 'is-urgent',
|
|||
|
|
label: '紧急!',
|
|||
|
|
char: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="9" r="3" fill="#fbbf24"/><path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/><circle cx="9" cy="8" r="0.8" fill="#1f2937"/><circle cx="15" cy="8" r="0.8" fill="#1f2937"/><ellipse cx="12" cy="12" rx="1.5" ry="0.8" fill="#1f2937"/></svg>',
|
|||
|
|
desc: '<strong>视觉</strong>: 红色背景 + 卡通惊恐表情(大眼睛+张嘴) | <strong>动画</strong>: urgentShake 0.4s 抖动 + urgentPulse 1.2s 脉冲 | <strong>交互</strong>: hover 弹出"紧急!"提示,点击直接呼叫坐席'
|
|||
|
|
},
|
|||
|
|
waiting: {
|
|||
|
|
cls: 'is-waiting',
|
|||
|
|
label: '排队中',
|
|||
|
|
char: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="9" r="3" fill="#fbbf24"/><path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/><circle cx="9" cy="9" r="0.5" fill="#1f2937"/><circle cx="15" cy="9" r="0.5" fill="#1f2937"/><path d="M8 4l-1 2 2-1" stroke="#1f2937" stroke-width="0.8" stroke-linecap="round" fill="none"/></svg>',
|
|||
|
|
desc: '<strong>视觉</strong>: 橙色背景 + 卡通思考姿态(问号/挠头) | <strong>动画</strong>: waitingThink 2.5s 摇头(左右 8°-6°-8°) | <strong>交互</strong>: hover 弹出"排队中 · 前面 N 人",点击取消排队'
|
|||
|
|
},
|
|||
|
|
end: {
|
|||
|
|
cls: 'is-end',
|
|||
|
|
label: '通话中',
|
|||
|
|
char: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="9" r="3" fill="#fbbf24"/><path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/><path d="M6 11 Q4 11 4 13 Q4 15 6 15 L7 14" stroke="#16a34a" stroke-width="1.5" fill="none" stroke-linecap="round"/><circle cx="9" cy="9" r="0.5" fill="#1f2937"/><circle cx="15" cy="9" r="0.5" fill="#1f2937"/><path d="M10 11.5c0.5 0.4 3 0.4 4 0" stroke="#1f2937" stroke-width="0.5" stroke-linecap="round"/></svg>',
|
|||
|
|
desc: '<strong>视觉</strong>: 绿色背景 + 卡通+耳机图标(电话通话中) | <strong>动画</strong>: phoneTalk 1s 缩放脉冲(1.0-1.15) | <strong>交互</strong>: hover 弹出"通话中 · 客服小王",点击结束会话'
|
|||
|
|
},
|
|||
|
|
reopen: {
|
|||
|
|
cls: 'is-reopen',
|
|||
|
|
label: '重新打开',
|
|||
|
|
char: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="9" r="3" fill="#fbbf24"/><path d="M5 21c0-3.866 3.134-7 7-7s7 3.134 7 7" fill="#fbbf24"/><circle cx="9" cy="9" r="0.5" fill="#1f2937"/><circle cx="15" cy="9" r="0.5" fill="#1f2937"/><path d="M9 11 Q9 13 12 13 Q15 13 15 11" stroke="#1f2937" stroke-width="0.5" fill="none"/><path d="M5 4 Q4 3 5 2" stroke="#2563eb" stroke-width="1" fill="none" stroke-linecap="round"/></svg>',
|
|||
|
|
desc: '<strong>视觉</strong>: 蓝色背景 + 卡通招手姿态(嘴笑+招手) | <strong>动画</strong>: reopenWave 1.5s 招手(左右 15° 旋转) | <strong>交互</strong>: hover 弹出"重新打开 · 24h 内有效",点击 reopenCurrentConversation'
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
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="island-btn ${s.cls} show-label">
|
|||
|
|
<span class="island-char">${s.char}</span>
|
|||
|
|
<span class="island-label">${s.label}</span>
|
|||
|
|
</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>
|