Jelajahi Sumber

feat:home-AIchat

0235967 2 minggu lalu
induk
melakukan
1d5e8ac180

+ 48 - 0
travel-web/src/modules/pc-home/pages/chat-assistant/chat-assistant.html

@@ -0,0 +1,48 @@
+<div class="chat-container">
+    <div class="chat-header">
+      <i class="fas fa-dove"></i>
+      <h3>AI客服助手 - 赣鄱小鹤</h3>
+      <button class="close-btn" (click)="closeChat()">
+        <i class="fas fa-times"></i>
+      </button>
+    </div>
+    
+    <div class="chat-messages" #chatContainer>
+      <div *ngFor="let message of messages" class="message" [ngClass]="{'user': message.role === 'user', 'assistant': message.role === 'assistant'}">
+        <div class="avatar" *ngIf="message.role === 'assistant'">
+          <i class="fas fa-dove"></i>
+        </div>
+        <div class="content">
+          <div class="text">{{message.content}}</div>
+        </div>
+        <div class="avatar" *ngIf="message.role === 'user'">
+          <i class="fas fa-user"></i>
+        </div>
+      </div>
+      
+      <div *ngIf="isLoading" class="message assistant">
+        <div class="avatar">
+          <i class="fas fa-dove"></i>
+        </div>
+        <div class="content">
+          <div class="loading-dots">
+            <span></span>
+            <span></span>
+            <span></span>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <div class="chat-input">
+      <input 
+        type="text" 
+        [(ngModel)]="userInput" 
+        (keyup.enter)="sendMessage()" 
+        placeholder="输入您的问题..."
+        [disabled]="isLoading">
+      <button (click)="sendMessage()" [disabled]="!userInput.trim() || isLoading">
+        <i class="fas fa-paper-plane"></i>
+      </button>
+    </div>
+  </div>

+ 187 - 0
travel-web/src/modules/pc-home/pages/chat-assistant/chat-assistant.scss

@@ -0,0 +1,187 @@
+.chat-container {
+    position: fixed;
+    bottom: 20px;
+    right: 20px;
+    width: 350px;
+    max-width: 90%;
+    height: 500px;
+    background: white;
+    border-radius: 15px;
+    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
+    display: flex;
+    flex-direction: column;
+    z-index: 1000;
+    overflow: hidden;
+    transform: translateY(20px);
+    opacity: 0;
+    animation: fadeInUp 0.3s ease-out forwards;
+  }
+  
+  @keyframes fadeInUp {
+    to {
+      transform: translateY(0);
+      opacity: 1;
+    }
+  }
+  
+  .chat-header {
+    background: linear-gradient(90deg, var(--mountain-green), #5d8c5a);
+    color: white;
+    padding: 15px;
+    display: flex;
+    align-items: center;
+    position: relative;
+    
+    i {
+      font-size: 1.2rem;
+      margin-right: 10px;
+    }
+    
+    h3 {
+      margin: 0;
+      font-size: 1rem;
+      font-weight: 600;
+    }
+    
+    .close-btn {
+      position: absolute;
+      right: 15px;
+      background: transparent;
+      border: none;
+      color: white;
+      cursor: pointer;
+      font-size: 1rem;
+    }
+  }
+  
+  .chat-messages {
+    flex: 1;
+    padding: 15px;
+    overflow-y: auto;
+    background: #f9f9f9;
+    
+    .message {
+      display: flex;
+      margin-bottom: 15px;
+      
+      &.user {
+        justify-content: flex-end;
+        
+        .content {
+          background: var(--primary-blue);
+          color: white;
+          border-radius: 15px 15px 0 15px;
+        }
+      }
+      
+      &.assistant {
+        justify-content: flex-start;
+        
+        .content {
+          background: white;
+          color: var(--dark-charcoal);
+          border-radius: 15px 15px 15px 0;
+          box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+        }
+      }
+      
+      .avatar {
+        width: 32px;
+        height: 32px;
+        border-radius: 50%;
+        background: #eee;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin: 0 10px;
+        flex-shrink: 0;
+        
+        i {
+          color: var(--mountain-green);
+        }
+      }
+      
+      .content {
+        max-width: 70%;
+        padding: 10px 15px;
+        
+        .text {
+          white-space: pre-wrap;
+          line-height: 1.4;
+        }
+      }
+    }
+    
+    .loading-dots {
+      display: flex;
+      padding: 10px 0;
+      
+      span {
+        width: 8px;
+        height: 8px;
+        margin: 0 3px;
+        background: var(--mountain-green);
+        border-radius: 50%;
+        display: inline-block;
+        animation: bounce 1.4s infinite ease-in-out both;
+        
+        &:nth-child(1) {
+          animation-delay: -0.32s;
+        }
+        
+        &:nth-child(2) {
+          animation-delay: -0.16s;
+        }
+      }
+    }
+  }
+  
+  @keyframes bounce {
+    0%, 80%, 100% { 
+      transform: scale(0);
+    }
+    40% { 
+      transform: scale(1.0);
+    }
+  }
+  
+  .chat-input {
+    display: flex;
+    padding: 10px;
+    border-top: 1px solid #eee;
+    background: white;
+    
+    input {
+      flex: 1;
+      padding: 10px 15px;
+      border: 1px solid #ddd;
+      border-radius: 30px;
+      outline: none;
+      font-size: 0.9rem;
+      
+      &:focus {
+        border-color: var(--primary-blue);
+      }
+    }
+    
+    button {
+      width: 40px;
+      height: 40px;
+      border-radius: 50%;
+      background: var(--mountain-green);
+      color: white;
+      border: none;
+      margin-left: 10px;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      
+      &:hover {
+        background: darken(#5d8c5a, 10%);
+      }
+      
+      &:disabled {
+        background: #ccc;
+        cursor: not-allowed;
+      }
+    }
+  }

+ 68 - 0
travel-web/src/modules/pc-home/pages/chat-assistant/chat-assistant.ts

@@ -0,0 +1,68 @@
+import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
+import { TestCompletion } from '../../../../lib/completion';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+@Component({
+  selector: 'app-chat-assistant',
+  standalone:true,
+  imports: [CommonModule, FormsModule],
+  templateUrl: './chat-assistant.html',
+  styleUrls: ['./chat-assistant.scss']
+})
+export class ChatAssistant implements AfterViewInit {
+  @ViewChild('chatContainer') chatContainer!: ElementRef;
+  
+  messages: Array<{role: string, content: string}> = [
+    {role: 'assistant', content: '您好!我是赣鄱小鹤,24小时为您服务。请问有什么可以帮您?'}
+  ];
+  userInput = '';
+  isLoading = false;
+  
+  constructor() {}
+
+  ngAfterViewInit() {
+    this.scrollToBottom();
+  }
+
+  closeChat() {
+    // 这里添加关闭聊天窗口的逻辑
+    console.log('Close chat clicked');
+    // 如果需要实际关闭,可以添加相应逻辑
+  }
+
+  async sendMessage() {
+    if (!this.userInput.trim() || this.isLoading) return;
+    
+    const userMessage = this.userInput;
+    this.messages.push({role: 'user', content: userMessage});
+    this.userInput = '';
+    this.isLoading = true;
+    this.scrollToBottom();
+    
+    try {
+      const completion = new TestCompletion(this.messages);
+      await completion.sendMessage(null, (content) => {
+        // 更新最后一条消息内容
+        if (this.messages[this.messages.length - 1].role === 'assistant') {
+          this.messages[this.messages.length - 1].content = content;
+        } else {
+          this.messages.push({role: 'assistant', content});
+        }
+        this.scrollToBottom();
+      });
+    } catch (error) {
+      console.error('AI 请求失败:', error);
+      this.messages.push({role: 'assistant', content: '抱歉,处理您的请求时出现了问题。请稍后再试。'});
+    } finally {
+      this.isLoading = false;
+      this.scrollToBottom();
+    }
+  }
+
+  private scrollToBottom(): void {
+    setTimeout(() => {
+      this.chatContainer.nativeElement.scrollTop = this.chatContainer.nativeElement.scrollHeight;
+    }, 0);
+  }
+}

+ 3 - 2
travel-web/src/modules/pc-home/pages/page-home/page-home.html

@@ -162,7 +162,7 @@
           <i class="fas fa-dove"></i>
         </div>
         <p>您好!我是赣鄱小鹤,24小时为您服务</p>
-        <button style="margin-top: 1.5rem; background: var(--mountain-green); color: white; border: none; padding: 0.8rem 2rem; border-radius: 30px; cursor: pointer; font-weight: bold; transition: all 0.3s ease;">
+        <button (click)="toggleChat()" style="margin-top: 1.5rem; background: var(--mountain-green); color: white; border: none; padding: 0.8rem 2rem; border-radius: 30px; cursor: pointer; font-weight: bold; transition: all 0.3s ease;">
           开始咨询
         </button>
       </div>
@@ -227,4 +227,5 @@
   <div class="copyright">
     © 2023 江西数字文化发展协会 版权所有 | 赣ICP备12345678号
   </div>
-</footer>
+</footer>
+<app-chat-assistant *ngIf="showChat"></app-chat-assistant>

+ 7 - 2
travel-web/src/modules/pc-home/pages/page-home/page-home.ts

@@ -2,21 +2,26 @@
 import { Component, AfterViewInit, ViewChild, ElementRef, OnDestroy } from '@angular/core';
 import { Autoplay, Pagination, Navigation } from 'swiper/modules';
 import { CommonModule } from '@angular/common';
+import { ChatAssistant } from '../chat-assistant/chat-assistant';
 import Swiper from 'swiper';
 import * as echarts from 'echarts';
 
 @Component({
   selector: 'app-page-home',
   standalone: true,
-  imports: [CommonModule],
+  imports: [ChatAssistant,CommonModule],
   templateUrl: './page-home.html',
-  styleUrls: ['./page-home.scss']
+  styleUrls: ['./page-home.scss'],
 })
 export class PageHome implements AfterViewInit, OnDestroy {
   @ViewChild('swiperContainer') swiperContainer!: ElementRef;
   @ViewChild('galleryChart') galleryChart!: ElementRef;
   @ViewChild('xrChart') xrChart!: ElementRef;
   @ViewChild('dashboardChart') dashboardChart!: ElementRef;
+  showChat=false;
+  toggleChat(){
+    this.showChat=!this.showChat;
+  }
 
   private swiper: any;
   private galleryChartInstance: any;