import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; interface ReferenceImage { id: string; name: string; url: string; categories: string[]; description?: string; tags?: string[]; uploadDate: Date; } interface SelectedFile { file: File; name: string; size: number; preview: string; } interface AIQuestion { id: string; title: string; description: string; example: string; icon: string; category?: string; } @Component({ selector: 'app-reference-image-manager', standalone: true, imports: [CommonModule, FormsModule], templateUrl: './reference-image-manager.component.html', styleUrls: ['./reference-image-manager.component.scss'] }) export class ReferenceImageManagerComponent implements OnInit { @Input() projectId: string = ''; @Output() imagesUpdated = new EventEmitter(); // 视图状态 viewMode: 'grid' | 'list' = 'grid'; activeFilter: string = 'all'; selectedImageId: string | null = null; // 数据 referenceImages: ReferenceImage[] = []; filteredImages: ReferenceImage[] = []; // 对话框状态 showUploadDialog = false; showEditDialog = false; showAIDialog = false; showPreviewDialog = false; // 上传相关 isDragging = false; selectedFiles: SelectedFile[] = []; // 编辑相关 editingImage: ReferenceImage | null = null; newTag = ''; // AI助手相关 aiImage: ReferenceImage | null = null; customQuestion = ''; // AI建议追问(参考图多的情况) aiQuestionsMultiple: AIQuestion[] = [ { id: 'q1', title: '明确灯光参考', description: '当有多张参考图时,需要明确哪张图主要用于灯光布局参考', example: '请问这几张参考图中,哪一张是您想要的灯光效果?主要参考它的主光源布置还是氛围灯效果?', icon: 'icon-lightbulb', category: 'lighting' }, { id: 'q2', title: '区分软装参考', description: '识别哪些图片用于软装家具的参考', example: '这些参考图中,哪几张是用于软装搭配的?具体是参考家具的款式、颜色还是整体搭配方案?', icon: 'icon-couch', category: 'furniture' }, { id: 'q3', title: '确认氛围感觉', description: '明确整体氛围和感觉的主要参考图', example: '您希望达到的整体氛围感觉,主要是参考哪张图?是温馨、现代还是其他风格?', icon: 'icon-stars', category: 'atmosphere' }, { id: 'q4', title: '结构布局说明', description: '确认空间结构和布局的参考依据', example: '空间的布局结构,是按照哪张图来的?需要完全一致还是可以适当调整?', icon: 'icon-cube', category: 'structure' } ]; // AI建议追问(参考图少的情况) aiQuestionsFew: AIQuestion[] = [ { id: 'q5', title: '细化感觉来源', description: '深入了解客户喜欢这张图的具体原因', example: '您喜欢这张图的哪些方面?是整体的色调、光线效果、还是家具的搭配?能具体说说吗?', icon: 'icon-heart', }, { id: 'q6', title: '明确重点元素', description: '确认图片中最重要的参考元素', example: '这张图里,您最想要的是什么?比如墙面的颜色、地板材质、还是家具的款式?请按重要性排个序。', icon: 'icon-target', }, { id: 'q7', title: '探索细节要求', description: '挖掘客户对细节的具体期望', example: '关于这张图的细节,比如灯具的样式、窗帘的材质、墙面的装饰等,您有特别的偏好吗?', icon: 'icon-zoom-in', }, { id: 'q8', title: '确认可调整空间', description: '了解哪些地方可以灵活调整', example: '如果完全按这张图来可能有些困难,哪些元素是必须保留的?哪些可以根据实际情况调整?', icon: 'icon-sliders', } ]; previewImageUrl = ''; ngOnInit() { this.loadReferenceImages(); } // 加载参考图数据 loadReferenceImages() { // 模拟数据,实际应该从服务器加载 this.referenceImages = [ { id: '1', name: '客厅灯光参考.jpg', url: document.baseURI+'/assets/images/portfolio-1.svg', categories: ['lighting', 'atmosphere'], description: '参考主灯和氛围灯的布局,营造温馨的晚间氛围', tags: ['吊灯', '暖光', '氛围灯'], uploadDate: new Date('2024-01-15') }, { id: '2', name: '软装搭配方案.jpg', url: document.baseURI+'/assets/images/portfolio-2.svg', categories: ['furniture'], description: '参考沙发、茶几的款式和颜色搭配', tags: ['现代简约', '布艺沙发', '木质茶几'], uploadDate: new Date('2024-01-16') }, { id: '3', name: '整体效果图.jpg', url: document.baseURI+'/assets/images/portfolio-3.svg', categories: [], description: '', tags: [], uploadDate: new Date('2024-01-17') } ]; this.filteredImages = [...this.referenceImages]; } // 分类筛选 filterByCategory(category: string) { this.activeFilter = category; if (category === 'all') { this.filteredImages = [...this.referenceImages]; } else if (category === 'uncategorized') { this.filteredImages = this.referenceImages.filter(img => !img.categories || img.categories.length === 0 ); } else { this.filteredImages = this.referenceImages.filter(img => img.categories && img.categories.includes(category) ); } } // 获取分类数量 getCategoryCount(category: string): number { return this.referenceImages.filter(img => img.categories && img.categories.includes(category) ).length; } // 获取未分类数量 getUncategorizedCount(): number { return this.referenceImages.filter(img => !img.categories || img.categories.length === 0 ).length; } // 获取分类标签文本 getCategoryLabel(category: string): string { const labels: { [key: string]: string } = { 'lighting': '灯光', 'furniture': '软装', 'atmosphere': '氛围', 'structure': '结构' }; return labels[category] || category; } // 获取筛选器标签 getFilterLabel(): string { const labels: { [key: string]: string } = { 'all': '全部', 'lighting': '灯光参考', 'furniture': '软装参考', 'atmosphere': '氛围参考', 'structure': '结构参考', 'uncategorized': '未分类' }; return labels[this.activeFilter] || ''; } // 选择图片 selectImage(image: ReferenceImage) { this.selectedImageId = image.id; } // 打开上传对话框 openUploadDialog() { this.showUploadDialog = true; this.selectedFiles = []; } // 关闭上传对话框 closeUploadDialog() { this.showUploadDialog = false; this.selectedFiles = []; } // 文件拖拽 onDragOver(event: DragEvent) { event.preventDefault(); this.isDragging = true; } onDragLeave(event: DragEvent) { event.preventDefault(); this.isDragging = false; } onDrop(event: DragEvent) { event.preventDefault(); this.isDragging = false; const files = event.dataTransfer?.files; if (files) { this.processFiles(files); } } // 文件选择 onFileSelected(event: Event) { const input = event.target as HTMLInputElement; if (input.files) { this.processFiles(input.files); } } // 处理文件 processFiles(files: FileList) { for (let i = 0; i < files.length; i++) { const file = files[i]; if (file.type.startsWith('image/')) { const reader = new FileReader(); reader.onload = (e) => { this.selectedFiles.push({ file: file, name: file.name, size: file.size, preview: e.target?.result as string }); }; reader.readAsDataURL(file); } } } // 移除选中的文件 removeSelectedFile(index: number) { this.selectedFiles.splice(index, 1); } // 格式化文件大小 formatFileSize(bytes: number): string { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB'; return (bytes / (1024 * 1024)).toFixed(2) + ' MB'; } // 上传文件 uploadFiles() { // 模拟上传 this.selectedFiles.forEach(file => { const newImage: ReferenceImage = { id: Date.now().toString() + Math.random(), name: file.name, url: file.preview, categories: [], description: '', tags: [], uploadDate: new Date() }; this.referenceImages.unshift(newImage); }); this.filteredImages = [...this.referenceImages]; this.imagesUpdated.emit(this.referenceImages); this.closeUploadDialog(); } // 编辑图片 editImage(image: ReferenceImage, event: Event) { event.stopPropagation(); this.editingImage = { ...image }; this.showEditDialog = true; } // 关闭编辑对话框 closeEditDialog() { this.showEditDialog = false; this.editingImage = null; } // 判断分类是否选中 isCategorySelected(category: string): boolean { return this.editingImage?.categories?.includes(category) || false; } // 切换分类 toggleCategory(category: string) { if (!this.editingImage) return; if (!this.editingImage.categories) { this.editingImage.categories = []; } const index = this.editingImage.categories.indexOf(category); if (index > -1) { this.editingImage.categories.splice(index, 1); } else { this.editingImage.categories.push(category); } } // 添加标签 addTag() { if (!this.editingImage || !this.newTag.trim()) return; if (!this.editingImage.tags) { this.editingImage.tags = []; } if (!this.editingImage.tags.includes(this.newTag.trim())) { this.editingImage.tags.push(this.newTag.trim()); } this.newTag = ''; } // 移除标签 removeTag(index: number) { if (this.editingImage?.tags) { this.editingImage.tags.splice(index, 1); } } // 保存编辑 saveEdit() { if (!this.editingImage) return; const index = this.referenceImages.findIndex(img => img.id === this.editingImage!.id); if (index > -1) { this.referenceImages[index] = { ...this.editingImage }; this.filterByCategory(this.activeFilter); this.imagesUpdated.emit(this.referenceImages); } this.closeEditDialog(); } // 删除图片 deleteImage(image: ReferenceImage, event: Event) { event.stopPropagation(); if (confirm(`确定要删除 "${image.name}" 吗?`)) { this.referenceImages = this.referenceImages.filter(img => img.id !== image.id); this.filterByCategory(this.activeFilter); this.imagesUpdated.emit(this.referenceImages); } } // 打开AI助手 openAIAssistant(image: ReferenceImage, event: Event) { event.stopPropagation(); this.aiImage = { ...image }; this.showAIDialog = true; } // 关闭AI对话框 closeAIDialog() { this.showAIDialog = false; this.aiImage = null; this.customQuestion = ''; } // 应用AI建议的问题 applyAIQuestion(question: AIQuestion) { // 这里可以实现将问题发送给客户的逻辑 console.log('应用AI问题:', question); // 如果问题有关联的分类,自动添加到图片分类中 if (question.category && this.aiImage) { if (!this.aiImage.categories) { this.aiImage.categories = []; } if (!this.aiImage.categories.includes(question.category)) { this.aiImage.categories.push(question.category); } } alert(`已将追问发送给客户:\n\n${question.example}`); } // 发送自定义问题 sendCustomQuestion() { if (!this.customQuestion.trim()) { alert('请输入追问内容'); return; } // 这里实现发送自定义问题的逻辑 console.log('发送自定义问题:', this.customQuestion); alert(`已将追问发送给客户:\n\n${this.customQuestion}`); this.customQuestion = ''; } // 应用AI建议并编辑 applyAISuggestionsAndEdit() { if (this.aiImage) { this.closeAIDialog(); this.editImage(this.aiImage, new Event('click')); } } // 预览图片 previewImage(image: ReferenceImage) { this.previewImageUrl = image.url; this.showPreviewDialog = true; } // 关闭预览 closePreviewDialog() { this.showPreviewDialog = false; this.previewImageUrl = ''; } }