Browse Source

优化小图标样式

dev-mcp
wanghanlin 4 weeks ago
parent
commit
eafb41ff77
  1. 145
      client/dist/chatbot-sdk.js
  2. 2
      client/dist/chatbot-sdk.js.map
  3. 2
      client/dist/chatbot-sdk.min.js
  4. 2
      client/dist/chatbot-sdk.min.js.map
  5. 1019
      client/icon-designs-preview.html
  6. 21
      client/src/config.ts
  7. 124
      client/src/styles.ts
  8. 8
      pom.xml
  9. 11
      src/main/resources/application.properties
  10. 6
      src/main/resources/application.yml
  11. 145
      src/main/resources/static/sdk/chatbot-sdk.js
  12. 2
      src/main/resources/static/sdk/chatbot-sdk.js.map
  13. 2
      src/main/resources/static/sdk/chatbot-sdk.min.js
  14. 2
      src/main/resources/static/sdk/chatbot-sdk.min.js.map

145
client/dist/chatbot-sdk.js

@ -82,10 +82,23 @@ var ChatbotSDK = (function () {
}, },
}; };
/** 默认悬浮按钮 SVG 图标(客服对话气泡) */
const DEFAULT_LAUNCHER_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
<path d="M8 9h8"/><path d="M8 13h6"/>
/** 默认悬浮按钮 SVG 图标(赛博机器人:对话气泡 + 机器人面孔 + 天线能量灯 + 眨眼动效) */
const DEFAULT_LAUNCHER_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 32 32" fill="none">
<defs>
<linearGradient id="csk-ico-grad" x1="6" y1="8" x2="26" y2="28" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#fff" stop-opacity="1"/>
<stop offset="100%" stop-color="#fff" stop-opacity="0.82"/>
</linearGradient>
</defs>
<rect x="5" y="8" width="22" height="16" rx="4" fill="url(#csk-ico-grad)"/>
<path d="M9 24L6 28.5l6-4.5z" fill="url(#csk-ico-grad)"/>
<line x1="16" y1="8" x2="16" y2="4" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="16" cy="3" r="1.5" fill="#fff" class="csk-ico-antenna"/>
<rect x="9.5" y="13" width="4" height="3.5" rx="1.2" fill="rgba(99,102,241,0.55)" class="csk-ico-eye"/>
<rect x="18.5" y="13" width="4" height="3.5" rx="1.2" fill="rgba(99,102,241,0.55)" class="csk-ico-eye"/>
<circle cx="11" cy="14.2" r="0.7" fill="#fff" opacity="0.9"/>
<circle cx="20" cy="14.2" r="0.7" fill="#fff" opacity="0.9"/>
<path d="M12.5 20 Q16 22.5 19.5 20" stroke="rgba(99,102,241,0.4)" stroke-width="1.2" fill="none" stroke-linecap="round"/>
</svg>`; </svg>`;
/** /**
* 解析并校验用户传入的配置填充默认值 * 解析并校验用户传入的配置填充默认值
@ -840,42 +853,119 @@ var ChatbotSDK = (function () {
position: fixed; position: fixed;
bottom: 24px; bottom: 24px;
z-index: 9998; z-index: 9998;
width: 58px;
height: 58px;
width: 60px;
height: 60px;
border-radius: 50%; border-radius: 50%;
background: var(--csk-bg-user); background: var(--csk-bg-user);
box-shadow: 0 8px 24px rgba(var(--csk-primary-rgb), 0.42), 0 2px 6px rgba(15, 23, 42, 0.12);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.22s ease;
border: none;
color: #fff; color: #fff;
user-select: none; user-select: none;
overflow: visible;
/* 半透明白色光环边框,在白色页面上清晰分离按钮与背景 */
border: 2.5px solid rgba(255, 255, 255, 0.55);
/* 三层投影:接地阴影 + 彩色光晕,把按钮从白底「托」出来 */
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.06),
0 4px 16px rgba(0, 0, 0, 0.10),
0 6px 24px rgba(var(--csk-primary-rgb), 0.28),
0 0 48px rgba(var(--csk-primary-rgb), 0.12);
transition:
transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.25s ease,
border-color 0.25s ease;
animation: csk-launcher-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
} }
.csk-launcher--right { right: 24px; } .csk-launcher--right { right: 24px; }
.csk-launcher--left { left: 24px; } .csk-launcher--left { left: 24px; }
/* 高光扫过动效 */
.csk-launcher::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 40%;
height: 200%;
border-radius: 50%;
background: linear-gradient(
105deg,
transparent 30%,
rgba(255, 255, 255, 0.28) 48%,
rgba(255, 255, 255, 0.1) 52%,
transparent 70%
);
transform: rotate(25deg);
animation: csk-shimmer 4s ease-in-out infinite;
pointer-events: none;
}
/* 呼吸色晕 — 配合接地阴影,强化白底上的立体存在感 */
.csk-launcher::after { .csk-launcher::after {
content: ''; content: '';
position: absolute; position: absolute;
inset: -4px;
inset: -18px;
border-radius: 50%; border-radius: 50%;
border: 2px solid rgba(var(--csk-primary-rgb), 0.35);
opacity: 0;
animation: csk-ping 2.6s cubic-bezier(0, 0, 0.2, 1) infinite;
background: radial-gradient(circle, rgba(var(--csk-primary-rgb), 0.18) 0%, rgba(var(--csk-primary-rgb), 0.05) 45%, transparent 68%);
animation: csk-breathe 3.5s ease-in-out infinite;
pointer-events: none; pointer-events: none;
} }
.csk-launcher:hover { .csk-launcher:hover {
transform: translateY(-2px) scale(1.05);
box-shadow: 0 12px 32px rgba(var(--csk-primary-rgb), 0.5), 0 4px 10px rgba(15, 23, 42, 0.14);
transform: translateY(-3px) scale(1.08);
border-color: rgba(255, 255, 255, 0.75);
box-shadow:
0 2px 6px rgba(0, 0, 0, 0.10),
0 8px 24px rgba(0, 0, 0, 0.14),
0 10px 36px rgba(var(--csk-primary-rgb), 0.32),
0 0 56px rgba(var(--csk-primary-rgb), 0.14);
}
.csk-launcher:hover::before { animation-play-state: paused; }
.csk-launcher:hover::after {
animation: none;
inset: -22px;
background: radial-gradient(circle, rgba(var(--csk-primary-rgb), 0.22) 0%, rgba(var(--csk-primary-rgb), 0.06) 45%, transparent 68%);
}
.csk-launcher:active { transform: scale(0.93); }
.csk-launcher svg {
width: 30px;
height: 30px;
position: relative;
z-index: 1;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.15));
}
@keyframes csk-launcher-in {
0% { opacity: 0; transform: scale(0.5) translateY(16px); }
60% { transform: scale(1.06) translateY(-2px); }
100% { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes csk-shimmer {
0%, 100% { left: -60%; opacity: 0; }
20% { opacity: 1; }
60% { opacity: 1; }
80% { left: 120%; opacity: 0; }
}
@keyframes csk-breathe {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.15); opacity: 0.35; }
} }
.csk-launcher:active { transform: scale(0.94); }
.csk-launcher svg { width: 28px; height: 28px; }
@keyframes csk-ping {
0% { transform: scale(0.92); opacity: 0.7; }
70%, 100% { transform: scale(1.35); opacity: 0; }
/* SVG 图标内部动效:眨眼 */
.csk-launcher .csk-ico-eye {
animation: csk-eye-blink 4s ease-in-out infinite;
}
@keyframes csk-eye-blink {
0%, 42%, 48%, 100% { opacity: 1; }
45% { opacity: 0.1; }
}
/* SVG 图标内部动效:天线能量闪烁 */
.csk-launcher .csk-ico-antenna {
animation: csk-antenna-glow 2s ease-in-out infinite;
}
@keyframes csk-antenna-glow {
0%, 100% { opacity: 0.5; }
50% { opacity: 1; }
} }
/* ========== 聊天弹窗 ========== */ /* ========== 聊天弹窗 ========== */
@ -1803,8 +1893,8 @@ var ChatbotSDK = (function () {
/* ========== Launcher 未读徽章 ========== */ /* ========== Launcher 未读徽章 ========== */
.csk-launcher__badge { .csk-launcher__badge {
position: absolute; position: absolute;
top: -3px;
right: -3px;
top: -2px;
right: -2px;
width: 16px; width: 16px;
height: 16px; height: 16px;
border-radius: 50%; border-radius: 50%;
@ -1931,7 +2021,16 @@ var ChatbotSDK = (function () {
border-radius: inherit; border-radius: inherit;
} }
/* 弹窗打开时隐藏 launcher 上的焦点环 */ /* 弹窗打开时隐藏 launcher 上的焦点环 */
.csk-launcher:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(var(--csk-primary-rgb), 0.4); }
.csk-launcher:focus-visible {
outline: none;
border-color: rgba(255, 255, 255, 0.75);
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.06),
0 4px 16px rgba(0, 0, 0, 0.10),
0 6px 24px rgba(var(--csk-primary-rgb), 0.28),
0 0 48px rgba(var(--csk-primary-rgb), 0.12),
0 0 0 4px rgba(var(--csk-primary-rgb), 0.3);
}
/* ========== a11y aria-live 播报区(视觉隐藏) ========== */ /* ========== a11y aria-live 播报区(视觉隐藏) ========== */
.csk-sr-only { .csk-sr-only {

2
client/dist/chatbot-sdk.js.map
File diff suppressed because it is too large
View File

2
client/dist/chatbot-sdk.min.js
File diff suppressed because it is too large
View File

2
client/dist/chatbot-sdk.min.js.map
File diff suppressed because it is too large
View File

1019
client/icon-designs-preview.html
File diff suppressed because it is too large
View File

21
client/src/config.ts

@ -9,10 +9,23 @@
import { SDKConfig, ResolvedConfig } from './types'; import { SDKConfig, ResolvedConfig } from './types';
import { logger } from './logger'; import { logger } from './logger';
/** 默认悬浮按钮 SVG 图标(客服对话气泡) */
const DEFAULT_LAUNCHER_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
<path d="M8 9h8"/><path d="M8 13h6"/>
/** 默认悬浮按钮 SVG 图标(赛博机器人:对话气泡 + 机器人面孔 + 天线能量灯 + 眨眼动效) */
const DEFAULT_LAUNCHER_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 32 32" fill="none">
<defs>
<linearGradient id="csk-ico-grad" x1="6" y1="8" x2="26" y2="28" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#fff" stop-opacity="1"/>
<stop offset="100%" stop-color="#fff" stop-opacity="0.82"/>
</linearGradient>
</defs>
<rect x="5" y="8" width="22" height="16" rx="4" fill="url(#csk-ico-grad)"/>
<path d="M9 24L6 28.5l6-4.5z" fill="url(#csk-ico-grad)"/>
<line x1="16" y1="8" x2="16" y2="4" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="16" cy="3" r="1.5" fill="#fff" class="csk-ico-antenna"/>
<rect x="9.5" y="13" width="4" height="3.5" rx="1.2" fill="rgba(99,102,241,0.55)" class="csk-ico-eye"/>
<rect x="18.5" y="13" width="4" height="3.5" rx="1.2" fill="rgba(99,102,241,0.55)" class="csk-ico-eye"/>
<circle cx="11" cy="14.2" r="0.7" fill="#fff" opacity="0.9"/>
<circle cx="20" cy="14.2" r="0.7" fill="#fff" opacity="0.9"/>
<path d="M12.5 20 Q16 22.5 19.5 20" stroke="rgba(99,102,241,0.4)" stroke-width="1.2" fill="none" stroke-linecap="round"/>
</svg>`; </svg>`;
/** /**

124
client/src/styles.ts

@ -72,42 +72,119 @@ function getStyles(config: ResolvedConfig): string {
position: fixed; position: fixed;
bottom: 24px; bottom: 24px;
z-index: 9998; z-index: 9998;
width: 58px;
height: 58px;
width: 60px;
height: 60px;
border-radius: 50%; border-radius: 50%;
background: var(--csk-bg-user); background: var(--csk-bg-user);
box-shadow: 0 8px 24px rgba(var(--csk-primary-rgb), 0.42), 0 2px 6px rgba(15, 23, 42, 0.12);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.22s ease;
border: none;
color: #fff; color: #fff;
user-select: none; user-select: none;
overflow: visible;
/* 半透明白色光环边框,在白色页面上清晰分离按钮与背景 */
border: 2.5px solid rgba(255, 255, 255, 0.55);
/* 三层投影:接地阴影 + 彩色光晕,把按钮从白底「托」出来 */
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.06),
0 4px 16px rgba(0, 0, 0, 0.10),
0 6px 24px rgba(var(--csk-primary-rgb), 0.28),
0 0 48px rgba(var(--csk-primary-rgb), 0.12);
transition:
transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.25s ease,
border-color 0.25s ease;
animation: csk-launcher-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
} }
.csk-launcher--right { right: 24px; } .csk-launcher--right { right: 24px; }
.csk-launcher--left { left: 24px; } .csk-launcher--left { left: 24px; }
/* 高光扫过动效 */
.csk-launcher::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 40%;
height: 200%;
border-radius: 50%;
background: linear-gradient(
105deg,
transparent 30%,
rgba(255, 255, 255, 0.28) 48%,
rgba(255, 255, 255, 0.1) 52%,
transparent 70%
);
transform: rotate(25deg);
animation: csk-shimmer 4s ease-in-out infinite;
pointer-events: none;
}
/* 呼吸色晕 — 配合接地阴影,强化白底上的立体存在感 */
.csk-launcher::after { .csk-launcher::after {
content: ''; content: '';
position: absolute; position: absolute;
inset: -4px;
inset: -18px;
border-radius: 50%; border-radius: 50%;
border: 2px solid rgba(var(--csk-primary-rgb), 0.35);
opacity: 0;
animation: csk-ping 2.6s cubic-bezier(0, 0, 0.2, 1) infinite;
background: radial-gradient(circle, rgba(var(--csk-primary-rgb), 0.18) 0%, rgba(var(--csk-primary-rgb), 0.05) 45%, transparent 68%);
animation: csk-breathe 3.5s ease-in-out infinite;
pointer-events: none; pointer-events: none;
} }
.csk-launcher:hover { .csk-launcher:hover {
transform: translateY(-2px) scale(1.05);
box-shadow: 0 12px 32px rgba(var(--csk-primary-rgb), 0.5), 0 4px 10px rgba(15, 23, 42, 0.14);
transform: translateY(-3px) scale(1.08);
border-color: rgba(255, 255, 255, 0.75);
box-shadow:
0 2px 6px rgba(0, 0, 0, 0.10),
0 8px 24px rgba(0, 0, 0, 0.14),
0 10px 36px rgba(var(--csk-primary-rgb), 0.32),
0 0 56px rgba(var(--csk-primary-rgb), 0.14);
}
.csk-launcher:hover::before { animation-play-state: paused; }
.csk-launcher:hover::after {
animation: none;
inset: -22px;
background: radial-gradient(circle, rgba(var(--csk-primary-rgb), 0.22) 0%, rgba(var(--csk-primary-rgb), 0.06) 45%, transparent 68%);
}
.csk-launcher:active { transform: scale(0.93); }
.csk-launcher svg {
width: 30px;
height: 30px;
position: relative;
z-index: 1;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.15));
}
@keyframes csk-launcher-in {
0% { opacity: 0; transform: scale(0.5) translateY(16px); }
60% { transform: scale(1.06) translateY(-2px); }
100% { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes csk-shimmer {
0%, 100% { left: -60%; opacity: 0; }
20% { opacity: 1; }
60% { opacity: 1; }
80% { left: 120%; opacity: 0; }
}
@keyframes csk-breathe {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.15); opacity: 0.35; }
} }
.csk-launcher:active { transform: scale(0.94); }
.csk-launcher svg { width: 28px; height: 28px; }
@keyframes csk-ping {
0% { transform: scale(0.92); opacity: 0.7; }
70%, 100% { transform: scale(1.35); opacity: 0; }
/* SVG 图标内部动效:眨眼 */
.csk-launcher .csk-ico-eye {
animation: csk-eye-blink 4s ease-in-out infinite;
}
@keyframes csk-eye-blink {
0%, 42%, 48%, 100% { opacity: 1; }
45% { opacity: 0.1; }
}
/* SVG 图标内部动效:天线能量闪烁 */
.csk-launcher .csk-ico-antenna {
animation: csk-antenna-glow 2s ease-in-out infinite;
}
@keyframes csk-antenna-glow {
0%, 100% { opacity: 0.5; }
50% { opacity: 1; }
} }
/* ========== 聊天弹窗 ========== */ /* ========== 聊天弹窗 ========== */
@ -1035,8 +1112,8 @@ function getStyles(config: ResolvedConfig): string {
/* ========== Launcher 未读徽章 ========== */ /* ========== Launcher 未读徽章 ========== */
.csk-launcher__badge { .csk-launcher__badge {
position: absolute; position: absolute;
top: -3px;
right: -3px;
top: -2px;
right: -2px;
width: 16px; width: 16px;
height: 16px; height: 16px;
border-radius: 50%; border-radius: 50%;
@ -1163,7 +1240,16 @@ function getStyles(config: ResolvedConfig): string {
border-radius: inherit; border-radius: inherit;
} }
/* 弹窗打开时隐藏 launcher 上的焦点环 */ /* 弹窗打开时隐藏 launcher 上的焦点环 */
.csk-launcher:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(var(--csk-primary-rgb), 0.4); }
.csk-launcher:focus-visible {
outline: none;
border-color: rgba(255, 255, 255, 0.75);
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.06),
0 4px 16px rgba(0, 0, 0, 0.10),
0 6px 24px rgba(var(--csk-primary-rgb), 0.28),
0 0 48px rgba(var(--csk-primary-rgb), 0.12),
0 0 0 4px rgba(var(--csk-primary-rgb), 0.3);
}
/* ========== a11y aria-live 播报区(视觉隐藏) ========== */ /* ========== a11y aria-live 播报区(视觉隐藏) ========== */
.csk-sr-only { .csk-sr-only {

8
pom.xml

@ -251,6 +251,14 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
<configuration>
<!-- 使用 @ 作为过滤分隔符(与 Spring Boot 父 POM 一致) -->
<!-- 避免与 yml/properties 中的 ${...} Spring 占位符冲突 -->
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
<executions> <executions>
<execution> <execution>
<id>copy-sdk-to-static</id> <id>copy-sdk-to-static</id>

11
src/main/resources/application.properties

@ -0,0 +1,11 @@
# ================================================================
# Profile 激活配置
# ================================================================
# Maven 打包时通过资源过滤替换占位符(pom.xml 配置 @ 分隔符):
# mvn clean package → dev(默认)
# mvn clean package -P prod → prod
# IDE 直接运行时占位符未替换,需添加 JVM 参数:
# -Dspring.profiles.active=dev
# 或先执行 mvn process-resources 让 Maven 替换占位符
# ================================================================
spring.profiles.active=@profiles.active@

6
src/main/resources/application.yml

@ -8,12 +8,6 @@
# ================================================================ # ================================================================
spring: spring:
# ==================== Profile 激活(由 Maven 替换) ====================
# 打包时 Maven 会将 @profiles.active@ 替换为 dev/test/prod
# 本地 IDE 直接运行时可在此处手动指定,或通过 --spring.profiles.active=dev 传入
profiles:
active: @profiles.active@
# ==================== Spring AI Alibaba DashScope 配置 ==================== # ==================== Spring AI Alibaba DashScope 配置 ====================
# 模型名称、温度、API Key 等参数已迁移到前端「AI 大模型配置管理」页面管理 # 模型名称、温度、API Key 等参数已迁移到前端「AI 大模型配置管理」页面管理
ai: ai:

145
src/main/resources/static/sdk/chatbot-sdk.js

@ -82,10 +82,23 @@ var ChatbotSDK = (function () {
}, },
}; };
/** 默认悬浮按钮 SVG 图标(客服对话气泡) */
const DEFAULT_LAUNCHER_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
<path d="M8 9h8"/><path d="M8 13h6"/>
/** 默认悬浮按钮 SVG 图标(赛博机器人:对话气泡 + 机器人面孔 + 天线能量灯 + 眨眼动效) */
const DEFAULT_LAUNCHER_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 32 32" fill="none">
<defs>
<linearGradient id="csk-ico-grad" x1="6" y1="8" x2="26" y2="28" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#fff" stop-opacity="1"/>
<stop offset="100%" stop-color="#fff" stop-opacity="0.82"/>
</linearGradient>
</defs>
<rect x="5" y="8" width="22" height="16" rx="4" fill="url(#csk-ico-grad)"/>
<path d="M9 24L6 28.5l6-4.5z" fill="url(#csk-ico-grad)"/>
<line x1="16" y1="8" x2="16" y2="4" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="16" cy="3" r="1.5" fill="#fff" class="csk-ico-antenna"/>
<rect x="9.5" y="13" width="4" height="3.5" rx="1.2" fill="rgba(99,102,241,0.55)" class="csk-ico-eye"/>
<rect x="18.5" y="13" width="4" height="3.5" rx="1.2" fill="rgba(99,102,241,0.55)" class="csk-ico-eye"/>
<circle cx="11" cy="14.2" r="0.7" fill="#fff" opacity="0.9"/>
<circle cx="20" cy="14.2" r="0.7" fill="#fff" opacity="0.9"/>
<path d="M12.5 20 Q16 22.5 19.5 20" stroke="rgba(99,102,241,0.4)" stroke-width="1.2" fill="none" stroke-linecap="round"/>
</svg>`; </svg>`;
/** /**
* 解析并校验用户传入的配置填充默认值 * 解析并校验用户传入的配置填充默认值
@ -840,42 +853,119 @@ var ChatbotSDK = (function () {
position: fixed; position: fixed;
bottom: 24px; bottom: 24px;
z-index: 9998; z-index: 9998;
width: 58px;
height: 58px;
width: 60px;
height: 60px;
border-radius: 50%; border-radius: 50%;
background: var(--csk-bg-user); background: var(--csk-bg-user);
box-shadow: 0 8px 24px rgba(var(--csk-primary-rgb), 0.42), 0 2px 6px rgba(15, 23, 42, 0.12);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.22s ease;
border: none;
color: #fff; color: #fff;
user-select: none; user-select: none;
overflow: visible;
/* 半透明白色光环边框,在白色页面上清晰分离按钮与背景 */
border: 2.5px solid rgba(255, 255, 255, 0.55);
/* 三层投影:接地阴影 + 彩色光晕,把按钮从白底「托」出来 */
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.06),
0 4px 16px rgba(0, 0, 0, 0.10),
0 6px 24px rgba(var(--csk-primary-rgb), 0.28),
0 0 48px rgba(var(--csk-primary-rgb), 0.12);
transition:
transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.25s ease,
border-color 0.25s ease;
animation: csk-launcher-in 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
} }
.csk-launcher--right { right: 24px; } .csk-launcher--right { right: 24px; }
.csk-launcher--left { left: 24px; } .csk-launcher--left { left: 24px; }
/* 高光扫过动效 */
.csk-launcher::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 40%;
height: 200%;
border-radius: 50%;
background: linear-gradient(
105deg,
transparent 30%,
rgba(255, 255, 255, 0.28) 48%,
rgba(255, 255, 255, 0.1) 52%,
transparent 70%
);
transform: rotate(25deg);
animation: csk-shimmer 4s ease-in-out infinite;
pointer-events: none;
}
/* 呼吸色晕 — 配合接地阴影,强化白底上的立体存在感 */
.csk-launcher::after { .csk-launcher::after {
content: ''; content: '';
position: absolute; position: absolute;
inset: -4px;
inset: -18px;
border-radius: 50%; border-radius: 50%;
border: 2px solid rgba(var(--csk-primary-rgb), 0.35);
opacity: 0;
animation: csk-ping 2.6s cubic-bezier(0, 0, 0.2, 1) infinite;
background: radial-gradient(circle, rgba(var(--csk-primary-rgb), 0.18) 0%, rgba(var(--csk-primary-rgb), 0.05) 45%, transparent 68%);
animation: csk-breathe 3.5s ease-in-out infinite;
pointer-events: none; pointer-events: none;
} }
.csk-launcher:hover { .csk-launcher:hover {
transform: translateY(-2px) scale(1.05);
box-shadow: 0 12px 32px rgba(var(--csk-primary-rgb), 0.5), 0 4px 10px rgba(15, 23, 42, 0.14);
transform: translateY(-3px) scale(1.08);
border-color: rgba(255, 255, 255, 0.75);
box-shadow:
0 2px 6px rgba(0, 0, 0, 0.10),
0 8px 24px rgba(0, 0, 0, 0.14),
0 10px 36px rgba(var(--csk-primary-rgb), 0.32),
0 0 56px rgba(var(--csk-primary-rgb), 0.14);
}
.csk-launcher:hover::before { animation-play-state: paused; }
.csk-launcher:hover::after {
animation: none;
inset: -22px;
background: radial-gradient(circle, rgba(var(--csk-primary-rgb), 0.22) 0%, rgba(var(--csk-primary-rgb), 0.06) 45%, transparent 68%);
}
.csk-launcher:active { transform: scale(0.93); }
.csk-launcher svg {
width: 30px;
height: 30px;
position: relative;
z-index: 1;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.15));
}
@keyframes csk-launcher-in {
0% { opacity: 0; transform: scale(0.5) translateY(16px); }
60% { transform: scale(1.06) translateY(-2px); }
100% { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes csk-shimmer {
0%, 100% { left: -60%; opacity: 0; }
20% { opacity: 1; }
60% { opacity: 1; }
80% { left: 120%; opacity: 0; }
}
@keyframes csk-breathe {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.15); opacity: 0.35; }
} }
.csk-launcher:active { transform: scale(0.94); }
.csk-launcher svg { width: 28px; height: 28px; }
@keyframes csk-ping {
0% { transform: scale(0.92); opacity: 0.7; }
70%, 100% { transform: scale(1.35); opacity: 0; }
/* SVG 图标内部动效:眨眼 */
.csk-launcher .csk-ico-eye {
animation: csk-eye-blink 4s ease-in-out infinite;
}
@keyframes csk-eye-blink {
0%, 42%, 48%, 100% { opacity: 1; }
45% { opacity: 0.1; }
}
/* SVG 图标内部动效:天线能量闪烁 */
.csk-launcher .csk-ico-antenna {
animation: csk-antenna-glow 2s ease-in-out infinite;
}
@keyframes csk-antenna-glow {
0%, 100% { opacity: 0.5; }
50% { opacity: 1; }
} }
/* ========== 聊天弹窗 ========== */ /* ========== 聊天弹窗 ========== */
@ -1803,8 +1893,8 @@ var ChatbotSDK = (function () {
/* ========== Launcher 未读徽章 ========== */ /* ========== Launcher 未读徽章 ========== */
.csk-launcher__badge { .csk-launcher__badge {
position: absolute; position: absolute;
top: -3px;
right: -3px;
top: -2px;
right: -2px;
width: 16px; width: 16px;
height: 16px; height: 16px;
border-radius: 50%; border-radius: 50%;
@ -1931,7 +2021,16 @@ var ChatbotSDK = (function () {
border-radius: inherit; border-radius: inherit;
} }
/* 弹窗打开时隐藏 launcher 上的焦点环 */ /* 弹窗打开时隐藏 launcher 上的焦点环 */
.csk-launcher:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(var(--csk-primary-rgb), 0.4); }
.csk-launcher:focus-visible {
outline: none;
border-color: rgba(255, 255, 255, 0.75);
box-shadow:
0 1px 2px rgba(0, 0, 0, 0.06),
0 4px 16px rgba(0, 0, 0, 0.10),
0 6px 24px rgba(var(--csk-primary-rgb), 0.28),
0 0 48px rgba(var(--csk-primary-rgb), 0.12),
0 0 0 4px rgba(var(--csk-primary-rgb), 0.3);
}
/* ========== a11y aria-live 播报区(视觉隐藏) ========== */ /* ========== a11y aria-live 播报区(视觉隐藏) ========== */
.csk-sr-only { .csk-sr-only {

2
src/main/resources/static/sdk/chatbot-sdk.js.map
File diff suppressed because it is too large
View File

2
src/main/resources/static/sdk/chatbot-sdk.min.js
File diff suppressed because it is too large
View File

2
src/main/resources/static/sdk/chatbot-sdk.min.js.map
File diff suppressed because it is too large
View File

Loading…
Cancel
Save