Browse Source

优化界面排版

TDesign-Vue-Next-1.20.6
wanghanlin 3 weeks ago
parent
commit
fe49bebadb
  1. 185
      client/dist/chatbot-sdk.js
  2. 2
      client/dist/chatbot-sdk.min.js
  3. 30
      client/src/dom.ts
  4. 91
      client/src/logger.ts
  5. 41
      client/src/styles.ts
  6. 185
      src/main/resources/static/sdk/chatbot-sdk.js
  7. 2
      src/main/resources/static/sdk/chatbot-sdk.min.js

185
client/dist/chatbot-sdk.js

@ -1,36 +1,27 @@
var ChatbotSDK = (function () {
'use strict';
const PREFIX = '[ChatbotSDK]';
let debugEnabled = true;
/** 错误回调函数(由宿主通过 onError 配置注入) */
let errorCallback = null;
/** 设置是否开启调试日志 */
function setDebug(enabled) {
debugEnabled = enabled;
/** 设置是否开启调试日志(保留接口兼容,不再输出控制台日志) */
function setDebug(_enabled) {
// 控制台日志已禁用,此方法保留仅为 API 兼容
}
/** 设置错误回调(宿主 onError 配置) */
function setErrorCallback(cb) {
errorCallback = cb || null;
}
/** 性能计时器 */
const timers = {};
const logger = {
/** 普通信息日志(受 debug 开关控制) */
info(msg, data) {
if (debugEnabled) {
console.log(PREFIX, msg, data !== undefined ? data : '');
}
/** 普通信息日志(已禁用控制台输出) */
info(_msg, _data) {
// 控制台日志已禁用
},
/** 警告日志(受 debug 开关控制) */
warn(msg, data) {
if (debugEnabled) {
console.warn(PREFIX, msg, data !== undefined ? data : '');
}
/** 警告日志(已禁用控制台输出) */
warn(_msg, _data) {
// 控制台日志已禁用
},
/** 错误日志(始终输出,不受 debug 开关控制;同时触发 onError 回调) */
/** 错误日志(不输出控制台,仅触发 onError 回调) */
error(msg, data) {
console.error(PREFIX, msg, data !== undefined ? data : '');
// 触发宿主的 onError 回调
if (errorCallback) {
try {
@ -40,59 +31,45 @@ var ChatbotSDK = (function () {
catch ( /* 回调异常不影响 SDK */_a) { /* 回调异常不影响 SDK */ }
}
},
/** 开始计时 */
time(label) {
timers[label] = Date.now();
/** 开始计时(已禁用) */
time(_label) {
// 控制台日志已禁用
},
/** 结束计时并输出日志 */
timeEnd(label, prefix) {
const start = timers[label];
if (start !== undefined) {
const duration = Date.now() - start;
delete timers[label];
if (debugEnabled) {
const msg = prefix ? `${prefix} ${duration}ms` : `${label} ${duration}ms`;
console.log(PREFIX, msg);
}
return duration;
}
/** 结束计时(已禁用) */
timeEnd(_label, _prefix) {
return 0;
},
/** 生命周期日志:init */
lifecycleInit(integrateId, requestDomain) {
this.info(`初始化完成 integrateId=${integrateId} requestDomain=${requestDomain}`);
lifecycleInit(_integrateId, _requestDomain) {
// 控制台日志已禁用
},
/** 生命周期日志:destroy */
lifecycleDestroy(integrateId) {
this.info(`销毁实例 integrateId=${integrateId}`);
lifecycleDestroy(_integrateId) {
// 控制台日志已禁用
},
/** 生命周期日志:sendMessage */
lifecycleSend(integrateId, length) {
this.info(`发送消息 integrateId=${integrateId} length=${length}`);
this.time(`send_${integrateId}`);
lifecycleSend(_integrateId, _length) {
// 控制台日志已禁用
},
/** 生命周期日志:收到回复 */
lifecycleReply(integrateId, length) {
const duration = this.timeEnd(`send_${integrateId}`, 'AI 回复');
this.info(`AI 回复 integrateId=${integrateId} length=${length} duration=${duration}ms`);
lifecycleReply(_integrateId, _length) {
// 控制台日志已禁用
},
/** 生命周期日志:请求失败 */
lifecycleError(integrateId, status, message) {
this.timeEnd(`send_${integrateId}`);
this.error(`请求失败 integrateId=${integrateId} status=${status} message=${message}`);
lifecycleError(_integrateId, _status, _message) {
// 控制台日志已禁用
},
/** 生命周期日志:新对话 */
lifecycleClear(integrateId) {
this.info(`新对话 integrateId=${integrateId}`);
lifecycleClear(_integrateId) {
// 控制台日志已禁用
},
/** 生命周期日志:流式回复完成 */
lifecycleStreamDone(integrateId, length) {
const duration = this.timeEnd(`send_${integrateId}`, '流式回复');
this.info(`流式回复完成 integrateId=${integrateId} length=${length} duration=${duration}ms`);
lifecycleStreamDone(_integrateId, _length) {
// 控制台日志已禁用
},
/** 生命周期日志:知识库切换 */
lifecycleCategoryChange(categoryId) {
this.info(`切换知识库分类 categoryId=${categoryId}`);
lifecycleCategoryChange(_categoryId) {
// 控制台日志已禁用
},
};
@ -882,7 +859,6 @@ var ChatbotSDK = (function () {
const cachedChatId = loadCachedChatId(activeId, currentConfig.userId);
if (cachedChatId) {
currentConfig.chatId = cachedChatId;
logger.info(`从缓存恢复 chatId=${cachedChatId}`);
return cachedChatId;
}
}
@ -902,13 +878,11 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn('查询后端会话列表失败,将生成新 chatId', err);
}
// 3. 生成新的 chatId
const newChatId = generateChatId();
currentConfig.chatId = newChatId;
saveCachedChatId(activeId, currentConfig.userId, newChatId);
logger.info(`生成新 chatId=${newChatId}`);
return newChatId;
}
/** 生成 chatId(格式:sdk_timestamp_random) */
@ -963,7 +937,6 @@ var ChatbotSDK = (function () {
return json.success && json.data ? (json.data.configValue || '') : '';
}
catch (_a) {
logger.warn(`获取系统配置 ${key} 失败,降级为空`);
return '';
}
}
@ -1377,7 +1350,7 @@ var ChatbotSDK = (function () {
/* 消息气泡 */
.csk-msg {
display: flex;
margin-bottom: 18px;
margin-bottom: 12px;
max-width: 100%;
word-break: break-word;
animation: csk-msg-in 0.28s cubic-bezier(0.22, 1, 0.36, 1);
@ -1440,10 +1413,20 @@ var ChatbotSDK = (function () {
.csk-msg__time {
font-size: 11px;
color: #9CA3AF;
margin-top: 5px;
margin-top: 3px;
padding: 0 4px;
}
/* 元信息行:时间戳居左,操作按钮居右,共用一行 */
.csk-msg__meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 3px;
width: 100%;
}
.csk-msg__meta .csk-msg__time { margin-top: 0; }
@keyframes csk-msg-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
@ -1457,7 +1440,7 @@ var ChatbotSDK = (function () {
.csk-loading {
display: flex;
align-items: center;
margin-bottom: 18px;
margin-bottom: 12px;
animation: csk-msg-in 0.28s ease;
}
.csk-loading__avatar {
@ -1642,7 +1625,7 @@ var ChatbotSDK = (function () {
/* ========== P1: RAG 引用来源卡片 ========== */
.csk-sources {
margin-top: 8px;
margin-top: 6px;
border: 1px solid var(--csk-border);
border-radius: 12px;
overflow: hidden;
@ -1654,7 +1637,7 @@ var ChatbotSDK = (function () {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
padding: 6px 10px;
background: #F3F4F7;
cursor: pointer;
user-select: none;
@ -1680,7 +1663,7 @@ var ChatbotSDK = (function () {
}
.csk-sources--collapsed .csk-sources__body { display: none; }
.csk-source-item {
padding: 9px 12px;
padding: 6px 10px;
border-bottom: 1px solid #F0F1F4;
transition: background 0.15s;
}
@ -1689,7 +1672,7 @@ var ChatbotSDK = (function () {
.csk-source-item__name {
font-weight: 500;
color: #1F2937;
margin-bottom: 3px;
margin-bottom: 2px;
}
.csk-source-item__snippet {
color: #6B7280;
@ -1703,7 +1686,7 @@ var ChatbotSDK = (function () {
.csk-source-item__meta {
font-size: 11px;
color: #9CA3AF;
margin-top: 4px;
margin-top: 2px;
}
/* ========== P1: Markdown 渲染样式 ========== */
@ -1982,26 +1965,20 @@ var ChatbotSDK = (function () {
/* ========== 推荐问题(suggest-message-list) ========== */
.csk-suggestions {
margin-top: 10px;
padding: 8px 0 0 0;
border-top: 1px solid var(--csk-border);
}
.csk-suggestions__label {
font-size: 12px;
color: #9CA3AF;
margin-bottom: 6px;
margin-top: 6px;
padding: 4px 0 0 0;
}
.csk-suggestions__list {
display: flex;
flex-wrap: wrap;
gap: 6px;
gap: 4px;
}
.csk-suggestion-item {
border: 1px solid var(--csk-border);
background: #fff;
color: #374151;
font-size: 12px;
padding: 6px 12px;
padding: 4px 10px;
border-radius: 999px;
cursor: pointer;
font-family: inherit;
@ -2022,7 +1999,6 @@ var ChatbotSDK = (function () {
.csk-msg__actions {
display: flex;
gap: 2px;
margin-top: 5px;
padding: 0 2px;
opacity: 0;
transition: opacity 0.15s ease;
@ -3302,9 +3278,12 @@ var ChatbotSDK = (function () {
time.className = 'csk-msg__time';
time.textContent = formatTime(timestamp);
content.appendChild(bubble);
// AI 操作条(复制 / 重试),插入到气泡与时间戳之间
content.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(time);
// 元信息行:时间戳居左,操作按钮居右
const meta = document.createElement('div');
meta.className = 'csk-msg__meta';
meta.appendChild(time);
meta.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(meta);
wrapper.appendChild(avatar);
wrapper.appendChild(content);
container.appendChild(wrapper);
@ -3330,8 +3309,12 @@ var ChatbotSDK = (function () {
time.className = 'csk-msg__time';
time.textContent = formatTime(timestamp);
content.appendChild(bubble);
content.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(time);
// 元信息行:时间戳居左,操作按钮居右
const meta = document.createElement('div');
meta.className = 'csk-msg__meta';
meta.appendChild(time);
meta.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(meta);
wrapper.appendChild(avatar);
wrapper.appendChild(content);
container.appendChild(wrapper);
@ -3551,10 +3534,10 @@ var ChatbotSDK = (function () {
}
sourcesEl.appendChild(header);
sourcesEl.appendChild(body);
// 插入到气泡和时间戳之间(时间戳在 content 容器内,故用其父节点插入
const timeEl = wrapper.querySelector('.csk-msg__time');
if (timeEl && timeEl.parentNode) {
timeEl.parentNode.insertBefore(sourcesEl, timeEl);
// 插入到元信息行之后(来源卡片紧接在 meta 行下方
const metaEl = wrapper.querySelector('.csk-msg__meta');
if (metaEl && metaEl.parentNode) {
metaEl.parentNode.insertBefore(sourcesEl, metaEl.nextSibling);
}
else {
wrapper.appendChild(sourcesEl);
@ -3727,9 +3710,6 @@ var ChatbotSDK = (function () {
return;
const section = document.createElement('div');
section.className = 'csk-suggestions';
const label = document.createElement('div');
label.className = 'csk-suggestions__label';
label.textContent = '💡 推荐问题';
const list = document.createElement('div');
list.className = 'csk-suggestions__list';
for (const text of suggestions) {
@ -3743,7 +3723,6 @@ var ChatbotSDK = (function () {
});
list.appendChild(chip);
}
section.appendChild(label);
section.appendChild(list);
// 插入到操作栏和来源卡片之间(在 content 内末尾)
const content = wrapper.querySelector('.csk-msg__content');
@ -3813,7 +3792,6 @@ var ChatbotSDK = (function () {
return data.messages;
}
catch (e) {
logger.warn('加载会话历史失败', e);
return [];
}
}
@ -3825,7 +3803,6 @@ var ChatbotSDK = (function () {
localStorage.removeItem(storageKey(integrateId));
}
catch (e) {
logger.warn('清空会话历史失败', e);
}
}
@ -4199,7 +4176,6 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn('从后端加载历史消息失败', err);
}
}
/** 绑定发送相关事件 */
@ -4376,17 +4352,8 @@ var ChatbotSDK = (function () {
if (newValue) {
const feedbackType = newValue === 'up' ? 'THUMBS_UP' : 'THUMBS_DOWN';
submitFeedbackApi(String(msgId), feedbackType).then(success => {
if (success) {
logger.info(`消息反馈已提交 msgId=${msgId} value=${newValue}`);
}
else {
logger.warn(`消息反馈提交失败 msgId=${msgId}(本地状态已更新)`);
}
});
}
else {
logger.info(`消息反馈已取消 msgId=${msgId}`);
}
}
function autoResizeInput() {
if (!inputEl$1)
@ -4651,7 +4618,6 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn('获取引用来源失败', err);
}
}
/** 加载知识库分类到下拉框 */
@ -4728,7 +4694,6 @@ var ChatbotSDK = (function () {
updateChatId(newId);
saveCachedChatId(config$1.integrateId, config$1.userId, newId);
logger.lifecycleClear(config$1.integrateId);
logger.info(`新 chatId=${newId}`);
}
/** 生成新 chatId */
function generateNewChatId() {
@ -4742,7 +4707,6 @@ var ChatbotSDK = (function () {
var _a;
currentCategoryId = categoryId;
useRag = (_a = config$1 === null || config$1 === void 0 ? void 0 : config$1.enableRag) !== null && _a !== void 0 ? _a : true;
logger.lifecycleCategoryChange(categoryId !== null && categoryId !== void 0 ? categoryId : '全部');
}
// ==================== 角色切换 ====================
/**
@ -4786,14 +4750,12 @@ var ChatbotSDK = (function () {
}
// 8. 强制查询后端会话列表(跳过 localStorage 缓存)
const foundChatId = await initChatId(true);
logger.info(`角色切换 initChatId 完成 chatId=${foundChatId} roleId=${newRoleId}`);
// 9. 从后端加载新角色的对话历史
if (foundChatId) {
try {
await loadHistoryFromBackend();
}
catch (err) {
logger.warn(`切换角色后加载后端历史失败 roleId=${newRoleId}`, err);
}
}
// 10. 隐藏新对话按钮 + 更新欢迎态
@ -4804,7 +4766,6 @@ var ChatbotSDK = (function () {
isNearBottom = true;
if (messagesContainer$1)
scrollToBottom(messagesContainer$1);
logger.info(`角色切换完成 ${oldRoleId} -> ${newRoleId}`);
}
// ==================== 会话管理面板 ====================
/** 加载会话列表并渲染 */
@ -4871,7 +4832,6 @@ var ChatbotSDK = (function () {
const convRoleId = String(historyItem.roleId);
const currentRoleId = getActiveIntegrateId();
if (convRoleId && convRoleId !== currentRoleId) {
logger.info(`会话角色不匹配,自动切换角色 ${currentRoleId} -> ${convRoleId}`);
setActiveRoleId(convRoleId);
// 更新角色下拉框高亮项
if (roleSelect) {
@ -4879,7 +4839,6 @@ var ChatbotSDK = (function () {
}
}
}
logger.info(`切换到会话 conversationId=${conversationId}`);
// 1. 更新 chatId
updateChatId(conversationId);
saveCachedChatId(getActiveIntegrateId(), config$1.userId, conversationId);
@ -4908,7 +4867,6 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn(`加载会话消息失败 conversationId=${conversationId}`, err);
}
// 5. 显示新对话按钮
if (clearBtn$1 && messages.length > 0) {
@ -4970,7 +4928,6 @@ var ChatbotSDK = (function () {
/** 初始化 SDK */
function init(rawConfig) {
if (isInitialized) {
logger.warn('SDK 已初始化,请先调用 destroy() 再重新初始化');
return;
}
// 1. 配置解析与校验
@ -5126,7 +5083,6 @@ var ChatbotSDK = (function () {
}
// 19. 异步初始化 chatId 和对话历史(不阻塞 UI)
initChatHistory().catch(err => {
logger.warn('chatId 初始化失败,将在发送消息时重试', err);
});
// 20. 异步拉取保密声明(config.disclaimer undefined = 从后端拉取,有值/空串已在 dom.ts 处理)
if (config.disclaimer === undefined) {
@ -5293,7 +5249,7 @@ var ChatbotSDK = (function () {
document.removeEventListener('keydown', onKeyDown);
window.removeEventListener('resize', onResize);
setErrorCallback(undefined);
const oldIntegrateId = config === null || config === void 0 ? void 0 : config.integrateId;
config === null || config === void 0 ? void 0 : config.integrateId;
config = null;
isInitialized = false;
messagesContainer = null;
@ -5308,7 +5264,6 @@ var ChatbotSDK = (function () {
audioCtx = null;
disclaimerEl = null;
clearApiConfig();
logger.lifecycleDestroy(oldIntegrateId || '');
}
function open() {
if (!windowEl)

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

30
client/src/dom.ts

@ -867,9 +867,12 @@ export function renderAIBubble(container: HTMLElement, text: string, timestamp:
time.textContent = formatTime(timestamp);
content.appendChild(bubble);
// AI 操作条(复制 / 重试),插入到气泡与时间戳之间
content.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(time);
// 元信息行:时间戳居左,操作按钮居右
const meta = document.createElement('div');
meta.className = 'csk-msg__meta';
meta.appendChild(time);
meta.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(meta);
wrapper.appendChild(avatar);
wrapper.appendChild(content);
container.appendChild(wrapper);
@ -902,8 +905,12 @@ export function createEmptyAIBubble(container: HTMLElement, timestamp: number, m
time.textContent = formatTime(timestamp);
content.appendChild(bubble);
content.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(time);
// 元信息行:时间戳居左,操作按钮居右
const meta = document.createElement('div');
meta.className = 'csk-msg__meta';
meta.appendChild(time);
meta.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(meta);
wrapper.appendChild(avatar);
wrapper.appendChild(content);
container.appendChild(wrapper);
@ -1142,10 +1149,10 @@ export function renderSources(wrapper: HTMLElement, sources: RagSource[]): void
sourcesEl.appendChild(header);
sourcesEl.appendChild(body);
// 插入到气泡和时间戳之间(时间戳在 content 容器内,故用其父节点插入
const timeEl = wrapper.querySelector('.csk-msg__time');
if (timeEl && timeEl.parentNode) {
timeEl.parentNode.insertBefore(sourcesEl, timeEl);
// 插入到元信息行之后(来源卡片紧接在 meta 行下方
const metaEl = wrapper.querySelector('.csk-msg__meta');
if (metaEl && metaEl.parentNode) {
metaEl.parentNode.insertBefore(sourcesEl, metaEl.nextSibling);
} else {
wrapper.appendChild(sourcesEl);
}
@ -1364,10 +1371,6 @@ export function renderSuggestions(
const section = document.createElement('div');
section.className = 'csk-suggestions';
const label = document.createElement('div');
label.className = 'csk-suggestions__label';
label.textContent = '💡 推荐问题';
const list = document.createElement('div');
list.className = 'csk-suggestions__list';
@ -1383,7 +1386,6 @@ export function renderSuggestions(
list.appendChild(chip);
}
section.appendChild(label);
section.appendChild(list);
// 插入到操作栏和来源卡片之间(在 content 内末尾)
const content = wrapper.querySelector('.csk-msg__content');

91
client/src/logger.ts

@ -1,19 +1,14 @@
/**
* - [ChatbotSDK]
*
* -
*/
import { ResolvedConfig } from './types';
const PREFIX = '[ChatbotSDK]';
let debugEnabled = true;
/** 错误回调函数(由宿主通过 onError 配置注入) */
let errorCallback: ((error: { message: string; code: string; detail?: unknown }) => void) | null = null;
/** 设置是否开启调试日志 */
export function setDebug(enabled: boolean): void {
debugEnabled = enabled;
/** 设置是否开启调试日志(保留接口兼容,不再输出控制台日志) */
export function setDebug(_enabled: boolean): void {
// 控制台日志已禁用,此方法保留仅为 API 兼容
}
/** 设置错误回调(宿主 onError 配置) */
@ -21,27 +16,19 @@ export function setErrorCallback(cb: ((error: { message: string; code: string; d
errorCallback = cb || null;
}
/** 性能计时器 */
const timers: Record<string, number> = {};
export const logger = {
/** 普通信息日志(受 debug 开关控制) */
info(msg: string, data?: unknown): void {
if (debugEnabled) {
console.log(PREFIX, msg, data !== undefined ? data : '');
}
/** 普通信息日志(已禁用控制台输出) */
info(_msg: string, _data?: unknown): void {
// 控制台日志已禁用
},
/** 警告日志(受 debug 开关控制) */
warn(msg: string, data?: unknown): void {
if (debugEnabled) {
console.warn(PREFIX, msg, data !== undefined ? data : '');
}
/** 警告日志(已禁用控制台输出) */
warn(_msg: string, _data?: unknown): void {
// 控制台日志已禁用
},
/** 错误日志(始终输出,不受 debug 开关控制;同时触发 onError 回调) */
/** 错误日志(不输出控制台,仅触发 onError 回调) */
error(msg: string, data?: unknown): void {
console.error(PREFIX, msg, data !== undefined ? data : '');
// 触发宿主的 onError 回调
if (errorCallback) {
try {
@ -51,67 +38,53 @@ export const logger = {
}
},
/** 开始计时 */
time(label: string): void {
timers[label] = Date.now();
/** 开始计时(已禁用) */
time(_label: string): void {
// 控制台日志已禁用
},
/** 结束计时并输出日志 */
timeEnd(label: string, prefix?: string): number {
const start = timers[label];
if (start !== undefined) {
const duration = Date.now() - start;
delete timers[label];
if (debugEnabled) {
const msg = prefix ? `${prefix} ${duration}ms` : `${label} ${duration}ms`;
console.log(PREFIX, msg);
}
return duration;
}
/** 结束计时(已禁用) */
timeEnd(_label: string, _prefix?: string): number {
return 0;
},
/** 生命周期日志:init */
lifecycleInit(integrateId: string, requestDomain: string): void {
this.info(`初始化完成 integrateId=${integrateId} requestDomain=${requestDomain}`);
lifecycleInit(_integrateId: string, _requestDomain: string): void {
// 控制台日志已禁用
},
/** 生命周期日志:destroy */
lifecycleDestroy(integrateId: string): void {
this.info(`销毁实例 integrateId=${integrateId}`);
lifecycleDestroy(_integrateId: string): void {
// 控制台日志已禁用
},
/** 生命周期日志:sendMessage */
lifecycleSend(integrateId: string, length: number): void {
this.info(`发送消息 integrateId=${integrateId} length=${length}`);
this.time(`send_${integrateId}`);
lifecycleSend(_integrateId: string, _length: number): void {
// 控制台日志已禁用
},
/** 生命周期日志:收到回复 */
lifecycleReply(integrateId: string, length: number): void {
const duration = this.timeEnd(`send_${integrateId}`, 'AI 回复');
this.info(`AI 回复 integrateId=${integrateId} length=${length} duration=${duration}ms`);
lifecycleReply(_integrateId: string, _length: number): void {
// 控制台日志已禁用
},
/** 生命周期日志:请求失败 */
lifecycleError(integrateId: string, status: string, message: string): void {
this.timeEnd(`send_${integrateId}`);
this.error(`请求失败 integrateId=${integrateId} status=${status} message=${message}`);
lifecycleError(_integrateId: string, _status: string, _message: string): void {
// 控制台日志已禁用
},
/** 生命周期日志:新对话 */
lifecycleClear(integrateId: string): void {
this.info(`新对话 integrateId=${integrateId}`);
lifecycleClear(_integrateId: string): void {
// 控制台日志已禁用
},
/** 生命周期日志:流式回复完成 */
lifecycleStreamDone(integrateId: string, length: number): void {
const duration = this.timeEnd(`send_${integrateId}`, '流式回复');
this.info(`流式回复完成 integrateId=${integrateId} length=${length} duration=${duration}ms`);
lifecycleStreamDone(_integrateId: string, _length: number): void {
// 控制台日志已禁用
},
/** 生命周期日志:知识库切换 */
lifecycleCategoryChange(categoryId: string | number): void {
this.info(`切换知识库分类 categoryId=${categoryId}`);
lifecycleCategoryChange(_categoryId: string | number): void {
// 控制台日志已禁用
},
};

41
client/src/styles.ts

@ -392,7 +392,7 @@ function getStyles(config: ResolvedConfig): string {
/* 消息气泡 */
.csk-msg {
display: flex;
margin-bottom: 18px;
margin-bottom: 12px;
max-width: 100%;
word-break: break-word;
animation: csk-msg-in 0.28s cubic-bezier(0.22, 1, 0.36, 1);
@ -455,10 +455,20 @@ function getStyles(config: ResolvedConfig): string {
.csk-msg__time {
font-size: 11px;
color: #9CA3AF;
margin-top: 5px;
margin-top: 3px;
padding: 0 4px;
}
/* 元信息行:时间戳居左,操作按钮居右,共用一行 */
.csk-msg__meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 3px;
width: 100%;
}
.csk-msg__meta .csk-msg__time { margin-top: 0; }
@keyframes csk-msg-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
@ -472,7 +482,7 @@ function getStyles(config: ResolvedConfig): string {
.csk-loading {
display: flex;
align-items: center;
margin-bottom: 18px;
margin-bottom: 12px;
animation: csk-msg-in 0.28s ease;
}
.csk-loading__avatar {
@ -657,7 +667,7 @@ function getStyles(config: ResolvedConfig): string {
/* ========== P1: RAG 引用来源卡片 ========== */
.csk-sources {
margin-top: 8px;
margin-top: 6px;
border: 1px solid var(--csk-border);
border-radius: 12px;
overflow: hidden;
@ -669,7 +679,7 @@ function getStyles(config: ResolvedConfig): string {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
padding: 6px 10px;
background: #F3F4F7;
cursor: pointer;
user-select: none;
@ -695,7 +705,7 @@ function getStyles(config: ResolvedConfig): string {
}
.csk-sources--collapsed .csk-sources__body { display: none; }
.csk-source-item {
padding: 9px 12px;
padding: 6px 10px;
border-bottom: 1px solid #F0F1F4;
transition: background 0.15s;
}
@ -704,7 +714,7 @@ function getStyles(config: ResolvedConfig): string {
.csk-source-item__name {
font-weight: 500;
color: #1F2937;
margin-bottom: 3px;
margin-bottom: 2px;
}
.csk-source-item__snippet {
color: #6B7280;
@ -718,7 +728,7 @@ function getStyles(config: ResolvedConfig): string {
.csk-source-item__meta {
font-size: 11px;
color: #9CA3AF;
margin-top: 4px;
margin-top: 2px;
}
/* ========== P1: Markdown 渲染样式 ========== */
@ -997,26 +1007,20 @@ function getStyles(config: ResolvedConfig): string {
/* ========== 推荐问题(suggest-message-list) ========== */
.csk-suggestions {
margin-top: 10px;
padding: 8px 0 0 0;
border-top: 1px solid var(--csk-border);
}
.csk-suggestions__label {
font-size: 12px;
color: #9CA3AF;
margin-bottom: 6px;
margin-top: 6px;
padding: 4px 0 0 0;
}
.csk-suggestions__list {
display: flex;
flex-wrap: wrap;
gap: 6px;
gap: 4px;
}
.csk-suggestion-item {
border: 1px solid var(--csk-border);
background: #fff;
color: #374151;
font-size: 12px;
padding: 6px 12px;
padding: 4px 10px;
border-radius: 999px;
cursor: pointer;
font-family: inherit;
@ -1037,7 +1041,6 @@ function getStyles(config: ResolvedConfig): string {
.csk-msg__actions {
display: flex;
gap: 2px;
margin-top: 5px;
padding: 0 2px;
opacity: 0;
transition: opacity 0.15s ease;

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

@ -1,36 +1,27 @@
var ChatbotSDK = (function () {
'use strict';
const PREFIX = '[ChatbotSDK]';
let debugEnabled = true;
/** 错误回调函数(由宿主通过 onError 配置注入) */
let errorCallback = null;
/** 设置是否开启调试日志 */
function setDebug(enabled) {
debugEnabled = enabled;
/** 设置是否开启调试日志(保留接口兼容,不再输出控制台日志) */
function setDebug(_enabled) {
// 控制台日志已禁用,此方法保留仅为 API 兼容
}
/** 设置错误回调(宿主 onError 配置) */
function setErrorCallback(cb) {
errorCallback = cb || null;
}
/** 性能计时器 */
const timers = {};
const logger = {
/** 普通信息日志(受 debug 开关控制) */
info(msg, data) {
if (debugEnabled) {
console.log(PREFIX, msg, data !== undefined ? data : '');
}
/** 普通信息日志(已禁用控制台输出) */
info(_msg, _data) {
// 控制台日志已禁用
},
/** 警告日志(受 debug 开关控制) */
warn(msg, data) {
if (debugEnabled) {
console.warn(PREFIX, msg, data !== undefined ? data : '');
}
/** 警告日志(已禁用控制台输出) */
warn(_msg, _data) {
// 控制台日志已禁用
},
/** 错误日志(始终输出,不受 debug 开关控制;同时触发 onError 回调) */
/** 错误日志(不输出控制台,仅触发 onError 回调) */
error(msg, data) {
console.error(PREFIX, msg, data !== undefined ? data : '');
// 触发宿主的 onError 回调
if (errorCallback) {
try {
@ -40,59 +31,45 @@ var ChatbotSDK = (function () {
catch ( /* 回调异常不影响 SDK */_a) { /* 回调异常不影响 SDK */ }
}
},
/** 开始计时 */
time(label) {
timers[label] = Date.now();
/** 开始计时(已禁用) */
time(_label) {
// 控制台日志已禁用
},
/** 结束计时并输出日志 */
timeEnd(label, prefix) {
const start = timers[label];
if (start !== undefined) {
const duration = Date.now() - start;
delete timers[label];
if (debugEnabled) {
const msg = prefix ? `${prefix} ${duration}ms` : `${label} ${duration}ms`;
console.log(PREFIX, msg);
}
return duration;
}
/** 结束计时(已禁用) */
timeEnd(_label, _prefix) {
return 0;
},
/** 生命周期日志:init */
lifecycleInit(integrateId, requestDomain) {
this.info(`初始化完成 integrateId=${integrateId} requestDomain=${requestDomain}`);
lifecycleInit(_integrateId, _requestDomain) {
// 控制台日志已禁用
},
/** 生命周期日志:destroy */
lifecycleDestroy(integrateId) {
this.info(`销毁实例 integrateId=${integrateId}`);
lifecycleDestroy(_integrateId) {
// 控制台日志已禁用
},
/** 生命周期日志:sendMessage */
lifecycleSend(integrateId, length) {
this.info(`发送消息 integrateId=${integrateId} length=${length}`);
this.time(`send_${integrateId}`);
lifecycleSend(_integrateId, _length) {
// 控制台日志已禁用
},
/** 生命周期日志:收到回复 */
lifecycleReply(integrateId, length) {
const duration = this.timeEnd(`send_${integrateId}`, 'AI 回复');
this.info(`AI 回复 integrateId=${integrateId} length=${length} duration=${duration}ms`);
lifecycleReply(_integrateId, _length) {
// 控制台日志已禁用
},
/** 生命周期日志:请求失败 */
lifecycleError(integrateId, status, message) {
this.timeEnd(`send_${integrateId}`);
this.error(`请求失败 integrateId=${integrateId} status=${status} message=${message}`);
lifecycleError(_integrateId, _status, _message) {
// 控制台日志已禁用
},
/** 生命周期日志:新对话 */
lifecycleClear(integrateId) {
this.info(`新对话 integrateId=${integrateId}`);
lifecycleClear(_integrateId) {
// 控制台日志已禁用
},
/** 生命周期日志:流式回复完成 */
lifecycleStreamDone(integrateId, length) {
const duration = this.timeEnd(`send_${integrateId}`, '流式回复');
this.info(`流式回复完成 integrateId=${integrateId} length=${length} duration=${duration}ms`);
lifecycleStreamDone(_integrateId, _length) {
// 控制台日志已禁用
},
/** 生命周期日志:知识库切换 */
lifecycleCategoryChange(categoryId) {
this.info(`切换知识库分类 categoryId=${categoryId}`);
lifecycleCategoryChange(_categoryId) {
// 控制台日志已禁用
},
};
@ -882,7 +859,6 @@ var ChatbotSDK = (function () {
const cachedChatId = loadCachedChatId(activeId, currentConfig.userId);
if (cachedChatId) {
currentConfig.chatId = cachedChatId;
logger.info(`从缓存恢复 chatId=${cachedChatId}`);
return cachedChatId;
}
}
@ -902,13 +878,11 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn('查询后端会话列表失败,将生成新 chatId', err);
}
// 3. 生成新的 chatId
const newChatId = generateChatId();
currentConfig.chatId = newChatId;
saveCachedChatId(activeId, currentConfig.userId, newChatId);
logger.info(`生成新 chatId=${newChatId}`);
return newChatId;
}
/** 生成 chatId(格式:sdk_timestamp_random) */
@ -963,7 +937,6 @@ var ChatbotSDK = (function () {
return json.success && json.data ? (json.data.configValue || '') : '';
}
catch (_a) {
logger.warn(`获取系统配置 ${key} 失败,降级为空`);
return '';
}
}
@ -1377,7 +1350,7 @@ var ChatbotSDK = (function () {
/* 消息气泡 */
.csk-msg {
display: flex;
margin-bottom: 18px;
margin-bottom: 12px;
max-width: 100%;
word-break: break-word;
animation: csk-msg-in 0.28s cubic-bezier(0.22, 1, 0.36, 1);
@ -1440,10 +1413,20 @@ var ChatbotSDK = (function () {
.csk-msg__time {
font-size: 11px;
color: #9CA3AF;
margin-top: 5px;
margin-top: 3px;
padding: 0 4px;
}
/* 元信息行:时间戳居左,操作按钮居右,共用一行 */
.csk-msg__meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 3px;
width: 100%;
}
.csk-msg__meta .csk-msg__time { margin-top: 0; }
@keyframes csk-msg-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
@ -1457,7 +1440,7 @@ var ChatbotSDK = (function () {
.csk-loading {
display: flex;
align-items: center;
margin-bottom: 18px;
margin-bottom: 12px;
animation: csk-msg-in 0.28s ease;
}
.csk-loading__avatar {
@ -1642,7 +1625,7 @@ var ChatbotSDK = (function () {
/* ========== P1: RAG 引用来源卡片 ========== */
.csk-sources {
margin-top: 8px;
margin-top: 6px;
border: 1px solid var(--csk-border);
border-radius: 12px;
overflow: hidden;
@ -1654,7 +1637,7 @@ var ChatbotSDK = (function () {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
padding: 6px 10px;
background: #F3F4F7;
cursor: pointer;
user-select: none;
@ -1680,7 +1663,7 @@ var ChatbotSDK = (function () {
}
.csk-sources--collapsed .csk-sources__body { display: none; }
.csk-source-item {
padding: 9px 12px;
padding: 6px 10px;
border-bottom: 1px solid #F0F1F4;
transition: background 0.15s;
}
@ -1689,7 +1672,7 @@ var ChatbotSDK = (function () {
.csk-source-item__name {
font-weight: 500;
color: #1F2937;
margin-bottom: 3px;
margin-bottom: 2px;
}
.csk-source-item__snippet {
color: #6B7280;
@ -1703,7 +1686,7 @@ var ChatbotSDK = (function () {
.csk-source-item__meta {
font-size: 11px;
color: #9CA3AF;
margin-top: 4px;
margin-top: 2px;
}
/* ========== P1: Markdown 渲染样式 ========== */
@ -1982,26 +1965,20 @@ var ChatbotSDK = (function () {
/* ========== 推荐问题(suggest-message-list) ========== */
.csk-suggestions {
margin-top: 10px;
padding: 8px 0 0 0;
border-top: 1px solid var(--csk-border);
}
.csk-suggestions__label {
font-size: 12px;
color: #9CA3AF;
margin-bottom: 6px;
margin-top: 6px;
padding: 4px 0 0 0;
}
.csk-suggestions__list {
display: flex;
flex-wrap: wrap;
gap: 6px;
gap: 4px;
}
.csk-suggestion-item {
border: 1px solid var(--csk-border);
background: #fff;
color: #374151;
font-size: 12px;
padding: 6px 12px;
padding: 4px 10px;
border-radius: 999px;
cursor: pointer;
font-family: inherit;
@ -2022,7 +1999,6 @@ var ChatbotSDK = (function () {
.csk-msg__actions {
display: flex;
gap: 2px;
margin-top: 5px;
padding: 0 2px;
opacity: 0;
transition: opacity 0.15s ease;
@ -3302,9 +3278,12 @@ var ChatbotSDK = (function () {
time.className = 'csk-msg__time';
time.textContent = formatTime(timestamp);
content.appendChild(bubble);
// AI 操作条(复制 / 重试),插入到气泡与时间戳之间
content.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(time);
// 元信息行:时间戳居左,操作按钮居右
const meta = document.createElement('div');
meta.className = 'csk-msg__meta';
meta.appendChild(time);
meta.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(meta);
wrapper.appendChild(avatar);
wrapper.appendChild(content);
container.appendChild(wrapper);
@ -3330,8 +3309,12 @@ var ChatbotSDK = (function () {
time.className = 'csk-msg__time';
time.textContent = formatTime(timestamp);
content.appendChild(bubble);
content.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(time);
// 元信息行:时间戳居左,操作按钮居右
const meta = document.createElement('div');
meta.className = 'csk-msg__meta';
meta.appendChild(time);
meta.appendChild(buildAIActions(bubble, wrapper));
content.appendChild(meta);
wrapper.appendChild(avatar);
wrapper.appendChild(content);
container.appendChild(wrapper);
@ -3551,10 +3534,10 @@ var ChatbotSDK = (function () {
}
sourcesEl.appendChild(header);
sourcesEl.appendChild(body);
// 插入到气泡和时间戳之间(时间戳在 content 容器内,故用其父节点插入
const timeEl = wrapper.querySelector('.csk-msg__time');
if (timeEl && timeEl.parentNode) {
timeEl.parentNode.insertBefore(sourcesEl, timeEl);
// 插入到元信息行之后(来源卡片紧接在 meta 行下方
const metaEl = wrapper.querySelector('.csk-msg__meta');
if (metaEl && metaEl.parentNode) {
metaEl.parentNode.insertBefore(sourcesEl, metaEl.nextSibling);
}
else {
wrapper.appendChild(sourcesEl);
@ -3727,9 +3710,6 @@ var ChatbotSDK = (function () {
return;
const section = document.createElement('div');
section.className = 'csk-suggestions';
const label = document.createElement('div');
label.className = 'csk-suggestions__label';
label.textContent = '💡 推荐问题';
const list = document.createElement('div');
list.className = 'csk-suggestions__list';
for (const text of suggestions) {
@ -3743,7 +3723,6 @@ var ChatbotSDK = (function () {
});
list.appendChild(chip);
}
section.appendChild(label);
section.appendChild(list);
// 插入到操作栏和来源卡片之间(在 content 内末尾)
const content = wrapper.querySelector('.csk-msg__content');
@ -3813,7 +3792,6 @@ var ChatbotSDK = (function () {
return data.messages;
}
catch (e) {
logger.warn('加载会话历史失败', e);
return [];
}
}
@ -3825,7 +3803,6 @@ var ChatbotSDK = (function () {
localStorage.removeItem(storageKey(integrateId));
}
catch (e) {
logger.warn('清空会话历史失败', e);
}
}
@ -4199,7 +4176,6 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn('从后端加载历史消息失败', err);
}
}
/** 绑定发送相关事件 */
@ -4376,17 +4352,8 @@ var ChatbotSDK = (function () {
if (newValue) {
const feedbackType = newValue === 'up' ? 'THUMBS_UP' : 'THUMBS_DOWN';
submitFeedbackApi(String(msgId), feedbackType).then(success => {
if (success) {
logger.info(`消息反馈已提交 msgId=${msgId} value=${newValue}`);
}
else {
logger.warn(`消息反馈提交失败 msgId=${msgId}(本地状态已更新)`);
}
});
}
else {
logger.info(`消息反馈已取消 msgId=${msgId}`);
}
}
function autoResizeInput() {
if (!inputEl$1)
@ -4651,7 +4618,6 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn('获取引用来源失败', err);
}
}
/** 加载知识库分类到下拉框 */
@ -4728,7 +4694,6 @@ var ChatbotSDK = (function () {
updateChatId(newId);
saveCachedChatId(config$1.integrateId, config$1.userId, newId);
logger.lifecycleClear(config$1.integrateId);
logger.info(`新 chatId=${newId}`);
}
/** 生成新 chatId */
function generateNewChatId() {
@ -4742,7 +4707,6 @@ var ChatbotSDK = (function () {
var _a;
currentCategoryId = categoryId;
useRag = (_a = config$1 === null || config$1 === void 0 ? void 0 : config$1.enableRag) !== null && _a !== void 0 ? _a : true;
logger.lifecycleCategoryChange(categoryId !== null && categoryId !== void 0 ? categoryId : '全部');
}
// ==================== 角色切换 ====================
/**
@ -4786,14 +4750,12 @@ var ChatbotSDK = (function () {
}
// 8. 强制查询后端会话列表(跳过 localStorage 缓存)
const foundChatId = await initChatId(true);
logger.info(`角色切换 initChatId 完成 chatId=${foundChatId} roleId=${newRoleId}`);
// 9. 从后端加载新角色的对话历史
if (foundChatId) {
try {
await loadHistoryFromBackend();
}
catch (err) {
logger.warn(`切换角色后加载后端历史失败 roleId=${newRoleId}`, err);
}
}
// 10. 隐藏新对话按钮 + 更新欢迎态
@ -4804,7 +4766,6 @@ var ChatbotSDK = (function () {
isNearBottom = true;
if (messagesContainer$1)
scrollToBottom(messagesContainer$1);
logger.info(`角色切换完成 ${oldRoleId} -> ${newRoleId}`);
}
// ==================== 会话管理面板 ====================
/** 加载会话列表并渲染 */
@ -4871,7 +4832,6 @@ var ChatbotSDK = (function () {
const convRoleId = String(historyItem.roleId);
const currentRoleId = getActiveIntegrateId();
if (convRoleId && convRoleId !== currentRoleId) {
logger.info(`会话角色不匹配,自动切换角色 ${currentRoleId} -> ${convRoleId}`);
setActiveRoleId(convRoleId);
// 更新角色下拉框高亮项
if (roleSelect) {
@ -4879,7 +4839,6 @@ var ChatbotSDK = (function () {
}
}
}
logger.info(`切换到会话 conversationId=${conversationId}`);
// 1. 更新 chatId
updateChatId(conversationId);
saveCachedChatId(getActiveIntegrateId(), config$1.userId, conversationId);
@ -4908,7 +4867,6 @@ var ChatbotSDK = (function () {
}
}
catch (err) {
logger.warn(`加载会话消息失败 conversationId=${conversationId}`, err);
}
// 5. 显示新对话按钮
if (clearBtn$1 && messages.length > 0) {
@ -4970,7 +4928,6 @@ var ChatbotSDK = (function () {
/** 初始化 SDK */
function init(rawConfig) {
if (isInitialized) {
logger.warn('SDK 已初始化,请先调用 destroy() 再重新初始化');
return;
}
// 1. 配置解析与校验
@ -5126,7 +5083,6 @@ var ChatbotSDK = (function () {
}
// 19. 异步初始化 chatId 和对话历史(不阻塞 UI)
initChatHistory().catch(err => {
logger.warn('chatId 初始化失败,将在发送消息时重试', err);
});
// 20. 异步拉取保密声明(config.disclaimer undefined = 从后端拉取,有值/空串已在 dom.ts 处理)
if (config.disclaimer === undefined) {
@ -5293,7 +5249,7 @@ var ChatbotSDK = (function () {
document.removeEventListener('keydown', onKeyDown);
window.removeEventListener('resize', onResize);
setErrorCallback(undefined);
const oldIntegrateId = config === null || config === void 0 ? void 0 : config.integrateId;
config === null || config === void 0 ? void 0 : config.integrateId;
config = null;
isInitialized = false;
messagesContainer = null;
@ -5308,7 +5264,6 @@ var ChatbotSDK = (function () {
audioCtx = null;
disclaimerEl = null;
clearApiConfig();
logger.lifecycleDestroy(oldIntegrateId || '');
}
function open() {
if (!windowEl)

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

Loading…
Cancel
Save