|
@@ -3,9 +3,17 @@ import { CommonModule } from '@angular/common';
|
|
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
|
import { ActivatedRoute } from '@angular/router';
|
|
|
import { IonIcon } from '@ionic/angular/standalone';
|
|
|
+import { MatDialog } from '@angular/material/dialog';
|
|
|
import { ProductSpaceService, Project } from '../../../services/product-space.service';
|
|
|
+import { ProjectFileService } from '../../../services/project-file.service';
|
|
|
+import { ColorGetDialogComponent } from '../../../components/color-get/color-get-dialog.component';
|
|
|
import { completionJSON } from 'fmode-ng/core';
|
|
|
+import { addIcons } from 'ionicons';
|
|
|
+import { add, colorPalette, sparkles, trash } from 'ionicons/icons';
|
|
|
|
|
|
+addIcons({
|
|
|
+ add,sparkles,colorPalette,trash
|
|
|
+})
|
|
|
/**
|
|
|
* 确认需求阶段组件 - Product表统一空间管理
|
|
|
*/
|
|
@@ -13,6 +21,7 @@ import { completionJSON } from 'fmode-ng/core';
|
|
|
selector: 'app-stage-requirements',
|
|
|
standalone: true,
|
|
|
imports: [CommonModule, FormsModule, ReactiveFormsModule, IonIcon],
|
|
|
+ providers: [],
|
|
|
templateUrl: './stage-requirements.component.html',
|
|
|
styleUrls: ['./stage-requirements.component.scss'],
|
|
|
changeDetection: ChangeDetectionStrategy.OnPush
|
|
@@ -76,6 +85,7 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
description?: string;
|
|
|
spaceId?: string;
|
|
|
tags: string[];
|
|
|
+ projectFile?: any; // ProjectFile对象引用
|
|
|
}> = [];
|
|
|
|
|
|
// CAD文件
|
|
@@ -86,6 +96,7 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
uploadTime: Date;
|
|
|
size: number;
|
|
|
spaceId?: string;
|
|
|
+ projectFile?: any; // ProjectFile对象引用
|
|
|
}> = [];
|
|
|
|
|
|
// AI生成的方案
|
|
@@ -182,7 +193,9 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
constructor(
|
|
|
private route: ActivatedRoute,
|
|
|
private cdr: ChangeDetectorRef,
|
|
|
- private productSpaceService: ProductSpaceService
|
|
|
+ private productSpaceService: ProductSpaceService,
|
|
|
+ private projectFileService: ProjectFileService,
|
|
|
+ private dialog: MatDialog
|
|
|
) {}
|
|
|
|
|
|
async ngOnInit() {
|
|
@@ -294,7 +307,7 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 上传参考图片
|
|
|
+ * 上传参考图片 - 使用ProjectFileService实际存储
|
|
|
*/
|
|
|
async uploadReferenceImage(event: any, productId?: string): Promise<void> {
|
|
|
const files = event.target.files;
|
|
@@ -302,42 +315,69 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
|
|
|
try {
|
|
|
this.uploading = true;
|
|
|
+ const targetProductId = productId || this.activeProductId;
|
|
|
+ const targetProjectId = this.projectId || this.project?.id;
|
|
|
+
|
|
|
+ if (!targetProjectId) {
|
|
|
+ console.error('未找到项目ID,无法上传文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
for (let i = 0; i < files.length; i++) {
|
|
|
const file = files[i];
|
|
|
|
|
|
- // 简单的文件类型验证
|
|
|
+ // 文件类型验证
|
|
|
if (!file.type.startsWith('image/')) {
|
|
|
console.warn(`文件 ${file.name} 不是图片格式,跳过`);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- // 验证文件大小 (10MB)
|
|
|
+ // 文件大小验证 (10MB)
|
|
|
if (file.size > 10 * 1024 * 1024) {
|
|
|
console.warn(`文件 ${file.name} 超过10MB限制,跳过`);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- // 模拟文件上传
|
|
|
+ // 使用ProjectFileService上传到服务器
|
|
|
+ const projectFile = await this.projectFileService.uploadProjectFileWithRecord(
|
|
|
+ file,
|
|
|
+ targetProjectId,
|
|
|
+ 'reference_image',
|
|
|
+ targetProductId,
|
|
|
+ 'requirements', // stage参数
|
|
|
+ {
|
|
|
+ imageType: 'style',
|
|
|
+ uploadedFor: 'requirements_analysis'
|
|
|
+ },
|
|
|
+ (progress) => {
|
|
|
+ console.log(`上传进度: ${progress}%`);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // 创建参考图片记录
|
|
|
const uploadedFile = {
|
|
|
- id: `img_${Date.now()}_${i}`,
|
|
|
- url: URL.createObjectURL(file),
|
|
|
- name: file.name,
|
|
|
+ id: projectFile.id || '',
|
|
|
+ url: projectFile.get('fileUrl') || '',
|
|
|
+ name: projectFile.get('fileName') || file.name,
|
|
|
type: 'style',
|
|
|
- uploadTime: new Date(),
|
|
|
- spaceId: productId || this.activeProductId, // 保持兼容性,后续可改为productId
|
|
|
- tags: []
|
|
|
+ uploadTime: projectFile.createdAt || new Date(),
|
|
|
+ spaceId: targetProductId,
|
|
|
+ tags: [],
|
|
|
+ projectFile: projectFile // 保存ProjectFile对象引用
|
|
|
};
|
|
|
|
|
|
// 添加到参考图片列表
|
|
|
- this.analysisImageMap[uploadedFile?.id] = uploadedFile
|
|
|
- this.referenceImages.push(uploadedFile);
|
|
|
+ if (uploadedFile.id) {
|
|
|
+ this.analysisImageMap[uploadedFile.id] = uploadedFile;
|
|
|
+ this.referenceImages.push(uploadedFile);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
this.cdr.markForCheck();
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('上传失败:', error);
|
|
|
+ alert('文件上传失败,请重试');
|
|
|
} finally {
|
|
|
this.uploading = false;
|
|
|
}
|
|
@@ -345,21 +385,69 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
|
|
|
analysisImageMap:any = {}
|
|
|
/**
|
|
|
- * 删除参考图片
|
|
|
+ * 删除参考图片 - 同时删除服务器文件
|
|
|
*/
|
|
|
async deleteReferenceImage(imageId: string): Promise<void> {
|
|
|
try {
|
|
|
+ // 查找图片记录
|
|
|
+ const image = this.referenceImages.find(img => img.id === imageId);
|
|
|
+
|
|
|
+ if (image && image.projectFile) {
|
|
|
+ // 使用ProjectFileService删除服务器上的文件
|
|
|
+ await this.projectFileService.deleteProjectFile(imageId);
|
|
|
+ }
|
|
|
+
|
|
|
// 从列表中移除
|
|
|
this.referenceImages = this.referenceImages.filter(img => img.id !== imageId);
|
|
|
+ delete this.analysisImageMap[imageId];
|
|
|
+
|
|
|
this.cdr.markForCheck();
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('删除参考图片失败:', error);
|
|
|
+ alert('删除文件失败,请重试');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 上传CAD文件
|
|
|
+ * 查看图片色彩分析 - 打开ColorGetDialog
|
|
|
+ */
|
|
|
+ async viewImageColorAnalysis(imageId: string): Promise<void> {
|
|
|
+ const image = this.referenceImages.find(img => img.id === imageId);
|
|
|
+ if (!image) {
|
|
|
+ console.error('未找到图片记录');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 打开色彩分析对话框
|
|
|
+ const dialogRef = this.dialog.open(ColorGetDialogComponent, {
|
|
|
+ width: '90vw',
|
|
|
+ maxWidth: '800px',
|
|
|
+ height: 'auto',
|
|
|
+ maxHeight: '90vh',
|
|
|
+ data: {
|
|
|
+ fileId: image.id,
|
|
|
+ fileObject: image.projectFile,
|
|
|
+ url: image.url,
|
|
|
+ name: image.name
|
|
|
+ },
|
|
|
+ panelClass: 'color-analysis-dialog'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 对话框关闭后,刷新分析结果
|
|
|
+ dialogRef.afterClosed().subscribe(result => {
|
|
|
+ console.log('色彩分析对话框已关闭', result);
|
|
|
+ this.cdr.markForCheck();
|
|
|
+ });
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('打开色彩分析对话框失败:', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 上传CAD文件 - 使用ProjectFileService实际存储
|
|
|
*/
|
|
|
async uploadCAD(event: any, productId?: string): Promise<void> {
|
|
|
const files = event.target.files;
|
|
@@ -367,6 +455,13 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
|
|
|
try {
|
|
|
this.uploading = true;
|
|
|
+ const targetProductId = productId || this.activeProductId;
|
|
|
+ const targetProjectId = this.projectId || this.project?.id;
|
|
|
+
|
|
|
+ if (!targetProjectId) {
|
|
|
+ console.error('未找到项目ID,无法上传文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
for (let i = 0; i < files.length; i++) {
|
|
|
const file = files[i];
|
|
@@ -385,40 +480,72 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- // 模拟文件上传
|
|
|
+ // 使用ProjectFileService上传到服务器
|
|
|
+ const projectFile = await this.projectFileService.uploadProjectFileWithRecord(
|
|
|
+ file,
|
|
|
+ targetProjectId,
|
|
|
+ 'cad_drawing',
|
|
|
+ targetProductId,
|
|
|
+ 'requirements', // stage参数
|
|
|
+ {
|
|
|
+ cadFormat: fileExtension.replace('.', ''),
|
|
|
+ uploadedFor: 'requirements_analysis'
|
|
|
+ },
|
|
|
+ (progress) => {
|
|
|
+ console.log(`上传进度: ${progress}%`);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ // 创建CAD文件记录
|
|
|
const uploadedFile = {
|
|
|
- id: `cad_${Date.now()}_${i}`,
|
|
|
- url: URL.createObjectURL(file),
|
|
|
- name: file.name,
|
|
|
- uploadTime: new Date(),
|
|
|
- size: file.size,
|
|
|
- spaceId: productId || this.activeProductId // 保持兼容性,后续可改为productId
|
|
|
+ id: projectFile.id || '',
|
|
|
+ url: projectFile.get('fileUrl') || '',
|
|
|
+ name: projectFile.get('fileName') || file.name,
|
|
|
+ uploadTime: projectFile.createdAt || new Date(),
|
|
|
+ size: projectFile.get('fileSize') || file.size,
|
|
|
+ spaceId: targetProductId,
|
|
|
+ projectFile: projectFile // 保存ProjectFile对象引用
|
|
|
};
|
|
|
|
|
|
// 添加到CAD文件列表
|
|
|
- this.cadFiles.push(uploadedFile);
|
|
|
+ if (uploadedFile.id) {
|
|
|
+ this.analysisFileMap[uploadedFile.id] = uploadedFile;
|
|
|
+ this.cadFiles.push(uploadedFile);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
this.cdr.markForCheck();
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('上传失败:', error);
|
|
|
+ alert('文件上传失败,请重试');
|
|
|
} finally {
|
|
|
this.uploading = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 删除CAD文件
|
|
|
+ * 删除CAD文件 - 同时删除服务器文件
|
|
|
*/
|
|
|
async deleteCAD(fileId: string): Promise<void> {
|
|
|
try {
|
|
|
+ // 查找文件记录
|
|
|
+ const file = this.cadFiles.find(f => f.id === fileId);
|
|
|
+
|
|
|
+ if (file && file.projectFile) {
|
|
|
+ // 使用ProjectFileService删除服务器上的文件
|
|
|
+ await this.projectFileService.deleteProjectFile(fileId);
|
|
|
+ }
|
|
|
+
|
|
|
// 从列表中移除
|
|
|
- this.cadFiles = this.cadFiles.filter(file => file.id !== fileId);
|
|
|
+ this.cadFiles = this.cadFiles.filter(f => f.id !== fileId);
|
|
|
+ delete this.analysisFileMap[fileId];
|
|
|
+
|
|
|
this.cdr.markForCheck();
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('删除CAD文件失败:', error);
|
|
|
+ alert('删除文件失败,请重试');
|
|
|
}
|
|
|
}
|
|
|
|