聊天工具优化
This commit is contained in:
+550
-113
@@ -1,15 +1,102 @@
|
||||
/**
|
||||
* AI助手Web客户端 - 前端交互逻辑
|
||||
* 100%还原原型设计的交互效果
|
||||
* 对接im-api后端聊天服务
|
||||
* @author huazm
|
||||
*/
|
||||
|
||||
// 全局变量
|
||||
let currentChatId = null;
|
||||
let currentAppId = 15; // 默认使用人岗匹配应用
|
||||
let currentAppId = null;
|
||||
let currentAppInfo = null;
|
||||
let allApps = [];
|
||||
let isTyping = false;
|
||||
let abortController = null; // 用于取消fetch请求
|
||||
let authToken = null; // 认证token
|
||||
|
||||
// API配置
|
||||
const API_BASE_URL = ''; // 使用相对路径
|
||||
const API_BASE_URL = '/api/ai-assistant'; // api后端地址
|
||||
|
||||
/**
|
||||
* Token管理功能
|
||||
*/
|
||||
// 打开Token设置模态框
|
||||
function openTokenModal() {
|
||||
const modal = document.getElementById('token-modal');
|
||||
const input = document.getElementById('token-input');
|
||||
const status = document.getElementById('token-status-modal');
|
||||
|
||||
// 加载已保存的token
|
||||
const savedToken = localStorage.getItem('authToken');
|
||||
if (savedToken) {
|
||||
input.value = savedToken;
|
||||
status.textContent = '已设置';
|
||||
status.className = 'font-medium text-green-400';
|
||||
} else {
|
||||
input.value = '';
|
||||
status.textContent = '未设置';
|
||||
status.className = 'font-medium text-slate-400';
|
||||
}
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
}
|
||||
|
||||
// 关闭Token设置模态框
|
||||
function closeTokenModal() {
|
||||
const modal = document.getElementById('token-modal');
|
||||
modal.classList.add('hidden');
|
||||
}
|
||||
|
||||
// 保存Token
|
||||
function saveToken() {
|
||||
const input = document.getElementById('token-input');
|
||||
const token = input.value.trim();
|
||||
|
||||
if (token) {
|
||||
// 保存到localStorage
|
||||
localStorage.setItem('authToken', token);
|
||||
authToken = token;
|
||||
|
||||
// 更新状态显示
|
||||
const statusModal = document.getElementById('token-status-modal');
|
||||
statusModal.textContent = '已设置';
|
||||
statusModal.className = 'font-medium text-green-400';
|
||||
|
||||
console.log('Token已保存');
|
||||
|
||||
// 关闭模态框
|
||||
closeTokenModal();
|
||||
|
||||
// 重新加载应用列表
|
||||
loadApplications();
|
||||
} else {
|
||||
alert('请输入有效的Token');
|
||||
}
|
||||
}
|
||||
|
||||
// 获取认证请求头
|
||||
function getAuthHeaders() {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
|
||||
// 从localStorage加载token
|
||||
const savedToken = localStorage.getItem('authToken');
|
||||
if (savedToken) {
|
||||
authToken = savedToken;
|
||||
headers['Authorization'] = `Bearer ${savedToken}`;
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
// 页面加载时初始化token
|
||||
function initToken() {
|
||||
const savedToken = localStorage.getItem('authToken');
|
||||
if (savedToken) {
|
||||
authToken = savedToken;
|
||||
console.log('已加载保存的Token');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建动态粒子背景
|
||||
@@ -17,34 +104,279 @@ const API_BASE_URL = ''; // 使用相对路径
|
||||
function createParticles() {
|
||||
const particlesContainer = document.getElementById('particles');
|
||||
const particleCount = 50;
|
||||
|
||||
|
||||
for (let i = 0; i < particleCount; i++) {
|
||||
const particle = document.createElement('div');
|
||||
particle.className = 'particle';
|
||||
|
||||
|
||||
// 随机位置和大小
|
||||
const size = Math.random() * 4 + 1;
|
||||
const posX = Math.random() * 100;
|
||||
const posY = Math.random() * 100;
|
||||
|
||||
|
||||
particle.style.width = `${size}px`;
|
||||
particle.style.height = `${size}px`;
|
||||
particle.style.left = `${posX}%`;
|
||||
particle.style.top = `${posY}%`;
|
||||
|
||||
|
||||
// 随机动画延迟
|
||||
particle.style.animationDelay = `${Math.random() * 5}s`;
|
||||
|
||||
|
||||
particlesContainer.appendChild(particle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载应用列表
|
||||
*/
|
||||
async function loadApplications() {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/chatapp`, {
|
||||
method: 'GET',
|
||||
headers: getAuthHeaders()
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
console.log('API返回数据:', result);
|
||||
|
||||
// 兼容两种数据格式:result.data 或 result.result
|
||||
const apps = result.data || result.result;
|
||||
|
||||
if (result.code === 200 && apps) {
|
||||
allApps = apps;
|
||||
// 按sortNum倒排
|
||||
allApps.sort((a, b) => {
|
||||
if (b.sortNum !== undefined && a.sortNum !== undefined) {
|
||||
return a.sortNum - b.sortNum; // 从小到大排序
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
renderApplications(allApps);
|
||||
} else {
|
||||
showError('加载应用列表失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载应用列表失败:', error);
|
||||
showError('加载应用列表失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染应用列表
|
||||
*/
|
||||
function renderApplications(apps) {
|
||||
const appList = document.getElementById('app-list');
|
||||
|
||||
if (!apps || apps.length === 0) {
|
||||
appList.innerHTML = `
|
||||
<div class="text-center text-slate-400 py-12 col-span-full">
|
||||
<i class="fas fa-inbox text-4xl mb-4"></i>
|
||||
<p>暂无可用的智能体</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
appList.innerHTML = apps.map(app => `
|
||||
<div class="app-card glass-effect bg-slate-800/50 p-6 rounded-xl border border-slate-700 hover:border-primary transition-all duration-300 cursor-pointer group"
|
||||
data-app-id="${app.id}"
|
||||
onclick="selectApplication('${app.id}')">
|
||||
<div class="flex items-start space-x-4">
|
||||
<div class="w-12 h-12 rounded-full bg-gradient-to-r from-primary to-secondary flex items-center justify-center text-white flex-shrink-0">
|
||||
${app.appAvatar ?
|
||||
`<img src="${app.appAvatar}" alt="${app.appName}" class="w-full h-full rounded-full object-cover">` :
|
||||
`<i class="fas fa-robot"></i>`
|
||||
}
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<h3 class="text-white font-semibold text-lg mb-1 truncate group-hover:text-primary transition-colors">
|
||||
${app.appName || '未命名应用'}
|
||||
</h3>
|
||||
<p class="text-slate-400 text-sm line-clamp-2 mb-2">
|
||||
${app.appDescription || app.scopeDescription || '暂无描述'}
|
||||
</p>
|
||||
${app.category ? `
|
||||
<span class="inline-block px-2 py-1 bg-primary/20 text-primary text-xs rounded-full">
|
||||
${app.category}
|
||||
</span>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索应用
|
||||
*/
|
||||
function searchApplications(keyword) {
|
||||
if (!keyword.trim()) {
|
||||
renderApplications(allApps);
|
||||
return;
|
||||
}
|
||||
|
||||
const filtered = allApps.filter(app => {
|
||||
const searchText = keyword.toLowerCase();
|
||||
return (app.appName && app.appName.toLowerCase().includes(searchText)) ||
|
||||
(app.appDescription && app.appDescription.toLowerCase().includes(searchText)) ||
|
||||
(app.scopeDescription && app.scopeDescription.toLowerCase().includes(searchText)) ||
|
||||
(app.category && app.category.toLowerCase().includes(searchText));
|
||||
});
|
||||
|
||||
renderApplications(filtered);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择应用并进入对话
|
||||
*/
|
||||
async function selectApplication(appId) {
|
||||
try {
|
||||
// 查找应用信息
|
||||
currentAppInfo = allApps.find(app => app.id === appId);
|
||||
if (!currentAppInfo) {
|
||||
showError('应用信息不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
currentAppId = appId;
|
||||
currentChatId = null; // 重置聊天ID,开始新对话
|
||||
|
||||
// 隐藏应用选择面板,显示对话面板
|
||||
document.getElementById('app-selector-panel').classList.add('hidden');
|
||||
document.getElementById('chat-panel').classList.remove('hidden');
|
||||
|
||||
// 更新顶部应用信息
|
||||
updateCurrentAppInfo();
|
||||
|
||||
// 清空对话内容
|
||||
clearChatContainer();
|
||||
|
||||
// 显示欢迎消息
|
||||
showWelcomeMessage();
|
||||
|
||||
// 加载快捷回复(如果有)
|
||||
loadQuickReplies();
|
||||
|
||||
} catch (error) {
|
||||
console.error('选择应用失败:', error);
|
||||
showError('选择应用失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新当前应用信息显示
|
||||
*/
|
||||
function updateCurrentAppInfo() {
|
||||
if (!currentAppInfo) return;
|
||||
|
||||
const appAvatar = document.getElementById('current-app-avatar');
|
||||
const appName = document.getElementById('current-app-name');
|
||||
const appDesc = document.getElementById('current-app-desc');
|
||||
|
||||
if (currentAppInfo.appAvatar) {
|
||||
appAvatar.src = currentAppInfo.appAvatar;
|
||||
appAvatar.style.display = 'block';
|
||||
} else {
|
||||
appAvatar.style.display = 'none';
|
||||
}
|
||||
|
||||
appName.textContent = currentAppInfo.appName || 'AI 助手';
|
||||
appDesc.textContent = currentAppInfo.appDescription || currentAppInfo.scopeDescription || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空对话容器
|
||||
*/
|
||||
function clearChatContainer() {
|
||||
const chatContainer = document.getElementById('chat-container');
|
||||
chatContainer.innerHTML = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示欢迎消息
|
||||
*/
|
||||
function showWelcomeMessage() {
|
||||
const chatContainer = document.getElementById('chat-container');
|
||||
const welcomeMsg = currentAppInfo.conversationStarter || '你好!我是' + (currentAppInfo.appName || 'AI助手') + ',有什么可以帮助你的吗?';
|
||||
|
||||
chatContainer.innerHTML = `
|
||||
<div class="flex justify-start slide-in">
|
||||
<div class="max-w-xs lg:max-w-md ai-bubble text-white p-4 rounded-2xl rounded-bl-md">
|
||||
<p>${welcomeMsg}</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载快捷回复
|
||||
*/
|
||||
async function loadQuickReplies() {
|
||||
const quickReplyContainer = document.getElementById('quick-reply-container');
|
||||
const quickReplyButtons = document.getElementById('quick-reply-buttons');
|
||||
|
||||
// 如果应用启用了推荐问题
|
||||
if (currentAppInfo.enableRecommendation) {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/chatapp/${currentAppId}/getRecommendQuestion?pageSize=3¤t=1`, {
|
||||
method: 'GET',
|
||||
headers: getAuthHeaders()
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.code === 200 && result.data && result.data.records && result.data.records.length > 0) {
|
||||
quickReplyButtons.innerHTML = result.data.records.map(q => `
|
||||
<button class="quick-reply-btn px-4 py-2 bg-slate-700 text-slate-300 rounded-lg text-sm hover:bg-slate-600 transition whitespace-nowrap"
|
||||
onclick="sendQuickReply('${q.question.replace(/'/g, "\\'")}')">
|
||||
<i class="fas fa-lightbulb mr-2"></i>${q.question}
|
||||
</button>
|
||||
`).join('');
|
||||
quickReplyContainer.classList.remove('hidden');
|
||||
} else {
|
||||
quickReplyContainer.classList.add('hidden');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载推荐问题失败:', error);
|
||||
quickReplyContainer.classList.add('hidden');
|
||||
}
|
||||
} else {
|
||||
quickReplyContainer.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回应用选择
|
||||
*/
|
||||
function backToApps() {
|
||||
// 取消正在进行的请求
|
||||
if (abortController) {
|
||||
abortController.abort();
|
||||
abortController = null;
|
||||
}
|
||||
|
||||
// 重置状态
|
||||
currentAppId = null;
|
||||
currentAppInfo = null;
|
||||
currentChatId = null;
|
||||
|
||||
// 切换面板
|
||||
document.getElementById('chat-panel').classList.add('hidden');
|
||||
document.getElementById('app-selector-panel').classList.remove('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加消息到聊天容器
|
||||
*/
|
||||
function addMessage(message, isUser = true) {
|
||||
const chatContainer = document.getElementById('chat-container');
|
||||
|
||||
|
||||
// 移除欢迎消息
|
||||
const welcomeDiv = chatContainer.querySelector('.flex.justify-center');
|
||||
if (welcomeDiv) {
|
||||
welcomeDiv.remove();
|
||||
}
|
||||
|
||||
// 移除打字指示器
|
||||
removeTypingIndicator();
|
||||
|
||||
@@ -119,62 +451,212 @@ function escapeHtml(text) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* 发送消息(使用SSE流式响应)
|
||||
*/
|
||||
async function sendMessage() {
|
||||
const input = document.getElementById('message-input');
|
||||
const message = input.value.trim();
|
||||
|
||||
if (!message) return;
|
||||
|
||||
|
||||
if (!message || !currentAppId) return;
|
||||
|
||||
// 添加用户消息
|
||||
addMessage(message, true);
|
||||
input.value = '';
|
||||
|
||||
|
||||
// 显示打字指示器
|
||||
showTypingIndicator();
|
||||
|
||||
|
||||
try {
|
||||
// 调用API
|
||||
const response = await fetch(`${API_BASE_URL}/api/chat/send`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
appId: currentAppId,
|
||||
message: message,
|
||||
chatId: currentChatId,
|
||||
stream: false
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// 移除打字指示器
|
||||
removeTypingIndicator();
|
||||
|
||||
if (data.code === 200 && data.data) {
|
||||
// 添加AI回复
|
||||
addMessage(data.data.answer, false);
|
||||
|
||||
// 更新chatId
|
||||
if (data.data.chatId) {
|
||||
currentChatId = data.data.chatId;
|
||||
// 构建请求体
|
||||
const requestBody = {
|
||||
chatId: currentChatId,
|
||||
appId: currentAppId,
|
||||
equipment: 'web',
|
||||
messageTag: 'AI_TAG',
|
||||
body: {
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: message
|
||||
}
|
||||
],
|
||||
channel: 'web',
|
||||
attachmentIds: [],
|
||||
recommendQuestions: [],
|
||||
variables: {},
|
||||
reasoning: currentAppInfo.reasoningEnable ? 'true' : 'false'
|
||||
}
|
||||
} else {
|
||||
addMessage(`错误: ${data.message || '未知错误'}`, false);
|
||||
};
|
||||
|
||||
// 使用fetch进行SSE连接(支持自定义请求头)
|
||||
const url = `${API_BASE_URL}/chat/completions/message`;
|
||||
|
||||
// 取消之前的请求
|
||||
if (abortController) {
|
||||
abortController.abort();
|
||||
}
|
||||
|
||||
// 创建新的AbortController
|
||||
abortController = new AbortController();
|
||||
|
||||
// 使用fetch发送POST请求,处理流式响应
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: getAuthHeaders(),
|
||||
body: JSON.stringify(requestBody),
|
||||
signal: abortController.signal
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
let aiMessage = '';
|
||||
let messageDiv = null;
|
||||
|
||||
// 读取流式响应
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = '';
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 解码数据
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
|
||||
// 按行分割
|
||||
const lines = buffer.split('\n');
|
||||
buffer = lines.pop() || ''; // 保留最后一个不完整的行
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('data: ')) {
|
||||
const data = line.substring(6).trim();
|
||||
|
||||
if (data === '[DONE]') {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
|
||||
// 处理不同类型的事件
|
||||
if (json.detailId) {
|
||||
// 保存chatId
|
||||
if (json.chatId && !currentChatId) {
|
||||
currentChatId = json.chatId;
|
||||
}
|
||||
|
||||
// 更新AI回复
|
||||
if (json.answer && json.answer.content) {
|
||||
aiMessage = json.answer.content;
|
||||
|
||||
// 移除打字指示器
|
||||
removeTypingIndicator();
|
||||
|
||||
// 更新或创建消息气泡
|
||||
if (!messageDiv) {
|
||||
messageDiv = createAIMessageBubble(aiMessage);
|
||||
} else {
|
||||
updateAIMessageBubble(messageDiv, aiMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否完成
|
||||
if (json.status === 'FINISH' || json.status === 'ERROR') {
|
||||
if (json.status === 'ERROR') {
|
||||
showError('AI回复出错');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('解析SSE数据失败:', parseError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 确保移除打字指示器
|
||||
removeTypingIndicator();
|
||||
|
||||
} catch (error) {
|
||||
console.error('发送消息失败:', error);
|
||||
removeTypingIndicator();
|
||||
addMessage('抱歉,发送消息失败,请稍后重试。', false);
|
||||
showError('发送消息失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建AI消息气泡
|
||||
*/
|
||||
function createAIMessageBubble(content) {
|
||||
const chatContainer = document.getElementById('chat-container');
|
||||
|
||||
const messageDiv = document.createElement('div');
|
||||
messageDiv.className = 'flex justify-start slide-in';
|
||||
messageDiv.innerHTML = `
|
||||
<div class="max-w-xs lg:max-w-md ai-bubble text-white p-4 rounded-2xl rounded-bl-md">
|
||||
<p class="ai-message-content">${escapeHtml(content)}</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
chatContainer.appendChild(messageDiv);
|
||||
scrollToBottom();
|
||||
|
||||
return messageDiv;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新AI消息气泡
|
||||
*/
|
||||
function updateAIMessageBubble(messageDiv, content) {
|
||||
const contentElement = messageDiv.querySelector('.ai-message-content');
|
||||
if (contentElement) {
|
||||
contentElement.innerHTML = escapeHtml(content);
|
||||
scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示错误消息
|
||||
*/
|
||||
function showError(message) {
|
||||
const chatContainer = document.getElementById('chat-container');
|
||||
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'flex justify-center my-4';
|
||||
errorDiv.innerHTML = `
|
||||
<div class="bg-red-500/20 border border-red-500 text-red-300 px-4 py-2 rounded-lg">
|
||||
<i class="fas fa-exclamation-circle mr-2"></i>${escapeHtml(message)}
|
||||
</div>
|
||||
`;
|
||||
|
||||
chatContainer.appendChild(errorDiv);
|
||||
scrollToBottom();
|
||||
|
||||
// 3秒后自动移除
|
||||
setTimeout(() => {
|
||||
errorDiv.remove();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 快捷回复按钮点击
|
||||
*/
|
||||
function sendQuickReply(text) {
|
||||
const input = document.getElementById('message-input');
|
||||
input.value = text;
|
||||
sendMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 快捷回复填充(不发送)
|
||||
*/
|
||||
function handleQuickReply(text) {
|
||||
const input = document.getElementById('message-input');
|
||||
input.value = text;
|
||||
@@ -217,35 +699,8 @@ function changeFont(font) {
|
||||
*/
|
||||
function startNewChat() {
|
||||
currentChatId = null;
|
||||
const chatContainer = document.getElementById('chat-container');
|
||||
|
||||
// 清空聊天记录(保留欢迎消息)
|
||||
const messages = chatContainer.querySelectorAll('.slide-in');
|
||||
messages.forEach(msg => msg.remove());
|
||||
|
||||
// 添加欢迎消息
|
||||
addMessage('您好!我是AI助手,有什么可以帮助您的吗?', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 待办事项管理
|
||||
*/
|
||||
function addTodoItem() {
|
||||
const input = document.getElementById('todo-input');
|
||||
const text = input.value.trim();
|
||||
|
||||
if (!text) return;
|
||||
|
||||
const todoList = document.getElementById('todo-list');
|
||||
const todoItem = document.createElement('div');
|
||||
todoItem.className = 'flex items-center space-x-2 p-2 bg-slate-800/30 rounded-lg';
|
||||
todoItem.innerHTML = `
|
||||
<input type="checkbox" class="rounded text-primary">
|
||||
<span class="text-slate-300 text-sm">${escapeHtml(text)}</span>
|
||||
`;
|
||||
|
||||
todoList.appendChild(todoItem);
|
||||
input.value = '';
|
||||
clearChatContainer();
|
||||
showWelcomeMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -257,6 +712,23 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// 创建粒子背景
|
||||
createParticles();
|
||||
|
||||
// 加载应用列表
|
||||
loadApplications();
|
||||
|
||||
// 绑定应用搜索
|
||||
const searchInput = document.getElementById('app-search-input');
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('input', function(e) {
|
||||
searchApplications(e.target.value);
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定返回按钮
|
||||
const backButton = document.getElementById('back-to-apps-btn');
|
||||
if (backButton) {
|
||||
backButton.addEventListener('click', backToApps);
|
||||
}
|
||||
|
||||
// 绑定发送按钮事件
|
||||
const sendButton = document.getElementById('send-button');
|
||||
if (sendButton) {
|
||||
@@ -274,27 +746,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定快捷回复按钮
|
||||
const quickReplyButtons = document.querySelectorAll('.quick-reply-btn');
|
||||
quickReplyButtons.forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const text = this.textContent.trim();
|
||||
// 移除图标文本
|
||||
const cleanText = text.replace(/[💡📅✅]/g, '').trim();
|
||||
handleQuickReply(cleanText);
|
||||
});
|
||||
});
|
||||
|
||||
// 绑定主题切换按钮
|
||||
const themeButtons = document.querySelectorAll('.theme-btn');
|
||||
themeButtons.forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const theme = this.dataset.theme;
|
||||
changeTheme(theme);
|
||||
});
|
||||
});
|
||||
|
||||
// 绑定字体选择
|
||||
// 绑定字体切换
|
||||
const fontSelect = document.getElementById('font-select');
|
||||
if (fontSelect) {
|
||||
fontSelect.addEventListener('change', function() {
|
||||
@@ -302,23 +754,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定待办事项添加
|
||||
const todoAddButton = document.getElementById('todo-add-btn');
|
||||
const todoInput = document.getElementById('todo-input');
|
||||
if (todoAddButton && todoInput) {
|
||||
todoAddButton.addEventListener('click', addTodoItem);
|
||||
todoInput.addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
addTodoItem();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加欢迎消息
|
||||
setTimeout(() => {
|
||||
addMessage('您好!我是AI助手,有什么可以帮助您的吗?', false);
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// 初始化Token
|
||||
initToken();
|
||||
|
||||
console.log('AI助手Web客户端初始化完成');
|
||||
});
|
||||
Reference in New Issue
Block a user