Bladeren bron

Merge branch 'master' of http://git.fmode.cn:3000/nkkj/yss-project

徐福静0235668 9 maanden geleden
bovenliggende
commit
32d61d79c0
24 gewijzigde bestanden met toevoegingen van 6041 en 14639 verwijderingen
  1. 123 295
      src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.html
  2. 508 696
      src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.scss
  3. 45 8
      src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.ts
  4. 9 0
      src/app/pages/team-leader/services/urgent-event.service.ts
  5. 504 0
      src/modules/project/pages/project-detail/stages/components/ai-design-analysis/ai-design-analysis.component.html
  6. 908 0
      src/modules/project/pages/project-detail/stages/components/ai-design-analysis/ai-design-analysis.component.scss
  7. 477 0
      src/modules/project/pages/project-detail/stages/components/ai-design-analysis/ai-design-analysis.component.ts
  8. 453 0
      src/modules/project/pages/project-detail/stages/components/space-requirement-item/space-requirement-item.component.html
  9. 600 0
      src/modules/project/pages/project-detail/stages/components/space-requirement-item/space-requirement-item.component.scss
  10. 232 0
      src/modules/project/pages/project-detail/stages/components/space-requirement-item/space-requirement-item.component.ts
  11. 91 264
      src/modules/project/pages/project-detail/stages/stage-delivery-new.component.html
  12. 372 1997
      src/modules/project/pages/project-detail/stages/stage-delivery-new.component.scss
  13. 16 3
      src/modules/project/pages/project-detail/stages/stage-delivery.component.ts
  14. 26 1577
      src/modules/project/pages/project-detail/stages/stage-requirements.component.html
  15. 36 5197
      src/modules/project/pages/project-detail/stages/stage-requirements.component.scss
  16. 174 4601
      src/modules/project/pages/project-detail/stages/stage-requirements.component.ts
  17. 24 0
      src/modules/project/services/design-analysis-ai.service.ts
  18. 338 0
      src/test/delivery-design-cards.html
  19. 255 0
      src/test/delivery-design-matrix.html
  20. 199 0
      src/test/delivery-design-tasks.html
  21. 186 0
      src/test/sidebar-v2-compact.html
  22. 288 0
      src/test/sidebar-v2-grid.html
  23. 176 0
      src/test/sidebar-v2-list.html
  24. 1 1
      tsconfig.app.json

+ 123 - 295
src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.html

@@ -4,13 +4,15 @@
     <div class="employee-detail-panel" (click)="stopPropagation($event)">
       <!-- 面板头部 -->
       <div class="panel-header">
-        <h3 class="panel-title">
-          <svg class="icon-user" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-            <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
-            <circle cx="12" cy="7" r="4"></circle>
-          </svg>
-          {{ currentEmployeeDetail.name }} 详情
-        </h3>
+        <div class="header-info">
+          <div class="avatar-placeholder">
+            {{ currentEmployeeDetail.name.charAt(0) }}
+          </div>
+          <div class="user-info">
+            <h3 class="user-name">{{ currentEmployeeDetail.name }}</h3>
+            <span class="user-role">设计师</span>
+          </div>
+        </div>
         <button class="btn-close" (click)="onClose()">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <line x1="18" y1="6" x2="6" y2="18"></line>
@@ -21,56 +23,86 @@
 
       <!-- 面板内容 -->
       <div class="panel-content">
-        <!-- 负载概况栏 -->
-        <div class="section workload-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
-              <line x1="9" y1="9" x2="15" y2="9"></line>
-              <line x1="9" y1="15" x2="15" y2="15"></line>
-            </svg>
-            <h4>负载概况</h4>
-          </div>
-          <div class="workload-info">
-            <div class="workload-stat">
-              <span class="stat-label">当前负责项目数:</span>
-              <span class="stat-value" [class]="currentEmployeeDetail.currentProjects >= 3 ? 'high-workload' : 'normal-workload'">
-                {{ currentEmployeeDetail.currentProjects }} 个
+        <!-- 概览区域 (Grid Layout) -->
+        <div class="overview-grid">
+          
+          <!-- 左侧:负载概况 -->
+          <div class="card workload-card">
+            <div class="card-header">
+              <h4>近期负载</h4>
+              <span class="status-badge" [style.background-color]="workloadStatus.color + '20'" [style.color]="workloadStatus.color">
+                {{ workloadStatus.label }}
               </span>
             </div>
-            @if (currentEmployeeDetail.projectData.length > 0) {
-              <div class="project-list">
-                <span class="project-label">核心项目:</span>
-                <div class="project-tags">
-                  @for (project of currentEmployeeDetail.projectData; track project.id) {
-                    <span class="project-tag clickable" 
-                          (click)="onProjectClick(project.id)"
-                          title="点击查看项目详情">
-                      {{ project.name }}
-                      <svg class="icon-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                        <path d="M7 17L17 7M17 7H7M17 7V17"/>
-                      </svg>
-                    </span>
-                  }
-                  @if (currentEmployeeDetail.currentProjects > currentEmployeeDetail.projectData.length) {
-                    <span class="project-tag more">+{{ currentEmployeeDetail.currentProjects - currentEmployeeDetail.projectData.length }}</span>
-                  }
-                </div>
+            <div class="workload-metrics">
+              <div class="metric-big">
+                <span class="number">{{ currentEmployeeDetail.currentProjects }}</span>
+                <span class="label">当前项目</span>
+              </div>
+              <div class="project-preview">
+                <span class="sub-label">核心项目:</span>
+                @if (currentEmployeeDetail.projectData.length > 0) {
+                  <div class="mini-project-list">
+                    @for (project of currentEmployeeDetail.projectData; track project.id) {
+                      <div class="mini-project-item" (click)="onProjectClick(project.id)" title="{{ project.name }}">
+                        <span class="dot"></span>
+                        <span class="name">{{ project.name }}</span>
+                      </div>
+                    }
+                  </div>
+                } @else {
+                  <span class="empty-text">暂无活跃项目</span>
+                }
+              </div>
+            </div>
+          </div>
+
+          <!-- 右侧:能力画像 -->
+          <div class="card capability-card">
+            <div class="card-header">
+              <h4>能力标签</h4>
+              <button class="btn-text" (click)="toggleSurveyDisplay()">详情 &gt;</button>
+            </div>
+            
+            @if (currentEmployeeDetail.surveyCompleted) {
+              <div class="tags-cloud">
+                @for (tag of strengthTags; track tag) {
+                  <span class="skill-tag">{{ tag }}</span>
+                }
+                @if (strengthTags.length === 0) {
+                  <span class="empty-text">暂无标签数据</span>
+                }
+              </div>
+              @if (currentEmployeeDetail.surveyData?.answers; as answers) {
+                 @if (getCapabilitySummary(answers); as summary) {
+                    <div class="mini-stats">
+                      <div class="stat-item">
+                        <span class="label">周承接:</span>
+                        <span class="val">{{ summary.capacity }}</span>
+                      </div>
+                      <div class="stat-item">
+                        <span class="label">接急单:</span>
+                        <span class="val">{{ summary.urgent }}</span>
+                      </div>
+                    </div>
+                 }
+              }
+            } @else {
+              <div class="empty-state">
+                <span>尚未完成能力问卷</span>
+                <button class="btn-refresh" (click)="onRefreshSurvey()" [disabled]="refreshingSurvey">
+                  <svg viewBox="0 0 24 24" width="14" height="14" [class.rotating]="refreshingSurvey"><path d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" fill="currentColor"/></svg>
+                  刷新
+                </button>
               </div>
             }
           </div>
         </div>
 
-        <!-- 负载详细日历 -->
+        <!-- 日历区域 -->
         <div class="section calendar-section">
           <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
-              <line x1="16" y1="2" x2="16" y2="6"></line>
-              <line x1="8" y1="2" x2="8" y2="6"></line>
-              <line x1="3" y1="10" x2="21" y2="10"></line>
-            </svg>
-            <h4>负载详细日历</h4>
+            <h4>项目日历分布</h4>
             <button class="btn-view-designer-calendar" (click)="openDesignerCalendar()" title="查看详细日历">
               📅 详细日历
             </button>
@@ -80,42 +112,23 @@
             <div class="employee-calendar">
               <!-- 月份标题 -->
               <div class="calendar-month-header">
-                <button class="btn-prev-month" 
-                        (click)="onChangeMonth(-1)"
-                        title="上月">
-                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                    <polyline points="15 18 9 12 15 6"></polyline>
-                  </svg>
+                <button class="btn-prev-month" (click)="onChangeMonth(-1)" title="上月">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"></polyline></svg>
                 </button>
-                <span class="month-title">
-                  {{ currentEmployeeDetail.calendarData.currentMonth | date:'yyyy年M月' }}
-                </span>
-                <button class="btn-next-month" 
-                        (click)="onChangeMonth(1)"
-                        title="下月">
-                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                    <polyline points="9 18 15 12 9 6"></polyline>
-                  </svg>
+                <span class="month-title">{{ currentEmployeeDetail.calendarData.currentMonth | date:'yyyy年M月' }}</span>
+                <button class="btn-next-month" (click)="onChangeMonth(1)" title="下月">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"></polyline></svg>
                 </button>
               </div>
-              
-              <!-- 星期标题 -->
+
               <div class="calendar-weekdays">
-                <div class="weekday">日</div>
-                <div class="weekday">一</div>
-                <div class="weekday">二</div>
-                <div class="weekday">三</div>
-                <div class="weekday">四</div>
-                <div class="weekday">五</div>
-                <div class="weekday">六</div>
+                <div class="weekday">日</div><div class="weekday">一</div><div class="weekday">二</div><div class="weekday">三</div><div class="weekday">四</div><div class="weekday">五</div><div class="weekday">六</div>
               </div>
-              
-              <!-- 日历网格 -->
               <div class="calendar-grid">
                 @for (day of currentEmployeeDetail.calendarData.days; track day.date.getTime()) {
                   <div class="calendar-day"
-                       [class.today]="day.isToday"
                        [class.other-month]="!day.isCurrentMonth"
+                       [class.today]="day.isToday"
                        [class.has-projects]="day.projectCount > 0"
                        [class.high-load]="day.projectCount >= 2"
                        [class.clickable]="day.projectCount > 0 && day.isCurrentMonth"
@@ -148,215 +161,38 @@
             </div>
           }
         </div>
-
-        <!-- 请假明细栏 -->
-        <div class="section leave-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
-              <line x1="16" y1="2" x2="16" y2="6"></line>
-              <line x1="8" y1="2" x2="8" y2="6"></line>
-              <line x1="3" y1="10" x2="21" y2="10"></line>
-            </svg>
-            <h4>请假明细(未来7天)</h4>
-          </div>
-          <div class="leave-table">
-            @if (currentEmployeeDetail.leaveRecords.length > 0) {
-              <table>
-                <thead>
-                  <tr>
-                    <th>日期</th>
-                    <th>状态</th>
-                    <th>备注</th>
-                  </tr>
-                </thead>
-                <tbody>
-                  @for (record of currentEmployeeDetail.leaveRecords; track record.id) {
-                    <tr [class]="record.isLeave ? 'leave-day' : 'work-day'">
-                      <td>{{ record.date | date:'M月d日' }}</td>
-                      <td>
-                        <span class="status-badge" [class]="record.isLeave ? 'leave' : 'work'">
-                          {{ record.isLeave ? '请假' : '正常' }}
-                        </span>
-                      </td>
-                      <td>{{ record.isLeave ? getLeaveTypeText(record.leaveType) : '-' }}</td>
-                    </tr>
-                  }
-                </tbody>
-              </table>
-            } @else {
-              <div class="no-leave">
-                <svg class="no-data-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <circle cx="12" cy="12" r="10"></circle>
-                  <path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
-                  <line x1="9" y1="9" x2="9.01" y2="9"></line>
-                  <line x1="15" y1="9" x2="15.01" y2="9"></line>
-                </svg>
-                <p>未来7天无请假安排</p>
-              </div>
-            }
+        
+        <!-- 请假区域 (折叠/简化) -->
+        @if (currentEmployeeDetail.leaveRecords.length > 0) {
+          <div class="leave-simple-alert">
+            <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
+            <span>未来7天有 <strong>{{ currentEmployeeDetail.leaveRecords.length }}</strong> 条请假记录</span>
           </div>
-        </div>
+        }
 
-        <!-- 红色标记说明 -->
-        <div class="section explanation-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <circle cx="12" cy="12" r="10"></circle>
-              <line x1="12" y1="8" x2="12" y2="12"></line>
-              <line x1="12" y1="16" x2="12.01" y2="16"></line>
-            </svg>
-            <h4>红色标记说明</h4>
-          </div>
-          <div class="explanation-content">
-            <p class="explanation-text">{{ currentEmployeeDetail.redMarkExplanation }}</p>
-          </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- 问卷详情侧边栏/弹窗 -->
+  @if (showFullSurvey && currentEmployeeDetail.surveyData) {
+    <div class="survey-drawer-overlay" (click)="toggleSurveyDisplay()">
+      <div class="survey-drawer" (click)="stopPropagation($event)">
+        <div class="drawer-header">
+          <h3>能力问卷详情</h3>
+          <button class="btn-close-text" (click)="toggleSurveyDisplay()">关闭</button>
         </div>
-        
-        <!-- 能力问卷 -->
-        <div class="section survey-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <path d="M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3"/>
-            </svg>
-            <h4>能力问卷</h4>
-            <button 
-              class="btn-refresh-survey" 
-              (click)="onRefreshSurvey()"
-              [disabled]="refreshingSurvey"
-              title="刷新问卷状态">
-              <svg viewBox="0 0 24 24" width="16" height="16" [class.rotating]="refreshingSurvey">
-                <path fill="currentColor" d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
-              </svg>
-            </button>
-          </div>
-          
-          @if (currentEmployeeDetail.surveyCompleted && currentEmployeeDetail.surveyData) {
-            <div class="survey-content">
-              <div class="survey-status completed">
-                <svg viewBox="0 0 24 24" width="20" height="20" fill="#34c759">
-                  <path d="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z"/>
-                </svg>
-                <span>已完成问卷</span>
-                <span class="survey-time">
-                  {{ currentEmployeeDetail.surveyData.createdAt | date:'yyyy-MM-dd HH:mm' }}
-                </span>
+        <div class="drawer-content">
+           @for (answer of currentEmployeeDetail.surveyData.answers; track $index) {
+              <div class="qa-item">
+                <div class="q-text">Q{{$index + 1}}: {{ answer.question }}</div>
+                <div class="a-text">{{ answer.answer || '未填写' }}</div>
               </div>
-              
-              <!-- 能力画像摘要 -->
-              @if (!showFullSurvey) {
-                <div class="capability-summary">
-                  <h5>您的能力画像</h5>
-                  @if (getCapabilitySummary(currentEmployeeDetail.surveyData.answers); as summary) {
-                    <div class="summary-grid">
-                      <div class="summary-item">
-                        <span class="label">擅长风格:</span>
-                        <span class="value">{{ summary.styles }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">擅长空间:</span>
-                        <span class="value">{{ summary.spaces }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">技术优势:</span>
-                        <span class="value">{{ summary.advantages }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">项目难度:</span>
-                        <span class="value">{{ summary.difficulty }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">周承接量:</span>
-                        <span class="value">{{ summary.capacity }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">紧急订单:</span>
-                        <span class="value">
-                          {{ summary.urgent }}
-                          @if (summary.urgentLimit) {
-                            <span class="limit-hint">(每月不超过{{summary.urgentLimit}}次)</span>
-                          }
-                        </span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">进度同步:</span>
-                        <span class="value">{{ summary.feedback }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">沟通方式:</span>
-                        <span class="value">{{ summary.communication }}</span>
-                      </div>
-                    </div>
-                  }
-                  
-                  <button class="btn-view-full" (click)="toggleSurveyDisplay()">
-                    <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
-                      <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
-                    </svg>
-                    查看完整问卷(共 {{ currentEmployeeDetail.surveyData.answers.length }} 道题)
-                  </button>
-                </div>
-              }
-              
-              <!-- 完整问卷答案 -->
-              @if (showFullSurvey) {
-                <div class="survey-answers">
-                  <h5>完整问卷答案(共 {{ currentEmployeeDetail.surveyData.answers.length }} 道题):</h5>
-                  @for (answer of currentEmployeeDetail.surveyData.answers; track $index) {
-                    <div class="answer-item">
-                      <div class="question-text">
-                        <strong>Q{{$index + 1}}:</strong> {{ answer.question }}
-                      </div>
-                      <div class="answer-text">
-                        @if (!answer.answer) {
-                          <span class="answer-tag empty">未填写(选填)</span>
-                        } @else if (answer.type === 'single' || answer.type === 'text' || answer.type === 'textarea' || answer.type === 'number') {
-                          <span class="answer-tag single">{{ answer.answer }}</span>
-                        } @else if (answer.type === 'multiple') {
-                          @if (Array.isArray(answer.answer)) {
-                            @for (opt of answer.answer; track opt) {
-                              <span class="answer-tag multiple">{{ opt }}</span>
-                            }
-                          } @else {
-                            <span class="answer-tag single">{{ answer.answer }}</span>
-                          }
-                        } @else if (answer.type === 'scale') {
-                          <div class="answer-scale">
-                            <div class="scale-bar">
-                              <div class="scale-fill" [style.width.%]="(answer.answer / 10) * 100">
-                                <span>{{ answer.answer }} / 10</span>
-                              </div>
-                            </div>
-                          </div>
-                        } @else {
-                          <span class="answer-tag single">{{ answer.answer }}</span>
-                        }
-                      </div>
-                    </div>
-                  }
-                  
-                  <button class="btn-collapse" (click)="toggleSurveyDisplay()">
-                    <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
-                      <path d="M19 13H5v-2h14v2z"/>
-                    </svg>
-                    收起详情
-                  </button>
-                </div>
-              }
-            </div>
-          } @else {
-            <div class="survey-empty">
-              <svg class="no-data-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                <circle cx="12" cy="12" r="10"></circle>
-                <path d="M8 12h8M12 8v8"/>
-              </svg>
-              <p>该员工尚未完成能力问卷</p>
-            </div>
-          }
+           }
         </div>
       </div>
     </div>
-  </div>
+  }
 }
 
 <!-- 日历项目列表弹窗 -->
@@ -369,7 +205,7 @@
             <path d="M9 11l3 3L22 4"></path>
             <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
           </svg>
-          {{ selectedDate | date:'M月d日' }} 项目
+          {{ selectedDate | date:'M月d日' }} 项目列表
         </h3>
         <button class="btn-close" (click)="closeCalendarProjectList()">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -388,15 +224,11 @@
           @for (project of selectedDayProjects; track project.id) {
             <div class="project-item">
               <div class="project-info" (click)="onProjectClick(project.id); closeCalendarProjectList()">
-                <svg class="project-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
-                  <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
-                </svg>
                 <div class="project-details">
                   <h4 class="project-name">{{ project.name }}</h4>
                   @if (project.deadline) {
                     <p class="project-deadline">
-                      截止日期: {{ project.deadline | date:'yyyy-MM-dd' }}
+                      截止: {{ project.deadline | date:'yyyy-MM-dd' }}
                     </p>
                   }
                 </div>
@@ -408,9 +240,11 @@
                   </svg>
                   <span>进度</span>
                 </button>
-                <svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" (click)="onProjectClick(project.id); closeCalendarProjectList()">
-                  <path d="M5 12h14M12 5l7 7-7 7"/>
-                </svg>
+                <button class="btn-arrow" (click)="onProjectClick(project.id); closeCalendarProjectList()">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                    <path d="M9 18l6-6-6-6"/>
+                  </svg>
+                </button>
               </div>
             </div>
           }
@@ -420,18 +254,12 @@
   </div>
 }
 
-<!-- 设计师详细日历(复用订单分配页组件) -->
+<!-- 设计师详细日历 -->
 @if (showDesignerCalendar) {
   <div class="calendar-project-modal-overlay" (click)="closeDesignerCalendar()">
-    <div class="calendar-project-modal" (click)="stopPropagation($event)">
+    <div class="calendar-project-modal full-modal" (click)="stopPropagation($event)">
       <div class="modal-header">
-        <h3>
-          <svg class="header-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-            <path d="M9 11l3 3L22 4"></path>
-            <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
-          </svg>
-          设计师工作日历
-        </h3>
+        <h3>设计师工作日历</h3>
         <button class="btn-close" (click)="closeDesignerCalendar()">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <line x1="18" y1="6" x2="6" y2="18"></line>

File diff suppressed because it is too large
+ 508 - 696
src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.scss


+ 45 - 8
src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.ts

@@ -81,6 +81,40 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
   showFullSurvey: boolean = false;
   refreshingSurvey: boolean = false;
 
+  // 获取负载状态
+  get workloadStatus(): { label: string; class: string; color: string } {
+    const count = this.currentEmployeeDetail?.currentProjects || 0;
+    if (count >= 3) {
+      return { label: '高负载', class: 'high', color: '#ef4444' }; // red
+    } else if (count >= 1) {
+      return { label: '正常', class: 'normal', color: '#3b82f6' }; // blue
+    }
+    return { label: '空闲', class: 'low', color: '#10b981' }; // green
+  }
+
+  // 获取能力标签
+  get strengthTags(): string[] {
+    if (!this.currentEmployeeDetail?.surveyData?.answers) return [];
+    
+    const summary = this.getCapabilitySummary(this.currentEmployeeDetail.surveyData.answers);
+    const tags: string[] = [];
+    
+    // 解析风格
+    if (summary.styles && summary.styles !== '未填写') {
+      tags.push(...summary.styles.split('、').slice(0, 3));
+    }
+    // 解析空间
+    if (summary.spaces && summary.spaces !== '未填写') {
+      tags.push(...summary.spaces.split('、').slice(0, 2));
+    }
+    // 技术优势
+    if (summary.advantages && summary.advantages !== '未填写') {
+      tags.push(...summary.advantages.split('、').slice(0, 2));
+    }
+    
+    return tags.slice(0, 6); // 最多显示6个标签
+  }
+
   // 获取当前显示的 employeeDetail(优先使用 Input,否则使用内部生成的)
   get currentEmployeeDetail(): EmployeeDetail | null {
     return this.employeeDetail || this.internalEmployeeDetail;
@@ -137,10 +171,13 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
     if (!this.employeeName) return;
 
     const employeeName = this.employeeName;
-    const currentProjects = this.projects.length;
     
-    // 保存完整的项目数据(最多显示3个)
-    const projectData = this.projects.slice(0, 3).map(p => ({
+    // 过滤出当前活跃的项目(非已完成/已交付)用于显示"当前项目数"
+    const activeProjects = this.projects.filter(p => p.status !== '已完成' && p.status !== '已交付');
+    const currentProjects = activeProjects.length;
+    
+    // 保存完整的项目数据(最多显示3个活跃项目)
+    const projectData = activeProjects.slice(0, 3).map(p => ({
       id: p.id,
       name: p.name
     }));
@@ -162,7 +199,7 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
     // 生成红色标记说明
     const redMarkExplanation = this.generateRedMarkExplanation(employeeName, employeeLeaveRecords, currentProjects);
     
-    // 生成日历数据
+    // 生成日历数据 (传入所有项目以显示历史负载)
     const calendarData = this.generateEmployeeCalendar(employeeName, this.projects);
     
     // 构建基础对象
@@ -257,10 +294,10 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
       
       // 找出该日期相关的项目(项目进行中且在当天范围内)
       const dayProjects = employeeProjects.filter(p => {
-        // 1. 过滤已完成/已交付的项目
-        if (p.status === '已完成' || p.status === '已交付') {
-          return false;
-        }
+        // 移除对已完成项目的过滤,以便在日历中显示历史负载
+        // if (p.status === '已完成' || p.status === '已交付') {
+        //   return false;
+        // }
 
         const projectData = p.data || {};
 

+ 9 - 0
src/app/pages/team-leader/services/urgent-event.service.ts

@@ -167,6 +167,13 @@ export class UrgentEventService {
             rendering: '渲染',
             postProcessing: '后期'
           };
+
+          const phaseTypeMap: Record<string, 'modeling' | 'soft_fitting' | 'rendering' | 'post_processing'> = {
+            modeling: 'modeling',
+            softDecor: 'soft_fitting',
+            rendering: 'rendering',
+            postProcessing: 'post_processing'
+          };
           
           Object.entries(project.phaseDeadlines).forEach(([key, phaseInfo]: [string, any]) => {
             if (phaseInfo && phaseInfo.deadline) {
@@ -178,6 +185,7 @@ export class UrgentEventService {
               // 如果阶段已经到期或即将到期(1天内),且状态不是已完成
               if (daysDiff <= 1 && phaseInfo.status !== 'completed') {
                 const phaseName = phaseMap[key as keyof typeof phaseMap] || key;
+                const phaseType = phaseTypeMap[key];
                 
                 // 获取该阶段的完成率
                 const summary = project.spaceDeliverableSummary;
@@ -196,6 +204,7 @@ export class UrgentEventService {
                   description: `项目「${project.projectName}」的${phaseName}阶段截止时间已${daysDiff < 0 ? '逾期' : '临近'}(完成率 ${completionRate}%)${descSuffix}`,
                   eventType: 'phase_deadline',
                   phaseName,
+                  phaseType,
                   deadline,
                   projectId: project.projectId,
                   projectName: project.projectName,

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

@@ -0,0 +1,504 @@
+<div class="ai-design-analysis-section">
+  <div class="card ai-analysis-card">
+    <div class="card-header">
+      <h3 class="card-title">
+        <span class="icon">✨</span>
+        AI设计分析
+      </h3>
+      <p class="card-subtitle">上传参考图片、CAD或PDF,AI将进行专业的灯光材质细节分析</p>
+    </div>
+    
+    <div class="card-content">
+      <!-- 空间选择器 -->
+      <div class="space-selector-inline">
+        <label class="selector-label">选择空间:</label>
+        <div class="space-tabs-inline">
+          @for (space of projectProducts; track space.id) {
+            <button
+              class="space-tab-btn"
+              [class.active]="aiDesignCurrentSpace?.id === space.id"
+              (click)="selectAISpace(space)">
+              {{ getSpaceDisplayName(space) }}
+            </button>
+          }
+        </div>
+      </div>
+
+      <!-- 步骤1: 上传图片和描述 -->
+      @if (!aiDesignAnalysisResult) {
+        <div class="upload-section">
+          <!-- 已上传的文件 -->
+          @if (aiDesignUploadedFiles.length > 0) {
+            <div class="uploaded-files">
+              @for (file of aiDesignUploadedFiles; track file.url; let i = $index) {
+                <div class="file-item" [class.is-image]="file.isImage">
+                  @if (file.isImage) {
+                    <!-- 图片预览 -->
+                    <img [src]="file.url" [alt]="file.name">
+                  } @else {
+                    <!-- 文件图标 -->
+                    <div class="file-icon" [class.pdf]="file.extension === 'pdf'" [class.cad]="file.extension === 'dwg' || file.extension === 'dxf'">
+                      @if (file.extension === 'pdf') {
+                        <span class="icon-text">📄</span>
+                        <span class="file-ext">PDF</span>
+                      } @else if (file.extension === 'dwg' || file.extension === 'dxf') {
+                        <span class="icon-text">📐</span>
+                        <span class="file-ext">{{ file.extension?.toUpperCase() }}</span>
+                      } @else {
+                        <span class="icon-text">📄</span>
+                        <span class="file-ext">{{ file.extension?.toUpperCase() }}</span>
+                      }
+                    </div>
+                  }
+                  <div class="file-info">
+                    <div class="file-name">{{ file.name }}</div>
+                    <div class="file-size">{{ formatFileSize(file.size) }}</div>
+                  </div>
+                  <button class="remove-btn" (click)="removeAIDialogImage(i)">×</button>
+                </div>
+              }
+              @if (aiDesignUploadedFiles.length < 3) {
+                <div class="add-more" (click)="triggerAIDialogFileInput()">
+                  <div class="add-icon">+</div>
+                  <div class="add-text">继续添加</div>
+                </div>
+              }
+            </div>
+            
+            <!-- 开始分析按钮(只在有文件且无对话时显示) -->
+            @if (aiChatMessages.length === 0 && !aiDesignAnalyzing) {
+              <div class="start-analysis-wrapper">
+                <button class="btn-start-analysis" (click)="startAIDesignAnalysis()">
+                  <span class="icon-text">📊</span>
+                  <span>开始AI分析</span>
+                  <div class="btn-hint">点击进行专业的设计分析</div>
+                </button>
+              </div>
+            }
+          } @else {
+            <!-- 上传卡片 -->
+            <div 
+              class="upload-card" 
+              (click)="triggerAIDialogFileInput()"
+              (drop)="onAIFileDrop($event)"
+              (dragover)="onAIFileDragOver($event)"
+              (dragleave)="onAIFileDragLeave($event)"
+              [class.drag-over]="aiDesignDragOver">
+              <div class="upload-icon">📸</div>
+              <h3>上传参考文件</h3>
+              <p class="upload-desc">支持图片、CAD、PDF等多种格式</p>
+              <p class="upload-hint">
+                <span class="hint-text">点击上传或拖拽文件到此处</span>
+                <span class="hint-formats">支持: JPG, PNG, PDF, DWG, DXF (最多3个文件)</span>
+              </p>
+            </div>
+          }
+
+          <!-- AI对话区域 -->
+          <div class="ai-chat-container">
+            
+            <!-- 对话历史显示区 -->
+            <div class="chat-messages-wrapper" #chatMessagesWrapper>
+              @if (aiChatMessages.length === 0) {
+                <!-- 欢迎提示 -->
+                <div class="chat-welcome">
+                  <div class="welcome-icon">
+                    <span class="icon-text">✨</span>
+                  </div>
+                  <h3>AI设计助手</h3>
+                  <p>上传图片后,告诉我你的设计需求,我会帮你深入分析</p>
+                  <div class="quick-prompts">
+                    <button class="prompt-chip" (click)="useQuickPrompt('分析整体设计风格和色彩搭配')">
+                      <span class="icon-text">🎨</span>
+                      <span>分析设计风格</span>
+                    </button>
+                    <button class="prompt-chip" (click)="useQuickPrompt('重点分析灯光设计和照明方案')">
+                      <span class="icon-text">💡</span>
+                      <span>灯光设计</span>
+                    </button>
+                    <button class="prompt-chip" (click)="useQuickPrompt('分析材质选择和质感搭配')">
+                      <span class="icon-text">📦</span>
+                      <span>材质分析</span>
+                    </button>
+                    <button class="prompt-chip" (click)="useQuickPrompt('提供空间优化建议')">
+                      <span class="icon-text">🔄</span>
+                      <span>空间优化</span>
+                    </button>
+                  </div>
+                </div>
+              } @else {
+                <!-- 对话消息列表 -->
+                <div class="chat-messages-list">
+                  @for (message of aiChatMessages; track message.id) {
+                    <div class="chat-message" [class.user-message]="message.role === 'user'" [class.ai-message]="message.role === 'assistant'">
+                      
+                      <!-- 用户消息 -->
+                      @if (message.role === 'user') {
+                        <div class="message-content user-content">
+                          <div class="message-bubble">
+                            <div class="message-text">{{ message.content }}</div>
+                            @if (message.images && message.images.length > 0) {
+                              <div class="message-images">
+                                @for (image of message.images; track image) {
+                                  <img [src]="image" alt="参考图">
+                                }
+                              </div>
+                            }
+                            <div class="message-time">{{ message.timestamp | date:'HH:mm' }}</div>
+                          </div>
+                          <div class="message-avatar user-avatar">
+                            <span class="icon-text">👤</span>
+                          </div>
+                        </div>
+                      }
+                      
+                      <!-- AI消息 -->
+                      @if (message.role === 'assistant') {
+                        <div class="message-content ai-content">
+                          <div class="message-avatar ai-avatar">
+                            <span class="icon-text">✨</span>
+                          </div>
+                          <div class="message-bubble">
+                            @if (message.isLoading) {
+                              <div class="message-loading">
+                                <div class="loading-dots">
+                                  <span></span>
+                                  <span></span>
+                                  <span></span>
+                                </div>
+                                <span class="loading-text">AI正在思考...</span>
+                              </div>
+                            } @else {
+                              <div class="message-text" [innerHTML]="formatMessageContent(message.content)"></div>
+                              <div class="message-actions">
+                                <button class="action-btn" (click)="copyMessage(message.content)" title="复制">
+                                  <span class="icon-text">📋</span>
+                                </button>
+                                <button class="action-btn" (click)="regenerateMessage(message)" title="重新生成">
+                                  <span class="icon-text">🔄</span>
+                                </button>
+                                <button class="action-btn" (click)="likeMessage(message)" [class.liked]="message.liked" title="有帮助">
+                                  <span class="icon-text">👍</span>
+                                </button>
+                                <button class="action-btn" (click)="dislikeMessage(message)" [class.disliked]="message.disliked" title="无帮助">
+                                  <span class="icon-text">👎</span>
+                                </button>
+                              </div>
+                              <div class="message-time">{{ message.timestamp | date:'HH:mm' }}</div>
+                            }
+                          </div>
+                        </div>
+                      }
+                    </div>
+                  }
+                </div>
+              }
+            </div>
+
+            <!-- 输入区域 -->
+            <div class="chat-input-container">
+              <div class="input-wrapper">
+                <textarea
+                  class="chat-input"
+                  [(ngModel)]="aiChatInput"
+                  placeholder="描述你的需求或提出修改意见..."
+                  rows="1"
+                  [disabled]="aiDesignAnalyzing"
+                  (input)="onChatInputChange($event)"
+                  (keydown.enter)="onChatInputEnter($event)"
+                  #chatInput></textarea>
+                
+                <div class="input-actions">
+                  <!-- 左侧按钮组 -->
+                  <div class="input-actions-left">
+                    <button class="action-btn" title="上传附件" [disabled]="aiDesignAnalyzing" (click)="openAttachmentDialog()">
+                      <span class="icon-text">📷</span>
+                    </button>
+                    <button class="action-btn" title="语音输入" [disabled]="aiDesignAnalyzing" (click)="startVoiceInput()">
+                      <span class="icon-text">🎤</span>
+                    </button>
+                  </div>
+                  
+                  <!-- 右侧发送按钮 -->
+                  <button 
+                    class="send-btn" 
+                    [disabled]="aiDesignAnalyzing || !aiChatInput?.trim()"
+                    (click)="sendChatMessage()">
+                    @if (aiDesignAnalyzing) {
+                      <span class="btn-loading">
+                        <span class="spinner"></span>
+                      </span>
+                    } @else {
+                      <span class="icon-text">✉️</span>
+                    }
+                  </button>
+                </div>
+              </div>
+              
+              <!-- 快捷操作栏 -->
+              <div class="quick-actions">
+                <button class="quick-action-btn" (click)="clearChat()" [disabled]="aiChatMessages.length === 0">
+                  <span class="icon-text">🗑️</span>
+                  <span>清空对话</span>
+                </button>
+                <button class="quick-action-btn" (click)="exportChat()" [disabled]="aiChatMessages.length === 0">
+                  <span class="icon-text">💾</span>
+                  <span>导出对话</span>
+                </button>
+                <button class="quick-action-btn" (click)="confirmCurrentAnalysis()" [disabled]="aiChatMessages.length === 0">
+                  <span class="icon-text">✅</span>
+                  <span>确认分析结果</span>
+                </button>
+              </div>
+            </div>
+          </div>
+        </div>
+      }
+
+      <!-- 步骤2: 显示分析结果 -->
+      @if (aiDesignAnalysisResult && !aiDesignReport) {
+        <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>
+
+          <!-- 🔥 快速总结卡片(设计师关键信息) -->
+          @if (aiDesignAnalysisResult.structuredData?.quickSummary) {
+            <div class="result-card quick-summary-card">
+              <div class="card-title">
+                <span class="title-icon">⚡</span>
+                <h4>图片分析总结</h4>
+              </div>
+              <div class="card-content quick-summary-content">
+                <div class="summary-item">
+                  <div class="summary-label">
+                    <span class="label-icon">🎨</span>
+                    <span class="label-text">色彩基调</span>
+                  </div>
+                  <div class="summary-value color-tone">
+                    {{ aiDesignAnalysisResult.structuredData.quickSummary.colorTone }}
+                  </div>
+                </div>
+                <div class="summary-item">
+                  <div class="summary-label">
+                    <span class="label-icon">🪵</span>
+                    <span class="label-text">主要材质</span>
+                  </div>
+                  <div class="summary-value materials">
+                    {{ aiDesignAnalysisResult.structuredData.quickSummary.mainMaterials }}
+                  </div>
+                </div>
+                <div class="summary-item">
+                  <div class="summary-label">
+                    <span class="label-icon">✨</span>
+                    <span class="label-text">整体氛围</span>
+                  </div>
+                  <div class="summary-value atmosphere">
+                    {{ aiDesignAnalysisResult.structuredData.quickSummary.atmosphere }}
+                  </div>
+                </div>
+              </div>
+            </div>
+          }
+
+          <!-- 简洁摘要卡片 -->
+          @if (getAISummary()) {
+            <div class="result-card summary-card">
+              <div class="card-title">
+                <span class="title-icon">📋</span>
+                <h4>设计概要</h4>
+              </div>
+              <div class="card-content">
+                <p class="summary-text">{{ getAISummary() }}</p>
+              </div>
+            </div>
+          }
+
+          <!-- 完整分析内容 -->
+          @if (aiDesignAnalysisResult.formattedContent || aiDesignAnalysisResult.rawContent) {
+            <div class="result-card full-analysis-card">
+              <div class="card-title">
+                <span class="title-icon">📊</span>
+                <h4>详细分析</h4>
+              </div>
+              <div class="card-content analysis-content">
+                <pre class="analysis-text">{{ aiDesignAnalysisResult.formattedContent || aiDesignAnalysisResult.rawContent }}</pre>
+              </div>
+            </div>
+          }
+
+          <!-- 按维度查看(可选) -->
+          @if (aiDesignAnalysisResult.structuredData) {
+            <div class="result-card dimensions-card">
+              <div class="card-title">
+                <span class="title-icon">🔍</span>
+                <h4>分维度查看</h4>
+              </div>
+              <div class="card-content">
+                <div class="dimensions-grid">
+                  <!-- 空间定位 -->
+                  @if (aiDesignAnalysisResult.structuredData.spacePositioning) {
+                    <div class="dimension-item">
+                      <div class="dimension-header" (click)="toggleDimension('spacePositioning')">
+                        <span class="dimension-icon">🏠</span>
+                        <span class="dimension-title">空间定位与场景属性</span>
+                        <span class="toggle-icon">{{ expandedDimensions.has('spacePositioning') ? '▼' : '▶' }}</span>
+                      </div>
+                      @if (expandedDimensions.has('spacePositioning')) {
+                        <div class="dimension-content">
+                          <p>{{ aiDesignAnalysisResult.structuredData.spacePositioning }}</p>
+                        </div>
+                      }
+                    </div>
+                  }
+
+                  <!-- 色调分析 -->
+                  @if (aiDesignAnalysisResult.structuredData.colorAnalysis) {
+                    <div class="dimension-item">
+                      <div class="dimension-header" (click)="toggleDimension('colorAnalysis')">
+                        <span class="dimension-icon">🎨</span>
+                        <span class="dimension-title">色调精准分析</span>
+                        <span class="toggle-icon">{{ expandedDimensions.has('colorAnalysis') ? '▼' : '▶' }}</span>
+                      </div>
+                      @if (expandedDimensions.has('colorAnalysis')) {
+                        <div class="dimension-content">
+                          <p>{{ aiDesignAnalysisResult.structuredData.colorAnalysis }}</p>
+                        </div>
+                      }
+                    </div>
+                  }
+
+                  <!-- 材质解析 -->
+                  @if (aiDesignAnalysisResult.structuredData.materials) {
+                    <div class="dimension-item">
+                      <div class="dimension-header" (click)="toggleDimension('materials')">
+                        <span class="dimension-icon">🪨</span>
+                        <span class="dimension-title">材质应用解析</span>
+                        <span class="toggle-icon">{{ expandedDimensions.has('materials') ? '▼' : '▶' }}</span>
+                      </div>
+                      @if (expandedDimensions.has('materials')) {
+                        <div class="dimension-content">
+                          <p>{{ aiDesignAnalysisResult.structuredData.materials }}</p>
+                        </div>
+                      }
+                    </div>
+                  }
+
+                  <!-- 风格氛围 -->
+                  @if (aiDesignAnalysisResult.structuredData.style) {
+                    <div class="dimension-item">
+                      <div class="dimension-header" (click)="toggleDimension('style')">
+                        <span class="dimension-icon">✨</span>
+                        <span class="dimension-title">风格与氛围营造</span>
+                        <span class="toggle-icon">{{ expandedDimensions.has('style') ? '▼' : '▶' }}</span>
+                      </div>
+                      @if (expandedDimensions.has('style')) {
+                        <div class="dimension-content">
+                          <p>{{ aiDesignAnalysisResult.structuredData.style }}</p>
+                        </div>
+                      }
+                    </div>
+                  }
+
+                  <!-- 优化建议 -->
+                  @if (aiDesignAnalysisResult.structuredData.suggestions) {
+                    <div class="dimension-item">
+                      <div class="dimension-header" (click)="toggleDimension('suggestions')">
+                        <span class="dimension-icon">💡</span>
+                        <span class="dimension-title">专业优化建议</span>
+                        <span class="toggle-icon">{{ expandedDimensions.has('suggestions') ? '▼' : '▶' }}</span>
+                      </div>
+                      @if (expandedDimensions.has('suggestions')) {
+                        <div class="dimension-content">
+                          <p>{{ aiDesignAnalysisResult.structuredData.suggestions }}</p>
+                        </div>
+                      }
+                    </div>
+                  }
+                </div>
+              </div>
+            </div>
+          }
+
+          <!-- 生成客服标注按钮 -->
+          <div class="action-section">
+            <button
+              class="btn btn-outline btn-generate"
+              (click)="generateServiceNotes()">
+              <span class="icon-text">📄</span>
+              <span>生成客服标注</span>
+            </button>
+            <button
+              class="btn btn-primary btn-generate"
+              (click)="generateClientReport()"
+              [disabled]="aiDesignGeneratingReport">
+              @if (aiDesignGeneratingReport) {
+                <span class="loading-spinner"></span>
+                <span>生成报告中...</span>
+              } @else {
+                <span class="icon-text">📄</span>
+                <span>生成客户报告</span>
+              }
+            </button>
+          </div>
+        </div>
+      }
+
+      <!-- 步骤3: 显示客户报告 -->
+      @if (aiDesignReport) {
+        <div class="report-section">
+          <div class="report-header">
+            <div class="header-icon">📋</div>
+            <h3>设计分析报告</h3>
+            <button class="btn-reset" (click)="resetAIAnalysis()">重新分析</button>
+          </div>
+
+          <div class="report-content markdown-body">
+            <pre class="report-text">{{ aiDesignReport }}</pre>
+          </div>
+
+          <!-- 确认按钮 - 优化企业微信端布局 -->
+          @if (!aiDesignReportConfirmed) {
+            <div class="action-section report-actions">
+              <button
+                class="btn btn-outline btn-reanalyze"
+                (click)="resetAIAnalysis()">
+                <span class="icon-text">🔄</span>
+                <span>重新分析</span>
+              </button>
+              <button
+                class="btn btn-info btn-export"
+                (click)="exportReportToWord()"
+                [disabled]="exportingWord">
+                @if (exportingWord) {
+                  <span class="loading-spinner"></span>
+                  <span>导出中...</span>
+                } @else {
+                  <span class="icon-text">📥</span>
+                  <span>导出Word</span>
+                }
+              </button>
+              <button
+                class="btn btn-success btn-confirm"
+                (click)="confirmDesignReport()">
+                <span class="icon-text">✅</span>
+                <span>确认保存</span>
+              </button>
+            </div>
+          }
+        </div>
+      }
+
+      <!-- 隐藏的文件input -->
+      <input 
+        type="file" 
+        id="aiDesignFileInput" 
+        (change)="handleAIFileSelect($event)" 
+        accept="image/*,.pdf,.dwg,.dxf" 
+        multiple 
+        style="display: none;">
+    </div>
+  </div>
+</div>

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

@@ -0,0 +1,908 @@
+// AI Design Analysis Component SCSS
+
+// CSS 变量定义
+:host {
+  --primary-color: #3880ff;
+  --primary-rgb: 56, 128, 255;
+  --secondary-color: #0cd1e8;
+  --tertiary-color: #7044ff;
+  --success-color: #2dd36f;
+  --success-rgb: 45, 211, 111;
+  --warning-color: #ffc409;
+  --danger-color: #eb445a;
+  --dark-color: #222428;
+  --medium-color: #92949c;
+  --light-color: #f4f5f8;
+  --light-shade: #d7d8da;
+  --white: #ffffff;
+  
+  display: block;
+}
+
+// 通用卡片样式
+.card {
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  margin-bottom: 16px;
+  overflow: hidden;
+
+  .card-header {
+    padding: 16px;
+    border-bottom: 1px solid var(--light-shade);
+    
+    .card-title {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      margin: 0 0 4px;
+      font-size: 16px;
+      font-weight: 600;
+      color: var(--dark-color);
+
+      .icon {
+        font-size: 20px;
+        color: var(--primary-color);
+      }
+    }
+
+    .card-subtitle {
+      color: var(--medium-color);
+      font-size: 12px;
+      margin: 0;
+    }
+  }
+
+  .card-content {
+    padding: 16px;
+  }
+}
+
+// Spinner
+.spinner-small {
+  width: 20px;
+  height: 20px;
+  position: relative;
+  display: inline-block;
+
+  .spinner-circle {
+    width: 100%;
+    height: 100%;
+    border: 3px solid rgba(255, 255, 255, 0.3);
+    border-top-color: white;
+    border-radius: 50%;
+    animation: spin 0.8s linear infinite;
+  }
+}
+
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+
+// AI Design Analysis Section
+.ai-design-analysis-section {
+  margin-bottom: 24px;
+
+  .ai-analysis-card {
+    border: 1px solid rgba(var(--primary-rgb), 0.2);
+    box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.1);
+  }
+
+  .space-selector-inline {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    margin-bottom: 16px;
+    
+    .selector-label {
+      font-size: 13px;
+      color: var(--medium-color);
+      white-space: nowrap;
+    }
+
+    .space-tabs-inline {
+      display: flex;
+      gap: 8px;
+      overflow-x: auto;
+      padding-bottom: 4px;
+
+      .space-tab-btn {
+        padding: 6px 12px;
+        border-radius: 16px;
+        border: 1px solid var(--light-shade);
+        background: white;
+        font-size: 12px;
+        color: var(--medium-color);
+        cursor: pointer;
+        white-space: nowrap;
+        transition: all 0.2s;
+
+        &.active {
+          background: var(--primary-color);
+          color: white;
+          border-color: var(--primary-color);
+        }
+
+        &:hover:not(.active) {
+          border-color: var(--primary-color);
+          color: var(--primary-color);
+        }
+      }
+    }
+  }
+
+  .upload-section {
+    .uploaded-files {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 12px;
+      margin-bottom: 16px;
+
+      .file-item {
+        position: relative;
+        width: 100px;
+        height: 100px;
+        border-radius: 8px;
+        border: 1px solid var(--light-shade);
+        overflow: hidden;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        background: var(--light-color);
+
+        &.is-image {
+          border: none;
+          
+          img {
+            width: 100%;
+            height: 100%;
+            object-fit: cover;
+          }
+          
+          .file-info {
+            display: none;
+          }
+        }
+
+        .file-icon {
+          font-size: 24px;
+          margin-bottom: 4px;
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          
+          &.pdf { color: #eb445a; }
+          &.cad { color: #3880ff; }
+          
+          .file-ext {
+            font-size: 10px;
+            font-weight: 600;
+            margin-top: 2px;
+          }
+        }
+
+        .file-info {
+          text-align: center;
+          padding: 0 4px;
+          width: 100%;
+
+          .file-name {
+            font-size: 10px;
+            color: var(--dark-color);
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+          }
+          
+          .file-size {
+            font-size: 9px;
+            color: var(--medium-color);
+          }
+        }
+
+        .remove-btn {
+          position: absolute;
+          top: 4px;
+          right: 4px;
+          width: 20px;
+          height: 20px;
+          border-radius: 50%;
+          background: rgba(0, 0, 0, 0.5);
+          color: white;
+          border: none;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-size: 14px;
+          cursor: pointer;
+          opacity: 0;
+          transition: opacity 0.2s;
+        }
+
+        &:hover .remove-btn {
+          opacity: 1;
+        }
+      }
+
+      .add-more {
+        width: 100px;
+        height: 100px;
+        border-radius: 8px;
+        border: 1px dashed var(--medium-color);
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        cursor: pointer;
+        color: var(--medium-color);
+        transition: all 0.2s;
+
+        .add-icon {
+          font-size: 24px;
+          margin-bottom: 4px;
+        }
+        
+        .add-text {
+          font-size: 12px;
+        }
+
+        &:hover {
+          border-color: var(--primary-color);
+          color: var(--primary-color);
+          background: rgba(var(--primary-rgb), 0.05);
+        }
+      }
+    }
+
+    .start-analysis-wrapper {
+      display: flex;
+      justify-content: center;
+      margin-bottom: 24px;
+
+      .btn-start-analysis {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        padding: 12px 40px;
+        background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
+        color: white;
+        border: none;
+        border-radius: 24px;
+        box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.3);
+        cursor: pointer;
+        transition: transform 0.2s;
+
+        &:hover {
+          transform: translateY(-2px);
+          box-shadow: 0 6px 16px rgba(var(--primary-rgb), 0.4);
+        }
+
+        .icon-text {
+          font-size: 24px;
+          margin-bottom: 4px;
+        }
+        
+        span:not(.icon-text) {
+          font-size: 16px;
+          font-weight: 600;
+        }
+
+        .btn-hint {
+          font-size: 11px;
+          opacity: 0.8;
+          margin-top: 2px;
+        }
+      }
+    }
+
+    .upload-card {
+      border: 2px dashed var(--light-shade);
+      border-radius: 12px;
+      padding: 32px;
+      text-align: center;
+      cursor: pointer;
+      transition: all 0.3s;
+      margin-bottom: 24px;
+
+      &:hover, &.drag-over {
+        border-color: var(--primary-color);
+        background: rgba(var(--primary-rgb), 0.05);
+      }
+
+      .upload-icon {
+        font-size: 48px;
+        margin-bottom: 16px;
+      }
+
+      h3 {
+        margin: 0 0 8px;
+        font-size: 16px;
+        color: var(--dark-color);
+      }
+
+      .upload-desc {
+        margin: 0 0 16px;
+        font-size: 14px;
+        color: var(--medium-color);
+      }
+
+      .upload-hint {
+        display: flex;
+        flex-direction: column;
+        gap: 4px;
+        font-size: 12px;
+        color: var(--medium-color);
+        
+        .hint-text { color: var(--primary-color); }
+        .hint-formats { font-size: 11px; opacity: 0.8; }
+      }
+    }
+
+    .ai-chat-container {
+      background: var(--light-color);
+      border-radius: 12px;
+      overflow: hidden;
+      display: flex;
+      flex-direction: column;
+      height: 500px;
+
+      .chat-messages-wrapper {
+        flex: 1;
+        overflow-y: auto;
+        padding: 16px;
+        
+        .chat-welcome {
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+          height: 100%;
+          text-align: center;
+          color: var(--medium-color);
+
+          .welcome-icon {
+            font-size: 48px;
+            margin-bottom: 16px;
+            background: white;
+            width: 80px;
+            height: 80px;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+          }
+
+          h3 {
+            color: var(--dark-color);
+            margin: 0 0 8px;
+          }
+
+          p {
+            font-size: 14px;
+            margin: 0 0 24px;
+            max-width: 280px;
+          }
+
+          .quick-prompts {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 8px;
+            justify-content: center;
+            max-width: 400px;
+
+            .prompt-chip {
+              display: flex;
+              align-items: center;
+              gap: 6px;
+              padding: 8px 16px;
+              background: white;
+              border: 1px solid var(--light-shade);
+              border-radius: 20px;
+              font-size: 12px;
+              color: var(--dark-color);
+              cursor: pointer;
+              transition: all 0.2s;
+
+              &:hover {
+                border-color: var(--primary-color);
+                color: var(--primary-color);
+                transform: translateY(-2px);
+                box-shadow: 0 2px 8px rgba(0,0,0,0.05);
+              }
+            }
+          }
+        }
+
+        .chat-messages-list {
+          display: flex;
+          flex-direction: column;
+          gap: 16px;
+
+          .chat-message {
+            display: flex;
+            gap: 12px;
+            max-width: 85%;
+
+            &.user-message {
+              align-self: flex-end;
+              flex-direction: row-reverse;
+              
+              .message-bubble {
+                background: var(--primary-color);
+                color: white;
+                border-radius: 16px 16px 4px 16px;
+
+                .message-time { color: rgba(255,255,255,0.7); }
+              }
+            }
+
+            &.ai-message {
+              align-self: flex-start;
+              
+              .message-bubble {
+                background: white;
+                border: 1px solid var(--light-shade);
+                border-radius: 16px 16px 16px 4px;
+                color: var(--dark-color);
+              }
+            }
+
+            .message-avatar {
+              width: 32px;
+              height: 32px;
+              border-radius: 50%;
+              background: white;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              font-size: 18px;
+              box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+              flex-shrink: 0;
+
+              &.ai-avatar { color: var(--primary-color); }
+              &.user-avatar { color: var(--medium-color); }
+            }
+
+            .message-bubble {
+              padding: 12px 16px;
+              position: relative;
+              box-shadow: 0 2px 4px rgba(0,0,0,0.05);
+
+              .message-text {
+                font-size: 14px;
+                line-height: 1.5;
+                white-space: pre-wrap;
+              }
+
+              .message-images {
+                display: flex;
+                gap: 8px;
+                margin-top: 8px;
+                flex-wrap: wrap;
+
+                img {
+                  width: 60px;
+                  height: 60px;
+                  border-radius: 4px;
+                  object-fit: cover;
+                  border: 1px solid rgba(255,255,255,0.2);
+                }
+              }
+
+              .message-loading {
+                display: flex;
+                align-items: center;
+                gap: 8px;
+                padding: 4px 0;
+
+                .loading-dots {
+                  display: flex;
+                  gap: 4px;
+                  span {
+                    width: 6px;
+                    height: 6px;
+                    background: var(--primary-color);
+                    border-radius: 50%;
+                    animation: bounce 1.4s infinite ease-in-out both;
+                    
+                    &:nth-child(1) { animation-delay: -0.32s; }
+                    &:nth-child(2) { animation-delay: -0.16s; }
+                  }
+                }
+                
+                .loading-text {
+                  font-size: 12px;
+                  color: var(--medium-color);
+                }
+              }
+
+              .message-actions {
+                display: flex;
+                gap: 8px;
+                margin-top: 8px;
+                padding-top: 8px;
+                border-top: 1px solid rgba(0,0,0,0.05);
+
+                .action-btn {
+                  background: none;
+                  border: none;
+                  padding: 4px;
+                  cursor: pointer;
+                  opacity: 0.5;
+                  transition: opacity 0.2s;
+                  font-size: 14px;
+
+                  &:hover { opacity: 1; }
+                  &.liked, &.disliked { opacity: 1; color: var(--primary-color); }
+                }
+              }
+
+              .message-time {
+                font-size: 10px;
+                margin-top: 4px;
+                text-align: right;
+                color: var(--medium-color);
+              }
+            }
+          }
+        }
+      }
+
+      .chat-input-container {
+        padding: 16px;
+        background: white;
+        border-top: 1px solid var(--light-shade);
+
+        .input-wrapper {
+          display: flex;
+          gap: 12px;
+          align-items: flex-end;
+          margin-bottom: 12px;
+          
+          .chat-input {
+            flex: 1;
+            border: 1px solid var(--light-shade);
+            border-radius: 20px;
+            padding: 12px 16px;
+            font-size: 14px;
+            line-height: 1.5;
+            resize: none;
+            max-height: 100px;
+            min-height: 44px;
+
+            &:focus {
+              outline: none;
+              border-color: var(--primary-color);
+              box-shadow: 0 0 0 2px rgba(var(--primary-rgb), 0.1);
+            }
+          }
+
+          .input-actions {
+            display: flex;
+            gap: 8px;
+            
+            .input-actions-left {
+              display: flex;
+              gap: 4px;
+            }
+
+            .action-btn, .send-btn {
+              width: 40px;
+              height: 40px;
+              border-radius: 50%;
+              border: none;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              cursor: pointer;
+              transition: all 0.2s;
+            }
+
+            .action-btn {
+              background: var(--light-color);
+              color: var(--medium-color);
+              font-size: 18px;
+              
+              &:hover {
+                background: var(--light-shade);
+                color: var(--dark-color);
+              }
+            }
+
+            .send-btn {
+              background: var(--primary-color);
+              color: white;
+              font-size: 18px;
+              
+              &:disabled {
+                background: var(--light-shade);
+                cursor: not-allowed;
+              }
+
+              &:hover:not(:disabled) {
+                background: #2c6de9;
+                transform: scale(1.05);
+              }
+            }
+          }
+        }
+
+        .quick-actions {
+          display: flex;
+          gap: 8px;
+          
+          .quick-action-btn {
+            display: flex;
+            align-items: center;
+            gap: 4px;
+            padding: 6px 12px;
+            background: var(--light-color);
+            border: none;
+            border-radius: 16px;
+            font-size: 12px;
+            color: var(--medium-color);
+            cursor: pointer;
+            transition: all 0.2s;
+
+            &:hover:not(:disabled) {
+              background: var(--light-shade);
+              color: var(--dark-color);
+            }
+
+            &:disabled {
+              opacity: 0.5;
+              cursor: not-allowed;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .analysis-result-section {
+    .result-header {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+      margin-bottom: 16px;
+
+      .header-icon {
+        font-size: 24px;
+      }
+
+      h3 {
+        flex: 1;
+        margin: 0;
+        font-size: 18px;
+        color: var(--dark-color);
+      }
+
+      .btn-reset {
+        padding: 6px 12px;
+        background: var(--light-color);
+        border: 1px solid var(--light-shade);
+        border-radius: 16px;
+        font-size: 12px;
+        color: var(--medium-color);
+        cursor: pointer;
+
+        &:hover {
+          background: var(--light-shade);
+          color: var(--dark-color);
+        }
+      }
+    }
+
+    .result-card {
+      background: white;
+      border: 1px solid var(--light-shade);
+      border-radius: 12px;
+      padding: 16px;
+      margin-bottom: 16px;
+
+      .card-title {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        margin-bottom: 12px;
+        
+        .title-icon { font-size: 18px; }
+        h4 { margin: 0; font-size: 14px; font-weight: 600; }
+      }
+
+      &.quick-summary-card {
+        background: linear-gradient(135deg, #f0f9ff, #e0f2fe);
+        border: none;
+
+        .quick-summary-content {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 16px;
+          
+          .summary-item {
+            flex: 1;
+            min-width: 150px;
+            background: rgba(255,255,255,0.6);
+            padding: 12px;
+            border-radius: 8px;
+            
+            .summary-label {
+              display: flex;
+              align-items: center;
+              gap: 6px;
+              margin-bottom: 6px;
+              font-size: 12px;
+              color: var(--medium-color);
+            }
+            
+            .summary-value {
+              font-size: 14px;
+              font-weight: 600;
+              color: var(--dark-color);
+            }
+          }
+        }
+      }
+
+      .analysis-text {
+        white-space: pre-wrap;
+        font-family: inherit;
+        font-size: 14px;
+        line-height: 1.6;
+        color: var(--dark-color);
+        margin: 0;
+      }
+    }
+
+    .dimensions-card {
+      .dimensions-grid {
+        display: grid;
+        gap: 12px;
+
+        .dimension-item {
+          border: 1px solid var(--light-shade);
+          border-radius: 8px;
+          overflow: hidden;
+
+          .dimension-header {
+            display: flex;
+            align-items: center;
+            gap: 12px;
+            padding: 12px 16px;
+            background: var(--light-color);
+            cursor: pointer;
+            transition: background 0.2s;
+
+            &:hover { background: var(--light-shade); }
+
+            .dimension-icon { font-size: 18px; }
+            .dimension-title { flex: 1; font-size: 13px; font-weight: 600; }
+            .toggle-icon { font-size: 10px; color: var(--medium-color); }
+          }
+
+          .dimension-content {
+            padding: 12px 16px;
+            font-size: 13px;
+            line-height: 1.5;
+            color: var(--dark-color);
+            border-top: 1px solid var(--light-shade);
+            
+            p { margin: 0; }
+          }
+        }
+      }
+    }
+
+    .action-section {
+      display: flex;
+      gap: 12px;
+      margin-top: 24px;
+      justify-content: flex-end;
+
+      .btn {
+        display: flex;
+        align-items: center;
+        gap: 6px;
+        padding: 10px 20px;
+        border-radius: 8px;
+        border: none;
+        font-size: 14px;
+        font-weight: 500;
+        cursor: pointer;
+        transition: all 0.2s;
+
+        &.btn-outline {
+          background: white;
+          border: 1px solid var(--light-shade);
+          color: var(--dark-color);
+          
+          &:hover { border-color: var(--primary-color); color: var(--primary-color); }
+        }
+
+        &.btn-primary {
+          background: var(--primary-color);
+          color: white;
+          
+          &:hover { background: #2c6de9; }
+          &:disabled { background: var(--light-shade); cursor: not-allowed; }
+        }
+        
+        .loading-spinner {
+          width: 14px;
+          height: 14px;
+          border: 2px solid rgba(255,255,255,0.3);
+          border-top-color: white;
+          border-radius: 50%;
+          animation: spin 0.8s linear infinite;
+        }
+      }
+    }
+  }
+
+  .report-section {
+    background: white;
+    border-radius: 12px;
+    padding: 24px;
+    box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+
+    .report-header {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+      margin-bottom: 24px;
+      padding-bottom: 16px;
+      border-bottom: 1px solid var(--light-shade);
+
+      .header-icon { font-size: 24px; }
+      h3 { flex: 1; margin: 0; font-size: 18px; }
+      .btn-reset { font-size: 12px; padding: 6px 12px; border-radius: 16px; border: 1px solid var(--light-shade); background: white; cursor: pointer; }
+    }
+
+    .report-content {
+      background: var(--light-color);
+      padding: 24px;
+      border-radius: 8px;
+      margin-bottom: 24px;
+      
+      .report-text {
+        white-space: pre-wrap;
+        font-family: inherit;
+        font-size: 14px;
+        line-height: 1.8;
+        color: var(--dark-color);
+        margin: 0;
+      }
+    }
+
+    .report-actions {
+      display: flex;
+      gap: 12px;
+      justify-content: flex-end;
+
+      .btn {
+        display: flex;
+        align-items: center;
+        gap: 6px;
+        padding: 10px 20px;
+        border-radius: 8px;
+        border: none;
+        font-size: 14px;
+        cursor: pointer;
+        
+        &.btn-outline { background: white; border: 1px solid var(--light-shade); color: var(--dark-color); &:hover { border-color: var(--medium-color); } }
+        &.btn-info { background: var(--secondary-color); color: white; &:hover { opacity: 0.9; } }
+        &.btn-success { background: var(--success-color); color: white; &:hover { opacity: 0.9; } }
+        
+        &:disabled { opacity: 0.6; cursor: not-allowed; }
+      }
+    }
+  }
+}
+
+@keyframes bounce {
+  0%, 100% { transform: scale(0); }
+  50% { transform: scale(1); }
+}

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

@@ -0,0 +1,477 @@
+import { Component, OnInit, Input, Output, EventEmitter, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { IonIcon } from '@ionic/angular/standalone';
+import { Project } from '../../../../../services/product-space.service';
+import { ProjectFileService } from '../../../../../services/project-file.service';
+import { DesignAnalysisAIService } from '../../../../../services/design-analysis-ai.service';
+import { addIcons } from 'ionicons';
+import { add, sparkles, send, trash, refresh, thumbsUp, thumbsDown, clipboard, cloudUpload, documentText, image } from 'ionicons/icons';
+
+addIcons({
+  add, sparkles, send, trash, refresh, 'thumbs-up': thumbsUp, 'thumbs-down': thumbsDown, clipboard, 'cloud-upload': cloudUpload, 'document-text': documentText, image
+});
+
+@Component({
+  selector: 'app-ai-design-analysis',
+  standalone: true,
+  imports: [CommonModule, FormsModule, ReactiveFormsModule, IonIcon],
+  templateUrl: './ai-design-analysis.component.html',
+  styleUrls: ['./ai-design-analysis.component.scss']
+})
+export class AiDesignAnalysisComponent implements OnInit {
+  @Input() project: any = null;
+  @Input() projectProducts: Project[] = [];
+  @Input() canEdit: boolean = true;
+  @Output() analysisComplete = new EventEmitter<any>();
+
+  // AI Design Analysis State
+  showAIDesignDialog: boolean = false;
+  aiDesignDialogVisible = false;
+  aiDesignUploading: boolean = false;
+  aiDesignCurrentSpace: any = null;
+  aiDesignUploadedImages: string[] = [];
+  aiDesignUploadedFiles: any[] = [];
+  aiDesignTextDescription = '';
+  aiDesignAnalyzing = false;
+  aiDesignAnalysisResult: any = null;
+  aiDesignGeneratingReport = false;
+  aiDesignReport = '';
+  aiDesignReportConfirmed = false;
+  aiDesignDragOver = false;
+  exportingWord = false;
+  
+  // AI Chat State
+  aiChatMessages: Array<{
+    id: string;
+    role: 'user' | 'assistant';
+    content: string;
+    timestamp: Date;
+    images?: string[];
+    isLoading?: boolean;
+    isStreaming?: boolean;
+    liked?: boolean;
+    disliked?: boolean;
+  }> = [];
+  aiChatInput: string = '';
+  expandedDimensions: Set<string> = new Set();
+
+  @ViewChild('chatMessagesWrapper') chatMessagesWrapper!: ElementRef;
+  @ViewChild('chatInput') chatInputElement!: ElementRef;
+  @ViewChild('aiDesignFileInput') aiDesignFileInput!: ElementRef;
+
+  constructor(
+    public elementRef: ElementRef,
+    private cdr: ChangeDetectorRef,
+    private projectFileService: ProjectFileService,
+    private designAnalysisAIService: DesignAnalysisAIService
+  ) {}
+
+  ngOnInit() {
+    // Auto select first space if available
+    if (this.projectProducts.length > 0 && !this.aiDesignCurrentSpace) {
+      this.aiDesignCurrentSpace = this.projectProducts[0];
+    }
+  }
+
+  // Space Selection
+  selectAISpace(space: Project) {
+    this.aiDesignCurrentSpace = space;
+    this.cdr.markForCheck();
+  }
+
+  getSpaceDisplayName(space: any): string {
+    return space.name || '未命名空间';
+  }
+
+  // File Handling
+  triggerAIDialogFileInput() {
+    const fileInput = document.getElementById('aiDesignFileInput') as HTMLInputElement;
+    if (fileInput) {
+      fileInput.click();
+    }
+  }
+
+  async handleAIFileSelect(event: any) {
+    const files = event.target.files;
+    if (files && files.length > 0) {
+      await this.processAIFiles(files);
+    }
+    // Reset input
+    event.target.value = '';
+  }
+
+  onAIFileDragOver(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.aiDesignDragOver = true;
+  }
+
+  onAIFileDragLeave(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.aiDesignDragOver = false;
+  }
+
+  async onAIFileDrop(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.aiDesignDragOver = false;
+    
+    const files = event.dataTransfer?.files;
+    if (files && files.length > 0) {
+      await this.processAIFiles(files);
+    }
+  }
+
+  async processAIFiles(files: FileList | File[]) {
+    if (this.aiDesignUploadedFiles.length + files.length > 3) {
+      window?.fmode?.alert('最多只能上传3个参考文件');
+      return;
+    }
+
+    this.aiDesignUploading = true;
+    
+    try {
+      // Process each file
+      for (let i = 0; i < files.length; i++) {
+        const file = files[i];
+        // Determine file type and preview
+        const extension = file.name.split('.').pop()?.toLowerCase() || '';
+        const isImage = ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(extension);
+        
+        let url = '';
+        if (isImage) {
+          url = await this.readFileAsDataURL(file);
+        }
+        
+        this.aiDesignUploadedFiles.push({
+          file: file,
+          name: file.name,
+          size: file.size,
+          extension: extension,
+          url: url,
+          isImage: isImage
+        });
+        
+        if (isImage) {
+          this.aiDesignUploadedImages.push(url);
+        }
+      }
+    } catch (error) {
+      console.error('File processing error:', error);
+      window?.fmode?.alert('文件处理失败');
+    } finally {
+      this.aiDesignUploading = false;
+      this.cdr.markForCheck();
+    }
+  }
+
+  readFileAsDataURL(file: File): Promise<string> {
+    return new Promise((resolve, reject) => {
+      const reader = new FileReader();
+      reader.onload = (e: any) => resolve(e.target.result);
+      reader.onerror = (e) => reject(e);
+      reader.readAsDataURL(file);
+    });
+  }
+
+  removeAIDialogImage(index: number) {
+    this.aiDesignUploadedFiles.splice(index, 1);
+    // Rebuild images array
+    this.aiDesignUploadedImages = this.aiDesignUploadedFiles
+      .filter(f => f.isImage)
+      .map(f => f.url);
+  }
+
+  formatFileSize(bytes: number): string {
+    if (bytes === 0) return '0 B';
+    const k = 1024;
+    const sizes = ['B', 'KB', 'MB', 'GB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  }
+
+  // AI Analysis
+  async startAIDesignAnalysis() {
+    if (this.aiDesignUploadedFiles.length === 0) {
+      window?.fmode?.alert('请先上传参考文件');
+      return;
+    }
+
+    this.aiDesignAnalyzing = true;
+    
+    // Add initial user message
+    const userMsg = {
+      id: Date.now().toString(),
+      role: 'user' as const,
+      content: '请分析这些设计文件,提供专业的设计建议。',
+      timestamp: new Date(),
+      images: [...this.aiDesignUploadedImages]
+    };
+    this.aiChatMessages.push(userMsg);
+    
+    // Add loading AI message
+    const aiMsgId = (Date.now() + 1).toString();
+    this.aiChatMessages.push({
+      id: aiMsgId,
+      role: 'assistant',
+      content: '',
+      timestamp: new Date(),
+      isLoading: true
+    });
+
+    try {
+      // Simulate upload to cloud if needed or use service
+      // For now assuming we send file objects or URLs to service
+      
+      // Call service
+      const result = await this.designAnalysisAIService.analyzeReferenceImages({
+        images: this.aiDesignUploadedImages,
+        textDescription: '请分析这些设计文件,提供专业的设计建议。',
+        spaceType: this.aiDesignCurrentSpace?.type || this.aiDesignCurrentSpace?.name,
+        onContentStream: (content) => {
+          // Update chat with streaming content
+          const aiMsgIndex = this.aiChatMessages.findIndex(m => m.id === aiMsgId);
+          if (aiMsgIndex !== -1) {
+            this.aiChatMessages[aiMsgIndex].isLoading = false;
+            this.aiChatMessages[aiMsgIndex].content = content;
+            this.aiChatMessages[aiMsgIndex].isStreaming = true;
+            this.cdr.markForCheck();
+            this.scrollToBottom();
+          }
+        }
+      });
+
+      this.aiDesignAnalysisResult = result;
+      
+      // 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 || '分析完成,请查看下方详细结果。';
+      }
+      
+      this.analysisComplete.emit(result);
+
+    } catch (error) {
+      console.error('Analysis failed:', error);
+      const aiMsgIndex = this.aiChatMessages.findIndex(m => m.id === aiMsgId);
+      if (aiMsgIndex !== -1) {
+        this.aiChatMessages[aiMsgIndex].isLoading = false;
+        this.aiChatMessages[aiMsgIndex].content = '抱歉,分析过程中出现错误,请重试。';
+      }
+      window?.fmode?.alert('AI分析失败,请重试');
+    } finally {
+      this.aiDesignAnalyzing = false;
+      this.cdr.markForCheck();
+    }
+  }
+
+  resetAIAnalysis() {
+    this.aiDesignAnalysisResult = null;
+    this.aiDesignReport = '';
+    this.aiChatMessages = [];
+    this.aiDesignUploadedFiles = [];
+    this.aiDesignUploadedImages = [];
+    this.aiDesignReportConfirmed = false;
+    this.cdr.markForCheck();
+  }
+
+  // Chat Functions
+  useQuickPrompt(prompt: string) {
+    this.aiChatInput = prompt;
+    this.sendChatMessage();
+  }
+
+  async sendChatMessage() {
+    if (!this.aiChatInput.trim() || this.aiDesignAnalyzing) return;
+
+    const content = this.aiChatInput;
+    this.aiChatInput = '';
+
+    // User message
+    this.aiChatMessages.push({
+      id: Date.now().toString(),
+      role: 'user',
+      content: content,
+      timestamp: new Date()
+    });
+
+    // AI Loading
+    const aiMsgId = (Date.now() + 1).toString();
+    this.aiChatMessages.push({
+      id: aiMsgId,
+      role: 'assistant',
+      content: '',
+      timestamp: new Date(),
+      isLoading: true
+    });
+    
+    this.scrollToBottom();
+
+    try {
+      // Call AI Chat service
+      // Note: Passing previous messages for context if API supports it
+      const history = this.aiChatMessages
+        .filter(m => m.id !== aiMsgId) // Exclude current loading message
+        .map(m => ({
+          role: m.role,
+          content: m.content
+        }));
+
+      const response = await this.designAnalysisAIService.chatWithAI({
+        userMessage: content,
+        conversationHistory: history,
+        onContentStream: (streamContent) => {
+          const aiMsgIndex = this.aiChatMessages.findIndex(m => m.id === aiMsgId);
+          if (aiMsgIndex !== -1) {
+            this.aiChatMessages[aiMsgIndex].isLoading = false;
+            this.aiChatMessages[aiMsgIndex].content = streamContent;
+            this.aiChatMessages[aiMsgIndex].isStreaming = true;
+            this.cdr.markForCheck();
+            this.scrollToBottom();
+          }
+        }
+      });
+
+      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 = response;
+      }
+    } catch (error) {
+      console.error('Chat failed:', error);
+      const aiMsgIndex = this.aiChatMessages.findIndex(m => m.id === aiMsgId);
+      if (aiMsgIndex !== -1) {
+        this.aiChatMessages[aiMsgIndex].isLoading = false;
+        this.aiChatMessages[aiMsgIndex].content = '抱歉,暂时无法回复,请稍后再试。';
+      }
+    } finally {
+      this.scrollToBottom();
+      this.cdr.markForCheck();
+    }
+  }
+
+  scrollToBottom() {
+    setTimeout(() => {
+      if (this.chatMessagesWrapper) {
+        this.chatMessagesWrapper.nativeElement.scrollTop = this.chatMessagesWrapper.nativeElement.scrollHeight;
+      }
+    }, 100);
+  }
+
+  onChatInputChange(event: any) {
+    // Auto resize logic if needed
+  }
+
+  onChatInputEnter(event: any) {
+    if (!event.shiftKey) {
+      event.preventDefault();
+      this.sendChatMessage();
+    }
+  }
+  
+  openAttachmentDialog() {
+    this.triggerAIDialogFileInput();
+  }
+  
+  startVoiceInput() {
+    window?.fmode?.toast('语音输入功能开发中...');
+  }
+
+  clearChat() {
+    this.aiChatMessages = [];
+  }
+
+  exportChat() {
+    window?.fmode?.toast('导出功能开发中...');
+  }
+
+  confirmCurrentAnalysis() {
+    // Maybe save to notes?
+    window?.fmode?.toast('分析结果已确认');
+  }
+
+  // Message Actions
+  copyMessage(content: string) {
+    navigator.clipboard.writeText(content).then(() => {
+      window?.fmode?.toast('已复制');
+    });
+  }
+
+  regenerateMessage(message: any) {
+    // Logic to regenerate
+    window?.fmode?.toast('重新生成中...');
+  }
+
+  likeMessage(message: any) {
+    message.liked = !message.liked;
+    message.disliked = false;
+  }
+
+  dislikeMessage(message: any) {
+    message.disliked = !message.disliked;
+    message.liked = false;
+  }
+
+  formatMessageContent(content: string): string {
+    // Simple markdown formatting or just return content
+    // In real app, use a markdown pipe or service
+    return content.replace(/\n/g, '<br>');
+  }
+
+  // Result View
+  toggleDimension(dimension: string) {
+    if (this.expandedDimensions.has(dimension)) {
+      this.expandedDimensions.delete(dimension);
+    } else {
+      this.expandedDimensions.add(dimension);
+    }
+  }
+
+  getAISummary(): string {
+    return this.aiDesignAnalysisResult?.summary || '';
+  }
+
+  // Reports
+  generateServiceNotes() {
+    // Logic to generate notes for CS
+    window?.fmode?.toast('客服标注已生成');
+  }
+
+  async generateClientReport() {
+    this.aiDesignGeneratingReport = true;
+    try {
+      const report = await this.designAnalysisAIService.generateClientReport({
+        analysisData: this.aiDesignAnalysisResult,
+        spaceName: this.aiDesignCurrentSpace?.name || '未命名空间'
+      });
+      this.aiDesignReport = report;
+    } catch (error) {
+      console.error('Report generation failed:', error);
+      window?.fmode?.alert('报告生成失败');
+    } finally {
+      this.aiDesignGeneratingReport = false;
+      this.cdr.markForCheck();
+    }
+  }
+
+  async exportReportToWord() {
+    this.exportingWord = true;
+    try {
+      await new Promise(resolve => setTimeout(resolve, 1500)); // Simulate
+      window?.fmode?.toast('导出成功');
+    } finally {
+      this.exportingWord = false;
+      this.cdr.markForCheck();
+    }
+  }
+
+  confirmDesignReport() {
+    this.aiDesignReportConfirmed = true;
+    window?.fmode?.toast('报告已保存');
+  }
+}

+ 453 - 0
src/modules/project/pages/project-detail/stages/components/space-requirement-item/space-requirement-item.component.html

@@ -0,0 +1,453 @@
+<div class="space-item" [class.expanded]="isExpanded">
+  <!-- 空间头部 - 折叠时显示 -->
+  <div class="space-header" (click)="toggleExpansion()">
+    <div class="space-name-section">
+      {{ getSpaceDisplayName() }}
+      <span class="reference-count-badge">
+        参考 {{ getTotalFileCount() }}
+      </span>
+    </div>
+    
+    <!-- 特殊需求显示 -->
+    @if (specialRequirements) {
+      <div class="special-requirements-box">
+        <span class="requirements-label">特殊要求:</span>
+        <span class="requirements-text">{{ specialRequirements | slice:0:30 }}{{ specialRequirements.length > 30 ? '...' : '' }}</span>
+      </div>
+    }
+    
+    <!-- 操作按钮 -->
+    <div class="header-actions">
+      @if (canEdit) {
+        <button class="btn-icon-small btn-ai" title="AI设计分析" (click)="openAiDialog.emit(space); $event.stopPropagation()">
+          <span class="icon-text">🤖</span>
+        </button>
+        <button class="btn-icon-small btn-edit" title="编辑特殊要求" (click)="toggleExpansion($event)">
+          <span class="icon-text">✏️</span>
+        </button>
+      }
+    </div>
+    
+    <!-- 展开/收起图标 -->
+    <div class="expand-icon" [class.expanded]="isExpanded">
+      <svg width="28" height="28" viewBox="0 0 24 24" fill="currentColor">
+        <path d="M7 10l5 5 5-5z"/>
+      </svg>
+    </div>
+  </div>
+
+  <!-- 空间内容 - 展开时显示 -->
+  @if (isExpanded) {
+    <div class="space-content">
+      <!-- 拖拽上传区域 -->
+      <div class="drag-drop-zone"
+            (dragover)="onDragOver($event)"
+            (dragleave)="onDragLeave($event)"
+            (drop)="onDrop($event)"
+            [class.drag-over]="isDragOver">
+        <div class="drag-drop-content">
+          <div class="drag-drop-icon">
+            <ion-icon name="cloud-upload-outline"></ion-icon>
+          </div>
+          <h4>拖拽参考图片到此</h4>
+          <p>或点击下方按钮上传</p>
+          <p class="drag-hint">AI将自动分析图片并智能分类</p>
+        </div>
+      </div>
+
+      <!-- 图片类型导航标签 -->
+      <div class="image-type-tabs">
+        @for (type of imageTypes; track type.id) {
+          <button
+            class="tab-button"
+            [class.active]="activeImageTab === type.id"
+            (click)="selectImageTab(type.id)">
+            <span class="tab-label">{{ type.name }}</span>
+            @if (getImageCountByType(type.id) > 0) {
+              <span class="tab-badge">{{ getImageCountByType(type.id) }}</span>
+            }
+          </button>
+        }
+      </div>
+
+      <!-- 图片展示区域 -->
+      <div class="images-section">
+        @if (activeImageTab === 'all') {
+          <!-- 全部图片和CAD文件 -->
+          <div class="section-header">
+            <h5>所有参考文件</h5>
+            @if (canEdit) {
+              <input
+                type="file"
+                accept="image/*"
+                multiple
+                (change)="onImageFileSelected($event)"
+                [disabled]="uploading"
+                hidden
+                [id]="'spaceImageInput_' + space.id" />
+              <button
+                class="btn btn-sm btn-outline"
+                (click)="triggerFileClick('spaceImageInput_' + space.id)"
+                [disabled]="uploading">
+                <ion-icon name="add"></ion-icon>
+                上传参考图
+              </button>
+            }
+          </div>
+          <div class="section-content">
+            @if (images.length > 0) {
+              <div class="images-grid">
+                @for (image of images; track image.id) {
+                  <div class="image-item">
+                    <img [src]="image.url" [alt]="image.name" (click)="viewAnalysis.emit(image.id)" />
+                    <div class="image-overlay">
+                      <div class="overlay-top">
+                        <span class="badge" [class]="getImageTypeBadgeClass(image.type)">
+                          {{ getImageTypeLabel(image.type) }}
+                        </span>
+                        @if (hasImageAnalysis(image.id)) {
+                          <span class="badge badge-success">
+                            <ion-icon name="sparkles"></ion-icon>
+                          </span>
+                        }
+                      </div>
+                      <div class="overlay-actions">
+                        <button
+                          class="btn-icon btn-primary"
+                          (click)="viewAnalysis.emit(image.id); $event.stopPropagation()"
+                          title="查看色彩分析">
+                          <ion-icon name="color-palette"></ion-icon>
+                        </button>
+                        @if (canEdit) {
+                          <button
+                            class="btn-icon btn-danger"
+                            (click)="deleteImage.emit(image.id); $event.stopPropagation()">
+                            <ion-icon name="trash"></ion-icon>
+                          </button>
+                        }
+                      </div>
+                    </div>
+                  </div>
+                }
+              </div>
+            } @else {
+              <div class="empty-state">
+                <ion-icon name="image-outline"></ion-icon>
+                <p>暂无参考图片</p>
+              </div>
+            }
+          </div>
+
+          <!-- CAD文件显示 -->
+          @if (cadFiles.length > 0) {
+            <div class="section-header">
+              <h5>CAD文件</h5>
+            </div>
+            <div class="section-content">
+              <div class="cad-files-list">
+                @for (cadFile of cadFiles; track cadFile.id) {
+                  <div class="cad-file-item">
+                    <div class="cad-icon">
+                      <ion-icon name="document"></ion-icon>
+                    </div>
+                    <div class="cad-info">
+                      <div class="cad-name">{{ cadFile.name }}</div>
+                      <div class="cad-meta">
+                        @if (hasImageAnalysis(cadFile.id)) {
+                          <span class="badge badge-success">
+                            <ion-icon name="sparkles"></ion-icon>
+                            已分析
+                          </span>
+                        }
+                      </div>
+                    </div>
+                    @if (canEdit) {
+                      <button
+                        class="btn-icon btn-danger"
+                        (click)="deleteCAD.emit(cadFile.id); $event.stopPropagation()">
+                        <ion-icon name="trash"></ion-icon>
+                      </button>
+                    }
+                  </div>
+                }
+              </div>
+            </div>
+          }
+
+          <!-- AI分析结果展示 - 新布局 -->
+          @if (analysisResults.length > 0) {
+            <div class="section-divider"></div>
+            <div class="ai-analysis-section">
+              <div class="section-header">
+                <h5>
+                  <ion-icon name="sparkles"></ion-icon>
+                  AI分析结果
+                </h5>
+              </div>
+              <div class="analysis-results-list">
+                @for (analysis of analysisResults; track analysis.imageId) {
+                  <div class="analysis-item-card">
+                    <!-- 左侧:图片 -->
+                    <div class="analysis-image-section">
+                      <div class="analysis-image">
+                        <img [src]="getImageUrl(analysis.imageId)" [alt]="'Analysis ' + analysis.imageId" />
+                      </div>
+                    </div>
+
+                    <!-- 右侧:分析结果 -->
+                    <div class="analysis-results-section">
+                      <!-- 参考类型和用户要求(按图1格式) -->
+                      <div class="analysis-header-box">
+                        <div class="header-info">
+                          <div class="info-item">
+                            <span class="info-label">参考类型:</span>
+                            <span class="info-value">{{ getImageTypeLabel(analysis.imageType) }}</span>
+                          </div>
+                          <div class="info-divider">|</div>
+                          <div class="info-item">
+                            <span class="info-label">备注用户要求</span>
+                          </div>
+                        </div>
+                      </div>
+
+                      <!-- AI分析结果内容 -->
+                      <div class="analysis-details-content">
+                        <!-- 原有分析维度 -->
+                        @if (analysis.originalAnalysis) {
+                          <div class="analysis-group">
+                            <h6>原有分析维度</h6>
+                            <div class="analysis-grid">
+                              @if (analysis.originalAnalysis.quality) {
+                                <div class="analysis-row">
+                                  <span class="label">质量评分:</span>
+                                  <span class="value">{{ analysis.originalAnalysis.quality.score }}/100 ({{ analysis.originalAnalysis.quality.level }})</span>
+                                </div>
+                              }
+                              @if (analysis.originalAnalysis.content) {
+                                <div class="analysis-row">
+                                  <span class="label">内容分类:</span>
+                                  <span class="value">{{ analysis.originalAnalysis.content.category }}</span>
+                                </div>
+                              }
+                              @if (analysis.originalAnalysis.technical) {
+                                <div class="analysis-row">
+                                  <span class="label">像素:</span>
+                                  <span class="value">{{ analysis.originalAnalysis.technical.megapixels }}MP</span>
+                                </div>
+                              }
+                            </div>
+                          </div>
+                        }
+
+                        <!-- 新增分析维度 -->
+                        @if (analysis.enhancedAnalysis) {
+                          <div class="analysis-group">
+                            <h6>设计分析维度</h6>
+                            <div class="analysis-grid">
+                              @if (analysis.enhancedAnalysis.style) {
+                                <div class="analysis-row">
+                                  <span class="label">风格:</span>
+                                  <span class="value">{{ analysis.enhancedAnalysis.style }}</span>
+                                </div>
+                              }
+                              @if (analysis.enhancedAnalysis.atmosphere) {
+                                <div class="analysis-row">
+                                  <span class="label">氛围:</span>
+                                  <span class="value">{{ analysis.enhancedAnalysis.atmosphere }}</span>
+                                </div>
+                              }
+                              @if (analysis.enhancedAnalysis.material) {
+                                <div class="analysis-row">
+                                  <span class="label">材质:</span>
+                                  <span class="value">{{ analysis.enhancedAnalysis.material }}</span>
+                                </div>
+                              }
+                              @if (analysis.enhancedAnalysis.texture) {
+                                <div class="analysis-row">
+                                  <span class="label">纹理:</span>
+                                  <span class="value">{{ analysis.enhancedAnalysis.texture }}</span>
+                                </div>
+                              }
+                            </div>
+                          </div>
+                        }
+
+                        <!-- 风格元素分析(新增) -->
+                        @if (analysis.styleElements) {
+                          <div class="analysis-group">
+                            <h6>风格元素</h6>
+                            <div class="analysis-tags">
+                              @for (keyword of analysis.styleElements.styleKeywords; track keyword) {
+                                <span class="tag">{{ keyword }}</span>
+                              }
+                            </div>
+                          </div>
+                        }
+
+                        <!-- 色彩搭配分析(新增) -->
+                        @if (analysis.colorScheme) {
+                          <div class="analysis-group">
+                            <h6>色彩搭配</h6>
+                            <div class="color-scheme-display">
+                              @if (analysis.colorScheme.primaryColors && analysis.colorScheme.primaryColors.length > 0) {
+                                <div class="color-row">
+                                  <span class="color-label">主色调:</span>
+                                  <div class="color-samples">
+                                    @for (color of analysis.colorScheme.primaryColors; track color) {
+                                      <div class="color-sample" [style.backgroundColor]="color" [title]="color"></div>
+                                    }
+                                  </div>
+                                </div>
+                              }
+                            </div>
+                          </div>
+                        }
+                      </div>
+                    </div>
+                  </div>
+                }
+              </div>
+            </div>
+          }
+          
+          <!-- 用户需求备注 -->
+          <div class="section-divider"></div>
+          <div class="user-notes-section">
+            <div class="section-header">
+              <h5>用户需求备注</h5>
+            </div>
+            <div class="section-content">
+              <textarea
+                class="form-textarea"
+                [ngModel]="specialRequirements"
+                (ngModelChange)="onSpecialRequirementsChange($event)"
+                [disabled]="!canEdit"
+                rows="4"
+                [placeholder]="'描述' + getSpaceDisplayName() + '的特殊要求和注意事项'"></textarea>
+            </div>
+          </div>
+        } @else if (activeImageTab === 'cad') {
+          <!-- CAD文件 -->
+          <div class="section-header">
+            <h5>CAD文件</h5>
+            @if (canEdit) {
+              <input
+                type="file"
+                accept=".dwg,.dxf,.pdf"
+                multiple
+                (change)="onCADFileSelected($event)"
+                [disabled]="uploading"
+                hidden
+                [id]="'spaceCADInput_' + space.id" />
+              <button
+                class="btn btn-sm btn-outline"
+                (click)="triggerFileClick('spaceCADInput_' + space.id)"
+                [disabled]="uploading">
+                <ion-icon name="add"></ion-icon>
+                上传CAD
+              </button>
+            }
+          </div>
+          <div class="section-content">
+            @if (cadFiles.length > 0) {
+              <div class="file-list">
+                @for (file of cadFiles; track file.id) {
+                  <div class="file-item">
+                    <ion-icon name="document-text" class="file-icon"></ion-icon>
+                    <div class="file-info">
+                      <h6>{{ file.name }}</h6>
+                      <p>{{ formatFileSize(file.size) }} · {{ file.uploadTime | date:'MM-dd HH:mm' }}</p>
+                      @if (hasImageAnalysis(file.id)) {
+                        <span class="badge badge-success">
+                          <ion-icon name="sparkles"></ion-icon>
+                          已分析
+                        </span>
+                      }
+                    </div>
+                    @if (canEdit) {
+                      <button
+                        class="btn-icon btn-danger"
+                        (click)="deleteCAD.emit(file.id)">
+                        <ion-icon name="trash"></ion-icon>
+                      </button>
+                    }
+                  </div>
+                }
+              </div>
+            } @else {
+              <div class="empty-state">
+                <ion-icon name="document-outline"></ion-icon>
+                <p>暂无CAD文件</p>
+              </div>
+            }
+          </div>
+        } @else {
+          <!-- 按类型过滤的图片 -->
+          <div class="section-header">
+            <h5>{{ getImageTypeLabel(activeImageTab) }}图片</h5>
+            @if (canEdit) {
+              <input
+                type="file"
+                accept="image/*"
+                multiple
+                (change)="onImageFileSelected($event, activeImageTab)"
+                [disabled]="uploading"
+                hidden
+                [id]="'spaceImageInput_' + space.id + '_' + activeImageTab" />
+              <button
+                class="btn btn-sm btn-outline"
+                (click)="triggerFileClick('spaceImageInput_' + space.id + '_' + activeImageTab)"
+                [disabled]="uploading">
+                <ion-icon name="add"></ion-icon>
+                上传{{ getImageTypeLabel(activeImageTab) }}图
+              </button>
+            }
+          </div>
+          <div class="section-content">
+            @if (getFilteredImages().length > 0) {
+              <div class="images-grid">
+                @for (image of getFilteredImages(); track image.id) {
+                  <div class="image-item">
+                    <img [src]="image.url" [alt]="image.name" (click)="viewAnalysis.emit(image.id)" />
+                    <div class="image-overlay">
+                      <div class="overlay-top">
+                        <span class="badge" [class]="getImageTypeBadgeClass(image.type)">
+                          {{ getImageTypeLabel(image.type) }}
+                        </span>
+                        @if (hasImageAnalysis(image.id)) {
+                          <span class="badge badge-success">
+                            <ion-icon name="sparkles"></ion-icon>
+                          </span>
+                        }
+                      </div>
+                      <div class="overlay-actions">
+                        <button
+                          class="btn-icon btn-primary"
+                          (click)="viewAnalysis.emit(image.id); $event.stopPropagation()"
+                          title="查看色彩分析">
+                          <ion-icon name="color-palette"></ion-icon>
+                        </button>
+                        @if (canEdit) {
+                          <button
+                            class="btn-icon btn-danger"
+                            (click)="deleteImage.emit(image.id); $event.stopPropagation()">
+                            <ion-icon name="trash"></ion-icon>
+                          </button>
+                        }
+                      </div>
+                    </div>
+                  </div>
+                }
+              </div>
+            } @else {
+              <div class="empty-state">
+                <ion-icon name="image-outline"></ion-icon>
+                <p>暂无{{ getImageTypeLabel(activeImageTab) }}图片</p>
+              </div>
+            }
+          </div>
+        }
+      </div>
+    </div>
+  }
+</div>

+ 600 - 0
src/modules/project/pages/project-detail/stages/components/space-requirement-item/space-requirement-item.component.scss

@@ -0,0 +1,600 @@
+// Space Requirement Item SCSS
+
+// CSS 变量定义
+:host {
+  --primary-color: #3880ff;
+  --primary-rgb: 56, 128, 255;
+  --secondary-color: #0cd1e8;
+  --tertiary-color: #7044ff;
+  --tertiary-rgb: 112, 68, 255;
+  --success-color: #2dd36f;
+  --success-rgb: 45, 211, 111;
+  --warning-color: #ffc409;
+  --danger-color: #eb445a;
+  --dark-color: #222428;
+  --medium-color: #92949c;
+  --light-color: #f4f5f8;
+  --light-shade: #d7d8da;
+  --white: #ffffff;
+  
+  display: block;
+  margin-bottom: 16px;
+}
+
+.space-item {
+  background: white;
+  border-radius: 12px;
+  border: 2px solid var(--light-shade);
+  overflow: hidden;
+  transition: all 0.3s ease;
+
+  &:hover {
+    border-color: var(--primary-color);
+    box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.15);
+  }
+
+  &.expanded {
+    box-shadow: 0 8px 24px rgba(var(--primary-rgb), 0.2);
+  }
+
+  // 空间头部
+  .space-header {
+    display: grid;
+    grid-template-columns: auto 1fr auto auto;
+    align-items: center;
+    gap: 16px;
+    padding: 16px 20px;
+    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+    border-bottom: 1px solid var(--light-shade);
+    cursor: pointer;
+    transition: all 0.3s ease;
+    min-height: 60px;
+
+    .space-name-section {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+      font-size: 16px;
+      font-weight: 600;
+      color: var(--dark-color);
+      white-space: nowrap;
+
+      .reference-count-badge {
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        padding: 4px 12px;
+        background: linear-gradient(135deg, #e0e7ff 0%, #ddd6fe 100%);
+        color: var(--primary-color);
+        font-size: 12px;
+        font-weight: 600;
+        border-radius: 12px;
+        box-shadow: 0 2px 6px rgba(var(--primary-rgb), 0.15);
+        flex-shrink: 0;
+      }
+    }
+
+    .special-requirements-box {
+      display: flex;
+      align-items: center;
+      gap: 6px; 
+      padding: 6px 10px; 
+      background: linear-gradient(135deg, rgba(251, 191, 36, 0.08), rgba(245, 158, 11, 0.08));
+      border-left: 3px solid var(--warning-color); 
+      border-radius: 4px;
+      font-size: 12px; 
+      overflow: hidden;
+      min-width: 0; 
+      flex: 1; 
+      max-width: 180px; 
+
+      .requirements-label {
+        font-weight: 600;
+        color: var(--warning-color);
+        white-space: nowrap;
+        flex-shrink: 0;
+        font-size: 11px; 
+      }
+
+      .requirements-text {
+        color: var(--medium-color);
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        flex: 1;
+        min-width: 0;
+      }
+    }
+
+    .header-actions {
+      display: flex;
+      align-items: center;
+      gap: 6px; 
+      flex-shrink: 0;
+
+      .btn-icon-small {
+        width: 30px; 
+        height: 30px;
+        padding: 4px;
+        background: rgba(var(--primary-rgb), 0.1);
+        color: var(--primary-color);
+        border: 1px solid rgba(var(--primary-rgb), 0.2);
+        border-radius: 6px;
+        cursor: pointer;
+        transition: all 0.2s ease;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex-shrink: 0;
+
+        .icon-text {
+          font-size: 15px; 
+          line-height: 1;
+          display: block;
+        }
+
+        ion-icon {
+          font-size: 15px;
+        }
+
+        &:hover {
+          background: rgba(var(--primary-rgb), 0.2);
+          border-color: var(--primary-color);
+          transform: scale(1.05);
+        }
+
+        &.btn-edit {
+          &:hover {
+            background: var(--primary-color);
+            color: white;
+          }
+        }
+      }
+    }
+
+    .expand-icon {
+      color: var(--medium-color);
+      transition: transform 0.3s;
+      display: flex;
+      align-items: center;
+      
+      &.expanded {
+        transform: rotate(180deg);
+      }
+    }
+  }
+
+  // 空间内容
+  .space-content {
+    padding: 20px;
+    background: #f8fafc;
+
+    .drag-drop-zone {
+      border: 2px dashed var(--light-shade);
+      border-radius: 12px;
+      padding: 32px;
+      text-align: center;
+      background: white;
+      margin-bottom: 20px;
+      transition: all 0.3s;
+
+      &.drag-over {
+        border-color: var(--primary-color);
+        background: rgba(var(--primary-rgb), 0.05);
+        transform: scale(1.02);
+      }
+
+      .drag-drop-content {
+        pointer-events: none;
+
+        .drag-drop-icon {
+          font-size: 48px;
+          color: var(--primary-color);
+          margin-bottom: 12px;
+        }
+
+        h4 {
+          margin: 0 0 8px;
+          font-size: 16px;
+          font-weight: 600;
+          color: var(--dark-color);
+        }
+
+        p {
+          margin: 0 0 4px;
+          color: var(--medium-color);
+          font-size: 14px;
+
+          &.drag-hint {
+            font-size: 12px;
+            color: var(--success-color);
+            margin-top: 8px;
+          }
+        }
+      }
+    }
+
+    .image-type-tabs {
+      display: flex;
+      gap: 8px;
+      margin-bottom: 16px;
+      overflow-x: auto;
+      padding-bottom: 4px;
+
+      .tab-button {
+        display: flex;
+        align-items: center;
+        gap: 6px;
+        padding: 8px 16px;
+        border: 1px solid var(--light-shade);
+        border-radius: 20px;
+        background: white;
+        color: var(--medium-color);
+        font-size: 13px;
+        cursor: pointer;
+        white-space: nowrap;
+        transition: all 0.2s;
+
+        .tab-badge {
+          background: var(--light-shade);
+          color: white;
+          font-size: 10px;
+          padding: 2px 6px;
+          border-radius: 10px;
+          transition: all 0.2s;
+        }
+
+        &:hover {
+          border-color: var(--primary-color);
+          color: var(--primary-color);
+        }
+
+        &.active {
+          background: var(--primary-color);
+          border-color: var(--primary-color);
+          color: white;
+
+          .tab-badge {
+            background: rgba(255, 255, 255, 0.3);
+          }
+        }
+      }
+    }
+
+    .section-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 12px;
+
+      h5 {
+        margin: 0;
+        font-size: 14px;
+        font-weight: 600;
+        color: var(--dark-color);
+      }
+
+      .btn-outline {
+        padding: 6px 12px;
+        border: 1px solid var(--primary-color);
+        border-radius: 6px;
+        background: white;
+        color: var(--primary-color);
+        font-size: 12px;
+        display: flex;
+        align-items: center;
+        gap: 4px;
+        cursor: pointer;
+        transition: all 0.2s;
+
+        &:hover {
+          background: var(--primary-color);
+          color: white;
+        }
+        
+        &:disabled {
+          opacity: 0.5;
+          cursor: not-allowed;
+        }
+      }
+    }
+
+    .images-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+      gap: 12px;
+      margin-bottom: 24px;
+
+      .image-item {
+        position: relative;
+        aspect-ratio: 1;
+        border-radius: 8px;
+        overflow: hidden;
+        cursor: pointer;
+        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+        transition: transform 0.2s, box-shadow 0.2s;
+
+        &:hover {
+          transform: translateY(-2px);
+          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+          
+          .image-overlay {
+            opacity: 1;
+          }
+        }
+
+        img {
+          width: 100%;
+          height: 100%;
+          object-fit: cover;
+        }
+
+        .image-overlay {
+          position: absolute;
+          top: 0;
+          left: 0;
+          right: 0;
+          bottom: 0;
+          background: rgba(0, 0, 0, 0.5);
+          opacity: 0;
+          transition: opacity 0.2s;
+          padding: 8px;
+          display: flex;
+          flex-direction: column;
+          justify-content: space-between;
+
+          .overlay-top {
+            display: flex;
+            justify-content: space-between;
+            align-items: flex-start;
+          }
+
+          .overlay-actions {
+            display: flex;
+            justify-content: flex-end;
+            gap: 8px;
+          }
+
+          .badge {
+            padding: 2px 6px;
+            border-radius: 4px;
+            font-size: 10px;
+            color: white;
+            
+            &.badge-success { background: var(--success-color); }
+            &.badge-soft-decor { background: #FF6B6B; }
+            &.badge-hard-decor { background: #4ECDC4; }
+            &.badge-other { background: var(--medium-color); }
+            &.badge-style { background: #FFD93D; color: var(--dark-color); }
+            &.badge-space { background: #6C5CE7; }
+            &.badge-material { background: #A8E6CF; color: var(--dark-color); }
+            &.badge-default { background: var(--medium-color); }
+          }
+          
+          .btn-icon {
+            width: 28px;
+            height: 28px;
+            border-radius: 50%;
+            border: none;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+            transition: transform 0.2s;
+            
+            &.btn-primary { background: var(--primary-color); color: white; }
+            &.btn-danger { background: var(--danger-color); color: white; }
+            
+            &:hover { transform: scale(1.1); }
+          }
+        }
+      }
+    }
+
+    .cad-files-list {
+      margin-bottom: 24px;
+      
+      .cad-file-item {
+        display: flex;
+        align-items: center;
+        padding: 12px;
+        background: white;
+        border: 1px solid var(--light-shade);
+        border-radius: 8px;
+        margin-bottom: 8px;
+
+        .cad-icon {
+          font-size: 24px;
+          color: var(--primary-color);
+          margin-right: 12px;
+        }
+
+        .cad-info {
+          flex: 1;
+          
+          .cad-name {
+            font-size: 14px;
+            font-weight: 500;
+            color: var(--dark-color);
+            margin-bottom: 2px;
+          }
+          
+          .cad-meta {
+            font-size: 12px;
+            color: var(--medium-color);
+            display: flex;
+            align-items: center;
+            gap: 8px;
+          }
+        }
+        
+        .btn-icon {
+          width: 32px;
+          height: 32px;
+          border-radius: 50%;
+          border: none;
+          background: transparent;
+          color: var(--medium-color);
+          cursor: pointer;
+          
+          &:hover {
+             background: rgba(var(--danger-color), 0.1);
+             color: var(--danger-color);
+          }
+          
+          &.btn-danger {
+             color: var(--danger-color);
+          }
+        }
+      }
+    }
+
+    .empty-state {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      padding: 32px;
+      color: var(--medium-color);
+      background: white;
+      border-radius: 8px;
+      border: 1px solid var(--light-shade);
+
+      ion-icon {
+        font-size: 32px;
+        margin-bottom: 8px;
+        opacity: 0.5;
+      }
+
+      p {
+        font-size: 13px;
+        margin: 0;
+      }
+    }
+
+    .section-divider {
+      height: 1px;
+      background: var(--light-shade);
+      margin: 24px 0;
+    }
+
+    .ai-analysis-section {
+      .analysis-results-list {
+        .analysis-item-card {
+          display: grid;
+          grid-template-columns: 120px 1fr;
+          gap: 16px;
+          padding: 16px;
+          background: white;
+          border-radius: 8px;
+          border: 1px solid var(--light-shade);
+          margin-bottom: 12px;
+
+          .analysis-image {
+             width: 100%;
+             height: 120px;
+             border-radius: 6px;
+             overflow: hidden;
+             
+             img {
+               width: 100%;
+               height: 100%;
+               object-fit: cover;
+             }
+          }
+
+          .analysis-results-section {
+            .analysis-header-box {
+               margin-bottom: 12px;
+               .header-info {
+                 display: flex;
+                 align-items: center;
+                 gap: 8px;
+                 font-size: 12px;
+                 color: var(--medium-color);
+                 
+                 .info-value { color: var(--dark-color); font-weight: 500; }
+               }
+            }
+
+            .analysis-details-content {
+               .analysis-group {
+                 margin-bottom: 12px;
+                 h6 { font-size: 12px; color: var(--medium-color); margin: 0 0 8px; }
+                 
+                 .analysis-grid {
+                   display: grid;
+                   grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+                   gap: 8px;
+                   
+                   .analysis-row {
+                     font-size: 12px;
+                     .label { color: var(--medium-color); margin-right: 4px; }
+                     .value { color: var(--dark-color); }
+                   }
+                 }
+                 
+                 .analysis-tags {
+                   display: flex;
+                   flex-wrap: wrap;
+                   gap: 6px;
+                   
+                   .tag {
+                     font-size: 11px;
+                     padding: 2px 8px;
+                     background: var(--light-color);
+                     border-radius: 4px;
+                     color: var(--dark-color);
+                   }
+                 }
+                 
+                 .color-scheme-display {
+                   .color-row {
+                     display: flex;
+                     align-items: center;
+                     gap: 8px;
+                     margin-bottom: 4px;
+                     
+                     .color-label { font-size: 11px; color: var(--medium-color); width: 50px; }
+                     .color-samples {
+                       display: flex;
+                       gap: 4px;
+                       
+                       .color-sample {
+                         width: 16px;
+                         height: 16px;
+                         border-radius: 4px;
+                         border: 1px solid rgba(0,0,0,0.1);
+                       }
+                     }
+                   }
+                 }
+               }
+            }
+          }
+        }
+      }
+    }
+
+    .user-notes-section {
+      .form-textarea {
+        width: 100%;
+        padding: 12px;
+        border: 1px solid var(--light-shade);
+        border-radius: 8px;
+        font-size: 14px;
+        resize: vertical;
+        
+        &:focus {
+          outline: none;
+          border-color: var(--primary-color);
+        }
+        
+        &:disabled {
+          background: var(--light-color);
+          cursor: not-allowed;
+        }
+      }
+    }
+  }
+}

+ 232 - 0
src/modules/project/pages/project-detail/stages/components/space-requirement-item/space-requirement-item.component.ts

@@ -0,0 +1,232 @@
+import { Component, OnInit, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { IonIcon } from '@ionic/angular/standalone';
+import { Project } from '../../../../../services/product-space.service';
+import { addIcons } from 'ionicons';
+import { add, trash, cloudUpload, documentText, image, sparkles, colorPalette, document as documentIcon, chevronDown, chevronForward } from 'ionicons/icons';
+
+addIcons({
+  add, trash, 'cloud-upload': cloudUpload, 'document-text': documentText, image, sparkles, 'color-palette': colorPalette, document: documentIcon, 'chevron-down': chevronDown, 'chevron-forward': chevronForward
+});
+
+@Component({
+  selector: 'app-space-requirement-item',
+  standalone: true,
+  imports: [CommonModule, FormsModule, ReactiveFormsModule, IonIcon],
+  templateUrl: './space-requirement-item.component.html',
+  styleUrls: ['./space-requirement-item.component.scss'],
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class SpaceRequirementItemComponent implements OnInit {
+  @Input() space: any = null; // Project/Product object
+  @Input() canEdit: boolean = true;
+  @Input() images: any[] = [];
+  @Input() cadFiles: any[] = [];
+  @Input() analysisResults: any[] = [];
+  @Input() specialRequirements: string = '';
+  @Input() isExpanded: boolean = false;
+
+  @Output() toggleExpand = new EventEmitter<string>();
+  @Output() uploadImages = new EventEmitter<{spaceId: string, files: File[], type?: string}>();
+  @Output() uploadCAD = new EventEmitter<{spaceId: string, files: File[]}>();
+  @Output() deleteImage = new EventEmitter<string>();
+  @Output() deleteCAD = new EventEmitter<string>();
+  @Output() specialRequirementsChange = new EventEmitter<{spaceId: string, content: string}>();
+  @Output() viewAnalysis = new EventEmitter<string>();
+  @Output() openAiDialog = new EventEmitter<any>();
+
+  activeImageTab: string = 'all';
+  isDragOver: boolean = false;
+  uploading: boolean = false;
+
+  imageTypes = [
+    { id: 'all', name: '全部' },
+    { id: 'soft_decor', name: '软装' },
+    { id: 'hard_decor', name: '硬装' },
+    { id: 'cad', name: 'CAD' },
+    { id: 'other', name: '其他' }
+  ];
+
+  constructor() {}
+
+  ngOnInit() {}
+
+  toggleExpansion(event?: Event) {
+    if (event) {
+      event.stopPropagation();
+    }
+    this.toggleExpand.emit(this.space.id);
+  }
+
+  getSpaceDisplayName(): string {
+    return this.space?.name || '未命名空间';
+  }
+
+  getTotalFileCount(): number {
+    return (this.images?.length || 0) + (this.cadFiles?.length || 0);
+  }
+
+  // Tab Handling
+  selectImageTab(tabId: string) {
+    this.activeImageTab = tabId;
+  }
+
+  getImageCountByType(typeId: string): number {
+    if (typeId === 'all') {
+      return this.images.length;
+    } else if (typeId === 'cad') {
+      return this.cadFiles.length;
+    } else {
+      return this.images.filter(img => img.type === typeId).length;
+    }
+  }
+
+  getFilteredImages(): any[] {
+    if (this.activeImageTab === 'all') {
+      return this.images;
+    }
+    return this.images.filter(img => img.type === this.activeImageTab);
+  }
+
+  // Drag and Drop
+  onDragOver(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.isDragOver = true;
+  }
+
+  onDragLeave(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.isDragOver = false;
+  }
+
+  onDrop(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.isDragOver = false;
+
+    const files = event.dataTransfer?.files;
+    if (!files || files.length === 0) return;
+
+    // Separate images and CADs
+    const imageFiles: File[] = [];
+    const cadFilesList: File[] = [];
+
+    for (let i = 0; i < files.length; i++) {
+      const file = files[i];
+      if (file.type.startsWith('image/')) {
+        imageFiles.push(file);
+      } else if (this.isCADFile(file)) {
+        cadFilesList.push(file);
+      }
+    }
+
+    if (imageFiles.length > 0) {
+      this.uploadImages.emit({ spaceId: this.space.id, files: imageFiles });
+    }
+    if (cadFilesList.length > 0) {
+      this.uploadCAD.emit({ spaceId: this.space.id, files: cadFilesList });
+    }
+  }
+
+  isCADFile(file: File): boolean {
+    const fileName = file.name.toLowerCase();
+    const cadExtensions = ['.dwg', '.dxf', '.rvt', '.ifc', '.step', '.stp', '.iges', '.igs', '.pdf'];
+    const cadMimeTypes = [
+      'application/vnd.autodesk.autocad.drawing',
+      'application/vnd.autodesk.autocad.drawing.macroenabled',
+      'application/pdf',
+      'application/x-pdf'
+    ];
+    return cadExtensions.some(ext => fileName.endsWith(ext)) || cadMimeTypes.includes(file.type);
+  }
+
+  // File Inputs
+  triggerFileClick(elementId: string) {
+    const element = window.document.getElementById(elementId) as HTMLInputElement;
+    if (element) {
+      element.click();
+    }
+  }
+
+  onImageFileSelected(event: any, type?: string) {
+    const files = event.target.files;
+    if (files && files.length > 0) {
+      // Convert FileList to array
+      const fileArray = Array.from(files) as File[];
+      this.uploadImages.emit({ spaceId: this.space.id, files: fileArray, type });
+    }
+    event.target.value = '';
+  }
+
+  onCADFileSelected(event: any) {
+    const files = event.target.files;
+    if (files && files.length > 0) {
+      const fileArray = Array.from(files) as File[];
+      this.uploadCAD.emit({ spaceId: this.space.id, files: fileArray });
+    }
+    event.target.value = '';
+  }
+
+  // Special Requirements
+  onSpecialRequirementsChange(value: string) {
+    this.specialRequirementsChange.emit({ spaceId: this.space.id, content: value });
+  }
+
+  // Labels
+  getImageTypeLabel(type: string): string {
+    const typeMap: { [key: string]: string } = {
+      'all': '全部',
+      'soft_decor': '软装',
+      'hard_decor': '硬装',
+      'cad': 'CAD',
+      'other': '其他',
+      'style': '风格',
+      'space': '空间',
+      'material': '材质'
+    };
+    return typeMap[type] || type;
+  }
+
+  getImageTypeBadgeClass(type: string): string {
+    const classMap: { [key: string]: string } = {
+      'soft_decor': 'badge-soft-decor',
+      'hard_decor': 'badge-hard-decor',
+      'other': 'badge-other',
+      'style': 'badge-style',
+      'space': 'badge-space',
+      'material': 'badge-material'
+    };
+    return classMap[type] || 'badge-default';
+  }
+
+  // Helpers
+  hasImageAnalysis(imageId: string): boolean {
+    return this.analysisResults.some(r => r.imageId === imageId);
+  }
+  
+  getImageAnalysisResults(): any[] {
+    return this.analysisResults;
+  }
+  
+  getImageUrl(imageId: string): string {
+    // Find image url from analysis ID (which is imageId) in local images list
+    const img = this.images.find(i => i.id === imageId);
+    return img ? img.url : '';
+  }
+
+  getImageType(imageId: string): string {
+     const img = this.images.find(i => i.id === imageId);
+     return img ? img.type : 'other';
+  }
+
+  formatFileSize(bytes: number): string {
+    if (bytes === 0) return '0 B';
+    const k = 1024;
+    const sizes = ['B', 'KB', 'MB', 'GB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  }
+}

+ 91 - 264
src/modules/project/pages/project-detail/stages/stage-delivery-new.component.html

@@ -29,40 +29,26 @@
   }
 
   @if (!loading) {
-    <!-- 🆕 空间列表(可折叠展开,显示4个阶段) -->
+    <!-- 🆕 空间列表(智能网格视图) -->
     @if (projectProducts.length > 0) {
       <div class="spaces-list-section">
         @for (space of projectProducts; track space.id) {
           <div class="space-card">
-            <!-- 空间头部(显示空间名和四个阶段名称) -->
+            <!-- 空间头部 -->
             <div class="space-header" (click)="toggleSpaceExpansion(space.id)">
-              <!-- 空间名称 -->
-              <div class="space-name-section">
+              <div class="space-title">
                 {{ getSpaceDisplayName(space) }}
-                <!-- 完成进度显示 -->
-                <span class="completion-badge">
-                  {{ getCompletedStagesCount(space.id) }}/4
-                </span>
-              </div>
-
-              <!-- 四个阶段名称(横向排列) -->
-              <div class="stage-names-row">
-                @for (type of deliveryTypes; track type.id) {
-                  <div class="stage-name-item"
-                       [class.has-files]="getSpaceStageFileCount(space.id, type.id) > 0">
-                    <span class="stage-label">{{ type.name }}</span>
-                    @if (getSpaceStageFileCount(space.id, type.id) > 0) {
-                      <span class="mini-badge">{{ getSpaceStageFileCount(space.id, type.id) }}</span>
-                    }
-                  </div>
+                @if (space.area) {
+                   <span class="space-badge">{{ space.area }}㎡</span>
                 }
               </div>
-
-              <!-- 展开/收起图标 -->
-              <div class="expand-icon" [class.expanded]="isSpaceExpanded(space.id)">
-                <svg width="28" height="28" viewBox="0 0 24 24" fill="currentColor">
-                  <path d="M7 10l5 5 5-5z"/>
-                </svg>
+              <div class="space-header-right">
+                <span class="progress-text">{{ getCompletedStagesCount(space.id) }}/4 完成</span>
+                <div class="expand-icon" [class.expanded]="isSpaceExpanded(space.id)">
+                  <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
+                    <path d="M7 10l5 5 5-5z"/>
+                  </svg>
+                </div>
               </div>
             </div>
 
@@ -83,180 +69,98 @@
                           <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
                         </svg>
                       </div>
-                      <h3>拖拽到 {{ getSpaceDisplayName(space) }}</h3>
-                      <p>AI将自动分析图片并智能分类到合适的阶段</p>
+                      <h3>拖拽到此处</h3>
+                      <p>AI自动归类</p>
                     </div>
                   </div>
                 }
                 
-                <!-- 4个阶段区域(横向排列,每个阶段独立显示) -->
-                <div class="stages-container">
+                <!-- 4个阶段网格(2x2布局) -->
+                <div class="stages-grid">
                   @for (type of deliveryTypes; track type.id) {
-                    <div class="stage-section"
-                         [class.has-files]="getSpaceStageFileCount(space.id, type.id) > 0">
-                      <!-- 阶段头部 -->
-                      <div class="stage-header" 
-                           [class.clickable]="getSpaceStageFileCount(space.id, type.id) > 0"
-                           (click)="getSpaceStageFileCount(space.id, type.id) > 0 ? openStageGallery(space.id, type.id, $event) : null">
-                        <div class="stage-title">
-                          <span class="stage-name">{{ type.name }}</span>
-                          @if (getSpaceStageFileCount(space.id, type.id) > 0) {
-                            <span class="file-count-badge">{{ getSpaceStageFileCount(space.id, type.id) }}</span>
-                          }
-                        </div>
+                    <div class="stage-item"
+                         [class.completed]="getSpaceStageFileCount(space.id, type.id) > 0"
+                         [class.pending]="getSpaceStageFileCount(space.id, type.id) === 0"
+                         [class.drag-over]="isDragOver && selectedSpaceId === space.id && selectedStageType === type.id"
+                         (dragover)="onDragOver($event, space.id, type.id)"
+                         (dragleave)="onDragLeave($event)"
+                         (drop)="onDrop($event, space.id, type.id)">
+
+                      <!-- 阶段标题与状态 -->
+                      <div class="stage-label">
+                        <span>{{ type.name }}</span>
                         @if (getSpaceStageFileCount(space.id, type.id) > 0) {
-                          <div class="view-all-hint">
-                            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
-                              <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>
-                            </svg>
-                            <span>查看全部</span>
-                          </div>
+                          <span class="status-icon icon-check">✓</span>
                         }
                       </div>
 
-                      <!-- 阶段内容区域 -->
-                      <div class="stage-body"
-                           (dragover)="onDragOver($event, space.id, type.id)"
-                           (dragleave)="onDragLeave($event)"
-                           (drop)="onDrop($event, space.id, type.id)"
-                           [class.drag-over]="isDragOver && selectedSpaceId === space.id && selectedStageType === type.id"
-                           (click)="selectSpaceAndStage(space.id, type.id)">
-
-                        <!-- 拖拽提示覆盖层 -->
-                        @if (isDragOver && selectedSpaceId === space.id && selectedStageType === type.id) {
-                          <div class="drag-overlay">
-                            <div class="drag-hint">
-                              <div class="drag-icon">
-                                <svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor">
-                                  <path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/>
-                                </svg>
-                              </div>
-                              <p>释放上传</p>
+                      <!-- 文件预览或上传操作 -->
+                      @if (getSpaceStageFileCount(space.id, type.id) > 0) {
+                        <div class="preview-strip">
+                          <!-- 显示前2张图片 -->
+                          @for (file of getProductDeliveryFiles(space.id, type.id) | slice:0:2; track file.id) {
+                            <div class="mini-thumb-wrapper" (click)="previewFile(file); $event.stopPropagation()">
+                              @if (isImageFile(file.name)) {
+                                <img [src]="file.url" class="mini-thumb" (error)="onImageError($event)" />
+                              } @else {
+                                <div class="mini-thumb file-icon">
+                                  <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
+                                    <path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/>
+                                  </svg>
+                                </div>
+                              }
                             </div>
-                          </div>
-                        }
-
-                        <!-- 文件上传按钮 -->
-                        @if (canEdit && getSpaceStageFileCount(space.id, type.id) === 0) {
-                          <div class="upload-zone-compact">
-                            <input
-                              type="file"
-                              multiple
-                              (change)="uploadDeliveryFile($event, space.id, type.id)"
-                              [accept]="'image/*,.pdf,.dwg,.dxf,.skp,.max'"
-                              [disabled]="uploadingDeliveryFiles"
-                              hidden
-                              #fileInput />
-
-                            <button class="upload-btn-compact" (click)="fileInput.click(); $event.stopPropagation()" [disabled]="uploadingDeliveryFiles">
-                              <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
-                                <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+                          }
+                          <!-- 添加按钮/查看更多 -->
+                          <div class="add-box" (click)="openStageGallery(space.id, type.id, $event)">
+                            @if (canEdit) {
+                              <span>+</span>
+                            } @else {
+                              <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
+                                <path d="M5 10h14v2H5z"/> <!-- Simple view icon or dots -->
+                                <circle cx="12" cy="12" r="2"/>
+                                <circle cx="19" cy="12" r="2"/>
+                                <circle cx="5" cy="12" r="2"/>
                               </svg>
-                              <span>上传{{ type.name }}</span>
-                            </button>
-                          </div>
-                        }
-
-                        <!-- 文件预览(缩略图) -->
-                        @if (getSpaceStageFileCount(space.id, type.id) > 0) {
-                          <div class="files-preview">
-                            @for (file of getProductDeliveryFiles(space.id, type.id).slice(0, 4); track file.id) {
-                              <div class="file-thumbnail" (click)="previewFile(file); $event.stopPropagation()">
-                                @if (isImageFile(file.name)) {
-                                  <img [src]="file.url" [alt]="file.name" class="thumbnail-img" (error)="onImageError($event)" />
-                                } @else {
-                                  <div class="thumbnail-placeholder">
-                                    <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
-                                      <path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/>
-                                    </svg>
-                                  </div>
-                                }
-                                <!-- 快捷发送图片按钮 -->
-                                @if (canEdit && isImageFile(file.name)) {
-                                  <button class="send-image-btn" (click)="sendSingleImage(space.id, type.id, file.url, $event); $event.stopPropagation()" title="发送图片(普通点击:选择话术 | Shift+点击:直接发送)">
-                                    <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
-                                      <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
-                                    </svg>
-                                  </button>
-                                }
-                                @if (canEdit) {
-                                  <button class="delete-thumbnail-btn" (click)="deleteDeliveryFile(space.id, type.id, file.id); $event.stopPropagation()">
-                                    <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
-                                      <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
-                                    </svg>
-                                  </button>
-                                }
-                              </div>
-                            }
-                            @if (getSpaceStageFileCount(space.id, type.id) > 4) {
-                              <div class="more-files-indicator">
-                                +{{ getSpaceStageFileCount(space.id, type.id) - 4 }}
-                              </div>
                             }
                           </div>
-
-                          <!-- 添加更多文件和发送消息按钮 -->
-                          @if (canEdit) {
-                            <div class="add-more-files">
-                              <input
+                        </div>
+                      } @else {
+                        <!-- 空状态:点击上传 -->
+                        @if (canEdit) {
+                           <div class="upload-action" (click)="fileInput.click(); $event.stopPropagation()">
+                             <input
                                 type="file"
                                 multiple
                                 (change)="uploadDeliveryFile($event, space.id, type.id)"
                                 [accept]="'image/*,.pdf,.dwg,.dxf,.skp,.max'"
                                 [disabled]="uploadingDeliveryFiles"
                                 hidden
-                                #fileInputMore />
-                              <button class="add-more-btn" (click)="fileInputMore.click(); $event.stopPropagation()" [disabled]="uploadingDeliveryFiles">
-                                <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
-                                  <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
-                                </svg>
-                                添加文件
-                              </button>
-                              <button class="send-message-btn" (click)="openMessageModalWithFiles(space.id, type.id); $event.stopPropagation()">
-                                <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
-                                  <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
-                                </svg>
-                                发送消息
-                              </button>
-                            </div>
-                          }
+                                #fileInput />
+                             <span>📤 点击上传</span>
+                           </div>
+                        } @else {
+                           <div class="empty-action">
+                             <span>暂无文件</span>
+                           </div>
                         }
-
-                        <!-- 空状态提示 -->
-                        @if (getSpaceStageFileCount(space.id, type.id) === 0 && !canEdit) {
-                          <div class="empty-stage-hint">
-                            <svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor" opacity="0.3">
-                              <path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/>
-                            </svg>
-                            <p>暂无文件</p>
-                          </div>
-                        }
-                      </div>
+                      }
                     </div>
                   }
                 </div>
 
-                <!-- 统一的交付执行清单确认按钮(在所有阶段下方) -->
+                <!-- 交付执行清单确认按钮 -->
                 <div class="space-confirm-section">
                   @if (!isSpaceConfirmed(space.id)) {
                     <button
                       class="confirm-space-btn"
                       (click)="confirmSpace(space.id)"
                       [disabled]="saving || getSpaceTotalFileCount(space.id) === 0">
-                      <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
-                        <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
-                      </svg>
-                      <span>交付执行清单确认</span>
+                      <span>确认清单</span>
                     </button>
                   } @else {
                     <div class="confirmed-info">
-                      <div class="confirmed-header">
-                        <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
-                          <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
-                        </svg>
-                        <span class="confirmed-text">已确认</span>
-                      </div>
-                      <div class="confirmed-details">{{ getSpaceConfirmationText(space.id) }}</div>
+                      <span class="confirmed-text">✓ 已确认</span>
                     </div>
                   }
                 </div>
@@ -271,18 +175,17 @@
     @if (projectProducts.length === 0 && !loading) {
       <div class="no-products-state">
         <div class="state-icon">
-          <svg class="icon" width="64" height="64" viewBox="0 0 24 24">
+          <svg class="icon" width="48" height="48" viewBox="0 0 24 24">
             <path fill="currentColor" d="M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2Z"/>
           </svg>
         </div>
-        <h3>暂无项目空间</h3>
-        <p>请先在方案深化阶段添加项目空间</p>
+        <p>暂无项目空间</p>
       </div>
     }
   }
 </div>
 
-<!-- 拖拽上传弹窗(增强版,支持AI识别和多空间选择) -->
+<!-- 拖拽上传弹窗 -->
 <app-drag-upload-modal
   [visible]="showDragUploadModal"
   [droppedFiles]="dragUploadFiles"
@@ -305,13 +208,9 @@
       <div class="gallery-header">
         <div class="gallery-title">
           <h3>{{ currentStageGallery.stageName }} - {{ currentStageGallery.spaceName }}</h3>
-          <p>{{ currentStageGallery.files.length }} 个文件</p>
+          <p>{{ currentStageGallery.files.length }} 个文件</p>
         </div>
-        <button class="close-btn" (click)="closeStageGallery()">
-          <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
-            <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
-          </svg>
-        </button>
+        <button class="close-btn" (click)="closeStageGallery()">×</button>
       </div>
       
       <!-- 图片网格 -->
@@ -324,38 +223,30 @@
                   <img [src]="file.url" [alt]="file.name" class="gallery-image" (error)="onImageError($event)" />
                 } @else {
                   <div class="file-placeholder">
-                    <svg width="48" height="48" viewBox="0 0 24 24" fill="currentColor">
+                    <svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor">
                       <path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/>
                     </svg>
                   </div>
                 }
                 <div class="image-info">
                   <div class="file-name" [title]="file.name">{{ file.name }}</div>
-                  <div class="file-size">{{ formatFileSize(file.size) }}</div>
                 </div>
                 @if (canEdit) {
-                  <button class="delete-image-btn" (click)="deleteDeliveryFile(currentStageGallery!.spaceId, currentStageGallery!.stageId, file.id); $event.stopPropagation()">
-                    <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
-                      <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
-                    </svg>
-                  </button>
+                  <button class="delete-image-btn" (click)="deleteDeliveryFile(currentStageGallery!.spaceId, currentStageGallery!.stageId, file.id); $event.stopPropagation()">×</button>
                 }
               </div>
             }
           </div>
         } @else {
           <div class="empty-gallery">
-            <svg width="64" height="64" viewBox="0 0 24 24" fill="currentColor" opacity="0.3">
-              <path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/>
-            </svg>
-            <p>该阶段暂无文件</p>
+            <p>暂无文件</p>
           </div>
         }
       </div>
       
       <!-- 模态框底部 -->
       <div class="gallery-footer">
-        @if (canEdit && currentStageGallery.files.length > 0) {
+        @if (canEdit) {
           <div class="gallery-actions">
             <input
               type="file"
@@ -366,14 +257,10 @@
               hidden
               #galleryFileInput />
             <button class="add-files-btn" (click)="galleryFileInput.click()" [disabled]="uploadingDeliveryFiles">
-              <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
-                <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
-              </svg>
               添加更多文件
             </button>
           </div>
         }
-        <button class="close-gallery-btn" (click)="closeStageGallery()">关闭</button>
       </div>
     </div>
   </div>
@@ -389,7 +276,7 @@
   (created)="onRevisionTaskCreated($event)">
 </app-revision-task-modal>
 
-<!-- 改图工单列表(全屏显示) -->
+<!-- 改图工单列表 -->
 @if (showRevisionTaskList) {
   <div class="revision-list-fullscreen">
     <app-revision-task-list
@@ -411,81 +298,21 @@
         <h4>发送消息</h4>
         <button class="close-btn" (click)="closeMessageModal()">×</button>
       </div>
-      
       <div class="modal-body">
-        <!-- 阶段信息 -->
-        <div class="stage-info-section">
-          <div class="info-item">
-            <span class="label">空间:</span>
-            <span class="value">{{ messageModalConfig.spaceName }}</span>
-          </div>
-          <div class="info-item">
-            <span class="label">阶段:</span>
-            <span class="value">{{ messageModalConfig.stageName }}</span>
-          </div>
-          @if (messageModalConfig.imageUrls.length > 0) {
-            <div class="info-item">
-              <span class="label">图片:</span>
-              <span class="value">{{ messageModalConfig.imageUrls.length }} 张</span>
-            </div>
-          }
-        </div>
-        
-        <!-- 预设话术 -->
-        <div class="template-section">
-          <label class="section-label">选择话术(可选):</label>
-          <div class="template-options">
-            @for (template of deliveryMessageService.getStageTemplates(messageModalConfig.stage); track template) {
-              <button class="template-option" 
-                      [class.active]="selectedTemplate === template"
-                      (click)="selectTemplate(template)">
-                {{ template }}
-              </button>
-            }
-          </div>
-        </div>
-        
-        <!-- 自定义消息 -->
-        <div class="custom-message-section">
-          <label class="section-label">自定义消息:</label>
-          <textarea 
+         <!-- 简化版消息发送界面,适配侧边栏 -->
+         <div class="info-item">
+            <span class="label">发送图片:</span>
+            <span class="value">{{ messageModalConfig.imageUrls.length }} 张</span>
+         </div>
+         <textarea 
             [(ngModel)]="customMessage" 
-            placeholder="输入自定义消息,如不填写将使用选中的话术..."
-            rows="4"
-            maxlength="500"></textarea>
-          <div class="char-count">{{ customMessage.length }}/500</div>
-        </div>
-        
-        <!-- 预览图片(如果有) -->
-        @if (messageModalConfig.imageUrls.length > 0) {
-          <div class="preview-images-section">
-            <label class="section-label">将发送的图片:</label>
-            <div class="preview-images-grid">
-              @for (url of messageModalConfig.imageUrls.slice(0, 6); track url) {
-                <img [src]="url" class="preview-img" />
-              }
-              @if (messageModalConfig.imageUrls.length > 6) {
-                <div class="more-images">
-                  +{{ messageModalConfig.imageUrls.length - 6 }}
-                </div>
-              }
-            </div>
-          </div>
-        }
+            placeholder="输入消息..."
+            rows="3"
+            style="width:100%;margin-top:10px;padding:8px;border:1px solid #e2e8f0;border-radius:6px;"></textarea>
       </div>
-      
       <div class="modal-footer">
         <button class="btn-cancel" (click)="closeMessageModal()">取消</button>
-        <button class="btn-send" 
-                (click)="sendMessage()" 
-                [disabled]="sendingMessage || (!customMessage.trim() && !selectedTemplate && messageModalConfig.imageUrls.length === 0)">
-          @if (sendingMessage) {
-            <span class="spinner-small"></span>
-            <span>发送中...</span>
-          } @else {
-            <span>发送</span>
-          }
-        </button>
+        <button class="btn-send" (click)="sendMessage()" [disabled]="sendingMessage">发送</button>
       </div>
     </div>
   </div>

+ 372 - 1997
src/modules/project/pages/project-detail/stages/stage-delivery-new.component.scss

@@ -1,2189 +1,564 @@
 .stage-delivery-container {
-  padding: 20px;
-  background-color: #f5f7fa;
+  padding: 12px;
+  background-color: #eef0f4;
   min-height: 100vh;
-  
-  // 🔥 企业微信端响应式:减小padding
-  @media screen and (max-width: 768px) {
-    padding: 12px !important;
-  }
-  
+
   @media screen and (max-width: 480px) {
-    padding: 8px !important;
+    padding: 8px;
   }
-  
-  // 改图工单工具栏
+
+  // Revision Toolbar
   .revision-toolbar {
     display: flex;
-    gap: 12px;
-    margin-bottom: 20px;
-    
-    // 🔥 企业微信端响应式
-    @media screen and (max-width: 768px) {
-      gap: 8px !important;
-      margin-bottom: 12px !important;
-    }
-    
+    gap: 8px;
+    margin-bottom: 12px;
+
     button {
-      padding: 10px 16px;
+      padding: 8px 12px;
       border: none;
-      border-radius: 8px;
-      font-size: 14px;
+      border-radius: 6px;
+      font-size: 13px;
       font-weight: 500;
       cursor: pointer;
-      transition: all 0.2s;
       display: flex;
       align-items: center;
-      gap: 8px;
-      
-      // 🔥 企业微信端响应式
-      @media screen and (max-width: 768px) {
-        padding: 8px 12px !important;
-        font-size: 13px !important;
-        
-        span {
-          display: none !important; // 隐藏文字,只显示图标
-        }
-      }
-      
-      svg {
-        flex-shrink: 0;
-        
-        // 🔥 企业微信端响应式
-        @media screen and (max-width: 768px) {
-          width: 16px !important;
-          height: 16px !important;
-        }
-      }
+      gap: 6px;
+      transition: all 0.2s;
     }
-    
+
     .btn-create-revision {
       background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
       color: white;
-      box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
-      
+      box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3);
+
       &:hover {
         transform: translateY(-1px);
-        box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
-      }
-      
-      &:active {
-        transform: translateY(0);
       }
     }
-    
+
     .btn-view-revisions {
       background: white;
       color: #4f46e5;
       border: 1px solid #e5e7eb;
       position: relative;
-      
-      &:hover {
-        background: #f9fafb;
-        border-color: #4f46e5;
-      }
-      
+
       .task-count-badge {
         position: absolute;
         top: -6px;
         right: -6px;
-        min-width: 20px;
-        height: 20px;
-        padding: 0 6px;
         background: #ef4444;
         color: white;
         border-radius: 10px;
-        font-size: 11px;
-        font-weight: 600;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        box-shadow: 0 2px 4px rgba(239, 68, 68, 0.3);
+        padding: 2px 6px;
+        font-size: 10px;
+        font-weight: 700;
       }
     }
   }
 
-  // 加载状态
+  // Loading State
   .loading-state {
     display: flex;
     flex-direction: column;
     align-items: center;
     justify-content: center;
-    padding: 60px 20px;
+    padding: 40px 20px;
     
     .spinner {
-      width: 48px;
-      height: 48px;
-      border: 4px solid #e0e0e0;
+      width: 32px; height: 32px;
+      border: 3px solid #e2e8f0;
       border-top-color: #667eea;
       border-radius: 50%;
       animation: spin 0.8s linear infinite;
     }
     
-    p {
-      margin-top: 16px;
-      color: #64748b;
-      font-size: 14px;
-    }
+    p { margin-top: 12px; font-size: 13px; color: #64748b; }
   }
 
-  @keyframes spin {
-    to { transform: rotate(360deg); }
-  }
+  @keyframes spin { to { transform: rotate(360deg); } }
 
-  // ==================== 🆕 空间列表样式 ====================
+  // ==================== 🆕 Spaces List (Smart Grid) ====================
   .spaces-list-section {
     display: flex;
     flex-direction: column;
-    gap: 24px;
+    gap: 12px;
 
-    // 空间卡片
     .space-card {
       background: white;
-      border-radius: 16px;
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-      overflow: hidden;
-      transition: all 0.3s ease;
-
-      &:hover {
-        box-shadow: 0 4px 16px rgba(102, 126, 234, 0.15);
-      }
-    }
-
-    // 空间头部(显示空间名和四个阶段名称)
-    .space-header {
-      display: flex;
-      align-items: center;
-      gap: 20px;
-      padding: 20px 28px;
-      background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
-      border: 2px solid #e2e8f0;
-      cursor: pointer;
-      transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
       border-radius: 12px;
-      position: relative;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
       overflow: hidden;
-      
-      // 🔥 企业微信端响应式:改为竖向布局
-      @media screen and (max-width: 768px) {
-        flex-direction: column !important;
-        align-items: stretch !important;
-        gap: 12px !important;
-        padding: 12px 16px 48px 16px !important; // 底部留空间给展开图标
-      }
-
-      // 顶部装饰条
-      &::before {
-        content: '';
-        position: absolute;
-        top: 0;
-        left: 0;
-        right: 0;
-        height: 4px;
-        background: linear-gradient(90deg, #667eea 0%, #764ba2 50%, #667eea 100%);
-        background-size: 200% 100%;
-        transition: all 0.3s ease;
-      }
+      transition: box-shadow 0.2s;
 
       &:hover {
-        border-color: #667eea;
-        box-shadow: 0 8px 24px rgba(102, 126, 234, 0.15);
-        transform: translateY(-2px);
-
-        &::before {
-          animation: shimmer 2s linear infinite;
-        }
-
-        .expand-icon {
-          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-          color: white;
-          transform: scale(1.1);
-        }
+        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
       }
 
-      // 空间名称区域
-      .space-name-section {
+      // Header
+      .space-header {
         display: flex;
+        justify-content: space-between;
         align-items: center;
-        gap: 12px;
-        flex-shrink: 0;
-        min-width: 100px;
-        font-size: 18px;
-        font-weight: 700;
-        color: #1e293b;
-        padding-right: 20px;
-        border-right: 2px solid #e2e8f0;
-        letter-spacing: 0.3px;
-        
-        // 🔥 企业微信端响应式
-        @media screen and (max-width: 768px) {
-          flex-direction: row !important;
-          justify-content: space-between !important;
-          min-width: auto !important;
-          font-size: 16px !important;
-          padding-right: 0 !important;
-          border-right: none !important;
-          border-bottom: 1px solid #e2e8f0 !important;
-          padding-bottom: 8px !important;
+        padding: 14px 16px;
+        cursor: pointer;
+        background: white;
+        border-bottom: 1px solid transparent;
+        transition: all 0.2s;
+
+        &:hover {
+          background: #f9fafb;
         }
 
-        .completion-badge {
-          display: inline-flex;
+        .space-title {
+          font-size: 16px;
+          font-weight: 700;
+          color: #1e293b;
+          display: flex;
           align-items: center;
-          justify-content: center;
-          padding: 4px 10px;
-          background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%);
-          color: white;
-          font-size: 13px;
-          font-weight: 600;
-          border-radius: 12px;
-          box-shadow: 0 2px 6px rgba(82, 196, 26, 0.3);
-          animation: pulse-badge 2s ease-in-out infinite;
-          
-          // 🔥 企业微信端响应式
-          @media screen and (max-width: 768px) {
-            padding: 3px 8px !important;
-            font-size: 12px !important;
+          gap: 6px;
+
+          .space-badge {
+            font-size: 10px;
+            padding: 2px 6px;
+            background: #e0e7ff;
+            color: #6366f1;
+            border-radius: 4px;
+            font-weight: 500;
           }
         }
-      }
-
-      // 四个阶段名称横向排列
-      .stage-names-row {
-        flex: 1;
-        display: grid;
-        grid-template-columns: repeat(4, 1fr);
-        gap: 12px;
-        padding: 0 8px;
-        
-        // 🔥 企业微信端响应式:改为2列
-        @media screen and (max-width: 768px) {
-          grid-template-columns: repeat(2, 1fr) !important;
-          gap: 8px;
-          padding: 0;
-        }
 
-        .stage-name-item {
+        .space-header-right {
           display: flex;
           align-items: center;
-          justify-content: center;
           gap: 8px;
-          padding: 12px 16px;
-          background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-          border: 2px solid #e2e8f0;
-          border-radius: 10px;
-          transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-          position: relative;
-          overflow: hidden;
-
-          // 底部装饰条
-          &::after {
-            content: '';
-            position: absolute;
-            bottom: 0;
-            left: 0;
-            right: 0;
-            height: 3px;
-            background: linear-gradient(90deg, #cbd5e1 0%, #94a3b8 100%);
-            transition: all 0.3s ease;
-          }
-
-          .stage-label {
-            font-size: 15px;
-            font-weight: 600;
-            color: #475569;
-            letter-spacing: 0.3px;
-            transition: all 0.3s ease;
-          }
 
-          .mini-badge {
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            min-width: 24px;
-            height: 24px;
-            padding: 0 8px;
-            background: linear-gradient(135deg, #cbd5e1 0%, #94a3b8 100%);
-            color: white;
-            border-radius: 12px;
+          .progress-text {
             font-size: 12px;
-            font-weight: 700;
-            box-shadow: 0 2px 6px rgba(148, 163, 184, 0.3);
-            transition: all 0.3s ease;
-          }
-
-          // 有文件的阶段样式
-          &.has-files {
-            background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
-            border-color: #6ee7b7;
-            box-shadow: 0 2px 8px rgba(16, 185, 129, 0.15);
-
-            &::after {
-              background: linear-gradient(90deg, #10b981 0%, #059669 100%);
-            }
-
-            .stage-label {
-              color: #047857;
-              font-weight: 700;
-            }
-
-            .mini-badge {
-              background: linear-gradient(135deg, #10b981 0%, #059669 100%);
-              box-shadow: 0 2px 8px rgba(16, 185, 129, 0.4);
-              animation: pulse-badge 2s ease-in-out infinite;
-            }
+            color: #64748b;
           }
 
-          // 悬停效果(仅在未展开时)
-          &:hover {
-            transform: translateY(-2px);
-            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
-            border-color: #667eea;
-
-            &::after {
-              background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
-            }
-
-            .stage-label {
-              color: #667eea;
+          .expand-icon {
+            color: #94a3b8;
+            transition: transform 0.3s;
+            display: flex;
+            
+            &.expanded {
+              transform: rotate(180deg);
             }
           }
         }
       }
 
-      // 展开/收起图标
-      .expand-icon {
-        flex-shrink: 0;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        width: 44px;
-        height: 44px;
-        background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
-        border: 2px solid #cbd5e1;
-        border-radius: 50%;
-        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-        
-        // 🔥 企业微信端响应式:移到右下角
-        @media screen and (max-width: 768px) {
-          position: absolute !important;
-          bottom: 12px !important;
-          right: 50% !important;
-          transform: translateX(50%) !important;
-          width: 32px !important;
-          height: 32px !important;
-        }
-
-        svg {
-          transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-          color: #64748b;
-        }
-
-        &.expanded svg {
-          transform: rotate(180deg);
-        }
-      }
-    }
-
-    // 空间内容(展开时显示)
-    .space-content {
-      padding: 24px;
-      animation: slideDown 0.3s ease-out;
-      position: relative;
-      transition: all 0.3s ease;
-      
-      // 🔥 企业微信端响应式
-      @media screen and (max-width: 768px) {
-        padding: 12px !important;
-      }
-      
-      @media screen and (max-width: 480px) {
-        padding: 8px !important;
-      }
-      
-      // 🔥 空间拖拽状态
-      &.space-drag-over {
-        background: rgba(102, 126, 234, 0.05);
-        border-radius: 16px;
-        box-shadow: inset 0 0 0 3px rgba(102, 126, 234, 0.3);
-      }
+      // Content
+      .space-content {
+        padding: 12px;
+        border-top: 1px solid #f1f5f9;
+        position: relative;
+        animation: slideDown 0.3s ease-out;
 
-      // 🆕 四个阶段区域容器(横向排列)
-      .stages-container {
-        display: grid;
-        grid-template-columns: repeat(4, 1fr);
-        gap: 16px;
-        margin-bottom: 32px;
-        
-        // 🔥 企业微信端响应式:改为2列
-        @media screen and (max-width: 768px) {
-          grid-template-columns: repeat(2, 1fr) !important;
-          gap: 12px !important;
-          margin-bottom: 16px;
-        }
-        
-        // 🔥 极窄屏幕:改为单列
-        @media screen and (max-width: 480px) {
-          grid-template-columns: 1fr !important;
-          gap: 10px !important;
+        &.space-drag-over {
+          background: #f8fafc;
         }
 
-        // 单个阶段区域
-        .stage-section {
-          background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
-          border: 2px solid #e2e8f0;
-          border-radius: 16px;
-          overflow: hidden;
-          transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
-          position: relative;
-
-          // 顶部装饰条
-          &::before {
-            content: '';
-            position: absolute;
-            top: 0;
-            left: 0;
-            right: 0;
-            height: 4px;
-            background: linear-gradient(90deg, #cbd5e1 0%, #94a3b8 100%);
-            transition: all 0.3s ease;
-          }
-
-          &:hover {
-            border-color: #667eea;
-            box-shadow: 0 8px 24px rgba(102, 126, 234, 0.15);
-            transform: translateY(-4px);
-
-            &::before {
-              background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
-            }
-          }
-
-          // 有文件的阶段
-          &.has-files {
-            background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);
-            border-color: #86efac;
-
-            &::before {
-              background: linear-gradient(90deg, #10b981 0%, #059669 100%);
-            }
-
-            .stage-header {
-              background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
-
-              .stage-name {
-                color: #065f46;
-              }
-
-              .file-count-badge {
-                background: linear-gradient(135deg, #10b981 0%, #059669 100%);
-                box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
-              }
+        // Drag Overlay
+        .space-drag-overlay {
+          position: absolute;
+          inset: 0;
+          background: rgba(255, 255, 255, 0.9);
+          z-index: 10;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          
+          .space-drag-hint {
+            text-align: center;
+            color: #6366f1;
+            .space-drag-icon { 
+               margin: 0 auto 8px; 
+               width: 48px; height: 48px; 
+               background: #e0e7ff; 
+               border-radius: 50%; 
+               display: flex; align-items: center; justify-content: center;
             }
+            h3 { margin: 0; font-size: 16px; }
+            p { margin: 4px 0 0; font-size: 12px; color: #64748b; }
           }
+        }
 
-          // 阶段头部
-          .stage-header {
-            background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-            padding: 12px 16px;
-            border-bottom: 1px solid #e2e8f0;
-            transition: all 0.3s ease;
-
-            .stage-title {
-              display: flex;
-              align-items: center;
-              justify-content: space-between;
-              gap: 8px;
-
-              .stage-name {
-                font-size: 15px;
-                font-weight: 700;
-                color: #475569;
-                letter-spacing: 0.3px;
-                transition: all 0.3s ease;
-              }
-
-              .file-count-badge {
-                display: inline-flex;
-                align-items: center;
-                justify-content: center;
-                min-width: 24px;
-                height: 24px;
-                padding: 0 8px;
-                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-                color: white;
-                border-radius: 12px;
-                font-size: 12px;
-                font-weight: 700;
-                box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3);
-                transition: all 0.3s ease;
-              }
-            }
-          }
+        // Grid Layout (2 Columns)
+        .stages-grid {
+          display: grid;
+          grid-template-columns: repeat(2, 1fr);
+          gap: 10px;
 
-          // 阶段内容区域
-          .stage-body {
-            padding: 16px;
-            min-height: 200px;
+          .stage-item {
+            background: #f9fafb;
+            border: 1px solid #e2e8f0;
+            border-radius: 8px;
+            padding: 10px;
             display: flex;
             flex-direction: column;
-            align-items: center;
-            justify-content: center;
+            gap: 8px;
             position: relative;
-            cursor: pointer;
-            transition: all 0.3s ease;
+            transition: all 0.2s;
+            min-height: 80px;
+
+            // Pending State
+            &.pending {
+              border-style: dashed;
+              border-color: #cbd5e1;
+              &:hover {
+                background: #f5f7ff;
+                border-color: #6366f1;
+              }
+            }
 
-            &:hover {
-              background: rgba(102, 126, 234, 0.02);
+            // Completed State
+            &.completed {
+              background: white;
+              border-color: #86efac; // Greenish border
+              box-shadow: 0 2px 4px rgba(16, 185, 129, 0.05);
             }
 
-            // 拖拽状态
+            // Drag Over State
             &.drag-over {
-              background: rgba(102, 126, 234, 0.08);
-              border: 2px dashed #667eea;
-              border-radius: 12px;
+              background: #e0e7ff;
+              border-color: #6366f1;
+              border-style: dashed;
+              box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
             }
 
-            // 拖拽提示覆盖层
-            .drag-overlay {
-              position: absolute;
-              top: 0;
-              left: 0;
-              right: 0;
-              bottom: 0;
-              background: rgba(102, 126, 234, 0.12);
-              backdrop-filter: blur(4px);
+            .stage-label {
+              font-size: 13px;
+              font-weight: 600;
+              color: #334155;
               display: flex;
+              justify-content: space-between;
               align-items: center;
-              justify-content: center;
-              z-index: 10;
-              border-radius: 12px;
-              animation: dragOverlay 0.3s ease-out;
-
-              .drag-hint {
-                text-align: center;
-                color: #667eea;
-
-                .drag-icon {
-                  margin-bottom: 8px;
-                  opacity: 0.9;
-
-                  svg {
-                    animation: bounce 1s ease-in-out infinite;
-                    color: #667eea;
-                  }
-                }
 
-                p {
-                  margin: 0;
-                  font-size: 13px;
-                  font-weight: 600;
-                  color: #667eea;
-                }
+              .status-icon {
+                width: 16px; height: 16px;
+                border-radius: 50%;
+                background: #10b981;
+                color: white;
+                font-size: 10px;
+                display: flex; align-items: center; justify-content: center;
               }
             }
 
-            // 紧凑型上传区域(无文件时显示)
-            .upload-zone-compact {
+            // Previews
+            .preview-strip {
               display: flex;
-              flex-direction: column;
-              align-items: center;
-              justify-content: center;
-              gap: 12px;
-              padding: 20px;
-
-              .upload-btn-compact {
-                display: flex;
-                align-items: center;
-                gap: 8px;
-                padding: 12px 24px;
-                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-                color: white;
-                border: none;
-                border-radius: 10px;
-                font-size: 14px;
-                font-weight: 600;
-                cursor: pointer;
-                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
-
-                &:hover:not(:disabled) {
-                  transform: translateY(-2px);
-                  box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
-                  background: linear-gradient(135deg, #5568d3 0%, #6a3f8f 100%);
-                }
-
-                &:active:not(:disabled) {
-                  transform: translateY(0);
-                }
+              gap: 6px;
+              margin-top: auto;
 
-                &:disabled {
-                  opacity: 0.5;
-                  cursor: not-allowed;
-                }
-
-                svg {
-                  width: 20px;
-                  height: 20px;
-                }
-              }
-            }
-
-            // 文件预览(缩略图网格)
-            .files-preview {
-              display: grid;
-              grid-template-columns: repeat(2, 1fr);
-              gap: 8px;
-              width: 100%;
-              padding: 8px;
-
-              .file-thumbnail {
-                position: relative;
-                width: 100%;
-                aspect-ratio: 1;
-                background: white;
-                border: 2px solid #e2e8f0;
-                border-radius: 8px;
+              .mini-thumb-wrapper {
+                width: 36px; height: 36px;
+                border-radius: 4px;
                 overflow: hidden;
+                border: 1px solid #e2e8f0;
+                background: white;
                 cursor: pointer;
-                transition: all 0.3s ease;
-                box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
-
-                &:hover {
-                  border-color: #667eea;
-                  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
-                  transform: scale(1.05);
-
-                  .delete-thumbnail-btn {
-                    opacity: 1;
-                  }
-                }
-
-                .thumbnail-img {
-                  width: 100%;
-                  height: 100%;
-                  object-fit: cover;
-                }
-
-                .thumbnail-placeholder {
-                  display: flex;
-                  align-items: center;
-                  justify-content: center;
-                  width: 100%;
-                  height: 100%;
-                  color: #cbd5e1;
-                  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-
-                  svg {
-                    width: 28px;
-                    height: 28px;
-                  }
-                }
-
-                .delete-thumbnail-btn {
-                  position: absolute;
-                  top: 4px;
-                  right: 4px;
-                  width: 24px;
-                  height: 24px;
-                  display: flex;
-                  align-items: center;
-                  justify-content: center;
-                  background: rgba(239, 68, 68, 0.95);
-                  color: white;
-                  border: none;
-                  border-radius: 6px;
-                  cursor: pointer;
-                  opacity: 0;
-                  transition: all 0.3s ease;
-                  box-shadow: 0 2px 6px rgba(239, 68, 68, 0.4);
-
-                  &:hover {
-                    background: rgba(220, 38, 38, 1);
-                    transform: scale(1.1);
-                  }
-
-                  svg {
-                    width: 12px;
-                    height: 12px;
-                  }
-                }
+                flex-shrink: 0;
                 
-                .send-image-btn {
-                  position: absolute;
-                  bottom: 4px;
-                  right: 4px;
-                  width: 28px;
-                  height: 28px;
-                  display: flex;
-                  align-items: center;
-                  justify-content: center;
-                  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
-                  color: white;
-                  border: none;
-                  border-radius: 6px;
-                  cursor: pointer;
-                  opacity: 0;
-                  transition: all 0.3s ease;
-                  box-shadow: 0 2px 8px rgba(16, 185, 129, 0.4);
-
-                  &:hover {
-                    background: linear-gradient(135deg, #059669 0%, #047857 100%);
-                    transform: scale(1.1);
-                    box-shadow: 0 4px 12px rgba(16, 185, 129, 0.6);
-                  }
-
-                  svg {
-                    width: 14px;
-                    height: 14px;
-                  }
+                .mini-thumb {
+                  width: 100%; height: 100%; object-fit: cover;
                 }
                 
-                &:hover {
-                  .send-image-btn {
-                    opacity: 1;
-                  }
+                .file-icon {
+                  display: flex; align-items: center; justify-content: center;
+                  color: #94a3b8;
                 }
               }
 
-              .more-files-indicator {
-                display: flex;
-                align-items: center;
-                justify-content: center;
-                background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
-                border: 2px dashed #cbd5e1;
-                border-radius: 8px;
-                font-size: 14px;
-                font-weight: 700;
-                color: #64748b;
+              .add-box {
+                width: 36px; height: 36px;
+                border-radius: 4px;
+                border: 1px dashed #cbd5e1;
+                display: flex; align-items: center; justify-content: center;
+                color: #94a3b8;
+                font-size: 16px;
                 cursor: pointer;
-                transition: all 0.3s ease;
-
+                background: white;
+                
                 &:hover {
-                  background: linear-gradient(135deg, #e0e7ff 0%, #ddd6fe 100%);
-                  border-color: #667eea;
-                  color: #667eea;
+                  border-color: #6366f1;
+                  color: #6366f1;
                 }
               }
             }
 
-            // 添加更多文件按钮
-            .add-more-files {
-              display: flex;
-              justify-content: center;
-              gap: 8px;
-              padding: 8px 0 0;
-
-              .add-more-btn, .send-message-btn {
-                display: flex;
-                align-items: center;
-                gap: 6px;
-                padding: 8px 16px;
-                border: 2px solid #e2e8f0;
-                border-radius: 8px;
-                font-size: 13px;
-                font-weight: 600;
-                cursor: pointer;
-                transition: all 0.3s ease;
-
-                &:disabled {
-                  opacity: 0.5;
-                  cursor: not-allowed;
-                }
-
-                svg {
-                  width: 16px;
-                  height: 16px;
-                }
-              }
-              
-              .add-more-btn {
-                background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-                color: #475569;
-
-                &:hover:not(:disabled) {
-                  background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);
-                  border-color: #667eea;
-                  color: #667eea;
-                  transform: translateY(-1px);
-                  box-shadow: 0 2px 8px rgba(102, 126, 234, 0.15);
-                }
-              }
-              
-              .send-message-btn {
-                background: linear-gradient(135deg, #10b981 0%, #059669 100%);
-                color: white;
-                border-color: #10b981;
-
-                &:hover {
-                  background: linear-gradient(135deg, #059669 0%, #047857 100%);
-                  border-color: #047857;
-                  transform: translateY(-1px);
-                  box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
-                }
-              }
+            // Empty Actions
+            .upload-action {
+               margin-top: auto;
+               height: 36px;
+               display: flex;
+               align-items: center;
+               justify-content: center;
+               gap: 4px;
+               font-size: 12px;
+               color: #6366f1;
+               background: white;
+               border: 1px solid #e0e7ff;
+               border-radius: 4px;
+               cursor: pointer;
+               transition: all 0.2s;
+
+               &:hover {
+                 background: #6366f1;
+                 color: white;
+               }
             }
-
-            // 空状态提示
-            .empty-stage-hint {
+            
+            .empty-action {
+              margin-top: auto;
+              height: 36px;
               display: flex;
-              flex-direction: column;
               align-items: center;
               justify-content: center;
-              padding: 20px;
-              color: #cbd5e1;
-
-              svg {
-                margin-bottom: 8px;
-              }
-
-              p {
-                margin: 0;
-                font-size: 13px;
-                font-weight: 500;
-                color: #94a3b8;
-              }
+              font-size: 12px;
+              color: #94a3b8;
             }
           }
         }
-      }
 
-      // 🆕 整体空间拖拽覆盖层
-      .space-drag-overlay {
-        position: absolute;
-        top: 0;
-        left: 0;
-        right: 0;
-        bottom: 0;
-        background: rgba(102, 126, 234, 0.15);
-        backdrop-filter: blur(8px);
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        z-index: 50;
-        border-radius: 16px;
-        animation: spaceOverlayFadeIn 0.3s ease-out;
-
-        .space-drag-hint {
-          text-align: center;
-          padding: 40px;
-          background: rgba(255, 255, 255, 0.95);
-          border-radius: 20px;
-          box-shadow: 0 20px 60px rgba(102, 126, 234, 0.4);
-          border: 3px solid rgba(102, 126, 234, 0.3);
-          max-width: 400px;
-          animation: spaceHintBounce 0.5s ease-out;
-
-          .space-drag-icon {
-            margin: 0 auto 20px;
-            width: 80px;
-            height: 80px;
-            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-            border-radius: 50%;
+        // Confirm Section
+        .space-confirm-section {
+          margin-top: 16px;
+          display: flex;
+          justify-content: center;
+          border-top: 1px solid #f1f5f9;
+          padding-top: 16px;
+
+          .confirm-space-btn {
+            width: 100%;
+            padding: 10px;
+            background: #10b981;
+            color: white;
+            border: none;
+            border-radius: 8px;
+            font-weight: 600;
+            cursor: pointer;
             display: flex;
             align-items: center;
             justify-content: center;
-            animation: iconPulse 2s ease-in-out infinite;
-            box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
-
-            svg {
-              color: white;
-              width: 40px;
-              height: 40px;
-              filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
+            gap: 8px;
+            
+            &:hover:not(:disabled) {
+              background: #059669;
+            }
+            &:disabled {
+              opacity: 0.5;
+              cursor: not-allowed;
             }
           }
 
-          h3 {
-            margin: 0 0 12px 0;
-            font-size: 24px;
-            font-weight: 700;
-            color: #475569;
-            letter-spacing: 0.5px;
-          }
-
-          p {
-            margin: 0;
-            font-size: 16px;
-            color: #64748b;
-            line-height: 1.6;
-            font-weight: 500;
+          .confirmed-info {
+            display: flex;
+            align-items: center;
+            gap: 6px;
+            color: #059669;
+            font-weight: 600;
+            font-size: 14px;
+            padding: 8px 16px;
+            background: #ecfdf5;
+            border-radius: 8px;
           }
         }
       }
+    }
+  }
 
-      // 统一的空间确认按钮区域
-      .space-confirm-section {
-        display: flex;
-        justify-content: center;
-        padding: 32px 0 0;
-        margin-top: 32px;
-        border-top: 2px solid #e2e8f0;
-        position: relative;
+  // Empty State
+  .no-products-state {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 60px 20px;
+    color: #94a3b8;
 
-        // 装饰性渐变背景
-        &::before {
-          content: '';
-          position: absolute;
-          top: -2px;
-          left: 50%;
-          transform: translateX(-50%);
-          width: 200px;
-          height: 2px;
-          background: linear-gradient(90deg, transparent 0%, #667eea 50%, transparent 100%);
-        }
+    .state-icon {
+      width: 64px; height: 64px;
+      background: #f1f5f9;
+      border-radius: 50%;
+      display: flex; align-items: center; justify-content: center;
+      margin-bottom: 16px;
+    }
+    p { margin: 0; font-size: 14px; }
+  }
+}
 
-        .confirm-space-btn {
-          display: flex;
-          align-items: center;
-          gap: 12px;
-          padding: 18px 56px;
-          background: linear-gradient(135deg, #10b981 0%, #059669 100%);
-          color: white;
-          border: none;
-          border-radius: 16px;
-          font-size: 18px;
-          font-weight: 700;
-          cursor: pointer;
-          transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-          box-shadow: 0 8px 24px rgba(16, 185, 129, 0.35);
-          letter-spacing: 0.5px;
-          position: relative;
-          overflow: hidden;
-
-          // 按钮光泽效果
-          &::before {
-            content: '';
-            position: absolute;
-            top: 0;
-            left: -100%;
-            width: 100%;
-            height: 100%;
-            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
-            transition: left 0.5s ease;
-          }
-
-          &:hover:not(:disabled) {
-            transform: translateY(-4px) scale(1.02);
-            box-shadow: 0 12px 32px rgba(16, 185, 129, 0.45);
-            background: linear-gradient(135deg, #059669 0%, #047857 100%);
-
-            &::before {
-              left: 100%;
-            }
-          }
-
-          &:active:not(:disabled) {
-            transform: translateY(-2px) scale(1);
-          }
-
-          &:disabled {
-            opacity: 0.5;
-            cursor: not-allowed;
-            background: linear-gradient(135deg, #94a3b8 0%, #64748b 100%);
-          }
-
-          svg {
-            width: 24px;
-            height: 24px;
-            filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
-          }
-        }
-
-        .confirmed-info {
-          display: flex;
-          flex-direction: column;
-          align-items: center;
-          gap: 12px;
-          padding: 24px 48px;
-          background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
-          border: 3px solid #6ee7b7;
-          border-radius: 16px;
-          box-shadow: 0 6px 20px rgba(16, 185, 129, 0.25);
-          position: relative;
-          overflow: hidden;
-
-          // 装饰性背景图案
-          &::before {
-            content: '';
-            position: absolute;
-            top: -50%;
-            right: -50%;
-            width: 200%;
-            height: 200%;
-            background: radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%);
-            animation: rotate 20s linear infinite;
-          }
-
-          .confirmed-header {
-            display: flex;
-            align-items: center;
-            gap: 12px;
-            position: relative;
-            z-index: 1;
-
-            svg {
-              width: 32px;
-              height: 32px;
-              color: #059669;
-              filter: drop-shadow(0 2px 4px rgba(5, 150, 105, 0.3));
-              animation: pulse 2s ease-in-out infinite;
-            }
+@keyframes slideDown {
+  from { opacity: 0; transform: translateY(-8px); }
+  to { opacity: 1; transform: translateY(0); }
+}
 
-            .confirmed-text {
-              font-size: 22px;
-              font-weight: 700;
-              color: #059669;
-              letter-spacing: 0.5px;
-              text-shadow: 0 1px 2px rgba(5, 150, 105, 0.2);
-            }
-          }
+// Modals (Simplified)
+.stage-gallery-modal-overlay, .message-modal-overlay {
+  position: fixed;
+  inset: 0;
+  background: rgba(0, 0, 0, 0.5);
+  z-index: 100;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 20px;
+}
 
-          .confirmed-details {
-            font-size: 14px;
-            font-weight: 500;
-            color: #047857;
-            text-align: center;
-            line-height: 1.6;
-            position: relative;
-            z-index: 1;
-            background: rgba(255, 255, 255, 0.5);
-            padding: 8px 16px;
-            border-radius: 8px;
-          }
-        }
-      }
-    }
-  }
+.stage-gallery-modal, .message-modal-box {
+  background: white;
+  border-radius: 12px;
+  width: 100%;
+  max-width: 400px;
+  max-height: 80vh;
+  display: flex;
+  flex-direction: column;
+  box-shadow: 0 10px 25px rgba(0,0,0,0.2);
+  overflow: hidden;
 
-  // 没有场景时的提示
-  .no-products-state {
+  .gallery-header, .modal-header {
+    padding: 16px;
+    border-bottom: 1px solid #e2e8f0;
     display: flex;
-    flex-direction: column;
+    justify-content: space-between;
     align-items: center;
-    justify-content: center;
-    padding: 80px 20px;
-    
-    .state-icon {
-      color: #cbd5e1;
-      margin-bottom: 20px;
-      
-      svg {
-        width: 64px;
-        height: 64px;
-      }
-    }
-    
-    h3 {
-      margin: 0 0 12px;
-      font-size: 20px;
-      font-weight: 600;
-      color: #475569;
-    }
-    
-    p {
-      margin: 0;
-      font-size: 15px;
-      color: #94a3b8;
-      text-align: center;
-    }
-  }
-
-  // ==================== 动画效果 ====================
-
-  // 空间内容展开动画
-  @keyframes slideDown {
-    from {
-      opacity: 0;
-      transform: translateY(-10px);
-    }
-    to {
-      opacity: 1;
-      transform: translateY(0);
-    }
-  }
-
-  // 拖拽覆盖层动画
-  @keyframes dragOverlay {
-    from {
-      opacity: 0;
-      transform: scale(0.95);
-    }
-    to {
-      opacity: 1;
-      transform: scale(1);
-    }
-  }
-
-  // 拖拽提示动画
-  @keyframes dragHint {
-    from {
-      opacity: 0;
-      transform: translateY(10px) scale(0.9);
-    }
-    to {
-      opacity: 1;
-      transform: translateY(0) scale(1);
-    }
-  }
-
-  // 弹跳动画
-  @keyframes bounce {
-    0%, 20%, 50%, 80%, 100% {
-      transform: translateY(0);
-    }
-    40% {
-      transform: translateY(-8px);
-    }
-    60% {
-      transform: translateY(-4px);
-    }
-  }
-
-  // 脉冲动画(用于确认图标)
-  @keyframes pulse {
-    0%, 100% {
-      transform: scale(1);
-      opacity: 1;
-    }
-    50% {
-      transform: scale(1.1);
-      opacity: 0.8;
-    }
-  }
 
-  // 旋转动画(用于装饰背景)
-  @keyframes rotate {
-    from {
-      transform: rotate(0deg);
-    }
-    to {
-      transform: rotate(360deg);
-    }
-  }
-
-  // 渐入动画
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-
-  // 从下方滑入动画
-  @keyframes slideUp {
-    from {
-      opacity: 0;
-      transform: translateY(20px);
-    }
-    to {
-      opacity: 1;
-      transform: translateY(0);
+    .gallery-title h3, h4 { margin: 0; font-size: 16px; font-weight: 700; }
+    p { margin: 4px 0 0; font-size: 12px; color: #64748b; }
+    
+    .close-btn {
+      background: none; border: none; font-size: 24px; color: #94a3b8; cursor: pointer;
+      &:hover { color: #ef4444; }
     }
   }
 
-  // 缩放进入动画
-  @keyframes scaleIn {
-    from {
-      opacity: 0;
-      transform: scale(0.9);
-    }
-    to {
-      opacity: 1;
-      transform: scale(1);
-    }
-  }
+  .gallery-content, .modal-body {
+    flex: 1;
+    overflow-y: auto;
+    padding: 16px;
 
-  // 光泽扫过动画(用于空间头部)
-  @keyframes shimmer {
-    0% {
-      background-position: 200% 0;
-    }
-    100% {
-      background-position: -200% 0;
-    }
-  }
+    // Gallery Grid
+    .images-grid {
+      display: grid;
+      grid-template-columns: repeat(3, 1fr);
+      gap: 8px;
 
-  // 徽章脉冲动画
-  @keyframes pulse-badge {
-    0%, 100% {
-      transform: scale(1);
-      box-shadow: 0 2px 8px rgba(16, 185, 129, 0.4);
-    }
-    50% {
-      transform: scale(1.05);
-      box-shadow: 0 4px 12px rgba(16, 185, 129, 0.6);
-    }
-  }
+      .image-item {
+        position: relative;
+        aspect-ratio: 1;
+        border-radius: 6px;
+        overflow: hidden;
+        background: #f8fafc;
+        border: 1px solid #e2e8f0;
 
-  // 🆕 空间拖拽动画
-  @keyframes spaceOverlayFadeIn {
-    from {
-      opacity: 0;
-      backdrop-filter: blur(0px);
-    }
-    to {
-      opacity: 1;
-      backdrop-filter: blur(8px);
+        img { width: 100%; height: 100%; object-fit: cover; }
+        .file-placeholder {
+           width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; color: #cbd5e1;
+        }
+        .image-info { 
+           position: absolute; bottom: 0; left: 0; right: 0; background: rgba(0,0,0,0.6); color: white; font-size: 10px; padding: 2px 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; 
+        }
+        .delete-image-btn {
+           position: absolute; top: 2px; right: 2px; width: 16px; height: 16px; background: rgba(239,68,68,0.9); color: white; border: none; border-radius: 50%; font-size: 12px; display: flex; align-items: center; justify-content: center; cursor: pointer;
+        }
+      }
     }
   }
 
-  @keyframes spaceHintBounce {
-    from {
-      opacity: 0;
-      transform: scale(0.8) translateY(20px);
-    }
-    to {
-      opacity: 1;
-      transform: scale(1) translateY(0);
-    }
-  }
+  .gallery-footer, .modal-footer {
+    padding: 12px 16px;
+    border-top: 1px solid #e2e8f0;
+    display: flex;
+    justify-content: flex-end;
+    gap: 8px;
 
-  @keyframes iconPulse {
-    0%, 100% {
-      transform: scale(1);
-      box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
+    .add-files-btn {
+      display: flex; align-items: center; gap: 6px;
+      background: #6366f1; color: white; border: none; padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 13px;
     }
-    50% {
-      transform: scale(1.1);
-      box-shadow: 0 15px 40px rgba(102, 126, 234, 0.6);
+    .close-gallery-btn, .btn-cancel {
+       background: white; border: 1px solid #e2e8f0; color: #64748b; padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 13px;
     }
-  }
-}
-
-// 阶段头部点击样式
-.stage-header {
-  &.clickable {
-    cursor: pointer;
-    transition: all 0.2s ease;
-    
-    &:hover {
-      background: rgba(59, 130, 246, 0.05);
-      
-      .view-all-hint {
-        opacity: 1;
-        transform: translateY(0);
-      }
-    }
-  }
-  
-  .view-all-hint {
-    display: flex;
-    align-items: center;
-    gap: 4px;
-    font-size: 12px;
-    color: #3b82f6;
-    opacity: 0;
-    transform: translateY(-4px);
-    transition: all 0.2s ease;
-    
-    svg {
-      flex-shrink: 0;
+    .btn-send {
+       background: #10b981; color: white; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px;
+       &:disabled { opacity: 0.5; }
     }
   }
 }
 
-// 阶段图片库模态框
-.stage-gallery-modal-overlay {
+// Revision list
+.revision-list-fullscreen {
   position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: rgba(0, 0, 0, 0.6);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-  backdrop-filter: blur(4px);
-}
-
-.stage-gallery-modal {
+  inset: 0;
+  z-index: 200;
   background: white;
-  border-radius: 16px;
-  width: 90vw;
-  max-width: 1200px;
-  height: 80vh;
-  max-height: 800px;
-  display: flex;
-  flex-direction: column;
-  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
-  overflow: hidden;
 }
 
-.gallery-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 24px 28px;
-  border-bottom: 1px solid #e2e8f0;
-  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-  
-  .gallery-title {
-    h3 {
-      margin: 0;
-      font-size: 20px;
-      font-weight: 600;
-      color: #1e293b;
-    }
-    
-    p {
-      margin: 4px 0 0 0;
-      font-size: 14px;
-      color: #64748b;
-    }
-  }
-  
-  .close-btn {
-    background: none;
-    border: none;
-    cursor: pointer;
-    padding: 8px;
-    border-radius: 8px;
-    color: #64748b;
-    transition: all 0.2s ease;
-    
-    &:hover {
-      background: rgba(248, 113, 113, 0.1);
-      color: #ef4444;
-    }
-  }
-}
+// ==================== 动画效果 ====================
 
-.gallery-content {
-  flex: 1;
-  overflow-y: auto;
-  padding: 24px 28px;
+// 拖拽覆盖层动画
+@keyframes dragOverlay {
+  from { opacity: 0; transform: scale(0.95); }
+  to { opacity: 1; transform: scale(1); }
 }
 
-.images-grid {
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
-  gap: 20px;
+// 拖拽提示动画
+@keyframes dragHint {
+  from { opacity: 0; transform: translateY(10px) scale(0.9); }
+  to { opacity: 1; transform: translateY(0) scale(1); }
 }
 
-.image-item {
-  position: relative;
-  background: #f8fafc;
-  border-radius: 12px;
-  overflow: hidden;
-  cursor: pointer;
-  transition: all 0.3s ease;
-  border: 2px solid transparent;
-  
-  &:hover {
-    transform: translateY(-4px);
-    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
-    border-color: #3b82f6;
-    
-    .delete-image-btn {
-      opacity: 1;
-    }
-  }
-  
-  .gallery-image {
-    width: 100%;
-    height: 150px;
-    object-fit: cover;
-    display: block;
-  }
-  
-  .file-placeholder {
-    width: 100%;
-    height: 150px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background: #f1f5f9;
-    color: #94a3b8;
-  }
-  
-  .image-info {
-    padding: 12px;
-    background: white;
-    
-    .file-name {
-      font-size: 13px;
-      font-weight: 500;
-      color: #1e293b;
-      margin-bottom: 4px;
-      white-space: nowrap;
-      overflow: hidden;
-      text-overflow: ellipsis;
-    }
-    
-    .file-size {
-      font-size: 12px;
-      color: #64748b;
-    }
-  }
-  
-  .delete-image-btn {
-    position: absolute;
-    top: 8px;
-    right: 8px;
-    background: rgba(239, 68, 68, 0.9);
-    color: white;
-    border: none;
-    border-radius: 6px;
-    padding: 6px;
-    cursor: pointer;
-    opacity: 0;
-    transition: all 0.2s ease;
-    
-    &:hover {
-      background: #dc2626;
-      transform: scale(1.1);
-    }
-  }
-}
-
-.empty-gallery {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  height: 300px;
-  color: #94a3b8;
-  
-  p {
-    margin-top: 16px;
-    font-size: 16px;
-  }
+// 弹跳动画
+@keyframes bounce {
+  0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
+  40% { transform: translateY(-8px); }
+  60% { transform: translateY(-4px); }
 }
 
-.gallery-footer {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 20px 28px;
-  border-top: 1px solid #e2e8f0;
-  background: #f8fafc;
-  
-  .gallery-actions {
-    display: flex;
-    gap: 12px;
-  }
-  
-  .add-files-btn {
-    display: flex;
-    align-items: center;
-    gap: 8px;
-    background: #3b82f6;
-    color: white;
-    border: none;
-    border-radius: 8px;
-    padding: 10px 16px;
-    font-size: 14px;
-    font-weight: 500;
-    cursor: pointer;
-    transition: all 0.2s ease;
-    
-    &:hover:not(:disabled) {
-      background: #2563eb;
-      transform: translateY(-1px);
-    }
-    
-    &:disabled {
-      opacity: 0.5;
-      cursor: not-allowed;
-    }
-  }
-  
-  .close-gallery-btn {
-    background: #6b7280;
-    color: white;
-    border: none;
-    border-radius: 8px;
-    padding: 10px 20px;
-    font-size: 14px;
-    font-weight: 500;
-    cursor: pointer;
-    transition: all 0.2s ease;
-    
-    &:hover {
-      background: #4b5563;
-    }
-  }
-}
-
-// 响应式设计 - 阶段图片库
-@media (max-width: 768px) {
-  .stage-gallery-modal {
-    width: 95vw;
-    height: 90vh;
-    margin: 20px;
-  }
-  
-  .gallery-header {
-    padding: 16px 20px;
-    
-    .gallery-title h3 {
-      font-size: 18px;
-    }
-  }
-  
-  .gallery-content {
-    padding: 16px 20px;
-  }
-  
-  .images-grid {
-    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
-    gap: 12px;
-  }
-  
-  .image-item {
-    .gallery-image,
-    .file-placeholder {
-      height: 120px;
-    }
-  }
-  
-  .gallery-footer {
-    padding: 16px 20px;
-    flex-direction: column;
-    gap: 12px;
-    
-    .gallery-actions {
-      width: 100%;
-      justify-content: center;
-    }
-  }
+// 脉冲动画(用于确认图标)
+@keyframes pulse {
+  0%, 100% { transform: scale(1); opacity: 1; }
+  50% { transform: scale(1.1); opacity: 0.8; }
 }
 
-// 全屏工单列表
-.revision-list-fullscreen {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: rgba(0, 0, 0, 0.5);
-  z-index: 2100;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  animation: fadeIn 0.2s ease;
-  pointer-events: auto;
-  
-  app-revision-task-list {
-    width: 90%;
-    max-width: 1200px;
-    height: 85vh;
-    background: white;
-    border-radius: 16px;
-    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
-    overflow: hidden;
-    animation: slideUp 0.3s ease;
-  }
+// 旋转动画(用于装饰背景)
+@keyframes rotate {
+  from { transform: rotate(0deg); }
+  to { transform: rotate(360deg); }
 }
 
+// 渐入动画
 @keyframes fadeIn {
   from { opacity: 0; }
   to { opacity: 1; }
 }
 
+// 从下方滑入动画
 @keyframes slideUp {
-  from {
-    opacity: 0;
-    transform: translateY(20px);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
+  from { opacity: 0; transform: translateY(20px); }
+  to { opacity: 1; transform: translateY(0); }
 }
 
-// 消息发送弹窗
-.message-modal-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: rgba(0, 0, 0, 0.5);
-  z-index: 2300;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  animation: fadeIn 0.2s ease;
-  pointer-events: auto;
+// 缩放进入动画
+@keyframes scaleIn {
+  from { opacity: 0; transform: scale(0.9); }
+  to { opacity: 1; transform: scale(1); }
 }
 
-.message-modal-box {
-  background: white;
-  border-radius: 16px;
-  width: 90%;
-  max-width: 600px;
-  max-height: 85vh;
-  display: flex;
-  flex-direction: column;
-  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
-  animation: slideUp 0.3s ease;
-  
-  .modal-header {
-    padding: 20px 24px;
-    border-bottom: 1px solid #e5e7eb;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    
-    h4 {
-      margin: 0;
-      font-size: 18px;
-      font-weight: 600;
-      color: #1f2937;
-    }
-    
-    .close-btn {
-      padding: 4px;
-      background: transparent;
-      border: none;
-      cursor: pointer;
-      color: #6b7280;
-      font-size: 28px;
-      line-height: 1;
-      
-      &:hover {
-        color: #1f2937;
-      }
-    }
-  }
-  
-  .modal-body {
-    flex: 1;
-    overflow-y: auto;
-    padding: 24px;
-    
-    .section-label {
-      display: block;
-      margin-bottom: 12px;
-      font-size: 14px;
-      font-weight: 600;
-      color: #374151;
-    }
-    
-    .stage-info-section {
-      background: #f9fafb;
-      border-radius: 12px;
-      padding: 16px;
-      margin-bottom: 20px;
-      
-      .info-item {
-        display: flex;
-        align-items: center;
-        margin-bottom: 8px;
-        
-        &:last-child {
-          margin-bottom: 0;
-        }
-        
-        .label {
-          font-size: 13px;
-          font-weight: 600;
-          color: #6b7280;
-          width: 60px;
-        }
-        
-        .value {
-          font-size: 14px;
-          color: #1f2937;
-          font-weight: 500;
-        }
-      }
-    }
-    
-    .template-section {
-      margin-bottom: 20px;
-      
-      .template-options {
-        display: flex;
-        flex-direction: column;
-        gap: 8px;
-        
-        .template-option {
-          padding: 12px 16px;
-          background: white;
-          border: 2px solid #e5e7eb;
-          border-radius: 10px;
-          text-align: left;
-          font-size: 14px;
-          line-height: 1.6;
-          color: #374151;
-          cursor: pointer;
-          transition: all 0.2s;
-          
-          &:hover {
-            background: #f9fafb;
-            border-color: #10b981;
-          }
-          
-          &.active {
-            background: #ecfdf5;
-            border-color: #10b981;
-            color: #065f46;
-            font-weight: 500;
-          }
-        }
-      }
-    }
-    
-    .custom-message-section {
-      margin-bottom: 20px;
-      
-      textarea {
-        width: 100%;
-        padding: 12px;
-        border: 2px solid #e5e7eb;
-        border-radius: 10px;
-        font-size: 14px;
-        font-family: inherit;
-        line-height: 1.6;
-        resize: vertical;
-        
-        &:focus {
-          outline: none;
-          border-color: #10b981;
-          box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
-        }
-      }
-      
-      .char-count {
-        margin-top: 4px;
-        font-size: 12px;
-        color: #9ca3af;
-        text-align: right;
-      }
-    }
-    
-    .preview-images-section {
-      margin-bottom: 20px;
-      
-      .preview-images-grid {
-        display: grid;
-        grid-template-columns: repeat(3, 1fr);
-        gap: 8px;
-        
-        .preview-img {
-          width: 100%;
-          aspect-ratio: 1;
-          object-fit: cover;
-          border-radius: 8px;
-          border: 2px solid #e5e7eb;
-        }
-        
-        .more-images {
-          display: flex;
-          align-items: center;
-          justify-content: center;
-          aspect-ratio: 1;
-          background: #f9fafb;
-          border: 2px dashed #d1d5db;
-          border-radius: 8px;
-          font-size: 14px;
-          font-weight: 600;
-          color: #6b7280;
-        }
-      }
-    }
-  }
-  
-  .modal-footer {
-    padding: 16px 24px;
-    border-top: 1px solid #e5e7eb;
-    display: flex;
-    gap: 12px;
-    justify-content: flex-end;
-    
-    button {
-      padding: 10px 24px;
-      border: none;
-      border-radius: 10px;
-      font-size: 14px;
-      font-weight: 600;
-      cursor: pointer;
-      transition: all 0.2s;
-      display: flex;
-      align-items: center;
-      gap: 8px;
-      
-      &:disabled {
-        opacity: 0.5;
-        cursor: not-allowed;
-      }
-    }
-    
-    .btn-cancel {
-      background: white;
-      color: #6b7280;
-      border: 2px solid #d1d5db;
-      
-      &:hover:not(:disabled) {
-        background: #f9fafb;
-        border-color: #9ca3af;
-      }
-    }
-    
-    .btn-send {
-      background: linear-gradient(135deg, #10b981 0%, #059669 100%);
-      color: white;
-      
-      &:hover:not(:disabled) {
-        background: linear-gradient(135deg, #059669 0%, #047857 100%);
-        box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
-      }
-      
-      .spinner-small {
-        width: 16px;
-        height: 16px;
-        border: 2px solid rgba(255, 255, 255, 0.3);
-        border-top-color: white;
-        border-radius: 50%;
-        animation: spin 0.6s linear infinite;
-      }
-    }
-  }
+// 🆕 空间拖拽动画
+@keyframes spaceOverlayFadeIn {
+  from { opacity: 0; backdrop-filter: blur(0px); }
+  to { opacity: 1; backdrop-filter: blur(8px); }
+}
 
-  // ==================== 🔥 企业微信端响应式适配 ====================
-  @media screen and (max-width: 768px) {
-    padding: 12px;
-    
-    // 工具栏优化
-    .revision-toolbar {
-      gap: 8px;
-      margin-bottom: 12px;
-      
-      button {
-        padding: 8px 12px;
-        font-size: 13px;
-        
-        svg {
-          width: 16px;
-          height: 16px;
-        }
-        
-        span {
-          display: none; // 隐藏文字,只显示图标
-        }
-      }
-      
-      .btn-view-revisions {
-        .task-count-badge {
-          top: -4px;
-          right: -4px;
-          min-width: 18px;
-          height: 18px;
-          font-size: 10px;
-        }
-      }
-    }
-    
-    // 空间卡片优化
-    .spaces-list-section {
-      gap: 16px;
-      
-      .space-card {
-        border-radius: 12px;
-        
-        .space-header {
-          flex-direction: column;
-          gap: 12px;
-          padding: 12px 16px;
-          align-items: stretch;
-          
-          &::before {
-            height: 3px;
-          }
-          
-          // 空间名称区域
-          .space-name-section {
-            flex-direction: row;
-            justify-content: space-between;
-            min-width: auto;
-            font-size: 16px;
-            padding-right: 0;
-            border-right: none;
-            border-bottom: 1px solid #e2e8f0;
-            padding-bottom: 8px;
-            
-            .completion-badge {
-              padding: 3px 8px;
-              font-size: 12px;
-              border-radius: 10px;
-            }
-          }
-          
-          // 四个阶段名称改为2x2网格
-          .stage-names-row {
-            grid-template-columns: repeat(2, 1fr);
-            gap: 8px;
-            padding: 0;
-            
-            .stage-name-item {
-              padding: 8px 12px;
-              border-radius: 8px;
-              
-              &::after {
-                height: 2px;
-              }
-              
-              .stage-label {
-                font-size: 13px;
-              }
-              
-              .mini-badge {
-                min-width: 20px;
-                height: 20px;
-                padding: 0 6px;
-                font-size: 11px;
-                border-radius: 10px;
-              }
-            }
-          }
-          
-          // 展开图标
-          .expand-icon {
-            position: absolute;
-            top: 12px;
-            right: 16px;
-            width: 32px;
-            height: 32px;
-            
-            svg {
-              width: 20px;
-              height: 20px;
-            }
-          }
-        }
-        
-        // 空间内容区域优化
-        .space-content {
-          padding: 12px;
-          
-          // 阶段容器改为2列布局
-          .stages-container {
-            grid-template-columns: repeat(2, 1fr);
-            gap: 12px;
-            margin-bottom: 16px;
-            
-            .stage-section {
-              border-radius: 12px;
-              
-              &::before {
-                height: 3px;
-              }
-              
-              .stage-header {
-                padding: 10px 12px;
-                
-                .stage-title {
-                  gap: 6px;
-                  
-                  .stage-name {
-                    font-size: 13px;
-                  }
-                  
-                  .file-count-badge {
-                    min-width: 20px;
-                    height: 20px;
-                    padding: 0 6px;
-                    font-size: 11px;
-                    border-radius: 10px;
-                  }
-                }
-                
-                .view-all-hint {
-                  font-size: 11px;
-                  gap: 4px;
-                  
-                  svg {
-                    width: 14px;
-                    height: 14px;
-                  }
-                }
-              }
-              
-              .stage-body {
-                padding: 12px;
-                min-height: 150px;
-                
-                .upload-zone-compact {
-                  padding: 12px;
-                  gap: 8px;
-                  
-                  .upload-btn-compact {
-                    padding: 10px 16px;
-                    font-size: 12px;
-                    border-radius: 8px;
-                    
-                    svg {
-                      width: 16px;
-                      height: 16px;
-                    }
-                  }
-                  
-                  .upload-hint {
-                    font-size: 11px;
-                  }
-                }
-                
-                // 文件预览网格
-                .files-preview-grid {
-                  grid-template-columns: repeat(2, 1fr);
-                  gap: 8px;
-                  
-                  .file-preview-item {
-                    .file-thumbnail {
-                      height: 80px;
-                      border-radius: 8px;
-                    }
-                    
-                    .file-name {
-                      font-size: 11px;
-                      padding: 4px 6px;
-                    }
-                    
-                    .btn-remove-file {
-                      width: 24px;
-                      height: 24px;
-                      top: 4px;
-                      right: 4px;
-                      
-                      svg {
-                        width: 14px;
-                        height: 14px;
-                      }
-                    }
-                  }
-                }
-                
-                // 加载状态
-                .stage-uploading {
-                  padding: 12px;
-                  
-                  .uploading-spinner {
-                    width: 32px;
-                    height: 32px;
-                    border-width: 3px;
-                  }
-                  
-                  p {
-                    font-size: 12px;
-                  }
-                }
-              }
-            }
-          }
-          
-          // 空间拖拽提示
-          .space-drag-overlay {
-            .space-drag-hint {
-              padding: 16px;
-              
-              .space-drag-icon svg {
-                width: 36px;
-                height: 36px;
-              }
-              
-              h3 {
-                font-size: 14px;
-                margin: 8px 0 4px;
-              }
-              
-              p {
-                font-size: 11px;
-              }
-            }
-          }
-        }
-      }
-    }
-    
-    // 确认状态卡片优化
-    .confirmation-card {
-      padding: 12px;
-      border-radius: 12px;
-      
-      .confirmation-header {
-        gap: 8px;
-        
-        .confirmation-icon svg {
-          width: 32px;
-          height: 32px;
-        }
-        
-        .confirmation-text {
-          h3 {
-            font-size: 15px;
-          }
-          
-          p {
-            font-size: 12px;
-          }
-        }
-      }
-    }
-    
-    // 空状态优化
-    .empty-state {
-      padding: 24px 16px;
-      
-      .empty-icon svg {
-        width: 48px;
-        height: 48px;
-      }
-      
-      h3 {
-        font-size: 15px;
-      }
-      
-      p {
-        font-size: 12px;
-      }
-    }
-  }
-  
-  // ==================== 🔥 极窄屏幕(<480px)单列布局 ====================
-  @media screen and (max-width: 480px) {
-    padding: 8px;
-    
-    .spaces-list-section {
-      gap: 12px;
-      
-      .space-card {
-        .space-content {
-          padding: 8px;
-          
-          // 阶段容器改为单列布局
-          .stages-container {
-            grid-template-columns: 1fr;
-            gap: 10px;
-            
-            .stage-section {
-              .stage-body {
-                min-height: 120px;
-                
-                .files-preview-grid {
-                  grid-template-columns: repeat(2, 1fr);
-                  gap: 6px;
-                  
-                  .file-preview-item {
-                    .file-thumbnail {
-                      height: 70px;
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
+@keyframes spaceHintBounce {
+  from { opacity: 0; transform: scale(0.8) translateY(20px); }
+  to { opacity: 1; transform: scale(1) translateY(0); }
+}
+
+@keyframes iconPulse {
+  0%, 100% { transform: scale(1); box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4); }
+  50% { transform: scale(1.1); box-shadow: 0 15px 40px rgba(102, 126, 234, 0.6); }
 }
 
 /* 🔥 企业微信端适配 - 让操作按钮始终可见 */

+ 16 - 3
src/modules/project/pages/project-detail/stages/stage-delivery.component.ts

@@ -369,9 +369,22 @@ export class StageDeliveryComponent implements OnInit, OnDestroy {
       // 如果没有currentUser,尝试获取
       if (!this.currentUser && this.cid) {
         console.log('👤 获取当前用户...');
-        // @ts-ignore - WxworkAuth type issue with fmode-ng
-        const wxwork = new WxworkAuth({ cid: this.cid, appId: 'crm' });
-        this.currentUser = await wxwork.currentProfile();
+        try {
+          // @ts-ignore - WxworkAuth type issue with fmode-ng
+          const wxwork = new WxworkAuth({ cid: this.cid, appId: 'crm' });
+          this.currentUser = await wxwork.currentProfile();
+        } catch (e) {
+          console.error('⚠️ WxworkAuth获取用户失败,尝试使用Parse.User.current()或忽略:', e);
+          // 尝试降级获取
+          try {
+            const user = Parse.User.current();
+            if (user) {
+              this.currentUser = await (user as any).fetch();
+            }
+          } catch (ex) {
+            console.warn('无法获取当前用户');
+          }
+        }
 
         const role = this.currentUser?.get('roleName') || '';
         // ⭐ 修复:使用模糊匹配判断权限(与订单分配阶段对齐)

+ 26 - 1577
src/modules/project/pages/project-detail/stages/stage-requirements.component.html

@@ -11,552 +11,14 @@
 <!-- 确认需求内容 -->
 @if (!loading) {
   <div class="stage-requirements-container">
-    <!-- 多产品切换器 (已隐藏) -->
-    <!-- 
-    @if (isMultiProductProject) {
-      <div class="space-selector">
-        <div class="space-tabs">
-          @for (product of projectProducts; track product.id) {
-            <button
-              class="space-tab"
-              [class.active]="activeProductId == product.id"
-              (click)="selectProduct(product.id)">
-              <span>{{ getProductDisplayName(product) }}</span>
-              <span class="progress-indicator" [style.width]="calculateProductCompletion(product.id) + '%'"></span>
-            </button>
-          }
-        </div>
-      </div>
-    }
-    -->
-
-    <!-- 需求分段导航 (已隐藏) -->
-    <!-- 
-    <div class="requirements-segment">
-      <div class="segment-buttons">
-        <button
-          class="segment-btn"
-          [class.active]="requirementsSegment == 'global'"
-          (click)="selectRequirementsSegment('global')">
-          全局需求
-        </button>
-        @if (isMultiProductProject) {
-          <button
-            class="segment-btn"
-            [class.active]="requirementsSegment == 'spaces'"
-            (click)="selectRequirementsSegment('spaces')">
-            产品需求
-          </button>
-        }
-      </div>
-    </div>
-    -->
-
-    <!-- AI设计分析区域 - 页面顶部 -->
-    <div class="ai-design-analysis-section">
-      <div class="card ai-analysis-card">
-        <div class="card-header">
-          <h3 class="card-title">
-            <span class="icon">✨</span>
-            AI设计分析
-          </h3>
-          <p class="card-subtitle">上传参考图片、CAD或PDF,AI将进行专业的灯光材质细节分析</p>
-        </div>
-        
-        <div class="card-content">
-          <!-- 空间选择器 -->
-          <div class="space-selector-inline">
-            <label class="selector-label">选择空间:</label>
-            <div class="space-tabs-inline">
-              @for (space of projectProducts; track space.id) {
-                <button
-                  class="space-tab-btn"
-                  [class.active]="aiDesignCurrentSpace?.id === space.id"
-                  (click)="selectAISpace(space)">
-                  {{ getSpaceDisplayName(space) }}
-                </button>
-              }
-            </div>
-          </div>
-
-          <!-- 步骤1: 上传图片和描述 -->
-          @if (!aiDesignAnalysisResult) {
-            <div class="upload-section">
-              <!-- 已上传的文件 -->
-              @if (aiDesignUploadedFiles.length > 0) {
-                <div class="uploaded-files">
-                  @for (file of aiDesignUploadedFiles; track file.url; let i = $index) {
-                    <div class="file-item" [class.is-image]="file.extension && ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(file.extension)">
-                      @if (file.extension && ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(file.extension)) {
-                        <!-- 图片预览 -->
-                        <img [src]="file.url" [alt]="file.name">
-                      } @else {
-                        <!-- 文件图标 -->
-                        <div class="file-icon" [class.pdf]="file.extension === 'pdf'" [class.cad]="file.extension === 'dwg' || file.extension === 'dxf'">
-                          @if (file.extension === 'pdf') {
-                            <span class="icon-text">📄</span>
-                            <span class="file-ext">PDF</span>
-                          } @else if (file.extension === 'dwg' || file.extension === 'dxf') {
-                            <span class="icon-text">📐</span>
-                            <span class="file-ext">{{ file.extension?.toUpperCase() }}</span>
-                          } @else {
-                            <span class="icon-text">📄</span>
-                            <span class="file-ext">{{ file.extension?.toUpperCase() }}</span>
-                          }
-                        </div>
-                      }
-                      <div class="file-info">
-                        <div class="file-name">{{ file.name }}</div>
-                        <div class="file-size">{{ formatFileSize(file.size) }}</div>
-                      </div>
-                      <button class="remove-btn" (click)="removeAIDialogImage(i)">×</button>
-                    </div>
-                  }
-                  @if (aiDesignUploadedFiles.length < 3) {
-                    <div class="add-more" (click)="triggerAIDialogFileInput()">
-                      <div class="add-icon">+</div>
-                      <div class="add-text">继续添加</div>
-                    </div>
-                  }
-                </div>
-                
-                <!-- 开始分析按钮(只在有文件且无对话时显示) -->
-                @if (aiChatMessages.length === 0 && !aiDesignAnalyzing) {
-                  <div class="start-analysis-wrapper">
-                    <button class="btn-start-analysis" (click)="startAIDesignAnalysis()">
-                      <span class="icon-text">📊</span>
-                      <span>开始AI分析</span>
-                      <div class="btn-hint">点击进行专业的设计分析</div>
-                    </button>
-                  </div>
-                }
-              } @else {
-                <!-- 上传卡片 -->
-                <div 
-                  class="upload-card" 
-                  (click)="triggerAIDialogFileInput()"
-                  (drop)="onAIFileDrop($event)"
-                  (dragover)="onAIFileDragOver($event)"
-                  (dragleave)="onAIFileDragLeave($event)"
-                  [class.drag-over]="aiDesignDragOver">
-                  <div class="upload-icon">📸</div>
-                  <h3>上传参考文件</h3>
-                  <p class="upload-desc">支持图片、CAD、PDF等多种格式</p>
-                  <p class="upload-hint">
-                    <span class="hint-text">点击上传或拖拽文件到此处</span>
-                    <span class="hint-formats">支持: JPG, PNG, PDF, DWG, DXF (最多3个文件)</span>
-                  </p>
-                </div>
-              }
-
-              <!-- AI对话区域 -->
-              <div class="ai-chat-container">
-                
-                <!-- 对话历史显示区 -->
-                <div class="chat-messages-wrapper" #chatMessagesWrapper>
-                  @if (aiChatMessages.length === 0) {
-                    <!-- 欢迎提示 -->
-                    <div class="chat-welcome">
-                      <div class="welcome-icon">
-                        <span class="icon-text">✨</span>
-                      </div>
-                      <h3>AI设计助手</h3>
-                      <p>上传图片后,告诉我你的设计需求,我会帮你深入分析</p>
-                      <div class="quick-prompts">
-                        <button class="prompt-chip" (click)="useQuickPrompt('分析整体设计风格和色彩搭配')">
-                          <span class="icon-text">🎨</span>
-                          <span>分析设计风格</span>
-                        </button>
-                        <button class="prompt-chip" (click)="useQuickPrompt('重点分析灯光设计和照明方案')">
-                          <span class="icon-text">💡</span>
-                          <span>灯光设计</span>
-                        </button>
-                        <button class="prompt-chip" (click)="useQuickPrompt('分析材质选择和质感搭配')">
-                          <span class="icon-text">📦</span>
-                          <span>材质分析</span>
-                        </button>
-                        <button class="prompt-chip" (click)="useQuickPrompt('提供空间优化建议')">
-                          <span class="icon-text">🔄</span>
-                          <span>空间优化</span>
-                        </button>
-                      </div>
-                    </div>
-                  } @else {
-                    <!-- 对话消息列表 -->
-                    <div class="chat-messages-list">
-                      @for (message of aiChatMessages; track message.id) {
-                        <div class="chat-message" [class.user-message]="message.role === 'user'" [class.ai-message]="message.role === 'assistant'">
-                          
-                          <!-- 用户消息 -->
-                          @if (message.role === 'user') {
-                            <div class="message-content user-content">
-                              <div class="message-bubble">
-                                <div class="message-text">{{ message.content }}</div>
-                                @if (message.images && message.images.length > 0) {
-                                  <div class="message-images">
-                                    @for (image of message.images; track image) {
-                                      <img [src]="image" alt="参考图">
-                                    }
-                                  </div>
-                                }
-                                <div class="message-time">{{ message.timestamp | date:'HH:mm' }}</div>
-                              </div>
-                              <div class="message-avatar user-avatar">
-                                <span class="icon-text">👤</span>
-                              </div>
-                            </div>
-                          }
-                          
-                          <!-- AI消息 -->
-                          @if (message.role === 'assistant') {
-                            <div class="message-content ai-content">
-                              <div class="message-avatar ai-avatar">
-                                <span class="icon-text">✨</span>
-                              </div>
-                              <div class="message-bubble">
-                                @if (message.isLoading) {
-                                  <div class="message-loading">
-                                    <div class="loading-dots">
-                                      <span></span>
-                                      <span></span>
-                                      <span></span>
-                                    </div>
-                                    <span class="loading-text">AI正在思考...</span>
-                                  </div>
-                                } @else {
-                                  <div class="message-text" [innerHTML]="formatMessageContent(message.content)"></div>
-                                  <div class="message-actions">
-                                    <button class="action-btn" (click)="copyMessage(message.content)" title="复制">
-                                      <span class="icon-text">📋</span>
-                                    </button>
-                                    <button class="action-btn" (click)="regenerateMessage(message)" title="重新生成">
-                                      <span class="icon-text">🔄</span>
-                                    </button>
-                                    <button class="action-btn" (click)="likeMessage(message)" [class.liked]="message.liked" title="有帮助">
-                                      <span class="icon-text">👍</span>
-                                    </button>
-                                    <button class="action-btn" (click)="dislikeMessage(message)" [class.disliked]="message.disliked" title="无帮助">
-                                      <span class="icon-text">👎</span>
-                                    </button>
-                                  </div>
-                                  <div class="message-time">{{ message.timestamp | date:'HH:mm' }}</div>
-                                }
-                              </div>
-                            </div>
-                          }
-                        </div>
-                      }
-                    </div>
-                  }
-                </div>
-
-                <!-- 输入区域 -->
-                <div class="chat-input-container">
-                  <div class="input-wrapper">
-                    <textarea
-                      class="chat-input"
-                      [(ngModel)]="aiChatInput"
-                      placeholder="描述你的需求或提出修改意见..."
-                      rows="1"
-                      [disabled]="aiDesignAnalyzing"
-                      (input)="onChatInputChange($event)"
-                      (keydown.enter)="onChatInputEnter($event)"
-                      #chatInput></textarea>
-                    
-                    <div class="input-actions">
-                      <!-- 左侧按钮组 -->
-                      <div class="input-actions-left">
-                        <button class="action-btn" title="上传附件" [disabled]="aiDesignAnalyzing" (click)="openAttachmentDialog()">
-                          <span class="icon-text">📷</span>
-                        </button>
-                        <button class="action-btn" title="语音输入" [disabled]="aiDesignAnalyzing" (click)="startVoiceInput()">
-                          <span class="icon-text">🎤</span>
-                        </button>
-                      </div>
-                      
-                      <!-- 右侧发送按钮 -->
-                      <button 
-                        class="send-btn" 
-                        [disabled]="aiDesignAnalyzing || !aiChatInput?.trim()"
-                        (click)="sendChatMessage()">
-                        @if (aiDesignAnalyzing) {
-                          <span class="btn-loading">
-                            <span class="spinner"></span>
-                          </span>
-                        } @else {
-                          <span class="icon-text">✉️</span>
-                        }
-                      </button>
-                    </div>
-                  </div>
-                  
-                  <!-- 快捷操作栏 -->
-                  <div class="quick-actions">
-                    <button class="quick-action-btn" (click)="clearChat()" [disabled]="aiChatMessages.length === 0">
-                      <span class="icon-text">🗑️</span>
-                      <span>清空对话</span>
-                    </button>
-                    <button class="quick-action-btn" (click)="exportChat()" [disabled]="aiChatMessages.length === 0">
-                      <span class="icon-text">💾</span>
-                      <span>导出对话</span>
-                    </button>
-                    <button class="quick-action-btn" (click)="confirmCurrentAnalysis()" [disabled]="aiChatMessages.length === 0">
-                      <span class="icon-text">✅</span>
-                      <span>确认分析结果</span>
-                    </button>
-                  </div>
-                </div>
-              </div>
-            </div>
-          }
-
-          <!-- 步骤2: 显示分析结果 -->
-          @if (aiDesignAnalysisResult && !aiDesignReport) {
-            <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>
-
-              <!-- 🔥 快速总结卡片(设计师关键信息) -->
-              @if (aiDesignAnalysisResult.structuredData?.quickSummary) {
-                <div class="result-card quick-summary-card">
-                  <div class="card-title">
-                    <span class="title-icon">⚡</span>
-                    <h4>图片分析总结</h4>
-                  </div>
-                  <div class="card-content quick-summary-content">
-                    <div class="summary-item">
-                      <div class="summary-label">
-                        <span class="label-icon">🎨</span>
-                        <span class="label-text">色彩基调</span>
-                      </div>
-                      <div class="summary-value color-tone">
-                        {{ aiDesignAnalysisResult.structuredData.quickSummary.colorTone }}
-                      </div>
-                    </div>
-                    <div class="summary-item">
-                      <div class="summary-label">
-                        <span class="label-icon">🪵</span>
-                        <span class="label-text">主要材质</span>
-                      </div>
-                      <div class="summary-value materials">
-                        {{ aiDesignAnalysisResult.structuredData.quickSummary.mainMaterials }}
-                      </div>
-                    </div>
-                    <div class="summary-item">
-                      <div class="summary-label">
-                        <span class="label-icon">✨</span>
-                        <span class="label-text">整体氛围</span>
-                      </div>
-                      <div class="summary-value atmosphere">
-                        {{ aiDesignAnalysisResult.structuredData.quickSummary.atmosphere }}
-                      </div>
-                    </div>
-                  </div>
-                </div>
-              }
-
-              <!-- 简洁摘要卡片 -->
-              @if (getAISummary()) {
-                <div class="result-card summary-card">
-                  <div class="card-title">
-                    <span class="title-icon">📋</span>
-                    <h4>设计概要</h4>
-                  </div>
-                  <div class="card-content">
-                    <p class="summary-text">{{ getAISummary() }}</p>
-                  </div>
-                </div>
-              }
-
-              <!-- 完整分析内容 -->
-              @if (aiDesignAnalysisResult.formattedContent || aiDesignAnalysisResult.rawContent) {
-                <div class="result-card full-analysis-card">
-                  <div class="card-title">
-                    <span class="title-icon">📊</span>
-                    <h4>详细分析</h4>
-                  </div>
-                  <div class="card-content analysis-content">
-                    <pre class="analysis-text">{{ aiDesignAnalysisResult.formattedContent || aiDesignAnalysisResult.rawContent }}</pre>
-                  </div>
-                </div>
-              }
-
-              <!-- 按维度查看(可选) -->
-              @if (aiDesignAnalysisResult.structuredData) {
-                <div class="result-card dimensions-card">
-                  <div class="card-title">
-                    <span class="title-icon">🔍</span>
-                    <h4>分维度查看</h4>
-                  </div>
-                  <div class="card-content">
-                    <div class="dimensions-grid">
-                      <!-- 空间定位 -->
-                      @if (aiDesignAnalysisResult.structuredData.spacePositioning) {
-                        <div class="dimension-item">
-                          <div class="dimension-header" (click)="toggleDimension('spacePositioning')">
-                            <span class="dimension-icon">🏠</span>
-                            <span class="dimension-title">空间定位与场景属性</span>
-                            <span class="toggle-icon">{{ expandedDimensions.has('spacePositioning') ? '▼' : '▶' }}</span>
-                          </div>
-                          @if (expandedDimensions.has('spacePositioning')) {
-                            <div class="dimension-content">
-                              <p>{{ aiDesignAnalysisResult.structuredData.spacePositioning }}</p>
-                            </div>
-                          }
-                        </div>
-                      }
-
-                      <!-- 色调分析 -->
-                      @if (aiDesignAnalysisResult.structuredData.colorAnalysis) {
-                        <div class="dimension-item">
-                          <div class="dimension-header" (click)="toggleDimension('colorAnalysis')">
-                            <span class="dimension-icon">🎨</span>
-                            <span class="dimension-title">色调精准分析</span>
-                            <span class="toggle-icon">{{ expandedDimensions.has('colorAnalysis') ? '▼' : '▶' }}</span>
-                          </div>
-                          @if (expandedDimensions.has('colorAnalysis')) {
-                            <div class="dimension-content">
-                              <p>{{ aiDesignAnalysisResult.structuredData.colorAnalysis }}</p>
-                            </div>
-                          }
-                        </div>
-                      }
-
-                      <!-- 材质解析 -->
-                      @if (aiDesignAnalysisResult.structuredData.materials) {
-                        <div class="dimension-item">
-                          <div class="dimension-header" (click)="toggleDimension('materials')">
-                            <span class="dimension-icon">🪨</span>
-                            <span class="dimension-title">材质应用解析</span>
-                            <span class="toggle-icon">{{ expandedDimensions.has('materials') ? '▼' : '▶' }}</span>
-                          </div>
-                          @if (expandedDimensions.has('materials')) {
-                            <div class="dimension-content">
-                              <p>{{ aiDesignAnalysisResult.structuredData.materials }}</p>
-                            </div>
-                          }
-                        </div>
-                      }
-
-                      <!-- 风格氛围 -->
-                      @if (aiDesignAnalysisResult.structuredData.style) {
-                        <div class="dimension-item">
-                          <div class="dimension-header" (click)="toggleDimension('style')">
-                            <span class="dimension-icon">✨</span>
-                            <span class="dimension-title">风格与氛围营造</span>
-                            <span class="toggle-icon">{{ expandedDimensions.has('style') ? '▼' : '▶' }}</span>
-                          </div>
-                          @if (expandedDimensions.has('style')) {
-                            <div class="dimension-content">
-                              <p>{{ aiDesignAnalysisResult.structuredData.style }}</p>
-                            </div>
-                          }
-                        </div>
-                      }
-
-                      <!-- 优化建议 -->
-                      @if (aiDesignAnalysisResult.structuredData.suggestions) {
-                        <div class="dimension-item">
-                          <div class="dimension-header" (click)="toggleDimension('suggestions')">
-                            <span class="dimension-icon">💡</span>
-                            <span class="dimension-title">专业优化建议</span>
-                            <span class="toggle-icon">{{ expandedDimensions.has('suggestions') ? '▼' : '▶' }}</span>
-                          </div>
-                          @if (expandedDimensions.has('suggestions')) {
-                            <div class="dimension-content">
-                              <p>{{ aiDesignAnalysisResult.structuredData.suggestions }}</p>
-                            </div>
-                          }
-                        </div>
-                      }
-                    </div>
-                  </div>
-                </div>
-              }
-
-              <!-- 生成客服标注按钮 -->
-              <div class="action-section">
-                <button
-                  class="btn btn-outline btn-generate"
-                  (click)="generateServiceNotes()">
-                  <span class="icon-text">📄</span>
-                  <span>生成客服标注</span>
-                </button>
-                <button
-                  class="btn btn-primary btn-generate"
-                  (click)="generateClientReport()"
-                  [disabled]="aiDesignGeneratingReport">
-                  @if (aiDesignGeneratingReport) {
-                    <span class="loading-spinner"></span>
-                    <span>生成报告中...</span>
-                  } @else {
-                    <span class="icon-text">📄</span>
-                    <span>生成客户报告</span>
-                  }
-                </button>
-              </div>
-            </div>
-          }
-
-          <!-- 步骤3: 显示客户报告 -->
-          @if (aiDesignReport) {
-            <div class="report-section">
-              <div class="report-header">
-                <div class="header-icon">📋</div>
-                <h3>设计分析报告</h3>
-                <button class="btn-reset" (click)="resetAIAnalysis()">重新分析</button>
-              </div>
-
-              <div class="report-content markdown-body">
-                <pre class="report-text">{{ aiDesignReport }}</pre>
-              </div>
-
-              <!-- 确认按钮 - 优化企业微信端布局 -->
-              @if (!aiDesignReportConfirmed) {
-                <div class="action-section report-actions">
-                  <button
-                    class="btn btn-outline btn-reanalyze"
-                    (click)="resetAIAnalysis()">
-                    <span class="icon-text">🔄</span>
-                    <span>重新分析</span>
-                  </button>
-                  <button
-                    class="btn btn-info btn-export"
-                    (click)="exportReportToWord()"
-                    [disabled]="exportingWord">
-                    @if (exportingWord) {
-                      <span class="loading-spinner"></span>
-                      <span>导出中...</span>
-                    } @else {
-                      <span class="icon-text">📥</span>
-                      <span>导出Word</span>
-                    }
-                  </button>
-                  <button
-                    class="btn btn-success btn-confirm"
-                    (click)="confirmDesignReport()">
-                    <span class="icon-text">✅</span>
-                    <span>确认保存</span>
-                  </button>
-                </div>
-              }
-            </div>
-          }
-
-          <!-- 隐藏的文件input -->
-          <input 
-            type="file" 
-            id="aiDesignFileInput" 
-            (change)="handleAIFileSelect($event)" 
-            accept="image/*,.pdf,.dwg,.dxf" 
-            multiple 
-            style="display: none;">
-        </div>
-      </div>
-    </div>
+    
+    <!-- AI设计分析区域 -->
+    <app-ai-design-analysis
+      [project]="project"
+      [projectProducts]="projectProducts"
+      [canEdit]="canEdit"
+      (analysisComplete)="onAnalysisComplete($event)">
+    </app-ai-design-analysis>
 
     <!-- 全局需求 (始终显示) -->
     <div class="global-requirements">
@@ -572,1040 +34,27 @@
           <div class="card-content">
             <div class="spaces-container">
               @for (space of projectProducts; track space.id) {
-                <div class="space-item" [class.expanded]="isSpaceExpanded(space.id)">
-                  <!-- 空间头部 - 折叠时显示 -->
-                  <div class="space-header" (click)="toggleSpaceExpansion(space.id)">
-                    <div class="space-name-section">
-                      {{ getSpaceDisplayName(space) }}
-                      <span class="reference-count-badge">
-                        参考 {{ getTotalSpaceFileCount(space.id) }}
-                      </span>
-                    </div>
-                    
-                    <!-- 特殊需求显示 -->
-                    @if (getSpaceSpecialRequirements(space.id)) {
-                      <div class="special-requirements-box">
-                        <span class="requirements-label">特殊要求:</span>
-                        <span class="requirements-text">{{ getSpaceSpecialRequirements(space.id) | slice:0:30 }}{{ getSpaceSpecialRequirements(space.id).length > 30 ? '...' : '' }}</span>
-                      </div>
-                    }
-                    
-                    <!-- 操作按钮 -->
-                    <div class="header-actions">
-                      @if (canEdit) {
-                        <button class="btn-icon-small btn-ai" title="AI设计分析" (click)="openAIDesignDialog(space); $event.stopPropagation()">
-                          <span class="icon-text">🤖</span>
-                        </button>
-                        <button class="btn-icon-small btn-edit" title="编辑特殊要求" (click)="toggleSpaceExpansion(space.id); $event.stopPropagation()">
-                          <span class="icon-text">✏️</span>
-                        </button>
-                      }
-                    </div>
-                    
-                    <!-- 展开/收起图标 -->
-                    <div class="expand-icon" [class.expanded]="isSpaceExpanded(space.id)">
-                      <svg width="28" height="28" viewBox="0 0 24 24" fill="currentColor">
-                        <path d="M7 10l5 5 5-5z"/>
-                      </svg>
-                    </div>
-                  </div>
-
-                  <!-- 空间内容 - 展开时显示 -->
-                  @if (isSpaceExpanded(space.id)) {
-                    <div class="space-content">
-                      <!-- 拖拽上传区域 -->
-                      <div class="drag-drop-zone"
-                           (dragover)="onDragOver($event, space.id)"
-                           (dragleave)="onDragLeave($event)"
-                           (drop)="onDrop($event, space.id)"
-                           [class.drag-over]="isDragOver && dragOverSpaceId === space.id">
-                        <div class="drag-drop-content">
-                          <div class="drag-drop-icon">
-                            <ion-icon name="cloud-upload-outline"></ion-icon>
-                          </div>
-                          <h4>拖拽参考图片到此</h4>
-                          <p>或点击下方按钮上传</p>
-                          <p class="drag-hint">AI将自动分析图片并智能分类</p>
-                        </div>
-                      </div>
-
-                      <!-- 图片类型导航标签 -->
-                      <div class="image-type-tabs">
-                        @for (type of imageTypes; track type.id) {
-                          <button
-                            class="tab-button"
-                            [class.active]="activeImageTab[space.id] === type.id"
-                            (click)="selectImageTab(space.id, type.id)">
-                            <span class="tab-label">{{ type.name }}</span>
-                            @if (getImageCountByType(space.id, type.id) > 0) {
-                              <span class="tab-badge">{{ getImageCountByType(space.id, type.id) }}</span>
-                            }
-                          </button>
-                        }
-                      </div>
-
-                      <!-- 图片展示区域 -->
-                      <div class="images-section">
-                        @if (activeImageTab[space.id] === 'all') {
-                          <!-- 全部图片和CAD文件 -->
-                          <div class="section-header">
-                            <h5>所有参考文件</h5>
-                            @if (canEdit) {
-                              <input
-                                type="file"
-                                accept="image/*"
-                                multiple
-                                (change)="uploadReferenceImage($event, space.id)"
-                                [disabled]="uploading"
-                                hidden
-                                [id]="'spaceImageInput_' + space.id" />
-                              <button
-                                class="btn btn-sm btn-outline"
-                                (click)="triggerFileClick('spaceImageInput_' + space.id)"
-                                [disabled]="uploading">
-                                <ion-icon name="add"></ion-icon>
-                                上传参考图
-                              </button>
-                            }
-                          </div>
-                          <div class="section-content">
-                            @if (getSpaceReferenceImages(space.id).length > 0) {
-                              <div class="images-grid">
-                                @for (image of getSpaceReferenceImages(space.id); track image.id) {
-                                  <div class="image-item">
-                                    <img [src]="image.url" [alt]="image.name" (click)="viewImageColorAnalysis(image.id)" />
-                                    <div class="image-overlay">
-                                      <div class="overlay-top">
-                                        <span class="badge" [class]="getImageTypeBadgeClass(image.type)">
-                                          {{ getImageTypeLabel(image.type) }}
-                                        </span>
-                                        @if (hasImageAnalysis(image.id)) {
-                                          <span class="badge badge-success">
-                                            <ion-icon name="sparkles"></ion-icon>
-                                          </span>
-                                        }
-                                      </div>
-                                      <div class="overlay-actions">
-                                        <button
-                                          class="btn-icon btn-primary"
-                                          (click)="viewImageColorAnalysis(image.id); $event.stopPropagation()"
-                                          title="查看色彩分析">
-                                          <ion-icon name="color-palette"></ion-icon>
-                                        </button>
-                                        @if (canEdit) {
-                                          <button
-                                            class="btn-icon btn-danger"
-                                            (click)="deleteReferenceImage(image.id); $event.stopPropagation()">
-                                            <ion-icon name="trash"></ion-icon>
-                                          </button>
-                                        }
-                                      </div>
-                                    </div>
-                                  </div>
-                                }
-                              </div>
-                            } @else {
-                              <div class="empty-state">
-                                <ion-icon name="image-outline"></ion-icon>
-                                <p>暂无参考图片</p>
-                              </div>
-                            }
-                          </div>
-
-                          <!-- CAD文件显示 -->
-                          @if (getSpaceCADFiles(space.id).length > 0) {
-                            <div class="section-header">
-                              <h5>CAD文件</h5>
-                            </div>
-                            <div class="section-content">
-                              <div class="cad-files-list">
-                                @for (cadFile of getSpaceCADFiles(space.id); track cadFile.id) {
-                                  <div class="cad-file-item">
-                                    <div class="cad-icon">
-                                      <ion-icon name="document"></ion-icon>
-                                    </div>
-                                    <div class="cad-info">
-                                      <div class="cad-name">{{ cadFile.name }}</div>
-                                      <div class="cad-meta">
-                                        @if (hasImageAnalysis(cadFile.id)) {
-                                          <span class="badge badge-success">
-                                            <ion-icon name="sparkles"></ion-icon>
-                                            已分析
-                                          </span>
-                                        }
-                                      </div>
-                                    </div>
-                                    @if (canEdit) {
-                                      <button
-                                        class="btn-icon btn-danger"
-                                        (click)="deleteCADFile(cadFile.id); $event.stopPropagation()">
-                                        <ion-icon name="trash"></ion-icon>
-                                      </button>
-                                    }
-                                  </div>
-                                }
-                              </div>
-                            </div>
-                          }
-
-                          <!-- AI分析结果展示 - 新布局 -->
-                          @if (getImageAnalysisResults(space.id).length > 0) {
-                            <div class="section-divider"></div>
-                            <div class="ai-analysis-section">
-                              <div class="section-header">
-                                <h5>
-                                  <ion-icon name="sparkles"></ion-icon>
-                                  AI分析结果
-                                </h5>
-                              </div>
-                              <div class="analysis-results-list">
-                                @for (analysis of getImageAnalysisResults(space.id); track analysis.imageId) {
-                                  <div class="analysis-item-card">
-                                    <!-- 左侧:图片 -->
-                                    <div class="analysis-image-section">
-                                      <div class="analysis-image">
-                                        <img [src]="getImageUrl(analysis.imageId)" [alt]="'Analysis ' + analysis.imageId" />
-                                      </div>
-                                    </div>
-
-                                    <!-- 右侧:分析结果 -->
-                                    <div class="analysis-results-section">
-                                      <!-- 参考类型和用户要求(按图1格式) -->
-                                      <div class="analysis-header-box">
-                                        <div class="header-info">
-                                          <div class="info-item">
-                                            <span class="info-label">参考类型:</span>
-                                            <span class="info-value">{{ getImageTypeLabel(analysis.imageType) }}</span>
-                                          </div>
-                                          <div class="info-divider">|</div>
-                                          <div class="info-item">
-                                            <span class="info-label">备注用户要求</span>
-                                          </div>
-                                        </div>
-                                      </div>
-
-                                      <!-- AI分析结果内容 -->
-                                      <div class="analysis-details-content">
-                                        <!-- 原有分析维度 -->
-                                        @if (analysis.originalAnalysis) {
-                                          <div class="analysis-group">
-                                            <h6>原有分析维度</h6>
-                                            <div class="analysis-grid">
-                                              @if (analysis.originalAnalysis.quality) {
-                                                <div class="analysis-row">
-                                                  <span class="label">质量评分:</span>
-                                                  <span class="value">{{ analysis.originalAnalysis.quality.score }}/100 ({{ analysis.originalAnalysis.quality.level }})</span>
-                                                </div>
-                                              }
-                                              @if (analysis.originalAnalysis.content) {
-                                                <div class="analysis-row">
-                                                  <span class="label">内容分类:</span>
-                                                  <span class="value">{{ analysis.originalAnalysis.content.category }}</span>
-                                                </div>
-                                              }
-                                              @if (analysis.originalAnalysis.technical) {
-                                                <div class="analysis-row">
-                                                  <span class="label">像素:</span>
-                                                  <span class="value">{{ analysis.originalAnalysis.technical.megapixels }}MP</span>
-                                                </div>
-                                              }
-                                            </div>
-                                          </div>
-                                        }
-
-                                        <!-- 新增分析维度 -->
-                                        @if (analysis.enhancedAnalysis) {
-                                          <div class="analysis-group">
-                                            <h6>设计分析维度</h6>
-                                            <div class="analysis-grid">
-                                              @if (analysis.enhancedAnalysis.style) {
-                                                <div class="analysis-row">
-                                                  <span class="label">风格:</span>
-                                                  <span class="value">{{ analysis.enhancedAnalysis.style }}</span>
-                                                </div>
-                                              }
-                                              @if (analysis.enhancedAnalysis.atmosphere) {
-                                                <div class="analysis-row">
-                                                  <span class="label">氛围:</span>
-                                                  <span class="value">{{ analysis.enhancedAnalysis.atmosphere }}</span>
-                                                </div>
-                                              }
-                                              @if (analysis.enhancedAnalysis.material) {
-                                                <div class="analysis-row">
-                                                  <span class="label">材质:</span>
-                                                  <span class="value">{{ analysis.enhancedAnalysis.material }}</span>
-                                                </div>
-                                              }
-                                              @if (analysis.enhancedAnalysis.texture) {
-                                                <div class="analysis-row">
-                                                  <span class="label">纹理:</span>
-                                                  <span class="value">{{ analysis.enhancedAnalysis.texture }}</span>
-                                                </div>
-                                              }
-                                            </div>
-                                          </div>
-                                        }
-
-                                        <!-- 风格元素分析(新增) -->
-                                        @if (analysis.styleElements) {
-                                          <div class="analysis-group">
-                                            <h6>风格元素</h6>
-                                            <div class="analysis-tags">
-                                              @for (keyword of analysis.styleElements.styleKeywords; track keyword) {
-                                                <span class="tag">{{ keyword }}</span>
-                                              }
-                                            </div>
-                                          </div>
-                                        }
-
-                                        <!-- 色彩搭配分析(新增) -->
-                                        @if (analysis.colorScheme) {
-                                          <div class="analysis-group">
-                                            <h6>色彩搭配</h6>
-                                            <div class="color-scheme-display">
-                                              @if (analysis.colorScheme.primaryColors && analysis.colorScheme.primaryColors.length > 0) {
-                                                <div class="color-row">
-                                                  <span class="color-label">主色调:</span>
-                                                  <div class="color-samples">
-                                                    @for (color of analysis.colorScheme.primaryColors; track color) {
-                                                      <div class="color-sample" [style.backgroundColor]="color" [title]="color"></div>
-                                                    }
-                                                  </div>
-                                                </div>
-                                              }
-                                              @if (analysis.colorScheme.secondaryColors && analysis.colorScheme.secondaryColors.length > 0) {
-                                                <div class="color-row">
-                                                  <span class="color-label">辅助色:</span>
-                                                  <div class="color-samples">
-                                                    @for (color of analysis.colorScheme.secondaryColors; track color) {
-                                                      <div class="color-sample" [style.backgroundColor]="color" [title]="color"></div>
-                                                    }
-                                                  </div>
-                                                </div>
-                                              }
-                                              @if (analysis.colorScheme.accentColors && analysis.colorScheme.accentColors.length > 0) {
-                                                <div class="color-row">
-                                                  <span class="color-label">点缀色:</span>
-                                                  <div class="color-samples">
-                                                    @for (color of analysis.colorScheme.accentColors; track color) {
-                                                      <div class="color-sample" [style.backgroundColor]="color" [title]="color"></div>
-                                                    }
-                                                  </div>
-                                                </div>
-                                              }
-                                            </div>
-                                          </div>
-                                        }
-
-                                        <!-- 材质分析(新增) -->
-                                        @if (analysis.materialAnalysis) {
-                                          <div class="analysis-group">
-                                            <h6>材质分析</h6>
-                                            <div class="analysis-tags">
-                                              @for (material of analysis.materialAnalysis.materials; track material) {
-                                                <span class="tag tag-material">{{ material }}</span>
-                                              }
-                                            </div>
-                                          </div>
-                                        }
-
-                                        <!-- 布局特征分析(新增) -->
-                                        @if (analysis.layoutFeatures) {
-                                          <div class="analysis-group">
-                                            <h6>布局特征</h6>
-                                            <div class="analysis-tags">
-                                              @for (feature of analysis.layoutFeatures.features; track feature) {
-                                                <span class="tag tag-layout">{{ feature }}</span>
-                                              }
-                                            </div>
-                                          </div>
-                                        }
-
-                                        <!-- 空间氛围分析(新增) -->
-                                        @if (analysis.atmosphereAnalysis) {
-                                          <div class="analysis-group">
-                                            <h6>空间氛围</h6>
-                                            <div class="analysis-row">
-                                              <span class="value">{{ analysis.atmosphereAnalysis.atmosphere }}</span>
-                                            </div>
-                                          </div>
-                                        }
-
-                                        <!-- 色彩解析报告 -->
-                                        @if (analysis.colorAnalysis) {
-                                          <div class="analysis-group">
-                                            <h6>色彩解析报告</h6>
-                                            <div class="color-analysis-content">
-                                              @if (analysis.colorAnalysis.brightness) {
-                                                <div class="color-item">
-                                                  <span class="color-label">明度:</span>
-                                                  <span class="color-value">{{ analysis.colorAnalysis.brightness }}</span>
-                                                </div>
-                                              }
-                                              @if (analysis.colorAnalysis.hue) {
-                                                <div class="color-item">
-                                                  <span class="color-label">色相:</span>
-                                                  <span class="color-value">{{ analysis.colorAnalysis.hue }}</span>
-                                                </div>
-                                              }
-                                              @if (analysis.colorAnalysis.saturation) {
-                                                <div class="color-item">
-                                                  <span class="color-label">饱和度:</span>
-                                                  <span class="color-value">{{ analysis.colorAnalysis.saturation }}</span>
-                                                </div>
-                                              }
-                                              @if (analysis.colorAnalysis.openness) {
-                                                <div class="color-item">
-                                                  <span class="color-label">色彩开放度:</span>
-                                                  <span class="color-value">{{ analysis.colorAnalysis.openness }}</span>
-                                                </div>
-                                              }
-
-                                              <!-- 颜色样本 -->
-                                              @if (analysis.colorAnalysis.extracted && analysis.colorAnalysis.extracted.length > 0) {
-                                                <div class="color-swatches-group">
-                                                  <span class="color-label">提取颜色:</span>
-                                                  <div class="color-swatches">
-                                                    @for (color of analysis.colorAnalysis.extracted; track color) {
-                                                      <div class="color-swatch" [style.backgroundColor]="color" [title]="color"></div>
-                                                    }
-                                                  </div>
-                                                </div>
-                                              }
-
-                                              @if (analysis.colorAnalysis.organized && analysis.colorAnalysis.organized.length > 0) {
-                                                <div class="color-org-group">
-                                                  <span class="color-label">组织颜色 (主次):</span>
-                                                  <div class="color-organization">
-                                                    @for (org of analysis.colorAnalysis.organized; track org.color) {
-                                                      <div class="color-org-item">
-                                                        <div class="color-org-swatch" [style.backgroundColor]="org.color"></div>
-                                                        <span class="color-org-label">{{ org.role }}: {{ org.percentage }}%</span>
-                                                      </div>
-                                                    }
-                                                  </div>
-                                                </div>
-                                              }
-                                            </div>
-                                          </div>
-                                        }
-                                      </div>
-                                    </div>
-                                  </div>
-                                }
-                              </div>
-                            </div>
-                          }
-                          
-                          <!-- 用户需求备注 -->
-                          <div class="section-divider"></div>
-                          <div class="user-notes-section">
-                            <div class="section-header">
-                              <h5>用户需求备注</h5>
-                            </div>
-                            <div class="section-content">
-                              <textarea
-                                class="form-textarea"
-                                [(ngModel)]="spaceSpecialRequirements[space.id]"
-                                (ngModelChange)="setSpaceSpecialRequirements(space.id, $event)"
-                                [disabled]="!canEdit"
-                                rows="4"
-                                [placeholder]="'描述' + getSpaceDisplayName(space) + '的特殊要求和注意事项'"></textarea>
-                            </div>
-                          </div>
-                        } @else if (activeImageTab[space.id] === 'cad') {
-                          <!-- CAD文件 -->
-                          <div class="section-header">
-                            <h5>CAD文件</h5>
-                            @if (canEdit) {
-                              <input
-                                type="file"
-                                accept=".dwg,.dxf,.pdf"
-                                multiple
-                                (change)="uploadCAD($event, space.id)"
-                                [disabled]="uploading"
-                                hidden
-                                [id]="'spaceCADInput_' + space.id" />
-                              <button
-                                class="btn btn-sm btn-outline"
-                                (click)="triggerFileClick('spaceCADInput_' + space.id)"
-                                [disabled]="uploading">
-                                <ion-icon name="add"></ion-icon>
-                                上传CAD
-                              </button>
-                            }
-                          </div>
-                          <div class="section-content">
-                            @if (getSpaceCADFiles(space.id).length > 0) {
-                              <div class="file-list">
-                                @for (file of getSpaceCADFiles(space.id); track file.id) {
-                                  <div class="file-item">
-                                    <ion-icon name="document-text" class="file-icon"></ion-icon>
-                                    <div class="file-info">
-                                      <h6>{{ file.name }}</h6>
-                                      <p>{{ formatFileSize(file.size) }} · {{ file.uploadTime | date:'MM-dd HH:mm' }}</p>
-                                      @if (hasImageAnalysis(file.id)) {
-                                        <span class="badge badge-success">
-                                          <ion-icon name="sparkles"></ion-icon>
-                                          已分析
-                                        </span>
-                                      }
-                                    </div>
-                                    @if (canEdit) {
-                                      <button
-                                        class="btn-icon btn-danger"
-                                        (click)="deleteCAD(file.id)">
-                                        <ion-icon name="trash"></ion-icon>
-                                      </button>
-                                    }
-                                  </div>
-                                }
-                              </div>
-                            } @else {
-                              <div class="empty-state">
-                                <ion-icon name="document-outline"></ion-icon>
-                                <p>暂无CAD文件</p>
-                              </div>
-                            }
-                          </div>
-                        } @else {
-                          <!-- 按类型过滤的图片 -->
-                          <div class="section-header">
-                            <h5>{{ getImageTypeLabel(activeImageTab[space.id]) }}图片</h5>
-                            @if (canEdit) {
-                              <input
-                                type="file"
-                                accept="image/*"
-                                multiple
-                                (change)="uploadReferenceImageWithType($event, space.id, activeImageTab[space.id])"
-                                [disabled]="uploading"
-                                hidden
-                                [id]="'spaceImageInput_' + space.id + '_' + activeImageTab[space.id]" />
-                              <button
-                                class="btn btn-sm btn-outline"
-                                (click)="triggerFileClick('spaceImageInput_' + space.id + '_' + activeImageTab[space.id])"
-                                [disabled]="uploading">
-                                <ion-icon name="add"></ion-icon>
-                                上传{{ getImageTypeLabel(activeImageTab[space.id]) }}图
-                              </button>
-                            }
-                          </div>
-                          <div class="section-content">
-                            @if (getImagesByType(space.id, activeImageTab[space.id]).length > 0) {
-                              <div class="images-grid">
-                                @for (image of getImagesByType(space.id, activeImageTab[space.id]); track image.id) {
-                                  <div class="image-item">
-                                    <img [src]="image.url" [alt]="image.name" (click)="viewImageColorAnalysis(image.id)" />
-                                    <div class="image-overlay">
-                                      <div class="overlay-top">
-                                        <span class="badge" [class]="getImageTypeBadgeClass(image.type)">
-                                          {{ getImageTypeLabel(image.type) }}
-                                        </span>
-                                        @if (hasImageAnalysis(image.id)) {
-                                          <span class="badge badge-success">
-                                            <ion-icon name="sparkles"></ion-icon>
-                                          </span>
-                                        }
-                                      </div>
-                                      <div class="overlay-actions">
-                                        <button
-                                          class="btn-icon btn-primary"
-                                          (click)="viewImageColorAnalysis(image.id); $event.stopPropagation()"
-                                          title="查看色彩分析">
-                                          <ion-icon name="color-palette"></ion-icon>
-                                        </button>
-                                        @if (canEdit) {
-                                          <button
-                                            class="btn-icon btn-danger"
-                                            (click)="deleteReferenceImage(image.id); $event.stopPropagation()">
-                                            <ion-icon name="trash"></ion-icon>
-                                          </button>
-                                        }
-                                      </div>
-                                    </div>
-                                  </div>
-                                }
-                              </div>
-                            } @else {
-                              <div class="empty-state">
-                                <ion-icon name="image-outline"></ion-icon>
-                                <p>暂无{{ getImageTypeLabel(activeImageTab[space.id]) }}图片</p>
-                              </div>
-                            }
-                          </div>
-                        }
-                      </div>
-                    </div>
-                  }
-                </div>
-              }
-            </div>
-          </div>
-        </div>
-
-        <!-- 风格偏好 - 已隐藏 -->
-        <!-- 
-        <div class="card style-preferences-card">
-          <div class="card-header">
-            <h3 class="card-title">
-              <span class="icon">🎨</span>
-              风格偏好
-            </h3>
-          </div>
-          <div class="card-content">
-            <div class="form-group">
-              <label class="form-label">风格偏好 <span class="required">*</span></label>
-              <input
-                type="text"
-                class="form-input"
-                [(ngModel)]="globalRequirements.stylePreference"
-                [disabled]="!canEdit"
-                placeholder="如:现代简约、北欧、轻奢等" />
-            </div>
-
-            <div class="color-scheme">
-              <div class="form-group">
-                <label class="form-label">色彩氛围</label>
-                <select
-                  class="form-select"
-                  [(ngModel)]="globalRequirements.colorScheme.atmosphere"
-                  [disabled]="!canEdit">
-                  <option value="">请选择</option>
-                  <option value="温馨">温馨</option>
-                  <option value="高级">高级</option>
-                  <option value="简约">简约</option>
-                  <option value="时尚">时尚</option>
-                  <option value="北欧">北欧</option>
-                  <option value="中式">中式</option>
-                  <option value="欧式">欧式</option>
-                </select>
-              </div>
-
-              <div class="color-inputs">
-                <div class="form-group">
-                  <label class="form-label">主色调</label>
-                  <input
-                    type="color"
-                    class="form-color-input"
-                    [(ngModel)]="globalRequirements.colorScheme.primary"
-                    [disabled]="!canEdit" />
-                </div>
-                <div class="form-group">
-                  <label class="form-label">副色调</label>
-                  <input
-                    type="color"
-                    class="form-color-input"
-                    [(ngModel)]="globalRequirements.colorScheme.secondary"
-                    [disabled]="!canEdit" />
-                </div>
-                <div class="form-group">
-                  <label class="form-label">点缀色</label>
-                  <input
-                    type="color"
-                    class="form-color-input"
-                    [(ngModel)]="globalRequirements.colorScheme.accent"
-                    [disabled]="!canEdit" />
-                </div>
-              </div>
-            </div>
-
-            <div class="quality-level">
-              <label class="form-label">质量等级</label>
-              <div class="radio-group">
-                <label class="radio-item">
-                  <input
-                    type="radio"
-                    name="qualityLevel"
-                    value="standard"
-                    [(ngModel)]="globalRequirements.qualityLevel"
-                    [disabled]="!canEdit" />
-                  <span class="radio-label">{{ getQualityLevelName('standard') }}</span>
-                </label>
-                <label class="radio-item">
-                  <input
-                    type="radio"
-                    name="qualityLevel"
-                    value="premium"
-                    [(ngModel)]="globalRequirements.qualityLevel"
-                    [disabled]="!canEdit" />
-                  <span class="radio-label">{{ getQualityLevelName('premium') }}</span>
-                </label>
-                <label class="radio-item">
-                  <input
-                    type="radio"
-                    name="qualityLevel"
-                    value="luxury"
-                    [(ngModel)]="globalRequirements.qualityLevel"
-                    [disabled]="!canEdit" />
-                  <span class="radio-label">{{ getQualityLevelName('luxury') }}</span>
-                </label>
-              </div>
-            </div>
-
-            <div class="form-group">
-              <label class="form-label">特殊需求</label>
-              <textarea
-                class="form-textarea"
-                [(ngModel)]="globalRequirements.specialRequirements"
-                [disabled]="!canEdit"
-                rows="3"
-                placeholder="描述任何特殊需求或注意事项"></textarea>
-            </div>
-          </div>
-        </div>
-        -->
-      </div>
-
-    <!-- 空间需求 (已隐藏,功能已集成到上方空间需求管理中) -->
-    <!-- 
-    @if (requirementsSegment == 'spaces' && isMultiProductProject) {
-      <div class="space-requirements">
-        @for (space of projectProducts; track space.id) {
-          <div class="card space-requirement-card" [class.active]="activeProductId == space.id">
-            <div class="card-header">
-              <h3 class="card-title">
-                {{ getSpaceDisplayName(space) }}
-              </h3>
-              <span class="completion-badge">{{ calculateProductCompletion(space.id) }}%</span>
-            </div>
-            <div class="card-content">
-              <div class="form-group">
-                <label class="form-label">空间特殊要求</label>
-                <textarea
-                  class="form-textarea"
-                  [(ngModel)]="currentProductSpecificRequirements"
-                  [disabled]="!canEdit"
-                  rows="2"
-                  placeholder="描述该空间的特殊要求"></textarea>
-              </div>
-
-              <div class="space-reference-images">
-                <h4>空间参考图片</h4>
-                <div class="images-grid small">
-                  @for (image of getSpaceReferenceImages(space.id); track image.id) {
-                    <div class="image-item small">
-                      <img [src]="image.url" [alt]="image.name" />
-                      <div class="image-overlay">
-                        @if (canEdit) {
-                          <button
-                            class="btn-icon btn-danger"
-                            (click)="deleteReferenceImage(image.id)">
-                            <ion-icon name="trash"></ion-icon>
-                          </button>
-                        }
-                      </div>
-                    </div>
-                  }
-
-                  @if (canEdit) {
-                    <div class="upload-placeholder small">
-                      <input
-                        type="file"
-                        accept="image/*"
-                        multiple
-                        (change)="uploadReferenceImage($event, space.id)"
-                        [disabled]="uploading"
-                        hidden
-                        id="spaceFileInput_{{ space.id }}" />
-                      <button
-                        class="btn btn-outline btn-sm"
-                        (click)="triggerFileClick('spaceFileInput_' + space.id)"
-                        [disabled]="uploading">
-                        <ion-icon name="add"></ion-icon>
-                      </button>
-                    </div>
-                  }
-                </div>
-              </div>
-            </div>
-          </div>
-        }
-      </div>
-    }
-    -->
-
-
-
-    <!-- 综合AI分析 -->
-    @if (aiAnalysisResults.comprehensiveAnalysis) {
-      <div class="card comprehensive-analysis-card">
-        <div class="card-header">
-          <h3 class="card-title">
-            <ion-icon name="analytics"></ion-icon>
-            综合AI分析
-          </h3>
-          <span class="badge badge-success">
-            <ion-icon name="checkmark-circle"></ion-icon>
-            分析完成
-          </span>
-        </div>
-        <div class="card-content">
-          <div class="comprehensive-analysis-content">
-            <!-- 整体风格 -->
-            <div class="analysis-section">
-              <h4>整体风格定位</h4>
-              <p>{{ aiAnalysisResults.comprehensiveAnalysis.overallStyle }}</p>
-            </div>
-
-            <!-- AI推荐色彩方案 -->
-            <div class="analysis-section">
-              <h4>AI推荐色彩方案</h4>
-              <div class="ai-color-scheme">
-                <div class="color-item">
-                  <div class="color-swatch" [style.background-color]="aiAnalysisResults.comprehensiveAnalysis.colorScheme.primary" [title]="aiAnalysisResults.comprehensiveAnalysis.colorScheme.primary"></div>
-                  <span class="color-label">主色调</span>
-                </div>
-                <div class="color-item">
-                  <div class="color-swatch" [style.background-color]="aiAnalysisResults.comprehensiveAnalysis.colorScheme.secondary" [title]="aiAnalysisResults.comprehensiveAnalysis.colorScheme.secondary"></div>
-                  <span class="color-label">副色调</span>
-                </div>
-                <div class="color-item">
-                  <div class="color-swatch" [style.background-color]="aiAnalysisResults.comprehensiveAnalysis.colorScheme.accent" [title]="aiAnalysisResults.comprehensiveAnalysis.colorScheme.accent"></div>
-                  <span class="color-label">点缀色</span>
-                </div>
-              </div>
-            </div>
-
-            <!-- 材质推荐 -->
-            <div class="analysis-section">
-              <h4>AI材质推荐</h4>
-              <div class="tags">
-                @for (material of aiAnalysisResults.comprehensiveAnalysis.materialRecommendations; track $index) {
-                  <span class="badge badge-tertiary">{{ material }}</span>
-                }
-              </div>
-            </div>
-
-            <!-- 布局优化建议 -->
-            <div class="analysis-section">
-              <h4>布局优化建议</h4>
-              <ul class="optimization-list">
-                @for (optimization of aiAnalysisResults.comprehensiveAnalysis.layoutOptimization; track $index) {
-                  <li>{{ optimization }}</li>
-                }
-              </ul>
-            </div>
-
-            <!-- AI预算评估 -->
-            <div class="analysis-section">
-              <h4>家装预算评估</h4>
-              <div class="budget-assessment">
-                <div class="budget-range">
-                  <span class="label">预估范围:</span>
-                  <span class="value">¥{{ aiAnalysisResults.comprehensiveAnalysis.budgetAssessment.estimatedMin?.toLocaleString() }} - ¥{{ aiAnalysisResults.comprehensiveAnalysis.budgetAssessment.estimatedMax?.toLocaleString() }}</span>
-                </div>
-                <div class="risk-level">
-                  <span class="label">风险等级:</span>
-                  <span class="badge" [class]="getRiskLevelClass(aiAnalysisResults.comprehensiveAnalysis.budgetAssessment.riskLevel)">
-                    {{ getRiskLevelName(aiAnalysisResults.comprehensiveAnalysis.budgetAssessment.riskLevel) }}
-                  </span>
-                </div>
-              </div>
-            </div>
-
-            <!-- 风险因素 -->
-            <div class="analysis-section">
-              <h4>潜在风险因素</h4>
-              <div class="tags">
-                @for (risk of aiAnalysisResults.comprehensiveAnalysis.riskFactors; track $index) {
-                  <span class="badge badge-warning">{{ risk }}</span>
-                }
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    }
-
-    <!-- AI生成方案 -->
-    <div class="card ai-solution-card">
-      <div class="card-header">
-        <h3 class="card-title">
-          <ion-icon name="sparkles"></ion-icon>
-          AI设计方案
-        </h3>
-        <div class="completion-indicator">
-          <span class="label">需求完成度</span>
-          <div class="progress-bar">
-            <div class="progress-fill" [style.width]="calculateRequirementsCompleteness() + '%'"></div>
-          </div>
-          <span class="progress-text">{{ calculateRequirementsCompleteness() }}%</span>
-        </div>
-      </div>
-      <div class="card-content">
-        @if (!aiSolution) {
-          <div class="empty-state">
-            <ion-icon name="sparkles-outline" class="icon-large"></ion-icon>
-            <p>尚未生成AI方案</p>
-            @if (canEdit) {
-              <button
-                class="btn btn-primary"
-                (click)="generateAISolution()"
-                [disabled]="generating || aiGeneratingComprehensive">
-                @if (generating || aiGeneratingComprehensive) {
-                  <div class="spinner-small">
-                    <div class="spinner-circle"></div>
-                  </div>
-                  生成中...
-                } @else {
-                  <ion-icon name="sparkles"></ion-icon>
-                  生成AI方案
-                }
-              </button>
-            }
-          </div>
-        } @else {
-          <div class="ai-solution-content">
-            <div class="solution-header">
-              <span class="badge badge-success">
-                <ion-icon name="checkmark"></ion-icon>
-                已生成
-              </span>
-              @if (canEdit) {
-                <button
-                  class="btn btn-outline btn-sm"
-                  (click)="generateAISolution()"
-                  [disabled]="generating || aiGeneratingComprehensive">
-                  <ion-icon name="refresh"></ion-icon>
-                  重新生成
-                </button>
-              }
-            </div>
-
-            <div class="solution-summary">
-              <p>{{ aiSolution.content }}</p>
-            </div>
-
-            <!-- 空间方案 -->
-            <div class="spaces-solution">
-              @for (space of aiSolution.spaces; track space.id) {
-                <div class="space-solution-item">
-                  <div class="space-header">
-                    <h4>{{ space.name }}</h4>
-                    <span class="badge" [class]="getProcessBadgeClass(space.type)">{{ getSpaceTypeName(space.type) }}</span>
-                  </div>
-                  <p class="style-desc">{{ space.styleDescription }}</p>
-
-                  <div class="color-palette">
-                    <span class="label">色彩搭配:</span>
-                    <div class="colors">
-                      @for (color of space.colorPalette; track color) {
-                        <div class="color-swatch" [style.background-color]="color" [title]="color"></div>
-                      }
-                    </div>
-                  </div>
-
-                  <div class="materials">
-                    <span class="label">材质选择:</span>
-                    <div class="tags">
-                      @for (material of space.materials; track material) {
-                        <span class="badge badge-tertiary">{{ material }}</span>
-                      }
-                    </div>
-                  </div>
-
-                  <div class="furniture">
-                    <span class="label">家具推荐:</span>
-                    <div class="tags">
-                      @for (item of space.furnitureRecommendations; track item) {
-                        <span class="badge badge-secondary">{{ item }}</span>
-                      }
-                    </div>
-                  </div>
-                </div>
+                <app-space-requirement-item
+                  [space]="space"
+                  [canEdit]="canEdit"
+                  [images]="getSpaceReferenceImages(space.id)"
+                  [cadFiles]="getSpaceCADFiles(space.id)"
+                  [analysisResults]="getSpaceAnalysisResults(space.id)"
+                  [specialRequirements]="spaceSpecialRequirements[space.id] || ''"
+                  [isExpanded]="isSpaceExpanded(space.id)"
+                  (toggleExpand)="toggleSpaceExpansion($event)"
+                  (uploadImages)="handleUploadImages($event)"
+                  (uploadCAD)="handleUploadCAD($event)"
+                  (deleteImage)="handleDeleteImage($event)"
+                  (deleteCAD)="handleDeleteCAD($event)"
+                  (specialRequirementsChange)="handleSpecialRequirementsChange($event)"
+                  (viewAnalysis)="handleViewAnalysis($event)"
+                  (openAiDialog)="openAIDialog($event)">
+                </app-space-requirement-item>
               }
             </div>
-
-          </div>
-        }
-      </div>
-    </div>
-
-    <!-- AI聊天助手 -->
-    <div class="card ai-chat-card">
-      <div class="card-header">
-        <h3 class="card-title">
-          <ion-icon name="chatbubbles"></ion-icon>
-          AI设计助手
-        </h3>
-        <button
-          class="btn btn-sm btn-outline"
-          (click)="toggleAIChat()">
-          <ion-icon [name]="showAIChat ? 'chevron-up' : 'chevron-down'"></ion-icon>
-          {{ showAIChat ? '收起' : '展开' }}
-        </button>
-      </div>
-      @if (showAIChat) {
-        <div class="card-content">
-          <div class="ai-chat-container">
-            <!-- 聊天消息列表 -->
-            <div class="chat-messages" #chatMessages>
-              @for (message of aiChatMessages; track message.id) {
-                <div class="message" [class.user-message]="message.role == 'user'" [class.ai-message]="message.role == 'assistant'">
-                  <div class="message-avatar">
-                    @if (message.role == 'user') {
-                      <ion-icon name="person-circle"></ion-icon>
-                    } @else {
-                      <ion-icon name="sparkles"></ion-icon>
-                    }
-                  </div>
-                  <div class="message-content">
-                    <div class="message-text">{{ message.content }}</div>
-                    <div class="message-time">{{ message.timestamp | date:'HH:mm' }}</div>
-                  </div>
-                </div>
-              }
-              @if (aiChatMessages.length == 0) {
-                <div class="empty-chat">
-                  <ion-icon name="chatbubble-ellipses-outline" class="icon-large"></ion-icon>
-                  <p>向AI设计助手咨询任何家装问题</p>
-                </div>
-              }
-            </div>
-
-            <!-- 输入区域 -->
-            <div class="chat-input">
-              <div class="input-group">
-                <input
-                  type="text"
-                  class="form-input"
-                  [ngModel]="aiChatInput"
-                  (ngModelChange)="onAiChatInputChange($event)"
-                  (keydown.enter)="sendAIChatMessage()"
-                  placeholder="询问家装设计相关问题..."
-                  [disabled]="aiAnalyzing" />
-                <button
-                  class="btn btn-primary"
-                  (click)="sendAIChatMessage()"
-                  [disabled]="isAiChatSendDisabled()">
-                  <ion-icon name="send"></ion-icon>
-                </button>
-              </div>
-            </div>
           </div>
         </div>
-      }
     </div>
-
-    <!-- 操作按钮 -->
-    @if (canEdit) {
-      <div class="action-buttons">
-        <button
-          class="btn btn-outline"
-          (click)="saveDraft()"
-          [disabled]="isSaving()">
-          <ion-icon name="save"></ion-icon>
-          保存草稿
-        </button>
-
-        <button
-          class="btn btn-primary"
-          (click)="submitRequirements()"
-          [disabled]="!canEdit || isSubmitDisabled()">
-          <ion-icon name="checkmark"></ion-icon>
-          确认需求
-        </button>
-      </div>
-    }
   </div>
-}
+}

+ 36 - 5197
src/modules/project/pages/project-detail/stages/stage-requirements.component.scss

@@ -1,4 +1,4 @@
-// 确认需求阶段样式 - 多空间支持
+// 确认需求阶段样式 - 主组件
 
 // CSS 变量定义
 :host {
@@ -14,6 +14,8 @@
   --light-color: #f4f5f8;
   --light-shade: #d7d8da;
   --white: #ffffff;
+  
+  display: block;
 }
 
 // 加载容器
@@ -48,5227 +50,64 @@
   }
 }
 
-.spinner-small {
-  width: 20px;
-  height: 20px;
-  position: relative;
-  display: inline-block;
-
-  .spinner-circle {
-    width: 100%;
-    height: 100%;
-    border: 3px solid rgba(255, 255, 255, 0.3);
-    border-top-color: white;
-    border-radius: 50%;
-    animation: spin 0.8s linear infinite;
-  }
-}
-
 @keyframes spin {
-  0% {
-    transform: rotate(0deg);
-  }
-  100% {
-    transform: rotate(360deg);
-  }
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
 }
 
 // 确认需求容器
 .stage-requirements-container {
   padding: 0 12px 80px;
+}
 
-  // 多空间切换器
-  .space-selector {
-    margin-bottom: 16px;
+// 通用卡片样式
+.card {
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  margin-bottom: 16px;
+  overflow: hidden;
 
-    .space-tabs {
+  .card-header {
+    padding: 16px;
+    border-bottom: 1px solid var(--light-shade);
+    
+    .card-title {
       display: flex;
-      overflow-x: auto;
+      align-items: center;
       gap: 8px;
-      padding: 4px;
-      background: var(--light-color);
-      border-radius: 12px;
-
-      &::-webkit-scrollbar {
-        height: 4px;
-      }
-
-      &::-webkit-scrollbar-track {
-        background: transparent;
-      }
-
-      &::-webkit-scrollbar-thumb {
-        background: var(--medium-color);
-        border-radius: 2px;
-      }
-
-      .space-tab {
-        display: flex;
-        align-items: center;
-        gap: 8px;
-        padding: 12px 16px;
-        border: none;
-        background: transparent;
-        border-radius: 8px;
-        font-size: 13px;
-        font-weight: 500;
-        color: var(--medium-color);
-        cursor: pointer;
-        transition: all 0.3s;
-        white-space: nowrap;
-        position: relative;
-        min-width: 120px;
-        justify-content: center;
-
-        .icon, .space-icon {
-          font-size: 18px;
-        }
-
-        .progress-indicator {
-          position: absolute;
-          bottom: 0;
-          left: 0;
-          height: 2px;
-          background: var(--success-color);
-          border-radius: 1px;
-          transition: width 0.3s;
-        }
-
-        &.active {
-          background: var(--primary-color);
-          color: white;
-          box-shadow: 0 2px 8px rgba(var(--primary-rgb), 0.3);
-        }
-
-        &:hover:not(.active) {
-          background: rgba(var(--primary-rgb), 0.1);
-          color: var(--primary-color);
-        }
-      }
-    }
-  }
-
-  // 需求分段导航
-  .requirements-segment {
-    margin-bottom: 16px;
-
-    .segment-buttons {
-      display: flex;
-      gap: 4px;
-      background: var(--light-color);
-      border-radius: 8px;
-      padding: 4px;
-
-      .segment-btn {
-        flex: 1;
-        padding: 12px 16px;
-        border: none;
-        background: transparent;
-        border-radius: 6px;
-        font-size: 13px;
-        font-weight: 500;
-        color: var(--medium-color);
-        cursor: pointer;
-        transition: all 0.3s;
-        white-space: nowrap;
-
-        &.active {
-          background: var(--primary-color);
-          color: white;
-          box-shadow: 0 2px 4px rgba(var(--primary-rgb), 0.3);
-        }
-
-        &:hover:not(.active) {
-          background: rgba(var(--primary-rgb), 0.1);
-          color: var(--primary-color);
-        }
-      }
-    }
-  }
-
-  // 通用卡片样式
-  .card {
-    background: white;
-    border-radius: 12px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-    margin-bottom: 16px;
-    overflow: hidden;
-
-    .card-header {
-      padding: 16px;
-      border-bottom: 1px solid var(--light-shade);
-      display: flex;
-      justify-content: space-between;
-      align-items: flex-start;
-
-      .card-title {
-        display: flex;
-        align-items: center;
-        gap: 8px;
-        margin: 0 0 4px;
-        font-size: 16px;
-        font-weight: 600;
-        color: var(--dark-color);
-
-        .icon, .space-icon {
-          font-size: 20px;
-          color: var(--primary-color);
-        }
-
-        .completion-indicator {
-          display: flex;
-          align-items: center;
-          gap: 8px;
-          font-size: 12px;
-
-          .progress-bar {
-            width: 60px;
-            height: 6px;
-            background: var(--light-shade);
-            border-radius: 3px;
-            overflow: hidden;
-
-            .progress-fill {
-              height: 100%;
-              background: var(--success-color);
-              transition: width 0.3s;
-            }
-          }
-
-          .progress-text {
-            font-weight: 600;
-            color: var(--success-color);
-          }
-        }
-      }
+      margin: 0 0 4px;
+      font-size: 16px;
+      font-weight: 600;
+      color: var(--dark-color);
 
-      .card-subtitle {
-        color: var(--medium-color);
-        font-size: 12px;
-        margin: 0;
+      .icon {
+        font-size: 20px;
+        color: var(--primary-color);
       }
     }
 
-    .card-content {
-      padding: 16px;
-    }
-
-    &.active {
-      border: 2px solid var(--primary-color);
-      box-shadow: 0 4px 16px rgba(var(--primary-rgb), 0.2);
-    }
-  }
-
-  // 必填标记
-  .required {
-    color: var(--danger-color);
-    margin-left: 4px;
-  }
-
-  // 空状态
-  .empty-state {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    padding: 40px 20px;
-    text-align: center;
-
-    .icon-large {
-      font-size: 64px;
-      color: var(--medium-color);
-      margin-bottom: 16px;
-      opacity: 0.5;
-    }
-
-    p {
+    .card-subtitle {
       color: var(--medium-color);
-      margin: 0 0 16px;
-    }
-
-    .btn {
-      margin-top: 8px;
-    }
-  }
-
-  // AI分析操作区域
-  .ai-analysis-actions {
-    display: flex;
-    gap: 8px;
-    align-items: center;
-
-    .btn {
-      .spinner-small {
-        margin-right: 4px;
-      }
-    }
-  }
-
-  // AI分析结果
-  .ai-analysis-results {
-    margin-bottom: 20px;
-
-    .analysis-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 16px;
-      padding-bottom: 8px;
-      border-bottom: 1px solid var(--light-shade);
-
-      .badge {
-        display: flex;
-        align-items: center;
-        gap: 4px;
-        font-size: 12px;
-        padding: 6px 12px;
-
-        .icon, .space-icon {
-          font-size: 14px;
-        }
-      }
-    }
-
-    .analysis-grid {
-      display: grid;
-      gap: 16px;
-
-      .analysis-item {
-        display: grid;
-        grid-template-columns: 200px 1fr;
-        gap: 16px;
-        padding: 16px;
-        background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.03), rgba(12, 209, 232, 0.03));
-        border-radius: 12px;
-        border: 1px solid rgba(var(--primary-rgb), 0.1);
-
-        .analysis-image {
-          position: relative;
-          border-radius: 8px;
-          overflow: hidden;
-          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-
-          img {
-            width: 100%;
-            height: 150px;
-            object-fit: cover;
-          }
-
-          .confidence-badge {
-            position: absolute;
-            top: 8px;
-            right: 8px;
-            background: rgba(0, 0, 0, 0.8);
-            color: white;
-            padding: 4px 8px;
-            border-radius: 12px;
-            font-size: 10px;
-            font-weight: 600;
-          }
-        }
-
-        .analysis-content {
-          display: flex;
-          flex-direction: column;
-          gap: 12px;
-
-          .analysis-section {
-            h5 {
-              margin: 0 0 8px;
-              font-size: 13px;
-              font-weight: 600;
-              color: var(--dark-color);
-              display: flex;
-              align-items: center;
-              gap: 6px;
-
-              &::before {
-                content: '';
-                width: 3px;
-                height: 14px;
-                background: var(--primary-color);
-                border-radius: 2px;
-              }
-            }
-
-            p {
-              margin: 0;
-              font-size: 12px;
-              line-height: 1.5;
-              color: var(--medium-color);
-            }
-
-            .color-palette {
-              display: flex;
-              gap: 6px;
-              flex-wrap: wrap;
-
-              .color-swatch {
-                width: 24px;
-                height: 24px;
-                border-radius: 4px;
-                border: 1px solid rgba(0, 0, 0, 0.1);
-                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-                cursor: pointer;
-                transition: transform 0.2s;
-
-                &:hover {
-                  transform: scale(1.1);
-                }
-              }
-            }
-
-            .tags {
-              display: flex;
-              flex-wrap: wrap;
-              gap: 6px;
-
-              .badge {
-                font-size: 10px;
-                padding: 3px 8px;
-              }
-            }
-          }
-        }
-      }
-    }
-
-    .cad-analysis-grid {
-      display: grid;
-      gap: 16px;
-
-      .cad-analysis-item {
-        padding: 16px;
-        background: linear-gradient(135deg, rgba(var(--tertiary-rgb), 0.03), rgba(45, 211, 111, 0.03));
-        border-radius: 12px;
-        border: 1px solid rgba(var(--tertiary-rgb), 0.1);
-
-        .cad-file-info {
-          display: flex;
-          align-items: center;
-          gap: 12px;
-          margin-bottom: 16px;
-          padding-bottom: 12px;
-          border-bottom: 1px solid var(--light-shade);
-
-          .file-icon {
-            font-size: 32px;
-            color: var(--tertiary-color);
-          }
-
-          .file-details {
-            flex: 1;
-
-            h4 {
-              margin: 0 0 4px;
-              font-size: 15px;
-              font-weight: 600;
-              color: var(--dark-color);
-            }
-
-            p {
-              margin: 0;
-              font-size: 12px;
-              color: var(--medium-color);
-            }
-          }
-        }
-
-        .cad-analysis-content {
-          display: grid;
-          gap: 16px;
-
-          .analysis-section {
-            h5 {
-              margin: 0 0 8px;
-              font-size: 13px;
-              font-weight: 600;
-              color: var(--dark-color);
-              display: flex;
-              align-items: center;
-              gap: 6px;
-
-              &::before {
-                content: '';
-                width: 3px;
-                height: 14px;
-                background: var(--tertiary-color);
-                border-radius: 2px;
-              }
-            }
-
-            .structure-info,
-            .dimensions-info {
-              display: grid;
-              grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
-              gap: 8px;
-
-              .info-item {
-                display: flex;
-                align-items: center;
-                gap: 8px;
-
-                .label {
-                  font-size: 12px;
-                  color: var(--medium-color);
-                  font-weight: 500;
-                }
-
-                .value {
-                  font-size: 13px;
-                  color: var(--dark-color);
-                  font-weight: 600;
-                }
-              }
-            }
-
-            .tags {
-              display: flex;
-              flex-wrap: wrap;
-              gap: 6px;
-
-              .badge {
-                font-size: 10px;
-                padding: 3px 8px;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // 综合AI分析卡片
-  .comprehensive-analysis-card {
-    border: 2px solid rgba(var(--success-rgb), 0.2);
-    box-shadow: 0 4px 16px rgba(45, 211, 111, 0.1);
-
-    .comprehensive-analysis-content {
-      .analysis-section {
-        margin-bottom: 20px;
-        padding-bottom: 16px;
-        border-bottom: 1px solid var(--light-shade);
-
-        &:last-child {
-          margin-bottom: 0;
-          padding-bottom: 0;
-          border-bottom: none;
-        }
-
-        h4 {
-          margin: 0 0 12px;
-          font-size: 15px;
-          font-weight: 600;
-          color: var(--dark-color);
-          display: flex;
-          align-items: center;
-          gap: 8px;
-
-          &::before {
-            content: '';
-            width: 4px;
-            height: 16px;
-            background: var(--success-color);
-            border-radius: 2px;
-          }
-        }
-
-        p {
-          margin: 0;
-          font-size: 14px;
-          line-height: 1.6;
-          color: var(--dark-color);
-        }
-
-        .ai-color-scheme {
-          display: flex;
-          gap: 16px;
-          align-items: center;
-          padding: 12px;
-          background: linear-gradient(135deg, rgba(var(--success-rgb), 0.05), rgba(112, 68, 255, 0.05));
-          border-radius: 8px;
-
-          .color-item {
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            gap: 8px;
-
-            .color-swatch {
-              width: 48px;
-              height: 48px;
-              border-radius: 8px;
-              border: 2px solid white;
-              box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-              cursor: pointer;
-              transition: transform 0.2s;
-
-              &:hover {
-                transform: scale(1.05);
-              }
-            }
-
-            .color-label {
-              font-size: 11px;
-              color: var(--medium-color);
-              font-weight: 500;
-            }
-          }
-        }
-
-        .optimization-list {
-          margin: 0;
-          padding-left: 20px;
-
-          li {
-            margin-bottom: 6px;
-            font-size: 13px;
-            line-height: 1.5;
-            color: var(--dark-color);
-
-            &:last-child {
-              margin-bottom: 0;
-            }
-
-            &::marker {
-              color: var(--success-color);
-            }
-          }
-        }
-
-        .budget-assessment {
-          display: grid;
-          grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
-          gap: 16px;
-
-          .budget-range,
-          .risk-level {
-            display: flex;
-            align-items: center;
-            gap: 8px;
-
-            .label {
-              font-size: 12px;
-              color: var(--medium-color);
-              font-weight: 500;
-            }
-
-            .value {
-              font-size: 14px;
-              color: var(--dark-color);
-              font-weight: 600;
-            }
-
-            .badge {
-              font-size: 10px;
-              padding: 4px 8px;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // AI聊天卡片
-  .ai-chat-card {
-    .ai-chat-container {
-      display: flex;
-      flex-direction: column;
-      height: 400px;
-
-      .chat-messages {
-        flex: 1;
-        overflow-y: auto;
-        padding: 16px;
-        background: var(--light-color);
-        border-radius: 8px;
-        margin-bottom: 12px;
-
-        &::-webkit-scrollbar {
-          width: 4px;
-        }
-
-        &::-webkit-scrollbar-track {
-          background: transparent;
-        }
-
-        &::-webkit-scrollbar-thumb {
-          background: var(--medium-color);
-          border-radius: 2px;
-        }
-
-        .message {
-          display: flex;
-          gap: 12px;
-          margin-bottom: 16px;
-
-          &:last-child {
-            margin-bottom: 0;
-          }
-
-          &.user-message {
-            flex-direction: row-reverse;
-
-            .message-avatar {
-              .icon, .space-icon {
-                color: var(--primary-color);
-              }
-            }
-
-            .message-content {
-              background: var(--primary-color);
-              color: white;
-            }
-          }
-
-          &.ai-message {
-            .message-avatar {
-              .icon, .space-icon {
-                color: var(--success-color);
-              }
-            }
-
-            .message-content {
-              background: white;
-              color: var(--dark-color);
-              border: 1px solid var(--light-shade);
-            }
-          }
-
-          .message-avatar {
-            flex-shrink: 0;
-            width: 32px;
-            height: 32px;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-
-            .icon, .space-icon {
-              font-size: 24px;
-            }
-          }
-
-          .message-content {
-            flex: 1;
-            max-width: 70%;
-            padding: 12px 16px;
-            border-radius: 16px;
-            word-wrap: break-word;
-
-            .message-text {
-              font-size: 13px;
-              line-height: 1.5;
-              margin-bottom: 4px;
-            }
-
-            .message-time {
-              font-size: 10px;
-              opacity: 0.7;
-            }
-          }
-        }
-
-        .empty-chat {
-          display: flex;
-          flex-direction: column;
-          align-items: center;
-          justify-content: center;
-          height: 100%;
-          text-align: center;
-
-          .icon-large {
-            font-size: 48px;
-            color: var(--medium-color);
-            margin-bottom: 12px;
-            opacity: 0.5;
-          }
-
-          p {
-            color: var(--medium-color);
-            margin: 0;
-            font-size: 13px;
-          }
-        }
-      }
-
-      .chat-input {
-        .input-group {
-          display: flex;
-          gap: 8px;
-
-          .form-input {
-            flex: 1;
-            padding: 12px 16px;
-            border: 1px solid var(--light-shade);
-            border-radius: 24px;
-            font-size: 13px;
-            background: white;
-
-            &:focus {
-              outline: none;
-              border-color: var(--primary-color);
-              box-shadow: 0 0 0 3px rgba(var(--primary-rgb), 0.1);
-            }
-
-            &::placeholder {
-              color: var(--medium-color);
-            }
-          }
-
-          .btn {
-            width: 48px;
-            height: 48px;
-            border-radius: 50%;
-            padding: 0;
-            flex-shrink: 0;
-
-            .icon, .space-icon {
-              font-size: 20px;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // 参考图片卡片
-  .reference-images-card {
-    .images-grid {
-      display: grid;
-      grid-template-columns: repeat(2, 1fr);
-      gap: 12px;
-
-      .image-item {
-        position: relative;
-        aspect-ratio: 1;
-        border-radius: 8px;
-        overflow: hidden;
-        cursor: pointer;
-        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-        transition: transform 0.2s, box-shadow 0.2s;
-
-        &:hover {
-          transform: translateY(-2px);
-          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-        }
-
-        img {
-          width: 100%;
-          height: 100%;
-          object-fit: cover;
-          transition: transform 0.3s;
-        }
-
-        &:hover img {
-          transform: scale(1.05);
-        }
-
-        .image-overlay {
-          position: absolute;
-          top: 0;
-          left: 0;
-          right: 0;
-          bottom: 0;
-          background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.7));
-          display: flex;
-          flex-direction: column;
-          justify-content: space-between;
-          padding: 8px;
-          opacity: 0;
-          transition: opacity 0.3s;
-
-          .overlay-top {
-            display: flex;
-            flex-wrap: wrap;
-            gap: 4px;
-            align-items: flex-start;
-
-            .badge {
-              height: fit-content;
-              font-size: 10px;
-              padding: 4px 8px;
-            }
-          }
-
-          .overlay-actions {
-            display: flex;
-            gap: 6px;
-            justify-content: flex-end;
-            align-items: center;
-
-            .btn-icon {
-              width: 32px;
-              height: 32px;
-              padding: 4px;
-              backdrop-filter: blur(4px);
-
-              &.btn-primary {
-                background: rgba(var(--primary-rgb), 0.9);
-                color: white;
-
-                &:hover:not(:disabled) {
-                  background: var(--primary-color);
-                  transform: scale(1.1);
-                }
-              }
-            }
-          }
-        }
-
-        &:hover .image-overlay {
-          opacity: 1;
-        }
-
-        &.small {
-          aspect-ratio: 1.2;
-
-          .image-overlay {
-            padding: 6px;
-          }
-        }
-      }
-
-      .upload-placeholder {
-        aspect-ratio: 1;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        border: 2px dashed var(--light-shade);
-        border-radius: 8px;
-        background-color: var(--light-color);
-        transition: all 0.3s;
-
-        &:hover {
-          border-color: var(--primary-color);
-          background-color: rgba(var(--primary-rgb), 0.05);
-        }
-
-        &.small {
-          aspect-ratio: 1.2;
-        }
-      }
-    }
-  }
-
-  // CAD文件卡片
-  .cad-files-card {
-    .file-list {
-      display: flex;
-      flex-direction: column;
-      gap: 0;
-      margin-bottom: 16px;
-    }
-
-    .file-item {
-      display: flex;
-      align-items: center;
-      gap: 12px;
-      padding: 12px 0;
-      border-bottom: 1px solid var(--light-shade);
-
-      &:last-child {
-        border-bottom: none;
-      }
-
-      .file-icon {
-        font-size: 40px;
-        color: var(--primary-color);
-        flex-shrink: 0;
-      }
-
-      .file-info {
-        flex: 1;
-        min-width: 0;
-
-        h4 {
-          margin: 0 0 4px;
-          font-size: 15px;
-          font-weight: 600;
-          color: var(--dark-color);
-          white-space: nowrap;
-          overflow: hidden;
-          text-overflow: ellipsis;
-        }
-
-        p {
-          margin: 0;
-          font-size: 12px;
-          color: var(--medium-color);
-        }
-      }
-
-      .btn-icon {
-        flex-shrink: 0;
-      }
+      font-size: 12px;
+      margin: 0;
     }
   }
 
-  // 风格偏好卡片
-  .style-preferences-card {
-    .color-scheme {
-      margin-bottom: 24px;
-
-      .color-inputs {
-        display: grid;
-        grid-template-columns: repeat(3, 1fr);
-        gap: 12px;
-        margin-top: 12px;
-
-        .form-color-input {
-          width: 100%;
-          height: 48px;
-          border: 1px solid var(--light-shade);
-          border-radius: 8px;
-          cursor: pointer;
-          padding: 4px;
-
-          &:disabled {
-            cursor: not-allowed;
-            opacity: 0.5;
-          }
-        }
-      }
-    }
-
-    .budget-range {
-      margin-bottom: 24px;
-
-      h4 {
-        margin: 0 0 12px;
-        font-size: 14px;
-        font-weight: 600;
-        color: var(--dark-color);
-      }
-
-      .budget-inputs {
-        display: grid;
-        grid-template-columns: 1fr auto 1fr;
-        align-items: flex-start;
-        gap: 12px;
-
-        .separator {
-          font-size: 20px;
-          font-weight: 600;
-          color: var(--medium-color);
-          padding-top: 32px;
-        }
-      }
-    }
-
-    .quality-level {
-      margin-bottom: 24px;
-
-      .radio-group {
-        display: flex;
-        gap: 16px;
-        margin-top: 8px;
-
-        .radio-item {
-          display: flex;
-          align-items: center;
-          gap: 8px;
-          cursor: pointer;
-
-          input[type="radio"] {
-            margin: 0;
-          }
-
-          .radio-label {
-            font-size: 14px;
-            color: var(--dark-color);
-          }
-        }
-      }
-    }
+  .card-content {
+    padding: 16px;
   }
+}
 
-  // 空间需求管理卡片 - 新布局
+// Global Requirements Area
+.global-requirements {
   .space-requirements-card {
+    // Using generic card styles
+    
     .spaces-container {
       display: flex;
       flex-direction: column;
       gap: 16px;
-
-      .space-item {
-        background: white;
-        border-radius: 12px;
-        border: 2px solid var(--light-shade);
-        overflow: hidden;
-        transition: all 0.3s ease;
-
-        &:hover {
-          border-color: var(--primary-color);
-          box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.15);
-        }
-
-        &.expanded {
-          box-shadow: 0 8px 24px rgba(var(--primary-rgb), 0.2);
-        }
-
-        // 空间头部
-        .space-header {
-          display: grid;
-          grid-template-columns: auto 1fr auto auto;
-          align-items: center;
-          gap: 16px;
-          padding: 16px 20px;
-          background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-          border-bottom: 1px solid var(--light-shade);
-          cursor: pointer;
-          transition: all 0.3s ease;
-          min-height: 60px;
-
-          .space-name-section {
-            display: flex;
-            align-items: center;
-            gap: 12px;
-            font-size: 16px;
-            font-weight: 600;
-            color: var(--dark-color);
-            white-space: nowrap;
-
-            .reference-count-badge {
-              display: inline-flex;
-              align-items: center;
-              justify-content: center;
-              padding: 4px 12px;
-              background: linear-gradient(135deg, #e0e7ff 0%, #ddd6fe 100%);
-              color: var(--primary-color);
-              font-size: 12px;
-              font-weight: 600;
-              border-radius: 12px;
-              box-shadow: 0 2px 6px rgba(var(--primary-rgb), 0.15);
-              flex-shrink: 0;
-            }
-          }
-
-          .special-requirements-box {
-            display: flex;
-            align-items: center;
-            gap: 6px; // 🔥 缩小gap
-            padding: 6px 10px; // 🔥 缩小padding适配企业微信
-            background: linear-gradient(135deg, rgba(251, 191, 36, 0.08), rgba(245, 158, 11, 0.08));
-            border-left: 3px solid var(--warning-color); // 🔥 缩小边框
-            border-radius: 4px;
-            font-size: 12px; // 🔥 缩小字体
-            overflow: hidden;
-            min-width: 0; // 🔥 允许内容收缩
-            flex: 1; // 🔥 自适应宽度
-            max-width: 180px; // 🔥 限制最大宽度
-
-            .requirements-label {
-              font-weight: 600;
-              color: var(--warning-color);
-              white-space: nowrap;
-              flex-shrink: 0;
-              font-size: 11px; // 🔥 缩小字体
-            }
-
-            .requirements-text {
-              color: var(--medium-color);
-              overflow: hidden;
-              text-overflow: ellipsis;
-              white-space: nowrap;
-              flex: 1;
-              min-width: 0;
-            }
-          }
-
-          .header-actions {
-            display: flex;
-            align-items: center;
-            gap: 6px; // 🔥 缩小gap
-            flex-shrink: 0;
-
-            .btn-icon-small {
-              width: 30px; // 🔥 缩小按钮适配企业微信
-              height: 30px;
-              padding: 4px;
-              background: rgba(var(--primary-rgb), 0.1);
-              color: var(--primary-color);
-              border: 1px solid rgba(var(--primary-rgb), 0.2);
-              border-radius: 6px;
-              cursor: pointer;
-              transition: all 0.2s ease;
-              display: flex;
-              align-items: center;
-              justify-content: center;
-              flex-shrink: 0;
-
-              .icon-text {
-                font-size: 15px; // 🔥 稍微缩小emoji大小
-                line-height: 1;
-                display: block;
-              }
-
-              ion-icon {
-                font-size: 15px;
-              }
-
-              &:hover {
-                background: rgba(var(--primary-rgb), 0.2);
-                border-color: var(--primary-color);
-                transform: scale(1.05);
-              }
-
-              &.btn-edit {
-                &:hover {
-                  background: var(--primary-color);
-                  color: white;
-                }
-              }
-
-              // 🔥 企业微信端额外优化
-              &.btn-ai {
-                &:hover {
-                  background: var(--tertiary-color);
-                  color: white;
-                  border-color: var(--tertiary-color);
-                }
-              }
-            }
-          }
-
-          .expand-icon {
-            flex-shrink: 0;
-            width: 28px; // 🔥 缩小图标适配企业微信
-            height: 28px;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
-            border-radius: 50%;
-            transition: all 0.3s ease;
-            color: var(--medium-color);
-
-            svg {
-              width: 20px; // 🔥 缩小SVG大小
-              height: 20px;
-              transition: transform 0.3s ease;
-            }
-
-            &.expanded svg {
-              transform: rotate(180deg);
-            }
-          }
-
-          &:hover {
-            background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%);
-
-            .expand-icon {
-              background: linear-gradient(135deg, var(--primary-color), #764ba2);
-              color: white;
-            }
-          }
-        }
-
-        // 空间内容
-        .space-content {
-          padding: 20px;
-          animation: slideDown 0.3s ease-out;
-
-          // 拖拽上传区域
-          .drag-drop-zone {
-            margin-bottom: 24px;
-            padding: 32px 20px;
-            border: 2px dashed var(--light-shade);
-            border-radius: 12px;
-            background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.02), rgba(12, 209, 232, 0.02));
-            transition: all 0.3s ease;
-            cursor: pointer;
-
-            &.drag-over {
-              border-color: var(--primary-color);
-              background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.1), rgba(12, 209, 232, 0.1));
-              box-shadow: 0 8px 24px rgba(var(--primary-rgb), 0.15);
-
-              .drag-drop-content {
-                transform: scale(1.05);
-              }
-            }
-
-            .drag-drop-content {
-              display: flex;
-              flex-direction: column;
-              align-items: center;
-              justify-content: center;
-              text-align: center;
-              transition: transform 0.3s ease;
-
-              .drag-drop-icon {
-                font-size: 48px;
-                color: var(--primary-color);
-                margin-bottom: 12px;
-                opacity: 0.8;
-              }
-
-              h4 {
-                margin: 0 0 8px;
-                font-size: 16px;
-                font-weight: 600;
-                color: var(--dark-color);
-              }
-
-              p {
-                margin: 0;
-                font-size: 13px;
-                color: var(--medium-color);
-
-                &.drag-hint {
-                  margin-top: 8px;
-                  font-size: 12px;
-                  color: var(--primary-color);
-                  font-weight: 500;
-                }
-              }
-            }
-          }
-
-          // 图片类型标签导航
-          .image-type-tabs {
-            display: flex;
-            gap: 8px;
-            margin-bottom: 20px;
-            padding-bottom: 12px;
-            border-bottom: 2px solid var(--light-shade);
-            overflow-x: auto;
-
-            &::-webkit-scrollbar {
-              height: 4px;
-            }
-
-            &::-webkit-scrollbar-track {
-              background: transparent;
-            }
-
-            &::-webkit-scrollbar-thumb {
-              background: var(--light-shade);
-              border-radius: 2px;
-            }
-
-            .tab-button {
-              display: flex;
-              align-items: center;
-              gap: 6px;
-              padding: 10px 16px;
-              background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-              border: 2px solid var(--light-shade);
-              border-radius: 8px;
-              font-size: 13px;
-              font-weight: 600;
-              color: var(--medium-color);
-              cursor: pointer;
-              transition: all 0.3s ease;
-              white-space: nowrap;
-
-              .tab-label {
-                flex-shrink: 0;
-              }
-
-              .tab-badge {
-                display: inline-flex;
-                align-items: center;
-                justify-content: center;
-                min-width: 20px;
-                height: 20px;
-                padding: 0 6px;
-                background: var(--light-shade);
-                border-radius: 10px;
-                font-size: 11px;
-                font-weight: 700;
-              }
-
-              &:hover {
-                border-color: var(--primary-color);
-                background: rgba(var(--primary-rgb), 0.05);
-                color: var(--primary-color);
-              }
-
-              &.active {
-                background: linear-gradient(135deg, var(--primary-color), #764ba2);
-                border-color: transparent;
-                color: white;
-                box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.3);
-
-                .tab-badge {
-                  background: rgba(255, 255, 255, 0.3);
-                  color: white;
-                }
-              }
-            }
-          }
-
-          // 图片展示区域
-          .images-section {
-            .section-header {
-              display: flex;
-              justify-content: space-between;
-              align-items: center;
-              margin-bottom: 16px;
-              padding-bottom: 12px;
-              border-bottom: 1px solid var(--light-shade);
-
-              h5 {
-                margin: 0;
-                font-size: 15px;
-                font-weight: 600;
-                color: var(--dark-color);
-              }
-
-              .btn {
-                padding: 8px 16px;
-                font-size: 12px;
-              }
-            }
-
-            .section-content {
-              margin-bottom: 16px;
-            }
-
-            .images-grid {
-              display: grid;
-              grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
-              gap: 12px;
-
-              .image-item {
-                position: relative;
-                aspect-ratio: 1;
-                border-radius: 8px;
-                overflow: hidden;
-                cursor: pointer;
-                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-                transition: all 0.3s ease;
-                border: 2px solid transparent;
-
-                &:hover {
-                  transform: translateY(-4px);
-                  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
-                  border-color: var(--primary-color);
-
-                  img {
-                    transform: scale(1.05);
-                  }
-
-                  .image-overlay {
-                    opacity: 1;
-                  }
-                }
-
-                img {
-                  width: 100%;
-                  height: 100%;
-                  object-fit: cover;
-                  transition: transform 0.3s ease;
-                }
-
-                .image-overlay {
-                  position: absolute;
-                  top: 0;
-                  left: 0;
-                  right: 0;
-                  bottom: 0;
-                  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.7));
-                  display: flex;
-                  flex-direction: column;
-                  justify-content: space-between;
-                  padding: 8px;
-                  opacity: 0;
-                  transition: opacity 0.3s ease;
-
-                  .overlay-top {
-                    display: flex;
-                    flex-wrap: wrap;
-                    gap: 4px;
-                    align-items: flex-start;
-
-                    .badge {
-                      height: fit-content;
-                      font-size: 10px;
-                      padding: 4px 8px;
-                      background: rgba(0, 0, 0, 0.6);
-                      color: white;
-                      border-radius: 4px;
-
-                      &.badge-soft-decor {
-                        background: rgba(16, 185, 129, 0.9);
-                      }
-
-                      &.badge-hard-decor {
-                        background: rgba(59, 130, 246, 0.9);
-                      }
-
-                      &.badge-other {
-                        background: rgba(107, 114, 128, 0.9);
-                      }
-
-                      &.badge-success {
-                        background: rgba(34, 197, 94, 0.9);
-                      }
-                    }
-                  }
-
-                  .overlay-actions {
-                    display: flex;
-                    gap: 6px;
-                    justify-content: flex-end;
-
-                    .btn-icon {
-                      width: 32px;
-                      height: 32px;
-                      padding: 4px;
-                      background: rgba(var(--primary-rgb), 0.9);
-                      color: white;
-                      border: none;
-                      border-radius: 6px;
-                      cursor: pointer;
-                      transition: all 0.2s ease;
-
-                      &:hover {
-                        background: var(--primary-color);
-                        transform: scale(1.1);
-                      }
-
-                      &.btn-danger {
-                        background: rgba(239, 68, 68, 0.9);
-
-                        &:hover {
-                          background: #ef4444;
-                        }
-                      }
-                    }
-                  }
-                }
-              }
-            }
-
-            .file-list {
-              display: flex;
-              flex-direction: column;
-              gap: 8px;
-
-              .file-item {
-                display: flex;
-                align-items: center;
-                gap: 12px;
-                padding: 12px;
-                background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-                border: 1px solid var(--light-shade);
-                border-radius: 8px;
-                transition: all 0.3s ease;
-
-                &:hover {
-                  border-color: var(--primary-color);
-                  background: rgba(var(--primary-rgb), 0.03);
-                }
-
-                .file-icon {
-                  font-size: 32px;
-                  color: var(--primary-color);
-                  flex-shrink: 0;
-                }
-
-                .file-info {
-                  flex: 1;
-                  min-width: 0;
-
-                  h6 {
-                    margin: 0 0 4px;
-                    font-size: 14px;
-                    font-weight: 600;
-                    color: var(--dark-color);
-                    overflow: hidden;
-                    text-overflow: ellipsis;
-                    white-space: nowrap;
-                  }
-
-                  p {
-                    margin: 0;
-                    font-size: 12px;
-                    color: var(--medium-color);
-                  }
-
-                  .badge {
-                    display: inline-flex;
-                    align-items: center;
-                    gap: 4px;
-                    margin-top: 4px;
-                    padding: 4px 8px;
-                    background: var(--success-color);
-                    color: white;
-                    font-size: 11px;
-                    border-radius: 4px;
-                  }
-                }
-
-                .btn-icon {
-                  flex-shrink: 0;
-                  width: 32px;
-                  height: 32px;
-                  padding: 4px;
-                  background: rgba(239, 68, 68, 0.1);
-                  color: var(--danger-color);
-                  border: none;
-                  border-radius: 6px;
-                  cursor: pointer;
-                  transition: all 0.2s ease;
-
-                  &:hover {
-                    background: rgba(239, 68, 68, 0.2);
-                    transform: scale(1.1);
-                  }
-                }
-              }
-            }
-
-            .empty-state {
-              display: flex;
-              flex-direction: column;
-              align-items: center;
-              justify-content: center;
-              padding: 40px 20px;
-              text-align: center;
-
-              ion-icon {
-                font-size: 48px;
-                color: var(--medium-color);
-                margin-bottom: 12px;
-                opacity: 0.5;
-              }
-
-              p {
-                margin: 0;
-                color: var(--medium-color);
-                font-size: 13px;
-              }
-            }
-
-            .section-divider {
-              height: 1px;
-              background: var(--light-shade);
-              margin: 20px 0;
-            }
-
-            // CAD文件列表
-            .cad-files-list {
-              display: flex;
-              flex-direction: column;
-              gap: 12px;
-
-              .cad-file-item {
-                display: flex;
-                align-items: center;
-                gap: 12px;
-                padding: 12px;
-                background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-                border: 1px solid var(--light-shade);
-                border-radius: 8px;
-                transition: all 0.2s ease;
-
-                &:hover {
-                  border-color: var(--primary-color);
-                  background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
-                }
-
-                .cad-icon {
-                  flex-shrink: 0;
-                  width: 40px;
-                  height: 40px;
-                  display: flex;
-                  align-items: center;
-                  justify-content: center;
-                  background: linear-gradient(135deg, #e0e7ff 0%, #ddd6fe 100%);
-                  border-radius: 6px;
-                  color: var(--primary-color);
-                  font-size: 20px;
-                }
-
-                .cad-info {
-                  flex: 1;
-                  min-width: 0;
-
-                  .cad-name {
-                    font-size: 13px;
-                    font-weight: 600;
-                    color: var(--dark-color);
-                    overflow: hidden;
-                    text-overflow: ellipsis;
-                    white-space: nowrap;
-                  }
-
-                  .cad-meta {
-                    display: flex;
-                    align-items: center;
-                    gap: 8px;
-                    margin-top: 4px;
-
-                    .badge {
-                      display: inline-flex;
-                      align-items: center;
-                      gap: 4px;
-                      padding: 2px 8px;
-                      font-size: 11px;
-                      font-weight: 600;
-                      border-radius: 4px;
-                      background: #d4edda;
-                      color: #155724;
-
-                      ion-icon {
-                        font-size: 12px;
-                      }
-                    }
-                  }
-                }
-
-                .btn-icon {
-                  flex-shrink: 0;
-                  width: 32px;
-                  height: 32px;
-                  padding: 4px;
-                  background: transparent;
-                  border: 1px solid var(--light-shade);
-                  border-radius: 6px;
-                  cursor: pointer;
-                  transition: all 0.2s ease;
-                  display: flex;
-                  align-items: center;
-                  justify-content: center;
-
-                  &.btn-danger {
-                    color: #dc3545;
-
-                    &:hover {
-                      background: #dc3545;
-                      color: white;
-                      border-color: #dc3545;
-                    }
-                  }
-                }
-              }
-            }
-
-            // AI分析结果区域 - 新布局
-            .ai-analysis-section {
-              .section-header {
-                display: flex;
-                align-items: center;
-                gap: 8px;
-                margin-bottom: 20px;
-                padding-bottom: 12px;
-                border-bottom: 2px solid var(--primary-color);
-
-                h5 {
-                  margin: 0;
-                  font-size: 15px;
-                  font-weight: 600;
-                  color: var(--dark-color);
-                  display: flex;
-                  align-items: center;
-                  gap: 6px;
-
-                  ion-icon {
-                    color: var(--primary-color);
-                    font-size: 18px;
-                  }
-                }
-              }
-
-              .analysis-results-list {
-                display: flex;
-                flex-direction: column;
-                gap: 20px;
-
-                .analysis-item-card {
-                  display: grid;
-                  grid-template-columns: 280px 1fr;
-                  gap: 20px;
-                  padding: 20px;
-                  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-                  border: 1px solid var(--light-shade);
-                  border-radius: 12px;
-                  transition: all 0.3s ease;
-
-                  &:hover {
-                    border-color: var(--primary-color);
-                    box-shadow: 0 8px 24px rgba(var(--primary-rgb), 0.15);
-                  }
-
-                  // 左侧:图片
-                  .analysis-image-section {
-                    display: flex;
-                    align-items: flex-start;
-                    justify-content: center;
-
-                    .analysis-image {
-                      position: relative;
-                      width: 100%;
-                      aspect-ratio: 1;
-                      border-radius: 8px;
-                      overflow: hidden;
-                      background: linear-gradient(135deg, #e0e7ff 0%, #ddd6fe 100%);
-                      border: 3px solid var(--primary-color);
-                      box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.2);
-
-                      img {
-                        width: 100%;
-                        height: 100%;
-                        object-fit: cover;
-                      }
-                    }
-                  }
-
-                  // 右侧:分析结果
-                  .analysis-results-section {
-                    display: flex;
-                    flex-direction: column;
-                    gap: 16px;
-                    max-height: 600px;
-                    overflow-y: auto;
-
-                    &::-webkit-scrollbar {
-                      width: 6px;
-                    }
-
-                    &::-webkit-scrollbar-track {
-                      background: transparent;
-                    }
-
-                    &::-webkit-scrollbar-thumb {
-                      background: var(--light-shade);
-                      border-radius: 3px;
-
-                      &:hover {
-                        background: var(--medium-color);
-                      }
-                    }
-
-                    // 头部:参考类型和用户要求(按图1格式)
-                    .analysis-header-box {
-                      padding: 16px;
-                      background: linear-gradient(135deg, #e0f2fe 0%, #cffafe 100%);
-                      border: 2px solid var(--primary-color);
-                      border-radius: 8px;
-                      min-height: 60px;
-                      display: flex;
-                      align-items: center;
-
-                      .header-info {
-                        display: flex;
-                        align-items: center;
-                        gap: 16px;
-                        width: 100%;
-
-                        .info-item {
-                          display: flex;
-                          align-items: center;
-                          gap: 8px;
-                          flex: 1;
-
-                          .info-label {
-                            font-size: 13px;
-                            font-weight: 600;
-                            color: var(--medium-color);
-                            white-space: nowrap;
-                          }
-
-                          .info-value {
-                            font-size: 14px;
-                            font-weight: 700;
-                            color: var(--dark-color);
-                            background: white;
-                            padding: 4px 12px;
-                            border-radius: 4px;
-                            display: inline-block;
-                          }
-                        }
-
-                        .info-divider {
-                          color: var(--light-shade);
-                          font-size: 16px;
-                        }
-                      }
-                    }
-
-                    // 分析内容
-                    .analysis-details-content {
-                      display: flex;
-                      flex-direction: column;
-                      gap: 12px;
-
-                      .analysis-group {
-                        padding: 12px;
-                        background: white;
-                        border: 1px solid var(--light-shade);
-                        border-radius: 6px;
-
-                        h6 {
-                          margin: 0 0 10px;
-                          font-size: 12px;
-                          font-weight: 700;
-                          color: var(--primary-color);
-                          text-transform: uppercase;
-                          letter-spacing: 0.5px;
-                        }
-
-                        .analysis-grid {
-                          display: flex;
-                          flex-direction: column;
-                          gap: 6px;
-
-                          .analysis-row {
-                            display: flex;
-                            align-items: center;
-                            gap: 8px;
-                            font-size: 12px;
-
-                            .label {
-                              font-weight: 600;
-                              color: var(--medium-color);
-                              min-width: 60px;
-                            }
-
-                            .value {
-                              color: var(--dark-color);
-                              flex: 1;
-                            }
-                          }
-                        }
-
-                        // 分析标签
-                        .analysis-tags {
-                          display: flex;
-                          flex-wrap: wrap;
-                          gap: 8px;
-
-                          .tag {
-                            display: inline-block;
-                            padding: 6px 12px;
-                            background: linear-gradient(135deg, #e0f2fe 0%, #cffafe 100%);
-                            color: var(--primary-color);
-                            border: 1px solid var(--primary-color);
-                            border-radius: 20px;
-                            font-size: 12px;
-                            font-weight: 600;
-                            white-space: nowrap;
-
-                            &.tag-material {
-                              background: linear-gradient(135deg, #f3e8ff 0%, #ede9fe 100%);
-                              color: #7c3aed;
-                              border-color: #7c3aed;
-                            }
-
-                            &.tag-layout {
-                              background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
-                              color: #1e40af;
-                              border-color: #1e40af;
-                            }
-                          }
-                        }
-
-                        // 色彩搭配显示
-                        .color-scheme-display {
-                          display: flex;
-                          flex-direction: column;
-                          gap: 12px;
-
-                          .color-row {
-                            display: flex;
-                            align-items: center;
-                            gap: 12px;
-
-                            .color-label {
-                              font-size: 12px;
-                              font-weight: 600;
-                              color: var(--medium-color);
-                              min-width: 60px;
-                            }
-
-                            .color-samples {
-                              display: flex;
-                              gap: 6px;
-
-                              .color-sample {
-                                width: 24px;
-                                height: 24px;
-                                border-radius: 4px;
-                                border: 1px solid rgba(0, 0, 0, 0.1);
-                                cursor: pointer;
-                                transition: transform 0.2s ease;
-
-                                &:hover {
-                                  transform: scale(1.1);
-                                  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
-                                }
-                              }
-                            }
-                          }
-                        }
-
-                        // 分析行
-                        .analysis-row {
-                          display: flex;
-                          align-items: center;
-                          gap: 8px;
-                          font-size: 12px;
-
-                          .value {
-                            color: var(--dark-color);
-                            flex: 1;
-                          }
-                        }
-
-                        // 色彩分析
-                        .color-analysis-content {
-                          display: flex;
-                          flex-direction: column;
-                          gap: 10px;
-
-                          .color-item {
-                            display: flex;
-                            align-items: center;
-                            gap: 8px;
-                            font-size: 12px;
-
-                            .color-label {
-                              font-weight: 600;
-                              color: var(--medium-color);
-                              min-width: 60px;
-                            }
-
-                            .color-value {
-                              color: var(--dark-color);
-                              flex: 1;
-                            }
-                          }
-
-                          .color-swatches-group,
-                          .color-org-group {
-                            display: flex;
-                            flex-direction: column;
-                            gap: 6px;
-
-                            .color-label {
-                              font-size: 12px;
-                              font-weight: 600;
-                              color: var(--medium-color);
-                            }
-
-                            .color-swatches {
-                              display: flex;
-                              gap: 6px;
-                              flex-wrap: wrap;
-
-                              .color-swatch {
-                                width: 32px;
-                                height: 32px;
-                                border-radius: 4px;
-                                border: 1px solid rgba(0, 0, 0, 0.1);
-                                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-                                cursor: pointer;
-                                transition: all 0.2s ease;
-
-                                &:hover {
-                                  transform: scale(1.15);
-                                  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-                                }
-                              }
-                            }
-
-                            .color-organization {
-                              display: flex;
-                              flex-direction: column;
-                              gap: 6px;
-
-                              .color-org-item {
-                                display: flex;
-                                align-items: center;
-                                gap: 6px;
-                                font-size: 11px;
-
-                                .color-org-swatch {
-                                  width: 24px;
-                                  height: 24px;
-                                  border-radius: 3px;
-                                  border: 1px solid rgba(0, 0, 0, 0.1);
-                                  flex-shrink: 0;
-                                }
-
-                                .color-org-label {
-                                  color: var(--medium-color);
-                                  flex: 1;
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                }
-              }
-            }
-
-            .user-notes-section {
-              .section-header {
-                margin-bottom: 12px;
-              }
-
-              .form-textarea {
-                width: 100%;
-                padding: 12px;
-                border: 1px solid var(--light-shade);
-                border-radius: 8px;
-                font-size: 13px;
-                font-family: inherit;
-                resize: vertical;
-                transition: all 0.3s ease;
-
-                &:focus {
-                  outline: none;
-                  border-color: var(--primary-color);
-                  box-shadow: 0 0 0 3px rgba(var(--primary-rgb), 0.1);
-                }
-
-                &:disabled {
-                  background: var(--light-color);
-                  cursor: not-allowed;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // 空间需求
-  .space-requirements {
-    display: flex;
-    flex-direction: column;
-    gap: 16px;
-
-    .space-requirement-card {
-      .completion-badge {
-        background: var(--success-color);
-        color: white;
-        padding: 4px 8px;
-        border-radius: 12px;
-        font-size: 12px;
-        font-weight: 600;
-      }
-
-      .space-reference-images {
-        h4 {
-          margin: 16px 0 8px;
-          font-size: 14px;
-          font-weight: 600;
-          color: var(--dark-color);
-        }
-      }
-    }
-  }
-
-  // 跨空间需求
-  .cross-space-requirements {
-    .cross-space-list {
-      .cross-space-item {
-        padding: 16px;
-        background-color: var(--light-color);
-        border-radius: 8px;
-        margin-bottom: 12px;
-
-        .item-header {
-          display: flex;
-          justify-content: space-between;
-          align-items: center;
-          margin-bottom: 8px;
-        }
-
-        .description {
-          margin: 0 0 12px;
-          font-size: 14px;
-          line-height: 1.5;
-          color: var(--dark-color);
-        }
-
-        .related-spaces {
-          display: flex;
-          align-items: center;
-          gap: 8px;
-
-          .label {
-            font-size: 12px;
-            color: var(--medium-color);
-            font-weight: 500;
-          }
-
-          .space-tags {
-            display: flex;
-            gap: 6px;
-            flex-wrap: wrap;
-          }
-        }
-      }
-    }
-  }
-
-  // AI方案卡片
-  .ai-solution-card {
-    .ai-solution-content {
-      .solution-header {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        margin-bottom: 20px;
-        padding-bottom: 16px;
-        border-bottom: 1px solid var(--light-shade);
-
-        .badge {
-          display: flex;
-          align-items: center;
-          gap: 4px;
-          padding: 6px 12px;
-
-          .icon, .space-icon {
-            font-size: 16px;
-          }
-        }
-      }
-
-      .solution-summary {
-        margin-bottom: 24px;
-        padding: 16px;
-        background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.05), rgba(12, 209, 232, 0.05));
-        border-radius: 8px;
-        border-left: 4px solid var(--primary-color);
-
-        p {
-          margin: 0;
-          font-size: 14px;
-          line-height: 1.6;
-          color: var(--dark-color);
-        }
-      }
-
-      .spaces-solution {
-        .space-solution-item {
-          padding: 16px;
-          background-color: var(--light-color);
-          border-radius: 8px;
-          margin-bottom: 16px;
-
-          &:last-child {
-            margin-bottom: 20px;
-          }
-
-          .space-header {
-            display: flex;
-            align-items: center;
-            gap: 8px;
-            margin-bottom: 8px;
-
-            .icon, .space-icon {
-              font-size: 20px;
-              color: var(--primary-color);
-            }
-
-            h4 {
-              margin: 0;
-              font-size: 16px;
-              font-weight: 600;
-              color: var(--dark-color);
-            }
-          }
-
-          .style-desc {
-            margin: 0 0 16px;
-            font-size: 13px;
-            line-height: 1.6;
-            color: var(--medium-color);
-          }
-
-          .solution-details {
-            display: grid;
-            grid-template-columns: repeat(2, 1fr);
-            gap: 12px;
-            margin-bottom: 16px;
-
-            .detail-item {
-              display: flex;
-              align-items: center;
-              gap: 8px;
-
-              .label {
-                font-size: 12px;
-                color: var(--medium-color);
-                font-weight: 500;
-              }
-
-              .value {
-                font-size: 14px;
-                color: var(--dark-color);
-                font-weight: 600;
-              }
-            }
-          }
-
-          .color-palette,
-          .materials,
-          .furniture {
-            display: flex;
-            align-items: center;
-            gap: 8px;
-            margin-bottom: 12px;
-
-            &:last-child {
-              margin-bottom: 0;
-            }
-
-            .label {
-              font-size: 12px;
-              font-weight: 500;
-              color: var(--medium-color);
-              white-space: nowrap;
-            }
-
-            .colors {
-              display: flex;
-              gap: 6px;
-              flex-wrap: wrap;
-
-              .color-swatch {
-                width: 32px;
-                height: 32px;
-                border-radius: 4px;
-                border: 1px solid rgba(0, 0, 0, 0.1);
-                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-                cursor: pointer;
-              }
-            }
-
-            .tags {
-              display: flex;
-              flex-wrap: wrap;
-              gap: 6px;
-            }
-          }
-        }
-      }
-
-      .cross-space-coordination {
-        margin-bottom: 24px;
-        padding: 16px;
-        background: linear-gradient(135deg, rgba(var(--secondary-rgb), 0.05), rgba(112, 68, 255, 0.05));
-        border-radius: 8px;
-        border-left: 4px solid var(--secondary-color);
-
-        h4 {
-          margin: 0 0 16px;
-          font-size: 15px;
-          font-weight: 600;
-          color: var(--dark-color);
-          display: flex;
-          align-items: center;
-          gap: 8px;
-
-          .icon, .space-icon {
-            font-size: 18px;
-            color: var(--secondary-color);
-          }
-        }
-
-        .coordination-items {
-          display: flex;
-          flex-direction: column;
-          gap: 12px;
-
-          .coordination-item {
-            display: flex;
-            align-items: flex-start;
-            gap: 12px;
-
-            .icon, .space-icon {
-              font-size: 20px;
-              color: var(--secondary-color);
-              flex-shrink: 0;
-              margin-top: 2px;
-            }
-
-            h5 {
-              margin: 0 0 4px;
-              font-size: 14px;
-              font-weight: 600;
-              color: var(--dark-color);
-            }
-
-            p {
-              margin: 0;
-              font-size: 13px;
-              line-height: 1.5;
-              color: var(--medium-color);
-            }
-          }
-        }
-      }
-
-      .summary {
-        display: grid;
-        grid-template-columns: repeat(2, 1fr);
-        gap: 12px;
-
-        .summary-item {
-          display: flex;
-          align-items: center;
-          gap: 12px;
-          padding: 16px;
-          background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.1), rgba(12, 209, 232, 0.1));
-          border-radius: 8px;
-
-          .icon, .space-icon {
-            font-size: 32px;
-            color: var(--primary-color);
-            flex-shrink: 0;
-          }
-
-          .label {
-            font-size: 11px;
-            color: var(--medium-color);
-            margin: 0 0 4px;
-          }
-
-          h3 {
-            margin: 0;
-            font-size: 18px;
-            font-weight: 700;
-            color: var(--primary-color);
-          }
-
-          p {
-            margin: 0;
-            font-size: 12px;
-            line-height: 1.4;
-            color: var(--medium-color);
-          }
-        }
-      }
-    }
-  }
-
-  // 操作按钮
-  .action-buttons {
-    display: grid;
-    grid-template-columns: 1fr 1fr;
-    gap: 12px;
-    padding: 16px 0;
-    margin-top: 20px;
-  }
-}
-
-// Badge 组件
-.badge {
-  display: inline-block;
-  padding: 4px 10px;
-  border-radius: 12px;
-  font-size: 11px;
-  font-weight: 600;
-  white-space: nowrap;
-
-  &.badge-primary {
-    background: var(--primary-color);
-    color: white;
-  }
-
-  &.badge-secondary {
-    background: var(--secondary-color);
-    color: white;
-  }
-
-  &.badge-tertiary {
-    background: var(--tertiary-color);
-    color: white;
-  }
-
-  &.badge-success {
-    background: var(--success-color);
-    color: white;
-  }
-
-  &.badge-warning {
-    background: var(--warning-color);
-    color: var(--dark-color);
-  }
-
-  &.badge-danger {
-    background: var(--danger-color);
-    color: white;
-  }
-
-  &.badge-medium {
-    background: var(--medium-color);
-    color: white;
-  }
-
-  &.badge-outline {
-    background: transparent;
-    border: 1px solid var(--medium-color);
-    color: var(--medium-color);
-  }
-}
-
-// 按钮样式
-.btn {
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
-  gap: 8px;
-  padding: 12px 24px;
-  border-radius: 8px;
-  font-size: 14px;
-  font-weight: 600;
-  cursor: pointer;
-  transition: all 0.3s;
-  border: none;
-  outline: none;
-  white-space: nowrap;
-
-  .icon, .space-icon {
-    font-size: 20px;
-  }
-
-  &.btn-primary {
-    background: var(--primary-color);
-    color: white;
-
-    &:hover:not(:disabled) {
-      background: #2f6ce5;
-      transform: translateY(-2px);
-      box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.3);
-    }
-
-    &:active:not(:disabled) {
-      transform: translateY(0);
-    }
-  }
-
-  &.btn-outline {
-    background: white;
-    color: var(--primary-color);
-    border: 2px solid var(--primary-color);
-
-    &:hover:not(:disabled) {
-      background: var(--primary-color);
-      color: white;
-    }
-
-    &:active:not(:disabled) {
-      transform: scale(0.98);
-    }
-  }
-
-  &.btn-sm {
-    padding: 8px 16px;
-    font-size: 12px;
-
-    .icon, .space-icon {
-      font-size: 16px;
-    }
-  }
-
-  &.btn-block {
-    display: flex;
-    width: 100%;
-  }
-
-  &:disabled {
-    opacity: 0.5;
-    cursor: not-allowed;
-  }
-}
-
-// 图标按钮
-.btn-icon {
-  display: inline-flex;
-  align-items: center;
-  justify-content: center;
-  width: 40px;
-  height: 40px;
-  border: none;
-  background: transparent;
-  border-radius: 50%;
-  cursor: pointer;
-  transition: all 0.2s;
-  padding: 8px;
-
-  .icon, .space-icon {
-    font-size: 24px;
-  }
-
-  &.btn-danger {
-    color: white;
-    background: var(--danger-color);
-
-    &:hover:not(:disabled) {
-      background: #d33939;
-      transform: scale(1.1);
-    }
-
-    &:active:not(:disabled) {
-      transform: scale(0.95);
-    }
-  }
-
-  &:disabled {
-    opacity: 0.5;
-    cursor: not-allowed;
-  }
-}
-
-// 表单样式
-.form-group {
-  margin-bottom: 16px;
-
-  &:last-child {
-    margin-bottom: 0;
-  }
-
-  .form-label {
-    display: block;
-    margin-bottom: 8px;
-    font-size: 13px;
-    font-weight: 600;
-    color: var(--dark-color);
-  }
-
-  .form-input,
-  .form-textarea,
-  .form-select {
-    width: 100%;
-    padding: 12px 16px;
-    border: 1px solid var(--light-shade);
-    border-radius: 8px;
-    font-size: 14px;
-    color: var(--dark-color);
-    background: white;
-    transition: all 0.3s;
-    font-family: inherit;
-
-    &:focus {
-      outline: none;
-      border-color: var(--primary-color);
-      box-shadow: 0 0 0 3px rgba(var(--primary-rgb), 0.1);
-    }
-
-    &::placeholder {
-      color: var(--medium-color);
-    }
-
-    &:disabled {
-      background: var(--light-color);
-      cursor: not-allowed;
-      opacity: 0.7;
-    }
-  }
-
-  .form-textarea {
-    min-height: 80px;
-    resize: vertical;
-  }
-
-  .form-select {
-    cursor: pointer;
-    appearance: none;
-    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23999' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
-    background-repeat: no-repeat;
-    background-position: right 12px center;
-    padding-right: 40px;
-
-    &:disabled {
-      cursor: not-allowed;
-    }
-  }
-}
-
-
-@media (max-width: 768px) {
-    .card-header{
-      display: flex!important;
-      flex-wrap: wrap!important;
-      .card-subtitle{
-        max-width: 150px;
-      }
-    }
-    .ai-analysis-actions{
-      width:100%;
-      justify-content: between;
-    }
-      .analysis-item{
-        display: flex!important;
-        flex-direction: column!important;
-      }
-
-}
-
-// 响应式适配
-@media (min-width: 768px) {
-
-
-  .stage-requirements-container {
-    max-width: 800px;
-    margin: 0 auto;
-    padding: 0 24px 80px;
-
-    .reference-images-card {
-      .images-grid {
-        grid-template-columns: repeat(3, 1fr);
-      }
-    }
-
-    .style-preferences-card {
-      .color-inputs {
-        grid-template-columns: repeat(4, 1fr);
-      }
-    }
-
-
-    .ai-solution-card {
-      .ai-solution-content {
-        .summary {
-          grid-template-columns: repeat(2, 1fr);
-        }
-      }
-    }
-  }
-}
-
-@media (min-width: 1024px) {
-  .stage-requirements-container {
-    max-width: 1000px;
-
-    .reference-images-card {
-      .images-grid {
-        grid-template-columns: repeat(4, 1fr);
-      }
-    }
-  }
-}
-
-// 移动端优化
-@media (max-width: 480px) {
-  .stage-requirements-container {
-    padding: 0 8px 70px;
-
-    .space-selector {
-      .space-tabs {
-        .space-tab {
-          min-width: 100px;
-          padding: 10px 12px;
-          font-size: 12px;
-
-          .icon, .space-icon {
-            font-size: 16px;
-          }
-        }
-      }
-    }
-
-    .card {
-      .card-header {
-        padding: 12px;
-
-        .card-title {
-          font-size: 15px;
-
-          .icon, .space-icon {
-            font-size: 18px;
-          }
-        }
-
-        .card-subtitle {
-          font-size: 11px;
-        }
-      }
-
-      .card-content {
-        padding: 12px;
-      }
-    }
-
-    .reference-images-card {
-      .images-grid {
-        gap: 8px;
-
-        .image-item {
-          // 在移动端始终显示overlay,便于点击操作
-          .image-overlay {
-            opacity: 1;
-            background: linear-gradient(to bottom, rgba(0, 0, 0, 0.4), transparent, rgba(0, 0, 0, 0.6));
-            padding: 6px;
-
-            .overlay-top {
-              .badge {
-                font-size: 9px;
-                padding: 3px 6px;
-              }
-            }
-
-            .overlay-actions {
-              gap: 4px;
-
-              .btn-icon {
-                width: 28px;
-                height: 28px;
-                padding: 3px;
-
-                .icon, .space-icon {
-                  font-size: 18px;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-
-    .style-preferences-card {
-      .color-inputs {
-        grid-template-columns: repeat(2, 1fr);
-        gap: 8px;
-      }
-
-      .quality-level {
-        .radio-group {
-          flex-direction: column;
-          gap: 8px;
-
-          .radio-item {
-            .radio-label {
-              font-size: 13px;
-            }
-          }
-        }
-      }
-    }
-
-    .ai-solution-card {
-      .ai-solution-content {
-        .spaces-solution {
-          .space-solution-item {
-            padding: 12px;
-
-            .space-header {
-              h4 {
-                font-size: 15px;
-              }
-            }
-
-            .solution-details {
-              grid-template-columns: 1fr;
-              gap: 8px;
-            }
-
-            .color-palette,
-            .materials,
-            .furniture {
-              flex-direction: column;
-              align-items: flex-start;
-              gap: 8px;
-
-              .label {
-                width: 100%;
-              }
-            }
-          }
-        }
-
-        .cross-space-coordination {
-          padding: 12px;
-
-          .coordination-items {
-            .coordination-item {
-              .icon, .space-icon {
-                font-size: 18px;
-              }
-            }
-          }
-        }
-
-        .summary {
-          grid-template-columns: 1fr;
-
-          .summary-item {
-            padding: 12px;
-
-            .icon, .space-icon {
-              font-size: 28px;
-            }
-
-            h3 {
-              font-size: 16px;
-            }
-          }
-        }
-      }
-    }
-
-    .action-buttons {
-      gap: 8px;
-
-      .btn {
-        padding: 10px 16px;
-        font-size: 13px;
-
-        .icon, .space-icon {
-          font-size: 18px;
-        }
-      }
-    }
-
-    .form-group {
-      margin-bottom: 14px;
-
-      .form-label {
-        font-size: 12px;
-      }
-
-      .form-input,
-      .form-textarea,
-      .form-select {
-        padding: 10px 12px;
-        font-size: 13px;
-      }
-    }
-
-    .btn {
-      padding: 10px 20px;
-      font-size: 13px;
-
-      .icon, .space-icon {
-        font-size: 18px;
-      }
-    }
-
-    .btn-icon {
-      width: 36px;
-      height: 36px;
-
-      .icon, .space-icon {
-        font-size: 20px;
-      }
-    }
-  }
-}
-
-// 新的空间需求管理样式
-.space-requirements-card {
-  .spaces-container {
-    display: flex;
-    flex-direction: column;
-    gap: 16px;
-  }
-
-  .space-item {
-    border: 2px solid var(--light-shade);
-    border-radius: 12px;
-    background: var(--white);
-    transition: all 0.3s ease;
-    overflow: hidden;
-
-    &.expanded {
-      border-color: var(--primary-color);
-      box-shadow: 0 4px 12px rgba(var(--primary-rgb), 0.15);
-    }
-
-    &:hover {
-      border-color: var(--primary-color);
-      box-shadow: 0 2px 8px rgba(var(--primary-rgb), 0.1);
-    }
-  }
-
-  .space-header {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding: 14px 16px; // 🔥 缩小padding适配企业微信
-    cursor: pointer;
-    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-    border-bottom: 1px solid transparent;
-    transition: all 0.2s ease;
-
-    &:hover {
-      background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
-    }
-
-    .expanded & {
-      border-bottom-color: var(--light-shade);
-    }
-  }
-
-  .space-info {
-    display: flex;
-    align-items: center;
-    gap: 12px; // 🔥 缩小gap
-    flex: 1;
-    min-width: 0; // 🔥 允许内容收缩
-  }
-
-  .space-title {
-    display: flex;
-    flex-direction: column;
-    gap: 6px; // 🔥 缩小gap
-    min-width: 0; // 🔥 允许内容收缩
-
-    h4 {
-      margin: 0;
-      font-size: 15px; // 🔥 缩小字体
-      font-weight: 600;
-      color: var(--dark-color);
-      white-space: nowrap;
-      overflow: hidden;
-      text-overflow: ellipsis;
-    }
-
-    .space-stats {
-      display: flex;
-      align-items: center;
-      gap: 10px; // 🔥 缩小gap
-    }
-
-    .file-count {
-      display: flex;
-      align-items: center;
-      gap: 4px;
-      font-size: 12px; // 🔥 缩小字体
-      color: var(--medium-color);
-      background: rgba(var(--primary-rgb), 0.1);
-      padding: 3px 6px; // 🔥 缩小padding
-      border-radius: 6px;
-
-      ion-icon {
-        font-size: 13px; // 🔥 缩小图标
-        color: var(--primary-color);
-      }
-    }
-
-    .no-files {
-      font-size: 12px; // 🔥 缩小字体
-      color: var(--medium-color);
-      font-style: italic;
-    }
-  }
-
-  .has-requirements {
-    display: flex;
-    align-items: center;
-    gap: 6px;
-    font-size: 13px;
-    color: var(--success-color);
-    background: rgba(45, 211, 111, 0.1);
-    padding: 6px 12px;
-    border-radius: 8px;
-
-    ion-icon {
-      font-size: 16px;
-    }
-  }
-
-  .expand-icon {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    width: 32px;
-    height: 32px;
-    border-radius: 8px;
-    background: rgba(var(--primary-rgb), 0.1);
-    color: var(--primary-color);
-    transition: all 0.2s ease;
-
-    ion-icon {
-      font-size: 18px;
-      transition: transform 0.2s ease;
-    }
-
-    .expanded & ion-icon {
-      transform: rotate(180deg);
-    }
-  }
-
-  .space-content {
-    padding: 0;
-    background: var(--white);
-  }
-
-  .space-section {
-    padding: 20px 24px;
-    border-bottom: 1px solid var(--light-shade);
-
-    &:last-child {
-      border-bottom: none;
-    }
-  }
-
-  .section-header {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    margin-bottom: 16px;
-
-    h5 {
-      margin: 0;
-      font-size: 16px;
-      font-weight: 600;
-      color: var(--dark-color);
-    }
-
-    .btn {
-      padding: 8px 16px;
-      font-size: 13px;
-      border-radius: 8px;
-    }
-  }
-
-  .section-content {
-    .form-textarea {
-      width: 100%;
-      min-height: 80px;
-      resize: vertical;
-    }
-  }
-
-  // 紧凑版图片网格
-  .images-grid.compact {
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
-    gap: 12px;
-    margin-top: 12px;
-
-    .image-item.compact {
-      aspect-ratio: 1;
-      border-radius: 8px;
-      overflow: hidden;
-      position: relative;
-      cursor: pointer;
-      transition: all 0.2s ease;
-
-      &:hover {
-        transform: translateY(-2px);
-        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-      }
-
-      img {
-        width: 100%;
-        height: 100%;
-        object-fit: cover;
-      }
-
-      .image-overlay {
-        position: absolute;
-        top: 0;
-        left: 0;
-        right: 0;
-        bottom: 0;
-        background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 0%, transparent 30%, transparent 70%, rgba(0, 0, 0, 0.7) 100%);
-        opacity: 0;
-        transition: opacity 0.2s ease;
-        display: flex;
-        flex-direction: column;
-        justify-content: space-between;
-        padding: 8px;
-
-        .overlay-top {
-          display: flex;
-          gap: 4px;
-          flex-wrap: wrap;
-
-          .badge {
-            font-size: 10px;
-            padding: 2px 6px;
-          }
-        }
-
-        .overlay-actions {
-          display: flex;
-          gap: 4px;
-          justify-content: flex-end;
-
-          .btn-icon {
-            width: 28px;
-            height: 28px;
-            font-size: 14px;
-          }
-        }
-      }
-
-      &:hover .image-overlay {
-        opacity: 1;
-      }
-    }
-  }
-
-  // 紧凑版文件列表
-  .file-list.compact {
-    display: flex;
-    flex-direction: column;
-    gap: 8px;
-    margin-top: 12px;
-
-    .file-item.compact {
-      display: flex;
-      align-items: center;
-      gap: 12px;
-      padding: 12px;
-      background: var(--light-color);
-      border-radius: 8px;
-      transition: all 0.2s ease;
-
-      &:hover {
-        background: var(--light-shade);
-        transform: translateX(4px);
-      }
-
-      .file-icon {
-        font-size: 20px;
-        color: var(--primary-color);
-        flex-shrink: 0;
-      }
-
-      .file-info {
-        flex: 1;
-        min-width: 0;
-
-        h6 {
-          margin: 0 0 4px 0;
-          font-size: 14px;
-          font-weight: 500;
-          color: var(--dark-color);
-          white-space: nowrap;
-          overflow: hidden;
-          text-overflow: ellipsis;
-        }
-
-        p {
-          margin: 0;
-          font-size: 12px;
-          color: var(--medium-color);
-          display: flex;
-          align-items: center;
-          gap: 8px;
-        }
-
-        .badge {
-          font-size: 10px;
-          padding: 2px 6px;
-          margin-top: 4px;
-        }
-      }
-
-      .btn-icon {
-        width: 32px;
-        height: 32px;
-        font-size: 16px;
-        flex-shrink: 0;
-      }
-    }
-  }
-
-  // 紧凑版空状态
-  .empty-state.compact {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    padding: 32px 16px;
-    color: var(--medium-color);
-    background: var(--light-color);
-    border-radius: 8px;
-    margin-top: 12px;
-
-    ion-icon {
-      font-size: 32px;
-      margin-bottom: 8px;
-      opacity: 0.6;
-    }
-
-    p {
-      margin: 0;
-      font-size: 14px;
-      text-align: center;
-    }
-  }
-}
-
-// 响应式设计 - 空间需求管理
-@media (max-width: 768px) {
-  .space-requirements-card {
-    .space-header {
-      padding: 16px 20px;
-      flex-direction: column;
-      align-items: flex-start;
-      gap: 12px;
-
-      .space-info {
-        width: 100%;
-        flex-direction: column;
-        align-items: flex-start;
-        gap: 12px;
-      }
-
-      .space-title {
-        width: 100%;
-
-        .space-stats {
-          justify-content: flex-start;
-        }
-      }
-
-      .expand-icon {
-        align-self: flex-end;
-      }
-    }
-
-    .space-section {
-      padding: 16px 20px;
-    }
-
-    .section-header {
-      flex-direction: column;
-      align-items: flex-start;
-      gap: 12px;
-
-      .btn {
-        align-self: flex-start;
-      }
-    }
-
-    .images-grid.compact {
-      grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
-      gap: 8px;
-    }
-
-    .file-list.compact {
-      .file-item.compact {
-        padding: 10px;
-        gap: 10px;
-
-        .file-info h6 {
-          font-size: 13px;
-        }
-
-        .file-info p {
-          font-size: 11px;
-        }
-      }
-    }
-  }
-}
-
-// ===== AI设计分析页面卡片样式 =====
-
-.ai-design-analysis-section {
-  margin-bottom: 32px;
-  animation: fadeSlideUp 0.4s ease-out;
-
-  @keyframes fadeSlideUp {
-    from {
-      opacity: 0;
-      transform: translateY(20px);
-    }
-    to {
-      opacity: 1;
-      transform: translateY(0);
-    }
-  }
-}
-
-.ai-analysis-card {
-  // 空间选择器
-  .space-selector-inline {
-    display: flex;
-    align-items: center;
-    gap: 16px;
-    margin-bottom: 24px;
-    padding: 16px;
-    background: linear-gradient(135deg, #f0f3ff 0%, #f7f0ff 100%);
-    border-radius: 12px;
-    border: 2px solid #e0e7ff;
-
-    .selector-label {
-      font-size: 16px;
-      font-weight: 600;
-      color: #5b21b6;
-      white-space: nowrap;
-    }
-
-    .space-tabs-inline {
-      display: flex;
-      flex-wrap: wrap;
-      gap: 8px;
-
-      .space-tab-btn {
-        padding: 8px 20px;
-        border: 2px solid #d8b4fe;
-        background: white;
-        color: #7c3aed;
-        font-size: 14px;
-        font-weight: 500;
-        border-radius: 20px;
-        cursor: pointer;
-        transition: all 0.2s;
-
-        &:hover {
-          background: #faf5ff;
-          border-color: #a78bfa;
-        }
-
-        &.active {
-          background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
-          color: white;
-          border-color: #7c3aed;
-          box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
-        }
-      }
-    }
-  }
-
-  // 按钮样式
-  .btn-reset {
-    padding: 6px 16px;
-    background: #f3f4f6;
-    color: #6b7280;
-    border: none;
-    border-radius: 8px;
-    font-size: 14px;
-    cursor: pointer;
-    transition: all 0.2s;
-
-    &:hover {
-      background: #e5e7eb;
-      color: #374151;
-    }
-  }
-
-  // 结果头部
-  .result-header {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-    margin-bottom: 24px;
-
-    .header-icon {
-      font-size: 32px;
-    }
-
-    h3 {
-      flex: 1;
-      margin: 0;
-      font-size: 20px;
-      font-weight: 600;
-      color: #1a202c;
-    }
-  }
-
-  // 报告头部
-  .report-header {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-    margin-bottom: 24px;
-
-    .header-icon {
-      font-size: 32px;
-    }
-
-    h3 {
-      flex: 1;
-      margin: 0;
-      font-size: 20px;
-      font-weight: 600;
-      color: #1a202c;
-    }
-  }
-
-  // 上传区域
-  .upload-section {
-    padding: 24px;
-
-    // 上传卡片
-    .upload-card {
-      background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
-      border-radius: 12px;
-      padding: 48px 32px;
-      text-align: center;
-      cursor: pointer;
-      transition: all 0.3s;
-      border: 2px dashed #cbd5e0;
-      position: relative;
-
-      &:hover {
-        transform: translateY(-2px);
-        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
-        border-color: #667eea;
-      }
-
-      &.drag-over {
-        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-        border-color: #667eea;
-        transform: scale(1.02);
-        
-        .upload-icon {
-          animation: bounce 0.5s ease infinite;
-        }
-        
-        h3, .upload-desc, .upload-hint {
-          color: white !important;
-        }
-      }
-
-      .upload-icon {
-        font-size: 64px;
-        margin-bottom: 16px;
-      }
-
-      h3 {
-        font-size: 20px;
-        color: #2d3748;
-        margin: 0 0 8px;
-      }
-
-      .upload-desc {
-        color: #4a5568;
-        font-size: 14px;
-        margin-bottom: 16px;
-      }
-
-      .upload-hint {
-        color: #718096;
-        font-size: 13px;
-        
-        .hint-text {
-          display: block;
-          margin-bottom: 8px;
-          font-style: italic;
-        }
-        
-        .hint-formats {
-          display: block;
-          font-size: 11px;
-          color: #a0aec0;
-        }
-      }
-    }
-
-    @keyframes bounce {
-      0%, 100% {
-        transform: translateY(0);
-      }
-      50% {
-        transform: translateY(-10px);
-      }
-    }
-
-    // 已上传文件
-    .uploaded-files {
-      display: grid;
-      grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
-      gap: 16px;
-      margin-bottom: 24px;
-
-      .file-item {
-        position: relative;
-        border-radius: 12px;
-        overflow: hidden;
-        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-        background: white;
-        transition: all 0.2s;
-
-        &:hover {
-          box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
-        }
-
-        &.is-image {
-          aspect-ratio: 1;
-          
-          img {
-            width: 100%;
-            height: 100%;
-            object-fit: cover;
-          }
-          
-          .file-info {
-            position: absolute;
-            bottom: 0;
-            left: 0;
-            right: 0;
-            background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
-            color: white;
-            padding: 8px;
-            opacity: 0;
-            transition: opacity 0.2s;
-          }
-          
-          &:hover .file-info {
-            opacity: 1;
-          }
-        }
-
-        .file-icon {
-          aspect-ratio: 1;
-          display: flex;
-          flex-direction: column;
-          align-items: center;
-          justify-content: center;
-          gap: 12px;
-          background: linear-gradient(135deg, #f5f7fa 0%, #e2e8f0 100%);
-          padding: 20px;
-          
-          ion-icon {
-            font-size: 48px;
-            color: #718096;
-          }
-          
-          .file-ext {
-            font-size: 14px;
-            font-weight: 600;
-            color: #4a5568;
-          }
-          
-          &.pdf ion-icon {
-            color: #e53e3e;
-          }
-          
-          &.cad ion-icon {
-            color: #3182ce;
-          }
-        }
-
-        .file-info {
-          .file-name {
-            font-size: 12px;
-            font-weight: 500;
-            white-space: nowrap;
-            overflow: hidden;
-            text-overflow: ellipsis;
-            margin-bottom: 4px;
-          }
-          
-          .file-size {
-            font-size: 10px;
-            color: #a0aec0;
-          }
-        }
-
-        .remove-btn {
-          position: absolute;
-          top: 8px;
-          right: 8px;
-          width: 28px;
-          height: 28px;
-          background: rgba(0, 0, 0, 0.7);
-          color: white;
-          border: none;
-          border-radius: 50%;
-          font-size: 18px;
-          cursor: pointer;
-          display: flex;
-          align-items: center;
-          justify-content: center;
-          opacity: 0;
-          transition: all 0.2s;
-          z-index: 10;
-
-          &:hover {
-            background: rgba(220, 38, 38, 0.9);
-          }
-        }
-
-        &:hover .remove-btn {
-          opacity: 1;
-        }
-      }
-
-      .add-more {
-        aspect-ratio: 1;
-        border: 2px dashed #cbd5e0;
-        border-radius: 12px;
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        justify-content: center;
-        cursor: pointer;
-        transition: all 0.2s;
-        background: #f7fafc;
-
-        &:hover {
-          border-color: #667eea;
-          background: #edf2f7;
-        }
-
-        .add-icon {
-          font-size: 36px;
-          color: #a0aec0;
-          margin-bottom: 4px;
-        }
-
-        .add-text {
-          font-size: 13px;
-          color: #718096;
-        }
-      }
-    }
-
-    // AI对话容器(优化布局,减少遮挡)
-    .ai-chat-container {
-      display: flex;
-      flex-direction: column;
-      height: 700px; // 增大高度,减少遮挡
-      background: white;
-      border-radius: 12px; // 减小圆角
-      overflow: hidden;
-      box-shadow: 0 1px 8px rgba(0, 0, 0, 0.06); // 减轻阴影
-      margin-bottom: 16px; // 减小底部边距
-
-      // 对话消息区域(优化padding,增大显示区域)
-      .chat-messages-wrapper {
-        flex: 1;
-        overflow-y: auto;
-        padding: 16px; // 减小padding,增大内容区域
-        background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);
-
-        // 欢迎界面
-        .chat-welcome {
-          display: flex;
-          flex-direction: column;
-          align-items: center;
-          justify-content: center;
-          height: 100%;
-          text-align: center;
-          padding: 40px 20px;
-
-          .welcome-icon {
-            width: 80px;
-            height: 80px;
-            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-            border-radius: 50%;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            margin-bottom: 24px;
-            box-shadow: 0 8px 24px rgba(102, 126, 234, 0.3);
-
-            ion-icon {
-              font-size: 40px;
-              color: white;
-            }
-
-            // 🔥 企业微信端emoji支持
-            .icon-text {
-              font-size: 40px;
-              line-height: 1;
-              display: inline-block;
-              color: white;
-            }
-          }
-
-          h3 {
-            font-size: 24px;
-            font-weight: 600;
-            color: #1e293b;
-            margin: 0 0 12px 0;
-          }
-
-          p {
-            font-size: 15px;
-            color: #64748b;
-            margin: 0 0 32px 0;
-            max-width: 400px;
-          }
-
-          .quick-prompts {
-            display: grid;
-            grid-template-columns: repeat(2, 1fr);
-            gap: 12px;
-            max-width: 500px;
-            width: 100%;
-
-            .prompt-chip {
-              display: flex;
-              align-items: center;
-              gap: 8px;
-              padding: 12px 20px;
-              background: white;
-              border: 1.5px solid #e2e8f0;
-              border-radius: 12px;
-              cursor: pointer;
-              transition: all 0.2s;
-              font-size: 14px;
-              color: #475569;
-              font-weight: 500;
-
-              ion-icon {
-                font-size: 20px;
-                color: #667eea;
-              }
-
-              // 🔥 企业微信端emoji支持
-              .icon-text {
-                font-size: 20px;
-                line-height: 1;
-                display: inline-block;
-              }
-
-              &:hover {
-                border-color: #667eea;
-                background: #f8f9ff;
-                transform: translateY(-2px);
-                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
-              }
-
-              &:active {
-                transform: translateY(0);
-              }
-            }
-          }
-        }
-
-        // 消息列表(优化间距和宽度)
-        .chat-messages-list {
-          display: flex;
-          flex-direction: column;
-          gap: 16px; // 减小消息间距
-
-          .chat-message {
-            display: flex;
-            animation: fadeInUp 0.3s ease-out;
-
-            .message-content {
-              display: flex;
-              gap: 10px; // 减小头像和内容间距
-              max-width: 90%; // 增大最大宽度,减少遮挡
-
-              .message-avatar {
-                width: 36px;
-                height: 36px;
-                border-radius: 50%;
-                display: flex;
-                align-items: center;
-                justify-content: center;
-                flex-shrink: 0;
-
-                ion-icon {
-                  font-size: 20px;
-                }
-
-                // 🔥 企业微信端emoji支持
-                .icon-text {
-                  font-size: 20px;
-                  line-height: 1;
-                  display: inline-block;
-                }
-
-                &.user-avatar {
-                  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
-                  color: white;
-                }
-
-                &.ai-avatar {
-                  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-                  color: white;
-                }
-              }
-
-              .message-bubble {
-                flex: 1;
-                padding: 12px 16px; // 减小padding,增大内容空间
-                border-radius: 12px; // 减小圆角
-                position: relative;
-
-                .message-text {
-                  font-size: 16px; // 增大字体,更易阅读
-                  line-height: 1.8; // 增大行高,增强可读性
-                  color: #1e293b;
-                  word-wrap: break-word;
-                  
-                  // 🎨 纯文本内容美观排版样式
-                  .content-paragraph {
-                    margin: 0 0 16px 0;
-                    line-height: 1.8;
-                    font-size: 16px;
-                    color: #334155;
-                    
-                    &:last-child {
-                      margin-bottom: 0;
-                    }
-                  }
-                  
-                  .content-heading {
-                    font-size: 18px;
-                    font-weight: 600;
-                    color: #0f172a;
-                    margin: 20px 0 12px 0;
-                    padding-left: 12px;
-                    border-left: 4px solid #667eea;
-                    
-                    &:first-child {
-                      margin-top: 0;
-                    }
-                  }
-                  
-                  .content-list {
-                    margin: 12px 0;
-                    padding-left: 24px;
-                    
-                    .content-list-item {
-                      margin: 8px 0;
-                      line-height: 1.8;
-                      font-size: 15px;
-                      color: #475569;
-                    }
-                  }
-                  
-                  // 优化markdown标题样式
-                  h3 {
-                    font-size: 18px;
-                    margin: 16px 0 10px 0;
-                    font-weight: 600;
-                    color: #0f172a;
-                  }
-                  
-                  h4 {
-                    font-size: 16px;
-                    margin: 12px 0 8px 0;
-                    font-weight: 600;
-                    color: #1e293b;
-                  }
-                  
-                  // 优化表格样式
-                  table {
-                    width: 100%;
-                    font-size: 13px;
-                    border-collapse: collapse;
-                    margin: 12px 0;
-                    
-                    th, td {
-                      padding: 6px 8px;
-                      border: 1px solid #e2e8f0;
-                      text-align: left;
-                    }
-                    
-                    th {
-                      background: #f8fafc;
-                      font-weight: 600;
-                    }
-                  }
-
-                  // 支持markdown样式
-                  p {
-                    margin: 0 0 12px 0;
-
-                    &:last-child {
-                      margin-bottom: 0;
-                    }
-                  }
-
-                  strong {
-                    font-weight: 600;
-                    color: #0f172a;
-                  }
-
-                  code {
-                    background: #f1f5f9;
-                    padding: 2px 6px;
-                    border-radius: 4px;
-                    font-family: 'Consolas', monospace;
-                    font-size: 14px;
-                  }
-
-                  ul, ol {
-                    margin: 8px 0;
-                    padding-left: 24px;
-
-                    li {
-                      margin: 4px 0;
-                    }
-                  }
-                }
-
-                .message-images {
-                  display: grid;
-                  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
-                  gap: 8px;
-                  margin-top: 12px;
-
-                  img {
-                    width: 100%;
-                    height: 120px;
-                    object-fit: cover;
-                    border-radius: 8px;
-                    cursor: pointer;
-                    transition: transform 0.2s;
-
-                    &:hover {
-                      transform: scale(1.05);
-                    }
-                  }
-                }
-
-                .message-loading {
-                  display: flex;
-                  align-items: center;
-                  gap: 12px;
-
-                  .loading-dots {
-                    display: flex;
-                    gap: 6px;
-
-                    span {
-                      width: 8px;
-                      height: 8px;
-                      background: #667eea;
-                      border-radius: 50%;
-                      animation: bounce 1.4s infinite ease-in-out;
-
-                      &:nth-child(1) {
-                        animation-delay: -0.32s;
-                      }
-
-                      &:nth-child(2) {
-                        animation-delay: -0.16s;
-                      }
-                    }
-                  }
-
-                  .loading-text {
-                    font-size: 14px;
-                    color: #64748b;
-                  }
-                }
-
-                .message-actions {
-                  display: flex;
-                  gap: 8px;
-                  margin-top: 12px;
-                  padding-top: 12px;
-                  border-top: 1px solid #f1f5f9;
-
-                  .action-btn {
-                    padding: 6px 12px;
-                    background: transparent;
-                    border: none;
-                    border-radius: 6px;
-                    cursor: pointer;
-                    color: #64748b;
-                    font-size: 14px;
-                    transition: all 0.2s;
-                    display: flex;
-                    align-items: center;
-                    gap: 4px;
-
-                    ion-icon {
-                      font-size: 16px;
-                    }
-
-                    // 🔥 企业微信端emoji支持
-                    .icon-text {
-                      font-size: 16px;
-                      line-height: 1;
-                      display: inline-block;
-                    }
-
-                    &:hover {
-                      background: #f8fafc;
-                      color: #475569;
-                    }
-
-                    &.liked {
-                      color: #3b82f6;
-                      background: #eff6ff;
-                    }
-
-                    &.disliked {
-                      color: #ef4444;
-                      background: #fef2f2;
-                    }
-                  }
-                }
-
-                .message-time {
-                  font-size: 12px;
-                  color: #94a3b8;
-                  margin-top: 8px;
-                  text-align: right;
-                }
-              }
-
-              &.user-content {
-                justify-content: flex-end;
-                margin-left: auto;
-
-                .message-bubble {
-                  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-                  color: white;
-                  border-bottom-right-radius: 4px;
-
-                  .message-text {
-                    color: white;
-                  }
-
-                  .message-time {
-                    color: rgba(255, 255, 255, 0.8);
-                  }
-                }
-              }
-
-              &.ai-content {
-                .message-bubble {
-                  background: white;
-                  border: 1px solid #e2e8f0;
-                  border-bottom-left-radius: 4px;
-                }
-              }
-            }
-          }
-        }
-      }
-
-      // 输入容器
-      .chat-input-container {
-        border-top: 1px solid #e2e8f0;
-        background: white;
-        padding: 16px 20px;
-
-        .input-wrapper {
-          background: #f8fafc;
-          border-radius: 12px;
-          border: 1.5px solid #e2e8f0;
-          transition: all 0.2s;
-
-          &:focus-within {
-            border-color: #667eea;
-            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
-          }
-
-          .chat-input {
-            width: 100%;
-            padding: 14px 16px;
-            border: none;
-            background: transparent;
-            font-size: 15px;
-            line-height: 1.6;
-            resize: none;
-            font-family: inherit;
-            color: #1e293b;
-            max-height: 150px;
-            overflow-y: auto;
-
-            &:focus {
-              outline: none;
-            }
-
-            &::placeholder {
-              color: #94a3b8;
-            }
-
-            &:disabled {
-              opacity: 0.5;
-              cursor: not-allowed;
-            }
-          }
-
-          .input-actions {
-            display: flex;
-            align-items: center;
-            justify-content: space-between;
-            padding: 8px 12px 12px;
-
-            .input-actions-left {
-              display: flex;
-              gap: 8px;
-
-              .action-btn {
-                width: 32px;
-                height: 32px;
-                border: none;
-                border-radius: 6px;
-                background: rgba(102, 126, 234, 0.1);
-                cursor: pointer;
-                display: flex;
-                align-items: center;
-                justify-content: center;
-                transition: all 0.2s ease;
-                position: relative;
-
-                .icon-text {
-                  font-size: 18px;
-                  line-height: 1;
-                  display: block;
-                }
-
-                ion-icon {
-                  font-size: 20px;
-                  color: #667eea !important;
-                  display: block;
-                  width: 20px;
-                  height: 20px;
-                }
-
-                &:hover:not(:disabled) {
-                  background: rgba(102, 126, 234, 0.2);
-                  transform: scale(1.05);
-                  
-                  ion-icon {
-                    color: #5568d3 !important;
-                  }
-                }
-
-                &:active:not(:disabled) {
-                  transform: scale(0.95);
-                }
-
-                &:disabled {
-                  opacity: 0.4;
-                  cursor: not-allowed;
-                  
-                  .icon-text {
-                    opacity: 0.6;
-                    filter: grayscale(1);
-                  }
-                  
-                  ion-icon {
-                    opacity: 0.5;
-                  }
-                }
-              }
-            }
-
-            .send-btn {
-              width: 40px;
-              height: 40px;
-              border: none;
-              border-radius: 50%;
-              background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-              color: white;
-              cursor: pointer;
-              display: flex;
-              align-items: center;
-              justify-content: center;
-              transition: all 0.2s;
-              box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
-
-              ion-icon {
-                font-size: 20px;
-              }
-
-              // 🔥 企业微信端emoji支持
-              .icon-text {
-                font-size: 20px;
-                line-height: 1;
-                display: inline-block;
-              }
-
-              .btn-loading {
-                .spinner {
-                  width: 20px;
-                  height: 20px;
-                  border: 2px solid rgba(255, 255, 255, 0.3);
-                  border-top-color: white;
-                  border-radius: 50%;
-                  animation: spin 0.8s linear infinite;
-                }
-              }
-
-              &:hover:not(:disabled) {
-                background: linear-gradient(135deg, #5568d3 0%, #6b3f91 100%);
-                transform: scale(1.05);
-                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
-              }
-
-              &:active:not(:disabled) {
-                transform: scale(0.95);
-              }
-
-              &:disabled {
-                opacity: 0.5;
-                cursor: not-allowed;
-                transform: none;
-              }
-            }
-          }
-        }
-
-        .quick-actions {
-          display: flex;
-          gap: 12px;
-          margin-top: 12px;
-
-          .quick-action-btn {
-            display: flex;
-            align-items: center;
-            gap: 6px;
-            padding: 8px 16px;
-            background: white;
-            border: 1px solid #e2e8f0;
-            border-radius: 8px;
-            cursor: pointer;
-            color: #64748b;
-            font-size: 14px;
-            transition: all 0.2s;
-
-            ion-icon {
-              font-size: 16px;
-            }
-
-            // 🔥 企业微信端emoji支持
-            .icon-text {
-              font-size: 16px;
-              line-height: 1;
-              display: inline-block;
-            }
-
-            &:hover:not(:disabled) {
-              border-color: #cbd5e0;
-              background: #f8fafc;
-              color: #475569;
-            }
-
-            &:disabled {
-              opacity: 0.4;
-              cursor: not-allowed;
-            }
-          }
-        }
-      }
-    }
-
-    // 动画
-    @keyframes fadeInUp {
-      from {
-        opacity: 0;
-        transform: translateY(10px);
-      }
-      to {
-        opacity: 1;
-        transform: translateY(0);
-      }
-    }
-
-    @keyframes bounce {
-      0%, 80%, 100% {
-        transform: scale(0);
-      }
-      40% {
-        transform: scale(1);
-      }
-    }
-
-    @keyframes spin {
-      to {
-        transform: rotate(360deg);
-      }
-    }
-
-    // 操作区域
-    .action-section {
-      display: flex;
-      justify-content: center;
-      gap: 12px;
-      margin-top: 24px;
-      flex-wrap: wrap;
-
-      .btn-analyze,
-      .btn-generate {
-        min-width: 180px;
-      }
-
-      .btn-confirm {
-        min-width: 160px;
-      }
-
-      .loading-spinner {
-        display: inline-block;
-        width: 16px;
-        height: 16px;
-        border: 2px solid rgba(255, 255, 255, 0.3);
-        border-top-color: white;
-        border-radius: 50%;
-        animation: spin 0.6s linear infinite;
-        margin-right: 8px;
-      }
-
-      // 🔥 企业微信端优化:确认报告按钮布局
-      &.report-actions {
-        gap: 8px;
-
-        .btn {
-          flex: 1;
-          min-width: 0;
-          max-width: 110px;
-          padding: 10px 8px;
-          font-size: 13px;
-
-          .icon-text {
-            font-size: 16px;
-            margin-right: 4px;
-          }
-
-          span:not(.icon-text):not(.loading-spinner) {
-            white-space: nowrap;
-            overflow: hidden;
-            text-overflow: ellipsis;
-          }
-        }
-      }
-    }
-  }
-
-  // 分析结果区域
-  .analysis-result-section {
-    padding: 24px;
-
-    .result-header {
-      display: flex;
-      align-items: center;
-      gap: 12px;
-      margin-bottom: 24px;
-      padding-bottom: 16px;
-      border-bottom: 2px solid #e5e5e5;
-
-      .header-icon {
-        font-size: 32px;
-      }
-
-      h3 {
-        margin: 0;
-        font-size: 20px;
-        color: #2d3748;
-        font-weight: 600;
-      }
-    }
-
-    .result-card {
-        background: white;
-        border: 1px solid #e2e8f0;
-        border-radius: 12px;
-        padding: 20px;
-        margin-bottom: 16px;
-        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
-        transition: all 0.2s;
-
-        &:hover {
-          box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
-        }
-
-        .card-title {
-          display: flex;
-          align-items: center;
-          gap: 10px;
-          margin-bottom: 16px;
-
-          .title-icon {
-            font-size: 24px;
-          }
-
-          h4 {
-            margin: 0;
-            font-size: 16px;
-            font-weight: 600;
-            color: #2d3748;
-          }
-        }
-
-        .card-content {
-          .info-row,
-          .lighting-row {
-            display: flex;
-            align-items: center;
-            padding: 10px 0;
-            border-bottom: 1px solid #f7fafc;
-
-            &:last-child {
-              border-bottom: none;
-            }
-
-            .label {
-              flex: 0 0 120px;
-              font-weight: 500;
-              color: #4a5568;
-              font-size: 14px;
-            }
-
-            .value {
-              flex: 1;
-              color: #2d3748;
-              font-size: 14px;
-            }
-          }
-
-          .color-item {
-            display: flex;
-            align-items: center;
-            gap: 12px;
-            padding: 12px 0;
-            border-bottom: 1px solid #f7fafc;
-
-            &:last-child {
-              border-bottom: none;
-            }
-
-            .color-preview {
-              width: 40px;
-              height: 40px;
-              border-radius: 8px;
-              border: 2px solid #e2e8f0;
-              flex-shrink: 0;
-            }
-
-            .color-label {
-              flex: 1;
-              font-weight: 500;
-              color: #4a5568;
-              font-size: 14px;
-            }
-
-            .color-value {
-              font-family: 'Courier New', monospace;
-              color: #718096;
-              font-size: 13px;
-            }
-          }
-
-          // 区域分析
-          .region-breakdown {
-            display: grid;
-            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
-            gap: 12px;
-            margin-top: 12px;
-
-            .breakdown-item {
-              display: flex;
-              justify-content: space-between;
-              align-items: center;
-              padding: 12px 16px;
-              background: linear-gradient(135deg, #f0f4ff 0%, #fef5ff 100%);
-              border-radius: 8px;
-              border: 1px solid #e0e7ff;
-
-              .label {
-                font-size: 13px;
-                font-weight: 500;
-                color: #5b21b6;
-              }
-
-              .percentage {
-                font-size: 16px;
-                font-weight: 600;
-                color: #7c3aed;
-              }
-            }
-          }
-
-          // 色彩权重
-          .color-weight-item {
-            padding: 16px;
-            background: linear-gradient(135deg, #fef3f2 0%, #fff7ed 100%);
-            border-radius: 8px;
-            border: 1px solid #fed7d7;
-            margin-bottom: 12px;
-
-            &:last-child {
-              margin-bottom: 0;
-            }
-
-            .color-category {
-              font-size: 15px;
-              font-weight: 600;
-              color: #7c2d12;
-              margin-bottom: 8px;
-            }
-
-            .color-details {
-              display: flex;
-              flex-wrap: wrap;
-              gap: 16px;
-              font-size: 13px;
-
-              .rgb-range,
-              .percentage,
-              .weight {
-                color: #9a3412;
-              }
-
-              .percentage {
-                font-weight: 600;
-              }
-            }
-          }
-        }
-      }
-
-      // 简洁摘要卡片特殊样式
-      &.summary-card {
-        background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
-        border-color: #7dd3fc;
-
-        .summary-text {
-          font-size: 15px;
-          line-height: 1.8;
-          color: #0c4a6e;
-          margin: 0;
-          font-weight: 500;
-        }
-      }
-
-      // 完整分析卡片
-      &.full-analysis-card {
-        .analysis-content {
-          max-height: 600px;
-          overflow-y: auto;
-
-          .analysis-text {
-            font-size: 14px;
-            line-height: 2;
-            color: #1e293b;
-            white-space: pre-wrap;
-            word-wrap: break-word;
-            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
-            margin: 0;
-            padding: 16px;
-            background: #f8fafc;
-            border-radius: 8px;
-          }
-        }
-      }
-
-      // 维度查看卡片
-      &.dimensions-card {
-        .dimensions-grid {
-          display: flex;
-          flex-direction: column;
-          gap: 12px;
-
-          .dimension-item {
-            border: 1px solid #e2e8f0;
-            border-radius: 8px;
-            overflow: hidden;
-            transition: all 0.2s;
-
-            &:hover {
-              border-color: #94a3b8;
-            }
-
-            .dimension-header {
-              display: flex;
-              align-items: center;
-              gap: 12px;
-              padding: 14px 16px;
-              background: #f8fafc;
-              cursor: pointer;
-              transition: background 0.2s;
-
-              &:hover {
-                background: #f1f5f9;
-              }
-
-              .dimension-icon {
-                font-size: 20px;
-              }
-
-              .dimension-title {
-                flex: 1;
-                font-size: 15px;
-                font-weight: 600;
-                color: #334155;
-              }
-
-              .toggle-icon {
-                font-size: 12px;
-                color: #64748b;
-                transition: transform 0.2s;
-              }
-            }
-
-            .dimension-content {
-              padding: 16px;
-              background: white;
-              border-top: 1px solid #e2e8f0;
-
-              p {
-                margin: 0;
-                font-size: 14px;
-                line-height: 1.8;
-                color: #475569;
-                white-space: pre-wrap;
-                word-wrap: break-word;
-              }
-            }
-          }
-        }
-      }
-  }
-
-  // 报告区域
-  .report-section {
-    padding: 24px;
-
-    .report-header {
-      display: flex;
-      align-items: center;
-      gap: 12px;
-      margin-bottom: 24px;
-      padding-bottom: 16px;
-      border-bottom: 2px solid #e5e5e5;
-
-      .header-icon {
-        font-size: 32px;
-      }
-
-      h3 {
-        margin: 0;
-        font-size: 20px;
-        color: #2d3748;
-        font-weight: 600;
-      }
-    }
-
-    .report-content {
-      background: white;
-      border: 1px solid #e2e8f0;
-      border-radius: 12px;
-      padding: 24px;
-      margin-bottom: 24px;
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
-      max-height: 500px;
-      overflow-y: auto;
-
-      .report-text {
-        margin: 0;
-        padding: 0;
-        white-space: pre-wrap;
-        word-wrap: break-word;
-        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
-        font-size: 14px;
-        line-height: 1.8;
-        color: #2d3748;
-        background: transparent;
-        border: none;
-      }
-    }
-  }
-}
-
-// AI按钮样式
-.btn-ai {
-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-  color: white;
-  border: none;
-
-  &:hover {
-    background: linear-gradient(135deg, #5568d3 0%, #6b3f91 100%);
-    box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
-  }
-}
-
-// 响应式设计 - AI分析卡片
-@media (max-width: 768px) {
-  .ai-analysis-card {
-    .space-selector-inline {
-      flex-direction: column;
-      align-items: flex-start;
-      gap: 12px;
-      padding: 12px;
-
-      .space-tabs-inline {
-        width: 100%;
-
-        .space-tab-btn {
-          font-size: 13px;
-          padding: 6px 16px;
-        }
-      }
-    }
-
-    .upload-section,
-    .analysis-result-section,
-    .report-section {
-      padding: 16px;
-    }
-
-    .uploaded-files {
-      grid-template-columns: repeat(2, 1fr);
-      gap: 12px;
-    }
-
-    // AI对话容器响应式(优化移动端显示)
-    .ai-chat-container {
-      height: 600px; // 移动端增大高度,改善显示
-      margin-bottom: 12px;
-
-      .chat-messages-wrapper {
-        padding: 12px; // 移动端减小padding
-
-        .chat-welcome {
-          padding: 20px 16px;
-
-          .welcome-icon {
-            width: 60px;
-            height: 60px;
-            margin-bottom: 16px;
-
-            ion-icon {
-              font-size: 30px;
-            }
-          }
-
-          h3 {
-            font-size: 20px;
-          }
-
-          p {
-            font-size: 14px;
-          }
-
-          .quick-prompts {
-            grid-template-columns: 1fr; // 移动端单列
-            gap: 8px;
-
-            .prompt-chip {
-              padding: 10px 16px;
-              font-size: 13px;
-
-              ion-icon {
-                font-size: 18px;
-              }
-            }
-          }
-        }
-
-        .chat-messages-list {
-          gap: 12px; // 移动端减小间距
-
-          .chat-message {
-            .message-content {
-              max-width: 95%; // 移动端进一步加宽,减少遮挡
-              gap: 8px; // 减小头像和内容间距
-
-              .message-avatar {
-                width: 30px; // 减小头像尺寸
-                height: 30px;
-
-                ion-icon {
-                  font-size: 16px;
-                }
-              }
-
-              .message-bubble {
-                padding: 10px 12px; // 减小padding
-
-                .message-text {
-                  font-size: 13px; // 移动端减小字体
-                  
-                  // 移动端优化标题
-                  h3 {
-                    font-size: 15px;
-                    margin: 10px 0 6px 0;
-                  }
-                  
-                  h4 {
-                    font-size: 14px;
-                    margin: 8px 0 4px 0;
-                  }
-                  
-                  // 移动端表格优化
-                  table {
-                    font-size: 11px;
-                    display: block;
-                    overflow-x: auto;
-                    -webkit-overflow-scrolling: touch;
-                    
-                    th, td {
-                      padding: 4px 6px;
-                      white-space: nowrap;
-                    }
-                  }
-                }
-
-                .message-images {
-                  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
-
-                  img {
-                    height: 100px;
-                  }
-                }
-
-                .message-actions {
-                  flex-wrap: wrap;
-
-                  .action-btn {
-                    padding: 4px 8px;
-                    font-size: 12px;
-
-                    ion-icon {
-                      font-size: 14px;
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-
-      .chat-input-container {
-        padding: 12px 16px;
-
-        .input-wrapper {
-          .chat-input {
-            padding: 12px 14px;
-            font-size: 14px;
-            max-height: 120px;
-          }
-
-          .input-actions {
-            padding: 6px 10px 10px;
-
-            .input-actions-left {
-              gap: 4px;
-
-              .input-action-btn {
-                width: 32px;
-                height: 32px;
-
-                ion-icon {
-                  font-size: 18px;
-                }
-              }
-            }
-
-            .send-btn {
-              width: 36px;
-              height: 36px;
-
-              ion-icon {
-                font-size: 18px;
-              }
-            }
-          }
-        }
-
-        .quick-actions {
-          flex-wrap: wrap;
-          gap: 8px;
-
-          .quick-action-btn {
-            padding: 6px 12px;
-            font-size: 12px;
-
-            ion-icon {
-              font-size: 14px;
-            }
-
-            span {
-              display: none; // 移动端只显示图标
-            }
-          }
-        }
-      }
-    }
-
-    .result-header,
-    .report-header {
-      h3 {
-        font-size: 18px;
-      }
-    }
-
-    .report-content {
-      padding: 12px;
-      
-      .report-text {
-        font-size: 13px;
-      }
-    }
-  }
-}
-
-// 开始AI分析按钮样式
-.start-analysis-wrapper {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  padding: 24px 16px;
-  margin-top: 16px;
-  
-  .btn-start-analysis {
-    position: relative;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    padding: 20px 40px;
-    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-    border: none;
-    border-radius: 16px;
-    color: white;
-    font-size: 16px;
-    font-weight: 600;
-    cursor: pointer;
-    transition: all 0.3s ease;
-    box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
-    overflow: hidden;
-    min-width: 280px;
-    
-    // 发光效果
-    &::before {
-      content: '';
-      position: absolute;
-      top: -50%;
-      left: -50%;
-      width: 200%;
-      height: 200%;
-      background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
-      animation: rotate-glow 3s linear infinite;
-    }
-    
-    ion-icon {
-      font-size: 32px;
-      margin-bottom: 8px;
-      filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
-      position: relative;
-      z-index: 1;
-    }
-    
-    // 🔥 企业微信端emoji支持
-    .icon-text {
-      font-size: 32px;
-      line-height: 1;
-      display: inline-block;
-      margin-bottom: 8px;
-      filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
-      position: relative;
-      z-index: 1;
-    }
-    
-    span {
-      position: relative;
-      z-index: 1;
-      text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
-      letter-spacing: 0.5px;
-    }
-    
-    .btn-hint {
-      position: relative;
-      z-index: 1;
-      font-size: 12px;
-      font-weight: 400;
-      margin-top: 6px;
-      opacity: 0.9;
-      color: rgba(255, 255, 255, 0.95);
-    }
-    
-    &:hover {
-      transform: translateY(-2px);
-      box-shadow: 0 12px 28px rgba(102, 126, 234, 0.4);
-      background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
-    }
-    
-    &:active {
-      transform: translateY(0);
-      box-shadow: 0 6px 16px rgba(102, 126, 234, 0.3);
-    }
-    
-    &:disabled {
-      opacity: 0.6;
-      cursor: not-allowed;
-      transform: none;
-    }
-  }
-}
-
-@keyframes rotate-glow {
-  0% {
-    transform: rotate(0deg);
-  }
-  100% {
-    transform: rotate(360deg);
-  }
-}
-
-// 导出Word按钮样式
-.btn-export {
-  background: linear-gradient(135deg, #1e88e5 0%, #1976d2 100%);
-  color: white;
-  border: none;
-  padding: 12px 24px;
-  border-radius: 8px;
-  font-size: 14px;
-  font-weight: 500;
-  cursor: pointer;
-  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-  box-shadow: 0 4px 12px rgba(30, 136, 229, 0.25);
-  display: inline-flex;
-  align-items: center;
-  gap: 8px;
-  
-  .icon-text {
-    font-size: 16px;
-    line-height: 1;
-  }
-  
-  .loading-spinner {
-    width: 14px;
-    height: 14px;
-    border: 2px solid rgba(255, 255, 255, 0.3);
-    border-top-color: white;
-    border-radius: 50%;
-    animation: spin 0.6s linear infinite;
-  }
-  
-  &:hover:not(:disabled) {
-    background: linear-gradient(135deg, #1976d2 0%, #1565c0 100%);
-    transform: translateY(-2px);
-    box-shadow: 0 6px 16px rgba(30, 136, 229, 0.35);
-  }
-  
-  &:active:not(:disabled) {
-    transform: translateY(0);
-    box-shadow: 0 2px 8px rgba(30, 136, 229, 0.3);
-  }
-  
-  &:disabled {
-    opacity: 0.6;
-    cursor: not-allowed;
-    transform: none;
-  }
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
-// 🔥 快速总结卡片样式
-.quick-summary-card {
-  background: linear-gradient(135deg, #fff8e1 0%, #ffffff 100%);
-  border-left: 4px solid #ff9800;
-  margin-bottom: 24px;
-  box-shadow: 0 2px 12px rgba(255, 152, 0, 0.1);
-  
-  .card-title {
-    display: flex;
-    align-items: center;
-    gap: 8px;
-    padding: 16px 20px;
-    border-bottom: 1px solid #ffe0b2;
-    background: rgba(255, 152, 0, 0.05);
-    
-    .title-icon {
-      font-size: 20px;
-    }
-    
-    h4 {
-      margin: 0;
-      font-size: 16px;
-      font-weight: 600;
-      color: #e65100;
-    }
-  }
-  
-  .quick-summary-content {
-    padding: 20px;
-    display: flex;
-    flex-direction: column;
-    gap: 16px;
-    
-    .summary-item {
-      display: flex;
-      flex-direction: column;
-      gap: 8px;
-      padding: 12px;
-      background: white;
-      border-radius: 8px;
-      box-shadow: 0 1px 3px rgba(0,0,0,0.05);
-      transition: all 0.3s ease;
-      
-      &:hover {
-        box-shadow: 0 2px 8px rgba(0,0,0,0.1);
-        transform: translateX(2px);
-      }
-      
-      .summary-label {
-        display: flex;
-        align-items: center;
-        gap: 6px;
-        font-size: 13px;
-        font-weight: 600;
-        color: #666;
-        
-        .label-icon {
-          font-size: 16px;
-        }
-        
-        .label-text {
-          letter-spacing: 0.5px;
-        }
-      }
-      
-      .summary-value {
-        font-size: 15px;
-        line-height: 1.6;
-        color: #333;
-        font-weight: 500;
-        padding-left: 22px;
-        
-        &.color-tone {
-          color: #d84315;
-          font-weight: 600;
-        }
-        
-        &.materials {
-          color: #5d4037;
-        }
-        
-        &.atmosphere {
-          color: #1976d2;
-        }
-      }
     }
   }
 }
-
-// 移动端适配
-@media (max-width: 768px) {
-  .quick-summary-card {
-    .quick-summary-content {
-      padding: 16px;
-      gap: 12px;
-      
-      .summary-item {
-        padding: 10px;
-        
-        .summary-value {
-          font-size: 14px;
-          padding-left: 20px;
-        }
-      }
-    }
-  }
-  
-  .start-analysis-wrapper {
-    padding: 16px 12px;
-    
-    .btn-start-analysis {
-      min-width: 240px;
-      padding: 16px 32px;
-      
-      ion-icon {
-        font-size: 28px;
-      }
-      
-      span {
-        font-size: 15px;
-      }
-      
-      .btn-hint {
-        font-size: 11px;
-      }
-    }
-  }
-}

+ 174 - 4601
src/modules/project/pages/project-detail/stages/stage-requirements.component.ts

@@ -1,34 +1,33 @@
-import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ElementRef } from '@angular/core';
+import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { ActivatedRoute } from '@angular/router';
-import { WxworkAuth, FmodeParse, NovaStorage } from 'fmode-ng/core';
+import { WxworkAuth, FmodeParse } from 'fmode-ng/core';
 import { IonIcon } from '@ionic/angular/standalone';
 import { MatDialog } from '@angular/material/dialog';
 import { ProductSpaceService, Project } from '../../../services/product-space.service';
 import { ProjectFileService } from '../../../services/project-file.service';
 import { DesignAnalysisAIService } from '../../../services/design-analysis-ai.service';
-import { ColorGetDialogComponent } from '../../../components/color-get/color-get-dialog.component';
-import { completionJSON } from 'fmode-ng/core';
 import { addIcons } from 'ionicons';
 import { add, chevronDown, colorPalette, send, sparkles, trash } from 'ionicons/icons';
-import { generatePhaseDeadlines } from '../../../../../app/utils/phase-deadline.utils';
-import { addDays, normalizeDateInput } from '../../../../../app/utils/date-utils';
-
-// 初始化Parse对象
-const Parse = FmodeParse.with('nova');
+import { AiDesignAnalysisComponent } from './components/ai-design-analysis/ai-design-analysis.component';
+import { SpaceRequirementItemComponent } from './components/space-requirement-item/space-requirement-item.component';
 
 addIcons({
   add,sparkles,colorPalette,trash,chevronDown,send
 })
-/**
- * 确认需求阶段组件 - Product表统一空间管理
- */
+
 @Component({
   selector: 'app-stage-requirements',
   standalone: true,
-  imports: [CommonModule, FormsModule, ReactiveFormsModule, IonIcon],
-  providers: [],
+  imports: [
+    CommonModule, 
+    FormsModule, 
+    ReactiveFormsModule, 
+    IonIcon,
+    AiDesignAnalysisComponent,
+    SpaceRequirementItemComponent
+  ],
   templateUrl: './stage-requirements.component.html',
   styleUrls: ['./stage-requirements.component.scss'],
   changeDetection: ChangeDetectionStrategy.OnPush
@@ -39,91 +38,31 @@ export class StageRequirementsComponent implements OnInit, OnDestroy {
   @Input() currentUser: any = null;
   @Input() canEdit: boolean = true;
 
-  // 路由参数
   cid: string = '';
   projectId: string = '';
 
-  // Product-based 空间管理
   projectProducts: Project[] = [];
   isMultiProductProject: boolean = false;
   activeProductId: string = '';
-  selectedProductIds: string[] = [];
-
-  // 需求分段管理
-  requirementsSegment: string = 'global'; // global | spaces | cross-space
-
-  // 产品更新事件监听器
+  
   private productUpdateListener: any = null;
-
-  // 空间折叠状态管理
   expandedSpaces: Set<string> = new Set();
-
-  // 空间特殊需求数据
   spaceSpecialRequirements: { [spaceId: string]: string } = {};
-
-  // 图片类型定义
-  imageTypes = [
-    { id: 'all', name: '全部' },
-    { id: 'soft_decor', name: '软装' },
-    { id: 'hard_decor', name: '硬装' },
-    { id: 'cad', name: 'CAD' },
-    { id: 'other', name: '其他' }
-  ];
-
-  // 当前选中的图片类型标签(按空间ID)
-  activeImageTab: { [spaceId: string]: string } = {};
-
-  // 拖拽相关
-  isDragOver: boolean = false;
-  dragOverSpaceId: string = '';
-
-  // AI分析结果存储(按空间ID)
   analysisResultsBySpace: { [spaceId: string]: any[] } = {};
 
-  // 全局需求
-  globalRequirements = {
-    stylePreference: '',
-    colorScheme: {
-      primary: '',
-      secondary: '',
-      accent: '',
-      atmosphere: ''
-    },
-    overallBudget: {
-      min: 0,
-      max: 0
-    },
-    timeline: '',
-    qualityLevel: 'standard', // standard | premium | luxury
-    specialRequirements: '',
-    environmentRequirements: {
-      lighting: '',
-      ventilation: '',
-      noise: '',
-      temperature: ''
-    }
-  };
-
-  // 空间需求数据
-  spaceRequirements: any[] = [];
-
-  // 跨空间需求
-  crossSpaceRequirements: any[] = [];
-
-  // 参考图片(支持按空间分类)
+  // File Data
   referenceImages: Array<{
     id: string;
     url: string;
     name: string;
-    type: string; // style | space | material
+    type: string;
     uploadTime: Date;
     description?: string;
     spaceId?: string;
     tags: string[];
-    projectFile?: any; // ProjectFile对象引用
+    projectFile?: any;
   }> = [];
 
-  // CAD文件
   cadFiles: Array<{
     id: string;
     url: string;
@@ -131,123 +70,16 @@ export class StageRequirementsComponent implements OnInit, OnDestroy {
     uploadTime: Date;
     size: number;
     spaceId?: string;
-    projectFile?: any; // ProjectFile对象引用
-  }> = [];
-
-  // AI生成的方案
-  aiSolution: {
-    generated: boolean;
-    content: string;
-    spaces: Array<{
-      id: string;
-      name: string;
-      type: string;
-      styleDescription: string;
-      colorPalette: string[];
-      materials: string[];
-      furnitureRecommendations: string[];
-      estimatedCost?: number;
-      timeline?: string;
-    }>;
-    estimatedCost: number;
-    timeline: string;
-    crossSpaceCoordination?: {
-      styleConsistency: {
-        description: string;
-        keyElements: string[];
-      };
-      functionalFlow: {
-        description: string;
-        considerations: string[];
-      };
-      timelineCoordination: {
-        description: string;
-        strategy: string;
-      };
-    };
-  } | null = null;
-
-  // AI分析相关数据
-  aiAnalysisResults: {
-    imageAnalysis?: Array<{
-      imageId: string;
-      styleElements: string[];
-      colorPalette: string[];
-      materialAnalysis: string[];
-      layoutFeatures: string[];
-      mood: string;
-      confidence: number;
-    }>;
-    cadAnalysis?: Array<{
-      fileId: string;
-      spaceStructure: any;
-      dimensions: any;
-      constraints: string[];
-      opportunities: string[];
-    }>;
-    comprehensiveAnalysis?: {
-      overallStyle: string;
-      colorScheme: any;
-      materialRecommendations: string[];
-      layoutOptimization: string[];
-      budgetAssessment: any;
-      timeline: string;
-      riskFactors: string[];
-    };
-  } = {};
-
-  // AI设计分析对话相关
-  showAIDesignDialog: boolean = false;
-  aiDesignDialogVisible = false;
-  aiDesignUploading: boolean = false;
-  aiDesignCurrentSpace: any = null;
-  aiDesignUploadedImages: string[] = [];
-  aiDesignUploadedFiles: any[] = []; // 存储文件信息(类型、名称等)
-  aiDesignTextDescription = '';
-  aiDesignAnalyzing = false;
-  aiDesignAnalysisResult: any = null;
-  aiDesignGeneratingReport = false;
-  aiDesignReport = '';
-  aiDesignReportConfirmed = false;
-  aiDesignDragOver = false; // 拖拽状态
-  exportingWord = false; // 导出Word状态
-  
-  // AI对话系统
-  aiChatMessages: Array<{
-    id: string;
-    role: 'user' | 'assistant';
-    content: string;
-    timestamp: Date;
-    images?: string[];
-    isLoading?: boolean;
-    isStreaming?: boolean; // 流式输出中
-    liked?: boolean;
-    disliked?: boolean;
+    projectFile?: any;
   }> = [];
-  aiChatInput: string = '';
-  deepThinkingEnabled: boolean = false;
-  expandedDimensions: Set<string> = new Set(); // 管理维度折叠状态
-  @ViewChild('chatMessagesWrapper') chatMessagesWrapper!: ElementRef;
-  @ViewChild('chatInput') chatInputElement!: ElementRef;
-  
-  // AI分析状态
-  aiAnalyzing: boolean = false;
-  aiAnalyzingImages: boolean = false;
-  aiAnalyzingCAD: boolean = false;
-  aiGeneratingComprehensive: boolean = false;
-  showAIChat: boolean = false;
 
-  // AI分析配置
-  private readonly AI_MODEL = 'fmode-1.6-cn';
+  // AI Analysis Data
+  aiAnalysisResults: any = {};
 
-  // 加载状态
   loading: boolean = true;
   uploading: boolean = false;
-  generating: boolean = false;
-  saving: boolean = false;
 
-  // 模板引用变量
-  @ViewChild('chatMessages') chatMessagesContainer!: ElementRef;
+  @ViewChild(AiDesignAnalysisComponent) aiDesignComponent!: AiDesignAnalysisComponent;
 
   constructor(
     private route: ActivatedRoute,
@@ -259,145 +91,67 @@ export class StageRequirementsComponent implements OnInit, OnDestroy {
   ) {}
 
   async ngOnInit() {
-    console.log('🚀 [确认需求] ngOnInit 开始');
-    
-    // 从父路由获取参数
     this.cid = this.route.parent?.snapshot.paramMap.get('cid') || this.cid;
     this.projectId = this.route.parent?.snapshot.paramMap.get('projectId') || this.projectId;
 
-    console.log('📋 [确认需求] 路由参数获取结果:', {
-      cid: this.cid,
-      projectId: this.projectId,
-      '有cid': !!this.cid,
-      '有projectId': !!this.projectId,
-      '完整路由': window.location.pathname
-    });
-
-    // 若无当前用户,从企业微信获取并计算权限
     try {
       if (!this.currentUser && this.cid) {
-        console.log('🔑 [确认需求] 开始获取当前用户...');
         const wx = new WxworkAuth({ cid: this.cid, appId: 'crm' });
         this.currentUser = await wx.currentProfile();
-        console.log('✅ [确认需求] 当前用户获取成功:', this.currentUser?.get?.('name'));
       }
       
       const role = this.currentUser?.get?.('roleName') || '';
-      
-      console.log('🔍 确认需求阶段权限检查:', {
-        '当前用户': this.currentUser?.get?.('name') || 'Unknown',
-        '用户角色': role,
-        '有currentUser': !!this.currentUser,
-        '原始canEdit': this.canEdit,
-        'cid': this.cid,
-        'projectId': this.projectId
-      });
-      
-      // 🔥 关键修复:只有当成功获取到用户且角色有效时,才覆盖canEdit
       if (this.currentUser && role) {
         const calculatedCanEdit = ['客服', '组员', '组长', '管理员', '设计师', '客服主管'].includes(role);
         this.canEdit = calculatedCanEdit;
-        console.log('✅ 根据角色计算canEdit:', calculatedCanEdit, '角色:', role);
-      } else {
-        // 如果没有用户信息或角色为空,保留默认值true
-        console.log('⚠️ 未获取到用户角色,保留默认canEdit:', this.canEdit);
       }
-      
-      console.log('✅ 最终canEdit值:', this.canEdit);
     } catch (e) {
-      console.error('权限检查失败,保留默认canEdit:', this.canEdit, e);
+      console.error('权限检查失败', e);
     }
 
     await this.loadData();
-    
-    // 监听产品更新事件
     this.setupProductUpdateListener();
-    
-    console.log('🏁 [确认需求] ngOnInit 完成,最终状态:', {
-      'this.project': !!this.project,
-      'this.currentUser': !!this.currentUser,
-      'this.canEdit': this.canEdit,
-      'projectId': this.project?.id
-    });
   }
 
-  /**
-   * 🔥 设置产品更新监听器
-   */
   private setupProductUpdateListener(): void {
     this.productUpdateListener = (event: any) => {
       const detail = event.detail || {};
       if (detail.projectId === this.projectId) {
-        console.log(`🔄 [确认需求] 检测到产品${detail.action === 'add' ? '添加' : detail.action === 'edit' ? '编辑' : '删除'}事件,重新加载空间...`);
         this.loadData();
       }
     };
-    
     document.addEventListener('product-spaces-updated', this.productUpdateListener);
-    console.log('✅ [确认需求] 已设置产品更新监听器');
   }
 
-  /**
-   * 组件销毁时清理监听器
-   */
   ngOnDestroy(): void {
     if (this.productUpdateListener) {
       document.removeEventListener('product-spaces-updated', this.productUpdateListener);
-      console.log('🧹 [确认需求] 已清理产品更新监听器');
     }
   }
 
-  /**
-   * 加载数据
-   */
   async loadData() {
-    console.log('📦 [确认需求] loadData 开始');
     try {
       this.loading = true;
 
-      // 🔥 关键修复:如果没有project对象,从projectId加载(参考售后归档组件)
       if (!this.project && this.projectId) {
-        console.log('📥 [确认需求] 从projectId加载项目信息...');
         const Parse = FmodeParse.with('nova');
         const query = new Parse.Query('Project');
         query.include('contact', 'assignee', 'department');
         try {
           this.project = await query.get(this.projectId);
-          console.log('✅ [确认需求] 项目信息加载成功:', {
-            projectId: this.project.id,
-            name: this.project.get('name'),
-            currentStage: this.project.get('currentStage')
-          });
-        } catch (error) {
-          console.error('❌ [确认需求] 加载项目失败:', error);
+        } catch (error: any) {
+          console.error('加载项目失败:', error);
           window?.fmode?.alert('加载项目失败: ' + (error.message || '未知错误'));
           return;
         }
       }
       
-      if (!this.project) {
-        console.warn('⚠️ [确认需求] 项目对象为空,无法加载数据');
-        return;
-      }
+      if (!this.project) return;
       
-      console.log('✅ [确认需求] 项目对象已准备好:', {
-        projectId: this.project.id,
-        name: this.project.get?.('name'),
-        currentStage: this.project.get?.('currentStage')
-      });
-
-      // ✅ 使用统一空间管理加载Product数据
       const projectId = this.projectId || this.project?.id || '';
       if (projectId) {
-        console.log('🔄 [需求确认] 开始加载项目空间...');
-        
-        // 从统一存储获取空间数据
         const unifiedSpaces = await this.productSpaceService.getUnifiedSpaceData(projectId);
-        
         if (unifiedSpaces.length > 0) {
-          console.log(`✅ [需求确认] 从统一存储加载到 ${unifiedSpaces.length} 个空间`);
-          
-          // 转换为组件使用的格式
           this.projectProducts = unifiedSpaces.map(space => ({
             id: space.id,
             name: space.name,
@@ -415,77 +169,31 @@ export class StageRequirementsComponent implements OnInit, OnDestroy {
             designerId: space.designerId
           }));
         } else {
-          console.log('⚠️ [需求确认] 没有找到统一空间数据,尝试从Product表加载...');
           this.projectProducts = await this.productSpaceService.getProjectProductSpaces(projectId);
         }
-        
-        console.log(`✅ [需求确认] 空间加载完成,共 ${this.projectProducts.length} 个空间`);
       }
 
-      // 防御性去重:避免同名空间重复展示
       this.projectProducts = this.projectProducts.filter((p, idx, arr) => {
         const key = (p.name || '').trim().toLowerCase();
         return arr.findIndex(x => (x.name || '').trim().toLowerCase() === key) === idx;
       });
       this.isMultiProductProject = this.projectProducts.length > 1;
 
-      // 如果有产品,默认选中第一个
       if (this.projectProducts.length > 0 && !this.activeProductId) {
         this.activeProductId = this.projectProducts[0].id;
       }
 
-      // 初始化每个空间的图片标签为"全部"
       for (const product of this.projectProducts) {
-        if (!this.activeImageTab[product.id]) {
-          this.activeImageTab[product.id] = 'all';
-        }
-        // 初始化空间特殊需求(从项目数据中加载或使用默认值)
         if (!this.spaceSpecialRequirements[product.id]) {
           const projectData = this.project?.get('data') || {};
           const spaceRequirements = projectData.spaceRequirements || {};
           this.spaceSpecialRequirements[product.id] = spaceRequirements[product.id] || '';
-          
-          // 如果没有数据,添加示例数据用于测试
-          if (!this.spaceSpecialRequirements[product.id]) {
-            const spaceName = product.name || '空间';
-            this.spaceSpecialRequirements[product.id] = `${spaceName}需要充足的储物空间,采用现代简约风格`;
-          }
         }
       }
 
-      // 模拟加载需求数据
-      this.globalRequirements = {
-        stylePreference: '现代简约',
-        colorScheme: {
-          primary: '#ffffff',
-          secondary: '#f5f5f5',
-          accent: '#3880ff',
-          atmosphere: '温馨'
-        },
-        overallBudget: { min: 15, max: 25 },
-        timeline: '45天',
-        qualityLevel: 'premium',
-        specialRequirements: '需要充足的储物空间',
-        environmentRequirements: {
-          lighting: '明亮自然',
-          ventilation: '良好通风',
-          noise: '隔音处理',
-          temperature: '恒温控制'
-        }
-      };
-
-      // 加载已上传的文件(参考图片和CAD文件)
       await this.loadProjectFiles();
-
-      // 加载已保存的AI分析结果
       await this.loadAnalysisResults();
-
-      // 自动选择第一个空间用于AI分析
-      if (this.projectProducts.length > 0 && !this.aiDesignCurrentSpace) {
-        this.aiDesignCurrentSpace = this.projectProducts[0];
-        console.log('✨ 自动选择第一个空间用于AI分析:', this.aiDesignCurrentSpace.name);
-      }
-
+      
       this.cdr.markForCheck();
 
     } catch (err) {
@@ -495,289 +203,164 @@ export class StageRequirementsComponent implements OnInit, OnDestroy {
     }
   }
 
-  // ===== 多空间需求管理方法 =====
-
-  /**
-   * 切换需求分段
-   */
-  onRequirementsSegmentChange(event: any): void {
-    this.requirementsSegment = event.detail.value;
-    this.cdr.markForCheck();
+  async loadProjectFiles() {
+    try {
+       const projectId = this.projectId || this.project?.id;
+       if (!projectId) return;
+       
+       const files = await this.projectFileService.getProjectFiles(projectId);
+       
+       this.referenceImages = [];
+       this.cadFiles = [];
+       
+       files.forEach((file: any) => {
+         const type = file.get('type');
+         const spaceId = file.get('spaceId');
+         const metadata = file.get('metadata') || {};
+         
+         if (type === 'reference_image' || metadata.uploadedFor === 'requirements_analysis') {
+            this.referenceImages.push({
+               id: file.id,
+               url: file.get('fileUrl'),
+               name: file.get('fileName'),
+               type: metadata.imageType || 'other',
+               uploadTime: file.createdAt,
+               spaceId: spaceId,
+               tags: metadata.tags || [],
+               projectFile: file
+            });
+         } else if (type === 'cad_file' || metadata.uploadedFor === 'requirements_cad') {
+            this.cadFiles.push({
+               id: file.id,
+               url: file.get('fileUrl'),
+               name: file.get('fileName'),
+               uploadTime: file.createdAt,
+               size: 0,
+               spaceId: spaceId,
+               projectFile: file
+            });
+         }
+       });
+       
+    } catch (e) {
+       console.error('Failed to load files', e);
+    }
   }
-
-  /**
-   * 选择需求分段
-   */
-  selectRequirementsSegment(segment: string): void {
-    this.requirementsSegment = segment;
-    this.cdr.markForCheck();
+  
+  async loadAnalysisResults() {
+    const projectData = this.project?.get('data') || {};
+    if (projectData.requirementsAnalysis) {
+      Object.keys(projectData.requirementsAnalysis).forEach(spaceId => {
+        this.analysisResultsBySpace[spaceId] = projectData.requirementsAnalysis[spaceId].analysisResults || [];
+      });
+    }
   }
 
-  /**
-   * 选择产品空间
-   */
-  selectProduct(productId: string): void {
-    this.activeProductId = productId;
-    this.cdr.markForCheck();
+  // Space List Helpers
+  getSpaceReferenceImages(spaceId: string): any[] {
+    return this.referenceImages.filter(img => img.spaceId === spaceId);
   }
 
-  /**
-   * 切换产品选择状态
-   */
-  toggleProductSelection(productId: string): void {
-    const index = this.selectedProductIds.indexOf(productId);
-    if (index > -1) {
-      this.selectedProductIds.splice(index, 1);
-    } else {
-      this.selectedProductIds.push(productId);
-    }
-    this.cdr.markForCheck();
+  getSpaceCADFiles(spaceId: string): any[] {
+    return this.cadFiles.filter(file => file.spaceId === spaceId);
   }
-
-  /**
-   * 选择图片类型标签
-   */
-  selectImageTab(spaceId: string, tabId: string): void {
-    this.activeImageTab[spaceId] = tabId;
-    this.cdr.markForCheck();
+  
+  getSpaceAnalysisResults(spaceId: string): any[] {
+    return this.analysisResultsBySpace[spaceId] || [];
   }
 
-  /**
-   * 获取空间的总文件数(图片+CAD)
-   */
-  getTotalSpaceFileCount(spaceId: string): number {
-    const imageCount = this.getSpaceReferenceImages(spaceId).length;
-    const cadCount = this.getSpaceCADFiles(spaceId).length;
-    return imageCount + cadCount;
+  isSpaceExpanded(spaceId: string): boolean {
+    return this.expandedSpaces.has(spaceId);
   }
 
-  /**
-   * 获取指定空间和类型的图片数量
-   */
-  getImageCountByType(spaceId: string, typeId: string): number {
-    if (typeId === 'all') {
-      return this.getSpaceReferenceImages(spaceId).length;
-    } else if (typeId === 'cad') {
-      return this.getSpaceCADFiles(spaceId).length;
+  toggleSpaceExpansion(spaceId: string) {
+    if (this.expandedSpaces.has(spaceId)) {
+      this.expandedSpaces.delete(spaceId);
     } else {
-      return this.getImagesByType(spaceId, typeId).length;
+      this.expandedSpaces.add(spaceId);
     }
   }
 
-  /**
-   * 按类型获取图片
-   */
-  getImagesByType(spaceId: string, type: string): any[] {
-    return this.getSpaceReferenceImages(spaceId).filter(img => img.type === type);
-  }
-
-  /**
-   * 获取图片类型标签文本
-   */
-  getImageTypeLabel(type: string): string {
-    const typeMap: { [key: string]: string } = {
-      'all': '全部',
-      'soft_decor': '软装',
-      'hard_decor': '硬装',
-      'cad': 'CAD',
-      'other': '其他',
-      'style': '风格',
-      'space': '空间',
-      'material': '材质'
-    };
-    return typeMap[type] || type;
-  }
-
-  /**
-   * 获取图片类型徽章样式类
-   */
-  getImageTypeBadgeClass(type: string): string {
-    const classMap: { [key: string]: string } = {
-      'soft_decor': 'badge-soft-decor',
-      'hard_decor': 'badge-hard-decor',
-      'other': 'badge-other',
-      'style': 'badge-style',
-      'space': 'badge-space',
-      'material': 'badge-material'
-    };
-    return classMap[type] || 'badge-default';
+  // Event Handlers from Children
+  onAnalysisComplete(result: any) {
+    console.log('AI Analysis Complete', result);
+    this.loadData();
   }
 
-  /**
-   * 拖拽悬停处理
-   */
-  onDragOver(event: DragEvent, spaceId: string): void {
-    event.preventDefault();
-    event.stopPropagation();
-    this.isDragOver = true;
-    this.dragOverSpaceId = spaceId;
+  async handleUploadImages(event: {spaceId: string, files: File[], type?: string}) {
+    console.log('Upload Images', event);
+    await this.uploadAndAnalyzeImages(event.files, event.spaceId, event.type);
   }
 
-  /**
-   * 拖拽离开处理
-   */
-  onDragLeave(event: DragEvent): void {
-    event.preventDefault();
-    event.stopPropagation();
-    this.isDragOver = false;
-    this.dragOverSpaceId = '';
+  async handleUploadCAD(event: {spaceId: string, files: File[]}) {
+    console.log('Upload CAD', event);
+    await this.uploadCADFiles(event.files, event.spaceId);
   }
 
-  /**
-   * 拖拽放下处理
-   */
-  async onDrop(event: DragEvent, spaceId: string): Promise<void> {
-    event.preventDefault();
-    event.stopPropagation();
-    this.isDragOver = false;
-    this.dragOverSpaceId = '';
-
-    const files = event.dataTransfer?.files;
-    if (!files || files.length === 0) return;
-
-    // 分类处理拖拽的文件
-    const imageFiles: File[] = [];
-    const cadFiles: File[] = [];
-    
-    for (let i = 0; i < files.length; i++) {
-      const file = files[i];
-      const fileName = file.name.toLowerCase();
-      
-      // 识别图片文件
-      if (file.type.startsWith('image/')) {
-        imageFiles.push(file);
-      }
-      // 识别CAD文件
-      else if (this.isCADFile(file, fileName)) {
-        cadFiles.push(file);
-      }
-    }
-
-    // 上传图片并进行AI分析
-    if (imageFiles.length > 0) {
-      await this.uploadAndAnalyzeImages(imageFiles, spaceId);
+  async handleDeleteImage(imageId: string) {
+    if (!confirm('确定要删除这张参考图片吗?')) return;
+    try {
+      await this.projectFileService.deleteProjectFile(imageId);
+      this.referenceImages = this.referenceImages.filter(img => img.id !== imageId);
+      this.cdr.markForCheck();
+    } catch (e) {
+      console.error('删除失败', e);
+      window?.fmode?.alert('删除失败');
     }
+  }
 
-    // 上传CAD文件
-    if (cadFiles.length > 0) {
-      await this.uploadCADFiles(cadFiles, spaceId);
+  async handleDeleteCAD(fileId: string) {
+    if (!confirm('确定要删除这个CAD文件吗?')) return;
+    try {
+      await this.projectFileService.deleteProjectFile(fileId);
+      this.cadFiles = this.cadFiles.filter(f => f.id !== fileId);
+      this.cdr.markForCheck();
+    } catch (e) {
+       console.error('删除失败', e);
+       window?.fmode?.alert('删除失败');
     }
-
-    this.cdr.markForCheck();
   }
 
-  /**
-   * 判断是否为CAD文件
-   */
-  private isCADFile(file: File, fileName: string): boolean {
-    const cadExtensions = ['.dwg', '.dxf', '.rvt', '.ifc', '.step', '.stp', '.iges', '.igs', '.pdf'];
-    const cadMimeTypes = [
-      'application/vnd.autodesk.autocad.drawing',
-      'application/vnd.autodesk.autocad.drawing.macroenabled',
-      'application/pdf',
-      'application/x-pdf'
-    ];
-    
-    // 检查文件扩展名
-    const hasCADExtension = cadExtensions.some(ext => fileName.endsWith(ext));
-    
-    // 检查MIME类型
-    const hasCADMimeType = cadMimeTypes.includes(file.type);
-    
-    return hasCADExtension || hasCADMimeType;
+  handleSpecialRequirementsChange(event: {spaceId: string, content: string}) {
+    this.spaceSpecialRequirements[event.spaceId] = event.content;
+    this.saveSpaceRequirements(event.spaceId, event.content);
+  }
+  
+  async saveSpaceRequirements(spaceId: string, content: string) {
+     try {
+        const projectData = this.project.get('data') || {};
+        if (!projectData.spaceRequirements) projectData.spaceRequirements = {};
+        projectData.spaceRequirements[spaceId] = content;
+        this.project.set('data', projectData);
+        await this.project.save();
+     } catch (e) {
+        console.error('保存需求备注失败', e);
+     }
   }
 
-  /**
-   * 上传CAD文件
-   */
-  async uploadCADFiles(files: File[], spaceId: string): Promise<void> {
-    try {
-      this.uploading = true;
-      const targetProjectId = this.projectId || this.project?.id;
-
-      if (!targetProjectId) {
-        console.error('未找到项目ID,无法上传文件');
-        return;
-      }
-
-      for (const file of files) {
-        // 文件大小验证 (50MB for CAD)
-        if (file.size > 50 * 1024 * 1024) {
-          console.warn(`CAD文件 ${file.name} 超过50MB限制,跳过`);
-          continue;
-        }
-
-        try {
-          // 上传CAD文件
-          const projectFile = await this.projectFileService.uploadProjectFileWithRecord(
-            file,
-            targetProjectId,
-            'cad_file',
-            spaceId,
-            'requirements',
-            {
-              uploadedFor: 'requirements_cad',
-              spaceId: spaceId,
-              uploadStage: 'requirements'
-            },
-            (progress) => {
-              console.log(`CAD文件上传进度: ${progress}%`);
-            }
-          );
-
-          // 创建CAD文件记录
-          const uploadedCAD = {
-            id: projectFile.id || '',
-            url: projectFile.get('fileUrl') || '',
-            name: projectFile.get('fileName') || file.name,
-            uploadTime: projectFile.createdAt || new Date(),
-            spaceId: spaceId,
-            size: file.size,
-            projectFile: projectFile
-          };
+  handleViewAnalysis(imageId: string) {
+    console.log('View Analysis for', imageId);
+    window?.fmode?.toast('查看分析详情功能开发中');
+  }
 
-          if (uploadedCAD.id) {
-            this.cadFiles.push(uploadedCAD);
-            console.log(`✅ CAD文件上传成功: ${uploadedCAD.name}`);
-            
-            // 对CAD文件进行AI分析
-            await this.analyzeCADFileWithAI(uploadedCAD, spaceId);
-          }
-        } catch (error) {
-          console.error(`CAD文件上传失败: ${file.name}`, error);
-        }
+  openAIDialog(space: any) {
+    if (this.aiDesignComponent) {
+      // Scroll to component
+      const element = (this.aiDesignComponent as any).elementRef?.nativeElement || document.querySelector('app-ai-design-analysis');
+      if (element) {
+        element.scrollIntoView({ behavior: 'smooth' });
       }
-
-      this.cdr.markForCheck();
-    } catch (error) {
-      console.error('CAD文件上传失败:', error);
-      window?.fmode?.alert('CAD文件上传失败,请重试');
-    } finally {
-      this.uploading = false;
+      // Select the space in AI component
+      this.aiDesignComponent.selectAISpace(space);
     }
   }
+  
+  async uploadAndAnalyzeImages(files: File[], spaceId: string, type: string = 'other'): Promise<void> {
+    this.uploading = true;
+    const targetProjectId = this.projectId || this.project?.id;
 
-  /**
-   * 上传并分析图片
-   */
-  async uploadAndAnalyzeImages(files: File[], spaceId: string): Promise<void> {
     try {
-      this.uploading = true;
-      const targetProjectId = this.projectId || this.project?.id;
-
-      if (!targetProjectId) {
-        console.error('未找到项目ID,无法上传文件');
-        return;
-      }
-
       for (const file of files) {
-        // 文件大小验证 (10MB)
-        if (file.size > 10 * 1024 * 1024) {
-          console.warn(`文件 ${file.name} 超过10MB限制,跳过`);
-          continue;
-        }
-
-        // 上传文件
         const projectFile = await this.projectFileService.uploadProjectFileWithRecord(
           file,
           targetProjectId,
@@ -787,4074 +370,64 @@ export class StageRequirementsComponent implements OnInit, OnDestroy {
           {
             uploadedFor: 'requirements_analysis',
             spaceId: spaceId,
-            uploadStage: 'requirements'
-          },
-          (progress) => {
-            console.log(`上传进度: ${progress}%`);
+            imageType: type
           }
         );
 
-        // 创建参考图片记录
-        const uploadedFile = {
+        this.referenceImages.push({
           id: projectFile.id || '',
           url: projectFile.get('fileUrl') || '',
           name: projectFile.get('fileName') || file.name,
-          type: 'other', // 默认类型,AI分析后会更新
+          type: type, 
           uploadTime: projectFile.createdAt || new Date(),
           spaceId: spaceId,
           tags: [],
           projectFile: projectFile
-        };
-
-        if (uploadedFile.id) {
-          this.analysisImageMap[uploadedFile.id] = uploadedFile;
-          this.referenceImages.push(uploadedFile);
-
-          // 触发AI分析
-          await this.analyzeImageWithAI(uploadedFile, spaceId);
-        }
+        });
       }
-
       this.cdr.markForCheck();
-
     } catch (error) {
       console.error('上传失败:', error);
-      window?.fmode?.alert('文件上传失败,请重试');
+      window?.fmode?.alert('文件上传失败');
     } finally {
       this.uploading = false;
     }
   }
 
-  /**
-   * 对CAD文件进行AI分析
-   */
-  async analyzeCADFileWithAI(cadFile: any, spaceId: string): Promise<void> {
-    try {
-      // CAD文件的AI分析结果
-      const analysisResult = {
-        suggestedImageType: 'cad',
-        originalAnalysis: {
-          quality: {
-            score: 85,
-            level: 'high',
-            sharpness: 90,
-            brightness: 80,
-            contrast: 85
-          },
-          content: {
-            category: 'cad',
-            confidence: 95,
-            description: 'CAD设计文件 - 建筑平面图/立面图',
-            tags: ['CAD', '设计图纸', '建筑']
-          },
-          technical: {
-            megapixels: 0,
-            dpi: 0,
-            format: cadFile.name.split('.').pop()?.toUpperCase() || 'CAD'
-          }
-        },
-        enhancedAnalysis: {
-          style: '专业建筑设计',
-          atmosphere: '精确、规范、专业',
-          material: '数字设计',
-          texture: '线条清晰',
-          quality: '高精度',
-          form: '几何精确',
-          structure: '标准建筑结构',
-          colorComposition: '黑白线条'
-        },
-        colorAnalysis: {
-          brightness: '高对比度,黑白分明',
-          hue: '黑色线条,白色背景',
-          saturation: '无饱和度(黑白图)',
-          openness: '低开放度,线条单一',
-          extracted: ['#000000', '#FFFFFF'],
-          organized: [
-            { color: '#FFFFFF', role: '背景', percentage: 70 },
-            { color: '#000000', role: '线条', percentage: 30 }
-          ],
-          expanded: [],
-          harmonized: []
-        }
-      };
-
-      // 存储分析结果
-      if (!this.analysisResultsBySpace[spaceId]) {
-        this.analysisResultsBySpace[spaceId] = [];
-      }
-
-      const analysisRecord = {
-        imageId: cadFile.id,
-        imageType: 'cad',
-        originalAnalysis: analysisResult.originalAnalysis,
-        enhancedAnalysis: analysisResult.enhancedAnalysis,
-        colorAnalysis: analysisResult.colorAnalysis,
-        analysisTime: new Date().toISOString(),
-        isCADFile: true,
-        fileName: cadFile.name
-      };
-
-      this.analysisResultsBySpace[spaceId].push(analysisRecord);
-
-      // 保存分析结果到数据库
-      await this.saveAnalysisResultToDatabase(spaceId, cadFile.id, analysisRecord);
-
-      console.log(`✅ CAD文件分析完成: ${cadFile.name}`);
-      this.cdr.markForCheck();
-    } catch (error) {
-      console.error('CAD文件分析失败:', error);
-    }
-  }
-
-  /**
-   * 使用AI分析图片
-   */
-  async analyzeImageWithAI(imageFile: any, spaceId: string): Promise<void> {
-    try {
-      // 调用AI分析服务
-      const analysisResult = await this.performImageAnalysis(imageFile.url, imageFile);
-
-      // 存储分析结果
-      if (!this.analysisResultsBySpace[spaceId]) {
-        this.analysisResultsBySpace[spaceId] = [];
-      }
-
-      const analysisRecord = {
-        imageId: imageFile.id,
-        imageType: analysisResult.suggestedImageType || 'other',
-        // 原有分析维度
-        originalAnalysis: analysisResult.originalAnalysis,
-        // 新增设计分析维度
-        enhancedAnalysis: analysisResult.enhancedAnalysis,
-        // 色彩解析报告
-        colorAnalysis: analysisResult.colorAnalysis,
-        // 分析时间戳
-        analysisTime: new Date().toISOString()
-      };
-
-      this.analysisResultsBySpace[spaceId].push(analysisRecord);
-
-      // 更新图片类型
-      const image = this.referenceImages.find(img => img.id === imageFile.id);
-      if (image) {
-        image.type = analysisResult.suggestedImageType || 'other';
-      }
-
-      // 保存分析结果到数据库
-      await this.saveAnalysisResultToDatabase(spaceId, imageFile.id, analysisRecord);
-
-      this.cdr.markForCheck();
-    } catch (error) {
-      console.error('AI分析失败:', error);
-    }
-  }
-
-  /**
-   * 保存分析结果到数据库
-   */
-  private async saveAnalysisResultToDatabase(spaceId: string, imageId: string, analysisRecord: any): Promise<void> {
-    try {
-      const projectData = this.project?.get('data') || {};
-      
-      // 初始化分析结果存储结构
-      if (!projectData.requirementsAnalysis) {
-        projectData.requirementsAnalysis = {};
-      }
-      if (!projectData.requirementsAnalysis[spaceId]) {
-        projectData.requirementsAnalysis[spaceId] = {
-          analysisResults: [],
-          lastUpdated: new Date().toISOString()
-        };
-      }
-
-      // 检查是否已存在该图片的分析结果
-      const existingIndex = projectData.requirementsAnalysis[spaceId].analysisResults.findIndex(
-        (r: any) => r.imageId === imageId
-      );
-
-      if (existingIndex >= 0) {
-        // 更新现有分析结果
-        projectData.requirementsAnalysis[spaceId].analysisResults[existingIndex] = analysisRecord;
-      } else {
-        // 添加新的分析结果
-        projectData.requirementsAnalysis[spaceId].analysisResults.push(analysisRecord);
-      }
-
-      projectData.requirementsAnalysis[spaceId].lastUpdated = new Date().toISOString();
-
-      // 保存到项目
-      this.project?.set('data', projectData);
-      await this.project?.save();
-
-      console.log(`✅ 分析结果已保存: 空间${spaceId}, 图片${imageId}`);
-    } catch (error) {
-      console.error('保存分析结果失败:', error);
-    }
-  }
-
-  /**
-   * 执行图片分析(调用豆包1.6)
-   */
-  async performImageAnalysis(imageUrl: string, imageFile: any): Promise<any> {
-    try {
-      // 获取图片基础信息用于分类
-      const imageInfo = await this.getImageInfo(imageFile);
-      
-      // 根据图片特征进行智能分类
-      const imageType = this.classifyImageByFeatures(imageInfo);
-      
-      // 调用AI服务进行深度分析
-      const aiAnalysis = await this.callAIAnalysis(imageUrl, imageInfo);
-      
-      return {
-        suggestedImageType: imageType,
-        // 原有分析维度(保留)
-        originalAnalysis: {
-          quality: aiAnalysis.quality || {
-            score: 75,
-            level: 'high',
-            sharpness: 80,
-            brightness: 70,
-            contrast: 75
-          },
-          content: aiAnalysis.content || {
-            category: imageType === 'soft_decor' ? 'soft_decor' : 'hard_decor',
-            confidence: 85,
-            description: '室内设计参考图',
-            tags: []
-          },
-          technical: {
-            megapixels: imageInfo.megapixels || 2.1,
-            dpi: imageInfo.dpi || 72,
-            format: imageInfo.format || 'image/jpeg'
-          }
-        },
-        // 新增设计分析维度
-        enhancedAnalysis: {
-          style: aiAnalysis.style || '现代简约',
-          atmosphere: aiAnalysis.atmosphere || '温馨舒适',
-          material: aiAnalysis.material || '木质、金属、布艺混合',
-          texture: aiAnalysis.texture || '光滑与粗糙结合',
-          quality: aiAnalysis.qualityDesc || '高质感',
-          form: aiAnalysis.form || '几何线条为主',
-          structure: aiAnalysis.structure || '开放式布局',
-          colorComposition: aiAnalysis.colorComposition || '中性色系为主'
-        },
-        // 色彩解析报告
-        colorAnalysis: {
-          brightness: aiAnalysis.brightness || '低长调,以低明度为主,明暗对比大',
-          hue: aiAnalysis.hue || '红、橙、黄、绿等4个色相',
-          saturation: aiAnalysis.saturation || '中等饱和度,整体素雅',
-          openness: aiAnalysis.openness || '色彩开放度中等,3-4种主要色系',
-          extracted: aiAnalysis.extractedColors || ['#FFFFFF', '#333333', '#999999'],
-          organized: aiAnalysis.organizedColors || [
-            { color: '#FFFFFF', role: '主色', percentage: 60 },
-            { color: '#333333', role: '次色', percentage: 30 },
-            { color: '#999999', role: '辅色', percentage: 10 }
-          ],
-          expanded: aiAnalysis.expandedColors || ['#F5F5F5', '#E0E0E0'],
-          harmonized: aiAnalysis.harmonizedColors || ['#FAFAFA', '#D9D9D9']
-        },
-        // 风格元素分析(新增)
-        styleElements: {
-          styleKeywords: aiAnalysis.styleKeywords || ['新古典主义', '现代轻奢', '艺术装饰']
-        },
-        // 色彩搭配分析(新增)
-        colorScheme: {
-          primaryColors: aiAnalysis.primaryColors || ['#333333', '#FFFFFF'],
-          secondaryColors: aiAnalysis.secondaryColors || ['#999999', '#F5F5F5'],
-          accentColors: aiAnalysis.accentColors || ['#D4AF37', '#C0C0C0']
-        },
-        // 材质分析(新增)
-        materialAnalysis: {
-          materials: aiAnalysis.materials || ['大理石', '玻璃', '布', '金属', '木材']
-        },
-        // 布局特征分析(新增)
-        layoutFeatures: {
-          features: aiAnalysis.layoutFeatures || [
-            '对称式布局',
-            '多区域采光设计',
-            '以壁炉为视觉中心',
-            '开放式活动空间',
-            '层次化软装陈设'
-          ]
-        },
-        // 空间氛围分析(新增)
-        atmosphereAnalysis: {
-          atmosphere: aiAnalysis.atmosphereDesc || '高级、温馨、舒适的居住氛围'
-        }
-      };
-    } catch (error) {
-      console.error('AI分析失败:', error);
-      // 返回默认分析结果
-      return this.getDefaultAnalysisResult();
-    }
-  }
-
-  /**
-   * 获取图片信息
-   */
-  private async getImageInfo(imageFile: any): Promise<any> {
-    return new Promise((resolve) => {
-      const img = new Image();
-      img.onload = () => {
-        const megapixels = (img.width * img.height) / 1000000;
-        resolve({
-          width: img.width,
-          height: img.height,
-          megapixels: Math.round(megapixels * 100) / 100,
-          dpi: 72,
-          format: imageFile.type || 'image/jpeg',
-          aspectRatio: img.width / img.height
-        });
-      };
-      img.onerror = () => {
-        resolve({
-          width: 1920,
-          height: 1080,
-          megapixels: 2.1,
-          dpi: 72,
-          format: imageFile.type || 'image/jpeg',
-          aspectRatio: 16 / 9
-        });
-      };
-      img.src = imageFile.url || '';
-    });
-  }
-
-  /**
-   * 根据图片特征分类
-   */
-  private classifyImageByFeatures(imageInfo: any): string {
-    // 根据像素、宽高比等特征进行分类
-    const megapixels = imageInfo.megapixels || 0;
-    const aspectRatio = imageInfo.aspectRatio || 1;
-    
-    // 高像素 + 宽屏 = 渲染图
-    if (megapixels > 3 && aspectRatio > 1.5) {
-      return 'rendering';
-    }
-    
-    // 中等像素 + 接近正方形 = 软装
-    if (megapixels > 1 && aspectRatio > 0.8 && aspectRatio < 1.3) {
-      return 'soft_decor';
-    }
-    
-    // 低像素或特殊比例 = 硬装
-    if (megapixels < 1.5) {
-      return 'hard_decor';
-    }
-    
-    return 'other';
-  }
-
-  /**
-   * 调用AI分析服务
-   */
-  private async callAIAnalysis(imageUrl: string, imageInfo: any): Promise<any> {
-    // 这里可以集成豆包1.6 API
-    // 目前返回模拟数据
-    return {
-      quality: {
-        score: 85,
-        level: 'high',
-        sharpness: 88,
-        brightness: 82,
-        contrast: 85
-      },
-      content: {
-        category: 'soft_decor',
-        confidence: 92,
-        description: '现代简约风格室内设计',
-        tags: ['现代', '简约', '温馨']
-      },
-      style: '现代简约',
-      atmosphere: '温馨舒适',
-      material: '木质、金属、布艺混合',
-      texture: '光滑与粗糙结合',
-      qualityDesc: '高质感',
-      form: '几何线条为主',
-      structure: '开放式布局',
-      colorComposition: '中性色系为主',
-      brightness: '低长调,以低明度为主,明暗对比大',
-      hue: '红、橙、黄、绿等4个色相',
-      saturation: '中等饱和度,整体素雅',
-      openness: '色彩开放度中等,3-4种主要色系',
-      extractedColors: ['#FFFFFF', '#333333', '#999999', '#CCCCCC'],
-      organizedColors: [
-        { color: '#FFFFFF', role: '主色', percentage: 55 },
-        { color: '#333333', role: '次色', percentage: 25 },
-        { color: '#999999', role: '辅色', percentage: 15 },
-        { color: '#CCCCCC', role: '点缀', percentage: 5 }
-      ],
-      expandedColors: ['#F5F5F5', '#E0E0E0', '#D9D9D9'],
-      harmonizedColors: ['#FAFAFA', '#D9D9D9', '#C0C0C0']
-    };
-  }
-
-  /**
-   * 获取默认分析结果
-   */
-  private getDefaultAnalysisResult(): any {
-    return {
-      suggestedImageType: 'other',
-      originalAnalysis: {
-        quality: { score: 70, level: 'medium', sharpness: 70, brightness: 70, contrast: 70 },
-        content: { category: 'unknown', confidence: 60, description: '参考图', tags: [] },
-        technical: { megapixels: 2.0, dpi: 72, format: 'image/jpeg' }
-      },
-      enhancedAnalysis: {
-        style: '待分析',
-        atmosphere: '待分析',
-        material: '待分析',
-        texture: '待分析',
-        quality: '待分析',
-        form: '待分析',
-        structure: '待分析',
-        colorComposition: '待分析'
-      },
-      colorAnalysis: {
-        brightness: '待分析',
-        hue: '待分析',
-        saturation: '待分析',
-        openness: '待分析',
-        extracted: [],
-        organized: [],
-        expanded: [],
-        harmonized: []
-      }
-    };
-  }
-
-  /**
-   * 获取图片分析结果
-   */
-  getImageAnalysisResults(spaceId: string): any[] {
-    return this.analysisResultsBySpace[spaceId] || [];
-  }
-
-  /**
-   * 获取图片URL
-   */
-  getImageUrl(imageId: string): string {
-    // 先查找参考图片
-    const image = this.referenceImages.find(img => img.id === imageId);
-    if (image) {
-      return image.url || '';
-    }
-    
-    // 再查找CAD文件
-    const cadFile = this.cadFiles.find(file => file.id === imageId);
-    if (cadFile) {
-      return cadFile.url || '';
-    }
-    
-    // 最后查找分析图片映射
-    const analysisImage = this.analysisImageMap[imageId];
-    return analysisImage?.url || '';
-  }
-
-  /**
-   * 加载已保存的AI分析结果
-   */
-  private async loadAnalysisResults(): Promise<void> {
-    try {
-      const projectData = this.project?.get('data') || {};
-      const requirementsAnalysis = projectData.requirementsAnalysis || {};
-
-      // 加载每个空间的分析结果
-      for (const spaceId in requirementsAnalysis) {
-        if (requirementsAnalysis.hasOwnProperty(spaceId)) {
-          const spaceAnalysis = requirementsAnalysis[spaceId];
-          if (spaceAnalysis.analysisResults && Array.isArray(spaceAnalysis.analysisResults)) {
-            this.analysisResultsBySpace[spaceId] = spaceAnalysis.analysisResults;
-            console.log(`✅ 已加载空间${spaceId}的分析结果: ${spaceAnalysis.analysisResults.length}条`);
-          }
-        }
-      }
-    } catch (error) {
-      console.error('加载分析结果失败:', error);
-    }
-  }
-
-  /**
-   * 获取空间特殊需求
-   */
-  getSpaceSpecialRequirements(spaceId: string): string {
-    return this.spaceSpecialRequirements[spaceId] || '';
-  }
-
-  /**
-   * 设置空间特殊需求
-   */
-  setSpaceSpecialRequirements(spaceId: string, value: string): void {
-    this.spaceSpecialRequirements[spaceId] = value;
-    // 保存到数据库或本地存储
-    this.saveSpaceRequirements(spaceId, value);
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 保存空间需求到数据库
-   */
-  private async saveSpaceRequirements(spaceId: string, requirements: string): Promise<void> {
-    try {
-      if (!this.project) return;
-
-      // 获取或初始化project.data
-      let projectData = this.project.get('data') || {};
-      
-      // 初始化特殊需求对象
-      if (!projectData.spaceSpecialRequirements) {
-        projectData.spaceSpecialRequirements = {};
-      }
-
-      // 保存该空间的特殊需求
-      projectData.spaceSpecialRequirements[spaceId] = {
-        content: requirements,
-        updatedAt: new Date().toISOString(),
-        updatedBy: this.currentUser?.id || 'unknown'
-      };
-
-      // 更新project对象
-      this.project.set('data', projectData);
-      
-      // 保存到服务器
-      await this.project.save();
-      
-      console.log(`✅ 空间 ${spaceId} 的特殊需求已保存:`, requirements);
-    } catch (error) {
-      console.error('保存特殊需求失败:', error);
-    }
-  }
-
-  /**
-   * 上传参考图片并指定类型
-   */
-  async uploadReferenceImageWithType(event: any, productId?: string, imageType?: string): Promise<void> {
-    const files = event.target.files;
-    if (!files || files.length === 0) return;
+  async uploadCADFiles(files: File[], spaceId: string): Promise<void> {
+    this.uploading = true;
+    const targetProjectId = this.projectId || this.project?.id;
 
     try {
-      this.uploading = true;
-      const targetProductId = productId || this.activeProductId;
-      const targetProjectId = this.projectId || this.project?.id;
-      const finalImageType = imageType || 'other';
-
-      if (!targetProjectId) {
-        console.error('未找到项目ID,无法上传文件');
-        return;
-      }
-
-      for (let i = 0; i < files.length; i++) {
-        const file = files[i];
-
-        // 文件类型验证
-        if (!file.type.startsWith('image/')) {
-          console.warn(`文件 ${file.name} 不是图片格式,跳过`);
-          continue;
-        }
-
-        // 文件大小验证 (10MB)
-        if (file.size > 10 * 1024 * 1024) {
-          console.warn(`文件 ${file.name} 超过10MB限制,跳过`);
-          continue;
-        }
-
-        // 使用ProjectFileService上传到服务器
+      for (const file of files) {
         const projectFile = await this.projectFileService.uploadProjectFileWithRecord(
           file,
           targetProjectId,
-          'reference_image',
-          targetProductId,
+          'cad_file',
+          spaceId,
           'requirements',
           {
-            imageType: finalImageType,
-            uploadedFor: 'requirements_analysis',
-            spaceId: targetProductId,
-            deliveryType: 'requirements_reference',
-            uploadStage: 'requirements'
-          },
-          (progress) => {
-            console.log(`上传进度: ${progress}%`);
+            uploadedFor: 'requirements_cad',
+            spaceId: spaceId
           }
         );
-
-        // 为ProjectFile添加扩展数据字段
-        const existingData = projectFile.get('data') || {};
-        projectFile.set('data', {
-          ...existingData,
-          spaceId: targetProductId,
-          deliveryType: 'requirements_reference',
-          uploadedFor: 'requirements_analysis',
-          imageType: finalImageType,
-          analysis: {
-            ai: null,
-            manual: null,
-            lastAnalyzedAt: null
-          }
-        });
-        await projectFile.save();
-
-        // 创建参考图片记录
-        const uploadedFile = {
-          id: projectFile.id || '',
-          url: projectFile.get('fileUrl') || '',
-          name: projectFile.get('fileName') || file.name,
-          type: finalImageType,
-          uploadTime: projectFile.createdAt || new Date(),
-          spaceId: targetProductId,
-          tags: [],
-          projectFile: projectFile
-        };
-
-        // 添加到参考图片列表
-        if (uploadedFile.id) {
-          this.analysisImageMap[uploadedFile.id] = uploadedFile;
-          this.referenceImages.push(uploadedFile);
-        }
-      }
-
-      this.cdr.markForCheck();
-
-    } catch (error) {
-      console.error('上传失败:', error);
-      window?.fmode?.alert('文件上传失败,请重试');
-    } finally {
-      this.uploading = false;
-    }
-  }
-
-  /**
-   * 上传参考图片 - 使用ProjectFileService实际存储
-   */
-  async uploadReferenceImage(event: any, productId?: string): Promise<void> {
-    const files = event.target.files;
-    if (!files || files.length === 0) return;
-
-    try {
-      this.uploading = true;
-      const targetProductId = productId || this.activeProductId;
-      const targetProjectId = this.projectId || this.project?.id;
-
-      if (!targetProjectId) {
-        console.error('未找到项目ID,无法上传文件');
-        return;
-      }
-
-      for (let i = 0; i < files.length; i++) {
-        const file = files[i];
-
-        // 文件类型验证
-        if (!file.type.startsWith('image/')) {
-          console.warn(`文件 ${file.name} 不是图片格式,跳过`);
-          continue;
-        }
-
-        // 文件大小验证 (10MB)
-        if (file.size > 10 * 1024 * 1024) {
-          console.warn(`文件 ${file.name} 超过10MB限制,跳过`);
-          continue;
-        }
-
-        // 使用ProjectFileService上传到服务器
-        const projectFile = await this.projectFileService.uploadProjectFileWithRecord(
-          file,
-          targetProjectId,
-          'reference_image',
-          targetProductId,
-          'requirements', // stage参数
-          {
-            imageType: 'style',
-            uploadedFor: 'requirements_analysis',
-            // 补充:添加关联空间ID和交付类型标识
-            spaceId: targetProductId,
-            deliveryType: 'requirements_reference', // 需求阶段参考图片
-            uploadStage: 'requirements'
-          },
-          (progress) => {
-            console.log(`上传进度: ${progress}%`);
-          }
-        );
-
-        // 补充:为ProjectFile添加扩展数据字段
-        const existingData = projectFile.get('data') || {};
-        projectFile.set('data', {
-          ...existingData,
-          spaceId: targetProductId,
-          deliveryType: 'requirements_reference',
-          uploadedFor: 'requirements_analysis',
-          analysis: {
-            // 预留AI分析结果字段
-            ai: null,
-            manual: null,
-            lastAnalyzedAt: null
-          }
-        });
-        await projectFile.save();
-
-        // 创建参考图片记录
-        const uploadedFile = {
-          id: projectFile.id || '',
-          url: projectFile.get('fileUrl') || '',
-          name: projectFile.get('fileName') || file.name,
-          type: 'style',
-          uploadTime: projectFile.createdAt || new Date(),
-          spaceId: targetProductId,
-          tags: [],
-          projectFile: projectFile // 保存ProjectFile对象引用
-        };
-
-        // 添加到参考图片列表
-        if (uploadedFile.id) {
-          this.analysisImageMap[uploadedFile.id] = uploadedFile;
-          this.referenceImages.push(uploadedFile);
-        }
-      }
-
-      this.cdr.markForCheck();
-
-    } catch (error) {
-      console.error('上传失败:', error);
-     window?.fmode?.alert('文件上传失败,请重试');
-    } finally {
-      this.uploading = false;
-    }
-  }
-
-  analysisImageMap:any = {}
-  /**
-   * 删除参考图片 - 同时删除服务器文件
-   */
-  async deleteReferenceImage(imageId: string): Promise<void> {
-    try {
-      // 查找图片记录
-      const image = this.referenceImages.find(img => img.id === imageId);
-
-      if (image && image.projectFile) {
-        // 使用ProjectFileService删除服务器上的文件
-        await this.projectFileService.deleteProjectFile(imageId);
-      }
-
-      // 从列表中移除
-      this.referenceImages = this.referenceImages.filter(img => img.id !== imageId);
-      delete this.analysisImageMap[imageId];
-
-      this.cdr.markForCheck();
-
-    } catch (error) {
-      console.error('删除参考图片失败:', error);
-     window?.fmode?.alert('删除文件失败,请重试');
-    }
-  }
-
-  /**
-   * 查看图片色彩分析 - 打开ColorGetDialog
-   */
-  async viewImageColorAnalysis(imageId: string): Promise<void> {
-    const image = this.referenceImages.find(img => img.id === imageId);
-    if (!image) {
-      console.error('未找到图片记录');
-      return;
-    }
-
-    try {
-      // 打开色彩分析对话框
-      const dialogRef = this.dialog.open(ColorGetDialogComponent, {
-        width: '90vw',
-        maxWidth: '800px',
-        height: 'auto',
-        maxHeight: '90vh',
-        data: {
-          fileId: image.id,
-          fileObject: image.projectFile,
-          url: image.url,
-          name: image.name
-        },
-        panelClass: 'color-analysis-dialog'
-      });
-
-      // 对话框关闭后,刷新分析结果
-      dialogRef.afterClosed().subscribe(result => {
-        console.log('色彩分析对话框已关闭', result);
-        this.cdr.markForCheck();
-      });
-
-    } catch (error) {
-      console.error('打开色彩分析对话框失败:', error);
-    }
-  }
-
-  /**
-   * 上传CAD文件 - 使用ProjectFileService实际存储
-   */
-  async uploadCAD(event: any, productId?: string): Promise<void> {
-    const files = event.target.files;
-    if (!files || files.length === 0) return;
-
-    try {
-      this.uploading = true;
-      const targetProductId = productId || this.activeProductId;
-      const targetProjectId = this.projectId || this.project?.id;
-
-      if (!targetProjectId) {
-        console.error('未找到项目ID,无法上传文件');
-        return;
-      }
-
-      for (let i = 0; i < files.length; i++) {
-        const file = files[i];
-
-        // 验证文件类型
-        const allowedExtensions = ['.dwg', '.dxf', '.pdf'];
-        const fileExtension = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
-        if (!allowedExtensions.includes(fileExtension)) {
-          console.warn(`文件 ${file.name} 不是支持的CAD格式,跳过`);
-          continue;
-        }
-
-        // 验证文件大小 (50MB)
-        if (file.size > 50 * 1024 * 1024) {
-          console.warn(`文件 ${file.name} 超过50MB限制,跳过`);
-          continue;
-        }
-
-        // 使用ProjectFileService上传到服务器
-        const projectFile = await this.projectFileService.uploadProjectFileWithRecord(
-          file,
-          targetProjectId,
-          'cad_drawing',
-          targetProductId,
-          'requirements', // stage参数
-          {
-            cadFormat: fileExtension.replace('.', ''),
-            uploadedFor: 'requirements_analysis',
-            // 补充:添加关联空间ID和交付类型标识
-            spaceId: targetProductId,
-            deliveryType: 'requirements_cad',
-            uploadStage: 'requirements'
-          },
-          (progress) => {
-            console.log(`上传进度: ${progress}%`);
-          }
-        );
-
-        // 补充:为CAD文件ProjectFile添加扩展数据字段
-        const existingData = projectFile.get('data') || {};
-        projectFile.set('data', {
-          ...existingData,
-          spaceId: targetProductId,
-          deliveryType: 'requirements_cad',
-          uploadedFor: 'requirements_analysis',
-          cadFormat: fileExtension.replace('.', ''),
-          analysis: {
-            // 预留CAD分析结果字段
-            ai: null,
-            manual: null,
-            lastAnalyzedAt: null,
-            spaceStructure: null,
-            dimensions: null,
-            constraints: [],
-            opportunities: []
-          }
+        
+        this.cadFiles.push({
+            id: projectFile.id || '',
+            url: projectFile.get('fileUrl') || '',
+            name: projectFile.get('fileName') || file.name,
+            uploadTime: projectFile.createdAt || new Date(),
+            spaceId: spaceId,
+            size: file.size,
+            projectFile: projectFile
         });
-        await projectFile.save();
-
-        // 创建CAD文件记录
-        const uploadedFile = {
-          id: projectFile.id || '',
-          url: projectFile.get('fileUrl') || '',
-          name: projectFile.get('fileName') || file.name,
-          uploadTime: projectFile.createdAt || new Date(),
-          size: projectFile.get('fileSize') || file.size,
-          spaceId: targetProductId,
-          projectFile: projectFile // 保存ProjectFile对象引用
-        };
-
-        // 添加到CAD文件列表
-        if (uploadedFile.id) {
-          this.analysisFileMap[uploadedFile.id] = uploadedFile;
-          this.cadFiles.push(uploadedFile);
-        }
       }
-
       this.cdr.markForCheck();
-
     } catch (error) {
-      console.error('上传失败:', error);
-     window?.fmode?.alert('文件上传失败,请重试');
+      console.error('CAD上传失败:', error);
+      window?.fmode?.alert('CAD上传失败');
     } finally {
       this.uploading = false;
     }
   }
-
-  /**
-   * 删除CAD文件 - 同时删除服务器文件
-   */
-  async deleteCAD(fileId: string): Promise<void> {
-    try {
-      // 查找文件记录
-      const file = this.cadFiles.find(f => f.id === fileId);
-
-      if (file && file.projectFile) {
-        // 使用ProjectFileService删除服务器上的文件
-        await this.projectFileService.deleteProjectFile(fileId);
-      }
-
-      // 从列表中移除
-      this.cadFiles = this.cadFiles.filter(f => f.id !== fileId);
-      delete this.analysisFileMap[fileId];
-
-      this.cdr.markForCheck();
-
-    } catch (error) {
-      console.error('删除CAD文件失败:', error);
-     window?.fmode?.alert('删除文件失败,请重试');
-    }
-  }
-
-  /**
-   * 生成AI方案
-   */
-  async generateAISolution(): Promise<void> {
-    try {
-      this.generating = true;
-
-      // 先进行AI分析,再生成方案
-      console.log("performComprehensiveAIAnalysis")
-      await this.performComprehensiveAIAnalysis();
-
-      // 基于AI分析结果生成方案
-      this.aiSolution = {
-        generated: true,
-        content: this.generateSolutionContent(),
-        spaces: this.generateSpaceSolutions(),
-        estimatedCost: this.calculateAIEnhancedEstimatedCost(),
-        timeline: this.calculateAIEnhancedTimeline(),
-        crossSpaceCoordination: this.generateAICrossSpaceCoordination()
-      };
-
-      this.cdr.markForCheck();
-
-    } catch (error) {
-      console.error('生成失败:', error);
-    } finally {
-      this.generating = false;
-    }
-  }
-
-  /**
-   * AI分析参考图片
-   */
-  async analyzeReferenceImages(): Promise<void> {
-    if (this.referenceImages.length === 0) return;
-
-    try {
-      this.aiAnalyzingImages = true;
-      this.aiAnalysisResults.imageAnalysis = [];
-
-      for (const image of this.referenceImages) {
-        const analysisResult = await this.analyzeImage(image);
-        this.aiAnalysisResults.imageAnalysis.push(analysisResult);
-      }
-
-      this.cdr.markForCheck();
-    } catch (error) {
-      console.error('图片分析失败:', error);
-    } finally {
-      this.aiAnalyzingImages = false;
-    }
-  }
-
-  /**
-   * 分析单张图片 - 使用URL而非Base64
-   */
-  private async analyzeImage(image: any): Promise<any> {
-    try {
-      const prompt = `作为专业的室内设计师,请分析这张家装参考图片,提取以下设计信息:
-
-要求:
-1. 准确识别图片中的设计风格 styleElements(如现代简约、北欧、轻奢等)
-2. 提取主要色彩搭配 colorPalette (使用HEX格式,如#FFFFFF)
-3. 识别使用的材质 materialAnalysis(如实木、大理石、布艺等)
-4. 分析空间布局特点 layoutFeatures
-5. 描述整体氛围感受 mood
-6. 给出分析置信度 confidence(0-1之间的小数)
-
-请严格按照以下JSON格式输出:`;
-
-      const outputSchema = `{
-  "styleElements": [""], 
-  "colorPalette": [""],
-  "materialAnalysis": [""],
-  "layoutFeatures": [""],
-  "mood": "",
-  "confidence": 0.00
-}`;
-
-      // 使用图片URL进行分析
-      const result = await completionJSON(
-        prompt,
-        outputSchema,
-        undefined,
-        2,
-        {
-          model: this.AI_MODEL,
-          vision: true,
-          images:[image.url], // 直接传入图片URL
-        }
-      );
-
-      // 保存分析结果到ProjectFile.analysis.ai
-      if (image.projectFile) {
-        await this.saveImageAnalysisToProjectFile(image.projectFile, result);
-      }
-
-      return {
-        imageId: image.id,
-        ...result
-      };
-
-    } catch (error) {
-      console.error('图片分析失败:', error);
-      return {
-        imageId: image.id,
-        styleElements: [],
-        colorPalette: [],
-        materialAnalysis: [],
-        layoutFeatures: [],
-        mood: '分析失败',
-        confidence: 0
-      };
-    }
-  }
-
-  /**
-   * 保存图片分析结果到ProjectFile.analysis.ai
-   */
-  private async saveImageAnalysisToProjectFile(projectFile: any, analysisResult: any): Promise<void> {
-    try {
-      // 补充:更新ProjectFile.data.analysis.ai字段(与现有analysis字段并存)
-      const existingData = projectFile.get('data') || {};
-      const existingAnalysis = existingData.analysis || {};
-      
-      // 保存AI分析结果到data.analysis.ai字段
-      existingAnalysis.ai = {
-        ...analysisResult,
-        analyzedAt: new Date().toISOString(),
-        version: '1.0',
-        source: 'image_analysis'
-      };
-      existingAnalysis.lastAnalyzedAt = new Date().toISOString();
-
-      existingData.analysis = existingAnalysis;
-      projectFile.set('data', existingData);
-
-      // 兼容:同时保存到原有的analysis字段
-      const currentAnalysis = projectFile.get('analysis') || {};
-      currentAnalysis.ai = {
-        ...analysisResult,
-        analyzedAt: new Date().toISOString(),
-        version: '1.0',
-        source: 'image_analysis'
-      };
-      projectFile.set('analysis', currentAnalysis);
-
-      // 确保关联Product
-      if(!projectFile?.get("product")?.id && projectFile?.get("data")?.spaceId){
-        projectFile.set("product",{__type:"Pointer",className:"Product",objectId:projectFile?.get("data")?.spaceId})
-      }
-      
-      await projectFile.save();
-
-      console.log('图片分析结果已保存到ProjectFile.data.analysis.ai和ProjectFile.analysis.ai');
-    } catch (error) {
-      console.error('保存分析结果失败:', error);
-    }
-  }
-
-  /**
-   * AI分析CAD文件
-   */
-  async analyzeCADFiles(): Promise<void> {
-    if (this.cadFiles.length === 0) return;
-
-    try {
-      this.aiAnalyzingCAD = true;
-      this.aiAnalysisResults.cadAnalysis = [];
-
-      for (const cadFile of this.cadFiles) {
-        const analysisResult = await this.analyzeCADFile(cadFile);
-        this.analysisFileMap[analysisResult?.fileId] = analysisResult;
-        this.aiAnalysisResults.cadAnalysis.push(analysisResult);
-      }
-
-      this.cdr.markForCheck();
-    } catch (error) {
-      console.error('CAD分析失败:', error);
-    } finally {
-      this.aiAnalyzingCAD = false;
-    }
-  }
-  analysisFileMap:any = {}
-
-  /**
-   * 分析单个CAD文件
-   */
-  private async analyzeCADFile(cadFile: any): Promise<any> {
-    try {
-      const prompt = `分析这个CAD户型文件,提取空间结构信息:
-{
-  "spaceStructure": {
-    "totalArea": "总面积",
-    "roomCount": "房间数量",
-    "layoutType": "布局类型"
-  },
-  "dimensions": {
-    "length": "长度",
-    "width": "宽度",
-    "height": "层高"
-  },
-  "constraints": ["限制因素1", "限制因素2"],
-  "opportunities": ["优化机会1", "优化机会2"]
 }
-
-要求:
-1. 识别空间结构和尺寸
-2. 分析承重墙、管道等限制因素
-3. 提供布局优化建议`;
-
-      const output = `{
-  "spaceStructure": {
-    "totalArea": "120㎡",
-    "roomCount": "3室2厅",
-    "layoutType": "南北通透"
-  },
-  "dimensions": {
-    "length": "12m",
-    "width": "10m",
-    "height": "2.8m"
-  },
-  "constraints": ["承重墙不可拆改", "主管道位置固定"],
-  "opportunities": ["客厅阳台可打通", "厨房可做开放式设计"]
-}`;
-
-      // 模拟CAD分析(实际需要CAD解析库)
-      const result = await completionJSON(
-        prompt,
-        output,
-        (_content) => {
-          // 进度回调
-        },
-        2,
-        {
-          model: this.AI_MODEL
-        }
-      );
-
-      return {
-        fileId: cadFile.id,
-        ...result
-      };
-
-    } catch (error) {
-      console.error('CAD文件分析失败:', error);
-      return {
-        fileId: cadFile.id,
-        spaceStructure: {},
-        dimensions: {},
-        constraints: [],
-        opportunities: []
-      };
-    }
-  }
-
-  /**
-   * 执行综合AI分析
-   */
-  async performComprehensiveAIAnalysis(): Promise<void> {
-    try {
-      this.aiGeneratingComprehensive = true;
-
-      // 并行执行图片和CAD分析
-      await Promise.all([
-        this.analyzeReferenceImages(),
-        this.analyzeCADFiles()
-      ]);
-
-      // 生成综合分析
-      await this.generateComprehensiveAnalysis();
-
-      this.cdr.markForCheck();
-    } catch (error) {
-      console.error('综合分析失败:', error);
-    } finally {
-      this.aiGeneratingComprehensive = false;
-    }
-  }
-
-  /**
-   * 生成综合分析
-   */
-  private async generateComprehensiveAnalysis(): Promise<void> {
-    try {
-      const prompt = `基于以下信息,生成综合设计方案分析:
-
-参考图片分析:${JSON.stringify(this.aiAnalysisResults.imageAnalysis, null, 2)}
-CAD文件分析:${JSON.stringify(this.aiAnalysisResults.cadAnalysis, null, 2)}
-用户需求:${JSON.stringify(this.globalRequirements, null, 2)}
-产品信息:${JSON.stringify(this.projectProducts.map(p => ({
-  name: p.name,
-  type: p.type,
-  area: p.area
-    })), null, 2)}
-
-请生成以下格式的综合分析:
-{
-  "overallStyle": "整体风格定位",
-  "colorScheme": {
-    "primary": "主色调",
-    "secondary": "副色调",
-    "accent": "点缀色"
-  },
-  "materialRecommendations": ["材质1", "材质2"],
-  "layoutOptimization": ["布局优化建议1", "布局优化建议2"],
-  "budgetAssessment": {
-    "estimatedMin": 最低预算,
-    "estimatedMax": 最高预算,
-    "riskLevel": "风险等级"
-  },
-  "timeline": "预计工期",
-  "riskFactors": ["风险因素1", "风险因素2"]
-}`;
-
-      const output = `{
-  "overallStyle": "现代简约风格,注重功能性和舒适性",
-  "colorScheme": {
-    "primary": "#FFFFFF",
-    "secondary": "#F5F5F5",
-    "accent": "#3880FF"
-  },
-  "materialRecommendations": ["实木复合地板", "环保乳胶漆", "布艺沙发"],
-  "layoutOptimization": ["打通客厅阳台,增加空间感", "厨房做开放式设计,提升互动性"],
-  "budgetAssessment": {
-    "estimatedMin": 150000,
-    "estimatedMax": 250000,
-    "riskLevel": "中等"
-  },
-  "timeline": "60-75个工作日",
-  "riskFactors": ["工期可能受天气影响", "材料价格波动风险"]
-}`;
-
-      const result = await completionJSON(
-        prompt,
-        output,
-        (_content) => {
-          // 进度回调
-        },
-        2,
-        {
-          model: this.AI_MODEL
-        }
-      );
-
-      this.aiAnalysisResults.comprehensiveAnalysis = result;
-
-    } catch (error) {
-      console.error('综合分析生成失败:', error);
-    }
-  }
-
-  /**
-   * AI聊天助手
-   */
-  async sendAIChatMessage(): Promise<void> {
-    if (!this.aiChatInput.trim()) return;
-
-    try {
-      const userMessage = {
-        id: `msg_${Date.now()}`,
-        role: 'user' as const,
-        content: this.aiChatInput,
-        timestamp: new Date()
-      };
-
-      this.aiChatMessages.push(userMessage);
-      this.aiChatInput = '';
-      this.cdr.markForCheck();
-
-      // 生成AI回复
-      const aiResponse = await this.generateAIChatResponse(userMessage.content);
-
-      this.aiChatMessages.push({
-        id: `msg_${Date.now() + 1}`,
-        role: 'assistant',
-        content: aiResponse,
-        timestamp: new Date()
-      });
-
-      this.cdr.markForCheck();
-
-    } catch (error) {
-      console.error('AI聊天失败:', error);
-    }
-  }
-
-  /**
-   * 生成AI聊天回复
-   */
-  private async generateAIChatResponse(userMessage: string): Promise<string> {
-    try {
-      const context = `
-项目背景:${JSON.stringify(this.globalRequirements, null, 2)}
-AI分析结果:${JSON.stringify(this.aiAnalysisResults, null, 2)}
-产品信息:${JSON.stringify(this.projectProducts.map(p => ({
-    name: p.name,
-    type: p.type,
-    area: p.area
-  })), null, 2)}`;
-
-      const prompt = `作为专业的家装设计AI助手,基于以下项目信息回答用户问题:
-
-${context}
-
-用户问题:${userMessage}
-
-请提供专业、实用的建议,回答要简洁明了,字数控制在200字以内。`;
-
-      const result = await completionJSON(
-        prompt,
-        '{"response": "专业的家装设计建议"}',
-        (content) => {
-          // 流式输出回调
-        },
-        2,
-        {
-          model: this.AI_MODEL
-        }
-      );
-
-      return result.response || '抱歉,我暂时无法回答这个问题。';
-
-    } catch (error) {
-      console.error('AI回复生成失败:', error);
-      return '抱歉,服务暂时不可用,请稍后再试。';
-    }
-  }
-
-  /**
-   * 从ProjectFile加载已上传的图片和CAD文件
-   */
-  async loadProjectFiles(): Promise<void> {
-    try {
-      const targetProjectId = this.projectId || this.project?.id;
-      if (!targetProjectId) {
-        console.warn('未找到项目ID,无法加载文件');
-        return;
-      }
-
-      // 加载参考图片
-      const referenceFiles = await this.projectFileService.getProjectFiles(
-        targetProjectId,
-        {
-          fileType: 'reference_image',
-          stage: 'requirements'
-        }
-      );
-
-      // 转换为referenceImages格式
-      this.referenceImages = referenceFiles.map(projectFile => ({
-        id: projectFile.id || '',
-        url: projectFile.get('fileUrl') || '',
-        name: projectFile.get('fileName') || '',
-        type: 'style',
-        uploadTime: projectFile.createdAt || new Date(),
-        spaceId: projectFile.get('data')?.spaceId,
-        tags: [],
-        projectFile: projectFile
-      }));
-
-      // 构建analysisImageMap
-      this.referenceImages.forEach(img => {
-        this.analysisImageMap[img.id] = img;
-      });
-
-      // 加载CAD文件
-      const cadFiles = await this.projectFileService.getProjectFiles(
-        targetProjectId,
-        {
-          fileType: 'cad_drawing',
-          stage: 'requirements'
-        }
-      );
-
-      // 转换为cadFiles格式
-      this.cadFiles = cadFiles.map(projectFile => ({
-        id: projectFile.id || '',
-        url: projectFile.get('fileUrl') || '',
-        name: projectFile.get('fileName') || '',
-        uploadTime: projectFile.createdAt || new Date(),
-        size: projectFile.get('fileSize') || 0,
-        spaceId: projectFile.get('data')?.spaceId,
-        projectFile: projectFile
-      }));
-
-      // 构建analysisFileMap
-      this.cadFiles.forEach(file => {
-        this.analysisFileMap[file.id] = file;
-      });
-
-      // 加载已有的AI分析结果
-      await this.loadExistingAnalysisResults();
-
-      this.cdr.markForCheck();
-      console.log(`已加载 ${this.referenceImages.length} 张参考图片和 ${this.cadFiles.length} 个CAD文件`);
-
-    } catch (error) {
-      console.error('加载项目文件失败:', error);
-    }
-  }
-
-  /**
-   * 加载已有的AI分析结果
-   */
-  private async loadExistingAnalysisResults(): Promise<void> {
-    try {
-      // 加载图片分析结果
-      this.aiAnalysisResults.imageAnalysis = [];
-      for (const image of this.referenceImages) {
-        if (image.projectFile) {
-          const analysis = image.projectFile.get('analysis');
-          if (analysis && analysis.ai) {
-            this.aiAnalysisResults.imageAnalysis.push({
-              imageId: image.id,
-              ...analysis.ai
-            });
-          }
-        }
-      }
-
-      console.log(`已加载 ${this.aiAnalysisResults.imageAnalysis.length} 个图片分析结果`);
-    } catch (error) {
-      console.error('加载分析结果失败:', error);
-    }
-  }
-
-  /**
-   * 生成方案内容
-   */
-  private generateSolutionContent(): string {
-    const analysis = this.aiAnalysisResults.comprehensiveAnalysis;
-    if (analysis) {
-      return `基于AI分析结果,我们为您推荐${analysis.overallStyle},通过${analysis.colorScheme.primary}、${analysis.colorScheme.secondary}、${analysis.colorScheme.accent}的色彩搭配,营造${this.globalRequirements.colorScheme.atmosphere}的居住氛围。`;
-    }
-    return `基于您的${this.globalRequirements.stylePreference}风格需求,我们为您设计了以下方案...`;
-  }
-
-  /**
-   * 生成空间方案
-   */
-  private generateSpaceSolutions(): any[] {
-    return this.projectProducts.map(product => {
-      const analysis = this.aiAnalysisResults.comprehensiveAnalysis;
-      return {
-        id: product.id,
-        name: product.name,
-        type: product.type,
-        styleDescription: `${analysis?.overallStyle || this.globalRequirements.stylePreference}风格${product.name}设计`,
-        colorPalette: analysis ? [analysis.colorScheme.primary, analysis.colorScheme.secondary, analysis.colorScheme.accent] : [this.globalRequirements.colorScheme.primary, this.globalRequirements.colorScheme.secondary, this.globalRequirements.colorScheme.accent],
-        materials: analysis?.materialRecommendations || ['实木', '大理石', '布艺'],
-        furnitureRecommendations: this.getFurnitureRecommendations(product.type),
-        estimatedCost: this.calculateProductEstimatedCost(product),
-        timeline: this.calculateProductTimeline(product)
-      };
-    });
-  }
-
-  /**
-   * 计算AI增强的估算成本
-   */
-  private calculateAIEnhancedEstimatedCost(): number {
-    const analysis = this.aiAnalysisResults.comprehensiveAnalysis;
-    if (analysis?.budgetAssessment) {
-      return analysis.budgetAssessment.estimatedMax || this.calculateTotalEstimatedCost();
-    }
-    return this.globalRequirements.overallBudget.max || this.calculateTotalEstimatedCost();
-  }
-
-  /**
-   * 计算AI增强的工期
-   */
-  private calculateAIEnhancedTimeline(): string {
-    const analysis = this.aiAnalysisResults.comprehensiveAnalysis;
-    return analysis?.timeline || this.calculateTotalTimeline();
-  }
-
-  /**
-   * 生成AI跨空间协调方案
-   */
-  private generateAICrossSpaceCoordination(): any {
-    const analysis = this.aiAnalysisResults.comprehensiveAnalysis;
-    return {
-      styleConsistency: {
-        description: analysis ? `确保${analysis.overallStyle}风格在各空间的统一体现` : '确保各空间风格统一协调',
-        keyElements: ['色彩搭配', '材质选择', '设计元素']
-      },
-      functionalFlow: {
-        description: analysis ? `基于${analysis.layoutOptimization?.join('、') || '空间规划'}优化功能流线` : '优化空间之间的功能流线',
-        considerations: ['动线规划', '采光通风', '噪音控制']
-      },
-      timelineCoordination: {
-        description: '协调各空间施工时间',
-        strategy: '并行施工,关键节点协调'
-      }
-    };
-  }
-
-  /**
-   * 切换AI聊天显示
-   */
-  toggleAIChat(): void {
-    this.showAIChat = !this.showAIChat;
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 获取家具推荐
-   */
-  private getFurnitureRecommendations(spaceType: string): string[] {
-    const recommendations: Record<string, string[]> = {
-      'living_room': ['沙发', '茶几', '电视柜', '书架', '装饰柜'],
-      'bedroom': ['床', '衣柜', '床头柜', '梳妆台', '椅子'],
-      'kitchen': ['橱柜', '冰箱', '灶具', '抽油烟机', '洗碗机'],
-      'bathroom': ['浴室柜', '马桶', '淋浴房', '花洒', '镜子'],
-      'dining_room': ['餐桌', '餐椅', '餐边柜', '酒柜', '装饰品'],
-      'study': ['书桌', '书椅', '书架', '台灯', '电脑桌']
-    };
-    return recommendations[spaceType] || ['基础家具'];
-  }
-
-  /**
-   * 计算产品估算成本
-   */
-  private calculateProductEstimatedCost(product: Project): number {
-    const baseCostPerSqm: Record<string, number> = {
-      'living_room': 1500,
-      'bedroom': 1200,
-      'kitchen': 2000,
-      'bathroom': 1800,
-      'dining_room': 1300,
-      'study': 1100
-    };
-    const baseCost = (baseCostPerSqm[product.type] || 1000) * (product.area || 10);
-    const qualityMultiplier: Record<string, number> = {
-      'standard': 1.0,
-      'premium': 1.5,
-      'luxury': 2.0
-    };
-    return baseCost * (qualityMultiplier[this.globalRequirements.qualityLevel] || 1.0);
-  }
-
-  /**
-   * 计算总估算成本
-   */
-  private calculateTotalEstimatedCost(): number {
-    return this.projectProducts.reduce((total, product) => {
-      return total + this.calculateProductEstimatedCost(product);
-    }, 0);
-  }
-
-  /**
-   * 计算产品工期
-   */
-  private calculateProductTimeline(product: Project): string {
-    const baseDays: Record<string, number> = {
-      'living_room': 15,
-      'bedroom': 12,
-      'kitchen': 20,
-      'bathroom': 18,
-      'dining_room': 10,
-      'study': 8
-    };
-    return `${baseDays[product.type] || 10}-15个工作日`;
-  }
-
-  /**
-   * 计算总工期
-   */
-  private calculateTotalTimeline(): string {
-    const totalDays = this.projectProducts.reduce((total, product) => {
-      const baseDays: Record<string, number> = {
-        'living_room': 15,
-        'bedroom': 12,
-        'kitchen': 20,
-        'bathroom': 18,
-        'dining_room': 10,
-        'study': 8
-      };
-      return total + (baseDays[product.type] || 10);
-    }, 0);
-    return `预计${Math.ceil(totalDays * 0.7)}-${totalDays}个工作日(考虑并行施工)`;
-  }
-
-  
-  /**
-   * 保存草稿
-   */
-  async saveDraft(): Promise<void> {
-    if (!this.project || !this.canEdit) return;
-
-    try {
-      this.saving = true;
-
-      // 模拟保存逻辑
-      console.log('保存草稿');
-
-    } catch (err) {
-      console.error('保存失败:', err);
-    } finally {
-      this.saving = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  
-
-  /**
-   * 提交确认(完全参考订单阶段实现)
-   */
-  async submitRequirements(): Promise<void> {
-    console.log('🔘 [确认需求] 按钮被点击', {
-      hasProject: !!this.project,
-      hasCurrentUser: !!this.currentUser,
-      canEdit: this.canEdit,
-      saving: this.saving,
-      projectId: this.project?.id
-    });
-    
-    if (!this.project || !this.currentUser) {
-      console.error('❌ [确认需求] 缺少必要数据', {
-        project: !!this.project,
-        currentUser: !!this.currentUser
-      });
-      window?.fmode?.alert('项目数据未加载,请刷新页面重试');
-      return;
-    }
-    
-    if (!this.canEdit) {
-      console.error('❌ [确认需求] 无编辑权限');
-      window?.fmode?.alert('当前账号无编辑权限,请联系组长或管理员');
-      return;
-    }
-
-    try {
-      this.saving = true;
-      this.cdr.markForCheck();
-      console.log('📝 [确认需求] 开始保存数据...');
-
-      const data = this.project.get('data') || {};
-      
-      // 保存需求确认数据
-      const confirmedAt = new Date();
-      data.requirementsConfirmed = true;
-      data.requirementsConfirmedBy = this.currentUser.id;
-      data.requirementsConfirmedByName = this.currentUser.get('name');
-      data.requirementsConfirmedAt = confirmedAt.toISOString();
-
-      // 补充:需求确认详细信息
-      data.requirementsDetail = {
-        globalRequirements: this.globalRequirements,
-        spaceRequirements: this.spaceRequirements,
-        crossSpaceRequirements: this.crossSpaceRequirements,
-        referenceImages: this.referenceImages.map(img => ({
-          id: img.id,
-          url: img.url,
-          name: img.name,
-          type: img.type,
-          spaceId: img.spaceId,
-          tags: img.tags
-        })),
-        cadFiles: this.cadFiles.map(file => ({
-          id: file.id,
-          url: file.url,
-          name: file.name,
-          size: file.size,
-          spaceId: file.spaceId
-        })),
-        aiAnalysisResults: this.aiAnalysisResults,
-        confirmedAt: new Date().toISOString()
-      };
-
-      // 重新生成阶段截止时间 (基于当前确认时间与项目交付日期)
-      this.rebuildPhaseDeadlines(data, confirmedAt);
-
-      // 补充:初始化空间交付物汇总
-      if (!data.spaceDeliverableSummary && this.projectProducts.length > 0) {
-        data.spaceDeliverableSummary = {};
-        let totalDeliverables = 0;
-        let completedDeliverables = 0;
-
-        this.projectProducts.forEach(product => {
-          const productSummary = {
-            spaceName: product.name,
-            totalDeliverables: 4, // 白模、软装、渲染、后期各1个
-            completedDeliverables: 0,
-            completionRate: 0,
-            lastUpdateTime: new Date().toISOString(),
-            phaseProgress: {
-              white_model: 0,
-              soft_decor: 0,
-              rendering: 0,
-              post_process: 0
-            }
-          };
-          
-          data.spaceDeliverableSummary[product.id] = productSummary;
-          totalDeliverables += productSummary.totalDeliverables;
-          completedDeliverables += productSummary.completedDeliverables;
-        });
-
-        data.spaceDeliverableSummary.overallCompletionRate = totalDeliverables > 0 
-          ? Math.round((completedDeliverables / totalDeliverables) * 100) 
-          : 0;
-      }
-
-      // 派发阶段完成事件,通知父组件前进
-      console.log('📡 [确认需求] 派发 stage:completed 事件');
-        try {
-        const ev = new CustomEvent('stage:completed', { 
-          detail: { stage: 'requirements', nextStage: 'delivery' }, 
-            bubbles: true,
-            cancelable: true
-          });
-        document.dispatchEvent(ev);
-        console.log('✅ [确认需求] 事件派发成功');
-      } catch (eventErr) {
-        console.warn('⚠️ [确认需求] 事件派发失败:', eventErr);
-        }
-
-      window?.fmode?.toast?.success?.('需求确认完成,项目已进入"交付执行"阶段');
-      console.log('✅ [确认需求] 流程完成');
-      this.cdr.markForCheck();
-    } catch (e) {
-      console.error('❌ [确认需求] 保存失败:', e);
-      window?.fmode?.alert('提交失败,请稍后重试');
-    } finally {
-      this.saving = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  private rebuildPhaseDeadlines(data: any, confirmedAt?: Date): void {
-    const start = confirmedAt ? new Date(confirmedAt) : new Date();
-    const projectDeadline = this.project?.get('deadline');
-    const fallbackDelivery = addDays(start, 30);
-    const deliveryDate = projectDeadline
-      ? normalizeDateInput(projectDeadline, fallbackDelivery)
-      : fallbackDelivery;
-
-    data.phaseDeadlines = generatePhaseDeadlines(start, deliveryDate);
-  }
-
-  // ===== 工具方法 =====
-
-  /**
-   * 获取空间图标
-   */
-  getSpaceIcon(spaceType: string): string {
-    const iconMap: Record<string, string> = {
-      'living_room': 'home',
-      'bedroom': 'bed',
-      'kitchen': 'restaurant',
-      'bathroom': 'water',
-      'dining_room': 'restaurant',
-      'study': 'book',
-      'balcony': 'sunny',
-      'corridor': 'walk',
-      'storage': 'archive',
-      'entrance': 'log-in',
-      'other': 'grid'
-    };
-    return iconMap[spaceType] || 'grid';
-  }
-
-  /**
-   * 获取空间类型名称
-   */
-  getSpaceTypeName(spaceType: string): string {
-    const nameMap: Record<string, string> = {
-      'living_room': '客厅',
-      'bedroom': '卧室',
-      'kitchen': '厨房',
-      'bathroom': '卫生间',
-      'dining_room': '餐厅',
-      'study': '书房',
-      'balcony': '阳台',
-      'corridor': '走廊',
-      'storage': '储物间',
-      'entrance': '玄关',
-      'other': '其他'
-    };
-    return nameMap[spaceType] || '其他';
-  }
-
-  /**
-   * 获取空间显示名称
-   */
-  getSpaceDisplayName(space: any): string {
-    return space.name || this.getSpaceTypeName(space.type);
-  }
-
-  /**
-   * 获取当前产品的需求
-   */
-  getCurrentProductRequirement(): any {
-    if (!this.activeProductId) return null;
-    return this.spaceRequirements.find(req => req.productId === this.activeProductId) || {
-      productId: this.activeProductId,
-      colorRequirement: {},
-      spaceStructureRequirement: {},
-      materialRequirement: {},
-      lightingRequirement: {},
-      specificRequirements: ''
-    };
-  }
-
-  /**
-   * 获取当前产品特殊需求的 getter/setter
-   */
-  get currentProductSpecificRequirements(): string {
-    const requirement = this.getCurrentProductRequirement();
-    return requirement?.specificRequirements || '';
-  }
-
-  set currentProductSpecificRequirements(value: string) {
-    const requirement = this.getCurrentProductRequirement();
-    if (requirement) {
-      requirement.specificRequirements = value;
-    }
-  }
-
-  /**
-   * 获取当前产品的评价
-   */
-  getCurrentProductFeedback(): any {
-    return null;
-  }
-
-  /**
-   * 过滤参考图片
-   */
-  getFilteredReferenceImages(): typeof this.referenceImages {
-    if (!this.isMultiProductProject || !this.activeProductId) {
-      return this.referenceImages;
-    }
-    return this.referenceImages.filter(img => !img.spaceId || img.spaceId === this.activeProductId);
-  }
-
-  /**
-   * 过滤CAD文件
-   */
-  getFilteredCADFiles(): typeof this.cadFiles {
-    if (!this.isMultiProductProject || !this.activeProductId) {
-      return this.cadFiles;
-    }
-    return this.cadFiles.filter(file => !file.spaceId || file.spaceId === this.activeProductId);
-  }
-
-
-
-  /**
-   * 格式化文件大小
-   */
-  formatFileSize(bytes: number): string {
-    if (bytes === 0) return '0 B';
-    const k = 1024;
-    const sizes = ['B', 'KB', 'MB', 'GB'];
-    const i = Math.floor(Math.log(bytes) / Math.log(k));
-    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
-  }
-
-  /**
-   * 获取质量等级名称
-   */
-  getQualityLevelName(level: string): string {
-    const levelMap: Record<string, string> = {
-      'standard': '标准',
-      'premium': '高级',
-      'luxury': '豪华'
-    };
-    return levelMap[level] || '标准';
-  }
-
-  /**
-   * 获取氛围名称
-   */
-  getAtmosphereName(atmosphere: string): string {
-    const atmosphereMap: Record<string, string> = {
-      'warm': '温馨',
-      'luxury': '高级',
-      'minimal': '简约',
-      'fashion': '时尚',
-      'nordic': '北欧',
-      'chinese': '中式',
-      'european': '欧式'
-    };
-    return atmosphereMap[atmosphere] || atmosphere;
-  }
-
-  /**
-   * 获取跨空间需求类型名称
-   */
-  getCrossSpaceRequirementTypeName(type: string): string {
-    const typeMap: Record<string, string> = {
-      'style': '风格统一',
-      'color': '色彩协调',
-      'material': '材质搭配',
-      'lighting': '照明衔接',
-      'functional': '功能关联',
-      'structural': '结构连接'
-    };
-    return typeMap[type] || type;
-  }
-
-  /**
-   * 计算需求完成度
-   */
-  calculateRequirementsCompleteness(): number {
-    let completedItems = 0;
-    let totalItems = 0;
-
-    // 全局需求检查
-    if (this.globalRequirements.stylePreference) completedItems++;
-    totalItems++;
-    if (this.globalRequirements.colorScheme.primary) completedItems++;
-    totalItems++;
-    if (this.globalRequirements.overallBudget.max > 0) completedItems++;
-    totalItems++;
-    if (this.globalRequirements.timeline) completedItems++;
-    totalItems++;
-
-    // 产品需求检查
-    for (const product of this.projectProducts) {
-      const productFeedback = this.spaceRequirements.find(req => req.productId === product.id);
-      if (productFeedback) {
-        completedItems++;
-      }
-      totalItems++;
-    }
-
-    return totalItems > 0 ? Math.round((completedItems / totalItems) * 100) : 0;
-  }
-
-  /**
-   * 计算产品完成度
-   */
-  calculateProductCompletion(_productId: string): number {
-    // 简化计算,实际应该基于产品的具体需求完成情况
-    return Math.floor(Math.random() * 100);
-  }
-
-  /**
-   * 创建跨产品需求
-   */
-  async createCrossProductRequirement(requirement?: any): Promise<void> {
-    console.log('创建跨产品需求:', requirement || {});
-  }
-
-  /**
-   * 删除跨产品需求
-   */
-  async deleteCrossProductRequirement(requirementId: string): Promise<void> {
-    console.log('删除跨产品需求:', requirementId);
-  }
-
-  /**
-   * 获取工序颜色
-   */
-  getProcessColor(spaceType: string): string {
-    const colorMap: Record<string, string> = {
-      'living_room': 'primary',
-      'bedroom': 'secondary',
-      'kitchen': 'tertiary',
-      'bathroom': 'success',
-      'dining_room': 'warning',
-      'study': 'medium'
-    };
-    return colorMap[spaceType] || 'primary';
-  }
-
-  /**
-   * 获取工序徽章类名
-   */
-  getProcessBadgeClass(spaceType: string): string {
-    const colorClass = this.getProcessColor(spaceType);
-    return `badge-${colorClass}`;
-  }
-
-  /**
-   * 获取关联空间ID列表
-   */
-  getRelatedSpaceIds(requirement: any): string[] {
-    if (!requirement) return [];
-    const ids = [requirement.primarySpaceId];
-    if (requirement.relatedSpaceIds && Array.isArray(requirement.relatedSpaceIds)) {
-      ids.push(...requirement.relatedSpaceIds);
-    }
-    return ids.filter(id => id); // 过滤掉空值
-  }
-
-  /**
-   * 根据产品ID获取产品显示名称(用于模板)
-   */
-  getProductDisplayNameById(productId: string): string {
-    const product = this.projectProducts.find(p => p.id === productId);
-    return this.getProductDisplayName(product);
-  }
-
-  /**
-   * 获取产品显示名称
-   */
-  getProductDisplayName(product: Project | undefined): string {
-    return product?.name || '未知产品';
-  }
-
-  /**
-   * 触发文件选择器点击
-   */
-  triggerFileClick(inputId: string): void {
-    const element = document.getElementById(inputId) as HTMLInputElement;
-    if (element) {
-      element.click();
-    }
-  }
-
-  // ===== AI分析辅助方法 =====
-
-  /**
-   * 获取分析对应的图片
-   */
-  getAnalysisImage(imageId: string): any {
-    return this.referenceImages.find(img => img.id === imageId);
-  }
-
-  /**
-   * 获取分析对应的CAD文件
-   */
-  getAnalysisFile(fileId: string): any {
-    return this.cadFiles.find(file => file.id === fileId);
-  }
-
-  // === 模板辅助方法:避免在模板中使用箭头函数/复杂表达式 ===
-  onAiChatInputChange(value: string): void {
-    this.aiChatInput = value;
-  }
-
-  isAiChatSendDisabled(): boolean {
-    return this.aiAnalyzing || !this.aiChatInput?.trim();
-  }
-
-  isSaving(): boolean {
-    return this.saving;
-  }
-
-  isSubmitDisabled(): boolean {
-    return this.saving || this.generating || this.aiAnalyzing;
-  }
-
-  /**
-   * 获取风险等级样式类名
-   */
-  getRiskLevelClass(riskLevel: string): string {
-    const classMap: Record<string, string> = {
-      'low': 'badge-success',
-      'medium': 'badge-warning',
-      'high': 'badge-danger'
-    };
-    return classMap[riskLevel] || 'badge-secondary';
-  }
-
-  /**
-   * 获取风险等级名称
-   */
-  getRiskLevelName(riskLevel: string): string {
-    const nameMap: Record<string, string> = {
-      'low': '低风险',
-      'medium': '中等风险',
-      'high': '高风险'
-    };
-    return nameMap[riskLevel] || '未知风险';
-  }
-
-  /**
-   * 切换空间折叠状态
-   */
-  toggleSpaceExpansion(spaceId: string): void {
-    if (this.expandedSpaces.has(spaceId)) {
-      this.expandedSpaces.delete(spaceId);
-    } else {
-      this.expandedSpaces.add(spaceId);
-    }
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 检查空间是否展开
-   */
-  isSpaceExpanded(spaceId: string): boolean {
-    return this.expandedSpaces.has(spaceId);
-  }
-
-  /**
-   * 获取空间的参考图片
-   */
-  getSpaceReferenceImages(spaceId: string): any[] {
-    return this.referenceImages.filter(img => img.spaceId === spaceId);
-  }
-
-  /**
-   * 获取空间的CAD文件
-   */
-  getSpaceCADFiles(spaceId: string): any[] {
-    return this.cadFiles.filter(file => file.spaceId === spaceId);
-  }
-
-  /**
-   * 检查图片是否有分析结果
-   */
-  hasImageAnalysis(imageId: string): boolean {
-    for (const spaceId in this.analysisResultsBySpace) {
-      const results = this.analysisResultsBySpace[spaceId];
-      if (results.some(r => r.imageId === imageId)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * 删除CAD文件
-   */
-  async deleteCADFile(cadFileId: string): Promise<void> {
-    if (!confirm('确定要删除此CAD文件吗?')) {
-      return;
-    }
-
-    try {
-      const index = this.cadFiles.findIndex(f => f.id === cadFileId);
-      if (index >= 0) {
-        this.cadFiles.splice(index, 1);
-        
-        // 删除相关的分析结果
-        for (const spaceId in this.analysisResultsBySpace) {
-          const results = this.analysisResultsBySpace[spaceId];
-          const analysisIndex = results.findIndex(r => r.imageId === cadFileId);
-          if (analysisIndex >= 0) {
-            results.splice(analysisIndex, 1);
-          }
-        }
-
-        console.log(`✅ CAD文件已删除: ${cadFileId}`);
-        this.cdr.markForCheck();
-      }
-    } catch (error) {
-      console.error('删除CAD文件失败:', error);
-    }
-  }
-
-  /**
-   * 获取空间文件数量统计
-   */
-  getSpaceFileCount(spaceId: string): { images: number; cad: number; total: number } {
-    const images = this.getSpaceReferenceImages(spaceId).length;
-    const cad = this.getSpaceCADFiles(spaceId).length;
-    return { images, cad, total: images + cad };
-  }
-
-  // ===== AI设计分析对话功能 =====
-
-  /**
-   * 选择AI分析空间
-   */
-  selectAISpace(space: any): void {
-    this.aiDesignCurrentSpace = space;
-
-    // 从保存的数据中加载(如果存在)
-    const projectData = this.project?.get('data') || {};
-    
-    // 加载对话历史
-    const aiChatHistory = projectData.aiChatHistory || {};
-    if (aiChatHistory[space.id]) {
-      this.aiChatMessages = aiChatHistory[space.id].messages.map((m: any) => ({
-        id: `${m.role}-${Date.now()}-${Math.random()}`,
-        role: m.role,
-        content: m.content,
-        timestamp: new Date(m.timestamp),
-        images: m.images
-      }));
-      console.log('💬 加载对话历史:', this.aiChatMessages.length, '条消息');
-    } else {
-      this.aiChatMessages = [];
-    }
-    
-    // 优先从确认的报告中加载
-    const designReports = projectData.designReports || {};
-    if (designReports[space.id]) {
-      const savedData = designReports[space.id];
-      console.log('✅ 加载已保存的AI分析数据:', space.name);
-      this.aiDesignUploadedImages = savedData.images || [];
-      this.aiDesignUploadedFiles = savedData.files || [];
-      this.aiDesignTextDescription = savedData.textDescription || '';
-      this.aiDesignAnalysisResult = savedData.analysisData || null;
-      this.aiDesignReport = savedData.report || '';
-      this.aiDesignReportConfirmed = !!savedData.confirmedAt;
-      
-      // 如果有对话历史但消息列表为空,从保存的对话历史加载
-      if (this.aiChatMessages.length === 0 && savedData.chatHistory) {
-        this.aiChatMessages = savedData.chatHistory.map((m: any) => ({
-          id: `${m.role}-${Date.now()}-${Math.random()}`,
-          role: m.role,
-          content: m.content,
-          timestamp: new Date(m.timestamp)
-        }));
-      }
-    } else {
-      // 如果没有确认的报告,尝试从分析结果中加载
-      const aiDesignAnalysis = projectData.aiDesignAnalysis || {};
-      if (aiDesignAnalysis[space.id]) {
-        const savedData = aiDesignAnalysis[space.id];
-        console.log('✅ 加载临时AI分析数据:', space.name);
-        this.aiDesignUploadedImages = savedData.images || [];
-        this.aiDesignUploadedFiles = savedData.files || [];
-        this.aiDesignTextDescription = savedData.textDescription || '';
-        this.aiDesignAnalysisResult = savedData.analysisData || null;
-        this.aiDesignReport = '';
-        this.aiDesignReportConfirmed = false;
-      } else {
-        console.log('ℹ️ 该空间暂无AI分析数据:', space.name);
-        this.aiDesignUploadedImages = [];
-        this.aiDesignUploadedFiles = [];
-        this.aiDesignTextDescription = '';
-        this.aiDesignAnalysisResult = null;
-        this.aiDesignReport = '';
-        this.aiDesignReportConfirmed = false;
-      }
-    }
-
-    this.cdr.markForCheck();
-    console.log('✨ 选择AI分析空间:', space.name);
-    
-    // 滚动到底部(如果有对话历史)
-    if (this.aiChatMessages.length > 0) {
-      this.scrollToBottom();
-    }
-  }
-
-  /**
-   * 打开AI设计分析对话框(兼容原按钮)
-   */
-  openAIDesignDialog(space: any): void {
-    // 兼容空间需求管理中的AI按钮,直接选择空间
-    this.selectAISpace(space);
-  }
-
-  /**
-   * 重置AI分析
-   */
-  resetAIAnalysis(): void {
-    this.aiDesignUploadedImages = [];
-    this.aiDesignUploadedFiles = [];
-    this.aiDesignTextDescription = '';
-    this.aiDesignAnalysisResult = null;
-    this.aiDesignReport = '';
-    this.aiDesignReportConfirmed = false;
-    this.aiDesignAnalyzing = false;
-    this.aiDesignGeneratingReport = false;
-    this.expandedDimensions.clear(); // 清空折叠状态
-    this.cdr.markForCheck();
-    console.log('🔄 重置AI分析');
-  }
-
-  /**
-   * 获取AI简洁摘要
-   */
-  getAISummary(): string {
-    if (!this.aiDesignAnalysisResult) {
-      return '';
-    }
-    
-    // 使用AI服务生成简洁摘要
-    return this.designAnalysisAIService.generateBriefSummary(this.aiDesignAnalysisResult);
-  }
-
-  /**
-   * 切换维度折叠状态
-   */
-  toggleDimension(dimensionKey: string): void {
-    if (this.expandedDimensions.has(dimensionKey)) {
-      this.expandedDimensions.delete(dimensionKey);
-    } else {
-      this.expandedDimensions.add(dimensionKey);
-    }
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 生成客服标注
-   */
-  async generateServiceNotes(): Promise<void> {
-    if (!this.aiDesignAnalysisResult) {
-      window?.fmode?.alert('请先完成AI分析');
-      return;
-    }
-
-    try {
-      // 使用AI服务生成客服标注格式
-      const serviceNotes = this.designAnalysisAIService.generateCustomerServiceNotes(
-        this.aiDesignAnalysisResult,
-        this.aiDesignTextDescription
-      );
-
-      console.log('📋 生成的客服标注:', serviceNotes);
-
-      // 保存到项目data
-      const projectData = this.project.get('data') || {};
-      
-      if (!projectData.designReports) {
-        projectData.designReports = {};
-      }
-
-      if (!projectData.designReports[this.aiDesignCurrentSpace.id]) {
-        projectData.designReports[this.aiDesignCurrentSpace.id] = {};
-      }
-
-      projectData.designReports[this.aiDesignCurrentSpace.id].serviceNotes = serviceNotes;
-      projectData.designReports[this.aiDesignCurrentSpace.id].serviceNotesGeneratedAt = new Date();
-
-      this.project.set('data', projectData);
-      await this.project.save();
-
-      // 自动复制到剪贴板
-      const copied = await this.copyToClipboard(serviceNotes);
-      
-      // 显示客服标注
-      const message = `客服标注已生成${copied ? '并复制到剪贴板' : ''}!\n\n${serviceNotes}`;
-      window?.fmode?.alert(message);
-      
-      console.log('✅ 客服标注已生成并保存');
-
-      this.cdr.markForCheck();
-    } catch (error: any) {
-      console.error('❌ 生成客服标注失败:', error);
-      window?.fmode?.alert('生成失败: ' + (error.message || '未知错误'));
-    }
-  }
-
-  /**
-   * 复制到剪贴板
-   */
-  private async copyToClipboard(text: string): Promise<boolean> {
-    try {
-      await navigator.clipboard.writeText(text);
-      console.log('✅ 已复制到剪贴板');
-      return true;
-    } catch (error) {
-      console.warn('⚠️ 复制失败,使用备用方案');
-      try {
-        // 备用方案
-        const textarea = document.createElement('textarea');
-        textarea.value = text;
-        textarea.style.position = 'fixed';
-        textarea.style.opacity = '0';
-        document.body.appendChild(textarea);
-        textarea.select();
-        const success = document.execCommand('copy');
-        document.body.removeChild(textarea);
-        if (success) {
-          console.log('✅ 备用方案复制成功');
-        }
-        return success;
-      } catch (fallbackError) {
-        console.error('❌ 复制失败:', fallbackError);
-        return false;
-      }
-    }
-  }
-
-  /**
-   * 触发AI对话框文件选择
-   */
-  triggerAIDialogFileInput(): void {
-    const element = document.getElementById('aiDesignFileInput') as HTMLInputElement;
-    if (element) {
-      element.click();
-    }
-  }
-
-  /**
-   * 处理AI对话框文件选择
-   */
-  async handleAIFileSelect(event: Event): Promise<void> {
-    const input = event.target as HTMLInputElement;
-    
-    if (!input.files || input.files.length === 0) {
-      return;
-    }
-
-    await this.handleAIFileUpload(Array.from(input.files));
-    
-    // 清空input,允许重复选择同一文件
-    input.value = '';
-  }
-
-  /**
-   * 移除AI对话框中的图片
-   */
-  removeAIDialogImage(index: number): void {
-    this.aiDesignUploadedImages.splice(index, 1);
-    this.aiDesignUploadedFiles.splice(index, 1);
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 处理文件拖拽进入
-   */
-  onAIFileDragOver(event: DragEvent): void {
-    event.preventDefault();
-    event.stopPropagation();
-    this.aiDesignDragOver = true;
-  }
-
-  /**
-   * 处理文件拖拽离开
-   */
-  onAIFileDragLeave(event: DragEvent): void {
-    event.preventDefault();
-    event.stopPropagation();
-    this.aiDesignDragOver = false;
-  }
-
-  /**
-   * 处理文件拖放
-   */
-  async onAIFileDrop(event: DragEvent): Promise<void> {
-    event.preventDefault();
-    event.stopPropagation();
-    this.aiDesignDragOver = false;
-
-    const files = event.dataTransfer?.files;
-    if (!files || files.length === 0) {
-      return;
-    }
-
-    await this.handleAIFileUpload(Array.from(files));
-  }
-
-  /**
-   * 处理AI文件上传(统一处理点击和拖拽)
-   * 🔥 修复:直接转base64,不上传到云存储,避免631错误
-   */
-  private async handleAIFileUpload(files: File[]): Promise<void> {
-    const maxFiles = 20; // 扩展至20个文件
-    const remainingSlots = maxFiles - this.aiDesignUploadedImages.length;
-    
-    if (remainingSlots <= 0) {
-      window?.fmode?.alert(`最多只能上传${maxFiles}个文件`);
-      return;
-    }
-
-    // 🔥 只支持图片格式进行AI分析
-    const supportedImageTypes = [
-      'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 
-      'image/webp', 'image/bmp', 'image/tiff'
-    ];
-
-    const filesToProcess = files.slice(0, remainingSlots);
-    this.aiDesignUploading = true;
-    this.cdr.markForCheck();
-
-    try {
-      for (const file of filesToProcess) {
-        // 检查文件类型
-        const fileExt = file.name.split('.').pop()?.toLowerCase();
-        const supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'tiff'];
-        const isSupported = supportedImageTypes.includes(file.type) || 
-                           supportedExtensions.includes(fileExt || '');
-
-        if (!isSupported) {
-          console.warn(`文件 ${file.name} 格式不支持,跳过`);
-          window?.fmode?.alert(`文件格式不支持: ${file.name}\n只支持图片格式: JPG、PNG、GIF、WebP等`);
-          continue;
-        }
-
-        // 🔥 智能处理大文件:自动压缩
-        let processedFile = file;
-        const maxSize = 50 * 1024 * 1024; // 50MB硬限制
-        const compressThreshold = 5 * 1024 * 1024; // 5MB开始压缩
-        
-        if (file.size > maxSize) {
-          console.warn(`文件 ${file.name} 超过50MB硬限制,跳过`);
-          window?.fmode?.alert(`文件超过50MB限制: ${file.name}\n请使用专业工具压缩后再上传`);
-          continue;
-        }
-
-        // 🔥 关键修复:直接转base64,不上传到云存储
-        console.log(`📤 准备处理文件: ${file.name}, 大小: ${(file.size / 1024 / 1024).toFixed(2)}MB`);
-        
-        // 如果文件大于5MB,自动压缩
-        if (file.size > compressThreshold) {
-          console.log(`🔄 文件较大,开始压缩...`);
-          try {
-            processedFile = await this.compressImage(file);
-            console.log(`✅ 压缩完成,压缩后大小: ${(processedFile.size / 1024 / 1024).toFixed(2)}MB`);
-          } catch (compressError) {
-            console.warn('⚠️ 压缩失败,使用原文件:', compressError);
-            // 压缩失败,继续使用原文件
-          }
-        }
-        
-        console.log(`🔄 将图片转换为base64格式...`);
-        
-        try {
-          // 使用FileReader转换为base64
-          const base64 = await new Promise<string>((resolve, reject) => {
-            const reader = new FileReader();
-            reader.onloadend = () => {
-              const result = reader.result as string;
-              resolve(result);
-            };
-            reader.onerror = () => {
-              reject(new Error('文件读取失败'));
-            };
-            reader.readAsDataURL(processedFile);
-          });
-          
-          console.log(`✅ 图片已转换为base64,大小: ${(base64.length / 1024).toFixed(2)}KB`);
-          
-          // 🔥 保存base64数据(AI分析时使用)
-          this.aiDesignUploadedImages.push(base64);
-          this.aiDesignUploadedFiles.push({
-            url: base64, // base64字符串
-            name: file.name,
-            type: file.type,
-            size: file.size,
-            extension: fileExt,
-            isBase64: true // 标记为base64数据
-          });
-          
-          console.log(`💾 已保存图片: ${file.name}`);
-          
-        } catch (convertError) {
-          console.error(`❌ 转换文件失败: ${file.name}`, convertError);
-          window?.fmode?.alert(`处理文件失败: ${file.name}`);
-          continue;
-        }
-      }
-
-      this.cdr.markForCheck();
-      console.log(`✅ 已处理${this.aiDesignUploadedImages.length}个文件`);
-      console.log(`🎯 所有图片已转为base64,可直接进行AI分析`);
-
-    } catch (error: any) {
-      console.error('❌ 处理文件失败:', error);
-      window?.fmode?.alert(`处理文件失败: ${error?.message || '未知错误'}`);
-    } finally {
-      this.aiDesignUploading = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  /**
-   * 开始AI分析(直接调用AI进行真实分析)
-   */
-  async startAIDesignAnalysis(): Promise<void> {
-    // 🔥 防止重复分析:如果正在分析中,直接返回
-    if (this.aiDesignAnalyzing) {
-      console.log('⚠️ 正在分析中,忽略重复调用');
-      return;
-    }
-
-    if (this.aiDesignUploadedImages.length === 0) {
-      window?.fmode?.alert('请先上传参考图片');
-      return;
-    }
-
-    // 🔥 关键检查:验证图片是否有效(支持HTTP/HTTPS URL 和 base64格式)
-    const validImages = this.aiDesignUploadedImages.filter(data => {
-      // 支持两种格式:1) HTTP/HTTPS URL  2) base64 (data:image/...)
-      const isValidUrl = data && (data.startsWith('http://') || data.startsWith('https://'));
-      const isValidBase64 = data && data.startsWith('data:image/');
-      const isValid = isValidUrl || isValidBase64;
-      
-      if (!isValid) {
-        console.warn('⚠️ 无效的图片数据:', data?.substring(0, 50) + '...');
-      }
-      return isValid;
-    });
-
-    if (validImages.length === 0) {
-      window?.fmode?.alert('图片处理失败,请重新上传。\n提示:\n• 支持JPG/PNG/GIF/WebP等格式\n• 单张图片最大50MB\n• 超过5MB会自动压缩\n• 支持同时上传多张图片');
-      // 清空无效的图片列表
-      this.aiDesignUploadedImages = [];
-      this.aiDesignUploadedFiles = [];
-      this.cdr.markForCheck();
-      return;
-    }
-
-    if (validImages.length < this.aiDesignUploadedImages.length) {
-      console.warn(`⚠️ 发现${this.aiDesignUploadedImages.length - validImages.length}个无效图片,已自动过滤`);
-      this.aiDesignUploadedImages = validImages;
-    }
-
-    console.log('✅ 验证通过,有效图片数量:', validImages.length);
-    console.log('📸 图片格式:', validImages.map(img => img.startsWith('data:') ? 'base64' : 'URL'));
-
-    try {
-      // 🔥 支持多轮对话:如果已有对话记录,将新上传的图片作为补充分析
-      const isFollowUp = this.aiChatMessages.length > 0;
-      
-      if (isFollowUp) {
-        console.log('📌 检测到已有对话记录,将作为补充分析');
-      }
-      // 添加用户消息(简短描述,不显示完整提示词)
-      const userMessage = {
-        id: `user-${Date.now()}`,
-        role: 'user' as const,
-        content: this.aiDesignTextDescription || `请对这${this.aiDesignUploadedImages.length}张参考图片进行专业的室内设计分析`,
-        timestamp: new Date(),
-        images: [...this.aiDesignUploadedImages]
-      };
-      
-      this.aiChatMessages.push(userMessage);
-
-      // 添加AI流式输出消息(初始为空,会实时更新)
-      const aiStreamMessage = {
-        id: `ai-${Date.now()}`,
-        role: 'assistant' as const,
-        content: '', // 初始为空,会实时更新
-        timestamp: new Date(),
-        isStreaming: true // 标记为流式输出中
-      };
-      
-      this.aiChatMessages.push(aiStreamMessage);
-      this.aiDesignAnalyzing = true;
-      this.cdr.markForCheck();
-
-      // 滚动到底部
-      this.scrollToBottom();
-
-      // 🔥 构建对话历史(排除当前正在添加的消息和流式输出中的消息)
-      const conversationHistory = this.aiChatMessages
-        .filter(m => m.id !== userMessage.id && m.id !== aiStreamMessage.id && !m.isStreaming)
-        .map(m => ({
-          role: m.role,
-          content: m.content || ''
-        }));
-
-      // 直接调用AI分析服务
-      console.log('🤖 开始AI图片分析...');
-      console.log('📸 图片数量:', this.aiDesignUploadedImages.length);
-      console.log('🏠 空间类型:', this.aiDesignCurrentSpace?.name);
-      console.log('💬 对话历史数量:', conversationHistory.length, '条');
-
-      const analysisResult = await this.designAnalysisAIService.analyzeReferenceImages({
-        images: this.aiDesignUploadedImages,
-        textDescription: this.aiDesignTextDescription,
-        // 🔥 不传递spaceType,让AI基于图片内容自动识别空间类型
-        spaceType: undefined,
-        conversationHistory: conversationHistory, // 🔥 传递对话历史,支持多轮对话
-        deepThinking: this.deepThinkingEnabled,
-        onProgressChange: (progress) => {
-          console.log('📊 AI分析进度:', progress);
-        },
-        // 🔥 流式输出回调:实时更新消息内容
-        onContentStream: (content) => {
-          const streamMsg = this.aiChatMessages.find(m => m.id === aiStreamMessage.id);
-          if (streamMsg) {
-            streamMsg.content = content;
-            this.cdr.markForCheck();
-            // 滚动到底部以显示新内容
-            setTimeout(() => this.scrollToBottom(), 50);
-          }
-        }
-      });
-
-      // 标记流式输出完成(保留流式输出的原始内容,不再重新格式化)
-      const finalMsg = this.aiChatMessages.find(m => m.id === aiStreamMessage.id);
-      if (finalMsg) {
-        finalMsg.isStreaming = false;
-        // 保持流式输出的内容不变,已经是完整的AI返回内容
-      }
-      
-      // 保存最新的分析结果
-      this.aiDesignAnalysisResult = analysisResult;
-
-      // 保存对话记录到项目
-      await this.saveChatHistory();
-
-      console.log('✅ AI分析完成');
-
-      // 滚动到底部
-      this.scrollToBottom();
-
-    } catch (error: any) {
-      console.error('❌ AI分析失败:', error);
-      
-      // 移除流式输出消息或加载消息
-      this.aiChatMessages = this.aiChatMessages.filter(m => !m.isLoading && !m.isStreaming);
-      
-      // 添加错误消息
-      this.aiChatMessages.push({
-        id: `ai-error-${Date.now()}`,
-        role: 'assistant' as const,
-        content: `抱歉,分析过程出现错误:${error.message || '未知错误'}。请重试。`,
-        timestamp: new Date()
-      });
-
-      window?.fmode?.alert('AI分析失败: ' + (error.message || '未知错误'));
-    } finally {
-      this.aiDesignAnalyzing = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  /**
-   * 生成客户报告
-   */
-  async generateClientReport(): Promise<void> {
-    if (!this.aiDesignAnalysisResult) {
-      window?.fmode?.alert('请先完成AI分析');
-      return;
-    }
-
-    try {
-      this.aiDesignGeneratingReport = true;
-      this.aiDesignReport = '';
-      this.cdr.markForCheck();
-
-      console.log('📝 开始生成报告...');
-
-      this.aiDesignReport = await this.designAnalysisAIService.generateClientReport({
-        analysisData: this.aiDesignAnalysisResult,
-        spaceName: this.aiDesignCurrentSpace?.name || '空间',
-        onContentChange: (content) => {
-          this.aiDesignReport = content;
-          this.cdr.markForCheck();
-        }
-      });
-
-      console.log('✅ 报告生成完成');
-      this.cdr.markForCheck();
-
-    } catch (error: any) {
-      console.error('❌ 生成报告失败:', error);
-      window?.fmode?.alert('生成报告失败: ' + (error.message || '未知错误'));
-    } finally {
-      this.aiDesignGeneratingReport = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  /**
-   * 确认报告
-   */
-  async confirmDesignReport(): Promise<void> {
-    if (!this.aiDesignReport) {
-      window?.fmode?.alert('报告尚未生成');
-      return;
-    }
-
-    try {
-      this.aiDesignReportConfirmed = true;
-
-      if (this.project && this.aiDesignCurrentSpace?.id) {
-        const projectData = this.project.get('data') || {};
-        
-        if (!projectData.designReports) {
-          projectData.designReports = {};
-        }
-
-        projectData.designReports[this.aiDesignCurrentSpace.id] = {
-          report: this.aiDesignReport,
-          analysisData: this.aiDesignAnalysisResult,
-          images: this.aiDesignUploadedImages,
-          files: this.aiDesignUploadedFiles,
-          textDescription: this.aiDesignTextDescription,
-          confirmedAt: new Date().toISOString(),
-          confirmedBy: this.currentUser?.id || 'unknown'
-        };
-        
-        console.log('💾 保存数据:', {
-          spaceId: this.aiDesignCurrentSpace.id,
-          spaceName: this.aiDesignCurrentSpace.name,
-          imagesCount: this.aiDesignUploadedImages.length,
-          filesCount: this.aiDesignUploadedFiles.length,
-          hasAnalysisResult: !!this.aiDesignAnalysisResult,
-          hasReport: !!this.aiDesignReport
-        });
-
-        this.project.set('data', projectData);
-        await this.project.save();
-
-        console.log('✅ 报告已保存');
-      }
-
-      window?.fmode?.alert('设计分析报告已确认并保存');
-      this.cdr.markForCheck();
-
-    } catch (error) {
-      console.error('❌ 保存报告失败:', error);
-      window?.fmode?.alert('保存报告失败,请重试');
-    }
-  }
-
-  /**
-   * 获取场景类型中文名
-   */
-  getSceneTypeName(type: string): string {
-    const typeMap: { [key: string]: string } = {
-      '客餐厅': '客餐厅',
-      '厨房': '厨房',
-      '卧室': '卧室',
-      '阳台': '阳台',
-      '卫生间': '卫生间',
-      '其他': '其他'
-    };
-    return typeMap[type] || type;
-  }
-
-  /**
-   * 获取空间基调图标
-   */
-  getSpaceToneIcon(tone: string): string {
-    const toneIcons: Record<string, string> = {
-      '温馨': '🏡',
-      '现代': '🏢',
-      '轻奢': '💎',
-      '简约': '⬜',
-      '古典': '🏛️',
-      '自然': '🌿'
-    };
-    return toneIcons[tone] || '🏠';
-  }
-
-  // ===== AI对话系统功能方法 =====
-
-  /**
-   * 输入框变化事件 - 自动调整高度
-   */
-  onChatInputChange(event: any): void {
-    const textarea = event.target;
-    if (textarea) {
-      textarea.style.height = 'auto';
-      textarea.style.height = Math.min(textarea.scrollHeight, 150) + 'px';
-    }
-  }
-
-  /**
-   * 输入框回车事件 - Shift+Enter换行,Enter发送
-   */
-  onChatInputEnter(event: Event): void {
-    const keyEvent = event as KeyboardEvent;
-    if (keyEvent.key === 'Enter' && !keyEvent.shiftKey) {
-      keyEvent.preventDefault();
-      this.sendChatMessage();
-    }
-  }
-
-  /**
-   * 使用快捷提示
-   */
-  useQuickPrompt(prompt: string): void {
-    this.aiChatInput = prompt;
-    this.cdr.markForCheck();
-    
-    // 聚焦到输入框
-    setTimeout(() => {
-      this.chatInputElement?.nativeElement?.focus();
-    }, 100);
-  }
-
-  /**
-   * 发送聊天消息
-   */
-  async sendChatMessage(): Promise<void> {
-    const message = this.aiChatInput?.trim();
-    
-    if (!message || this.aiDesignAnalyzing) {
-      return;
-    }
-
-    // 🔥 优化:如果已有对话历史,允许继续对话;否则需要先上传图片
-    if (this.aiDesignUploadedImages.length === 0 && this.aiChatMessages.length === 0) {
-      window?.fmode?.alert('请先上传参考图片开始分析');
-      return;
-    }
-
-    // 如果没有图片但有对话历史,使用之前的图片继续对话
-    const imagesToUse = this.aiDesignUploadedImages.length > 0 
-      ? this.aiDesignUploadedImages 
-      : this.getPreviousImages();
-
-    if (imagesToUse.length === 0) {
-      window?.fmode?.alert('请先上传参考图片');
-      return;
-    }
-
-    try {
-      // 添加用户消息
-      const userMessage = {
-        id: `user-${Date.now()}`,
-        role: 'user' as const,
-        content: message,
-        timestamp: new Date(),
-        images: [...imagesToUse]
-      };
-      
-      this.aiChatMessages.push(userMessage);
-      this.aiChatInput = '';
-      
-      // 重置输入框高度
-      if (this.chatInputElement) {
-        this.chatInputElement.nativeElement.style.height = 'auto';
-      }
-
-      // 添加AI流式输出消息(初始为空,会实时更新)
-      const aiStreamMessage = {
-        id: `ai-${Date.now()}`,
-        role: 'assistant' as const,
-        content: '', // 初始为空,会实时更新
-        timestamp: new Date(),
-        isStreaming: true // 标记为流式输出中
-      };
-      
-      this.aiChatMessages.push(aiStreamMessage);
-      this.aiDesignAnalyzing = true;
-      this.cdr.markForCheck();
-
-      // 滚动到底部
-      this.scrollToBottom();
-
-      // 🔥 构建对话历史(排除当前消息和流式输出中的消息)
-      const conversationHistory = this.aiChatMessages
-        .filter(m => 
-          m.id !== userMessage.id && 
-          m.id !== aiStreamMessage.id && 
-          !m.isStreaming && 
-          m.content && 
-          m.content.trim().length > 0
-        )
-        .map(m => ({
-          role: m.role,
-          content: m.content || ''
-        }));
-
-      // 🔥 使用真正的AI对话功能(而不是重复分析)
-      console.log('💬 开始AI对话...');
-      console.log('📜 对话历史数量:', conversationHistory.length, '条');
-      console.log('📸 使用图片数量:', imagesToUse.length, '张');
-
-      const aiResponse = await this.designAnalysisAIService.chatWithAI({
-        userMessage: message,
-        conversationHistory: conversationHistory,
-        images: imagesToUse,
-        // 🔥 流式输出回调:实时更新消息内容
-        onContentStream: (content) => {
-          const streamMsg = this.aiChatMessages.find(m => m.id === aiStreamMessage.id);
-          if (streamMsg) {
-            streamMsg.content = content;
-            this.cdr.markForCheck();
-            // 滚动到底部以显示新内容
-            setTimeout(() => this.scrollToBottom(), 50);
-          }
-        }
-      });
-
-      // 标记流式输出完成
-      const finalMsg = this.aiChatMessages.find(m => m.id === aiStreamMessage.id);
-      if (finalMsg) {
-        finalMsg.isStreaming = false;
-        finalMsg.content = aiResponse; // 确保内容是最终的响应
-      }
-
-      // 保存对话记录到项目
-      await this.saveChatHistory();
-
-      console.log('✅ AI对话完成');
-
-      // 滚动到底部
-      this.scrollToBottom();
-
-    } catch (error: any) {
-      console.error('❌ AI对话失败:', error);
-      
-      // 移除流式输出消息或加载消息
-      this.aiChatMessages = this.aiChatMessages.filter(m => !m.isLoading && !m.isStreaming);
-      
-      // 添加错误消息
-      this.aiChatMessages.push({
-        id: `ai-error-${Date.now()}`,
-        role: 'assistant' as const,
-        content: `抱歉,分析过程出现错误:${error.message || '未知错误'}。请重试或修改您的问题。`,
-        timestamp: new Date()
-      });
-
-      window?.fmode?.alert('AI分析失败: ' + (error.message || '未知错误'));
-    } finally {
-      this.aiDesignAnalyzing = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  /**
-   * 获取之前对话中使用的图片
-   */
-  private getPreviousImages(): string[] {
-    // 从对话历史中获取最近的用户消息的图片
-    for (let i = this.aiChatMessages.length - 1; i >= 0; i--) {
-      const message = this.aiChatMessages[i];
-      if (message.role === 'user' && message.images && message.images.length > 0) {
-        console.log('📸 使用之前对话中的图片继续分析,图片数量:', message.images.length);
-        return message.images;
-      }
-    }
-    
-    // 如果对话历史中没有图片,尝试从分析结果中获取
-    if (this.aiDesignAnalysisResult && this.aiDesignUploadedImages.length > 0) {
-      console.log('📸 使用初始分析的图片继续对话');
-      return this.aiDesignUploadedImages;
-    }
-    
-    return [];
-  }
-
-  /**
-   * 格式化AI响应(优化显示效果)
-   */
-  private formatAIResponse(analysisResult: any): string {
-    if (!analysisResult) {
-      return '❌ 分析结果为空';
-    }
-
-    // 如果有原始内容,直接使用(AI返回的是纯文字格式)
-    if (analysisResult.rawContent) {
-      return analysisResult.rawContent;
-    }
-
-    // 否则格式化结构化数据(兼容模式)
-    let response = '';
-
-    // 添加分析标题
-    response += `# ✨ AI设计分析报告\n\n`;
-    response += `> 基于豆包1.6模型的"灯光+材质"细节落地分析\n\n`;
-    response += `---\n\n`;
-
-    // 场景识别
-    if (analysisResult.sceneRecognition && Object.keys(analysisResult.sceneRecognition).length > 0) {
-      response += `## 🏠 场景识别\n\n`;
-      if (analysisResult.sceneRecognition.spaceType) {
-        response += `- **空间类型**:${analysisResult.sceneRecognition.spaceType}\n`;
-      }
-      if (analysisResult.sceneRecognition.confidence) {
-        response += `- **识别置信度**:${analysisResult.sceneRecognition.confidence}\n`;
-      }
-      if (analysisResult.sceneRecognition.evidence) {
-        response += `- **识别依据**:${analysisResult.sceneRecognition.evidence}\n`;
-      }
-      response += '\n';
-    }
-
-    // 整体基调
-    if (analysisResult.overallTone && Object.keys(analysisResult.overallTone).length > 0) {
-      response += `## 🎭 整体基调\n\n`;
-      if (analysisResult.overallTone.primary) {
-        response += `- **主基调**:${analysisResult.overallTone.primary}\n`;
-      }
-      if (analysisResult.overallTone.secondary) {
-        response += `- **次基调**:${analysisResult.overallTone.secondary}\n`;
-      }
-      if (analysisResult.overallTone.description) {
-        response += `- **基调特征**:${analysisResult.overallTone.description}\n`;
-      }
-      response += '\n';
-    }
-
-    // 设计维度分析
-    if (analysisResult.designDimensions) {
-      response += `## 🎨 设计维度分析\n\n`;
-      
-      const dims = analysisResult.designDimensions;
-      
-      if (dims.colorSystem) {
-        response += `### 🌈 色彩系统\n\n`;
-        if (dims.colorSystem.primaryColors?.length > 0) {
-          response += `- **主色调**:${dims.colorSystem.primaryColors.join(', ')}\n`;
-        }
-        if (dims.colorSystem.secondaryColors?.length > 0) {
-          response += `- **辅助色**:${dims.colorSystem.secondaryColors.join(', ')}\n`;
-        }
-        response += '\n';
-      }
-
-      if (dims.lightingDesign) {
-        response += `### 💡 灯光设计\n\n`;
-        response += `${dims.lightingDesign.description || '暂无描述'}\n\n`;
-      }
-
-      if (dims.materialAnalysis) {
-        response += `### 🏗️ 材质分析\n\n`;
-        response += `${dims.materialAnalysis.description || '暂无描述'}\n\n`;
-      }
-    }
-
-    // 优化建议
-    if (analysisResult.suggestions && analysisResult.suggestions.length > 0) {
-      response += `## ✨ 专业优化建议\n\n`;
-      analysisResult.suggestions.forEach((suggestion: string, index: number) => {
-        response += `${index + 1}. ${suggestion}\n`;
-      });
-      response += '\n';
-    }
-
-    return this.enhanceMarkdownFormat(response);
-  }
-
-  /**
-   * 增强Markdown格式(添加更多视觉元素)
-   */
-  private enhanceMarkdownFormat(content: string): string {
-    // 为表格添加样式标记
-    let enhanced = content;
-    
-    // 确保表格格式正确
-    enhanced = enhanced.replace(/\n\|/g, '\n|');
-    
-    // 为重要信息添加强调
-    enhanced = enhanced.replace(/RGB\((\d+),\s*(\d+),\s*(\d+)\)/g, '**RGB($1, $2, $3)**');
-    enhanced = enhanced.replace(/(\d+)lux/g, '**$1lux**');
-    enhanced = enhanced.replace(/(\d+)K/g, '**$1K**');
-    enhanced = enhanced.replace(/Ra(\d+)/g, '**Ra$1**');
-    enhanced = enhanced.replace(/(\d+)mm/g, '**$1mm**');
-    
-    return enhanced;
-  }
-
-  /**
-   * 格式化消息内容 - 纯文本美观排版
-   */
-  formatMessageContent(content: string): string {
-    if (!content) return '';
-
-    let formatted = content;
-    
-    // 将连续的换行符转换为段落
-    formatted = formatted.replace(/\n\n+/g, '</p><p class="content-paragraph">');
-    
-    // 单个换行符转换为 <br>
-    formatted = formatted.replace(/\n/g, '<br>');
-    
-    // 包裹在段落标签中
-    formatted = `<p class="content-paragraph">${formatted}</p>`;
-    
-    // 识别并标记标题行(以中文冒号或数字开头的行)
-    formatted = formatted.replace(/<p class="content-paragraph">([一二三四五六七八九十]+、.*?)<br>/g, '<h4 class="content-heading">$1</h4><p class="content-paragraph">');
-    formatted = formatted.replace(/<p class="content-paragraph">(\d+[\.|、].*?)<br>/g, '<h4 class="content-heading">$1</h4><p class="content-paragraph">');
-    
-    // 识别列表项(以 - 或 • 开头)
-    formatted = formatted.replace(/- (.*?)<br>/g, '<li class="content-list-item">$1</li>');
-    formatted = formatted.replace(/• (.*?)<br>/g, '<li class="content-list-item">$1</li>');
-    
-    // 包裹连续的列表项
-    formatted = formatted.replace(/(<li class="content-list-item">.*?<\/li>)+/g, '<ul class="content-list">$&</ul>');
-    
-    // 清理空段落
-    formatted = formatted.replace(/<p class="content-paragraph"><\/p>/g, '');
-
-    return formatted;
-  }
-
-  /**
-   * 保存对话历史到项目
-   */
-  private async saveChatHistory(): Promise<void> {
-    if (!this.project || !this.aiDesignCurrentSpace?.id) {
-      return;
-    }
-
-    try {
-      const projectData = this.project.get('data') || {};
-      
-      if (!projectData.aiChatHistory) {
-        projectData.aiChatHistory = {};
-      }
-
-      projectData.aiChatHistory[this.aiDesignCurrentSpace.id] = {
-        messages: this.aiChatMessages.map(m => ({
-          role: m.role,
-          content: m.content,
-          timestamp: m.timestamp.toISOString(),
-          images: m.images
-        })),
-        lastUpdated: new Date().toISOString()
-      };
-
-      this.project.set('data', projectData);
-      await this.project.save();
-
-      console.log('💾 对话历史已保存');
-    } catch (error) {
-      console.error('保存对话历史失败:', error);
-    }
-  }
-
-  /**
-   * 滚动到底部
-   */
-  private scrollToBottom(): void {
-    setTimeout(() => {
-      if (this.chatMessagesWrapper) {
-        const element = this.chatMessagesWrapper.nativeElement;
-        element.scrollTop = element.scrollHeight;
-      }
-    }, 100);
-  }
-
-  /**
-   * 打开附件对话框
-   */
-  openAttachmentDialog(): void {
-    console.log('📎 打开附件对话框');
-    // 触发文件上传
-    const fileInput = document.getElementById('aiDesignFileInput') as HTMLInputElement;
-    if (fileInput) {
-      fileInput.click();
-    }
-  }
-
-  /**
-   * 切换深度思考模式
-   */
-  toggleDeepThinking(): void {
-    this.deepThinkingEnabled = !this.deepThinkingEnabled;
-    console.log('💡 深度思考模式:', this.deepThinkingEnabled ? '已开启' : '已关闭');
-    
-    const status = this.deepThinkingEnabled ? '已开启' : '已关闭';
-    window?.fmode?.alert(`深度思考模式${status}`);
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 复制消息内容
-   */
-  copyMessage(content: string): void {
-    if (!content) return;
-
-    // 移除HTML标签
-    const textContent = content.replace(/<[^>]*>/g, '').replace(/&nbsp;/g, ' ');
-
-    navigator.clipboard.writeText(textContent).then(() => {
-      console.log('📋 消息已复制');
-      window?.fmode?.alert('消息已复制到剪贴板');
-    }).catch(err => {
-      console.error('复制失败:', err);
-      window?.fmode?.alert('复制失败');
-    });
-  }
-
-  /**
-   * 重新生成消息
-   */
-  async regenerateMessage(message: any): Promise<void> {
-    // 找到该消息的索引
-    const index = this.aiChatMessages.findIndex(m => m.id === message.id);
-    if (index === -1) return;
-
-    // 找到之前的用户消息
-    let userMessageIndex = index - 1;
-    while (userMessageIndex >= 0 && this.aiChatMessages[userMessageIndex].role !== 'user') {
-      userMessageIndex--;
-    }
-
-    if (userMessageIndex < 0) {
-      window?.fmode?.alert('找不到对应的用户消息');
-      return;
-    }
-
-    const userMessage = this.aiChatMessages[userMessageIndex];
-
-    // 移除当前AI消息
-    this.aiChatMessages.splice(index, 1);
-
-    // 重新发送
-    this.aiChatInput = userMessage.content;
-    await this.sendChatMessage();
-  }
-
-  /**
-   * 点赞消息
-   */
-  likeMessage(message: any): void {
-    message.liked = !message.liked;
-    if (message.liked) {
-      message.disliked = false;
-    }
-    console.log('👍 消息反馈: 有帮助');
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 点踩消息
-   */
-  dislikeMessage(message: any): void {
-    message.disliked = !message.disliked;
-    if (message.disliked) {
-      message.liked = false;
-    }
-    console.log('👎 消息反馈: 无帮助');
-    this.cdr.markForCheck();
-  }
-
-  /**
-   * 清空对话
-   */
-  clearChat(): void {
-    if (this.aiChatMessages.length === 0) return;
-
-    if (confirm('确定要清空所有对话记录吗?')) {
-      this.aiChatMessages = [];
-      this.aiChatInput = '';
-      console.log('🗑️ 对话已清空');
-      window?.fmode?.alert('对话已清空');
-      this.cdr.markForCheck();
-    }
-  }
-
-  /**
-   * 导出对话
-   */
-  exportChat(): void {
-    if (this.aiChatMessages.length === 0) {
-      window?.fmode?.alert('没有对话记录可导出');
-      return;
-    }
-
-    let exportContent = `# AI设计分析对话记录\n\n`;
-    exportContent += `项目: ${this.project?.get('name') || '未命名项目'}\n`;
-    exportContent += `空间: ${this.aiDesignCurrentSpace?.name || '未知空间'}\n`;
-    exportContent += `导出时间: ${new Date().toLocaleString()}\n\n`;
-    exportContent += `---\n\n`;
-
-    this.aiChatMessages.forEach((message, index) => {
-      const role = message.role === 'user' ? '👤 用户' : '🤖 AI助手';
-      const time = message.timestamp.toLocaleTimeString();
-      const content = message.content.replace(/<[^>]*>/g, '').replace(/&nbsp;/g, ' ');
-
-      exportContent += `## ${role} [${time}]\n\n`;
-      exportContent += `${content}\n\n`;
-      
-      if (message.images && message.images.length > 0) {
-        exportContent += `附图: ${message.images.length} 张\n\n`;
-      }
-      
-      exportContent += `---\n\n`;
-    });
-
-    // 创建下载
-    const blob = new Blob([exportContent], { type: 'text/markdown;charset=utf-8' });
-    const url = URL.createObjectURL(blob);
-    const link = document.createElement('a');
-    link.href = url;
-    link.download = `AI对话记录_${this.aiDesignCurrentSpace?.name}_${Date.now()}.md`;
-    document.body.appendChild(link);
-    link.click();
-    document.body.removeChild(link);
-    URL.revokeObjectURL(url);
-
-    console.log('💾 对话已导出');
-    window?.fmode?.alert('对话已导出');
-  }
-
-  /**
-   * 确认当前分析结果
-   */
-  async confirmCurrentAnalysis(): Promise<void> {
-    if (this.aiChatMessages.length === 0) {
-      window?.fmode?.alert('没有分析结果可确认');
-      return;
-    }
-
-    try {
-      // 整合所有AI回复作为最终报告
-      const aiReplies = this.aiChatMessages
-        .filter(m => m.role === 'assistant' && m.content && !m.isLoading)
-        .map(m => m.content)
-        .join('\n\n---\n\n');
-
-      this.aiDesignReport = aiReplies;
-      this.aiDesignReportConfirmed = true;
-
-      // 保存到项目
-      if (this.project && this.aiDesignCurrentSpace?.id) {
-        const projectData = this.project.get('data') || {};
-        
-        if (!projectData.designReports) {
-          projectData.designReports = {};
-        }
-
-        projectData.designReports[this.aiDesignCurrentSpace.id] = {
-          report: this.aiDesignReport,
-          analysisData: this.aiDesignAnalysisResult,
-          images: this.aiDesignUploadedImages,
-          files: this.aiDesignUploadedFiles,
-          chatHistory: this.aiChatMessages.map(m => ({
-            role: m.role,
-            content: m.content,
-            timestamp: m.timestamp.toISOString()
-          })),
-          confirmedAt: new Date().toISOString(),
-          confirmedBy: this.currentUser?.id || 'unknown'
-        };
-
-        this.project.set('data', projectData);
-        await this.project.save();
-
-        console.log('✅ 分析结果已确认并保存');
-        
-        // 询问是否生成客户报告
-        const result = await window?.fmode?.confirm(
-          '分析结果已保存!\n\n是否立即生成客户报告?\n客户报告将整理分析结果为专业的结构化文档,可直接发送给客户。'
-        );
-        
-        if (result) {
-          await this.generateAndShowClientReport();
-        } else {
-          window?.fmode?.alert('已保存分析结果,您可以稍后在报告区域生成客户报告。');
-        }
-        
-        this.cdr.markForCheck();
-      }
-    } catch (error) {
-      console.error('❌ 确认分析结果失败:', error);
-      window?.fmode?.alert('确认失败,请重试');
-    }
-  }
-
-  /**
-   * 生成并显示客户报告
-   */
-  async generateAndShowClientReport(): Promise<void> {
-    if (!this.aiDesignReport) {
-      window?.fmode?.alert('请先确认分析结果');
-      return;
-    }
-
-    // 设置生成状态
-    this.aiDesignGeneratingReport = true;
-    this.cdr.markForCheck();
-
-    try {
-      console.log('🤖 正在生成客户报告...');
-
-      // 调用AI服务生成结构化客户报告
-      const clientReport = await this.designAnalysisAIService.generateClientReport({
-        analysisData: {
-          report: this.aiDesignReport,
-          analysisResult: this.aiDesignAnalysisResult,
-          spaceInfo: this.aiDesignCurrentSpace
-        },
-        spaceName: this.aiDesignCurrentSpace?.name || '未命名空间',
-        onContentChange: (content) => {
-          console.log('📝 报告生成中...', content.length, '字');
-        }
-      });
-
-      // 保存客户报告
-      if (this.project && this.aiDesignCurrentSpace?.id) {
-        const projectData = this.project.get('data') || {};
-        
-        if (!projectData.designReports) {
-          projectData.designReports = {};
-        }
-
-        if (!projectData.designReports[this.aiDesignCurrentSpace.id]) {
-          projectData.designReports[this.aiDesignCurrentSpace.id] = {};
-        }
-
-        projectData.designReports[this.aiDesignCurrentSpace.id].clientReport = clientReport;
-        projectData.designReports[this.aiDesignCurrentSpace.id].clientReportGeneratedAt = new Date().toISOString();
-
-        this.project.set('data', projectData);
-        await this.project.save();
-      }
-
-      console.log('✅ 客户报告生成完成');
-      
-      // 显示成功提示
-      window?.fmode?.toast?.success?.('客户报告生成成功!');
-      
-      // 询问是否查看报告
-      const result = await window?.fmode?.confirm(
-        `客户报告已生成并保存!\n\n您可以:\n1. 在项目详情中查看完整报告\n2. 导出为PDF发送给客户\n3. 复制内容分享给客户\n\n是否立即查看报告?`
-      );
-
-      if (result) {
-        // TODO: 这里可以打开报告预览对话框或跳转到报告页面
-        window?.fmode?.alert('报告预览功能开发中,敬请期待!');
-      }
-
-    } catch (error: any) {
-      console.error('❌ 生成客户报告失败:', error);
-      window?.fmode?.alert('生成报告失败: ' + (error.message || '未知错误'));
-    } finally {
-      // 恢复状态
-      this.aiDesignGeneratingReport = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  /**
-   * 打开技能对话框
-   */
-  openSkillsDialog(): void {
-    console.log('🧩 打开技能对话框');
-    window?.fmode?.alert('技能功能开发中...');
-  }
-
-  /**
-   * 剪切文本
-   */
-  cutText(): void {
-    const selection = window.getSelection();
-    const selectedText = selection?.toString();
-    
-    if (selectedText) {
-      // 复制到剪贴板
-      navigator.clipboard.writeText(selectedText).then(() => {
-        console.log('✂️ 文本已剪切:', selectedText);
-        window?.fmode?.alert('文本已剪切');
-        
-        // 删除选中的文本
-        const textarea = document.querySelector('.compact-editor-input') as HTMLTextAreaElement;
-        if (textarea) {
-          const start = textarea.selectionStart;
-          const end = textarea.selectionEnd;
-          const text = textarea.value;
-          this.aiDesignTextDescription = text.substring(0, start) + text.substring(end);
-          this.cdr.markForCheck();
-        }
-      }).catch(err => {
-        console.error('剪切失败:', err);
-      });
-    } else {
-      window?.fmode?.alert('请先选择要剪切的文本');
-    }
-  }
-
-  /**
-   * 开始语音通话
-   */
-  startVoiceCall(): void {
-    console.log('📞 开始语音通话');
-    window?.fmode?.alert('语音通话功能开发中...');
-  }
-
-  /**
-   * 开始语音输入
-   */
-  startVoiceInput(): void {
-    console.log('🎤 开始语音输入');
-    
-    // 检查浏览器是否支持语音识别
-    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
-    
-    if (!SpeechRecognition) {
-      window?.fmode?.toast?.error?.('您的浏览器不支持语音识别功能,请使用Chrome或Edge浏览器');
-      return;
-    }
-
-    const recognition = new SpeechRecognition();
-    recognition.lang = 'zh-CN'; // 中文识别
-    recognition.continuous = false; // 单次识别
-    recognition.interimResults = false; // 不显示中间结果
-
-    recognition.onstart = () => {
-      console.log('🎤 语音识别已启动');
-      window?.fmode?.toast?.success?.('🎤 正在录音,请说话...');
-    };
-
-    recognition.onresult = (event: any) => {
-      const transcript = event.results[0][0].transcript;
-      const confidence = event.results[0][0].confidence;
-      console.log('🎤 识别结果:', transcript, '置信度:', confidence);
-      
-      // 将识别结果添加到对话输入框
-      if (this.aiChatInput) {
-        this.aiChatInput += ' ' + transcript;
-      } else {
-        this.aiChatInput = transcript;
-      }
-      
-      // 更新UI
-      this.cdr.markForCheck();
-      
-      // 聚焦到输入框
-      if (this.chatInputElement) {
-        this.chatInputElement.nativeElement.focus();
-      }
-      
-      // 显示成功提示
-      window?.fmode?.toast?.success?.(`✅ 识别成功: ${transcript}`);
-    };
-
-    recognition.onerror = (event: any) => {
-      console.error('🎤 语音识别错误:', event.error);
-      
-      // 根据不同的错误类型提供友好的提示
-      let errorMessage = '语音识别失败';
-      
-      switch (event.error) {
-        case 'no-speech':
-          errorMessage = '未检测到语音,请重试并大声说话';
-          break;
-        case 'audio-capture':
-          errorMessage = '无法访问麦克风,请检查权限设置';
-          break;
-        case 'not-allowed':
-          errorMessage = '麦克风权限被拒绝,请在浏览器设置中允许麦克风访问';
-          break;
-        case 'network':
-          errorMessage = '网络错误,请检查网络连接';
-          break;
-        case 'aborted':
-          errorMessage = '语音识别已中止';
-          break;
-        default:
-          errorMessage = `语音识别错误: ${event.error}`;
-      }
-      
-      window?.fmode?.toast?.error?.(errorMessage);
-    };
-
-    recognition.onend = () => {
-      console.log('🎤 语音识别已结束');
-    };
-
-    try {
-      recognition.start();
-    } catch (error: any) {
-      console.error('启动语音识别失败:', error);
-      
-      // 检查是否是因为正在进行中
-      if (error.message && error.message.includes('already started')) {
-        window?.fmode?.toast?.warning?.('语音识别已在进行中');
-      } else {
-        window?.fmode?.toast?.error?.('启动语音识别失败,请重试');
-      }
-    }
-  }
-
-  /**
-   * 导出AI分析报告为Word文档
-   */
-  async exportReportToWord(): Promise<void> {
-    if (!this.aiDesignReport && !this.aiDesignAnalysisResult) {
-      window?.fmode?.alert('没有可导出的报告内容');
-      return;
-    }
-
-    this.exportingWord = true;
-    this.cdr.markForCheck();
-
-    try {
-      // 动态导入docx库
-      const { Document, Paragraph, TextRun, HeadingLevel, AlignmentType, Packer } = await import('docx');
-      
-      console.log('📄 开始生成Word文档...');
-
-      // 准备报告内容
-      const reportContent = this.aiDesignReport || this.aiDesignAnalysisResult?.formattedContent || this.aiDesignAnalysisResult?.rawContent || '';
-      
-      if (!reportContent) {
-        window?.fmode?.alert('报告内容为空,无法导出');
-        this.exportingWord = false;
-        this.cdr.markForCheck();
-        return;
-      }
-
-      // 解析报告内容为段落
-      const paragraphs: any[] = [];
-      
-      // 添加文档标题
-      paragraphs.push(
-        new Paragraph({
-          text: 'AI设计分析报告',
-          heading: HeadingLevel.HEADING_1,
-          alignment: AlignmentType.CENTER,
-          spacing: { after: 400 }
-        })
-      );
-
-      // 添加项目信息
-      if (this.project) {
-        paragraphs.push(
-          new Paragraph({
-            children: [
-              new TextRun({
-                text: '项目信息',
-                bold: true,
-                size: 28
-              })
-            ],
-            spacing: { before: 200, after: 200 }
-          })
-        );
-
-        paragraphs.push(
-          new Paragraph({
-            children: [
-              new TextRun({
-                text: `项目名称: ${this.project.name || '未命名项目'}`,
-                size: 24
-              })
-            ],
-            spacing: { after: 100 }
-          })
-        );
-
-        if (this.customer) {
-          paragraphs.push(
-            new Paragraph({
-              children: [
-                new TextRun({
-                  text: `客户姓名: ${this.customer.name || '未知'}`,
-                  size: 24
-                })
-              ],
-              spacing: { after: 100 }
-            })
-          );
-        }
-
-        if (this.aiDesignCurrentSpace) {
-          paragraphs.push(
-            new Paragraph({
-              children: [
-                new TextRun({
-                  text: `分析空间: ${this.getSpaceDisplayName(this.aiDesignCurrentSpace)}`,
-                  size: 24
-                })
-              ],
-              spacing: { after: 100 }
-            })
-          );
-        }
-
-        paragraphs.push(
-          new Paragraph({
-            children: [
-              new TextRun({
-                text: `生成时间: ${new Date().toLocaleString('zh-CN')}`,
-                size: 24
-              })
-            ],
-            spacing: { after: 400 }
-          })
-        );
-      }
-
-      // 添加分隔线
-      paragraphs.push(
-        new Paragraph({
-          text: '———————————————————————————————————————————',
-          alignment: AlignmentType.CENTER,
-          spacing: { before: 200, after: 200 }
-        })
-      );
-
-      // 🔥 添加快速总结(如果有)
-      if (this.aiDesignAnalysisResult?.structuredData?.quickSummary) {
-        const qs = this.aiDesignAnalysisResult.structuredData.quickSummary;
-        
-        paragraphs.push(
-          new Paragraph({
-            children: [
-              new TextRun({
-                text: '【图片分析总结】',
-                bold: true,
-                size: 32,
-                color: 'FF6600'
-              })
-            ],
-            spacing: { before: 300, after: 200 }
-          })
-        );
-
-        // 色彩基调
-        paragraphs.push(
-          new Paragraph({
-            children: [
-              new TextRun({
-                text: '🎨 色彩基调: ',
-                bold: true,
-                size: 24
-              }),
-              new TextRun({
-                text: qs.colorTone,
-                size: 24,
-                color: 'D84315'
-              })
-            ],
-            spacing: { after: 150 }
-          })
-        );
-
-        // 主要材质
-        paragraphs.push(
-          new Paragraph({
-            children: [
-              new TextRun({
-                text: '🪵 主要材质: ',
-                bold: true,
-                size: 24
-              }),
-              new TextRun({
-                text: qs.mainMaterials,
-                size: 24,
-                color: '5D4037'
-              })
-            ],
-            spacing: { after: 150 }
-          })
-        );
-
-        // 整体氛围
-        paragraphs.push(
-          new Paragraph({
-            children: [
-              new TextRun({
-                text: '✨ 整体氛围: ',
-                bold: true,
-                size: 24
-              }),
-              new TextRun({
-                text: qs.atmosphere,
-                size: 24,
-                color: '1976D2'
-              })
-            ],
-            spacing: { after: 400 }
-          })
-        );
-
-        // 添加分隔线
-        paragraphs.push(
-          new Paragraph({
-            text: '———————————————————————————————————————————',
-            alignment: AlignmentType.CENTER,
-            spacing: { before: 200, after: 300 }
-          })
-        );
-      }
-
-      // 解析并添加报告内容
-      const lines = reportContent.split('\n');
-      
-      for (let i = 0; i < lines.length; i++) {
-        const line = lines[i].trim();
-        
-        if (!line) {
-          // 空行,添加一个空段落
-          paragraphs.push(new Paragraph({ text: '' }));
-          continue;
-        }
-
-        // 检查是否是标题(一、二、三等)
-        const titleMatch = line.match(/^([一二三四五六七八九十]+、)(.+)$/);
-        if (titleMatch) {
-          paragraphs.push(
-            new Paragraph({
-              children: [
-                new TextRun({
-                  text: line,
-                  bold: true,
-                  size: 28
-                })
-              ],
-              spacing: { before: 300, after: 200 }
-            })
-          );
-        } 
-        // 检查是否是子标题(包含":"的行)
-        else if (line.includes(':') || line.includes(':')) {
-          const parts = line.split(/[::]/);
-          if (parts.length === 2) {
-            paragraphs.push(
-              new Paragraph({
-                children: [
-                  new TextRun({
-                    text: parts[0] + ':',
-                    bold: true,
-                    size: 24
-                  }),
-                  new TextRun({
-                    text: parts[1],
-                    size: 24
-                  })
-                ],
-                spacing: { before: 150, after: 150 }
-              })
-            );
-          } else {
-            paragraphs.push(
-              new Paragraph({
-                children: [
-                  new TextRun({
-                    text: line,
-                    size: 24
-                  })
-                ],
-                spacing: { before: 100, after: 100 }
-              })
-            );
-          }
-        }
-        // 普通段落
-        else {
-          paragraphs.push(
-            new Paragraph({
-              children: [
-                new TextRun({
-                  text: line,
-                  size: 24
-                })
-              ],
-              spacing: { before: 100, after: 100 },
-              alignment: AlignmentType.LEFT
-            })
-          );
-        }
-      }
-
-      // 创建文档
-      const doc = new Document({
-        sections: [{
-          properties: {},
-          children: paragraphs
-        }]
-      });
-
-      // 生成Blob
-      const blob = await Packer.toBlob(doc);
-      
-      // 生成文件名
-      const spaceName = this.aiDesignCurrentSpace ? this.getSpaceDisplayName(this.aiDesignCurrentSpace) : '未知空间';
-      const projectName = this.project?.name || '未命名项目';
-      const timestamp = new Date().toISOString().slice(0, 10);
-      const fileName = `${projectName}-${spaceName}-AI设计分析报告-${timestamp}.docx`;
-
-      // 下载文件
-      const url = window.URL.createObjectURL(blob);
-      const link = document.createElement('a');
-      link.href = url;
-      link.download = fileName;
-      link.click();
-      
-      // 清理
-      window.URL.revokeObjectURL(url);
-
-      console.log('✅ Word文档已生成并下载');
-      window?.fmode?.toast?.success?.('Word文档导出成功!');
-
-    } catch (error: any) {
-      console.error('❌ 导出Word文档失败:', error);
-      window?.fmode?.alert(`导出失败: ${error.message || '未知错误'}\n\n提示:请确保已安装docx依赖包`);
-    } finally {
-      this.exportingWord = false;
-      this.cdr.markForCheck();
-    }
-  }
-
-  /**
-   * 压缩图片
-   * @param file 原始图片文件
-   * @returns 压缩后的Blob文件
-   */
-  private async compressImage(file: File): Promise<File> {
-    return new Promise((resolve, reject) => {
-      const reader = new FileReader();
-      
-      reader.onload = (e: any) => {
-        const img = new Image();
-        
-        img.onload = () => {
-          // 创建canvas
-          const canvas = document.createElement('canvas');
-          const ctx = canvas.getContext('2d');
-          
-          if (!ctx) {
-            reject(new Error('无法创建Canvas上下文'));
-            return;
-          }
-
-          // 计算压缩后的尺寸
-          let width = img.width;
-          let height = img.height;
-          const maxDimension = 2048; // 最大宽度或高度
-          
-          // 如果图片尺寸超过限制,按比例缩小
-          if (width > maxDimension || height > maxDimension) {
-            if (width > height) {
-              height = (height / width) * maxDimension;
-              width = maxDimension;
-            } else {
-              width = (width / height) * maxDimension;
-              height = maxDimension;
-            }
-          }
-          
-          // 设置canvas尺寸
-          canvas.width = width;
-          canvas.height = height;
-          
-          // 绘制图片
-          ctx.drawImage(img, 0, 0, width, height);
-          
-          // 转换为Blob,质量设置为0.7(可调整)
-          canvas.toBlob(
-            (blob) => {
-              if (!blob) {
-                reject(new Error('图片压缩失败'));
-                return;
-              }
-              
-              // 创建新的File对象
-              const compressedFile = new File([blob], file.name, {
-                type: 'image/jpeg', // 统一转为JPEG以获得更好的压缩率
-                lastModified: Date.now()
-              });
-              
-              console.log(`📊 压缩效果: ${(file.size / 1024 / 1024).toFixed(2)}MB → ${(compressedFile.size / 1024 / 1024).toFixed(2)}MB`);
-              console.log(`📊 压缩比例: ${((1 - compressedFile.size / file.size) * 100).toFixed(1)}%`);
-              
-              resolve(compressedFile);
-            },
-            'image/jpeg',
-            0.7 // 质量参数:0.7表示70%质量,平衡质量和文件大小
-          );
-        };
-        
-        img.onerror = () => {
-          reject(new Error('图片加载失败'));
-        };
-        
-        img.src = e.target.result;
-      };
-      
-      reader.onerror = () => {
-        reject(new Error('文件读取失败'));
-      };
-      
-      reader.readAsDataURL(file);
-    });
-  }
-}

+ 24 - 0
src/modules/project/services/design-analysis-ai.service.ts

@@ -1318,6 +1318,7 @@ export class DesignAnalysisAIService {
     userMessage: string;
     conversationHistory: Array<{ role: string; content: string; images?: string[] }>;
     images?: string[];
+    context?: any;
     onContentStream?: (content: string) => void;
   }): Promise<string> {
     console.log('💬 [chatWithAI] 开始AI对话');
@@ -1330,6 +1331,29 @@ export class DesignAnalysisAIService {
         // 构建消息列表(包含历史对话和当前消息)
         const messageList: any[] = [];
 
+        // 🔥 如果有上下文(结构化分析结果),添加为系统提示
+        if (options.context) {
+          console.log('🧠 [chatWithAI] 添加结构化上下文');
+          let contextContent = '';
+          
+          // 如果是完整的分析结果对象
+          if (options.context.structuredData) {
+             contextContent = JSON.stringify(options.context.structuredData);
+          } else {
+             contextContent = JSON.stringify(options.context);
+          }
+          
+          // 限制上下文长度,避免超出token限制
+          if (contextContent.length > 5000) {
+            contextContent = contextContent.substring(0, 5000) + '...';
+          }
+          
+          messageList.push({
+            role: 'system',
+            content: `这是当前设计的详细分析数据,请基于此回答用户问题:\n${contextContent}`
+          });
+        }
+
         // 添加历史对话(但不包含图片,只在首次分析时使用图片)
         options.conversationHistory.forEach(msg => {
           messageList.push({

+ 338 - 0
src/test/delivery-design-cards.html

@@ -0,0 +1,338 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>交付执行 - 方案A:空间进度卡片</title>
+    <style>
+        :root {
+            --primary: #6366f1;
+            --primary-light: #e0e7ff;
+            --success: #10b981;
+            --success-light: #d1fae5;
+            --warning: #f59e0b;
+            --warning-light: #fef3c7;
+            --gray-50: #f9fafb;
+            --gray-100: #f3f4f6;
+            --gray-200: #e5e7eb;
+            --gray-500: #6b7280;
+            --gray-700: #374151;
+            --gray-900: #111827;
+        }
+
+        * { box-sizing: border-box; margin: 0; padding: 0; }
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+            background-color: #f3f4f6;
+            color: var(--gray-900);
+            padding: 20px;
+        }
+
+        .container {
+            max-width: 1200px;
+            margin: 0 auto;
+        }
+
+        .header {
+            margin-bottom: 24px;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+
+        .header h1 { font-size: 24px; font-weight: 700; }
+        .header-stats { display: flex; gap: 16px; }
+        .stat-item {
+            background: white;
+            padding: 8px 16px;
+            border-radius: 8px;
+            box-shadow: 0 1px 2px rgba(0,0,0,0.05);
+            font-size: 14px;
+            color: var(--gray-500);
+        }
+        .stat-value { font-weight: 700; color: var(--primary); margin-left: 4px; }
+
+        /* Space List */
+        .space-list {
+            display: flex;
+            flex-direction: column;
+            gap: 16px;
+        }
+
+        /* Space Card */
+        .space-card {
+            background: white;
+            border-radius: 12px;
+            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+            overflow: hidden;
+            border: 1px solid var(--gray-200);
+        }
+
+        .space-header {
+            padding: 16px 24px;
+            background: linear-gradient(to right, #fff, var(--gray-50));
+            border-bottom: 1px solid var(--gray-200);
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+
+        .space-info { display: flex; align-items: center; gap: 12px; }
+        .space-name { font-size: 18px; font-weight: 600; }
+        .space-meta { color: var(--gray-500); font-size: 13px; }
+        
+        .progress-bar-container {
+            width: 200px;
+            height: 8px;
+            background: var(--gray-200);
+            border-radius: 4px;
+            overflow: hidden;
+        }
+        .progress-bar {
+            height: 100%;
+            background: var(--success);
+            width: 50%; /* Demo value */
+        }
+
+        .space-body {
+            padding: 20px 24px;
+            display: grid;
+            grid-template-columns: repeat(4, 1fr);
+            gap: 20px;
+        }
+
+        /* Stage Column */
+        .stage-col {
+            display: flex;
+            flex-direction: column;
+            gap: 12px;
+        }
+
+        .stage-header-text {
+            font-size: 14px;
+            font-weight: 600;
+            color: var(--gray-700);
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+        .file-count {
+            font-size: 12px;
+            padding: 2px 8px;
+            background: var(--gray-100);
+            border-radius: 12px;
+            color: var(--gray-500);
+        }
+
+        /* Stage Box States */
+        .stage-box {
+            border: 2px dashed var(--gray-200);
+            border-radius: 8px;
+            min-height: 120px;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            justify-content: center;
+            transition: all 0.2s;
+            position: relative;
+            background: var(--gray-50);
+        }
+
+        .stage-box:hover {
+            border-color: var(--primary);
+            background: var(--primary-light);
+            cursor: pointer;
+        }
+
+        /* State: Empty */
+        .stage-box.empty {
+            color: var(--gray-500);
+        }
+        .upload-hint { font-size: 13px; margin-top: 8px; }
+        .icon-upload { font-size: 24px; color: var(--gray-400); }
+
+        /* State: Has Files */
+        .stage-box.filled {
+            border-style: solid;
+            border-color: var(--gray-200);
+            background: white;
+            padding: 8px;
+            display: grid;
+            grid-template-columns: repeat(2, 1fr);
+            grid-template-rows: repeat(2, 1fr);
+            gap: 4px;
+            align-content: start;
+            justify-items: stretch;
+        }
+        
+        .stage-box.filled img {
+            width: 100%;
+            height: 50px;
+            object-fit: cover;
+            border-radius: 4px;
+        }
+
+        .add-more-btn {
+            position: absolute;
+            bottom: 8px;
+            right: 8px;
+            background: rgba(255,255,255,0.9);
+            border: 1px solid var(--gray-200);
+            border-radius: 4px;
+            padding: 4px 8px;
+            font-size: 12px;
+            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
+        }
+
+        /* State: Completed/Verified */
+        .stage-status {
+            margin-top: 4px;
+            font-size: 12px;
+            text-align: center;
+        }
+        .status-tag {
+            display: inline-block;
+            padding: 2px 6px;
+            border-radius: 4px;
+        }
+        .status-pending { color: var(--warning); background: var(--warning-light); }
+        .status-done { color: var(--success); background: var(--success-light); }
+        
+        /* Drag Overlay Mock */
+        .drag-overlay {
+            position: absolute;
+            inset: 0;
+            background: rgba(99, 102, 241, 0.1);
+            border: 2px solid var(--primary);
+            border-radius: 8px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: var(--primary);
+            font-weight: 600;
+            opacity: 0;
+            pointer-events: none;
+        }
+        .stage-box:hover .drag-overlay { opacity: 1; }
+
+        @media (max-width: 768px) {
+            .space-body {
+                grid-template-columns: 1fr;
+            }
+        }
+    </style>
+</head>
+<body>
+
+<div class="container">
+    <div class="header">
+        <h1>交付执行看板</h1>
+        <div class="header-stats">
+            <div class="stat-item">总空间 <span class="stat-value">4</span></div>
+            <div class="stat-item">整体进度 <span class="stat-value">35%</span></div>
+        </div>
+    </div>
+
+    <div class="space-list">
+        
+        <!-- Space 1: Active -->
+        <div class="space-card">
+            <div class="space-header">
+                <div class="space-info">
+                    <span class="space-name">客厅 (Living Room)</span>
+                    <span class="space-meta">35㎡ · 现代简约</span>
+                </div>
+                <div class="progress-bar-container">
+                    <div class="progress-bar" style="width: 50%"></div>
+                </div>
+            </div>
+            <div class="space-body">
+                <!-- Stage 1: Verified -->
+                <div class="stage-col">
+                    <div class="stage-header-text">白模阶段 <span class="file-count">4</span></div>
+                    <div class="stage-box filled">
+                        <img src="https://placehold.co/100x100/e0e7ff/6366f1?text=WM1" alt="thumb">
+                        <img src="https://placehold.co/100x100/e0e7ff/6366f1?text=WM2" alt="thumb">
+                        <img src="https://placehold.co/100x100/e0e7ff/6366f1?text=WM3" alt="thumb">
+                        <div style="background:#f3f4f6;border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:12px;">+1</div>
+                    </div>
+                    <div class="stage-status"><span class="status-tag status-done">✓ 已确认</span></div>
+                </div>
+
+                <!-- Stage 2: In Progress -->
+                <div class="stage-col">
+                    <div class="stage-header-text">软装阶段 <span class="file-count">2</span></div>
+                    <div class="stage-box filled">
+                        <img src="https://placehold.co/100x100/fce7f3/ec4899?text=SD1" alt="thumb">
+                        <img src="https://placehold.co/100x100/fce7f3/ec4899?text=SD2" alt="thumb">
+                        <div class="drag-overlay">拖拽上传</div>
+                    </div>
+                    <div class="stage-status"><span class="status-tag status-pending">● 进行中</span></div>
+                </div>
+
+                <!-- Stage 3: Empty (Next) -->
+                <div class="stage-col">
+                    <div class="stage-header-text">渲染阶段 <span class="file-count">0</span></div>
+                    <div class="stage-box empty">
+                        <span class="icon-upload">📷</span>
+                        <span class="upload-hint">点击或拖拽上传</span>
+                    </div>
+                    <div class="stage-status"><span style="color:#9ca3af;font-size:12px;">未开始</span></div>
+                </div>
+
+                <!-- Stage 4: Empty -->
+                <div class="stage-col">
+                    <div class="stage-header-text">后期阶段 <span class="file-count">0</span></div>
+                    <div class="stage-box empty">
+                        <span class="icon-upload">✨</span>
+                        <span class="upload-hint">等待渲染完成</span>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- Space 2: Empty -->
+        <div class="space-card">
+            <div class="space-header">
+                <div class="space-info">
+                    <span class="space-name">主卧 (Master Bedroom)</span>
+                    <span class="space-meta">22㎡ · 现代简约</span>
+                </div>
+                <div class="progress-bar-container">
+                    <div class="progress-bar" style="width: 0%"></div>
+                </div>
+            </div>
+            <div class="space-body">
+                <div class="stage-col">
+                    <div class="stage-header-text">白模阶段 <span class="file-count">0</span></div>
+                    <div class="stage-box empty">
+                        <span class="icon-upload">🧊</span>
+                        <span class="upload-hint">上传白模文件</span>
+                    </div>
+                </div>
+                <div class="stage-col">
+                    <div class="stage-header-text">软装阶段 <span class="file-count">0</span></div>
+                    <div class="stage-box empty" style="opacity:0.5">
+                        <span class="upload-hint">待白模确认</span>
+                    </div>
+                </div>
+                <div class="stage-col">
+                    <div class="stage-header-text">渲染阶段 <span class="file-count">0</span></div>
+                    <div class="stage-box empty" style="opacity:0.5">
+                        <span class="upload-hint">待软装确认</span>
+                    </div>
+                </div>
+                <div class="stage-col">
+                    <div class="stage-header-text">后期阶段 <span class="file-count">0</span></div>
+                    <div class="stage-box empty" style="opacity:0.5">
+                        <span class="upload-hint">待渲染确认</span>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+    </div>
+</div>
+
+</body>
+</html>

+ 255 - 0
src/test/delivery-design-matrix.html

@@ -0,0 +1,255 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>交付执行 - 方案B:矩阵表格视图</title>
+    <style>
+        :root {
+            --primary: #4f46e5;
+            --gray-100: #f3f4f6;
+            --gray-200: #e5e7eb;
+            --gray-300: #d1d5db;
+            --gray-600: #4b5563;
+            --gray-900: #111827;
+        }
+        body {
+            font-family: sans-serif;
+            background: #f9fafb;
+            padding: 40px;
+            color: var(--gray-900);
+        }
+        .container {
+            max-width: 1200px;
+            margin: 0 auto;
+            background: white;
+            border-radius: 16px;
+            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
+            overflow: hidden;
+        }
+        .header {
+            padding: 24px;
+            border-bottom: 1px solid var(--gray-200);
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+        .table-wrapper {
+            width: 100%;
+            overflow-x: auto;
+        }
+        table {
+            width: 100%;
+            border-collapse: collapse;
+            min-width: 800px;
+        }
+        th {
+            text-align: left;
+            padding: 16px 24px;
+            background: var(--gray-100);
+            font-weight: 600;
+            font-size: 14px;
+            color: var(--gray-600);
+        }
+        td {
+            padding: 16px 24px;
+            border-top: 1px solid var(--gray-200);
+            vertical-align: top;
+        }
+        
+        /* Space Row Header */
+        .space-cell {
+            width: 200px;
+        }
+        .space-name { font-weight: 700; font-size: 16px; display: block; }
+        .space-meta { font-size: 13px; color: #9ca3af; margin-top: 4px; }
+
+        /* Stage Cells */
+        .stage-cell {
+            width: 200px;
+            position: relative;
+        }
+        
+        .cell-content {
+            border: 1px solid transparent;
+            border-radius: 8px;
+            padding: 12px;
+            transition: all 0.2s;
+            min-height: 80px;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+        }
+        
+        /* Hover State */
+        .cell-content:hover {
+            background: #feffff;
+            border-color: var(--primary);
+            box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+        }
+        
+        /* Status Indicators */
+        .status-dot {
+            width: 8px;
+            height: 8px;
+            border-radius: 50%;
+            display: inline-block;
+            margin-right: 6px;
+        }
+        .dot-gray { background: #d1d5db; }
+        .dot-green { background: #10b981; }
+        .dot-blue { background: #3b82f6; }
+
+        .status-text { font-size: 13px; font-weight: 500; }
+        
+        /* File Preview in Cell */
+        .file-preview-row {
+            display: flex;
+            gap: 4px;
+            margin-top: 8px;
+        }
+        .file-thumb {
+            width: 32px;
+            height: 32px;
+            border-radius: 4px;
+            object-fit: cover;
+            background: #e5e7eb;
+        }
+        .more-files {
+            width: 32px;
+            height: 32px;
+            border-radius: 4px;
+            background: #f3f4f6;
+            font-size: 10px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: #6b7280;
+        }
+
+        /* Action Buttons (Show on Hover) */
+        .cell-actions {
+            margin-top: 8px;
+            display: none;
+        }
+        .cell-content:hover .cell-actions {
+            display: flex;
+            gap: 8px;
+        }
+        
+        .btn-xs {
+            padding: 4px 8px;
+            font-size: 12px;
+            border-radius: 4px;
+            border: 1px solid var(--gray-300);
+            background: white;
+            cursor: pointer;
+        }
+        .btn-primary-xs {
+            background: var(--primary);
+            color: white;
+            border: none;
+        }
+
+        /* Empty State */
+        .empty-state {
+            text-align: center;
+            color: #9ca3af;
+            font-size: 13px;
+        }
+    </style>
+</head>
+<body>
+
+<div class="container">
+    <div class="header">
+        <h2>交付进度矩阵</h2>
+        <button class="btn-xs" style="padding: 8px 16px;">批量导出</button>
+    </div>
+    <div class="table-wrapper">
+        <table>
+            <thead>
+                <tr>
+                    <th>空间名称</th>
+                    <th>白模 (White Model)</th>
+                    <th>软装 (Soft Decor)</th>
+                    <th>渲染 (Rendering)</th>
+                    <th>后期 (Post Process)</th>
+                </tr>
+            </thead>
+            <tbody>
+                <!-- Row 1 -->
+                <tr>
+                    <td class="space-cell">
+                        <span class="space-name">客厅</span>
+                        <span class="space-meta">Living Room</span>
+                    </td>
+                    <td class="stage-cell">
+                        <div class="cell-content">
+                            <div><span class="status-dot dot-green"></span><span class="status-text">已确认 (4)</span></div>
+                            <div class="file-preview-row">
+                                <img src="https://placehold.co/40" class="file-thumb">
+                                <img src="https://placehold.co/40" class="file-thumb">
+                                <span class="more-files">+2</span>
+                            </div>
+                            <div class="cell-actions">
+                                <button class="btn-xs">查看</button>
+                                <button class="btn-xs">补传</button>
+                            </div>
+                        </div>
+                    </td>
+                    <td class="stage-cell">
+                        <div class="cell-content">
+                            <div><span class="status-dot dot-blue"></span><span class="status-text">待审核 (2)</span></div>
+                            <div class="file-preview-row">
+                                <img src="https://placehold.co/40" class="file-thumb">
+                                <img src="https://placehold.co/40" class="file-thumb">
+                            </div>
+                            <div class="cell-actions">
+                                <button class="btn-xs">查看</button>
+                                <button class="btn-xs btn-primary-xs">上传</button>
+                            </div>
+                        </div>
+                    </td>
+                    <td class="stage-cell">
+                        <div class="cell-content">
+                            <div class="empty-state">
+                                <div>- 暂无文件 -</div>
+                            </div>
+                            <div class="cell-actions" style="justify-content: center;">
+                                <button class="btn-xs btn-primary-xs">上传渲染图</button>
+                            </div>
+                        </div>
+                    </td>
+                    <td class="stage-cell">
+                        <div class="cell-content">
+                             <div class="empty-state">-</div>
+                        </div>
+                    </td>
+                </tr>
+                
+                <!-- Row 2 -->
+                <tr>
+                    <td class="space-cell">
+                        <span class="space-name">主卧</span>
+                        <span class="space-meta">Master Bedroom</span>
+                    </td>
+                    <td class="stage-cell">
+                        <div class="cell-content">
+                            <div class="empty-state">未开始</div>
+                            <div class="cell-actions" style="justify-content: center;">
+                                <button class="btn-xs btn-primary-xs">上传白模</button>
+                            </div>
+                        </div>
+                    </td>
+                    <td class="stage-cell"><div class="cell-content"><div class="empty-state">-</div></div></td>
+                    <td class="stage-cell"><div class="cell-content"><div class="empty-state">-</div></div></td>
+                    <td class="stage-cell"><div class="cell-content"><div class="empty-state">-</div></div></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+</body>
+</html>

+ 199 - 0
src/test/delivery-design-tasks.html

@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>交付执行 - 方案C:任务清单视图</title>
+    <style>
+        :root {
+            --primary: #3b82f6;
+            --bg: #f8fafc;
+            --card-bg: #ffffff;
+            --text-main: #1e293b;
+            --text-sub: #64748b;
+            --border: #e2e8f0;
+        }
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+            background: var(--bg);
+            padding: 40px 20px;
+            color: var(--text-main);
+        }
+        .layout {
+            max-width: 800px;
+            margin: 0 auto;
+            display: grid;
+            gap: 32px;
+        }
+
+        .section-title {
+            font-size: 18px;
+            font-weight: 700;
+            margin-bottom: 16px;
+            display: flex;
+            align-items: center;
+            gap: 8px;
+        }
+        .badge {
+            background: #ef4444;
+            color: white;
+            font-size: 12px;
+            padding: 2px 8px;
+            border-radius: 10px;
+        }
+
+        /* Task Card */
+        .task-card {
+            background: var(--card-bg);
+            border: 1px solid var(--border);
+            border-radius: 12px;
+            padding: 16px 20px;
+            margin-bottom: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            transition: transform 0.2s, box-shadow 0.2s;
+        }
+        .task-card:hover {
+            transform: translateY(-2px);
+            box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+            border-color: var(--primary);
+        }
+
+        .task-left {
+            display: flex;
+            align-items: center;
+            gap: 16px;
+        }
+        .task-icon {
+            width: 40px;
+            height: 40px;
+            background: #eff6ff;
+            color: var(--primary);
+            border-radius: 8px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 20px;
+        }
+        .task-info h4 {
+            margin: 0;
+            font-size: 16px;
+            font-weight: 600;
+        }
+        .task-info p {
+            margin: 4px 0 0;
+            font-size: 14px;
+            color: var(--text-sub);
+        }
+
+        .task-actions {
+            display: flex;
+            gap: 12px;
+        }
+        .btn {
+            padding: 8px 16px;
+            border-radius: 6px;
+            font-size: 14px;
+            font-weight: 500;
+            cursor: pointer;
+            border: none;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+        .btn-primary {
+            background: var(--primary);
+            color: white;
+        }
+        .btn-primary:hover { background: #2563eb; }
+        
+        .btn-outline {
+            background: transparent;
+            border: 1px solid var(--border);
+            color: var(--text-sub);
+        }
+        .btn-outline:hover { border-color: var(--text-sub); color: var(--text-main); }
+
+        /* Section: Completed */
+        .completed-section { opacity: 0.7; }
+        .completed-section .task-card { background: #f1f5f9; border-color: transparent; }
+        .completed-section .task-icon { background: #dcfce7; color: #166534; }
+
+    </style>
+</head>
+<body>
+
+<div class="layout">
+
+    <!-- Pending Section -->
+    <div>
+        <div class="section-title">
+            待处理任务 <span class="badge">3</span>
+        </div>
+
+        <!-- Task 1 -->
+        <div class="task-card">
+            <div class="task-left">
+                <div class="task-icon">📷</div>
+                <div class="task-info">
+                    <h4>上传渲染图</h4>
+                    <p>客厅 (Living Room) · 渲染阶段</p>
+                </div>
+            </div>
+            <div class="task-actions">
+                <button class="btn btn-primary">📤 立即上传</button>
+            </div>
+        </div>
+
+        <!-- Task 2 -->
+        <div class="task-card">
+            <div class="task-left">
+                <div class="task-icon">🧊</div>
+                <div class="task-info">
+                    <h4>上传白模文件</h4>
+                    <p>主卧 (Master Bedroom) · 白模阶段</p>
+                </div>
+            </div>
+            <div class="task-actions">
+                <button class="btn btn-primary">📤 立即上传</button>
+            </div>
+        </div>
+
+         <!-- Task 3 -->
+         <div class="task-card">
+            <div class="task-left">
+                <div class="task-icon">✨</div>
+                <div class="task-info">
+                    <h4>确认后期图</h4>
+                    <p>餐厅 (Dining Room) · 后期阶段</p>
+                </div>
+            </div>
+            <div class="task-actions">
+                <button class="btn btn-outline">👀 查看详情</button>
+            </div>
+        </div>
+    </div>
+
+    <!-- Completed Section -->
+    <div class="completed-section">
+        <div class="section-title">已完成</div>
+
+        <div class="task-card">
+            <div class="task-left">
+                <div class="task-icon">✓</div>
+                <div class="task-info">
+                    <h4 style="text-decoration: line-through;">上传白模文件</h4>
+                    <p>客厅 (Living Room) · 白模阶段 · 已确认</p>
+                </div>
+            </div>
+            <div class="task-actions">
+                <button class="btn btn-outline">查看文件</button>
+            </div>
+        </div>
+    </div>
+
+</div>
+
+</body>
+</html>

+ 186 - 0
src/test/sidebar-v2-compact.html

@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>侧边栏 - 方案C:极简状态条</title>
+    <style>
+        body {
+            font-family: sans-serif;
+            background: #f8fafc;
+            margin: 0; padding: 12px;
+            max-width: 400px;
+            margin: 0 auto;
+            border: 1px solid #eee;
+        }
+        
+        .space-block {
+            background: white;
+            border-radius: 8px;
+            padding: 12px;
+            margin-bottom: 12px;
+            box-shadow: 0 1px 2px rgba(0,0,0,0.05);
+        }
+        
+        .space-head {
+            font-weight: bold;
+            margin-bottom: 12px;
+            font-size: 15px;
+            display: flex;
+            justify-content: space-between;
+        }
+        
+        /* Compact 4-Step Bar */
+        .status-bar-container {
+            display: flex;
+            gap: 8px;
+        }
+        
+        .status-pill {
+            flex: 1;
+            background: #f1f5f9;
+            border-radius: 6px;
+            padding: 8px 4px;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            justify-content: center;
+            font-size: 11px;
+            color: #64748b;
+            cursor: pointer;
+            border: 1px solid transparent;
+            position: relative;
+        }
+        
+        .status-pill:hover {
+            background: #eef2ff;
+            color: #4f46e5;
+        }
+        
+        .status-pill.done {
+            background: #ecfdf5;
+            color: #059669;
+            border-color: #a7f3d0;
+        }
+        
+        .status-pill.active {
+            background: white;
+            border-color: #6366f1;
+            color: #6366f1;
+            box-shadow: 0 2px 4px rgba(99,102,241,0.1);
+        }
+        
+        .pill-icon { font-size: 16px; margin-bottom: 2px; }
+        
+        .count-bubble {
+            position: absolute;
+            top: -4px; right: -4px;
+            background: #ef4444;
+            color: white;
+            font-size: 9px;
+            width: 14px; height: 14px;
+            border-radius: 50%;
+            display: flex; align-items: center; justify-content: center;
+        }
+
+        /* Expanded Panel for Active Stage */
+        .active-stage-panel {
+            margin-top: 12px;
+            border-top: 1px dashed #e2e8f0;
+            padding-top: 12px;
+        }
+        
+        .panel-header {
+            font-size: 13px;
+            color: #475569;
+            margin-bottom: 8px;
+            font-weight: 600;
+            display: flex;
+            justify-content: space-between;
+        }
+        
+        .upload-box-rect {
+            border: 2px dashed #cbd5e1;
+            border-radius: 6px;
+            height: 60px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: #94a3b8;
+            font-size: 12px;
+            gap: 6px;
+            cursor: pointer;
+        }
+        .upload-box-rect:hover {
+            border-color: #6366f1;
+            color: #6366f1;
+            background: #eef2ff;
+        }
+
+    </style>
+</head>
+<body>
+
+<div class="space-block">
+    <div class="space-head">
+        <span>客厅</span>
+        <span style="color:#999;font-weight:normal;font-size:12px;">35㎡</span>
+    </div>
+    
+    <!-- 4 Steps Horizontal -->
+    <div class="status-bar-container">
+        <div class="status-pill done">
+            <span class="pill-icon">🧊</span>
+            白模
+            <div class="count-bubble" style="background:#10b981">4</div>
+        </div>
+        <div class="status-pill active">
+            <span class="pill-icon">🛋️</span>
+            软装
+            <div class="count-bubble">0</div>
+        </div>
+        <div class="status-pill">
+            <span class="pill-icon">📷</span>
+            渲染
+        </div>
+        <div class="status-pill">
+            <span class="pill-icon">✨</span>
+            后期
+        </div>
+    </div>
+
+    <!-- Active Panel (shows because Soft Decor is clicked) -->
+    <div class="active-stage-panel">
+        <div class="panel-header">软装阶段 - 待上传</div>
+        <div class="upload-box-rect">
+            <span>📤 点击上传软装方案</span>
+        </div>
+    </div>
+</div>
+
+<div class="space-block">
+    <div class="space-head">
+        <span>主卧</span>
+    </div>
+    <div class="status-bar-container">
+        <div class="status-pill">
+            <span class="pill-icon">🧊</span>
+            白模
+        </div>
+        <div class="status-pill">
+            <span class="pill-icon">🛋️</span>
+            软装
+        </div>
+        <div class="status-pill">
+            <span class="pill-icon">📷</span>
+            渲染
+        </div>
+        <div class="status-pill">
+            <span class="pill-icon">✨</span>
+            后期
+        </div>
+    </div>
+</div>
+
+</body>
+</html>

+ 288 - 0
src/test/sidebar-v2-grid.html

@@ -0,0 +1,288 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>侧边栏 - 方案A:智能网格视图</title>
+    <style>
+        :root {
+            --primary: #6366f1;
+            --primary-bg: #e0e7ff;
+            --success: #10b981;
+            --text-main: #1f2937;
+            --text-sub: #6b7280;
+            --border: #e5e7eb;
+            --bg: #f3f4f6;
+        }
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+            background-color: #eef0f4;
+            margin: 0;
+            padding: 0;
+            /* 模拟企业微信侧边栏宽度 */
+            max-width: 400px;
+            margin: 0 auto;
+            min-height: 100vh;
+            border-left: 1px solid #ddd;
+            border-right: 1px solid #ddd;
+        }
+
+        /* 模拟顶部导航 */
+        .mock-header {
+            background: white;
+            padding: 12px 16px;
+            border-bottom: 1px solid var(--border);
+            position: sticky;
+            top: 0;
+            z-index: 10;
+        }
+        .stage-stepper {
+            display: flex;
+            justify-content: space-between;
+            font-size: 12px;
+            color: var(--text-sub);
+            margin-bottom: 8px;
+        }
+        .step { position: relative; text-align: center; }
+        .step.active { color: var(--primary); font-weight: 600; }
+        .step-circle { 
+            width: 20px; height: 20px; background: #ddd; border-radius: 50%; margin: 0 auto 4px; 
+            display: flex; align-items: center; justify-content: center; font-size: 10px; color: white;
+        }
+        .step.active .step-circle { background: var(--primary); }
+
+        /* Content Area */
+        .content { padding: 12px; display: flex; flex-direction: column; gap: 12px; }
+
+        /* Space Card */
+        .space-card {
+            background: white;
+            border-radius: 12px;
+            padding: 16px;
+            box-shadow: 0 1px 3px rgba(0,0,0,0.05);
+        }
+
+        .space-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 12px;
+        }
+        .space-title {
+            font-size: 16px;
+            font-weight: 700;
+            color: var(--text-main);
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+        .space-badge {
+            font-size: 10px;
+            padding: 2px 6px;
+            background: var(--primary-bg);
+            color: var(--primary);
+            border-radius: 4px;
+        }
+        .progress-text {
+            font-size: 12px;
+            color: var(--text-sub);
+        }
+
+        /* 2x2 Grid for Stages */
+        .stages-grid {
+            display: grid;
+            grid-template-columns: 1fr 1fr;
+            gap: 10px;
+        }
+
+        .stage-item {
+            background: #f9fafb;
+            border: 1px solid var(--border);
+            border-radius: 8px;
+            padding: 10px;
+            display: flex;
+            flex-direction: column;
+            gap: 8px;
+            position: relative;
+            transition: all 0.2s;
+        }
+
+        /* Empty State / Action Needed */
+        .stage-item.pending {
+            border-style: dashed;
+            border-color: #cbd5e1;
+        }
+        .stage-item.pending:hover {
+            border-color: var(--primary);
+            background: #f5f7ff;
+        }
+
+        /* Completed State */
+        .stage-item.completed {
+            background: white;
+            border-color: var(--success);
+            box-shadow: 0 2px 4px rgba(16,185,129,0.1);
+        }
+
+        .stage-label {
+            font-size: 13px;
+            font-weight: 600;
+            color: var(--text-main);
+            display: flex;
+            justify-content: space-between;
+        }
+        
+        .status-icon {
+            width: 16px; height: 16px;
+            border-radius: 50%;
+            display: flex; align-items: center; justify-content: center;
+            font-size: 10px;
+        }
+        .icon-check { background: var(--success); color: white; }
+        .icon-wait { background: #e5e7eb; color: #9ca3af; }
+
+        /* File Previews within grid */
+        .preview-strip {
+            display: flex;
+            gap: 4px;
+            height: 40px;
+        }
+        .mini-thumb {
+            width: 40px;
+            height: 40px;
+            border-radius: 4px;
+            background: #eee;
+            object-fit: cover;
+        }
+        .add-box {
+            width: 40px;
+            height: 40px;
+            border-radius: 4px;
+            border: 1px dashed #ccc;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: #999;
+            font-size: 18px;
+            cursor: pointer;
+        }
+        .add-box:hover {
+            border-color: var(--primary);
+            color: var(--primary);
+        }
+
+        /* Upload Action Area (for empty stages) */
+        .upload-action {
+            height: 40px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            gap: 6px;
+            font-size: 12px;
+            color: var(--primary);
+            background: white;
+            border-radius: 4px;
+            cursor: pointer;
+            border: 1px solid #e0e7ff;
+        }
+        .upload-action:hover {
+            background: var(--primary);
+            color: white;
+        }
+
+    </style>
+</head>
+<body>
+
+<div class="mock-header">
+    <div class="stage-stepper">
+        <div class="step"><div class="step-circle">1</div>订单</div>
+        <div class="step"><div class="step-circle">2</div>需求</div>
+        <div class="step active"><div class="step-circle">3</div>交付</div>
+        <div class="step"><div class="step-circle">4</div>售后</div>
+    </div>
+</div>
+
+<div class="content">
+    
+    <!-- Space 1: Living Room -->
+    <div class="space-card">
+        <div class="space-header">
+            <div class="space-title">客厅 <span class="space-badge">35㎡</span></div>
+            <span class="progress-text">2/4 完成</span>
+        </div>
+        
+        <div class="stages-grid">
+            <!-- Stage 1: Done -->
+            <div class="stage-item completed">
+                <div class="stage-label">
+                    白模
+                    <span class="status-icon icon-check">✓</span>
+                </div>
+                <div class="preview-strip">
+                    <img src="https://placehold.co/40" class="mini-thumb">
+                    <img src="https://placehold.co/40" class="mini-thumb">
+                    <div class="add-box">+</div>
+                </div>
+            </div>
+
+            <!-- Stage 2: Done -->
+            <div class="stage-item completed">
+                <div class="stage-label">
+                    软装
+                    <span class="status-icon icon-check">✓</span>
+                </div>
+                <div class="preview-strip">
+                    <img src="https://placehold.co/40/pink/white" class="mini-thumb">
+                    <div class="add-box">+</div>
+                </div>
+            </div>
+
+            <!-- Stage 3: Pending (Action Needed) -->
+            <div class="stage-item pending">
+                <div class="stage-label">
+                    渲染
+                    <span class="status-icon icon-wait">!</span>
+                </div>
+                <div class="upload-action">
+                    <span>📤 点击上传</span>
+                </div>
+            </div>
+
+            <!-- Stage 4: Locked/Pending -->
+            <div class="stage-item pending" style="opacity: 0.6;">
+                <div class="stage-label">
+                    后期
+                </div>
+                <div class="upload-action" style="cursor: not-allowed; border: none; background: transparent; color: #999;">
+                    <span>等待渲染</span>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!-- Space 2: Master Bedroom -->
+    <div class="space-card">
+        <div class="space-header">
+            <div class="space-title">主卧 <span class="space-badge">22㎡</span></div>
+            <span class="progress-text">0/4 完成</span>
+        </div>
+        
+        <div class="stages-grid">
+            <div class="stage-item pending">
+                <div class="stage-label">白模</div>
+                <div class="upload-action"><span>📤 上传白模</span></div>
+            </div>
+            <div class="stage-item pending">
+                <div class="stage-label">软装</div>
+                <div class="upload-action"><span>📤 上传软装</span></div>
+            </div>
+            <div class="stage-item pending" style="opacity: 0.5"><div class="stage-label">渲染</div></div>
+            <div class="stage-item pending" style="opacity: 0.5"><div class="stage-label">后期</div></div>
+        </div>
+    </div>
+
+</div>
+
+</body>
+</html>

+ 176 - 0
src/test/sidebar-v2-list.html

@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>侧边栏 - 方案B:垂直列表详情</title>
+    <style>
+        :root {
+            --primary: #6366f1;
+            --text-dark: #111827;
+            --text-gray: #6b7280;
+            --border: #e5e7eb;
+            --bg-card: #ffffff;
+        }
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+            background-color: #f3f4f6;
+            margin: 0; padding: 0;
+            max-width: 400px;
+            margin: 0 auto;
+            border-left: 1px solid #ddd;
+            border-right: 1px solid #ddd;
+            min-height: 100vh;
+        }
+
+        .space-container {
+            background: white;
+            margin-bottom: 8px;
+            border-bottom: 1px solid var(--border);
+        }
+
+        .space-title-bar {
+            padding: 16px;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            font-weight: 700;
+            color: var(--text-dark);
+            background: white;
+            cursor: pointer;
+        }
+        .toggle-icon {
+            transition: transform 0.2s;
+        }
+        .space-title-bar.active .toggle-icon {
+            transform: rotate(180deg);
+        }
+
+        .stage-list {
+            display: block; /* Expanded by default in this demo */
+            padding: 0 16px 16px;
+        }
+
+        .stage-row {
+            display: flex;
+            gap: 12px;
+            padding: 12px 0;
+            border-top: 1px solid #f3f4f6;
+        }
+
+        .stage-icon {
+            width: 36px; height: 36px;
+            background: #f3f4f6;
+            border-radius: 8px;
+            display: flex; align-items: center; justify-content: center;
+            font-size: 18px;
+            flex-shrink: 0;
+        }
+        .stage-info {
+            flex: 1;
+            display: flex;
+            flex-direction: column;
+            gap: 4px;
+        }
+        .stage-name { font-size: 14px; font-weight: 600; }
+        .stage-desc { font-size: 12px; color: var(--text-gray); }
+
+        .stage-action {
+            display: flex;
+            align-items: center;
+        }
+
+        /* Button Styles */
+        .btn-upload {
+            padding: 6px 12px;
+            background: var(--primary);
+            color: white;
+            border: none;
+            border-radius: 6px;
+            font-size: 12px;
+            cursor: pointer;
+        }
+        .btn-view {
+            padding: 6px 12px;
+            background: white;
+            border: 1px solid var(--border);
+            color: var(--text-dark);
+            border-radius: 6px;
+            font-size: 12px;
+            cursor: pointer;
+        }
+
+        /* File Thumbs Row */
+        .file-row {
+            margin-top: 8px;
+            display: flex;
+            gap: 6px;
+            overflow-x: auto;
+            padding-bottom: 4px;
+        }
+        .file-row img {
+            width: 48px; height: 48px; border-radius: 4px; object-fit: cover;
+            border: 1px solid #eee;
+        }
+    </style>
+</head>
+<body>
+
+<!-- Space 1 -->
+<div class="space-container">
+    <div class="space-title-bar active">
+        <span>客厅 (Living Room)</span>
+        <span class="toggle-icon">▼</span>
+    </div>
+    <div class="stage-list">
+        
+        <!-- Stage: White Model -->
+        <div class="stage-row">
+            <div class="stage-icon">🧊</div>
+            <div class="stage-info">
+                <div class="stage-name">白模阶段 <span style="color:green;font-size:10px;background:#d1fae5;padding:1px 4px;border-radius:4px;">已完成</span></div>
+                <div class="file-row">
+                    <img src="https://placehold.co/50">
+                    <img src="https://placehold.co/50">
+                    <img src="https://placehold.co/50">
+                </div>
+            </div>
+            <div class="stage-action">
+                <button class="btn-view">管理</button>
+            </div>
+        </div>
+
+        <!-- Stage: Soft Decor -->
+        <div class="stage-row">
+            <div class="stage-icon">🛋️</div>
+            <div class="stage-info">
+                <div class="stage-name">软装阶段</div>
+                <div class="stage-desc">等待上传软装方案</div>
+            </div>
+            <div class="stage-action">
+                <button class="btn-upload">上传</button>
+            </div>
+        </div>
+
+        <!-- Stage: Rendering -->
+        <div class="stage-row">
+            <div class="stage-icon">📷</div>
+            <div class="stage-info">
+                <div class="stage-name">渲染阶段</div>
+                <div class="stage-desc">未开始</div>
+            </div>
+        </div>
+
+    </div>
+</div>
+
+<!-- Space 2 -->
+<div class="space-container">
+    <div class="space-title-bar">
+        <span>主卧 (Master Bedroom)</span>
+        <span class="toggle-icon" style="transform: rotate(0deg);">▶</span>
+    </div>
+</div>
+
+</body>
+</html>

+ 1 - 1
tsconfig.app.json

@@ -4,7 +4,7 @@
   "extends": "./tsconfig.json",
   "compilerOptions": {
     "outDir": "./out-tsc/app",
-    "types": ["echarts"]
+    "types": ["echarts", "node"]
   },
   "include": [
     "src/**/*.ts"

Some files were not shown because too many files changed in this diff