Преглед на файлове

feat(需求确认): 增强材料分析功能并优化流程交互

添加形体分析服务及增强色彩分析功能,改进需求确认卡片和上传成功模态的UI展示
优化项目详情页的阶段流程验证逻辑和折叠面板交互
移除调试日志并修复色彩分析状态管理问题
0235711 преди 1 ден
родител
ревизия
51eef07c52

+ 4 - 1
.vscode/extensions.json

@@ -1,4 +1,7 @@
 {
   // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
-  "recommendations": ["angular.ng-template"]
+  "recommendations": [
+    "angular.ng-template",
+    "alibaba-cloud.tongyi-lingma"
+  ]
 }

+ 3 - 1
src/app/app.config.ts

@@ -1,6 +1,7 @@
 import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
 import { provideRouter } from '@angular/router';
 import { provideHttpClient } from '@angular/common/http';
+import { provideAnimations } from '@angular/platform-browser/animations';
 
 import { routes } from './app.routes';
 
@@ -8,6 +9,7 @@ export const appConfig: ApplicationConfig = {
   providers: [
     provideHttpClient(),
     provideZoneChangeDetection({ eventCoalescing: true }),
-    provideRouter(routes)
+    provideRouter(routes),
+    provideAnimations()
   ]
 };

+ 62 - 38
src/app/pages/designer/project-detail/project-detail.ts

@@ -1627,7 +1627,17 @@ export class ProjectDetail implements OnInit, OnDestroy {
 
   // 新增:建模阶段 确认上传并自动进入下一阶段(软装)
   confirmWhiteModelUpload(): void {
-    if (this.whiteModelImages.length === 0) return;
+    // 检查建模阶段的图片数据
+    const modelingProcess = this.deliveryProcesses.find(p => p.id === 'modeling');
+    if (!modelingProcess) return;
+    
+    // 检查是否有任何空间上传了图片
+    const hasImages = modelingProcess.spaces.some(space => {
+      const content = modelingProcess.content[space.id];
+      return content && content.images && content.images.length > 0;
+    });
+    
+    if (!hasImages) return;
     this.advanceToNextStage('建模');
   }
 
@@ -1808,7 +1818,17 @@ export class ProjectDetail implements OnInit, OnDestroy {
 
   // 新增:后期阶段 确认上传并自动进入下一阶段(尾款结算)
   confirmPostProcessUpload(): void {
-    if (this.postProcessImages.length === 0) return;
+    // 检查后期阶段的图片数据
+    const postProcessProcess = this.deliveryProcesses.find(p => p.id === 'post-processing');
+    if (!postProcessProcess) return;
+    
+    // 检查是否有任何空间上传了图片
+    const hasImages = postProcessProcess.spaces.some(space => {
+      const content = postProcessProcess.content[space.id];
+      return content && content.images && content.images.length > 0;
+    });
+    
+    if (!hasImages) return;
     this.advanceToNextStage('后期');
   }
 
@@ -1851,13 +1871,33 @@ export class ProjectDetail implements OnInit, OnDestroy {
 
   // 新增:软装阶段 确认上传并自动进入下一阶段(渲染)
   confirmSoftDecorUpload(): void {
-    if (this.softDecorImages.length === 0) return;
+    // 检查软装阶段的图片数据
+    const softDecorProcess = this.deliveryProcesses.find(p => p.id === 'soft-decoration');
+    if (!softDecorProcess) return;
+    
+    // 检查是否有任何空间上传了图片
+    const hasImages = softDecorProcess.spaces.some(space => {
+      const content = softDecorProcess.content[space.id];
+      return content && content.images && content.images.length > 0;
+    });
+    
+    if (!hasImages) return;
     this.advanceToNextStage('软装');
   }
 
   // 新增:渲染阶段 确认上传并自动进入下一阶段(后期)
   confirmRenderUpload(): void {
-    if (this.renderLargeImages.length === 0) return;
+    // 检查渲染阶段的图片数据
+    const renderProcess = this.deliveryProcesses.find(p => p.id === 'rendering');
+    if (!renderProcess) return;
+    
+    // 检查是否有任何空间上传了图片
+    const hasImages = renderProcess.spaces.some(space => {
+      const content = renderProcess.content[space.id];
+      return content && content.images && content.images.length > 0;
+    });
+    
+    if (!hasImages) return;
     this.advanceToNextStage('渲染');
   }
 
@@ -2336,14 +2376,8 @@ export class ProjectDetail implements OnInit, OnDestroy {
 
   // 检查必需阶段是否全部完成(流程进度 > 确认需求 > 需求沟通四个流程)
   areRequiredStagesCompleted(): boolean {
-    console.log('=== areRequiredStagesCompleted 调试信息 ===');
-    console.log('项目数据:', this.project);
-    console.log('当前阶段:', this.project?.currentStage);
-    console.log('需求关键信息:', this.requirementKeyInfo);
-    
     // 检查项目是否已经进入方案确认阶段或更后的阶段
     if (!this.project) {
-      console.log('项目数据为空,返回false');
       return false;
     }
     
@@ -2356,13 +2390,8 @@ export class ProjectDetail implements OnInit, OnDestroy {
     const proposalStageIndex = stageOrder.indexOf('方案确认');
     const requirementStageIndex = stageOrder.indexOf('需求沟通');
     
-    console.log('当前阶段索引:', currentStageIndex);
-    console.log('方案确认阶段索引:', proposalStageIndex);
-    console.log('需求沟通阶段索引:', requirementStageIndex);
-    
     // 如果当前阶段是方案确认或之后的阶段,则认为需求阶段已完成
     if (currentStageIndex >= proposalStageIndex) {
-      console.log('当前阶段>=方案确认,确保需求数据并返回true');
       // 确保有基本的需求信息数据,如果没有则初始化模拟数据
       this.ensureRequirementData();
       return true;
@@ -2370,7 +2399,6 @@ export class ProjectDetail implements OnInit, OnDestroy {
     
     // 如果当前阶段是需求沟通,检查需求沟通是否已完成
     if (currentStageIndex === requirementStageIndex) {
-      console.log('当前阶段是需求沟通,检查需求数据');
       // 检查需求关键信息是否有数据,或者检查需求沟通组件的完成状态
       const hasRequirementData = this.getRequirementSummary().length > 0 && 
              (!!this.requirementKeyInfo.colorAtmosphere.description || 
@@ -2378,31 +2406,23 @@ export class ProjectDetail implements OnInit, OnDestroy {
               this.requirementKeyInfo.materialWeights.woodRatio > 0 ||
               !!this.requirementKeyInfo.presetAtmosphere.name);
       
-      console.log('需求数据检查结果:', hasRequirementData);
-      console.log('需求摘要长度:', this.getRequirementSummary().length);
-      
-      // 如果有需求数据,说明需求沟通已完成,可以显示方案确认内容
+      // 只有在真正有需求数据时才返回true,不再自动初始化模拟数据
       if (hasRequirementData) {
-        console.log('有需求数据,返回true');
         return true;
       }
       
-      // 如果没有需求数据,但是需求沟通阶段已经展开一段时间,也初始化模拟数据
-      // 这样可以确保方案确认卡片能够正常显示
-      console.log('没有需求数据,初始化模拟数据并返回true');
-      this.ensureRequirementData();
-      return true;
+      // 如果没有需求数据,返回false,不允许进入下一阶段
+      return false;
     }
     
     // 其他情况返回false
-    console.log('其他情况,返回false');
     return false;
   }
 
   // 确保有需求数据用于方案确认显示
   private ensureRequirementData(): void {
-    console.log('=== ensureRequirementData 开始确保需求数据 ===');
-    console.log('当前requirementKeyInfo:', this.requirementKeyInfo);
+    // console.log('=== ensureRequirementData 开始确保需求数据 ===');
+    // console.log('当前requirementKeyInfo:', this.requirementKeyInfo);
     
     // 修复条件判断:检查是否需要初始化数据
     const needsInitialization = 
@@ -2444,9 +2464,9 @@ export class ProjectDetail implements OnInit, OnDestroy {
           materials: ['木质', '金属']
         }
       };
-      console.log('初始化后的requirementKeyInfo:', this.requirementKeyInfo);
+      // console.log('初始化后的requirementKeyInfo:', this.requirementKeyInfo);
     } else {
-      console.log('需求关键信息已存在,无需初始化');
+      // console.log('需求关键信息已存在,无需初始化');
     }
   }
 
@@ -2748,15 +2768,22 @@ export class ProjectDetail implements OnInit, OnDestroy {
       
       // 接收色彩分析结果并存储用于右侧展示
       if (data.colorAnalysisResult) {
+        console.log('接收到色彩分析结果:', data.colorAnalysisResult);
         this.colorAnalysisResult = data.colorAnalysisResult as ColorAnalysisResult;
+        console.log('设置colorAnalysisResult后:', this.colorAnalysisResult);
+        
         // 计算主色:按占比最高的颜色
         const colors = this.colorAnalysisResult?.colors || [];
         if (colors.length > 0) {
           const dominant = colors.reduce((max, cur) => cur.percentage > max.percentage ? cur : max, colors[0]);
           this.dominantColorHex = dominant.hex;
+          console.log('计算出的主色:', this.dominantColorHex);
         } else {
           this.dominantColorHex = null;
+          console.log('没有颜色数据,主色设为null');
         }
+      } else {
+        console.log('没有接收到色彩分析结果');
       }
 
       // 新增:根据上传来源拆分材料文件用于左右区展示
@@ -2767,7 +2794,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
       // 触发变更检测以更新UI
       this.cdr.detectChanges();
       
-      console.log('客户信息已实时更新');
+      console.log('客户信息已实时更新,当前colorAnalysisResult状态:', !!this.colorAnalysisResult);
     }
   }
 
@@ -3196,15 +3223,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
 
   // 横向折叠面板相关方法
   
-  // 切换流程展开状态(三个卡片同时展开收起
+  // 切换流程展开状态(独立控制每个流程
   toggleProcess(processId: string): void {
     const process = this.deliveryProcesses.find(p => p.id === processId);
     if (process) {
-      const newExpandedState = !process.isExpanded;
-      // 所有流程同时展开或收起
-      this.deliveryProcesses.forEach(p => {
-        p.isExpanded = newExpandedState;
-      });
+      // 只切换当前点击的流程状态
+      process.isExpanded = !process.isExpanded;
     }
   }
 

+ 107 - 2
src/app/shared/components/requirements-confirm-card/requirements-confirm-card.html

@@ -176,8 +176,112 @@
                         }
                         </div>
                       } @else if (material.type === 'image') {
-                        <div class="color-info">
-                          <span class="color-temp">色温: {{ material.analysis.colorTemperature }}K</span>
+                        <div class="analysis-results">
+                          <!-- 基础色彩信息 -->
+                          <div class="color-info">
+                            <span class="color-temp">色温: {{ material.analysis.colorTemperature }}K</span>
+                          </div>
+                          
+                          <!-- 增强色彩分析 -->
+                          @if (material.analysis.enhancedColorAnalysis) {
+                            <div class="enhanced-analysis">
+                              <div class="analysis-section">
+                                <h6>色彩分析</h6>
+                                
+                                <!-- 色轮分析 -->
+                                @if (material.analysis.enhancedColorAnalysis.colorWheel) {
+                                  <div class="color-wheel-info">
+                                    <div class="color-wheel-icon">
+                                      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                                        <circle cx="12" cy="12" r="10"></circle>
+                                        <path d="M12 2a10 10 0 0 1 10 10"></path>
+                                        <path d="M12 2a10 10 0 0 0-10 10"></path>
+                                        <path d="M12 12l8.66-5"></path>
+                                        <path d="M12 12l-8.66-5"></path>
+                                      </svg>
+                                    </div>
+                                    <span>主色调: {{ material.analysis.enhancedColorAnalysis.colorWheel.primaryHue }}°</span>
+                                    <span>饱和度: {{ material.analysis.enhancedColorAnalysis.colorWheel.saturation }}%</span>
+                                  </div>
+                                }
+                                
+                                <!-- 色彩心理学 -->
+                                @if (material.analysis.enhancedColorAnalysis.colorPsychology) {
+                                  <div class="psychology-info">
+                                    <span class="mood-tag">{{ material.analysis.enhancedColorAnalysis.colorPsychology.primaryMood }}</span>
+                                    <span class="atmosphere-tag">{{ material.analysis.enhancedColorAnalysis.colorPsychology.atmosphere }}</span>
+                                  </div>
+                                }
+                              </div>
+                              
+                              <!-- 形体分析 -->
+                              @if (material.analysis.formAnalysis) {
+                                <div class="analysis-section">
+                                  <h6>形体分析</h6>
+                                  @if (material.analysis.formAnalysis.overallAssessment) {
+                                    <div class="form-metrics">
+                                      <div class="metric-item">
+                                        <span class="metric-label">复杂度:</span>
+                                        <div class="metric-bar">
+                                          <div class="metric-fill" [style.width.%]="material.analysis.formAnalysis.overallAssessment.formComplexity"></div>
+                                        </div>
+                                      </div>
+                                      <div class="metric-item">
+                                        <span class="metric-label">视觉冲击:</span>
+                                        <div class="metric-bar">
+                                          <div class="metric-fill" [style.width.%]="material.analysis.formAnalysis.overallAssessment.visualImpact"></div>
+                                        </div>
+                                      </div>
+                                    </div>
+                                  }
+                                </div>
+                              }
+                              
+                              <!-- 质感分析 -->
+                              @if (material.analysis.textureAnalysis) {
+                                <div class="analysis-section">
+                                  <h6>质感分析</h6>
+                                  @if (material.analysis.textureAnalysis.materialClassification) {
+                                    <div class="material-info">
+                                      <span class="material-tag">{{ material.analysis.textureAnalysis.materialClassification.primaryMaterial.category }}</span>
+                                      @if (material.analysis.textureAnalysis.surfaceProperties) {
+                                        <span class="surface-tag">{{ material.analysis.textureAnalysis.surfaceProperties.roughness.level }}</span>
+                                      }
+                                    </div>
+                                  }
+                                </div>
+                              }
+                              
+                              <!-- 纹理分析 -->
+                              @if (material.analysis.patternAnalysis) {
+                                <div class="analysis-section">
+                                  <h6>纹理分析</h6>
+                                  @if (material.analysis.patternAnalysis.patternRecognition) {
+                                    <div class="pattern-info">
+                                      @for (pattern of material.analysis.patternAnalysis.patternRecognition.primaryPatterns; track pattern.type) {
+                                        <span class="pattern-tag">{{ pattern.type }} ({{ pattern.coverage }}%)</span>
+                                      }
+                                    </div>
+                                  }
+                                </div>
+                              }
+                              
+                              <!-- 灯光分析 -->
+                              @if (material.analysis.lightingAnalysis) {
+                                <div class="analysis-section">
+                                  <h6>灯光分析</h6>
+                                  @if (material.analysis.lightingAnalysis.ambientAnalysis) {
+                                    <div class="lighting-info">
+                                      <span class="mood-tag">{{ material.analysis.lightingAnalysis.ambientAnalysis.lightingMood.primary }}</span>
+                                      @if (material.analysis.lightingAnalysis.illuminationAnalysis) {
+                                        <span class="brightness-tag">亮度: {{ material.analysis.lightingAnalysis.illuminationAnalysis.brightness.overall }}%</span>
+                                      }
+                                    </div>
+                                  }
+                                </div>
+                              }
+                            </div>
+                          }
                         </div>
                       }
                     </div>
@@ -775,6 +879,7 @@
   [uploadedFiles]="uploadedFiles"
   [uploadType]="uploadType"
   [analysisResult]="colorAnalysisResult"
+  [isAnalyzing]="isAnalyzingColors"
   (closeModal)="onModalClose()"
   (analyzeColors)="onAnalyzeColors()"
   (viewReport)="onViewReport()">

+ 163 - 4
src/app/shared/components/requirements-confirm-card/requirements-confirm-card.scss

@@ -635,10 +635,169 @@
               }
             }
             
-            .color-info {
-              .color-temp {
-                font-size: $ios-font-size-xs;
-                color: $ios-text-secondary;
+            .analysis-results {
+              .color-info {
+                margin-bottom: $ios-spacing-sm;
+                
+                .color-temp {
+                  font-size: $ios-font-size-xs;
+                  color: $ios-text-secondary;
+                }
+              }
+              
+              .enhanced-analysis {
+                .analysis-section {
+                  margin-bottom: $ios-spacing-md;
+                  padding: $ios-spacing-sm;
+                  background: rgba(0, 122, 255, 0.02);
+                  border-radius: 6px;
+                  border: 1px solid rgba(0, 122, 255, 0.1);
+                  
+                  h6 {
+                    margin: 0 0 $ios-spacing-xs 0;
+                    font-size: $ios-font-size-xs;
+                    font-weight: $ios-font-weight-semibold;
+                    color: $ios-primary;
+                  }
+                  
+                  .color-wheel-info {
+                    display: flex;
+                    align-items: center;
+                    gap: $ios-spacing-xs;
+                    margin-bottom: $ios-spacing-xs;
+                    
+                    .color-wheel-icon {
+                      display: flex;
+                      align-items: center;
+                      justify-content: center;
+                      width: 24px;
+                      height: 24px;
+                      
+                      svg {
+                        color: $ios-primary;
+                      }
+                    }
+                    
+                    span {
+                      font-size: $ios-font-size-xs;
+                      color: $ios-text-secondary;
+                      margin-right: $ios-spacing-sm;
+                    }
+                  }
+                  
+                  .psychology-info {
+                    display: flex;
+                    gap: $ios-spacing-xs;
+                    flex-wrap: wrap;
+                    
+                    .mood-tag, .atmosphere-tag {
+                      display: inline-block;
+                      background: rgba(52, 199, 89, 0.1);
+                      color: #34C759;
+                      padding: 2px 6px;
+                      border-radius: 4px;
+                      font-size: $ios-font-size-xs;
+                      font-weight: $ios-font-weight-medium;
+                    }
+                    
+                    .atmosphere-tag {
+                      background: rgba(255, 149, 0, 0.1);
+                      color: #FF9500;
+                    }
+                  }
+                  
+                  .form-metrics {
+                    .metric-item {
+                      display: flex;
+                      align-items: center;
+                      gap: $ios-spacing-sm;
+                      margin-bottom: $ios-spacing-xs;
+                      
+                      .metric-label {
+                        font-size: $ios-font-size-xs;
+                        color: $ios-text-secondary;
+                        min-width: 60px;
+                      }
+                      
+                      .metric-bar {
+                        flex: 1;
+                        height: 4px;
+                        background: $ios-border;
+                        border-radius: 2px;
+                        overflow: hidden;
+                        
+                        .metric-fill {
+                          height: 100%;
+                          background: linear-gradient(90deg, #34C759, #007AFF);
+                          transition: width 0.3s ease;
+                        }
+                      }
+                    }
+                  }
+                  
+                  .material-info {
+                    display: flex;
+                    gap: $ios-spacing-xs;
+                    flex-wrap: wrap;
+                    
+                    .material-tag, .surface-tag {
+                      display: inline-block;
+                      background: rgba(175, 82, 222, 0.1);
+                      color: #AF52DE;
+                      padding: 2px 6px;
+                      border-radius: 4px;
+                      font-size: $ios-font-size-xs;
+                      font-weight: $ios-font-weight-medium;
+                    }
+                    
+                    .surface-tag {
+                      background: rgba(255, 45, 85, 0.1);
+                      color: #FF2D55;
+                    }
+                  }
+                  
+                  .pattern-info {
+                    display: flex;
+                    gap: $ios-spacing-xs;
+                    flex-wrap: wrap;
+                    
+                    .pattern-tag {
+                      display: inline-block;
+                      background: rgba(88, 86, 214, 0.1);
+                      color: #5856D6;
+                      padding: 2px 6px;
+                      border-radius: 4px;
+                      font-size: $ios-font-size-xs;
+                      font-weight: $ios-font-weight-medium;
+                    }
+                  }
+                  
+                  .lighting-info {
+                    display: flex;
+                    gap: $ios-spacing-xs;
+                    flex-wrap: wrap;
+                    
+                    .mood-tag {
+                      display: inline-block;
+                      background: rgba(255, 204, 0, 0.1);
+                      color: #FFCC00;
+                      padding: 2px 6px;
+                      border-radius: 4px;
+                      font-size: $ios-font-size-xs;
+                      font-weight: $ios-font-weight-medium;
+                    }
+                    
+                    .brightness-tag {
+                      display: inline-block;
+                      background: rgba(255, 149, 0, 0.1);
+                      color: #FF9500;
+                      padding: 2px 6px;
+                      border-radius: 4px;
+                      font-size: $ios-font-size-xs;
+                      font-weight: $ios-font-weight-medium;
+                    }
+                  }
+                }
               }
             }
           }

+ 198 - 18
src/app/shared/components/requirements-confirm-card/requirements-confirm-card.ts

@@ -37,6 +37,150 @@ interface MaterialAnalysis {
   structuralElements?: { type: string; position: string; changeable: boolean }[];
   spaceMetrics?: { room: string; ratio: string; width: string }[];
   flowMetrics?: { area: string; width: string; compliance: boolean }[];
+  
+  // 增强色彩分析
+  enhancedColorAnalysis?: {
+    colorWheel?: {
+      primaryHue: number;
+      saturation: number;
+      brightness: number;
+      dominantColors: Array<{ hue: number; saturation: number; brightness: number; percentage: number }>;
+      colorDistribution: string;
+    };
+    colorHarmony?: {
+      harmonyType: string;
+      harmonyScore: number;
+      complementaryColors: string[];
+      suggestions: string[];
+    };
+    colorTemperatureAnalysis?: {
+      kelvin: number;
+      warmCoolBalance: number;
+      description: string;
+      lightingRecommendations: string[];
+    };
+    colorPsychology?: {
+      primaryMood: string;
+      atmosphere: string;
+      psychologicalEffects: string[];
+      suitableSpaces: string[];
+    };
+  };
+  
+  // 形体分析
+  formAnalysis?: {
+    lineAnalysis?: {
+      dominantLines: Array<{ type: string; percentage: number; characteristics: string[] }>;
+      lineQuality: { smoothness: number; precision: number; expressiveness: number };
+      visualFlow: { direction: string; rhythm: string; continuity: number };
+    };
+    geometryAnalysis?: {
+      primaryShapes: Array<{ shape: string; percentage: number; characteristics: string[] }>;
+      complexity: string;
+      symmetry: { type: string; score: number };
+      balance: { visual: number; compositional: number };
+    };
+    proportionAnalysis?: {
+      aspectRatio: number;
+      goldenRatio: number;
+      proportionHarmony: number;
+      scaleRelationships: Array<{ element: string; scale: string; relationship: string }>;
+    };
+    overallAssessment?: {
+      formComplexity: number;
+      visualImpact: number;
+      functionalSuitability: number;
+      aestheticAppeal: number;
+    };
+  };
+  
+  // 质感分析
+  textureAnalysis?: {
+    surfaceProperties?: {
+      roughness: { level: string; value: number; description: string };
+      glossiness: { level: string; value: number; reflectivity: number };
+      transparency: { level: string; value: number };
+      porosity: { level: string; value: number };
+    };
+    tactilePredict?: {
+      temperature: { perceived: string; thermalConductivity: number };
+      hardness: { level: string; value: number };
+      flexibility: { level: string; value: number };
+      weight: { perceived: string; density: number };
+      comfort: { tactileComfort: number; ergonomicSuitability: number };
+    };
+    materialClassification?: {
+      primaryMaterial: { category: string; confidence: number; subcategory?: string };
+      secondaryMaterials: Array<{ category: string; percentage: number; confidence: number }>;
+      materialProperties: { durability: number; maintenance: string; sustainability: number; costLevel: string };
+    };
+    textureQuality?: {
+      overallQuality: number;
+      consistency: number;
+      authenticity: number;
+      visualAppeal: number;
+      functionalSuitability: number;
+      ageingCharacteristics: { wearResistance: number; patinaPotential: number; maintenanceNeeds: string[] };
+    };
+  };
+  
+  // 纹理图案分析
+  patternAnalysis?: {
+    patternRecognition?: {
+      primaryPatterns: Array<{ type: string; confidence: number; coverage: number; characteristics: string[] }>;
+      patternComplexity: { level: string; score: number; elements: number };
+      patternScale: { size: string; uniformity: number; variation: number };
+    };
+    repetitionAnalysis?: {
+      repetitionType: { primary: string; pattern: string; consistency: number };
+      spacing: { horizontal: number; vertical: number; uniformity: number; rhythm: string };
+      symmetry: { type: string; strength: number; axes: number };
+      tiling: { seamless: boolean; quality: number; edgeHandling: string };
+    };
+    textureClassification?: {
+      textureFamily: { primary: string; subcategory: string; confidence: number };
+      surfaceCharacter: { tactileQuality: string; visualDepth: number; dimensionality: string };
+      materialSuggestion: { likelyMaterials: string[]; fabricationMethod: string[]; applicationSuitability: string[] };
+    };
+    visualRhythm?: {
+      rhythmType: { primary: string; intensity: number; tempo: string };
+      movement: { direction: string; flow: number; energy: number };
+      emphasis: { focalPoints: number; contrast: number; hierarchy: number };
+      harmony: { overall: number; balance: number; unity: number };
+    };
+  };
+  
+  // 灯光分析
+  lightingAnalysis?: {
+    lightSourceIdentification?: {
+      primarySources: Array<{
+        type: string;
+        subtype: string;
+        position: { direction: string; angle: number; distance: string };
+        intensity: number;
+        confidence: number;
+      }>;
+      lightingSetup: { complexity: string; sourceCount: number; dominantSource: string; lightingStyle: string };
+    };
+    illuminationAnalysis?: {
+      brightness: { overall: number; distribution: string; dynamicRange: number; exposure: string };
+      contrast: { level: number; type: string; areas: { highlights: number; midtones: number; shadows: number } };
+      colorTemperature: { kelvin: number; warmth: string; consistency: number; mixedLighting: boolean };
+      lightQuality: { softness: number; diffusion: number; directionality: number; evenness: number };
+    };
+    shadowAnalysis?: {
+      shadowPresence: { coverage: number; intensity: number; sharpness: string; definition: number };
+      shadowCharacteristics: { direction: string; length: string; density: number; falloff: string };
+      shadowTypes: Array<{ type: 'cast' | 'form' | 'occlusion' | 'contact'; prominence: number; contribution: string }>;
+      dimensionalEffect: { depth: number; volume: number; threedimensionality: number };
+    };
+    ambientAnalysis?: {
+      ambientLevel: { strength: number; uniformity: number; contribution: number };
+      lightingMood: { primary: string; intensity: number; emotional_impact: string[] };
+      atmosphericEffects: { haze: number; glare: number; reflections: number; transparency: number };
+      spatialPerception: { depth_enhancement: number; space_definition: number; focal_guidance: number };
+    };
+  };
 }
 
 // 需求指标接口
@@ -203,6 +347,7 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
   uploadType: 'image' | 'document' | 'mixed' = 'image';
   colorAnalysisResult?: ColorAnalysisResult;
   cadAnalysisResult?: CadAnalysisResult;
+  isAnalyzingColors = false; // 新增:色彩分析状态
 
   // 全局提示组件状态
   showGlobalPrompt = false;
@@ -414,7 +559,7 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
   }
 
   // 素材解析功能
-  private analyzeMaterial(material: MaterialFile) {
+  private analyzeMaterial(material: MaterialFile): void {
     this.isAnalyzing = true;
     
     // CAD采用服务分析,其它类型保持模拟
@@ -1505,31 +1650,60 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
     if (this.uploadedFiles.length > 0 && this.uploadType === 'image') {
       const imageFile = this.uploadedFiles[0];
       
-      // 创建一个File对象用于分析
-      const file = new File([], imageFile.name, { type: imageFile.type || 'image/jpeg' });
+      // 设置分析状态为true
+      this.isAnalyzingColors = true;
       
-      // 使用模拟分析(在实际应用中应该调用真实的API)
-      this.colorAnalysisService.simulateAnalysis(file).subscribe({
-        next: (result) => {
-          this.colorAnalysisResult = result;
-          // 可以在这里更新颜色指标
-          if (result.colors.length > 0) {
-            const mainColor = result.colors[0];
-            this.updateColorIndicator('mainColor', mainColor.rgb);
+      // 从URL获取文件数据并创建File对象
+      fetch(imageFile.url)
+        .then(response => {
+          if (!response.ok) {
+            throw new Error(`HTTP error! status: ${response.status}`);
           }
-          // 新增:分析完成后向父级发射数据更新,包含色彩分析结果
-          this.emitDataUpdate();
-        },
-        error: (error) => {
-          console.error('颜色分析失败:', error);
-        }
-      });
+          return response.blob();
+        })
+        .then(blob => {
+          // 创建包含实际文件数据的File对象
+          const file = new File([blob], imageFile.name, { type: imageFile.type || 'image/jpeg' });
+          
+          // 使用模拟分析(在实际应用中应该调用真实的API)
+          this.colorAnalysisService.simulateAnalysis(file).subscribe({
+            next: (result) => {
+              this.colorAnalysisResult = result;
+              this.isAnalyzingColors = false; // 分析完成,设置状态为false
+              
+              // 可以在这里更新颜色指标
+              if (result.colors.length > 0) {
+                const mainColor = result.colors[0];
+                this.updateColorIndicator('mainColor', mainColor.rgb);
+              }
+              // 新增:分析完成后向父级发射数据更新,包含色彩分析结果
+              this.emitDataUpdate();
+            },
+            error: (error) => {
+              console.error('颜色分析失败:', error);
+              this.isAnalyzingColors = false; // 分析失败,也要重置状态
+            }
+          });
+        })
+        .catch(error => {
+          console.error('获取文件数据失败:', error);
+          this.isAnalyzingColors = false; // 获取文件失败,重置状态
+        });
     }
   }
 
   onViewReport(): void {
+    console.log('onViewReport被调用,当前colorAnalysisResult:', this.colorAnalysisResult);
     // 打开全屏报告覆盖层
     this.showFullReportOverlay = true;
+    
+    // 确保色彩分析结果传递给父组件用于右侧展示
+    if (this.colorAnalysisResult) {
+      console.log('调用emitDataUpdate传递色彩分析结果');
+      this.emitDataUpdate();
+    } else {
+      console.log('没有色彩分析结果可传递');
+    }
   }
 
   onCloseFullReport(): void {
@@ -1550,6 +1724,12 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
       colorAnalysisResult: this.colorAnalysisResult
     };
     
+    console.log('emitDataUpdate被调用,准备发射数据:', {
+      colorAnalysisResult: this.colorAnalysisResult,
+      materials: this.materials,
+      requirementItems: this.requirementItems
+    });
+    
     this.dataUpdated.emit(currentData);
     console.log('实时数据更新事件已发射:', currentData);
   }

+ 192 - 0
src/app/shared/components/upload-success-modal/upload-success-modal.component.html

@@ -130,6 +130,198 @@
                   }
                 </div>
 
+                <!-- 增强分析结果 -->
+                @if (analysisResult.enhancedAnalysis) {
+                  <div class="enhanced-analysis">
+                    <div class="analysis-tabs">
+                      <button class="tab-btn" 
+                              [class.active]="activeTab === 'color'"
+                              (click)="activeTab = 'color'">色彩分析</button>
+                      <button class="tab-btn" 
+                              [class.active]="activeTab === 'form'"
+                              (click)="activeTab = 'form'">形体分析</button>
+                      <button class="tab-btn" 
+                              [class.active]="activeTab === 'texture'"
+                              (click)="activeTab = 'texture'">质感分析</button>
+                      <button class="tab-btn" 
+                              [class.active]="activeTab === 'pattern'"
+                              (click)="activeTab = 'pattern'">纹理分析</button>
+                      <button class="tab-btn" 
+                              [class.active]="activeTab === 'lighting'"
+                              (click)="activeTab = 'lighting'">灯光分析</button>
+                    </div>
+
+                    <div class="tab-content">
+                      <!-- 色彩分析标签页 -->
+                      @if (activeTab === 'color') {
+                        <div class="color-analysis-tab">
+                          <div class="analysis-section">
+                            <h6>色轮分析</h6>
+                            <div class="color-wheel-info">
+                              <div class="info-item">
+                                <span class="label">主色调:</span>
+                                <span class="value">{{ analysisResult.enhancedAnalysis.colorWheel.dominantHue }}°</span>
+                              </div>
+                              <div class="info-item">
+                                <span class="label">饱和度范围:</span>
+                                <span class="value">{{ (analysisResult.enhancedAnalysis.colorWheel.saturationRange?.min || 0) }}% - {{ (analysisResult.enhancedAnalysis.colorWheel.saturationRange?.max || 100) }}%</span>
+                              </div>
+                            </div>
+                          </div>
+                          
+                          <div class="analysis-section">
+                            <h6>色彩心理学</h6>
+                            <div class="psychology-info">
+                              <div class="mood-atmosphere">
+                                <span class="mood">{{ analysisResult.enhancedAnalysis.colorPsychology.mood || '无' }}</span>
+                                <span class="atmosphere">{{ analysisResult.enhancedAnalysis.colorPsychology.atmosphere || '无' }}</span>
+                              </div>
+                              <div class="suitable-spaces">
+                                @for (space of analysisResult.enhancedAnalysis.colorPsychology.suitableSpaces; track space) {
+                                  <span class="space-tag">{{ space }}</span>
+                                }
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                      }
+
+                      <!-- 形体分析标签页 -->
+                      @if (activeTab === 'form' && analysisResult.formAnalysis) {
+                        <div class="form-analysis-tab">
+                          <div class="analysis-section">
+                            <h6>线条分析</h6>
+                            <div class="form-info">
+                              <div class="info-item">
+                <span class="label">主导线条:</span>
+                <span class="value">{{ analysisResult.formAnalysis.lineAnalysis.dominantLineType || '无' }}</span>
+              </div>
+                              <div class="info-item">
+                                <span class="label">视觉流动:</span>
+                                <span class="value">{{ analysisResult.formAnalysis.lineAnalysis.visualFlow || '无' }}</span>
+                              </div>
+                            </div>
+                          </div>
+                          
+                          <div class="analysis-section">
+                            <h6>整体评估</h6>
+                            <div class="overall-info">
+                              <div class="metric">
+                                <span class="metric-label">复杂度</span>
+                                <div class="metric-bar">
+                                  <div class="metric-fill" [style.width.%]="analysisResult.formAnalysis.overallAssessment.complexity"></div>
+                                </div>
+                                <span class="metric-value">{{ analysisResult.formAnalysis.overallAssessment.complexity || 0 }}%</span>
+                              </div>
+                              <div class="metric">
+                                <span class="metric-label">视觉冲击</span>
+                                <div class="metric-bar">
+                                  <div class="metric-fill" [style.width.%]="analysisResult.formAnalysis.overallAssessment.visualImpact"></div>
+                                </div>
+                                <span class="metric-value">{{ analysisResult.formAnalysis.overallAssessment.visualImpact || 0 }}%</span>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                      }
+
+                      <!-- 质感分析标签页 -->
+                      @if (activeTab === 'texture' && analysisResult.textureAnalysis) {
+                        <div class="texture-analysis-tab">
+                          <div class="analysis-section">
+                            <h6>表面属性</h6>
+                            <div class="texture-properties">
+                              @for (property of getTextureProperties(); track property.name) {
+                                <div class="property-item">
+                                  <span class="property-name">{{ property.name }}</span>
+                                  <div class="property-bar">
+                                    <div class="property-fill" [style.width.%]="property.value"></div>
+                                  </div>
+                                  <span class="property-value">{{ property.value }}%</span>
+                                </div>
+                              }
+                            </div>
+                          </div>
+                          
+                          <div class="analysis-section">
+                            <h6>材质分类</h6>
+                            <div class="material-tags">
+                              @for (material of analysisResult.textureAnalysis.materialClassification.primaryMaterials; track material; let i = $index) {
+                                <span class="material-tag primary">{{ material }}</span>
+                              }
+                              @for (material of analysisResult.textureAnalysis.materialClassification.secondaryMaterials; track material; let i = $index) {
+                                <span class="material-tag secondary">{{ material }}</span>
+                              }
+                            </div>
+                          </div>
+                        </div>
+                      }
+
+                      <!-- 纹理分析标签页 -->
+                      @if (activeTab === 'pattern' && analysisResult.patternAnalysis) {
+                        <div class="pattern-analysis-tab">
+                          <div class="analysis-section">
+                            <h6>图案识别</h6>
+                            <div class="pattern-info">
+                              <div class="info-item">
+                <span class="label">主要图案:</span>
+                <span class="value">{{ analysisResult.patternAnalysis.patternRecognition.primaryPatterns[0]?.type || '无' }}</span>
+              </div>
+                              <div class="info-item">
+                                <span class="label">复杂度:</span>
+                                <span class="value">{{ analysisResult.patternAnalysis.patternRecognition.patternComplexity.level || '无' }}</span>
+                              </div>
+                            </div>
+                          </div>
+                          
+                          <div class="analysis-section">
+                            <h6>视觉节奏</h6>
+                            <div class="rhythm-info">
+                              <div class="rhythm-tags">
+                                <span class="rhythm-tag">{{ analysisResult.patternAnalysis.visualRhythm.rhythmType.primary || '无' }}</span>
+                                <span class="rhythm-tag">{{ analysisResult.patternAnalysis.visualRhythm.movement.direction || '无' }}</span>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                      }
+
+                      <!-- 灯光分析标签页 -->
+                      @if (activeTab === 'lighting' && analysisResult.lightingAnalysis) {
+                        <div class="lighting-analysis-tab">
+                          <div class="analysis-section">
+                            <h6>光源识别</h6>
+                            <div class="lighting-info">
+                              <div class="info-item">
+                <span class="label">主要光源:</span>
+                <span class="value">{{ analysisResult.lightingAnalysis.lightSourceIdentification.primarySources?.join(', ') || '无' }}</span>
+              </div>
+                              <div class="info-item">
+                                <span class="label">灯光设置:</span>
+                                <span class="value">{{ analysisResult.lightingAnalysis.lightSourceIdentification.lightingSetup || '无' }}</span>
+                              </div>
+                            </div>
+                          </div>
+                          
+                          <div class="analysis-section">
+                            <h6>环境分析</h6>
+                            <div class="ambient-info">
+                              <div class="info-item">
+                                <span class="label">环境光:</span>
+                                <span class="value">{{ analysisResult.lightingAnalysis.ambientAnalysis.ambientLight || '无' }}</span>
+                              </div>
+                              <div class="info-item">
+                                <span class="label">灯光情绪:</span>
+                                <span class="value">{{ analysisResult.lightingAnalysis.ambientAnalysis.lightingMood || '无' }}</span>
+                              </div>
+                            </div>
+                          </div>
+                        </div>
+                      }
+                    </div>
+                  </div>
+                }
+
                 <div class="result-actions">
                   <button class="view-report-btn" (click)="onViewReportClick()">
                     <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

+ 288 - 8
src/app/shared/components/upload-success-modal/upload-success-modal.component.scss

@@ -33,15 +33,295 @@ $animation-easing: cubic-bezier(0.25, 0.8, 0.25, 1);
     padding: 1rem;
     align-items: center; // 确保移动端也居中显示
   }
-  
-  @media (min-width: $mobile-breakpoint) and (max-width: $tablet-breakpoint) {
-    padding: 1rem;
-    align-items: center; // 确保平板端也居中显示
+}
+
+// 增强分析结果样式
+.enhanced-analysis {
+  margin-top: 24px;
+  border-top: 1px solid #e5e5ea;
+  padding-top: 24px;
+
+  .analysis-tabs {
+    display: flex;
+    gap: 8px;
+    margin-bottom: 20px;
+    border-bottom: 1px solid #e5e5ea;
+    overflow-x: auto;
+    padding-bottom: 12px;
+
+    .tab-btn {
+      padding: 8px 16px;
+      border: none;
+      background: #f8f9fa;
+      color: #666;
+      border-radius: 20px;
+      font-size: 14px;
+      font-weight: 500;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      white-space: nowrap;
+      flex-shrink: 0;
+
+      &:hover {
+        background: #e9ecef;
+        color: #495057;
+      }
+
+      &.active {
+        background: #007AFF;
+        color: white;
+        box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
+      }
+    }
   }
-  
-  @media (min-width: $tablet-breakpoint) {
-    padding: 2rem;
-    align-items: center; // 确保桌面端也居中显示
+
+  .tab-content {
+    min-height: 200px;
+
+    .analysis-section {
+      margin-bottom: 20px;
+
+      h6 {
+        font-size: 16px;
+        font-weight: 600;
+        color: #333;
+        margin-bottom: 12px;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        &::before {
+          content: '';
+          width: 4px;
+          height: 16px;
+          background: #007AFF;
+          border-radius: 2px;
+        }
+      }
+
+      .info-item {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding: 8px 0;
+        border-bottom: 1px solid #f0f0f0;
+
+        &:last-child {
+          border-bottom: none;
+        }
+
+        .label {
+          font-weight: 500;
+          color: #666;
+          font-size: 14px;
+        }
+
+        .value {
+          font-weight: 600;
+          color: #333;
+          font-size: 14px;
+        }
+      }
+    }
+
+    // 色彩分析标签页样式
+    .color-analysis-tab {
+      .mood-atmosphere {
+        display: flex;
+        gap: 12px;
+        margin-bottom: 12px;
+
+        .mood, .atmosphere {
+          padding: 6px 12px;
+          background: #f8f9fa;
+          border-radius: 16px;
+          font-size: 13px;
+          font-weight: 500;
+          color: #495057;
+        }
+      }
+
+      .suitable-spaces {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 8px;
+
+        .space-tag {
+          padding: 4px 10px;
+          background: #e3f2fd;
+          color: #1976d2;
+          border-radius: 12px;
+          font-size: 12px;
+          font-weight: 500;
+        }
+      }
+    }
+
+    // 形体分析标签页样式
+    .form-analysis-tab {
+      .overall-info {
+        .metric {
+          display: flex;
+          align-items: center;
+          gap: 12px;
+          margin-bottom: 12px;
+
+          .metric-label {
+            min-width: 60px;
+            font-size: 13px;
+            font-weight: 500;
+            color: #666;
+          }
+
+          .metric-bar {
+            flex: 1;
+            height: 8px;
+            background: #f0f0f0;
+            border-radius: 4px;
+            overflow: hidden;
+
+            .metric-fill {
+              height: 100%;
+              background: linear-gradient(90deg, #007AFF, #34C759);
+              border-radius: 4px;
+              transition: width 0.3s ease;
+            }
+          }
+
+          .metric-value {
+            min-width: 40px;
+            text-align: right;
+            font-size: 13px;
+            font-weight: 600;
+            color: #333;
+          }
+        }
+      }
+    }
+
+    // 质感分析标签页样式
+    .texture-analysis-tab {
+      .texture-properties {
+        .property-item {
+          display: flex;
+          align-items: center;
+          gap: 12px;
+          margin-bottom: 12px;
+
+          .property-name {
+            min-width: 60px;
+            font-size: 13px;
+            font-weight: 500;
+            color: #666;
+          }
+
+          .property-bar {
+            flex: 1;
+            height: 6px;
+            background: #f0f0f0;
+            border-radius: 3px;
+            overflow: hidden;
+
+            .property-fill {
+              height: 100%;
+              background: linear-gradient(90deg, #FF9500, #FF6B35);
+              border-radius: 3px;
+              transition: width 0.3s ease;
+            }
+          }
+
+          .property-value {
+            min-width: 40px;
+            text-align: right;
+            font-size: 13px;
+            font-weight: 600;
+            color: #333;
+          }
+        }
+      }
+
+      .material-tags {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 8px;
+
+        .material-tag {
+          padding: 6px 12px;
+          border-radius: 16px;
+          font-size: 12px;
+          font-weight: 500;
+
+          &.primary {
+            background: #fff3cd;
+            color: #856404;
+            border: 1px solid #ffeaa7;
+          }
+
+          &.secondary {
+            background: #f8f9fa;
+            color: #6c757d;
+            border: 1px solid #dee2e6;
+          }
+        }
+      }
+    }
+
+    // 纹理分析标签页样式
+    .pattern-analysis-tab {
+      .rhythm-tags {
+        display: flex;
+        gap: 12px;
+
+        .rhythm-tag {
+          padding: 8px 16px;
+          background: #e8f5e8;
+          color: #2e7d32;
+          border-radius: 20px;
+          font-size: 13px;
+          font-weight: 500;
+        }
+      }
+    }
+
+    // 灯光分析标签页样式
+    .lighting-analysis-tab {
+      .lighting-info, .ambient-info {
+        background: #f8f9fa;
+        padding: 16px;
+        border-radius: 12px;
+        margin-bottom: 16px;
+      }
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .enhanced-analysis {
+    .analysis-tabs {
+      .tab-btn {
+        padding: 6px 12px;
+        font-size: 13px;
+      }
+    }
+
+    .tab-content {
+      .analysis-section {
+        h6 {
+          font-size: 15px;
+        }
+
+        .info-item {
+          flex-direction: column;
+          align-items: flex-start;
+          gap: 4px;
+
+          .label, .value {
+            font-size: 13px;
+          }
+        }
+      }
+    }
   }
 }
 

+ 401 - 17
src/app/shared/components/upload-success-modal/upload-success-modal.component.ts

@@ -1,6 +1,10 @@
 import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ChangeDetectionStrategy, HostListener } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { ColorAnalysisService, AnalysisProgress } from '../../services/color-analysis.service';
+import { ColorAnalysisService, AnalysisProgress, ColorAnalysisResult } from '../../services/color-analysis.service';
+import { FormAnalysisService } from '../../services/form-analysis.service';
+import { TextureAnalysisService } from '../../services/texture-analysis.service';
+import { PatternAnalysisService } from '../../services/pattern-analysis.service';
+import { LightingAnalysisService } from '../../services/lighting-analysis.service';
 import { Subscription } from 'rxjs';
 import { modalAnimations } from './upload-success-modal.animations';
 
@@ -20,12 +24,6 @@ export interface ColorInfo {
   name?: string; // 颜色名称,如"深蓝色"、"暖白色"等
 }
 
-export interface ColorAnalysisResult {
-  colors: ColorInfo[];
-  reportUrl?: string;
-  mosaicUrl?: string;
-}
-
 @Component({
   selector: 'app-upload-success-modal',
   standalone: true,
@@ -40,16 +38,20 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy {
   @Input() uploadedFiles: UploadedFile[] = [];
   @Input() uploadType: 'image' | 'document' | 'mixed' = 'image';
   @Input() analysisResult?: ColorAnalysisResult;
+  @Input() isAnalyzing: boolean = false; // 新增:从父组件接收分析状态
 
   @Output() closeModal = new EventEmitter<void>();
   @Output() analyzeColors = new EventEmitter<UploadedFile[]>();
   @Output() viewReport = new EventEmitter<ColorAnalysisResult>();
 
-  // 颜色分析状态
-  isAnalyzing = false;
+  // 移除本地的isAnalyzing属性,使用@Input()的isAnalyzing
+  // isAnalyzing = false; // 已移除,现在从父组件接收
   analysisProgress: AnalysisProgress | null = null;
   analysisError: string | null = null;
   
+  // 增强分析标签页状态
+  activeTab: 'color' | 'form' | 'texture' | 'pattern' | 'lighting' = 'color';
+  
   // 响应式状态
   isMobile = false;
   isTablet = false;
@@ -62,7 +64,13 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy {
   private progressSubscription?: Subscription;
   private resizeSubscription?: Subscription;
 
-  constructor(private colorAnalysisService: ColorAnalysisService) {}
+  constructor(
+    private colorAnalysisService: ColorAnalysisService,
+    private formAnalysisService: FormAnalysisService,
+    private textureAnalysisService: TextureAnalysisService,
+    private patternAnalysisService: PatternAnalysisService,
+    private lightingAnalysisService: LightingAnalysisService
+  ) {}
 
   ngOnInit() {
     this.checkScreenSize();
@@ -93,21 +101,19 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy {
       return;
     }
 
-    this.isAnalyzing = true;
     this.analysisError = null;
 
     try {
       // 发射分析事件给父组件处理
       this.analyzeColors.emit(this.uploadedFiles);
       
-      // 模拟分析过程(实际应该由父组件处理并返回结果)
-      await this.simulateAnalysis();
+      // 注意:不再调用本地的simulateAnalysis,而是等待父组件传递分析结果
+      // 父组件会通过@Input() analysisResult传递分析结果
+      // 父组件也会通过@Input() isAnalyzing控制分析状态
       
     } catch (error) {
       this.analysisError = '颜色分析失败,请重试';
       console.error('Color analysis error:', error);
-    } finally {
-      this.isAnalyzing = false;
     }
   }
 
@@ -124,9 +130,106 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy {
           { hex: '#DEB887', rgb: { r: 222, g: 184, b: 135 }, percentage: 12.5 },
           { hex: '#F5F5DC', rgb: { r: 245, g: 245, b: 220 }, percentage: 2.8 }
         ],
-          reportUrl: '/assets/reports/color-analysis-report.html',
-          mosaicUrl: '/assets/reports/mosaic-image.png'
+        originalImage: this.uploadedFiles[0]?.url || '',
+        mosaicImage: '/assets/images/mock-mosaic.jpg',
+        reportPath: '/reports/color-analysis-' + Date.now() + '.html',
+        enhancedAnalysis: {
+          colorWheel: {
+            dominantHue: 45,
+            saturationRange: { min: 20, max: 80 },
+            brightnessRange: { min: 40, max: 90 },
+            colorDistribution: [
+              { hue: 45, saturation: 65, brightness: 75, percentage: 62.3 },
+              { hue: 30, saturation: 45, brightness: 85, percentage: 22.4 },
+              { hue: 40, saturation: 55, brightness: 70, percentage: 12.5 }
+            ]
+          },
+          colorHarmony: {
+            harmonyType: 'analogous',
+            harmonyScore: 78,
+            suggestions: ['保持温暖色调的统一性', '可适当增加对比色作为点缀'],
+            relationships: [
+              { color1: '#8B4513', color2: '#D2B48C', relationship: '相似色', strength: 85 }
+            ]
+          },
+          colorTemperature: {
+            averageTemperature: 3200,
+            temperatureRange: { min: 2800, max: 3600 },
+            warmCoolBalance: 65,
+            temperatureDescription: '温暖色调,适合营造舒适氛围',
+            lightingRecommendations: ['适合使用暖白光照明(2700K-3000K)', '营造温馨舒适的氛围']
+          },
+          colorPsychology: {
+            mood: '温馨',
+            atmosphere: '舒适',
+            suitableSpaces: ['客厅', '卧室', '餐厅'],
+            psychologicalEffects: ['放松身心', '增强温暖感', '促进交流'],
+            emotionalImpact: {
+              energy: 45,
+              warmth: 85,
+              sophistication: 60,
+              comfort: 90
+            }
+          }
+        },
+        // 模拟其他分析结果
+        formAnalysis: {
+          lineAnalysis: {
+            dominantLines: ['直线', '曲线'],
+            dominantLineType: '直线',
+            visualFlow: '流畅'
+          },
+          overallAssessment: {
+            complexity: 65,
+            visualImpact: 78
+          }
+        },
+        textureAnalysis: {
+          surfaceProperties: {
+            roughness: { level: 'moderate', value: 50, description: '中等粗糙度' },
+            glossiness: { level: 'satin', value: 40, reflectivity: 35 },
+            transparency: { level: 'opaque', value: 10, description: '基本不透明' },
+            reflectivity: { level: 'low', value: 25, description: '低反射' }
+          },
+          materialClassification: {
+            primaryMaterials: ['木材', '织物'],
+            secondaryMaterials: ['金属', '玻璃']
+          }
+        },
+        patternAnalysis: {
+          patternRecognition: {
+            primaryPatterns: [{ type: 'geometric', confidence: 80, coverage: 60, characteristics: ['规则', '对称'] }],
+            patternComplexity: { level: 'moderate', value: 60, description: '中等复杂度' }
+          },
+          visualRhythm: {
+            rhythmType: { primary: 'regular', secondary: 'flowing' },
+            movement: { direction: 'horizontal', intensity: 65 }
+          }
+        },
+        lightingAnalysis: {
+          lightSourceIdentification: {
+            primarySources: ['自然光', '人工光'],
+            lightingSetup: '混合照明'
+          },
+          ambientAnalysis: {
+            ambientLight: '柔和',
+            lightingMood: '温馨'
+          }
+        }
         };
+        
+        // 添加调试输出
+        console.log('=== 分析结果数据结构调试 ===');
+        console.log('完整分析结果:', this.analysisResult);
+        console.log('形体分析:', this.analysisResult.formAnalysis);
+        console.log('质感分析:', this.analysisResult.textureAnalysis);
+        console.log('纹理分析:', this.analysisResult.patternAnalysis);
+        console.log('灯光分析:', this.analysisResult.lightingAnalysis);
+        console.log('色彩分析:', this.analysisResult.enhancedAnalysis);
+        console.log('主要光源:', this.analysisResult.lightingAnalysis.lightSourceIdentification.primarySources);
+        console.log('材质分类:', this.analysisResult.textureAnalysis.materialClassification);
+        console.log('视觉节奏:', this.analysisResult.patternAnalysis.visualRhythm);
+        
         resolve();
       }, 2000);
     });
@@ -608,6 +711,92 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy {
       color: #666;
       margin-top: 4px;
     }
+    .enhanced-section {
+      background: #f8f9fa;
+      border-radius: 12px;
+      padding: 24px;
+      margin-bottom: 30px;
+    }
+    .enhanced-title {
+      font-size: 20px;
+      font-weight: 600;
+      color: #333;
+      margin-bottom: 20px;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+    }
+    .enhanced-title::before {
+      content: '';
+      width: 4px;
+      height: 20px;
+      background: #007AFF;
+      border-radius: 2px;
+    }
+    .analysis-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+      gap: 20px;
+    }
+    .analysis-card {
+      background: white;
+      border-radius: 8px;
+      padding: 20px;
+      border: 1px solid #e5e5ea;
+    }
+    .analysis-card h4 {
+      font-size: 16px;
+      font-weight: 600;
+      color: #333;
+      margin-bottom: 12px;
+    }
+    .info-row {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 8px 0;
+      border-bottom: 1px solid #f0f0f0;
+    }
+    .info-row:last-child {
+      border-bottom: none;
+    }
+    .info-label {
+      font-weight: 500;
+      color: #666;
+      font-size: 14px;
+    }
+    .info-value {
+      font-weight: 600;
+      color: #333;
+      font-size: 14px;
+    }
+    .tag-list {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 8px;
+      margin-top: 8px;
+    }
+    .tag {
+      padding: 4px 10px;
+      background: #e3f2fd;
+      color: #1976d2;
+      border-radius: 12px;
+      font-size: 12px;
+      font-weight: 500;
+    }
+    .progress-bar {
+      width: 100%;
+      height: 8px;
+      background: #f0f0f0;
+      border-radius: 4px;
+      overflow: hidden;
+      margin: 8px 0;
+    }
+    .progress-fill {
+      height: 100%;
+      background: linear-gradient(90deg, #007AFF, #34C759);
+      border-radius: 4px;
+    }
     .footer {
       text-align: center;
       margin-top: 40px;
@@ -655,6 +844,186 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy {
         </div>
       </div>
     </div>
+
+    ${this.analysisResult.enhancedAnalysis ? `
+    <div class="section">
+      <h2 class="section-title">增强色彩分析</h2>
+      <div class="enhanced-section">
+        <div class="enhanced-title">色轮分析</div>
+        <div class="analysis-grid">
+          <div class="analysis-card">
+            <h4>色相分布</h4>
+            <div class="info-row">
+              <span class="info-label">主色调:</span>
+              <span class="info-value">${this.analysisResult.enhancedAnalysis.colorWheel.dominantHue}°</span>
+            </div>
+            <div class="info-row">
+              <span class="info-label">饱和度范围:</span>
+              <span class="info-value">${this.analysisResult.enhancedAnalysis.colorWheel.saturationRange.min}% - ${this.analysisResult.enhancedAnalysis.colorWheel.saturationRange.max}%</span>
+            </div>
+          </div>
+          <div class="analysis-card">
+            <h4>色彩心理学</h4>
+            <div class="info-row">
+              <span class="info-label">情绪:</span>
+              <span class="info-value">${this.analysisResult.enhancedAnalysis.colorPsychology.mood}</span>
+            </div>
+            <div class="info-row">
+              <span class="info-label">氛围:</span>
+              <span class="info-value">${this.analysisResult.enhancedAnalysis.colorPsychology.atmosphere}</span>
+            </div>
+            <div class="tag-list">
+              ${this.analysisResult.enhancedAnalysis.colorPsychology.suitableSpaces.map(space => `<span class="tag">${space}</span>`).join('')}
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    ` : ''}
+
+    ${this.analysisResult.formAnalysis ? `
+    <div class="section">
+      <h2 class="section-title">形体分析</h2>
+      <div class="enhanced-section">
+        <div class="analysis-grid">
+          <div class="analysis-card">
+            <h4>线条分析</h4>
+            <div class="info-row">
+              <span class="info-label">主导线条:</span>
+              <span class="info-value">${this.analysisResult.formAnalysis.lineAnalysis.dominantLineType}</span>
+            </div>
+            <div class="info-row">
+              <span class="info-label">视觉流动:</span>
+              <span class="info-value">${this.analysisResult.formAnalysis.lineAnalysis.visualFlow}</span>
+            </div>
+          </div>
+          <div class="analysis-card">
+            <h4>整体评估</h4>
+            <div class="info-row">
+              <span class="info-label">复杂度:</span>
+              <span class="info-value">${this.analysisResult.formAnalysis.overallAssessment.complexity}%</span>
+            </div>
+            <div class="progress-bar">
+              <div class="progress-fill" style="width: ${this.analysisResult.formAnalysis.overallAssessment.complexity}%"></div>
+            </div>
+            <div class="info-row">
+              <span class="info-label">视觉冲击:</span>
+              <span class="info-value">${this.analysisResult.formAnalysis.overallAssessment.visualImpact}%</span>
+            </div>
+            <div class="progress-bar">
+              <div class="progress-fill" style="width: ${this.analysisResult.formAnalysis.overallAssessment.visualImpact}%"></div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    ` : ''}
+
+    ${this.analysisResult.textureAnalysis ? `
+    <div class="section">
+      <h2 class="section-title">质感分析</h2>
+      <div class="enhanced-section">
+        <div class="analysis-grid">
+          <div class="analysis-card">
+            <h4>表面属性</h4>
+            <div class="info-row">
+              <span class="info-label">粗糙度:</span>
+              <span class="info-value">${this.analysisResult.textureAnalysis.surfaceProperties.roughness}%</span>
+            </div>
+            <div class="progress-bar">
+              <div class="progress-fill" style="width: ${this.analysisResult.textureAnalysis.surfaceProperties.roughness}%"></div>
+            </div>
+            <div class="info-row">
+              <span class="info-label">光泽度:</span>
+              <span class="info-value">${this.analysisResult.textureAnalysis.surfaceProperties.glossiness}%</span>
+            </div>
+            <div class="progress-bar">
+              <div class="progress-fill" style="width: ${this.analysisResult.textureAnalysis.surfaceProperties.glossiness}%"></div>
+            </div>
+          </div>
+          <div class="analysis-card">
+            <h4>材质分类</h4>
+            <div class="info-row">
+              <span class="info-label">主要材质:</span>
+            </div>
+            <div class="tag-list">
+              ${this.analysisResult.textureAnalysis.materialClassification.primaryMaterials.map((material: string) => `<span class="tag">${material}</span>`).join('')}
+            </div>
+            <div class="info-row">
+              <span class="info-label">次要材质:</span>
+            </div>
+            <div class="tag-list">
+              ${this.analysisResult.textureAnalysis.materialClassification.secondaryMaterials.map((material: string) => `<span class="tag">${material}</span>`).join('')}
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    ` : ''}
+
+    ${this.analysisResult.patternAnalysis ? `
+    <div class="section">
+      <h2 class="section-title">纹理分析</h2>
+      <div class="enhanced-section">
+        <div class="analysis-grid">
+          <div class="analysis-card">
+            <h4>图案识别</h4>
+            <div class="info-row">
+              <span class="info-label">主要图案:</span>
+              <span class="info-value">${this.analysisResult.patternAnalysis.patternRecognition.primaryPatterns[0]?.type || '无'}</span>
+            </div>
+            <div class="info-row">
+              <span class="info-label">复杂度:</span>
+              <span class="info-value">${this.analysisResult.patternAnalysis.patternRecognition.complexity}</span>
+            </div>
+          </div>
+          <div class="analysis-card">
+            <h4>视觉节奏</h4>
+            <div class="info-row">
+              <span class="info-label">节奏类型:</span>
+              <span class="info-value">${this.analysisResult.patternAnalysis.visualRhythm.rhythmType}</span>
+            </div>
+            <div class="info-row">
+              <span class="info-label">运动感:</span>
+              <span class="info-value">${this.analysisResult.patternAnalysis.visualRhythm.movement}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    ` : ''}
+
+    ${this.analysisResult.lightingAnalysis ? `
+    <div class="section">
+      <h2 class="section-title">灯光分析</h2>
+      <div class="enhanced-section">
+        <div class="analysis-grid">
+          <div class="analysis-card">
+            <h4>光源识别</h4>
+            <div class="info-row">
+              <span class="info-label">主要光源:</span>
+              <span class="info-value">${this.analysisResult.lightingAnalysis.lightSourceIdentification.primarySources[0] || '无'}</span>
+            </div>
+            <div class="info-row">
+              <span class="info-label">灯光设置:</span>
+              <span class="info-value">${this.analysisResult.lightingAnalysis.lightSourceIdentification.lightingSetup}</span>
+            </div>
+          </div>
+          <div class="analysis-card">
+            <h4>环境分析</h4>
+            <div class="info-row">
+              <span class="info-label">环境光:</span>
+              <span class="info-value">${this.analysisResult.lightingAnalysis.ambientAnalysis.ambientLight}</span>
+            </div>
+            <div class="info-row">
+              <span class="info-label">灯光情绪:</span>
+              <span class="info-value">${this.analysisResult.lightingAnalysis.ambientAnalysis.lightingMood}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    ` : ''}
     
     <div class="section">
       <h2 class="section-title">颜色描述文字</h2>
@@ -699,4 +1068,19 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy {
   private setupResizeListener(): void {
     // 可以添加更复杂的响应式逻辑
   }
+
+  // 获取质感分析属性数组,用于模板中的循环显示
+  getTextureProperties(): Array<{name: string, value: number}> {
+    if (!this.analysisResult?.textureAnalysis?.surfaceProperties) {
+      return [];
+    }
+    
+    const properties = this.analysisResult.textureAnalysis.surfaceProperties;
+    return [
+      { name: '粗糙度', value: properties.roughness?.value || 0 },
+      { name: '光泽度', value: properties.glossiness?.value || 0 },
+      { name: '透明度', value: properties.transparency?.value || 0 },
+      { name: '反射率', value: properties.reflectivity?.value || 0 }
+    ];
+  }
 }

+ 454 - 37
src/app/shared/services/color-analysis.service.ts

@@ -1,7 +1,11 @@
 import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
-import { Observable, BehaviorSubject, throwError } from 'rxjs';
+import { Observable, BehaviorSubject, throwError, forkJoin } from 'rxjs';
 import { catchError, map } from 'rxjs/operators';
+import { FormAnalysisService } from './form-analysis.service';
+import { TextureAnalysisService } from './texture-analysis.service';
+import { PatternAnalysisService } from './pattern-analysis.service';
+import { LightingAnalysisService } from './lighting-analysis.service';
 
 export interface UploadedFile {
   id: string;
@@ -17,10 +21,75 @@ export interface ColorAnalysisResult {
     hex: string;
     rgb: { r: number; g: number; b: number };
     percentage: number;
+    name?: string; // 添加可选的name属性
   }>;
   originalImage: string;
   mosaicImage: string;
   reportPath: string;
+  // 新增增强分析结果
+  enhancedAnalysis?: EnhancedColorAnalysis;
+  // 新增其他分析结果
+  formAnalysis?: any;
+  textureAnalysis?: any;
+  patternAnalysis?: any;
+  lightingAnalysis?: any;
+}
+
+// 新增:增强色彩分析结果接口
+export interface EnhancedColorAnalysis {
+  colorWheel: ColorWheelData;
+  colorHarmony: ColorHarmonyAnalysis;
+  colorTemperature: ColorTemperatureAnalysis;
+  colorPsychology: ColorPsychologyAnalysis;
+}
+
+// 色轮数据
+export interface ColorWheelData {
+  dominantHue: number; // 主色调角度 (0-360)
+  saturationRange: { min: number; max: number }; // 饱和度范围
+  brightnessRange: { min: number; max: number }; // 亮度范围
+  colorDistribution: Array<{
+    hue: number;
+    saturation: number;
+    brightness: number;
+    percentage: number;
+  }>;
+}
+
+// 色彩和谐度分析
+export interface ColorHarmonyAnalysis {
+  harmonyType: 'monochromatic' | 'analogous' | 'complementary' | 'triadic' | 'tetradic' | 'split-complementary';
+  harmonyScore: number; // 0-100
+  suggestions: string[];
+  relationships: Array<{
+    color1: string;
+    color2: string;
+    relationship: string;
+    strength: number;
+  }>;
+}
+
+// 色温详细分析
+export interface ColorTemperatureAnalysis {
+  averageTemperature: number; // 开尔文值
+  temperatureRange: { min: number; max: number };
+  warmCoolBalance: number; // -100(冷) 到 100(暖)
+  temperatureDescription: string;
+  lightingRecommendations: string[];
+}
+
+// 色彩心理学分析
+export interface ColorPsychologyAnalysis {
+  mood: string; // 整体情绪
+  atmosphere: string; // 氛围描述
+  psychologicalEffects: string[];
+  suitableSpaces: string[]; // 适合的空间类型
+  emotionalImpact: {
+    energy: number; // 0-100
+    warmth: number; // 0-100
+    sophistication: number; // 0-100
+    comfort: number; // 0-100
+  };
 }
 
 export interface AnalysisProgress {
@@ -40,7 +109,13 @@ export class ColorAnalysisService {
     progress: 0
   });
 
-  constructor(private http: HttpClient) {}
+  constructor(
+    private http: HttpClient,
+    private formAnalysisService: FormAnalysisService,
+    private textureAnalysisService: TextureAnalysisService,
+    private patternAnalysisService: PatternAnalysisService,
+    private lightingAnalysisService: LightingAnalysisService
+  ) {}
 
   /**
    * 获取分析进度
@@ -149,6 +224,328 @@ export class ColorAnalysisService {
     );
   }
 
+  /**
+   * 增强色彩分析 - 包含色轮、和谐度、色温、心理学分析
+   * @param colors 基础颜色分析结果
+   */
+  performEnhancedColorAnalysis(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): EnhancedColorAnalysis {
+    return {
+      colorWheel: this.analyzeColorWheel(colors),
+      colorHarmony: this.analyzeColorHarmony(colors),
+      colorTemperature: this.analyzeColorTemperature(colors),
+      colorPsychology: this.analyzeColorPsychology(colors)
+    };
+  }
+
+  /**
+   * 色轮分析
+   */
+  private analyzeColorWheel(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorWheelData {
+    const colorDistribution = colors.map(color => {
+      const hsl = this.rgbToHsl(color.rgb.r, color.rgb.g, color.rgb.b);
+      return {
+        hue: hsl.h,
+        saturation: hsl.s,
+        brightness: hsl.l,
+        percentage: color.percentage
+      };
+    });
+
+    const dominantColor = colorDistribution.reduce((prev, current) => 
+      prev.percentage > current.percentage ? prev : current
+    );
+
+    const saturationValues = colorDistribution.map(c => c.saturation);
+    const brightnessValues = colorDistribution.map(c => c.brightness);
+
+    return {
+      dominantHue: dominantColor.hue,
+      saturationRange: {
+        min: Math.min(...saturationValues),
+        max: Math.max(...saturationValues)
+      },
+      brightnessRange: {
+        min: Math.min(...brightnessValues),
+        max: Math.max(...brightnessValues)
+      },
+      colorDistribution
+    };
+  }
+
+  /**
+   * 色彩和谐度分析
+   */
+  private analyzeColorHarmony(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorHarmonyAnalysis {
+    const hues = colors.map(color => {
+      const hsl = this.rgbToHsl(color.rgb.r, color.rgb.g, color.rgb.b);
+      return { hue: hsl.h, hex: color.hex, percentage: color.percentage };
+    });
+
+    // 分析色彩关系
+    const relationships = [];
+    for (let i = 0; i < hues.length; i++) {
+      for (let j = i + 1; j < hues.length; j++) {
+        const hueDiff = Math.abs(hues[i].hue - hues[j].hue);
+        const minDiff = Math.min(hueDiff, 360 - hueDiff);
+        
+        let relationship = '';
+        let strength = 0;
+        
+        if (minDiff < 30) {
+          relationship = '相似色';
+          strength = 90 - minDiff;
+        } else if (minDiff > 150 && minDiff < 210) {
+          relationship = '互补色';
+          strength = 100 - Math.abs(minDiff - 180);
+        } else if (minDiff > 110 && minDiff < 130) {
+          relationship = '三角色';
+          strength = 100 - Math.abs(minDiff - 120);
+        }
+
+        if (relationship) {
+          relationships.push({
+            color1: hues[i].hex,
+            color2: hues[j].hex,
+            relationship,
+            strength
+          });
+        }
+      }
+    }
+
+    // 确定和谐类型
+    let harmonyType: ColorHarmonyAnalysis['harmonyType'] = 'monochromatic';
+    let harmonyScore = 60;
+
+    if (relationships.some(r => r.relationship === '互补色' && r.strength > 80)) {
+      harmonyType = 'complementary';
+      harmonyScore = 85;
+    } else if (relationships.filter(r => r.relationship === '相似色').length >= 2) {
+      harmonyType = 'analogous';
+      harmonyScore = 75;
+    } else if (relationships.some(r => r.relationship === '三角色')) {
+      harmonyType = 'triadic';
+      harmonyScore = 80;
+    }
+
+    return {
+      harmonyType,
+      harmonyScore,
+      relationships,
+      suggestions: this.generateHarmonySuggestions(harmonyType, harmonyScore)
+    };
+  }
+
+  /**
+   * 色温分析
+   */
+  private analyzeColorTemperature(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorTemperatureAnalysis {
+    const temperatures = colors.map(color => {
+      // 简化的色温计算
+      const temp = this.calculateColorTemperature(color.rgb);
+      return { temperature: temp, percentage: color.percentage };
+    });
+
+    const weightedAverage = temperatures.reduce((sum, t) => sum + t.temperature * t.percentage, 0) / 100;
+    const tempValues = temperatures.map(t => t.temperature);
+    
+    const warmCoolBalance = this.calculateWarmCoolBalance(colors);
+    
+    return {
+      averageTemperature: Math.round(weightedAverage),
+      temperatureRange: {
+        min: Math.min(...tempValues),
+        max: Math.max(...tempValues)
+      },
+      warmCoolBalance,
+      temperatureDescription: this.getTemperatureDescription(weightedAverage),
+      lightingRecommendations: this.generateLightingRecommendations(weightedAverage, warmCoolBalance)
+    };
+  }
+
+  /**
+   * 色彩心理学分析
+   */
+  private analyzeColorPsychology(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): ColorPsychologyAnalysis {
+    const psychologyData = colors.map(color => {
+      const psychology = this.getColorPsychology(color.hex);
+      return { ...psychology, percentage: color.percentage };
+    });
+
+    // 计算加权平均情感影响
+    const emotionalImpact = {
+      energy: Math.round(psychologyData.reduce((sum, p) => sum + p.energy * p.percentage, 0) / 100),
+      warmth: Math.round(psychologyData.reduce((sum, p) => sum + p.warmth * p.percentage, 0) / 100),
+      sophistication: Math.round(psychologyData.reduce((sum, p) => sum + p.sophistication * p.percentage, 0) / 100),
+      comfort: Math.round(psychologyData.reduce((sum, p) => sum + p.comfort * p.percentage, 0) / 100)
+    };
+
+    return {
+      mood: this.determineMood(emotionalImpact),
+      atmosphere: this.determineAtmosphere(emotionalImpact),
+      psychologicalEffects: this.aggregatePsychologicalEffects(psychologyData),
+      suitableSpaces: this.determineSuitableSpaces(emotionalImpact),
+      emotionalImpact
+    };
+  }
+
+  // 辅助方法
+  private rgbToHsl(r: number, g: number, b: number): {h: number, s: number, l: number} {
+    r /= 255; g /= 255; b /= 255;
+    const max = Math.max(r, g, b), min = Math.min(r, g, b);
+    let h = 0, s = 0, l = (max + min) / 2;
+
+    if (max !== min) {
+      const d = max - min;
+      s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+      switch (max) {
+        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+        case g: h = (b - r) / d + 2; break;
+        case b: h = (r - g) / d + 4; break;
+      }
+      h /= 6;
+    }
+
+    return { h: h * 360, s: s * 100, l: l * 100 };
+  }
+
+  private calculateColorTemperature(rgb: {r: number, g: number, b: number}): number {
+    // 简化的色温计算公式
+    const ratio = rgb.b / (rgb.r + rgb.g + rgb.b);
+    return Math.round(2000 + ratio * 4000); // 2000K-6000K范围
+  }
+
+  private calculateWarmCoolBalance(colors: Array<{hex: string; rgb: {r: number; g: number; b: number}; percentage: number}>): number {
+    let warmScore = 0;
+    colors.forEach(color => {
+      const { r, g, b } = color.rgb;
+      const warmness = (r - b) / 255 * 100; // 红色减蓝色的比例
+      warmScore += warmness * color.percentage / 100;
+    });
+    return Math.max(-100, Math.min(100, warmScore));
+  }
+
+  private getTemperatureDescription(temp: number): string {
+    if (temp < 3000) return '暖色调';
+    if (temp < 4000) return '中性偏暖';
+    if (temp < 5000) return '中性色调';
+    if (temp < 6000) return '中性偏冷';
+    return '冷色调';
+  }
+
+  private generateLightingRecommendations(temp: number, balance: number): string[] {
+    const recommendations = [];
+    if (temp < 3500) {
+      recommendations.push('适合使用暖白光照明(2700K-3000K)');
+      recommendations.push('营造温馨舒适的氛围');
+    } else if (temp > 5000) {
+      recommendations.push('适合使用冷白光照明(5000K-6500K)');
+      recommendations.push('营造清爽现代的感觉');
+    } else {
+      recommendations.push('适合使用中性白光照明(4000K-4500K)');
+      recommendations.push('平衡温暖与清爽的感觉');
+    }
+    return recommendations;
+  }
+
+  private generateHarmonySuggestions(harmonyType: string, score: number): string[] {
+    const suggestions = [];
+    if (score < 70) {
+      suggestions.push('考虑调整色彩比例以提高和谐度');
+      suggestions.push('可以添加中性色作为过渡');
+    }
+    
+    switch (harmonyType) {
+      case 'complementary':
+        suggestions.push('互补色搭配,建议一主一辅的比例');
+        break;
+      case 'analogous':
+        suggestions.push('相似色搭配,可以添加少量对比色增加活力');
+        break;
+      case 'triadic':
+        suggestions.push('三角色搭配,注意控制各色彩的饱和度');
+        break;
+    }
+    
+    return suggestions;
+  }
+
+  private getColorPsychology(hex: string): {energy: number, warmth: number, sophistication: number, comfort: number} {
+    // 基于色相的心理学属性(简化版)
+    const rgb = this.hexToRgb(hex);
+    if (!rgb) return { energy: 50, warmth: 50, sophistication: 50, comfort: 50 };
+    
+    const hsl = this.rgbToHsl(rgb.r, rgb.g, rgb.b);
+    const hue = hsl.h;
+    
+    // 根据色相确定心理属性
+    if (hue >= 0 && hue < 60) { // 红-橙
+      return { energy: 85, warmth: 90, sophistication: 60, comfort: 70 };
+    } else if (hue >= 60 && hue < 120) { // 黄-绿
+      return { energy: 75, warmth: 70, sophistication: 50, comfort: 80 };
+    } else if (hue >= 120 && hue < 180) { // 绿-青
+      return { energy: 45, warmth: 30, sophistication: 70, comfort: 85 };
+    } else if (hue >= 180 && hue < 240) { // 青-蓝
+      return { energy: 35, warmth: 20, sophistication: 85, comfort: 75 };
+    } else if (hue >= 240 && hue < 300) { // 蓝-紫
+      return { energy: 55, warmth: 40, sophistication: 90, comfort: 65 };
+    } else { // 紫-红
+      return { energy: 70, warmth: 60, sophistication: 80, comfort: 60 };
+    }
+  }
+
+  private hexToRgb(hex: string): {r: number, g: number, b: number} | null {
+    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+    return result ? {
+      r: parseInt(result[1], 16),
+      g: parseInt(result[2], 16),
+      b: parseInt(result[3], 16)
+    } : null;
+  }
+
+  private determineMood(impact: {energy: number, warmth: number, sophistication: number, comfort: number}): string {
+    if (impact.energy > 70 && impact.warmth > 70) return '活力温暖';
+    if (impact.sophistication > 80) return '优雅精致';
+    if (impact.comfort > 80) return '舒适宁静';
+    if (impact.energy > 70) return '充满活力';
+    return '平和稳定';
+  }
+
+  private determineAtmosphere(impact: {energy: number, warmth: number, sophistication: number, comfort: number}): string {
+    if (impact.warmth > 70 && impact.comfort > 70) return '温馨舒适的家居氛围';
+    if (impact.sophistication > 80 && impact.energy < 50) return '高雅静谧的商务氛围';
+    if (impact.energy > 70) return '活跃动感的现代氛围';
+    return '平衡和谐的中性氛围';
+  }
+
+  private aggregatePsychologicalEffects(data: any[]): string[] {
+    const effects = new Set<string>();
+    data.forEach(d => {
+      if (d.energy > 70) effects.add('提升活力和注意力');
+      if (d.warmth > 70) effects.add('营造温暖亲切感');
+      if (d.sophistication > 80) effects.add('增强空间品质感');
+      if (d.comfort > 80) effects.add('促进放松和舒适感');
+    });
+    return Array.from(effects);
+  }
+
+  private determineSuitableSpaces(impact: {energy: number, warmth: number, sophistication: number, comfort: number}): string[] {
+    const spaces = [];
+    if (impact.warmth > 70 && impact.comfort > 70) {
+      spaces.push('客厅', '卧室', '餐厅');
+    }
+    if (impact.sophistication > 80) {
+      spaces.push('办公室', '会议室', '接待区');
+    }
+    if (impact.energy > 70) {
+      spaces.push('工作区', '健身房', '娱乐区');
+    }
+    if (impact.comfort > 80 && impact.energy < 50) {
+      spaces.push('休息区', '阅读角', '冥想室');
+    }
+    return spaces.length > 0 ? spaces : ['通用空间'];
+  }
+
   /**
    * 更新分析进度
    */
@@ -173,44 +570,64 @@ export class ColorAnalysisService {
    */
   simulateAnalysis(imageFile: File): Observable<ColorAnalysisResult> {
     return new Observable(observer => {
-      // 模拟分析步骤
-      const steps = [
-        { stage: 'preparing' as const, message: '准备分析图片...', progress: 10 },
-        { stage: 'processing' as const, message: '生成马赛克图片...', progress: 30 },
-        { stage: 'extracting' as const, message: '提取颜色信息...', progress: 60 },
-        { stage: 'generating' as const, message: '生成分析报告...', progress: 90 },
-      ];
-
-      let currentStep = 0;
-      const interval = setInterval(() => {
-        if (currentStep < steps.length) {
-          const step = steps[currentStep];
-          this.updateProgress(step.stage, step.message, step.progress);
-          currentStep++;
-        } else {
-          clearInterval(interval);
+      this.updateProgress('processing', '开始分析...', 10);
+      
+      setTimeout(() => {
+        this.updateProgress('extracting', '提取颜色信息...', 30);
+        
+        setTimeout(() => {
+          this.updateProgress('generating', '生成分析报告...', 70);
           
-          // 模拟分析结果
-          const mockResult: ColorAnalysisResult = {
-            colors: [
-              { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
-              { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3 },
-              { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7 },
-              { hex: '#96CEB4', rgb: { r: 150, g: 206, b: 180 }, percentage: 12.1 },
-              { hex: '#FFEAA7', rgb: { r: 255, g: 234, b: 167 }, percentage: 10.8 },
-              { hex: '#DDA0DD', rgb: { r: 221, g: 160, b: 221 }, percentage: 8.9 },
-              { hex: '#98D8C8', rgb: { r: 152, g: 216, b: 200 }, percentage: 8.7 }
-            ],
-            originalImage: URL.createObjectURL(imageFile),
-            mosaicImage: URL.createObjectURL(imageFile), // 在实际应用中这里应该是处理后的图片
-            reportPath: '/mock-report.html'
+          // 使用forkJoin来并行处理所有分析服务
+          const analysisObservables = {
+            formAnalysis: this.formAnalysisService.analyzeImageForm(imageFile),
+            textureAnalysis: this.textureAnalysisService.analyzeImageTexture(imageFile),
+            patternAnalysis: this.patternAnalysisService.analyzeImagePattern(imageFile),
+            lightingAnalysis: this.lightingAnalysisService.analyzeImageLighting(imageFile)
           };
 
-          this.updateProgress('completed', '分析完成', 100);
-          observer.next(mockResult);
-          observer.complete();
-        }
-      }, 800);
+          forkJoin(analysisObservables).subscribe({
+            next: (analysisResults) => {
+              const mockResult: ColorAnalysisResult = {
+                colors: [
+                  { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
+                  { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3 },
+                  { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7 },
+                  { hex: '#96CEB4', rgb: { r: 150, g: 206, b: 180 }, percentage: 12.1 },
+                  { hex: '#FFEAA7', rgb: { r: 255, g: 234, b: 167 }, percentage: 10.8 },
+                  { hex: '#DDA0DD', rgb: { r: 221, g: 160, b: 221 }, percentage: 8.9 },
+                  { hex: '#98D8C8', rgb: { r: 152, g: 216, b: 200 }, percentage: 8.7 }
+                ],
+                originalImage: URL.createObjectURL(imageFile),
+                mosaicImage: URL.createObjectURL(imageFile), // 在实际应用中这里应该是处理后的图片
+                reportPath: '/mock-report.html',
+                // 添加增强色彩分析
+                enhancedAnalysis: this.performEnhancedColorAnalysis([
+                  { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
+                  { hex: '#4ECDC4', rgb: { r: 78, g: 205, b: 196 }, percentage: 18.3 },
+                  { hex: '#45B7D1', rgb: { r: 69, g: 183, b: 209 }, percentage: 15.7 },
+                  { hex: '#96CEB4', rgb: { r: 150, g: 206, b: 180 }, percentage: 12.1 },
+                  { hex: '#FFEAA7', rgb: { r: 255, g: 234, b: 167 }, percentage: 10.8 }
+                ]),
+                // 添加其他分析结果
+                formAnalysis: analysisResults.formAnalysis,
+                textureAnalysis: analysisResults.textureAnalysis,
+                patternAnalysis: analysisResults.patternAnalysis,
+                lightingAnalysis: analysisResults.lightingAnalysis
+              };
+
+              this.updateProgress('completed', '分析完成', 100);
+              observer.next(mockResult);
+              observer.complete();
+            },
+            error: (error) => {
+              console.error('分析服务出错:', error);
+              this.updateProgress('error', '分析失败', 0);
+              observer.error(error);
+            }
+          });
+        }, 500);
+      }, 300);
     });
   }
 }

+ 292 - 0
src/app/shared/services/form-analysis.service.ts

@@ -0,0 +1,292 @@
+import { Injectable } from '@angular/core';
+import { Observable, of } from 'rxjs';
+
+// 形体分析结果接口
+export interface FormAnalysisResult {
+  lineAnalysis: LineAnalysis;
+  geometryAnalysis: GeometryAnalysis;
+  proportionAnalysis: ProportionAnalysis;
+  overallAssessment: OverallFormAssessment;
+}
+
+// 线条分析
+export interface LineAnalysis {
+  dominantLineType: 'straight' | 'curved' | 'mixed';
+  lineDirection: {
+    horizontal: number; // 0-100
+    vertical: number;   // 0-100
+    diagonal: number;   // 0-100
+  };
+  lineWeight: 'thin' | 'medium' | 'thick' | 'varied';
+  lineQuality: {
+    smoothness: number; // 0-100
+    continuity: number; // 0-100
+    precision: number;  // 0-100
+  };
+  suggestions: string[];
+}
+
+// 几何形状分析
+export interface GeometryAnalysis {
+  primaryShapes: Array<{
+    shape: 'circle' | 'square' | 'rectangle' | 'triangle' | 'polygon' | 'organic';
+    percentage: number;
+    characteristics: string[];
+  }>;
+  complexity: 'simple' | 'moderate' | 'complex';
+  symmetry: {
+    type: 'bilateral' | 'radial' | 'asymmetric';
+    score: number; // 0-100
+  };
+  balance: {
+    visual: number; // 0-100
+    compositional: number; // 0-100
+  };
+}
+
+// 比例分析
+export interface ProportionAnalysis {
+  goldenRatio: {
+    present: boolean;
+    score: number; // 0-100
+    applications: string[];
+  };
+  aspectRatio: {
+    width: number;
+    height: number;
+    ratio: string;
+  };
+  scaleRelationships: Array<{
+    element1: string;
+    element2: string;
+    ratio: number;
+    harmony: number; // 0-100
+  }>;
+  proportionalHarmony: number; // 0-100
+}
+
+// 整体形体评估
+export interface OverallFormAssessment {
+  styleClassification: string[];
+  designPrinciples: {
+    unity: number;      // 0-100
+    balance: number;    // 0-100
+    emphasis: number;   // 0-100
+    rhythm: number;     // 0-100
+  };
+  spatialQuality: {
+    openness: number;   // 0-100
+    flow: number;       // 0-100
+    hierarchy: number;  // 0-100
+  };
+  recommendations: string[];
+}
+
+@Injectable({
+  providedIn: 'root'
+})
+export class FormAnalysisService {
+
+  constructor() { }
+
+  /**
+   * 分析图片中的形体特征
+   * @param imageFile 图片文件
+   */
+  analyzeImageForm(imageFile: File): Observable<FormAnalysisResult> {
+    // 模拟分析过程
+    return of(this.simulateFormAnalysis(imageFile));
+  }
+
+  /**
+   * 分析上传的图片文件形体
+   * @param imageUrl 图片URL
+   */
+  analyzeFormFromUrl(imageUrl: string): Observable<FormAnalysisResult> {
+    return of(this.simulateFormAnalysisFromUrl(imageUrl));
+  }
+
+  /**
+   * 模拟形体分析(实际项目中应该调用AI服务)
+   */
+  private simulateFormAnalysis(imageFile: File): FormAnalysisResult {
+    // 基于文件名或随机生成模拟数据
+    const fileName = imageFile.name.toLowerCase();
+    
+    return {
+      lineAnalysis: this.generateLineAnalysis(fileName),
+      geometryAnalysis: this.generateGeometryAnalysis(fileName),
+      proportionAnalysis: this.generateProportionAnalysis(fileName),
+      overallAssessment: this.generateOverallAssessment(fileName)
+    };
+  }
+
+  private simulateFormAnalysisFromUrl(imageUrl: string): FormAnalysisResult {
+    const urlLower = imageUrl.toLowerCase();
+    
+    return {
+      lineAnalysis: this.generateLineAnalysis(urlLower),
+      geometryAnalysis: this.generateGeometryAnalysis(urlLower),
+      proportionAnalysis: this.generateProportionAnalysis(urlLower),
+      overallAssessment: this.generateOverallAssessment(urlLower)
+    };
+  }
+
+  private generateLineAnalysis(context: string): LineAnalysis {
+    // 根据上下文生成不同的线条分析
+    const isModern = context.includes('modern') || context.includes('contemporary');
+    const isClassical = context.includes('classic') || context.includes('traditional');
+    
+    if (isModern) {
+      return {
+        dominantLineType: 'straight',
+        lineDirection: { horizontal: 60, vertical: 30, diagonal: 10 },
+        lineWeight: 'thin',
+        lineQuality: { smoothness: 90, continuity: 85, precision: 95 },
+        suggestions: ['保持简洁的线条设计', '强调水平线条的延展感', '注意线条的精确度']
+      };
+    } else if (isClassical) {
+      return {
+        dominantLineType: 'curved',
+        lineDirection: { horizontal: 40, vertical: 35, diagonal: 25 },
+        lineWeight: 'medium',
+        lineQuality: { smoothness: 85, continuity: 90, precision: 80 },
+        suggestions: ['增强曲线的优雅感', '平衡各方向线条的比例', '注意线条的流畅性']
+      };
+    } else {
+      return {
+        dominantLineType: 'mixed',
+        lineDirection: { horizontal: 45, vertical: 35, diagonal: 20 },
+        lineWeight: 'varied',
+        lineQuality: { smoothness: 75, continuity: 80, precision: 85 },
+        suggestions: ['协调直线与曲线的关系', '统一线条的视觉重量', '提升整体线条质量']
+      };
+    }
+  }
+
+  private generateGeometryAnalysis(context: string): GeometryAnalysis {
+    const isMinimalist = context.includes('minimal') || context.includes('simple');
+    const isOrganic = context.includes('organic') || context.includes('natural');
+    
+    if (isMinimalist) {
+      return {
+        primaryShapes: [
+          { shape: 'rectangle', percentage: 60, characteristics: ['简洁', '规整', '现代'] },
+          { shape: 'square', percentage: 25, characteristics: ['稳定', '平衡'] },
+          { shape: 'circle', percentage: 15, characteristics: ['柔和', '完整'] }
+        ],
+        complexity: 'simple',
+        symmetry: { type: 'bilateral', score: 90 },
+        balance: { visual: 95, compositional: 90 }
+      };
+    } else if (isOrganic) {
+      return {
+        primaryShapes: [
+          { shape: 'organic', percentage: 70, characteristics: ['自然', '流动', '有机'] },
+          { shape: 'circle', percentage: 20, characteristics: ['柔和', '和谐'] },
+          { shape: 'polygon', percentage: 10, characteristics: ['变化', '动态'] }
+        ],
+        complexity: 'moderate',
+        symmetry: { type: 'asymmetric', score: 30 },
+        balance: { visual: 75, compositional: 80 }
+      };
+    } else {
+      return {
+        primaryShapes: [
+          { shape: 'rectangle', percentage: 40, characteristics: ['结构化', '功能性'] },
+          { shape: 'circle', percentage: 30, characteristics: ['和谐', '完整'] },
+          { shape: 'triangle', percentage: 20, characteristics: ['动态', '指向性'] },
+          { shape: 'polygon', percentage: 10, characteristics: ['复杂', '装饰性'] }
+        ],
+        complexity: 'moderate',
+        symmetry: { type: 'bilateral', score: 70 },
+        balance: { visual: 80, compositional: 85 }
+      };
+    }
+  }
+
+  private generateProportionAnalysis(context: string): ProportionAnalysis {
+    const hasGoldenRatio = Math.random() > 0.5;
+    
+    return {
+      goldenRatio: {
+        present: hasGoldenRatio,
+        score: hasGoldenRatio ? 85 + Math.random() * 15 : 30 + Math.random() * 40,
+        applications: hasGoldenRatio ? 
+          ['主要构图比例', '元素间距关系', '视觉焦点定位'] : 
+          ['可考虑应用黄金比例优化构图']
+      },
+      aspectRatio: {
+        width: 16,
+        height: 9,
+        ratio: '16:9'
+      },
+      scaleRelationships: [
+        { element1: '主体', element2: '背景', ratio: 1.618, harmony: 85 },
+        { element1: '前景', element2: '中景', ratio: 1.414, harmony: 75 },
+        { element1: '细节', element2: '整体', ratio: 0.618, harmony: 90 }
+      ],
+      proportionalHarmony: 75 + Math.random() * 20
+    };
+  }
+
+  private generateOverallAssessment(context: string): OverallFormAssessment {
+    const isContemporary = context.includes('contemporary') || context.includes('modern');
+    
+    const baseStyles = ['现代简约', '功能主义'];
+    if (context.includes('luxury')) baseStyles.push('奢华风格');
+    if (context.includes('natural')) baseStyles.push('自然风格');
+    if (context.includes('industrial')) baseStyles.push('工业风格');
+    
+    return {
+      styleClassification: baseStyles,
+      designPrinciples: {
+        unity: 80 + Math.random() * 15,
+        balance: 75 + Math.random() * 20,
+        emphasis: 70 + Math.random() * 25,
+        rhythm: 65 + Math.random() * 30
+      },
+      spatialQuality: {
+        openness: isContemporary ? 85 + Math.random() * 10 : 60 + Math.random() * 25,
+        flow: 70 + Math.random() * 25,
+        hierarchy: 75 + Math.random() * 20
+      },
+      recommendations: [
+        '保持设计的整体一致性',
+        '注意元素间的比例关系',
+        '强化视觉层次的表达',
+        '优化空间的流动性'
+      ]
+    };
+  }
+
+  /**
+   * 获取形体分析建议
+   * @param result 分析结果
+   */
+  getFormRecommendations(result: FormAnalysisResult): string[] {
+    const recommendations = [];
+    
+    // 基于线条分析的建议
+    if (result.lineAnalysis.lineQuality.smoothness < 70) {
+      recommendations.push('提升线条的流畅度和精确性');
+    }
+    
+    // 基于几何分析的建议
+    if (result.geometryAnalysis.balance.visual < 70) {
+      recommendations.push('调整元素布局以改善视觉平衡');
+    }
+    
+    // 基于比例分析的建议
+    if (result.proportionAnalysis.proportionalHarmony < 70) {
+      recommendations.push('优化元素间的比例关系');
+    }
+    
+    // 基于整体评估的建议
+    if (result.overallAssessment.designPrinciples.unity < 70) {
+      recommendations.push('增强设计的统一性');
+    }
+    
+    return recommendations.length > 0 ? recommendations : ['当前形体设计已达到良好水平'];
+  }
+}

+ 815 - 0
src/app/shared/services/lighting-analysis.service.ts

@@ -0,0 +1,815 @@
+import { Injectable } from '@angular/core';
+import { Observable, of } from 'rxjs';
+
+// 灯光分析结果接口
+export interface LightingAnalysisResult {
+  lightSourceIdentification: LightSourceIdentification;
+  illuminationAnalysis: IlluminationAnalysis;
+  shadowAnalysis: ShadowAnalysis;
+  ambientAnalysis: AmbientAnalysis;
+  lightingRecommendations: string[];
+}
+
+// 光源识别
+export interface LightSourceIdentification {
+  primarySources: Array<{
+    type: 'natural' | 'artificial' | 'mixed';
+    subtype: string; // 如:'sunlight', 'LED', 'fluorescent', 'incandescent', 'candle'
+    position: {
+      direction: 'top' | 'front' | 'back' | 'left' | 'right' | 'multiple';
+      angle: number; // 0-360度
+      distance: 'close' | 'medium' | 'far' | 'unknown';
+    };
+    intensity: number; // 0-100
+    confidence: number; // 0-100
+  }>;
+  lightingSetup: {
+    complexity: 'simple' | 'moderate' | 'complex' | 'professional';
+    sourceCount: number;
+    dominantSource: string;
+    lightingStyle: 'dramatic' | 'soft' | 'even' | 'accent' | 'task' | 'ambient';
+  };
+}
+
+// 照明效果分析
+export interface IlluminationAnalysis {
+  brightness: {
+    overall: number; // 0-100
+    distribution: 'even' | 'uneven' | 'gradient' | 'spotty';
+    dynamicRange: number; // 0-100
+    exposure: 'underexposed' | 'well-exposed' | 'overexposed' | 'mixed';
+  };
+  contrast: {
+    level: number; // 0-100
+    type: 'low' | 'medium' | 'high' | 'extreme';
+    areas: {
+      highlights: number; // 0-100
+      midtones: number; // 0-100
+      shadows: number; // 0-100
+    };
+  };
+  colorTemperature: {
+    kelvin: number; // 色温值
+    warmth: 'very-warm' | 'warm' | 'neutral' | 'cool' | 'very-cool';
+    consistency: number; // 0-100
+    mixedLighting: boolean;
+  };
+  lightQuality: {
+    softness: number; // 0-100 (0=hard, 100=soft)
+    diffusion: number; // 0-100
+    directionality: number; // 0-100 (0=omnidirectional, 100=highly directional)
+    evenness: number; // 0-100
+  };
+}
+
+// 阴影分析
+export interface ShadowAnalysis {
+  shadowPresence: {
+    coverage: number; // 0-100
+    intensity: number; // 0-100
+    sharpness: 'very-soft' | 'soft' | 'medium' | 'sharp' | 'very-sharp';
+    definition: number; // 0-100
+  };
+  shadowCharacteristics: {
+    direction: string;
+    length: 'short' | 'medium' | 'long' | 'varied';
+    density: number; // 0-100
+    falloff: 'gradual' | 'medium' | 'abrupt';
+  };
+  shadowTypes: Array<{
+    type: 'cast' | 'form' | 'occlusion' | 'contact';
+    prominence: number; // 0-100
+    contribution: string;
+  }>;
+  dimensionalEffect: {
+    depth: number; // 0-100
+    volume: number; // 0-100
+    threedimensionality: number; // 0-100
+  };
+}
+
+// 环境光分析
+export interface AmbientAnalysis {
+  ambientLevel: {
+    strength: number; // 0-100
+    uniformity: number; // 0-100
+    contribution: number; // 0-100 (相对于直接光的贡献)
+  };
+  lightingMood: {
+    primary: 'dramatic' | 'romantic' | 'energetic' | 'calm' | 'mysterious' | 'cheerful' | 'professional';
+    intensity: number; // 0-100
+    emotional_impact: string[];
+  };
+  atmosphericEffects: {
+    haze: number; // 0-100
+    glare: number; // 0-100
+    reflections: number; // 0-100
+    transparency: number; // 0-100
+  };
+  spatialPerception: {
+    depth_enhancement: number; // 0-100
+    space_definition: number; // 0-100
+    focal_guidance: number; // 0-100
+  };
+}
+
+@Injectable({
+  providedIn: 'root'
+})
+export class LightingAnalysisService {
+
+  constructor() { }
+
+  /**
+   * 分析图片中的灯光效果
+   * @param imageFile 图片文件
+   */
+  analyzeImageLighting(imageFile: File): Observable<LightingAnalysisResult> {
+    return of(this.simulateLightingAnalysis(imageFile));
+  }
+
+  /**
+   * 分析URL图片的灯光效果
+   * @param imageUrl 图片URL
+   */
+  analyzeLightingFromUrl(imageUrl: string): Observable<LightingAnalysisResult> {
+    return of(this.simulateLightingAnalysisFromUrl(imageUrl));
+  }
+
+  /**
+   * 模拟灯光分析
+   */
+  private simulateLightingAnalysis(imageFile: File): LightingAnalysisResult {
+    const fileName = imageFile.name.toLowerCase();
+    return this.generateLightingAnalysis(fileName);
+  }
+
+  private simulateLightingAnalysisFromUrl(imageUrl: string): LightingAnalysisResult {
+    const urlLower = imageUrl.toLowerCase();
+    return this.generateLightingAnalysis(urlLower);
+  }
+
+  private generateLightingAnalysis(context: string): LightingAnalysisResult {
+    const lightingType = this.inferLightingType(context);
+    
+    return {
+      lightSourceIdentification: this.generateLightSourceIdentification(lightingType, context),
+      illuminationAnalysis: this.generateIlluminationAnalysis(lightingType, context),
+      shadowAnalysis: this.generateShadowAnalysis(lightingType, context),
+      ambientAnalysis: this.generateAmbientAnalysis(lightingType, context),
+      lightingRecommendations: this.generateLightingRecommendations(lightingType, context)
+    };
+  }
+
+  private inferLightingType(context: string): string {
+    if (context.includes('natural') || context.includes('sun') || context.includes('daylight')) return 'natural';
+    if (context.includes('artificial') || context.includes('led') || context.includes('lamp')) return 'artificial';
+    if (context.includes('dramatic') || context.includes('shadow')) return 'dramatic';
+    if (context.includes('soft') || context.includes('diffuse')) return 'soft';
+    if (context.includes('bright') || context.includes('high')) return 'bright';
+    if (context.includes('dim') || context.includes('low')) return 'dim';
+    if (context.includes('warm')) return 'warm';
+    if (context.includes('cool')) return 'cool';
+    return 'mixed'; // 默认混合光源
+  }
+
+  private generateLightSourceIdentification(lightingType: string, context: string): LightSourceIdentification {
+    const isNatural = lightingType === 'natural' || context.includes('outdoor');
+    const isComplex = context.includes('complex') || context.includes('multiple');
+    
+    return {
+      primarySources: this.generatePrimarySources(lightingType, isNatural, isComplex),
+      lightingSetup: {
+        complexity: isComplex ? 'complex' : this.getLightingComplexity(lightingType),
+        sourceCount: isComplex ? 3 + Math.floor(Math.random() * 3) : this.getSourceCount(lightingType),
+        dominantSource: this.getDominantSource(lightingType, isNatural),
+        lightingStyle: this.getLightingStyle(lightingType)
+      }
+    };
+  }
+
+  private generatePrimarySources(lightingType: string, isNatural: boolean, isComplex: boolean): any[] {
+    const sources = [];
+    
+    if (isNatural) {
+      sources.push({
+        type: 'natural',
+        subtype: 'sunlight',
+        position: {
+          direction: 'top',
+          angle: 45 + Math.random() * 90,
+          distance: 'far'
+        },
+        intensity: 70 + Math.random() * 25,
+        confidence: 85 + Math.random() * 10
+      });
+    } else {
+      sources.push({
+        type: 'artificial',
+        subtype: this.getArtificialSubtype(lightingType),
+        position: {
+          direction: this.getLightDirection(lightingType),
+          angle: Math.random() * 360,
+          distance: this.getLightDistance(lightingType)
+        },
+        intensity: this.getLightIntensity(lightingType),
+        confidence: 80 + Math.random() * 15
+      });
+    }
+
+    if (isComplex) {
+      // 添加辅助光源
+      sources.push({
+        type: 'artificial',
+        subtype: 'LED',
+        position: {
+          direction: 'front',
+          angle: 30 + Math.random() * 60,
+          distance: 'medium'
+        },
+        intensity: 40 + Math.random() * 30,
+        confidence: 70 + Math.random() * 20
+      });
+    }
+
+    return sources;
+  }
+
+  private generateIlluminationAnalysis(lightingType: string, context: string): IlluminationAnalysis {
+    const isBright = lightingType === 'bright' || context.includes('bright');
+    const isDim = lightingType === 'dim' || context.includes('dim');
+    const isWarm = lightingType === 'warm' || context.includes('warm');
+    const isCool = lightingType === 'cool' || context.includes('cool');
+    
+    return {
+      brightness: {
+        overall: this.getBrightnessLevel(lightingType, isBright, isDim),
+        distribution: this.getBrightnessDistribution(lightingType),
+        dynamicRange: this.getDynamicRange(lightingType),
+        exposure: this.getExposureLevel(lightingType, isBright, isDim)
+      },
+      contrast: {
+        level: this.getContrastLevel(lightingType),
+        type: this.getContrastType(lightingType),
+        areas: {
+          highlights: this.getHighlights(lightingType),
+          midtones: this.getMidtones(lightingType),
+          shadows: this.getShadowsLevel(lightingType)
+        }
+      },
+      colorTemperature: {
+        kelvin: this.getColorTemperature(lightingType, isWarm, isCool),
+        warmth: this.getWarmthLevel(lightingType, isWarm, isCool),
+        consistency: this.getTemperatureConsistency(lightingType),
+        mixedLighting: lightingType === 'mixed' || context.includes('mixed')
+      },
+      lightQuality: {
+        softness: this.getLightSoftness(lightingType),
+        diffusion: this.getLightDiffusion(lightingType),
+        directionality: this.getLightDirectionality(lightingType),
+        evenness: this.getLightEvenness(lightingType)
+      }
+    };
+  }
+
+  private generateShadowAnalysis(lightingType: string, context: string): ShadowAnalysis {
+    const isDramatic = lightingType === 'dramatic' || context.includes('dramatic');
+    const isSoft = lightingType === 'soft' || context.includes('soft');
+    
+    return {
+      shadowPresence: {
+        coverage: this.getShadowCoverage(lightingType, isDramatic),
+        intensity: this.getShadowIntensity(lightingType, isDramatic),
+        sharpness: this.getShadowSharpness(lightingType, isSoft),
+        definition: this.getShadowDefinition(lightingType)
+      },
+      shadowCharacteristics: {
+        direction: this.getShadowDirection(lightingType),
+        length: this.getShadowLength(lightingType),
+        density: this.getShadowDensity(lightingType),
+        falloff: this.getShadowFalloff(lightingType, isSoft)
+      },
+      shadowTypes: this.getShadowTypes(lightingType),
+      dimensionalEffect: {
+        depth: this.getDepthEffect(lightingType, isDramatic),
+        volume: this.getVolumeEffect(lightingType),
+        threedimensionality: this.get3DEffect(lightingType, isDramatic)
+      }
+    };
+  }
+
+  private generateAmbientAnalysis(lightingType: string, context: string): AmbientAnalysis {
+    return {
+      ambientLevel: {
+        strength: this.getAmbientStrength(lightingType),
+        uniformity: this.getAmbientUniformity(lightingType),
+        contribution: this.getAmbientContribution(lightingType)
+      },
+      lightingMood: {
+        primary: this.getLightingMood(lightingType, context),
+        intensity: this.getMoodIntensity(lightingType),
+        emotional_impact: this.getEmotionalImpact(lightingType, context)
+      },
+      atmosphericEffects: {
+        haze: this.getHazeLevel(lightingType, context),
+        glare: this.getGlareLevel(lightingType),
+        reflections: this.getReflectionLevel(lightingType, context),
+        transparency: this.getTransparencyLevel(lightingType)
+      },
+      spatialPerception: {
+        depth_enhancement: this.getDepthEnhancement(lightingType),
+        space_definition: this.getSpaceDefinition(lightingType),
+        focal_guidance: this.getFocalGuidance(lightingType)
+      }
+    };
+  }
+
+  private generateLightingRecommendations(lightingType: string, context: string): string[] {
+    const recommendations = [];
+    
+    // 基于光照类型的建议
+    switch (lightingType) {
+      case 'natural':
+        recommendations.push('充分利用自然光的方向性和时间变化');
+        recommendations.push('考虑添加辅助人工光源平衡光照');
+        break;
+      case 'artificial':
+        recommendations.push('注意人工光源的色温一致性');
+        recommendations.push('避免过度依赖单一光源');
+        break;
+      case 'dramatic':
+        recommendations.push('保持强烈的明暗对比效果');
+        recommendations.push('注意阴影的艺术表现力');
+        break;
+      case 'soft':
+        recommendations.push('维持柔和均匀的光照效果');
+        recommendations.push('避免产生过强的阴影');
+        break;
+      case 'bright':
+        recommendations.push('控制过度曝光的风险');
+        recommendations.push('注意高光区域的细节保留');
+        break;
+      case 'dim':
+        recommendations.push('增强关键区域的照明');
+        recommendations.push('注意暗部细节的可见性');
+        break;
+    }
+    
+    // 基于上下文的建议
+    if (context.includes('interior')) {
+      recommendations.push('考虑室内空间的光照层次');
+      recommendations.push('注意光照对材质表现的影响');
+    }
+    if (context.includes('portrait')) {
+      recommendations.push('优化面部光照的均匀性');
+      recommendations.push('避免产生不利的阴影');
+    }
+    if (context.includes('product')) {
+      recommendations.push('确保产品细节的清晰展示');
+      recommendations.push('避免反光和眩光问题');
+    }
+    
+    return recommendations.length > 0 ? recommendations : ['保持光照设计的整体协调性'];
+  }
+
+  // 辅助方法实现
+  private getLightingComplexity(lightingType: string): 'simple' | 'moderate' | 'complex' | 'professional' {
+    const complexities: { [key: string]: 'simple' | 'moderate' | 'complex' | 'professional' } = {
+      natural: 'simple', artificial: 'moderate', dramatic: 'complex',
+      soft: 'moderate', bright: 'simple', dim: 'moderate',
+      warm: 'simple', cool: 'simple', mixed: 'complex'
+    };
+    return complexities[lightingType] || 'moderate';
+  }
+
+  private getSourceCount(lightingType: string): number {
+    const counts: { [key: string]: number } = {
+      natural: 1, artificial: 2, dramatic: 3, soft: 2,
+      bright: 1, dim: 2, warm: 1, cool: 1, mixed: 3
+    };
+    return counts[lightingType] || 2;
+  }
+
+  private getDominantSource(lightingType: string, isNatural: boolean): string {
+    if (isNatural) return 'sunlight';
+    const sources: { [key: string]: string } = {
+      artificial: 'LED', dramatic: 'spotlight', soft: 'softbox',
+      bright: 'floodlight', dim: 'ambient', warm: 'incandescent',
+      cool: 'fluorescent', mixed: 'multiple'
+    };
+    return sources[lightingType] || 'LED';
+  }
+
+  private getLightingStyle(lightingType: string): 'dramatic' | 'soft' | 'even' | 'accent' | 'task' | 'ambient' {
+    const styles: { [key: string]: 'dramatic' | 'soft' | 'even' | 'accent' | 'task' | 'ambient' } = {
+      natural: 'even', artificial: 'task', dramatic: 'dramatic',
+      soft: 'soft', bright: 'even', dim: 'ambient',
+      warm: 'ambient', cool: 'task', mixed: 'accent'
+    };
+    return styles[lightingType] || 'even';
+  }
+
+  private getArtificialSubtype(lightingType: string): string {
+    const subtypes: { [key: string]: string } = {
+      artificial: 'LED', dramatic: 'spotlight', soft: 'softbox',
+      bright: 'floodlight', dim: 'ambient', warm: 'incandescent',
+      cool: 'fluorescent', mixed: 'LED'
+    };
+    return subtypes[lightingType] || 'LED';
+  }
+
+  private getLightDirection(lightingType: string): 'top' | 'front' | 'back' | 'left' | 'right' | 'multiple' {
+    const directions: { [key: string]: 'top' | 'front' | 'back' | 'left' | 'right' | 'multiple' } = {
+      natural: 'top', artificial: 'front', dramatic: 'left',
+      soft: 'front', bright: 'top', dim: 'multiple',
+      warm: 'front', cool: 'top', mixed: 'multiple'
+    };
+    return directions[lightingType] || 'front';
+  }
+
+  private getLightDistance(lightingType: string): 'close' | 'medium' | 'far' | 'unknown' {
+    const distances: { [key: string]: 'close' | 'medium' | 'far' | 'unknown' } = {
+      natural: 'far', artificial: 'medium', dramatic: 'close',
+      soft: 'medium', bright: 'far', dim: 'close',
+      warm: 'close', cool: 'medium', mixed: 'medium'
+    };
+    return distances[lightingType] || 'medium';
+  }
+
+  private getLightIntensity(lightingType: string): number {
+    const intensities: { [key: string]: number } = {
+      natural: 80, artificial: 70, dramatic: 85, soft: 60,
+      bright: 90, dim: 30, warm: 65, cool: 75, mixed: 70
+    };
+    return (intensities[lightingType] || 70) + Math.random() * 15;
+  }
+
+  private getBrightnessLevel(lightingType: string, isBright: boolean, isDim: boolean): number {
+    if (isBright) return 80 + Math.random() * 15;
+    if (isDim) return 20 + Math.random() * 20;
+    
+    const levels: { [key: string]: number } = {
+      natural: 75, artificial: 65, dramatic: 60, soft: 70,
+      warm: 60, cool: 70, mixed: 65
+    };
+    return (levels[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getBrightnessDistribution(lightingType: string): 'even' | 'uneven' | 'gradient' | 'spotty' {
+    const distributions: { [key: string]: 'even' | 'uneven' | 'gradient' | 'spotty' } = {
+      natural: 'gradient', artificial: 'even', dramatic: 'uneven',
+      soft: 'even', bright: 'even', dim: 'uneven',
+      warm: 'gradient', cool: 'even', mixed: 'spotty'
+    };
+    return distributions[lightingType] || 'even';
+  }
+
+  private getDynamicRange(lightingType: string): number {
+    const ranges: { [key: string]: number } = {
+      natural: 85, artificial: 70, dramatic: 90, soft: 60,
+      bright: 75, dim: 80, warm: 70, cool: 75, mixed: 85
+    };
+    return (ranges[lightingType] || 75) + Math.random() * 10;
+  }
+
+  private getExposureLevel(lightingType: string, isBright: boolean, isDim: boolean): 'underexposed' | 'well-exposed' | 'overexposed' | 'mixed' {
+    if (isBright) return 'overexposed';
+    if (isDim) return 'underexposed';
+    
+    const exposures: { [key: string]: 'underexposed' | 'well-exposed' | 'overexposed' | 'mixed' } = {
+      natural: 'well-exposed', artificial: 'well-exposed', dramatic: 'mixed',
+      soft: 'well-exposed', warm: 'well-exposed', cool: 'well-exposed', mixed: 'mixed'
+    };
+    return exposures[lightingType] || 'well-exposed';
+  }
+
+  private getContrastLevel(lightingType: string): number {
+    const contrasts: { [key: string]: number } = {
+      natural: 70, artificial: 60, dramatic: 90, soft: 40,
+      bright: 65, dim: 75, warm: 55, cool: 65, mixed: 80
+    };
+    return (contrasts[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getContrastType(lightingType: string): 'low' | 'medium' | 'high' | 'extreme' {
+    const types: { [key: string]: 'low' | 'medium' | 'high' | 'extreme' } = {
+      natural: 'medium', artificial: 'medium', dramatic: 'extreme',
+      soft: 'low', bright: 'medium', dim: 'high',
+      warm: 'low', cool: 'medium', mixed: 'high'
+    };
+    return types[lightingType] || 'medium';
+  }
+
+  private getHighlights(lightingType: string): number {
+    const highlights: { [key: string]: number } = {
+      natural: 80, artificial: 70, dramatic: 85, soft: 60,
+      bright: 90, dim: 40, warm: 65, cool: 75, mixed: 75
+    };
+    return (highlights[lightingType] || 70) + Math.random() * 15;
+  }
+
+  private getMidtones(lightingType: string): number {
+    const midtones: { [key: string]: number } = {
+      natural: 60, artificial: 65, dramatic: 50, soft: 70,
+      bright: 55, dim: 45, warm: 65, cool: 60, mixed: 60
+    };
+    return (midtones[lightingType] || 60) + Math.random() * 15;
+  }
+
+  private getShadowsLevel(lightingType: string): number {
+    const shadows: { [key: string]: number } = {
+      natural: 40, artificial: 45, dramatic: 20, soft: 55,
+      bright: 35, dim: 65, warm: 50, cool: 40, mixed: 45
+    };
+    return (shadows[lightingType] || 45) + Math.random() * 15;
+  }
+
+  private getColorTemperature(lightingType: string, isWarm: boolean, isCool: boolean): number {
+    if (isWarm) return 2700 + Math.random() * 500;
+    if (isCool) return 5500 + Math.random() * 1000;
+    
+    const temperatures: { [key: string]: number } = {
+      natural: 5500, artificial: 4000, dramatic: 3200,
+      soft: 4500, bright: 5000, dim: 3000, mixed: 4200
+    };
+    return temperatures[lightingType] || 4000;
+  }
+
+  private getWarmthLevel(lightingType: string, isWarm: boolean, isCool: boolean): 'very-warm' | 'warm' | 'neutral' | 'cool' | 'very-cool' {
+    if (isWarm) return 'warm';
+    if (isCool) return 'cool';
+    
+    const warmths: { [key: string]: 'very-warm' | 'warm' | 'neutral' | 'cool' | 'very-cool' } = {
+      natural: 'neutral', artificial: 'neutral', dramatic: 'warm',
+      soft: 'warm', bright: 'cool', dim: 'warm', mixed: 'neutral'
+    };
+    return warmths[lightingType] || 'neutral';
+  }
+
+  private getTemperatureConsistency(lightingType: string): number {
+    const consistencies: { [key: string]: number } = {
+      natural: 90, artificial: 85, dramatic: 70, soft: 80,
+      bright: 85, dim: 75, warm: 90, cool: 85, mixed: 60
+    };
+    return (consistencies[lightingType] || 80) + Math.random() * 10;
+  }
+
+  private getLightSoftness(lightingType: string): number {
+    const softnesses: { [key: string]: number } = {
+      natural: 70, artificial: 60, dramatic: 30, soft: 90,
+      bright: 50, dim: 80, warm: 75, cool: 55, mixed: 65
+    };
+    return (softnesses[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getLightDiffusion(lightingType: string): number {
+    const diffusions: { [key: string]: number } = {
+      natural: 75, artificial: 65, dramatic: 40, soft: 85,
+      bright: 60, dim: 70, warm: 70, cool: 60, mixed: 70
+    };
+    return (diffusions[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getLightDirectionality(lightingType: string): number {
+    const directionalities: { [key: string]: number } = {
+      natural: 80, artificial: 70, dramatic: 90, soft: 40,
+      bright: 75, dim: 50, warm: 60, cool: 70, mixed: 60
+    };
+    return (directionalities[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getLightEvenness(lightingType: string): number {
+    const evennesses: { [key: string]: number } = {
+      natural: 60, artificial: 75, dramatic: 30, soft: 85,
+      bright: 80, dim: 50, warm: 70, cool: 75, mixed: 55
+    };
+    return (evennesses[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getShadowCoverage(lightingType: string, isDramatic: boolean): number {
+    if (isDramatic) return 60 + Math.random() * 30;
+    
+    const coverages: { [key: string]: number } = {
+      natural: 50, artificial: 40, soft: 25, bright: 30,
+      dim: 70, warm: 45, cool: 35, mixed: 50
+    };
+    return (coverages[lightingType] || 45) + Math.random() * 20;
+  }
+
+  private getShadowIntensity(lightingType: string, isDramatic: boolean): number {
+    if (isDramatic) return 75 + Math.random() * 20;
+    
+    const intensities: { [key: string]: number } = {
+      natural: 60, artificial: 50, soft: 30, bright: 45,
+      dim: 65, warm: 40, cool: 55, mixed: 55
+    };
+    return (intensities[lightingType] || 50) + Math.random() * 20;
+  }
+
+  private getShadowSharpness(lightingType: string, isSoft: boolean): 'very-soft' | 'soft' | 'medium' | 'sharp' | 'very-sharp' {
+    if (isSoft) return 'soft';
+    
+    const sharpnesses: { [key: string]: 'very-soft' | 'soft' | 'medium' | 'sharp' | 'very-sharp' } = {
+      natural: 'medium', artificial: 'medium', dramatic: 'sharp',
+      bright: 'sharp', dim: 'soft', warm: 'soft', cool: 'medium', mixed: 'medium'
+    };
+    return sharpnesses[lightingType] || 'medium';
+  }
+
+  private getShadowDefinition(lightingType: string): number {
+    const definitions: { [key: string]: number } = {
+      natural: 70, artificial: 65, dramatic: 85, soft: 40,
+      bright: 75, dim: 55, warm: 50, cool: 70, mixed: 60
+    };
+    return (definitions[lightingType] || 60) + Math.random() * 15;
+  }
+
+  private getShadowDirection(lightingType: string): string {
+    const directions = ['左下', '右下', '正下', '左侧', '右侧', '多方向'];
+    return directions[Math.floor(Math.random() * directions.length)];
+  }
+
+  private getShadowLength(lightingType: string): 'short' | 'medium' | 'long' | 'varied' {
+    const lengths: { [key: string]: 'short' | 'medium' | 'long' | 'varied' } = {
+      natural: 'medium', artificial: 'short', dramatic: 'long',
+      soft: 'short', bright: 'short', dim: 'medium',
+      warm: 'medium', cool: 'short', mixed: 'varied'
+    };
+    return lengths[lightingType] || 'medium';
+  }
+
+  private getShadowDensity(lightingType: string): number {
+    const densities: { [key: string]: number } = {
+      natural: 60, artificial: 55, dramatic: 80, soft: 35,
+      bright: 45, dim: 70, warm: 50, cool: 60, mixed: 60
+    };
+    return (densities[lightingType] || 55) + Math.random() * 20;
+  }
+
+  private getShadowFalloff(lightingType: string, isSoft: boolean): 'gradual' | 'medium' | 'abrupt' {
+    if (isSoft) return 'gradual';
+    
+    const falloffs: { [key: string]: 'gradual' | 'medium' | 'abrupt' } = {
+      natural: 'gradual', artificial: 'medium', dramatic: 'abrupt',
+      bright: 'medium', dim: 'gradual', warm: 'gradual',
+      cool: 'medium', mixed: 'medium'
+    };
+    return falloffs[lightingType] || 'medium';
+  }
+
+  private getShadowTypes(lightingType: string): Array<{type: 'cast' | 'form' | 'occlusion' | 'contact', prominence: number, contribution: string}> {
+    const types: Array<{type: 'cast' | 'form' | 'occlusion' | 'contact', prominence: number, contribution: string}> = [
+      { type: 'cast', prominence: 70 + Math.random() * 25, contribution: '主要阴影效果' },
+      { type: 'form', prominence: 50 + Math.random() * 30, contribution: '形体塑造' }
+    ];
+    
+    if (lightingType === 'dramatic') {
+      types.push({ type: 'occlusion', prominence: 60 + Math.random() * 30, contribution: '遮挡阴影' });
+    }
+    
+    types.push({ type: 'contact', prominence: 40 + Math.random() * 20, contribution: '接触阴影' });
+    
+    return types;
+  }
+
+  private getDepthEffect(lightingType: string, isDramatic: boolean): number {
+    if (isDramatic) return 80 + Math.random() * 15;
+    
+    const depths: { [key: string]: number } = {
+      natural: 70, artificial: 60, soft: 45, bright: 55,
+      dim: 75, warm: 60, cool: 65, mixed: 65
+    };
+    return (depths[lightingType] || 60) + Math.random() * 20;
+  }
+
+  private getVolumeEffect(lightingType: string): number {
+    const volumes: { [key: string]: number } = {
+      natural: 65, artificial: 55, dramatic: 85, soft: 40,
+      bright: 50, dim: 70, warm: 55, cool: 60, mixed: 60
+    };
+    return (volumes[lightingType] || 60) + Math.random() * 20;
+  }
+
+  private get3DEffect(lightingType: string, isDramatic: boolean): number {
+    if (isDramatic) return 85 + Math.random() * 10;
+    
+    const effects: { [key: string]: number } = {
+      natural: 75, artificial: 65, soft: 45, bright: 60,
+      dim: 70, warm: 60, cool: 70, mixed: 70
+    };
+    return (effects[lightingType] || 65) + Math.random() * 20;
+  }
+
+  private getAmbientStrength(lightingType: string): number {
+    const strengths: { [key: string]: number } = {
+      natural: 70, artificial: 60, dramatic: 40, soft: 80,
+      bright: 65, dim: 85, warm: 75, cool: 55, mixed: 65
+    };
+    return (strengths[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getAmbientUniformity(lightingType: string): number {
+    const uniformities: { [key: string]: number } = {
+      natural: 60, artificial: 75, dramatic: 30, soft: 85,
+      bright: 70, dim: 50, warm: 70, cool: 75, mixed: 55
+    };
+    return (uniformities[lightingType] || 65) + Math.random() * 15;
+  }
+
+  private getAmbientContribution(lightingType: string): number {
+    const contributions: { [key: string]: number } = {
+      natural: 40, artificial: 50, dramatic: 25, soft: 70,
+      bright: 35, dim: 80, warm: 60, cool: 45, mixed: 55
+    };
+    return (contributions[lightingType] || 50) + Math.random() * 20;
+  }
+
+  private getLightingMood(lightingType: string, context: string): 'dramatic' | 'romantic' | 'energetic' | 'calm' | 'mysterious' | 'cheerful' | 'professional' {
+    if (context.includes('romantic')) return 'romantic';
+    if (context.includes('energetic')) return 'energetic';
+    if (context.includes('calm')) return 'calm';
+    if (context.includes('mysterious')) return 'mysterious';
+    if (context.includes('cheerful')) return 'cheerful';
+    if (context.includes('professional')) return 'professional';
+    
+    const moods: { [key: string]: 'dramatic' | 'romantic' | 'energetic' | 'calm' | 'mysterious' | 'cheerful' | 'professional' } = {
+      natural: 'cheerful', artificial: 'professional', dramatic: 'dramatic',
+      soft: 'romantic', bright: 'energetic', dim: 'mysterious',
+      warm: 'calm', cool: 'professional', mixed: 'energetic'
+    };
+    return moods[lightingType] || 'calm';
+  }
+
+  private getMoodIntensity(lightingType: string): number {
+    const intensities: { [key: string]: number } = {
+      natural: 70, artificial: 60, dramatic: 90, soft: 75,
+      bright: 80, dim: 85, warm: 70, cool: 65, mixed: 75
+    };
+    return (intensities[lightingType] || 70) + Math.random() * 15;
+  }
+
+  private getEmotionalImpact(lightingType: string, context: string): string[] {
+    const impacts: { [key: string]: string[] } = {
+      natural: ['自然', '舒适', '健康'],
+      artificial: ['现代', '功能性', '可控'],
+      dramatic: ['戏剧性', '强烈', '艺术感'],
+      soft: ['温柔', '浪漫', '舒缓'],
+      bright: ['活力', '清晰', '积极'],
+      dim: ['神秘', '私密', '放松'],
+      warm: ['温暖', '舒适', '亲密'],
+      cool: ['清爽', '专业', '现代'],
+      mixed: ['丰富', '层次', '复杂']
+    };
+    return impacts[lightingType] || ['平衡', '和谐'];
+  }
+
+  private getHazeLevel(lightingType: string, context: string): number {
+    const base = context.includes('haze') || context.includes('fog') ? 60 : 20;
+    return base + Math.random() * 30;
+  }
+
+  private getGlareLevel(lightingType: string): number {
+    const glares: { [key: string]: number } = {
+      natural: 30, artificial: 25, dramatic: 40, soft: 10,
+      bright: 60, dim: 5, warm: 15, cool: 35, mixed: 30
+    };
+    return (glares[lightingType] || 25) + Math.random() * 20;
+  }
+
+  private getReflectionLevel(lightingType: string, context: string): number {
+    const base = context.includes('reflection') || context.includes('mirror') ? 70 : 30;
+    return base + Math.random() * 25;
+  }
+
+  private getTransparencyLevel(lightingType: string): number {
+    const transparencies: { [key: string]: number } = {
+      natural: 85, artificial: 75, dramatic: 60, soft: 80,
+      bright: 90, dim: 50, warm: 70, cool: 80, mixed: 70
+    };
+    return (transparencies[lightingType] || 75) + Math.random() * 15;
+  }
+
+  private getDepthEnhancement(lightingType: string): number {
+    const enhancements: { [key: string]: number } = {
+      natural: 75, artificial: 65, dramatic: 90, soft: 50,
+      bright: 60, dim: 80, warm: 60, cool: 70, mixed: 75
+    };
+    return (enhancements[lightingType] || 70) + Math.random() * 15;
+  }
+
+  private getSpaceDefinition(lightingType: string): number {
+    const definitions: { [key: string]: number } = {
+      natural: 70, artificial: 80, dramatic: 85, soft: 60,
+      bright: 75, dim: 55, warm: 65, cool: 75, mixed: 70
+    };
+    return (definitions[lightingType] || 70) + Math.random() * 15;
+  }
+
+  private getFocalGuidance(lightingType: string): number {
+    const guidances: { [key: string]: number } = {
+      natural: 60, artificial: 70, dramatic: 90, soft: 50,
+      bright: 65, dim: 75, warm: 55, cool: 70, mixed: 75
+    };
+    return (guidances[lightingType] || 65) + Math.random() * 15;
+  }
+}

+ 553 - 0
src/app/shared/services/pattern-analysis.service.ts

@@ -0,0 +1,553 @@
+import { Injectable } from '@angular/core';
+import { Observable, of } from 'rxjs';
+
+// 纹理分析结果接口
+export interface PatternAnalysisResult {
+  patternRecognition: PatternRecognition;
+  repetitionAnalysis: RepetitionAnalysis;
+  textureClassification: TextureClassification;
+  visualRhythm: VisualRhythm;
+  designRecommendations: string[];
+}
+
+// 图案识别
+export interface PatternRecognition {
+  primaryPatterns: Array<{
+    type: 'geometric' | 'organic' | 'abstract' | 'floral' | 'striped' | 'checkered' | 'dotted' | 'textured';
+    confidence: number; // 0-100
+    coverage: number; // 0-100
+    characteristics: string[];
+  }>;
+  patternComplexity: {
+    level: 'simple' | 'moderate' | 'complex' | 'very-complex';
+    score: number; // 0-100
+    elements: number; // 图案元素数量
+  };
+  patternScale: {
+    size: 'micro' | 'small' | 'medium' | 'large' | 'macro';
+    uniformity: number; // 0-100
+    variation: number; // 0-100
+  };
+}
+
+// 重复性分析
+export interface RepetitionAnalysis {
+  repetitionType: {
+    primary: 'regular' | 'irregular' | 'random' | 'semi-regular';
+    pattern: 'grid' | 'brick' | 'hexagonal' | 'radial' | 'linear' | 'organic';
+    consistency: number; // 0-100
+  };
+  spacing: {
+    horizontal: number; // 像素或相对单位
+    vertical: number;
+    uniformity: number; // 0-100
+    rhythm: 'tight' | 'moderate' | 'loose' | 'varied';
+  };
+  symmetry: {
+    type: 'bilateral' | 'radial' | 'translational' | 'rotational' | 'none';
+    strength: number; // 0-100
+    axes: number; // 对称轴数量
+  };
+  tiling: {
+    seamless: boolean;
+    quality: number; // 0-100
+    edgeHandling: 'perfect' | 'good' | 'fair' | 'poor';
+  };
+}
+
+// 纹理分类
+export interface TextureClassification {
+  textureFamily: {
+    primary: 'natural' | 'artificial' | 'hybrid';
+    subcategory: string;
+    confidence: number; // 0-100
+  };
+  surfaceCharacter: {
+    tactileQuality: 'smooth' | 'rough' | 'bumpy' | 'ridged' | 'woven' | 'carved';
+    visualDepth: number; // 0-100
+    dimensionality: '2D' | '2.5D' | '3D';
+  };
+  materialSuggestion: {
+    likelyMaterials: string[];
+    fabricationMethod: string[];
+    applicationSuitability: string[];
+  };
+}
+
+// 视觉节奏
+export interface VisualRhythm {
+  rhythmType: {
+    primary: 'regular' | 'alternating' | 'flowing' | 'progressive' | 'random';
+    intensity: number; // 0-100
+    tempo: 'slow' | 'moderate' | 'fast' | 'varied';
+  };
+  movement: {
+    direction: 'horizontal' | 'vertical' | 'diagonal' | 'radial' | 'multi-directional';
+    flow: number; // 0-100
+    energy: number; // 0-100
+  };
+  emphasis: {
+    focalPoints: number;
+    contrast: number; // 0-100
+    hierarchy: number; // 0-100
+  };
+  harmony: {
+    overall: number; // 0-100
+    balance: number; // 0-100
+    unity: number; // 0-100
+  };
+}
+
+@Injectable({
+  providedIn: 'root'
+})
+export class PatternAnalysisService {
+
+  constructor() { }
+
+  /**
+   * 分析图片中的纹理图案
+   * @param imageFile 图片文件
+   */
+  analyzeImagePattern(imageFile: File): Observable<PatternAnalysisResult> {
+    return of(this.simulatePatternAnalysis(imageFile));
+  }
+
+  /**
+   * 分析URL图片的纹理图案
+   * @param imageUrl 图片URL
+   */
+  analyzePatternFromUrl(imageUrl: string): Observable<PatternAnalysisResult> {
+    return of(this.simulatePatternAnalysisFromUrl(imageUrl));
+  }
+
+  /**
+   * 模拟纹理图案分析
+   */
+  private simulatePatternAnalysis(imageFile: File): PatternAnalysisResult {
+    const fileName = imageFile.name.toLowerCase();
+    return this.generatePatternAnalysis(fileName);
+  }
+
+  private simulatePatternAnalysisFromUrl(imageUrl: string): PatternAnalysisResult {
+    const urlLower = imageUrl.toLowerCase();
+    return this.generatePatternAnalysis(urlLower);
+  }
+
+  private generatePatternAnalysis(context: string): PatternAnalysisResult {
+    const patternType = this.inferPatternType(context);
+    
+    return {
+      patternRecognition: this.generatePatternRecognition(patternType, context),
+      repetitionAnalysis: this.generateRepetitionAnalysis(patternType, context),
+      textureClassification: this.generateTextureClassification(patternType, context),
+      visualRhythm: this.generateVisualRhythm(patternType, context),
+      designRecommendations: this.generateDesignRecommendations(patternType, context)
+    };
+  }
+
+  private inferPatternType(context: string): string {
+    if (context.includes('geometric') || context.includes('grid')) return 'geometric';
+    if (context.includes('floral') || context.includes('flower')) return 'floral';
+    if (context.includes('stripe') || context.includes('line')) return 'striped';
+    if (context.includes('dot') || context.includes('circle')) return 'dotted';
+    if (context.includes('check') || context.includes('square')) return 'checkered';
+    if (context.includes('organic') || context.includes('natural')) return 'organic';
+    if (context.includes('abstract')) return 'abstract';
+    return 'textured'; // 默认纹理类型
+  }
+
+  private generatePatternRecognition(patternType: string, context: string): PatternRecognition {
+    const isComplex = context.includes('complex') || context.includes('detailed');
+    const isLarge = context.includes('large') || context.includes('big');
+    
+    const basePattern = this.getBasePatternData(patternType);
+    
+    return {
+      primaryPatterns: [
+        {
+          type: patternType as any,
+          confidence: 85 + Math.random() * 10,
+          coverage: 70 + Math.random() * 25,
+          characteristics: basePattern.characteristics
+        }
+      ],
+      patternComplexity: {
+        level: isComplex ? 'complex' : basePattern.complexity.level,
+        score: isComplex ? 80 + Math.random() * 15 : basePattern.complexity.score,
+        elements: isComplex ? 15 + Math.floor(Math.random() * 10) : basePattern.complexity.elements
+      },
+      patternScale: {
+        size: isLarge ? 'large' : basePattern.scale.size,
+        uniformity: basePattern.scale.uniformity,
+        variation: basePattern.scale.variation
+      }
+    };
+  }
+
+  private getBasePatternData(patternType: string): any {
+    const patterns: { [key: string]: any } = {
+      geometric: {
+        characteristics: ['规则', '对称', '数学性', '现代'],
+        complexity: { level: 'moderate', score: 60, elements: 8 },
+        scale: { size: 'medium', uniformity: 85, variation: 20 }
+      },
+      floral: {
+        characteristics: ['自然', '有机', '装饰性', '传统'],
+        complexity: { level: 'complex', score: 75, elements: 12 },
+        scale: { size: 'medium', uniformity: 60, variation: 40 }
+      },
+      striped: {
+        characteristics: ['线性', '方向性', '简洁', '经典'],
+        complexity: { level: 'simple', score: 30, elements: 3 },
+        scale: { size: 'medium', uniformity: 90, variation: 15 }
+      },
+      dotted: {
+        characteristics: ['点状', '规律', '轻盈', '现代'],
+        complexity: { level: 'simple', score: 35, elements: 4 },
+        scale: { size: 'small', uniformity: 80, variation: 25 }
+      },
+      checkered: {
+        characteristics: ['格子', '对比', '经典', '结构化'],
+        complexity: { level: 'simple', score: 40, elements: 2 },
+        scale: { size: 'medium', uniformity: 95, variation: 10 }
+      },
+      organic: {
+        characteristics: ['自然', '流动', '不规则', '和谐'],
+        complexity: { level: 'moderate', score: 65, elements: 10 },
+        scale: { size: 'varied', uniformity: 45, variation: 60 }
+      },
+      abstract: {
+        characteristics: ['抽象', '艺术性', '创新', '表现力'],
+        complexity: { level: 'complex', score: 80, elements: 15 },
+        scale: { size: 'varied', uniformity: 40, variation: 70 }
+      },
+      textured: {
+        characteristics: ['质感', '触觉', '深度', '材质感'],
+        complexity: { level: 'moderate', score: 55, elements: 6 },
+        scale: { size: 'small', uniformity: 70, variation: 35 }
+      }
+    };
+
+    return patterns[patternType] || patterns['textured'];
+  }
+
+  private generateRepetitionAnalysis(patternType: string, context: string): RepetitionAnalysis {
+    const isRegular = patternType === 'geometric' || patternType === 'striped' || patternType === 'checkered';
+    const isSeamless = context.includes('seamless') || context.includes('tile');
+    
+    return {
+      repetitionType: {
+        primary: isRegular ? 'regular' : 'semi-regular',
+        pattern: this.getRepetitionPattern(patternType),
+        consistency: isRegular ? 85 + Math.random() * 10 : 60 + Math.random() * 25
+      },
+      spacing: {
+        horizontal: 50 + Math.random() * 100,
+        vertical: 50 + Math.random() * 100,
+        uniformity: isRegular ? 85 + Math.random() * 10 : 55 + Math.random() * 30,
+        rhythm: this.getSpacingRhythm(patternType)
+      },
+      symmetry: {
+        type: this.getSymmetryType(patternType),
+        strength: this.getSymmetryStrength(patternType),
+        axes: this.getSymmetryAxes(patternType)
+      },
+      tiling: {
+        seamless: isSeamless,
+        quality: isSeamless ? 90 + Math.random() * 8 : 60 + Math.random() * 30,
+        edgeHandling: isSeamless ? 'perfect' : 'good'
+      }
+    };
+  }
+
+  private generateTextureClassification(patternType: string, context: string): TextureClassification {
+    const isNatural = patternType === 'organic' || patternType === 'floral' || context.includes('natural');
+    
+    return {
+      textureFamily: {
+        primary: isNatural ? 'natural' : 'artificial',
+        subcategory: this.getTextureSubcategory(patternType),
+        confidence: 80 + Math.random() * 15
+      },
+      surfaceCharacter: {
+        tactileQuality: this.getTactileQuality(patternType),
+        visualDepth: this.getVisualDepth(patternType),
+        dimensionality: this.getDimensionality(patternType)
+      },
+      materialSuggestion: {
+        likelyMaterials: this.getLikelyMaterials(patternType),
+        fabricationMethod: this.getFabricationMethods(patternType),
+        applicationSuitability: this.getApplicationSuitability(patternType)
+      }
+    };
+  }
+
+  private generateVisualRhythm(patternType: string, context: string): VisualRhythm {
+    const isDynamic = context.includes('dynamic') || context.includes('movement');
+    
+    return {
+      rhythmType: {
+        primary: this.getRhythmType(patternType),
+        intensity: this.getRhythmIntensity(patternType, isDynamic),
+        tempo: this.getRhythmTempo(patternType)
+      },
+      movement: {
+        direction: this.getMovementDirection(patternType),
+        flow: this.getFlowValue(patternType),
+        energy: isDynamic ? 80 + Math.random() * 15 : 50 + Math.random() * 30
+      },
+      emphasis: {
+        focalPoints: this.getFocalPoints(patternType),
+        contrast: this.getContrastValue(patternType),
+        hierarchy: this.getHierarchyValue(patternType)
+      },
+      harmony: {
+        overall: 70 + Math.random() * 25,
+        balance: this.getBalanceValue(patternType),
+        unity: this.getUnityValue(patternType)
+      }
+    };
+  }
+
+  private generateDesignRecommendations(patternType: string, context: string): string[] {
+    const recommendations = [];
+    
+    // 基于图案类型的建议
+    switch (patternType) {
+      case 'geometric':
+        recommendations.push('保持几何图案的精确性和一致性');
+        recommendations.push('考虑使用对比色增强视觉效果');
+        break;
+      case 'floral':
+        recommendations.push('平衡花卉图案的复杂度和可读性');
+        recommendations.push('注意色彩搭配的自然和谐');
+        break;
+      case 'striped':
+        recommendations.push('控制条纹的宽度比例');
+        recommendations.push('注意条纹方向对空间感的影响');
+        break;
+      case 'organic':
+        recommendations.push('保持有机图案的自然流动感');
+        recommendations.push('避免过度规则化');
+        break;
+    }
+    
+    // 基于上下文的建议
+    if (context.includes('interior')) {
+      recommendations.push('考虑图案对室内空间感的影响');
+    }
+    if (context.includes('fabric')) {
+      recommendations.push('注意图案的可缝制性和耐用性');
+    }
+    if (context.includes('wallpaper')) {
+      recommendations.push('确保图案的无缝拼接效果');
+    }
+    
+    return recommendations.length > 0 ? recommendations : ['保持图案设计的整体协调性'];
+  }
+
+  // 辅助方法
+  private getRepetitionPattern(patternType: string): 'grid' | 'brick' | 'hexagonal' | 'radial' | 'linear' | 'organic' {
+    const patterns: { [key: string]: 'grid' | 'brick' | 'hexagonal' | 'radial' | 'linear' | 'organic' } = {
+      geometric: 'grid', striped: 'linear', checkered: 'grid', 
+      dotted: 'grid', floral: 'organic', organic: 'organic', 
+      abstract: 'radial', textured: 'brick'
+    };
+    return patterns[patternType] || 'grid';
+  }
+
+  private getSpacingRhythm(patternType: string): 'tight' | 'moderate' | 'loose' | 'varied' {
+    const rhythms: { [key: string]: 'tight' | 'moderate' | 'loose' | 'varied' } = {
+      geometric: 'moderate', striped: 'tight', checkered: 'moderate',
+      dotted: 'moderate', floral: 'varied', organic: 'varied',
+      abstract: 'varied', textured: 'tight'
+    };
+    return rhythms[patternType] || 'moderate';
+  }
+
+  private getSymmetryType(patternType: string): 'bilateral' | 'radial' | 'translational' | 'rotational' | 'none' {
+    const types: { [key: string]: 'bilateral' | 'radial' | 'translational' | 'rotational' | 'none' } = {
+      geometric: 'bilateral', striped: 'translational', checkered: 'bilateral',
+      dotted: 'translational', floral: 'radial', organic: 'none',
+      abstract: 'rotational', textured: 'translational'
+    };
+    return types[patternType] || 'bilateral';
+  }
+
+  private getSymmetryStrength(patternType: string): number {
+    const strengths: { [key: string]: number } = {
+      geometric: 90, striped: 85, checkered: 95, dotted: 80,
+      floral: 60, organic: 30, abstract: 50, textured: 70
+    };
+    return (strengths[patternType] || 70) + Math.random() * 10;
+  }
+
+  private getSymmetryAxes(patternType: string): number {
+    const axes: { [key: string]: number } = {
+      geometric: 2, striped: 1, checkered: 2, dotted: 4,
+      floral: 4, organic: 0, abstract: 3, textured: 1
+    };
+    return axes[patternType] || 2;
+  }
+
+  private getTextureSubcategory(patternType: string): string {
+    const subcategories: { [key: string]: string } = {
+      geometric: '几何纹理', floral: '植物纹理', striped: '线性纹理',
+      dotted: '点状纹理', checkered: '格子纹理', organic: '有机纹理',
+      abstract: '抽象纹理', textured: '表面纹理'
+    };
+    return subcategories[patternType] || '混合纹理';
+  }
+
+  private getTactileQuality(patternType: string): 'smooth' | 'rough' | 'bumpy' | 'ridged' | 'woven' | 'carved' {
+    const qualities: { [key: string]: 'smooth' | 'rough' | 'bumpy' | 'ridged' | 'woven' | 'carved' } = {
+      geometric: 'smooth', floral: 'carved', striped: 'ridged',
+      dotted: 'bumpy', checkered: 'woven', organic: 'rough',
+      abstract: 'rough', textured: 'rough'
+    };
+    return qualities[patternType] || 'smooth';
+  }
+
+  private getVisualDepth(patternType: string): number {
+    const depths: { [key: string]: number } = {
+      geometric: 40, floral: 70, striped: 30, dotted: 50,
+      checkered: 35, organic: 80, abstract: 85, textured: 90
+    };
+    return depths[patternType] || 50;
+  }
+
+  private getDimensionality(patternType: string): '2D' | '2.5D' | '3D' {
+    const dims: { [key: string]: '2D' | '2.5D' | '3D' } = {
+      geometric: '2D', floral: '2.5D', striped: '2D', dotted: '2D',
+      checkered: '2D', organic: '3D', abstract: '2.5D', textured: '3D'
+    };
+    return dims[patternType] || '2D';
+  }
+
+  private getLikelyMaterials(patternType: string): string[] {
+    const materials: { [key: string]: string[] } = {
+      geometric: ['金属', '塑料', '陶瓷'],
+      floral: ['织物', '壁纸', '陶瓷'],
+      striped: ['织物', '木材', '金属'],
+      dotted: ['织物', '塑料', '纸张'],
+      checkered: ['织物', '瓷砖', '纸张'],
+      organic: ['木材', '石材', '皮革'],
+      abstract: ['画布', '金属', '玻璃'],
+      textured: ['石材', '混凝土', '皮革']
+    };
+    return materials[patternType] || ['通用材料'];
+  }
+
+  private getFabricationMethods(patternType: string): string[] {
+    const methods: { [key: string]: string[] } = {
+      geometric: ['激光切割', '数控加工', '模具成型'],
+      floral: ['印刷', '刺绣', '雕刻'],
+      striped: ['编织', '印刷', '切割'],
+      dotted: ['打孔', '印刷', '压花'],
+      checkered: ['编织', '印刷', '拼接'],
+      organic: ['手工雕刻', '铸造', '3D打印'],
+      abstract: ['手绘', '喷涂', '数字印刷'],
+      textured: ['压花', '喷砂', '化学蚀刻']
+    };
+    return methods[patternType] || ['常规加工'];
+  }
+
+  private getApplicationSuitability(patternType: string): string[] {
+    const applications: { [key: string]: string[] } = {
+      geometric: ['现代室内', '办公空间', '科技产品'],
+      floral: ['家居装饰', '服装设计', '传统空间'],
+      striped: ['服装', '室内装饰', '包装设计'],
+      dotted: ['儿童用品', '休闲服装', '装饰品'],
+      checkered: ['经典服装', '餐厅装饰', '游戏用品'],
+      organic: ['自然风格室内', '艺术品', '高端产品'],
+      abstract: ['艺术空间', '创意产品', '展示设计'],
+      textured: ['建筑外观', '工业设计', '触觉产品']
+    };
+    return applications[patternType] || ['通用应用'];
+  }
+
+  private getRhythmType(patternType: string): 'regular' | 'alternating' | 'flowing' | 'progressive' | 'random' {
+    const types: { [key: string]: 'regular' | 'alternating' | 'flowing' | 'progressive' | 'random' } = {
+      geometric: 'regular', floral: 'flowing', striped: 'alternating',
+      dotted: 'regular', checkered: 'alternating', organic: 'flowing',
+      abstract: 'progressive', textured: 'random'
+    };
+    return types[patternType] || 'regular';
+  }
+
+  private getRhythmIntensity(patternType: string, isDynamic: boolean): number {
+    const base: { [key: string]: number } = {
+      geometric: 60, floral: 70, striped: 80, dotted: 50,
+      checkered: 75, organic: 65, abstract: 85, textured: 55
+    };
+    const intensity = base[patternType] || 60;
+    return isDynamic ? Math.min(95, intensity + 20) : intensity;
+  }
+
+  private getRhythmTempo(patternType: string): 'slow' | 'moderate' | 'fast' | 'varied' {
+    const tempos: { [key: string]: 'slow' | 'moderate' | 'fast' | 'varied' } = {
+      geometric: 'moderate', floral: 'slow', striped: 'fast',
+      dotted: 'moderate', checkered: 'fast', organic: 'varied',
+      abstract: 'varied', textured: 'slow'
+    };
+    return tempos[patternType] || 'moderate';
+  }
+
+  private getMovementDirection(patternType: string): 'horizontal' | 'vertical' | 'diagonal' | 'radial' | 'multi-directional' {
+    const directions: { [key: string]: 'horizontal' | 'vertical' | 'diagonal' | 'radial' | 'multi-directional' } = {
+      geometric: 'multi-directional', floral: 'radial', striped: 'horizontal',
+      dotted: 'multi-directional', checkered: 'multi-directional', organic: 'radial',
+      abstract: 'multi-directional', textured: 'multi-directional'
+    };
+    return directions[patternType] || 'multi-directional';
+  }
+
+  private getFlowValue(patternType: string): number {
+    const flows: { [key: string]: number } = {
+      geometric: 50, floral: 80, striped: 70, dotted: 40,
+      checkered: 45, organic: 90, abstract: 75, textured: 60
+    };
+    return (flows[patternType] || 60) + Math.random() * 15;
+  }
+
+  private getFocalPoints(patternType: string): number {
+    const points: { [key: string]: number } = {
+      geometric: 4, floral: 6, striped: 2, dotted: 8,
+      checkered: 4, organic: 3, abstract: 5, textured: 2
+    };
+    return points[patternType] || 4;
+  }
+
+  private getContrastValue(patternType: string): number {
+    const contrasts: { [key: string]: number } = {
+      geometric: 80, floral: 60, striped: 90, dotted: 70,
+      checkered: 95, organic: 50, abstract: 85, textured: 65
+    };
+    return (contrasts[patternType] || 70) + Math.random() * 15;
+  }
+
+  private getHierarchyValue(patternType: string): number {
+    const hierarchies: { [key: string]: number } = {
+      geometric: 85, floral: 70, striped: 60, dotted: 55,
+      checkered: 75, organic: 65, abstract: 80, textured: 50
+    };
+    return (hierarchies[patternType] || 65) + Math.random() * 15;
+  }
+
+  private getBalanceValue(patternType: string): number {
+    const balances: { [key: string]: number } = {
+      geometric: 90, floral: 75, striped: 85, dotted: 80,
+      checkered: 95, organic: 60, abstract: 70, textured: 65
+    };
+    return (balances[patternType] || 75) + Math.random() * 15;
+  }
+
+  private getUnityValue(patternType: string): number {
+    const unities: { [key: string]: number } = {
+      geometric: 85, floral: 80, striped: 90, dotted: 75,
+      checkered: 90, organic: 70, abstract: 65, textured: 70
+    };
+    return (unities[patternType] || 75) + Math.random() * 15;
+  }
+}

+ 458 - 0
src/app/shared/services/texture-analysis.service.ts

@@ -0,0 +1,458 @@
+import { Injectable } from '@angular/core';
+import { Observable, of } from 'rxjs';
+
+// 质感分析结果接口
+export interface TextureAnalysisResult {
+  surfaceProperties: SurfaceProperties;
+  tactilePredict: TactilePredict;
+  materialClassification: MaterialClassification;
+  textureQuality: TextureQuality;
+  recommendations: string[];
+}
+
+// 表面属性
+export interface SurfaceProperties {
+  roughness: {
+    level: 'very-smooth' | 'smooth' | 'moderate' | 'rough' | 'very-rough';
+    value: number; // 0-100
+    description: string;
+  };
+  glossiness: {
+    level: 'matte' | 'satin' | 'semi-gloss' | 'gloss' | 'high-gloss';
+    value: number; // 0-100
+    reflectivity: number; // 0-100
+  };
+  transparency: {
+    level: 'opaque' | 'translucent' | 'semi-transparent' | 'transparent';
+    value: number; // 0-100
+  };
+  porosity: {
+    level: 'non-porous' | 'low-porous' | 'moderate-porous' | 'high-porous';
+    value: number; // 0-100
+  };
+}
+
+// 触感预测
+export interface TactilePredict {
+  temperature: {
+    perceived: 'cold' | 'cool' | 'neutral' | 'warm' | 'hot';
+    thermalConductivity: number; // 0-100
+  };
+  hardness: {
+    level: 'very-soft' | 'soft' | 'medium' | 'hard' | 'very-hard';
+    value: number; // 0-100
+  };
+  flexibility: {
+    level: 'rigid' | 'semi-rigid' | 'flexible' | 'very-flexible';
+    value: number; // 0-100
+  };
+  weight: {
+    perceived: 'very-light' | 'light' | 'medium' | 'heavy' | 'very-heavy';
+    density: number; // 0-100
+  };
+  comfort: {
+    tactileComfort: number; // 0-100
+    ergonomicSuitability: number; // 0-100
+  };
+}
+
+// 材质分类
+export interface MaterialClassification {
+  primaryMaterial: {
+    category: 'wood' | 'metal' | 'fabric' | 'leather' | 'plastic' | 'glass' | 'ceramic' | 'stone' | 'composite';
+    confidence: number; // 0-100
+    subcategory?: string;
+  };
+  secondaryMaterials: Array<{
+    category: string;
+    percentage: number;
+    confidence: number;
+  }>;
+  materialProperties: {
+    durability: number; // 0-100
+    maintenance: 'low' | 'medium' | 'high';
+    sustainability: number; // 0-100
+    costLevel: 'budget' | 'mid-range' | 'premium' | 'luxury';
+  };
+}
+
+// 质感质量评估
+export interface TextureQuality {
+  overallQuality: number; // 0-100
+  consistency: number; // 0-100
+  authenticity: number; // 0-100
+  visualAppeal: number; // 0-100
+  functionalSuitability: number; // 0-100
+  ageingCharacteristics: {
+    wearResistance: number; // 0-100
+    patinaPotential: number; // 0-100
+    maintenanceNeeds: string[];
+  };
+}
+
+@Injectable({
+  providedIn: 'root'
+})
+export class TextureAnalysisService {
+
+  constructor() { }
+
+  /**
+   * 分析图片中的质感特征
+   * @param imageFile 图片文件
+   */
+  analyzeImageTexture(imageFile: File): Observable<TextureAnalysisResult> {
+    return of(this.simulateTextureAnalysis(imageFile));
+  }
+
+  /**
+   * 分析URL图片的质感
+   * @param imageUrl 图片URL
+   */
+  analyzeTextureFromUrl(imageUrl: string): Observable<TextureAnalysisResult> {
+    return of(this.simulateTextureAnalysisFromUrl(imageUrl));
+  }
+
+  /**
+   * 模拟质感分析
+   */
+  private simulateTextureAnalysis(imageFile: File): TextureAnalysisResult {
+    const fileName = imageFile.name.toLowerCase();
+    return this.generateTextureAnalysis(fileName);
+  }
+
+  private simulateTextureAnalysisFromUrl(imageUrl: string): TextureAnalysisResult {
+    const urlLower = imageUrl.toLowerCase();
+    return this.generateTextureAnalysis(urlLower);
+  }
+
+  private generateTextureAnalysis(context: string): TextureAnalysisResult {
+    // 根据上下文推断材质类型
+    const materialType = this.inferMaterialType(context);
+    
+    return {
+      surfaceProperties: this.generateSurfaceProperties(materialType, context),
+      tactilePredict: this.generateTactilePredict(materialType, context),
+      materialClassification: this.generateMaterialClassification(materialType, context),
+      textureQuality: this.generateTextureQuality(materialType, context),
+      recommendations: this.generateTextureRecommendations(materialType, context)
+    };
+  }
+
+  private inferMaterialType(context: string): string {
+    if (context.includes('wood') || context.includes('timber')) return 'wood';
+    if (context.includes('metal') || context.includes('steel') || context.includes('aluminum')) return 'metal';
+    if (context.includes('fabric') || context.includes('textile') || context.includes('cloth')) return 'fabric';
+    if (context.includes('leather')) return 'leather';
+    if (context.includes('glass')) return 'glass';
+    if (context.includes('ceramic') || context.includes('porcelain')) return 'ceramic';
+    if (context.includes('stone') || context.includes('marble') || context.includes('granite')) return 'stone';
+    if (context.includes('plastic') || context.includes('polymer')) return 'plastic';
+    return 'composite'; // 默认复合材料
+  }
+
+  private generateSurfaceProperties(materialType: string, context: string): SurfaceProperties {
+    const baseProperties = this.getMaterialBaseProperties(materialType);
+    
+    // 根据上下文调整属性
+    const isPolished = context.includes('polished') || context.includes('glossy');
+    const isRough = context.includes('rough') || context.includes('textured');
+    
+    // 确定最终的粗糙度级别
+    const finalRoughnessLevel = isRough ? 'rough' : isPolished ? 'smooth' : baseProperties.roughness.level;
+    
+    return {
+      roughness: {
+        level: finalRoughnessLevel,
+        value: isRough ? 75 : isPolished ? 15 : baseProperties.roughness.value,
+        description: this.getRoughnessDescription(finalRoughnessLevel)
+      },
+      glossiness: {
+        level: isPolished ? 'high-gloss' : baseProperties.glossiness.level,
+        value: isPolished ? 90 : baseProperties.glossiness.value,
+        reflectivity: isPolished ? 85 : baseProperties.glossiness.reflectivity
+      },
+      transparency: baseProperties.transparency,
+      porosity: baseProperties.porosity
+    };
+  }
+
+  private getMaterialBaseProperties(materialType: string): SurfaceProperties {
+    const properties: { [key: string]: SurfaceProperties } = {
+      wood: {
+        roughness: { level: 'moderate', value: 45, description: '天然木纹质感' },
+        glossiness: { level: 'satin', value: 40, reflectivity: 35 },
+        transparency: { level: 'opaque', value: 5 },
+        porosity: { level: 'moderate-porous', value: 60 }
+      },
+      metal: {
+        roughness: { level: 'smooth', value: 20, description: '金属光滑表面' },
+        glossiness: { level: 'gloss', value: 80, reflectivity: 85 },
+        transparency: { level: 'opaque', value: 0 },
+        porosity: { level: 'non-porous', value: 5 }
+      },
+      fabric: {
+        roughness: { level: 'moderate', value: 55, description: '织物纤维质感' },
+        glossiness: { level: 'matte', value: 15, reflectivity: 10 },
+        transparency: { level: 'translucent', value: 30 },
+        porosity: { level: 'high-porous', value: 85 }
+      },
+      leather: {
+        roughness: { level: 'moderate', value: 50, description: '皮革天然纹理' },
+        glossiness: { level: 'semi-gloss', value: 60, reflectivity: 45 },
+        transparency: { level: 'opaque', value: 0 },
+        porosity: { level: 'low-porous', value: 25 }
+      },
+      glass: {
+        roughness: { level: 'very-smooth', value: 5, description: '玻璃光滑表面' },
+        glossiness: { level: 'high-gloss', value: 95, reflectivity: 90 },
+        transparency: { level: 'transparent', value: 90 },
+        porosity: { level: 'non-porous', value: 0 }
+      },
+      ceramic: {
+        roughness: { level: 'smooth', value: 25, description: '陶瓷光滑质感' },
+        glossiness: { level: 'gloss', value: 75, reflectivity: 70 },
+        transparency: { level: 'opaque', value: 0 },
+        porosity: { level: 'low-porous', value: 15 }
+      },
+      stone: {
+        roughness: { level: 'rough', value: 70, description: '石材天然质感' },
+        glossiness: { level: 'matte', value: 20, reflectivity: 15 },
+        transparency: { level: 'opaque', value: 0 },
+        porosity: { level: 'moderate-porous', value: 45 }
+      },
+      plastic: {
+        roughness: { level: 'smooth', value: 30, description: '塑料表面质感' },
+        glossiness: { level: 'semi-gloss', value: 65, reflectivity: 55 },
+        transparency: { level: 'translucent', value: 40 },
+        porosity: { level: 'non-porous', value: 5 }
+      },
+      composite: {
+        roughness: { level: 'moderate', value: 40, description: '复合材料质感' },
+        glossiness: { level: 'satin', value: 50, reflectivity: 40 },
+        transparency: { level: 'opaque', value: 10 },
+        porosity: { level: 'moderate-porous', value: 35 }
+      }
+    };
+
+    return properties[materialType] || properties['composite'];
+  }
+
+  private generateTactilePredict(materialType: string, context: string): TactilePredict {
+    const baseTactile = this.getMaterialTactileProperties(materialType);
+    
+    // 根据上下文调整
+    const isLuxury = context.includes('luxury') || context.includes('premium');
+    
+    return {
+      temperature: baseTactile.temperature,
+      hardness: baseTactile.hardness,
+      flexibility: baseTactile.flexibility,
+      weight: baseTactile.weight,
+      comfort: {
+        tactileComfort: isLuxury ? Math.min(100, baseTactile.comfort.tactileComfort + 15) : baseTactile.comfort.tactileComfort,
+        ergonomicSuitability: baseTactile.comfort.ergonomicSuitability
+      }
+    };
+  }
+
+  private getMaterialTactileProperties(materialType: string): TactilePredict {
+    const properties: { [key: string]: TactilePredict } = {
+      wood: {
+        temperature: { perceived: 'neutral', thermalConductivity: 30 },
+        hardness: { level: 'medium', value: 60 },
+        flexibility: { level: 'semi-rigid', value: 25 },
+        weight: { perceived: 'medium', density: 50 },
+        comfort: { tactileComfort: 80, ergonomicSuitability: 85 }
+      },
+      metal: {
+        temperature: { perceived: 'cold', thermalConductivity: 90 },
+        hardness: { level: 'very-hard', value: 95 },
+        flexibility: { level: 'rigid', value: 5 },
+        weight: { perceived: 'heavy', density: 85 },
+        comfort: { tactileComfort: 45, ergonomicSuitability: 60 }
+      },
+      fabric: {
+        temperature: { perceived: 'warm', thermalConductivity: 15 },
+        hardness: { level: 'soft', value: 20 },
+        flexibility: { level: 'very-flexible', value: 90 },
+        weight: { perceived: 'light', density: 20 },
+        comfort: { tactileComfort: 95, ergonomicSuitability: 90 }
+      },
+      leather: {
+        temperature: { perceived: 'neutral', thermalConductivity: 35 },
+        hardness: { level: 'medium', value: 55 },
+        flexibility: { level: 'flexible', value: 70 },
+        weight: { perceived: 'medium', density: 45 },
+        comfort: { tactileComfort: 85, ergonomicSuitability: 80 }
+      }
+    };
+
+    return properties[materialType] || properties['wood'];
+  }
+
+  private generateMaterialClassification(materialType: string, context: string): MaterialClassification {
+    const isLuxury = context.includes('luxury') || context.includes('premium');
+    const isEco = context.includes('eco') || context.includes('sustainable');
+    
+    return {
+      primaryMaterial: {
+        category: materialType as any,
+        confidence: 85 + Math.random() * 10,
+        subcategory: this.getSubcategory(materialType, context)
+      },
+      secondaryMaterials: this.getSecondaryMaterials(materialType),
+      materialProperties: {
+        durability: this.getDurability(materialType),
+        maintenance: this.getMaintenanceLevel(materialType),
+        sustainability: isEco ? 85 + Math.random() * 10 : this.getSustainability(materialType),
+        costLevel: isLuxury ? 'luxury' : this.getCostLevel(materialType)
+      }
+    };
+  }
+
+  private generateTextureQuality(materialType: string, context: string): TextureQuality {
+    const isHighEnd = context.includes('luxury') || context.includes('premium') || context.includes('high-end');
+    const baseQuality = isHighEnd ? 85 : 70;
+    
+    return {
+      overallQuality: baseQuality + Math.random() * 10,
+      consistency: baseQuality + Math.random() * 15,
+      authenticity: this.getAuthenticity(materialType, context),
+      visualAppeal: baseQuality + Math.random() * 15,
+      functionalSuitability: this.getFunctionalSuitability(materialType),
+      ageingCharacteristics: {
+        wearResistance: this.getWearResistance(materialType),
+        patinaPotential: this.getPatinaPotential(materialType),
+        maintenanceNeeds: this.getMaintenanceNeeds(materialType)
+      }
+    };
+  }
+
+  private generateTextureRecommendations(materialType: string, context: string): string[] {
+    const recommendations = [];
+    
+    switch (materialType) {
+      case 'wood':
+        recommendations.push('定期保养以维持木材质感');
+        recommendations.push('注意防潮和防虫处理');
+        break;
+      case 'metal':
+        recommendations.push('定期清洁以保持光泽');
+        recommendations.push('注意防锈处理');
+        break;
+      case 'fabric':
+        recommendations.push('选择合适的清洁方式');
+        recommendations.push('注意防污和防褪色');
+        break;
+      case 'leather':
+        recommendations.push('定期使用皮革保养剂');
+        recommendations.push('避免长期暴露在阳光下');
+        break;
+    }
+    
+    if (context.includes('outdoor')) {
+      recommendations.push('选择耐候性强的材质');
+    }
+    
+    return recommendations;
+  }
+
+  // 辅助方法
+  private getRoughnessDescription(level: string): string {
+    const descriptions: { [key: string]: string } = {
+      'very-smooth': '极其光滑的表面',
+      'smooth': '光滑的表面',
+      'moderate': '中等粗糙度',
+      'rough': '粗糙的表面',
+      'very-rough': '非常粗糙的表面'
+    };
+    return descriptions[level] || '表面质感';
+  }
+
+  private getSubcategory(materialType: string, context: string): string {
+    // 根据材质类型和上下文返回子类别
+    const subcategories: { [key: string]: string[] } = {
+      wood: ['硬木', '软木', '复合木材', '竹材'],
+      metal: ['不锈钢', '铝合金', '铜', '铁'],
+      fabric: ['棉质', '丝质', '羊毛', '合成纤维'],
+      leather: ['真皮', '人造革', '绒面革', '漆皮']
+    };
+    
+    const options = subcategories[materialType];
+    return options ? options[Math.floor(Math.random() * options.length)] : '标准类型';
+  }
+
+  private getSecondaryMaterials(materialType: string): Array<{category: string; percentage: number; confidence: number}> {
+    // 返回次要材质
+    return [
+      { category: '涂层', percentage: 15, confidence: 70 },
+      { category: '粘合剂', percentage: 5, confidence: 60 }
+    ];
+  }
+
+  private getDurability(materialType: string): number {
+    const durability: { [key: string]: number } = {
+      wood: 75, metal: 90, fabric: 60, leather: 80, glass: 85, ceramic: 80, stone: 95, plastic: 65
+    };
+    return durability[materialType] || 70;
+  }
+
+  private getMaintenanceLevel(materialType: string): 'low' | 'medium' | 'high' {
+    const maintenance: { [key: string]: 'low' | 'medium' | 'high' } = {
+      wood: 'medium', metal: 'low', fabric: 'high', leather: 'medium', glass: 'low', ceramic: 'low', stone: 'low', plastic: 'low'
+    };
+    return maintenance[materialType] || 'medium';
+  }
+
+  private getSustainability(materialType: string): number {
+    const sustainability: { [key: string]: number } = {
+      wood: 85, metal: 70, fabric: 60, leather: 50, glass: 80, ceramic: 75, stone: 90, plastic: 30
+    };
+    return sustainability[materialType] || 60;
+  }
+
+  private getCostLevel(materialType: string): 'budget' | 'mid-range' | 'premium' | 'luxury' {
+    const cost: { [key: string]: 'budget' | 'mid-range' | 'premium' | 'luxury' } = {
+      wood: 'mid-range', metal: 'mid-range', fabric: 'budget', leather: 'premium', glass: 'mid-range', ceramic: 'mid-range', stone: 'premium', plastic: 'budget'
+    };
+    return cost[materialType] || 'mid-range';
+  }
+
+  private getAuthenticity(materialType: string, context: string): number {
+    const base = 80;
+    const isNatural = context.includes('natural') || context.includes('authentic');
+    return isNatural ? base + 15 : base;
+  }
+
+  private getFunctionalSuitability(materialType: string): number {
+    const suitability: { [key: string]: number } = {
+      wood: 85, metal: 80, fabric: 75, leather: 80, glass: 70, ceramic: 75, stone: 85, plastic: 70
+    };
+    return suitability[materialType] || 75;
+  }
+
+  private getWearResistance(materialType: string): number {
+    const resistance: { [key: string]: number } = {
+      wood: 70, metal: 95, fabric: 50, leather: 75, glass: 60, ceramic: 85, stone: 90, plastic: 65
+    };
+    return resistance[materialType] || 70;
+  }
+
+  private getPatinaPotential(materialType: string): number {
+    const patina: { [key: string]: number } = {
+      wood: 85, metal: 70, fabric: 30, leather: 90, glass: 10, ceramic: 20, stone: 60, plastic: 15
+    };
+    return patina[materialType] || 40;
+  }
+
+  private getMaintenanceNeeds(materialType: string): string[] {
+    const needs: { [key: string]: string[] } = {
+      wood: ['定期打蜡', '防潮处理', '避免划伤'],
+      metal: ['防锈处理', '定期清洁', '避免腐蚀'],
+      fabric: ['定期清洗', '防污处理', '避免褪色'],
+      leather: ['皮革保养', '防干裂', '避免暴晒']
+    };
+    return needs[materialType] || ['常规保养'];
+  }
+}