123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- 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<ReferenceImage[]>();
- // 视图状态
- 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 = '';
- }
- }
|