NEW_GALLERY_COMPONENT.md 13 KB

🎨 新的精美画廊组件

📋 概述

创建了一个全新的独立画廊组件 StageGalleryModalComponent,用于展示阶段图片。该组件具有现代化的设计、完善的响应式支持和优秀的用户体验。


✨ 核心特性

1. 精美设计

  • 🌈 渐变背景 - 紫色渐变头部,视觉吸引力强
  • 玻璃拟态 - 背景模糊、半透明效果
  • 🎭 阴影层次 - 多层阴影增强立体感
  • 🎨 动画效果 - 弹性滑入、hover 动画
  • 🔲 大圆角 - 16-20px 圆角,柔和友好

2. 响应式布局

  • 💻 桌面端 - 自适应列数(240px 最小宽度)
  • 📱 平板端 - 3列网格布局
  • 📱 手机端 - 2列网格布局
  • 📏 智能间距 - 根据屏幕大小自动调整

3. 完整功能

  • 🖼️ 大图预览 - 点击图片全屏查看
  • ⬅️ 左右切换 - 键盘和按钮切换
  • 🗑️ 删除文件 - 带确认的删除功能
  • 📤 上传文件 - 底部渐变按钮上传
  • 📁 文件支持 - 图片和文档预览

4. 用户体验

  • 🎬 流畅动画 - 打开、关闭、hover
  • 👆 易于操作 - 大按钮、清晰图标
  • 📊 信息完整 - 文件名、数量、大小
  • 🎯 视觉反馈 - hover 高亮、点击缩放

📁 文件结构

src/modules/project/components/stage-gallery-modal/
├── stage-gallery-modal.component.ts       # 组件逻辑
├── stage-gallery-modal.component.html     # 模板
└── stage-gallery-modal.component.scss     # 样式

🎯 组件接口

输入属性 (Inputs)

@Input() visible: boolean = false;                  // 是否显示
@Input() config: GalleryConfig | null = null;      // 画廊配置

输出事件 (Outputs)

@Output() close = new EventEmitter<void>();                        // 关闭事件
@Output() deleteFile = new EventEmitter<{ file, event }>();        // 删除文件
@Output() uploadFiles = new EventEmitter<Event>();                 // 上传文件
@Output() previewFile = new EventEmitter<GalleryFile>();          // 预览文件

配置接口 (GalleryConfig)

interface GalleryConfig {
  spaceId: string;         // 空间ID
  spaceName: string;       // 空间名称
  stageId: string;         // 阶段ID
  stageName: string;       // 阶段名称
  files: GalleryFile[];    // 文件列表
  canEdit?: boolean;       // 是否可编辑
}

interface GalleryFile {
  id: string;              // 文件ID
  name: string;            // 文件名
  url: string;             // 文件URL
  size?: number;           // 文件大小
  type?: string;           // 文件类型
  uploadTime?: Date;       // 上传时间
}

🎨 视觉设计

头部设计

┌────────────────────────────────────────────┐
│ [🏠] 后期 - 门厅                      [×]  │ ← 渐变紫色背景
│      📁 6 个文件                           │ ← 文件数提示
└────────────────────────────────────────────┘

特点:

  • 渐变背景 (#667eea → #764ba2)
  • 大图标 (56px)
  • 玻璃拟态效果
  • 关闭按钮 hover 变红

内容区域

┌────────────────────────────────────────────┐
│  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐  │
│  │ 📷   │  │ 📷   │  │ 📷   │  │ 📷   │  │
│  │ [X]  │  │ [X]  │  │ [X]  │  │ [X]  │  │
│  └──────┘  └──────┘  └──────┘  └──────┘  │
│   文件名    文件名    文件名    文件名     │
│                                            │
│  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐  │
│  │ 📷   │  │ 📄   │  │ 📷   │  │ 📷   │  │
│  │ [X]  │  │ PDF  │  │ [X]  │  │ [X]  │  │
│  └──────┘  └──────┘  └──────┘  └──────┘  │
└────────────────────────────────────────────┘

特点:

  • 浅灰背景 (#f8f9fa)
  • 白色卡片 + 阴影
  • hover 上移 + 阴影增强
  • 删除按钮仅 hover 显示(移动端始终显示)
  • 4:3 图片比例

底部操作栏

┌────────────────────────────────────────────┐
│         [📤 上传文件]                      │ ← 渐变紫色按钮
└────────────────────────────────────────────┘

特点:

  • 渐变按钮 (#667eea → #764ba2)
  • 阴影效果
  • hover 上移动画
  • 全宽按钮(移动端)

大图预览

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                    [×]                    ┃
┃                                           ┃
┃   [<]        [  大图预览  ]         [>]  ┃
┃                                           ┃
┃            文件名.jpg  2/6                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

特点:

  • 黑色半透明背景 + 模糊
  • 大图居中显示
  • 左右箭头切换
  • 底部文件信息
  • 点击空白关闭

🎬 动画效果

打开动画

animation: slideUpBounce 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);

// 弹性滑入效果
0%   → 透明 + 下移 + 缩小
70%  → 上移过头 + 放大
100% → 归位

卡片 hover

transform: translateY(-4px) scale(1.02);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12);

// 图片放大
.preview-image {
  transform: scale(1.05);
}

按钮 hover

transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);

📱 响应式设计

桌面端 (>1024px)

.images-grid {
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 24px;
}

平板端 (768px - 1024px)

.images-grid {
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

手机端 (<768px)

.images-grid {
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

小手机 (<480px)

.gallery-container {
  max-width: 100vw;
  max-height: 100vh;
  border-radius: 20px 20px 0 0; // 底部不圆角
}

🔧 使用方法

1. 在父组件导入

import { StageGalleryModalComponent, GalleryConfig } from '@/components/stage-gallery-modal';

@Component({
  imports: [StageGalleryModalComponent],
  // ...
})
export class ParentComponent {
  showGallery = false;
  galleryConfig: GalleryConfig | null = null;
}

2. 准备配置数据

openGallery() {
  this.galleryConfig = {
    spaceId: 'space-001',
    spaceName: '客厅',
    stageId: 'rendering',
    stageName: '渲染',
    files: [
      {
        id: 'file-001',
        name: 'living-room.jpg',
        url: 'https://example.com/image.jpg',
        size: 1024000, // 1MB
        uploadTime: new Date()
      }
    ],
    canEdit: true
  };
  
  this.showGallery = true;
}

3. 在模板中使用

<app-stage-gallery-modal
  [visible]="showGallery"
  [config]="galleryConfig"
  (close)="onClose()"
  (deleteFile)="onDelete($event)"
  (uploadFiles)="onUpload($event)"
  (previewFile)="onPreview($event)">
</app-stage-gallery-modal>

4. 处理事件

onClose() {
  this.showGallery = false;
  this.galleryConfig = null;
}

onDelete(event: { file: GalleryFile; event: Event }) {
  console.log('删除文件:', event.file);
  // 处理删除逻辑
}

onUpload(event: Event) {
  const input = event.target as HTMLInputElement;
  const files = input.files;
  // 处理上传逻辑
}

onPreview(file: GalleryFile) {
  console.log('预览文件:', file);
  // 处理预览逻辑
}

🎯 实际集成示例

stage-delivery-execution 中的集成

TypeScript 更新

// 1. 导入组件
import { StageGalleryModalComponent, GalleryConfig } from '@/components/stage-gallery-modal';

// 2. 添加到 imports
@Component({
  imports: [StageGalleryModalComponent],
  // ...
})

// 3. 更新属性
export class StageDeliveryExecutionComponent {
  showStageGalleryModal = false;
  galleryConfig: GalleryConfig | null = null;
  
  // 4. 打开画廊
  openStageGallery(spaceId: string, stageId: string) {
    const space = this.projectProducts.find(p => p.id === spaceId);
    const stage = this.deliveryTypes.find(t => t.id === stageId);
    const files = this.getProductDeliveryFiles(spaceId, stageId);
    
    this.galleryConfig = {
      spaceId,
      spaceName: space.name,
      stageId,
      stageName: stage.name,
      files: files.map(f => ({
        id: f.id,
        name: f.name,
        url: f.url,
        size: f.size,
        uploadTime: f.uploadTime
      })),
      canEdit: this.canEdit
    };
    
    this.showStageGalleryModal = true;
  }
  
  // 5. 事件处理
  onGalleryDeleteFile(event: { file: any; event: Event }) {
    const file = this.deliveryFiles[this.galleryConfig?.spaceId || '']
      ?.[this.galleryConfig?.stageId as any]
      ?.find(f => f.id === event.file.id);
    if (file) {
      this.deleteDeliveryFile(file, event.event);
    }
  }
  
  onGalleryUploadFiles(event: Event) {
    if (this.galleryConfig) {
      this.uploadDeliveryFile(event, this.galleryConfig.spaceId, this.galleryConfig.stageId);
    }
  }
}

HTML 更新

<!-- 旧代码(删除) -->
<!-- <div class="stage-gallery-modal-overlay">...</div> -->

<!-- 新代码 -->
<app-stage-gallery-modal
  [visible]="showStageGalleryModal"
  [config]="galleryConfig"
  (close)="closeStageGallery()"
  (deleteFile)="onGalleryDeleteFile($event)"
  (uploadFiles)="onGalleryUploadFiles($event)"
  (previewFile)="onGalleryPreviewFile($event)">
</app-stage-gallery-modal>

🎨 样式亮点

1. 渐变设计

// 头部渐变
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

// 按钮渐变
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

2. 玻璃拟态

backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);

3. 阴影层次

// 弹窗阴影
box-shadow: 
  0 20px 60px rgba(0, 0, 0, 0.3),
  0 0 0 1px rgba(255, 255, 255, 0.1);

// 卡片阴影
box-shadow: 
  0 2px 8px rgba(0, 0, 0, 0.06),
  0 0 0 1px rgba(0, 0, 0, 0.04);

// hover 阴影
box-shadow: 
  0 12px 24px rgba(0, 0, 0, 0.12),
  0 0 0 1px rgba(102, 126, 234, 0.3);

4. 自定义滚动条

&::-webkit-scrollbar {
  width: 8px;
}

&::-webkit-scrollbar-thumb {
  background: #cbd5e0;
  border-radius: 4px;
}

🚀 性能优化

1. 懒加载图片

<img loading="lazy" [src]="file.url" />

2. ChangeDetection优化

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush
})

3. 事件传播控制

(click)="$event.stopPropagation()"

📊 对比表

特性 旧组件 新组件 改进
设计 简单白色 渐变 + 玻璃拟态 ✅ 现代化
动画 简单滑入 弹性滑入 ✅ 更生动
响应式 基本支持 完整适配 ✅ 更友好
大图预览 ✅ 新功能
卡片效果 平面 阴影 + hover ✅ 更立体
删除按钮 始终显示 桌面hover显示 ✅ 更整洁
文件类型 只有图片 图片 + 文档 ✅ 更完善
按钮样式 普通按钮 渐变 + 动画 ✅ 更吸引

✅ 优势总结

视觉优势

  1. 现代设计 - 渐变、玻璃拟态、阴影
  2. 🎨 统一风格 - 紫色主题贯穿
  3. 🎬 流畅动画 - 弹性、淡入、hover
  4. 📐 层次分明 - 头部、内容、底部清晰

功能优势

  1. 🖼️ 大图预览 - 全屏查看 + 左右切换
  2. 📱 完全响应式 - 适配所有屏幕
  3. 🗑️ 智能删除 - 桌面hover,移动端始终显示
  4. 📤 便捷上传 - 底部渐变按钮

体验优势

  1. 👆 易于操作 - 大按钮、清晰反馈
  2. 📊 信息完整 - 文件名、大小、数量
  3. 🎯 视觉引导 - 图标、颜色、动画
  4. 🚀 性能优化 - 懒加载、OnPush

🎉 总结

新的画廊组件是一个独立、完整、精美的解决方案,具有:

  • 完善的功能 - 预览、删除、上传
  • 精美的设计 - 渐变、玻璃拟态、动画
  • 响应式布局 - 适配所有设备
  • 易于集成 - 清晰的接口和文档
  • 性能优化 - 懒加载、OnPush

可以在任何需要展示图片画廊的场景中使用!


创建日期: 2025-12-07
版本: v1.0.0
状态: ✅ 完成并可用