|
@@ -1805,6 +1805,7 @@
|
|
|
} @else if (stage === '需求沟通') {
|
|
|
<!-- 需求沟通阶段:确认需求组件 -->
|
|
|
<app-requirements-confirm-card
|
|
|
+ #requirementsCard
|
|
|
(requirementConfirmed)="syncRequirementKeyInfo($event)"
|
|
|
(progressUpdated)="syncRequirementKeyInfo($event)"
|
|
|
(stageCompleted)="onRequirementsStageCompleted($event)"
|
|
@@ -1814,91 +1815,147 @@
|
|
|
</app-requirements-confirm-card>
|
|
|
|
|
|
} @else if (stage === '方案确认') {
|
|
|
- <!-- 需求映射面板(替换原色彩分析报告区域) -->
|
|
|
- <div class="requirement-mapping-panel" style="width:100%; display:flex; flex-direction:column; gap:14px;">
|
|
|
- <h3 class="panel-title" style="margin:0 0 16px 0; font-size:18px; font-weight:700; color:#495057;">🎯 需求映射</h3>
|
|
|
-
|
|
|
- <div class="mapping-progress" style="background:#f8f9fa; border-radius:8px; padding:16px; margin-bottom:12px;">
|
|
|
- @if (mappingUploadedFiles.length > 0) {
|
|
|
- <div class="progress-badge" style="display:inline-block; padding:6px 14px; background:linear-gradient(135deg, #667eea 0%, #764ba2 100%); color:white; border-radius:14px; font-size:12px; font-weight:600; margin-bottom:12px;">
|
|
|
- 📸 已同步 {{ mappingUploadedFiles.length }} 张参考图片
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- <div class="steps-list" style="display:flex; flex-direction:column; gap:10px;">
|
|
|
- <div class="step-item" style="display:flex; align-items:center; gap:10px;">
|
|
|
- <span class="step-index" style="width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:#e9ecef;color:#495057;font-size:12px;">1</span>
|
|
|
- <span class="step-title" style="flex:1;font-size:14px;">图片上传</span>
|
|
|
- <span class="step-status" style="font-size:12px;color:#666;">@if (mappingUploadedFiles.length > 0) { ✅ 完成 } @else { ⭕ 待上传 }</span>
|
|
|
- </div>
|
|
|
- <div class="step-item" style="display:flex; align-items:center; gap:10px;">
|
|
|
- <span class="step-index" style="width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:#e9ecef;color:#495057;font-size:12px;">2</span>
|
|
|
- <span class="step-title" style="flex:1;font-size:14px;">图片分析</span>
|
|
|
- <span class="step-status" style="font-size:12px;color:#666;">@if (mappingIsAnalyzing) { ⏳ 进行中 } @else if (mappingAnalysisResult) { ✅ 完成 } @else { ⭕ 待开始 }</span>
|
|
|
- </div>
|
|
|
- <div class="step-item" style="display:flex; align-items:center; gap:10px;">
|
|
|
- <span class="step-index" style="width:18px;height:18px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:#e9ecef;color:#495057;font-size:12px;">3</span>
|
|
|
- <span class="step-title" style="flex:1;font-size:14px;">需求映射</span>
|
|
|
- <span class="step-status" style="font-size:12px;color:#666;">@if (mappingIsGeneratingMapping) { ⏳ 生成中 } @else if (mappingRequirementMapping) { ✅ 完成 } @else { ⭕ 待生成 }</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <!-- 分析数据汇总面板(原需求映射面板) -->
|
|
|
+ <div class="analysis-summary-section" style="max-height: calc(100vh - 200px); overflow-y: auto; overflow-x: hidden; padding: 20px;">
|
|
|
+ <div class="section-header" style="margin-bottom: 24px; text-align: center;">
|
|
|
+ <h4 style="font-size: 1.5rem; font-weight: 700; color: #2c3e50; margin-bottom: 8px;">📊 分析数据汇总</h4>
|
|
|
+ <p class="section-description" style="color: #6c757d; font-size: 0.95rem;">查看所有素材的详细分析数据及可视化</p>
|
|
|
</div>
|
|
|
-
|
|
|
- @if (mappingAnalysisResult) {
|
|
|
- <div class="analysis-summary-panel" style="background:#f8f9fa;border-radius:8px;padding:16px;">
|
|
|
- <h4 style="margin:0 0 12px 0; font-size:15px; font-weight:600; color:#333;">图片分析摘要</h4>
|
|
|
- <div class="param-items" style="display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px;">
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">主色</span><span style="font-weight:500;">{{ mappingAnalysisResult.primaryColor?.hex || '未知' }}</span></div>
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">材质</span><span style="font-weight:500;">{{ getMaterialName(mappingAnalysisResult.materialType) }}</span></div>
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">灯光</span><span style="font-weight:500;">{{ getLightingMoodName(mappingAnalysisResult.lightingMood) }}</span></div>
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">对比</span><span style="font-weight:500;">{{ mappingAnalysisResult.contrast || '未知' }}</span></div>
|
|
|
- </div>
|
|
|
+
|
|
|
+ @if (requirementsCard?.materials?.length === 0 || !requirementsCard?.materials) {
|
|
|
+ <div class="empty-state" style="text-align: center; padding: 60px 20px;">
|
|
|
+ <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#dee2e6" stroke-width="1" style="margin-bottom: 20px;">
|
|
|
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
|
+ <line x1="9" y1="9" x2="15" y2="9"></line>
|
|
|
+ <line x1="9" y1="15" x2="15" y2="15"></line>
|
|
|
+ </svg>
|
|
|
+ <p style="color: #6c757d; font-size: 1rem; margin: 8px 0;">暂无素材分析数据</p>
|
|
|
+ <p class="hint" style="color: #adb5bd; font-size: 0.9rem; margin: 8px 0;">请先在"需求沟通"阶段上传素材</p>
|
|
|
</div>
|
|
|
}
|
|
|
-
|
|
|
- @if (mappingRequirementMapping) {
|
|
|
- <div class="mapping-result-panel" style="background:#f8f9fa;border-radius:8px;padding:16px;">
|
|
|
- <h4 style="margin:0 0 12px 0; font-size:15px; font-weight:600; color:#333;">需求映射结果</h4>
|
|
|
- @if (mappingRequirementMapping.color) {
|
|
|
- <div class="param-section" style="margin-bottom:12px;">
|
|
|
- <div class="section-title" style="font-weight:600;color:#555;margin-bottom:8px;font-size:13px;">色彩参数</div>
|
|
|
- <div class="param-items" style="display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px;">
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">和谐度</span><span style="font-weight:500;">{{ getColorHarmonyName(mappingRequirementMapping.color?.harmony) }}</span></div>
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">色温</span><span style="font-weight:500;">{{ getTemperatureName(mappingRequirementMapping.color?.temperature) }}</span></div>
|
|
|
+
|
|
|
+ @for (material of requirementsCard?.materials || []; track material.id) {
|
|
|
+ @if (material.analysis && material.type === 'image') {
|
|
|
+ <div class="material-analysis-card" style="background: white; border-radius: 12px; padding: 20px; margin-bottom: 24px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);">
|
|
|
+ <div class="material-header" style="display: flex; align-items: center; gap: 16px; margin-bottom: 20px; padding-bottom: 16px; border-bottom: 2px solid #f8f9fa;">
|
|
|
+ <img [src]="material.url" [alt]="material.name" class="material-thumbnail" style="width: 80px; height: 80px; object-fit: cover; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);">
|
|
|
+ <div class="material-info" style="flex: 1;">
|
|
|
+ <h5 style="font-size: 1.1rem; font-weight: 600; color: #2c3e50; margin-bottom: 4px;">{{ material.name }}</h5>
|
|
|
+ <span class="upload-time" style="font-size: 0.85rem; color: #6c757d;">{{ material.uploadTime | date: 'yyyy-MM-dd HH:mm' }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- }
|
|
|
- @if (mappingRequirementMapping.space) {
|
|
|
- <div class="param-section">
|
|
|
- <div class="section-title" style="font-weight:600;color:#555;margin-bottom:8px;font-size:13px;">空间参数</div>
|
|
|
- <div class="param-items" style="display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px;">
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">布局</span><span style="font-weight:500;">{{ getLayoutTypeName(mappingRequirementMapping.space?.layoutType) }}</span></div>
|
|
|
- <div class="param-row" style="font-size:13px;"><span style="color:#868e96;">流线</span><span style="font-weight:500;">{{ getFlowTypeName(mappingRequirementMapping.space?.flowType) }}</span></div>
|
|
|
- </div>
|
|
|
+
|
|
|
+ <div class="analysis-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
|
|
|
+ <!-- 色彩分析卡片 -->
|
|
|
+ @if (material.analysis.enhancedColorAnalysis) {
|
|
|
+ <div class="analysis-card color-card" style="background: #f8f9fa; padding: 14px; border-radius: 10px; border: 1px solid #e9ecef;">
|
|
|
+ <h6 style="font-size: 0.95rem; font-weight: 600; margin-bottom: 12px; color: #495057;">🎨 色彩分析</h6>
|
|
|
+ @if (material.analysis.mainColors && material.analysis.mainColors.length > 0) {
|
|
|
+ <app-color-wheel-visualizer
|
|
|
+ [colors]="material.analysis.mainColors"
|
|
|
+ [size]="140"
|
|
|
+ [showLabels]="true"
|
|
|
+ [showPercentages]="true">
|
|
|
+ </app-color-wheel-visualizer>
|
|
|
+ }
|
|
|
+ @if (material.analysis.enhancedColorAnalysis.colorPsychology) {
|
|
|
+ <div class="psychology-tags" style="display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px;">
|
|
|
+ <span class="tag" style="padding: 4px 12px; background: white; border-radius: 20px; font-size: 0.8rem; color: #667eea; border: 1px solid #667eea;">{{ material.analysis.enhancedColorAnalysis.colorPsychology.primaryMood }}</span>
|
|
|
+ <span class="tag" style="padding: 4px 12px; background: white; border-radius: 20px; font-size: 0.8rem; color: #667eea; border: 1px solid #667eea;">{{ material.analysis.enhancedColorAnalysis.colorPsychology.atmosphere }}</span>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
+ <!-- 形体分析卡片 -->
|
|
|
+ @if (material.analysis.formAnalysis) {
|
|
|
+ <div class="analysis-card form-card" style="background: #f8f9fa; padding: 14px; border-radius: 10px; border: 1px solid #e9ecef;">
|
|
|
+ <h6 style="font-size: 0.95rem; font-weight: 600; margin-bottom: 12px; color: #495057;">📐 形体分析</h6>
|
|
|
+ <app-furniture-form-selector
|
|
|
+ (formSelected)="requirementsCard?.onFormSelected($event)"
|
|
|
+ (formDeselected)="requirementsCard?.onFormDeselected($event)">
|
|
|
+ </app-furniture-form-selector>
|
|
|
+ @if (material.analysis.formAnalysis.overallAssessment) {
|
|
|
+ <div class="assessment-metrics" style="display: flex; gap: 12px; margin-top: 12px;">
|
|
|
+ <div class="metric" style="flex: 1; display: flex; flex-direction: column; align-items: center; padding: 10px; background: white; border-radius: 8px;">
|
|
|
+ <span style="font-size: 0.8rem; color: #6c757d;">复杂度</span>
|
|
|
+ <span class="value" style="font-size: 1.1rem; font-weight: 700; color: #667eea; margin-top: 4px;">{{ material.analysis.formAnalysis.overallAssessment.formComplexity }}%</span>
|
|
|
+ </div>
|
|
|
+ <div class="metric" style="flex: 1; display: flex; flex-direction: column; align-items: center; padding: 10px; background: white; border-radius: 8px;">
|
|
|
+ <span style="font-size: 0.8rem; color: #6c757d;">视觉冲击</span>
|
|
|
+ <span class="value" style="font-size: 1.1rem; font-weight: 700; color: #667eea; margin-top: 4px;">{{ material.analysis.formAnalysis.overallAssessment.visualImpact }}%</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
+ <!-- 质感分析卡片 -->
|
|
|
+ @if (material.analysis.textureAnalysis) {
|
|
|
+ <div class="analysis-card texture-card" style="background: #f8f9fa; padding: 14px; border-radius: 10px; border: 1px solid #e9ecef;">
|
|
|
+ <h6 style="font-size: 0.95rem; font-weight: 600; margin-bottom: 12px; color: #495057;">🪨 质感分析</h6>
|
|
|
+ <app-texture-comparison-visualizer
|
|
|
+ [textures]="requirementsCard?.getTextureDataForMaterial(material) || []">
|
|
|
+ </app-texture-comparison-visualizer>
|
|
|
+ @if (material.analysis.textureAnalysis.materialClassification?.primaryMaterial) {
|
|
|
+ <div class="material-tag" style="text-align: center; padding: 8px 14px; background: white; border-radius: 8px; font-size: 0.85rem; font-weight: 600; color: #667eea; margin-top: 12px;">
|
|
|
+ {{ material.analysis.textureAnalysis.materialClassification?.primaryMaterial?.category }}
|
|
|
+ ({{ material.analysis.textureAnalysis.materialClassification?.primaryMaterial?.confidence }}%)
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
+ <!-- 纹理分析卡片 -->
|
|
|
+ @if (material.analysis.patternAnalysis) {
|
|
|
+ <div class="analysis-card pattern-card" style="background: #f8f9fa; padding: 14px; border-radius: 10px; border: 1px solid #e9ecef;">
|
|
|
+ <h6 style="font-size: 0.95rem; font-weight: 600; margin-bottom: 12px; color: #495057;">🖼️ 纹理分析</h6>
|
|
|
+ <app-pattern-visualizer>
|
|
|
+ </app-pattern-visualizer>
|
|
|
+ @if (material.analysis.patternAnalysis.patternRecognition) {
|
|
|
+ <div class="pattern-tags" style="display: flex; gap: 6px; flex-wrap: wrap; margin-top: 12px;">
|
|
|
+ @for (pattern of material.analysis.patternAnalysis.patternRecognition.primaryPatterns; track pattern.type) {
|
|
|
+ <span class="tag" style="padding: 4px 10px; background: white; border-radius: 20px; font-size: 0.75rem; color: #667eea; border: 1px solid #667eea;">{{ pattern.type }} ({{ pattern.coverage }}%)</span>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
+ <!-- 灯光分析卡片 -->
|
|
|
+ @if (material.analysis.lightingAnalysis) {
|
|
|
+ <div class="analysis-card lighting-card" style="background: #f8f9fa; padding: 14px; border-radius: 10px; border: 1px solid #e9ecef;">
|
|
|
+ <h6 style="font-size: 0.95rem; font-weight: 600; margin-bottom: 12px; color: #495057;">💡 灯光分析</h6>
|
|
|
+ @if (material.analysis.lightingAnalysis.lightingRatio) {
|
|
|
+ <div class="lighting-ratio-visual">
|
|
|
+ <div class="ratio-bar" style="display: flex; height: 34px; border-radius: 8px; overflow: hidden; margin-bottom: 10px;">
|
|
|
+ <div class="key-light" [style.width.%]="material.analysis.lightingAnalysis.lightingRatio.keyLightIntensity" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; align-items: center; justify-content: center; color: white; font-size: 0.75rem; font-weight: 600;">
|
|
|
+ 主光 {{ material.analysis.lightingAnalysis.lightingRatio.keyLightIntensity }}%
|
|
|
+ </div>
|
|
|
+ <div class="fill-light" [style.width.%]="material.analysis.lightingAnalysis.lightingRatio.fillLightIntensity" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); display: flex; align-items: center; justify-content: center; color: white; font-size: 0.75rem; font-weight: 600;">
|
|
|
+ 补光 {{ material.analysis.lightingAnalysis.lightingRatio.fillLightIntensity }}%
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <span class="ratio-quality" style="display: block; text-align: center; font-size: 0.85rem; color: #667eea; font-weight: 600;">{{ requirementsCard?.getRatioDescription(material.analysis.lightingAnalysis.lightingRatio.description) }}</span>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ @if (material.analysis.lightingAnalysis.lightDistribution) {
|
|
|
+ <div class="light-distribution" style="display: flex; flex-direction: column; gap: 6px; margin-top: 10px;">
|
|
|
+ <div class="dist-item" style="display: flex; justify-content: space-between; align-items: center; padding: 6px 10px; background: white; border-radius: 6px;">
|
|
|
+ <span style="font-size: 0.85rem; color: #495057;">自然光</span>
|
|
|
+ <span class="value" style="font-weight: 700; color: #667eea; font-size: 0.85rem;">{{ material.analysis.lightingAnalysis.lightDistribution.natural }}%</span>
|
|
|
+ </div>
|
|
|
+ <div class="dist-item" style="display: flex; justify-content: space-between; align-items: center; padding: 6px 10px; background: white; border-radius: 6px;">
|
|
|
+ <span style="font-size: 0.85rem; color: #495057;">人工光</span>
|
|
|
+ <span class="value" style="font-weight: 700; color: #667eea; font-size: 0.85rem;">{{ material.analysis.lightingAnalysis.lightDistribution.artificial }}%</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
</div>
|
|
|
- }
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- @if (mappingIsAnalyzing) {
|
|
|
- <div class="analyzing-indicator" style="display:flex; align-items:center; gap:10px; background:#f8f9fa; padding:12px; border-radius:8px;">
|
|
|
- <div class="spinner" style="width:16px;height:16px;border:2px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;animation:spin 1s linear infinite;"></div>
|
|
|
- <span style="font-size:14px; color:#666;">正在解析图片...</span>
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- @if (mappingIsGeneratingMapping) {
|
|
|
- <div class="analyzing-indicator" style="display:flex; align-items:center; gap:10px; background:#f8f9fa; padding:12px; border-radius:8px;">
|
|
|
- <div class="spinner" style="width:16px;height:16px;border:2px solid #e5e7eb;border-top-color:#10b981;border-radius:50%;animation:spin 1s linear infinite;"></div>
|
|
|
- <span style="font-size:14px; color:#666;">正在生成需求映射...</span>
|
|
|
- </div>
|
|
|
- }
|
|
|
-
|
|
|
- @if (!mappingAnalysisResult && !mappingIsAnalyzing && mappingUploadedFiles.length === 0) {
|
|
|
- <div class="empty-state" style="text-align:center; padding:32px; color:#999;">
|
|
|
- <div style="font-size:48px; margin-bottom:12px;">📊</div>
|
|
|
- <div style="font-size:14px;">在需求沟通中上传图片后,这里将实时显示需求映射结果</div>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
}
|
|
|
</div>
|
|
|
|