class ChatService { constructor() { this.messages = []; this.welcomeMessageShown = false; this.pageReady = false; this.userId = this.getOrCreateUserId(); this.init(); } checkAndShowWelcomeMessage() { const checkWelcomeMessage = () => { if (document.getElementById('chat-messages')) { setTimeout(() => { this.showWelcomeMessage(); }, 500); } else { setTimeout(checkWelcomeMessage, 100); } }; checkWelcomeMessage(); } getOrCreateUserId() { let userId = localStorage.getItem('chatUserId'); if (!userId) { userId = 'user_' + Date.now() + '_' + Math.floor(Math.random() * 1000000); localStorage.setItem('chatUserId', userId); } return userId; } init() { if (!this.userId) { this.userId = this.getOrCreateUserId(); } this.loadFromLocalStorage(); this.displayMessages(); this.setupEventListeners(); this.pageReady = true; window.addEventListener('languageChanged', () => { const welcomeMsg = this.messages.find(msg => msg.id.startsWith('welcome_')); if (welcomeMsg) { let welcomeText = '您好!欢迎访问无穷智能自动售货机官网,有什么可以帮助您的吗?'; if (window.languageManager && window.languageManager.isLoaded) { const translatedWelcome = window.languageManager.getTranslation('chat_welcome'); if (translatedWelcome) { welcomeText = translatedWelcome; } } welcomeMsg.message = welcomeText; this.displayMessages(); } }); const waitForLanguageManager = async () => { if (window.languageManager && window.languageManager.isLoaded) { await this.loadMessages(); } else { setTimeout(waitForLanguageManager, 100); } }; waitForLanguageManager(); } loadFromLocalStorage() { const storedMessages = localStorage.getItem('chatMessages'); if (storedMessages) { try { const parsedMessages = JSON.parse(storedMessages); this.messages = parsedMessages.filter(msg => { if (msg.userId !== this.userId) { return false; } if (msg.id.startsWith('welcome_')) { return false; } return true; }); } catch (error) { this.messages = []; } } else { this.messages = []; } } async loadMessages() { const currentNonWelcomeMessages = this.messages.filter(msg => !msg.id.startsWith('welcome_')); try { const response = await fetch(`/api/chat?userId=${this.userId}`); if (response.ok) { const data = await response.json(); if (data.success && data.data) { const serverMessages = data.data.filter(msg => { const msgUserId = msg.userId || msg.sessionId; if (msgUserId !== this.userId) return false; if (msg.id.startsWith('welcome_')) return false; return true; }); const mergedMessages = [...currentNonWelcomeMessages, ...serverMessages]; const filteredMergedMessages = mergedMessages.filter(msg => { const msgUserId = msg.userId || msg.sessionId; if (msgUserId !== this.userId) return false; if (msg.id.startsWith('welcome_')) return false; return true; }); const uniqueMessages = this.removeDuplicateMessages(filteredMergedMessages); if (!this.messagesEqual(currentNonWelcomeMessages, uniqueMessages)) { const welcomeMsg = this.messages.find(msg => msg.id.startsWith('welcome_')); this.messages = uniqueMessages; if (welcomeMsg) { this.messages.unshift(welcomeMsg); } this.saveToLocalStorage(); this.displayMessages(); } return; } } } catch (error) { } const storedMessages = localStorage.getItem('chatMessages'); if (storedMessages) { try { const parsedMessages = JSON.parse(storedMessages); const filteredMessages = parsedMessages.filter(msg => { const msgUserId = msg.userId || msg.sessionId; if (msgUserId !== this.userId) return false; if (msg.id.startsWith('welcome_')) return false; return true; }); const finalMessages = [...currentNonWelcomeMessages, ...filteredMessages]; const uniqueMessages = this.removeDuplicateMessages(finalMessages); if (!this.messagesEqual(currentNonWelcomeMessages, uniqueMessages)) { const welcomeMsg = this.messages.find(msg => msg.id.startsWith('welcome_')); this.messages = uniqueMessages; if (welcomeMsg) { this.messages.unshift(welcomeMsg); } this.displayMessages(); } } catch (error) { this.displayMessages(); } } } removeDuplicateMessages(messages) { const uniqueMessages = []; const seenMessages = new Map(); const welcomeMessages = []; const sortedMessages = messages.sort((a, b) => { return new Date(b.timestamp) - new Date(a.timestamp); }); for (const message of sortedMessages) { if (message.id.startsWith('welcome_')) { if (welcomeMessages.length === 0) { welcomeMessages.push(message); } } else { const messageKey = `${message.message}-${message.userType}-${message.timestamp}-${message.userId || message.sessionId}`; if (!seenMessages.has(messageKey)) { seenMessages.set(messageKey, true); uniqueMessages.push(message); } } } return [...welcomeMessages, ...uniqueMessages].sort((a, b) => { return new Date(a.timestamp) - new Date(b.timestamp); }); } messagesEqual(arr1, arr2) { if (arr1.length !== arr2.length) return false; for (let i = 0; i < arr1.length; i++) { if (arr1[i].id !== arr2[i].id || arr1[i].message !== arr2[i].message || arr1[i].userType !== arr2[i].userType || arr1[i].timestamp !== arr2[i].timestamp || arr1[i].status !== arr2[i].status || arr1[i].userId !== arr2[i].userId) { return false; } } return true; } saveToLocalStorage() { const filteredMessages = this.messages.filter(msg => { if (msg.id.startsWith('welcome_')) { return false; } return true; }); localStorage.setItem('chatMessages', JSON.stringify(filteredMessages)); } setupEventListeners() { const setupListeners = () => { const chatSend = document.getElementById('chat-send'); const chatInput = document.getElementById('chat-input'); if (chatSend) { chatSend.addEventListener('click', () => { const message = chatInput.value.trim(); if (message) { this.sendMessage(message); chatInput.value = ''; } }); } if (chatInput) { chatInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { const message = chatInput.value.trim(); if (message) { this.sendMessage(message); chatInput.value = ''; } } }); } const chatButton = document.getElementById('chat-button'); const chatBox = document.getElementById('chat-box'); const chatClose = document.getElementById('chat-close'); if (chatButton && chatBox) { chatButton.addEventListener('click', () => { chatBox.classList.add('open'); chatButton.style.display = 'none'; this.showWelcomeMessage(); }); } if (chatClose && chatBox) { chatClose.addEventListener('click', () => { chatBox.classList.remove('open'); const chatButton = document.getElementById('chat-button'); if (chatButton) { chatButton.style.display = 'flex'; } }); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', setupListeners); } else { setupListeners(); } } getCurrentDate() { const now = new Date(); return now.toISOString().split('T')[0]; } isTodayMessage(message) { if (!message.timestamp) return false; const messageDate = new Date(message.timestamp).toISOString().split('T')[0]; const currentDate = this.getCurrentDate(); return messageDate === currentDate; } showWelcomeMessage() { const chatMessages = document.getElementById('chat-messages'); if (!chatMessages) return; let welcomeText = '您好!欢迎访问无穷智能自动售货机官网,有什么可以帮助您的吗?'; if (window.languageManager && window.languageManager.isLoaded) { const translatedWelcome = window.languageManager.getTranslation('chat_welcome'); if (translatedWelcome) { welcomeText = translatedWelcome; } } this.messages = this.messages.filter(msg => !msg.id.startsWith('welcome_')); const welcomeMessage = { id: 'welcome_' + Date.now(), message: welcomeText, userType: 'bot', timestamp: new Date().toISOString(), status: 'sent', userId: this.userId }; this.messages.unshift(welcomeMessage); this.displayMessages(); this.welcomeMessageShown = true; } updateWelcomeMessage(welcomeText) { const welcomeMsg = this.messages.find(msg => msg.id.startsWith('welcome_')); if (welcomeMsg) { welcomeMsg.message = welcomeText; this.saveToLocalStorage(); this.displayMessages(); } } async sendMessage(message) { const newMessage = { id: 'msg_' + Date.now() + '_' + Math.floor(Math.random() * 1000), message: message, userType: 'user', timestamp: new Date().toISOString(), status: 'sending', userId: this.userId }; this.messages.push(newMessage); this.saveToLocalStorage(); this.displayMessage(newMessage); try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: message, userType: 'user', timestamp: newMessage.timestamp, userId: this.userId }) }); if (response.ok) { const data = await response.json(); if (data.success) { newMessage.status = 'sent'; this.saveToLocalStorage(); this.updateMessageDisplay(newMessage); await this.loadMessages(); } } } catch (error) { newMessage.status = 'failed'; this.saveToLocalStorage(); this.updateMessageDisplay(newMessage); } } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } displayMessage(message) { const chatMessages = document.getElementById('chat-messages'); if (!chatMessages) return; const messageElement = document.createElement('div'); messageElement.id = 'msg_' + message.id; messageElement.className = `chat-message ${message.userType === 'user' ? 'user' : 'bot'}`; let statusIndicator = ''; if (message.userType === 'user') { if (message.status === 'sending') { statusIndicator = ''; } else if (message.status === 'failed') { statusIndicator = ''; } } messageElement.innerHTML = `
`; chatMessages.appendChild(messageElement); chatMessages.scrollTop = chatMessages.scrollHeight; } updateMessageDisplay(message) { const messageElement = document.getElementById('msg_' + message.id); if (!messageElement) return; let statusIndicator = ''; if (message.userType === 'user') { if (message.status === 'sent') { statusIndicator = ''; } else if (message.status === 'failed') { statusIndicator = ''; } } const footerElement = messageElement.querySelector('.chat-message-footer'); if (footerElement) { footerElement.innerHTML = ` ${statusIndicator} `; } } displayMessages() { const chatMessages = document.getElementById('chat-messages'); if (!chatMessages) return; chatMessages.innerHTML = ''; this.messages.forEach(message => { this.displayMessage(message); }); if (this.messages.length === 0) { this.welcomeMessageShown = false; } } formatTime(timestamp) { const date = new Date(timestamp); return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }); } clearMessages() { this.messages = this.messages.filter(msg => !msg.id.startsWith('welcome_')); this.welcomeMessageShown = false; this.saveToLocalStorage(); this.displayMessages(); } startPolling() { this.pollingInterval = setInterval(() => { this.loadMessages(); }, 5000); } stopPolling() { if (this.pollingInterval) { clearInterval(this.pollingInterval); } } } if (typeof window !== 'undefined') { const initChatService = () => { const waitForLanguageManager = () => { if (window.languageManager) { window.chatService = new ChatService(); window.chatService.startPolling(); } else { setTimeout(waitForLanguageManager, 100); } }; waitForLanguageManager(); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initChatService); } else { initChatService(); } }