Переглянути джерело

feat: add chat history persistence and view toggle for AI design analysis

- Implemented chat history save/load functionality using project data storage
- Added toggle button to switch between analysis results and chat history view
- Enhanced UI with header actions grouping and emoji icons for better UX
徐福静0235668 23 годин тому
батько
коміт
c3023ae134

+ 6 - 3
src/modules/project/pages/project-detail/stages/components/ai-design-analysis/ai-design-analysis.component.html

@@ -25,7 +25,7 @@
       </div>
 
       <!-- 步骤1: 上传图片和描述 -->
-      @if (!aiDesignAnalysisResult) {
+      @if (!aiDesignAnalysisResult || showChatHistory) {
         <div class="upload-section">
           <!-- 已上传的文件 -->
           @if (aiDesignUploadedFiles.length > 0) {
@@ -260,12 +260,15 @@
       }
 
       <!-- 步骤2: 显示分析结果 -->
-      @if (aiDesignAnalysisResult && !aiDesignReport) {
+      @if (aiDesignAnalysisResult && !aiDesignReport && !showChatHistory) {
         <div class="analysis-result-section">
           <div class="result-header">
             <div class="header-icon">✨</div>
             <h3>AI设计分析结果</h3>
-            <button class="btn-reset" (click)="resetAIAnalysis()">重新分析</button>
+            <div class="header-actions">
+              <button class="btn-view-chat" (click)="toggleChatHistory()">💬 查看对话</button>
+              <button class="btn-reset" (click)="resetAIAnalysis()">🔄 重新分析</button>
+            </div>
           </div>
 
           <!-- 🔥 快速总结卡片(设计师关键信息) -->

+ 7 - 0
src/modules/project/pages/project-detail/stages/components/ai-design-analysis/ai-design-analysis.component.scss

@@ -680,6 +680,12 @@
         color: var(--dark-color);
       }
 
+      .header-actions {
+        display: flex;
+        gap: 8px;
+      }
+
+      .btn-view-chat,
       .btn-reset {
         padding: 6px 12px;
         background: var(--light-color);
@@ -688,6 +694,7 @@
         font-size: 12px;
         color: var(--medium-color);
         cursor: pointer;
+        transition: all 0.2s;
 
         &:hover {
           background: var(--light-shade);

+ 100 - 2
src/modules/project/pages/project-detail/stages/components/ai-design-analysis/ai-design-analysis.component.ts

@@ -40,6 +40,7 @@ export class AiDesignAnalysisComponent implements OnInit {
   aiDesignReportConfirmed = false;
   aiDesignDragOver = false;
   exportingWord = false;
+  showChatHistory = false;  // 🔥 控制对话历史显示
   
   // AI Chat State
   aiChatMessages: Array<{
@@ -72,6 +73,9 @@ export class AiDesignAnalysisComponent implements OnInit {
     if (this.projectProducts.length > 0 && !this.aiDesignCurrentSpace) {
       this.aiDesignCurrentSpace = this.projectProducts[0];
     }
+    
+    // 🔥 加载保存的对话历史
+    this.loadChatHistory();
   }
 
   // Space Selection
@@ -245,15 +249,24 @@ export class AiDesignAnalysisComponent implements OnInit {
 
       this.aiDesignAnalysisResult = result;
       
-      // Final update
+      // 🔥 Final update:仅标记完成,不覆盖内容(内容已通过流式输出显示)
       const aiMsgIndex = this.aiChatMessages.findIndex(m => m.id === aiMsgId);
       if (aiMsgIndex !== -1) {
         this.aiChatMessages[aiMsgIndex].isLoading = false;
         this.aiChatMessages[aiMsgIndex].isStreaming = false;
-        this.aiChatMessages[aiMsgIndex].content = result.formattedContent || result.rawContent || '分析完成,请查看下方详细结果。';
+        // 🔥 如果流式输出的内容为空或太短,才使用完整内容
+        if (!this.aiChatMessages[aiMsgIndex].content || this.aiChatMessages[aiMsgIndex].content.length < 100) {
+          console.log('⚠️ 流式输出内容不足,使用完整内容');
+          this.aiChatMessages[aiMsgIndex].content = result.formattedContent || result.rawContent || '分析完成,请查看下方详细结果。';
+        } else {
+          console.log('✅ 保留流式输出的完整内容,长度:', this.aiChatMessages[aiMsgIndex].content.length);
+        }
       }
       
       this.analysisComplete.emit(result);
+      
+      // 🔥 保存对话历史
+      await this.saveChatHistory();
 
     } catch (error) {
       console.error('Analysis failed:', error);
@@ -276,7 +289,89 @@ export class AiDesignAnalysisComponent implements OnInit {
     this.aiDesignUploadedFiles = [];
     this.aiDesignUploadedImages = [];
     this.aiDesignReportConfirmed = false;
+    this.showChatHistory = false;  // 🔥 重置时隐藏对话历史
+    this.cdr.markForCheck();
+  }
+
+  // 🔥 切换对话历史显示
+  toggleChatHistory() {
+    this.showChatHistory = !this.showChatHistory;
+    console.log('💬 [切换对话历史] showChatHistory:', this.showChatHistory);
     this.cdr.markForCheck();
+    
+    // 如果切换到对话视图,滚动到底部
+    if (this.showChatHistory) {
+      setTimeout(() => this.scrollToBottom(), 100);
+    }
+  }
+
+  // 🔥 加载对话历史
+  loadChatHistory() {
+    try {
+      if (!this.project?.id) {
+        console.log('⚠️ [加载对话] 项目id不存在');
+        return;
+      }
+
+      const spaceId = this.aiDesignCurrentSpace?.id;
+      if (!spaceId) {
+        console.log('⚠️ [加载对话] 空间id不存在');
+        return;
+      }
+
+      // 🔥 从 Project.data.aiDesignChats 加载对话
+      const savedChats = this.project.data?.aiDesignChats?.[spaceId];
+      if (savedChats && Array.isArray(savedChats) && savedChats.length > 0) {
+        this.aiChatMessages = savedChats.map((msg: any) => ({
+          ...msg,
+          timestamp: msg.timestamp ? new Date(msg.timestamp) : new Date()
+        }));
+        console.log(`✅ [加载对话] 成功加载 ${this.aiChatMessages.length} 条对话`);
+      } else {
+        console.log('💭 [加载对话] 无历史对话');
+      }
+    } catch (error) {
+      console.error('❌ [加载对话] 失败:', error);
+    }
+  }
+
+  // 🔥 保存对话历史
+  async saveChatHistory() {
+    try {
+      if (!this.project?.id) {
+        console.log('⚠️ [保存对话] 项目id不存在');
+        return;
+      }
+
+      const spaceId = this.aiDesignCurrentSpace?.id;
+      if (!spaceId) {
+        console.log('⚠️ [保存对话] 空间id不存在');
+        return;
+      }
+
+      // 🔥 保存到 Project.data.aiDesignChats
+      if (!this.project.data) {
+        this.project.data = {};
+      }
+      if (!this.project.data.aiDesignChats) {
+        this.project.data.aiDesignChats = {};
+      }
+
+      // 只保存必要的字段,避免数据过大
+      this.project.data.aiDesignChats[spaceId] = this.aiChatMessages.map(msg => ({
+        id: msg.id,
+        role: msg.role,
+        content: msg.content,
+        timestamp: msg.timestamp.toISOString(),
+        images: msg.images
+      }));
+
+      // 🔥 保存到Parse
+      await this.project.save();
+      console.log(`✅ [保存对话] 成功保存 ${this.aiChatMessages.length} 条对话`);
+    } catch (error) {
+      console.error('❌ [保存对话] 失败:', error);
+    }
   }
 
   // Chat Functions
@@ -342,6 +437,9 @@ export class AiDesignAnalysisComponent implements OnInit {
         this.aiChatMessages[aiMsgIndex].isStreaming = false;
         this.aiChatMessages[aiMsgIndex].content = response;
       }
+      
+      // 🔥 保存对话历史
+      await this.saveChatHistory();
     } catch (error) {
       console.error('Chat failed:', error);
       const aiMsgIndex = this.aiChatMessages.findIndex(m => m.id === aiMsgId);