创建了一个全新的独立画廊组件 StageGalleryModalComponent,用于展示阶段图片。该组件具有现代化的设计、完善的响应式支持和优秀的用户体验。
src/modules/project/components/stage-gallery-modal/
├── stage-gallery-modal.component.ts # 组件逻辑
├── stage-gallery-modal.component.html # 模板
└── stage-gallery-modal.component.scss # 样式
@Input() visible: boolean = false; // 是否显示
@Input() config: GalleryConfig | null = null; // 画廊配置
@Output() close = new EventEmitter<void>(); // 关闭事件
@Output() deleteFile = new EventEmitter<{ file, event }>(); // 删除文件
@Output() uploadFiles = new EventEmitter<Event>(); // 上传文件
@Output() previewFile = new EventEmitter<GalleryFile>(); // 预览文件
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)┌────────────────────────────────────────────┐
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 📷 │ │ 📷 │ │ 📷 │ │ 📷 │ │
│ │ [X] │ │ [X] │ │ [X] │ │ [X] │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ 文件名 文件名 文件名 文件名 │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 📷 │ │ 📄 │ │ 📷 │ │ 📷 │ │
│ │ [X] │ │ PDF │ │ [X] │ │ [X] │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
└────────────────────────────────────────────┘
特点:
#f8f9fa)┌────────────────────────────────────────────┐
│ [📤 上传文件] │ ← 渐变紫色按钮
└────────────────────────────────────────────┘
特点:
#667eea → #764ba2)┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ [×] ┃
┃ ┃
┃ [<] [ 大图预览 ] [>] ┃
┃ ┃
┃ 文件名.jpg 2/6 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
特点:
animation: slideUpBounce 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
// 弹性滑入效果
0% → 透明 + 下移 + 缩小
70% → 上移过头 + 放大
100% → 归位
transform: translateY(-4px) scale(1.02);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12);
// 图片放大
.preview-image {
transform: scale(1.05);
}
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
.images-grid {
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 24px;
}
.images-grid {
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.images-grid {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.gallery-container {
max-width: 100vw;
max-height: 100vh;
border-radius: 20px 20px 0 0; // 底部不圆角
}
import { StageGalleryModalComponent, GalleryConfig } from '@/components/stage-gallery-modal';
@Component({
imports: [StageGalleryModalComponent],
// ...
})
export class ParentComponent {
showGallery = false;
galleryConfig: GalleryConfig | null = null;
}
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;
}
<app-stage-gallery-modal
[visible]="showGallery"
[config]="galleryConfig"
(close)="onClose()"
(deleteFile)="onDelete($event)"
(uploadFiles)="onUpload($event)"
(previewFile)="onPreview($event)">
</app-stage-gallery-modal>
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 中的集成// 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);
}
}
}
<!-- 旧代码(删除) -->
<!-- <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>
// 头部渐变
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
// 按钮渐变
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.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);
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-thumb {
background: #cbd5e0;
border-radius: 4px;
}
<img loading="lazy" [src]="file.url" />
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
(click)="$event.stopPropagation()"
| 特性 | 旧组件 | 新组件 | 改进 |
|---|---|---|---|
| 设计 | 简单白色 | 渐变 + 玻璃拟态 | ✅ 现代化 |
| 动画 | 简单滑入 | 弹性滑入 | ✅ 更生动 |
| 响应式 | 基本支持 | 完整适配 | ✅ 更友好 |
| 大图预览 | 无 | 有 | ✅ 新功能 |
| 卡片效果 | 平面 | 阴影 + hover | ✅ 更立体 |
| 删除按钮 | 始终显示 | 桌面hover显示 | ✅ 更整洁 |
| 文件类型 | 只有图片 | 图片 + 文档 | ✅ 更完善 |
| 按钮样式 | 普通按钮 | 渐变 + 动画 | ✅ 更吸引 |
新的画廊组件是一个独立、完整、精美的解决方案,具有:
可以在任何需要展示图片画廊的场景中使用!
创建日期: 2025-12-07
版本: v1.0.0
状态: ✅ 完成并可用