import { Component, Inject, OnInit, OnDestroy } from '@angular/core'; import { I18NService } from '@core'; import { ALAIN_I18N_TOKEN, SettingsService, User } from '@delon/theme'; import { LayoutDefaultOptions } from '@delon/theme/layout-default'; import { environment } from '@env/environment'; import { Observable, Subject, of } from 'rxjs'; import { delay, tap, finalize, catchError, takeUntil } from 'rxjs/operators'; import { CONSTANTS } from '../../shared/constants'; import { AiBotService, ChatMessage } from '../../shared/services/ai-bot.service'; @Component({ selector: 'layout-basic', template: `
Apache HertzBeat (incubating) {{ version }}
Copyright © {{ currentYear }} Apache HertzBeat
Licensed under the Apache License, Version 2.0
{{ 'ai.bot.title' | i18n }}
{{ message.content }}
{{ message.timestamp | date : 'HH:mm' }}
{{ currentBotMessage.content }}
{{ currentBotMessage.timestamp | date : 'HH:mm' }}
`, styleUrls: ['./basic.component.less'] }) export class LayoutBasicComponent implements OnInit, OnDestroy { options: LayoutDefaultOptions = { logoExpanded: `./assets/brand_white.svg`, logoCollapsed: `./assets/logo.svg` }; avatar: string = `./assets/img/avatar.svg`; searchToggleStatus = false; showSettingDrawer = !environment.production; version = CONSTANTS.VERSION; currentYear = new Date().getFullYear(); get user(): User { return this.settings.user; } get role(): string { let userTmp = this.settings.user; if (userTmp == undefined || userTmp.role == undefined) { return this.i18nSvc.fanyi('app.role.admin'); } else { let roles: string[] = JSON.parse(userTmp.role); return roles.length > 0 ? roles[0] : ''; } } // AI Chatbot related properties isChatbotOpen = false; isChatbotMaximized = false; chatMessages: ChatMessage[] = []; currentMessage = ''; isLoading = false; currentBotMessage: ChatMessage | null = null; // For subscription cleanup private destroy$ = new Subject(); constructor( private settings: SettingsService, @Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService, private aiBotService: AiBotService ) {} ngOnInit(): void { // Initialize welcome message this.chatMessages.push({ content: this.i18nSvc.fanyi('ai.bot.greeting'), isUser: false, timestamp: new Date() }); console.log('AI Chatbot initialization completed'); } ngOnDestroy(): void { // Cancel all subscriptions when component is destroyed this.destroy$.next(); this.destroy$.complete(); } toggleChatbot(): void { this.isChatbotOpen = !this.isChatbotOpen; if (!this.isChatbotOpen) { setTimeout(() => { this.isChatbotMaximized = false; }, 300); } else { // Scroll to bottom when window opens setTimeout(() => this.scrollToBottom(), 100); } console.log('Toggle chatbot status:', this.isChatbotOpen ? 'open' : 'closed'); } toggleMaximize(): void { setTimeout(() => { this.isChatbotMaximized = !this.isChatbotMaximized; console.log('Chat window maximize status:', this.isChatbotMaximized ? 'maximized' : 'normal'); }, 10); } sendMessage(): void { if (!this.currentMessage.trim() || this.isLoading) return; // Add user message this.chatMessages.push({ content: this.currentMessage, isUser: true, timestamp: new Date() }); const userMessage = this.currentMessage; this.currentMessage = ''; this.isLoading = true; this.currentBotMessage = null; // Ensure scrolling to bottom after message display setTimeout(() => this.scrollToBottom(), 100); // Call AI service to get response this.aiBotService .sendMessage(userMessage) .pipe( takeUntil(this.destroy$), finalize(() => { this.isLoading = false; // If there is a current message, add it to chat history if (this.currentBotMessage) { this.chatMessages.push({ ...this.currentBotMessage }); this.currentBotMessage = null; } // Ensure scrolling to bottom after message display setTimeout(() => this.scrollToBottom(), 100); }) ) .subscribe({ next: response => { console.log('Received AI response update:', response); // Update currently receiving message this.currentBotMessage = response; // Scroll to bottom in real-time this.scrollToBottom(); }, error: error => { console.error('AI response error:', error); // Add error message this.chatMessages.push({ content: this.i18nSvc.fanyi('ai.bot.connect-fail'), isUser: false, timestamp: new Date() }); } }); } // Scroll to bottom of messages private scrollToBottom(): void { try { const chatMessages = document.querySelector('.chatbot-messages'); if (chatMessages) { chatMessages.scrollTop = chatMessages.scrollHeight; } } catch (err) { console.error('Failed to scroll to bottom:', err); } } }