Kaynağa Gözat

feat(项目详情): 为交付流程添加空间图片管理功能

为每个交付流程的空间添加图片上传、预览和删除功能
初始化空间内容数据结构
重构图片删除逻辑以同时支持新旧图片存储方式
添加文件输入控件和图片展示UI
触发变更检测以确保界面更新
0235711 2 gün önce
ebeveyn
işleme
0ea7e7b8af

+ 59 - 0
src/app/pages/designer/project-detail/project-detail.html

@@ -131,6 +131,18 @@
       </div>
     </div>
 
+  <!-- 隐藏的文件输入元素 -->
+  @for (process of deliveryProcesses; track process.id) {
+    @for (space of process.spaces; track space.id) {
+      <input 
+        type="file" 
+        [id]="'space-file-input-' + process.id + '-' + space.id"
+        accept="image/*" 
+        multiple 
+        (change)="onSpaceFileSelected($event, process.id, space.id)" 
+        style="display: none;" />
+    }
+  }
 </div>
 
 
@@ -928,6 +940,53 @@
                                             } @else if (process.type === 'rendering') {
                                               <!-- 渲染内容 -->
                                               <div class="rendering-content">
+                                                <div class="upload-section">
+                                                  <div class="upload-header">
+                                                    <h6>上传渲染图片</h6>
+                                                    <span class="hint">建议 ≥4K 分辨率的 JPG/PNG 图片</span>
+                                                  </div>
+                                                  @if (canEditSection('delivery')) {
+                                                    <div class="upload-dropzone" 
+                                                         (click)="!process.content[space.id]?.images || process.content[space.id].images.length === 0 ? triggerSpaceFileInput(process.id, space.id) : null"
+                                                         [class.has-images]="(process.content[space.id]?.images?.length || 0) > 0">
+                                                      @if (!process.content[space.id]?.images || process.content[space.id].images.length === 0) {
+                                                        <div class="upload-icon"></div>
+                                                        <div class="upload-text">点击此处上传渲染图片</div>
+                                                        <div class="upload-hint">支持 JPG、PNG 格式,建议 4K 分辨率</div>
+                                                      } @else {
+                                                        <div class="uploaded-images-grid">
+                                                          @for (img of process.content[space.id].images; track img.id) {
+                                                            <div class="uploaded-image-item" (click)="previewImage(img)">
+                                                              <img [src]="img.url" [alt]="img.name" />
+                                                              <div class="image-overlay">
+                                                                <div class="image-name">{{ img.name }}</div>
+                                                                <div class="image-actions">
+                                                                  <button class="preview-btn" (click)="$event.stopPropagation(); previewImage(img)">
+                                                                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+                                                                      <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
+                                                                      <circle cx="12" cy="12" r="3"></circle>
+                                                                    </svg>
+                                                                  </button>
+                                                                  <button class="remove-btn" (click)="$event.stopPropagation(); removeSpaceImage(process.id, space.id, img.id)">
+                                                                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+                                                                      <line x1="18" y1="6" x2="6" y2="18"></line>
+                                                                      <line x1="6" y1="6" x2="18" y2="18"></line>
+                                                                    </svg>
+                                                                  </button>
+                                                                </div>
+                                                              </div>
+                                                            </div>
+                                                          }
+                                                          <div class="add-more-btn" (click)="triggerSpaceFileInput(process.id, space.id)">
+                                                            <div class="add-icon">+</div>
+                                                            <div class="add-text">添加更多</div>
+                                                          </div>
+                                                        </div>
+                                                      }
+                                                    </div>
+                                                  }
+                                                </div>
+                                                
                                                 <div class="render-progress-info">
                                                   <h6>渲染进度</h6>
                                                   <div class="progress-details">

+ 47 - 12
src/app/pages/designer/project-detail/project-detail.ts

@@ -339,7 +339,11 @@ export class ProjectDetail implements OnInit, OnDestroy {
         { id: 'living', name: '客厅', isExpanded: false, order: 2 },
         { id: 'kitchen', name: '厨房', isExpanded: false, order: 3 }
       ],
-      content: {}
+      content: {
+        'bedroom': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() },
+        'living': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() },
+        'kitchen': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() }
+      }
     },
     {
       id: 'softDecor',
@@ -351,7 +355,11 @@ export class ProjectDetail implements OnInit, OnDestroy {
         { id: 'living', name: '客厅', isExpanded: false, order: 2 },
         { id: 'kitchen', name: '厨房', isExpanded: false, order: 3 }
       ],
-      content: {}
+      content: {
+        'bedroom': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() },
+        'living': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() },
+        'kitchen': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() }
+      }
     },
     {
       id: 'rendering',
@@ -363,7 +371,11 @@ export class ProjectDetail implements OnInit, OnDestroy {
         { id: 'living', name: '客厅', isExpanded: false, order: 2 },
         { id: 'kitchen', name: '厨房', isExpanded: false, order: 3 }
       ],
-      content: {}
+      content: {
+        'bedroom': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() },
+        'living': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() },
+        'kitchen': { images: [], progress: 0, status: 'pending', notes: '', lastUpdated: new Date() }
+      }
     }
   ];
 
@@ -1622,16 +1634,36 @@ export class ProjectDetail implements OnInit, OnDestroy {
 
   removeImageFromPreview(): void {
     if (this.previewImageData) {
-      // 根据图片类型调用相应的删除方法
-      if (this.whiteModelImages.find(i => i.id === this.previewImageData.id)) {
-        this.removeWhiteModelImage(this.previewImageData.id);
-      } else if (this.softDecorImages.find(i => i.id === this.previewImageData.id)) {
-        this.removeSoftDecorImage(this.previewImageData.id);
-      } else if (this.renderLargeImages.find(i => i.id === this.previewImageData.id)) {
-        this.removeRenderLargeImage(this.previewImageData.id);
-      } else if (this.postProcessImages.find(i => i.id === this.previewImageData.id)) {
-        this.removePostProcessImage(this.previewImageData.id);
+      // 首先检查新的 deliveryProcesses 结构
+      let imageFound = false;
+      
+      for (const process of this.deliveryProcesses) {
+        for (const space of process.spaces) {
+          if (process.content[space.id]?.images) {
+            const imageIndex = process.content[space.id].images.findIndex(img => img.id === this.previewImageData.id);
+            if (imageIndex > -1) {
+              this.removeSpaceImage(process.id, space.id, this.previewImageData.id);
+              imageFound = true;
+              break;
+            }
+          }
+        }
+        if (imageFound) break;
       }
+      
+      // 如果在新结构中没找到,检查旧的图片数组
+      if (!imageFound) {
+        if (this.whiteModelImages.find(i => i.id === this.previewImageData.id)) {
+          this.removeWhiteModelImage(this.previewImageData.id);
+        } else if (this.softDecorImages.find(i => i.id === this.previewImageData.id)) {
+          this.removeSoftDecorImage(this.previewImageData.id);
+        } else if (this.renderLargeImages.find(i => i.id === this.previewImageData.id)) {
+          this.removeRenderLargeImage(this.previewImageData.id);
+        } else if (this.postProcessImages.find(i => i.id === this.previewImageData.id)) {
+          this.removePostProcessImage(this.previewImageData.id);
+        }
+      }
+      
       this.closeImagePreview();
     }
   }
@@ -3249,6 +3281,9 @@ export class ProjectDetail implements OnInit, OnDestroy {
           process.content[spaceId].images.push(imageItem);
           process.content[spaceId].lastUpdated = new Date();
         });
+        
+        // 触发变更检测以更新界面
+        this.cdr.detectChanges();
       }
     }