|
@@ -431,13 +431,33 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
'requirements', // stage参数
|
|
'requirements', // stage参数
|
|
|
{
|
|
{
|
|
|
imageType: 'style',
|
|
imageType: 'style',
|
|
|
- uploadedFor: 'requirements_analysis'
|
|
|
|
|
|
|
+ uploadedFor: 'requirements_analysis',
|
|
|
|
|
+ // 补充:添加关联空间ID和交付类型标识
|
|
|
|
|
+ spaceId: targetProductId,
|
|
|
|
|
+ deliveryType: 'requirements_reference', // 需求阶段参考图片
|
|
|
|
|
+ uploadStage: 'requirements'
|
|
|
},
|
|
},
|
|
|
(progress) => {
|
|
(progress) => {
|
|
|
console.log(`上传进度: ${progress}%`);
|
|
console.log(`上传进度: ${progress}%`);
|
|
|
}
|
|
}
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+ // 补充:为ProjectFile添加扩展数据字段
|
|
|
|
|
+ const existingData = projectFile.get('data') || {};
|
|
|
|
|
+ projectFile.set('data', {
|
|
|
|
|
+ ...existingData,
|
|
|
|
|
+ spaceId: targetProductId,
|
|
|
|
|
+ deliveryType: 'requirements_reference',
|
|
|
|
|
+ uploadedFor: 'requirements_analysis',
|
|
|
|
|
+ analysis: {
|
|
|
|
|
+ // 预留AI分析结果字段
|
|
|
|
|
+ ai: null,
|
|
|
|
|
+ manual: null,
|
|
|
|
|
+ lastAnalyzedAt: null
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ await projectFile.save();
|
|
|
|
|
+
|
|
|
// 创建参考图片记录
|
|
// 创建参考图片记录
|
|
|
const uploadedFile = {
|
|
const uploadedFile = {
|
|
|
id: projectFile.id || '',
|
|
id: projectFile.id || '',
|
|
@@ -573,13 +593,38 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
'requirements', // stage参数
|
|
'requirements', // stage参数
|
|
|
{
|
|
{
|
|
|
cadFormat: fileExtension.replace('.', ''),
|
|
cadFormat: fileExtension.replace('.', ''),
|
|
|
- uploadedFor: 'requirements_analysis'
|
|
|
|
|
|
|
+ uploadedFor: 'requirements_analysis',
|
|
|
|
|
+ // 补充:添加关联空间ID和交付类型标识
|
|
|
|
|
+ spaceId: targetProductId,
|
|
|
|
|
+ deliveryType: 'requirements_cad',
|
|
|
|
|
+ uploadStage: 'requirements'
|
|
|
},
|
|
},
|
|
|
(progress) => {
|
|
(progress) => {
|
|
|
console.log(`上传进度: ${progress}%`);
|
|
console.log(`上传进度: ${progress}%`);
|
|
|
}
|
|
}
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+ // 补充:为CAD文件ProjectFile添加扩展数据字段
|
|
|
|
|
+ const existingData = projectFile.get('data') || {};
|
|
|
|
|
+ projectFile.set('data', {
|
|
|
|
|
+ ...existingData,
|
|
|
|
|
+ spaceId: targetProductId,
|
|
|
|
|
+ deliveryType: 'requirements_cad',
|
|
|
|
|
+ uploadedFor: 'requirements_analysis',
|
|
|
|
|
+ cadFormat: fileExtension.replace('.', ''),
|
|
|
|
|
+ analysis: {
|
|
|
|
|
+ // 预留CAD分析结果字段
|
|
|
|
|
+ ai: null,
|
|
|
|
|
+ manual: null,
|
|
|
|
|
+ lastAnalyzedAt: null,
|
|
|
|
|
+ spaceStructure: null,
|
|
|
|
|
+ dimensions: null,
|
|
|
|
|
+ constraints: [],
|
|
|
|
|
+ opportunities: []
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ await projectFile.save();
|
|
|
|
|
+
|
|
|
// 创建CAD文件记录
|
|
// 创建CAD文件记录
|
|
|
const uploadedFile = {
|
|
const uploadedFile = {
|
|
|
id: projectFile.id || '',
|
|
id: projectFile.id || '',
|
|
@@ -754,25 +799,40 @@ export class StageRequirementsComponent implements OnInit {
|
|
|
*/
|
|
*/
|
|
|
private async saveImageAnalysisToProjectFile(projectFile: any, analysisResult: any): Promise<void> {
|
|
private async saveImageAnalysisToProjectFile(projectFile: any, analysisResult: any): Promise<void> {
|
|
|
try {
|
|
try {
|
|
|
- // 获取现有的analysis对象
|
|
|
|
|
- const currentAnalysis = projectFile.get('analysis') || {};
|
|
|
|
|
|
|
+ // 补充:更新ProjectFile.data.analysis.ai字段(与现有analysis字段并存)
|
|
|
|
|
+ const existingData = projectFile.get('data') || {};
|
|
|
|
|
+ const existingAnalysis = existingData.analysis || {};
|
|
|
|
|
+
|
|
|
|
|
+ // 保存AI分析结果到data.analysis.ai字段
|
|
|
|
|
+ existingAnalysis.ai = {
|
|
|
|
|
+ ...analysisResult,
|
|
|
|
|
+ analyzedAt: new Date().toISOString(),
|
|
|
|
|
+ version: '1.0',
|
|
|
|
|
+ source: 'image_analysis'
|
|
|
|
|
+ };
|
|
|
|
|
+ existingAnalysis.lastAnalyzedAt = new Date().toISOString();
|
|
|
|
|
+
|
|
|
|
|
+ existingData.analysis = existingAnalysis;
|
|
|
|
|
+ projectFile.set('data', existingData);
|
|
|
|
|
|
|
|
- // 保存AI分析结果到analysis.ai字段
|
|
|
|
|
|
|
+ // 兼容:同时保存到原有的analysis字段
|
|
|
|
|
+ const currentAnalysis = projectFile.get('analysis') || {};
|
|
|
currentAnalysis.ai = {
|
|
currentAnalysis.ai = {
|
|
|
...analysisResult,
|
|
...analysisResult,
|
|
|
analyzedAt: new Date().toISOString(),
|
|
analyzedAt: new Date().toISOString(),
|
|
|
version: '1.0',
|
|
version: '1.0',
|
|
|
source: 'image_analysis'
|
|
source: 'image_analysis'
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
- // 更新ProjectFile
|
|
|
|
|
projectFile.set('analysis', currentAnalysis);
|
|
projectFile.set('analysis', currentAnalysis);
|
|
|
|
|
+
|
|
|
|
|
+ // 确保关联Product
|
|
|
if(!projectFile?.get("product")?.id && projectFile?.get("data")?.spaceId){
|
|
if(!projectFile?.get("product")?.id && projectFile?.get("data")?.spaceId){
|
|
|
projectFile.set("product",{__type:"Pointer",className:"Product",objectId:projectFile?.get("data")?.spaceId})
|
|
projectFile.set("product",{__type:"Pointer",className:"Product",objectId:projectFile?.get("data")?.spaceId})
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
await projectFile.save();
|
|
await projectFile.save();
|
|
|
|
|
|
|
|
- console.log('图片分析结果已保存到ProjectFile.analysis.ai');
|
|
|
|
|
|
|
+ console.log('图片分析结果已保存到ProjectFile.data.analysis.ai和ProjectFile.analysis.ai');
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('保存分析结果失败:', error);
|
|
console.error('保存分析结果失败:', error);
|
|
|
}
|
|
}
|
|
@@ -1365,6 +1425,107 @@ ${context}
|
|
|
data.requirementsConfirmedByName = this.currentUser.get('name');
|
|
data.requirementsConfirmedByName = this.currentUser.get('name');
|
|
|
data.requirementsConfirmedAt = new Date().toISOString();
|
|
data.requirementsConfirmedAt = new Date().toISOString();
|
|
|
|
|
|
|
|
|
|
+ // 补充:需求确认详细信息
|
|
|
|
|
+ data.requirementsDetail = {
|
|
|
|
|
+ globalRequirements: this.globalRequirements,
|
|
|
|
|
+ spaceRequirements: this.spaceRequirements,
|
|
|
|
|
+ crossSpaceRequirements: this.crossSpaceRequirements,
|
|
|
|
|
+ referenceImages: this.referenceImages.map(img => ({
|
|
|
|
|
+ id: img.id,
|
|
|
|
|
+ url: img.url,
|
|
|
|
|
+ name: img.name,
|
|
|
|
|
+ type: img.type,
|
|
|
|
|
+ spaceId: img.spaceId,
|
|
|
|
|
+ tags: img.tags
|
|
|
|
|
+ })),
|
|
|
|
|
+ cadFiles: this.cadFiles.map(file => ({
|
|
|
|
|
+ id: file.id,
|
|
|
|
|
+ url: file.url,
|
|
|
|
|
+ name: file.name,
|
|
|
|
|
+ size: file.size,
|
|
|
|
|
+ spaceId: file.spaceId
|
|
|
|
|
+ })),
|
|
|
|
|
+ aiAnalysisResults: this.aiAnalysisResults,
|
|
|
|
|
+ confirmedAt: new Date().toISOString()
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 补充:初始化阶段截止时间 (基于项目交付日期推算)
|
|
|
|
|
+ if (!data.phaseDeadlines && this.project.get('deadline')) {
|
|
|
|
|
+ const deliveryDate = new Date(this.project.get('deadline'));
|
|
|
|
|
+ const startDate = new Date();
|
|
|
|
|
+ const totalDays = Math.ceil((deliveryDate.getTime() - startDate.getTime()) / (24 * 60 * 60 * 1000));
|
|
|
|
|
+
|
|
|
|
|
+ // 按比例分配各阶段时间:建模30%,软装25%,渲染30%,后期15%
|
|
|
|
|
+ const modelingDays = Math.ceil(totalDays * 0.3);
|
|
|
|
|
+ const softDecorDays = Math.ceil(totalDays * 0.25);
|
|
|
|
|
+ const renderingDays = Math.ceil(totalDays * 0.3);
|
|
|
|
|
+ const postProcessDays = totalDays - modelingDays - softDecorDays - renderingDays;
|
|
|
|
|
+
|
|
|
|
|
+ let currentDate = new Date(startDate);
|
|
|
|
|
+
|
|
|
|
|
+ data.phaseDeadlines = {
|
|
|
|
|
+ modeling: {
|
|
|
|
|
+ startDate: new Date(currentDate),
|
|
|
|
|
+ deadline: new Date(currentDate.setDate(currentDate.getDate() + modelingDays)),
|
|
|
|
|
+ estimatedDays: modelingDays,
|
|
|
|
|
+ status: 'not_started',
|
|
|
|
|
+ priority: 'high'
|
|
|
|
|
+ },
|
|
|
|
|
+ softDecor: {
|
|
|
|
|
+ startDate: new Date(currentDate),
|
|
|
|
|
+ deadline: new Date(currentDate.setDate(currentDate.getDate() + softDecorDays)),
|
|
|
|
|
+ estimatedDays: softDecorDays,
|
|
|
|
|
+ status: 'not_started',
|
|
|
|
|
+ priority: 'medium'
|
|
|
|
|
+ },
|
|
|
|
|
+ rendering: {
|
|
|
|
|
+ startDate: new Date(currentDate),
|
|
|
|
|
+ deadline: new Date(currentDate.setDate(currentDate.getDate() + renderingDays)),
|
|
|
|
|
+ estimatedDays: renderingDays,
|
|
|
|
|
+ status: 'not_started',
|
|
|
|
|
+ priority: 'high'
|
|
|
|
|
+ },
|
|
|
|
|
+ postProcessing: {
|
|
|
|
|
+ startDate: new Date(currentDate),
|
|
|
|
|
+ deadline: new Date(currentDate.setDate(currentDate.getDate() + postProcessDays)),
|
|
|
|
|
+ estimatedDays: postProcessDays,
|
|
|
|
|
+ status: 'not_started',
|
|
|
|
|
+ priority: 'medium'
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 补充:初始化空间交付物汇总
|
|
|
|
|
+ if (!data.spaceDeliverableSummary && this.projectProducts.length > 0) {
|
|
|
|
|
+ data.spaceDeliverableSummary = {};
|
|
|
|
|
+ let totalDeliverables = 0;
|
|
|
|
|
+ let completedDeliverables = 0;
|
|
|
|
|
+
|
|
|
|
|
+ this.projectProducts.forEach(product => {
|
|
|
|
|
+ const productSummary = {
|
|
|
|
|
+ spaceName: product.name,
|
|
|
|
|
+ totalDeliverables: 4, // 白模、软装、渲染、后期各1个
|
|
|
|
|
+ completedDeliverables: 0,
|
|
|
|
|
+ completionRate: 0,
|
|
|
|
|
+ lastUpdateTime: new Date().toISOString(),
|
|
|
|
|
+ phaseProgress: {
|
|
|
|
|
+ white_model: 0,
|
|
|
|
|
+ soft_decor: 0,
|
|
|
|
|
+ rendering: 0,
|
|
|
|
|
+ post_process: 0
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ data.spaceDeliverableSummary[product.id] = productSummary;
|
|
|
|
|
+ totalDeliverables += productSummary.totalDeliverables;
|
|
|
|
|
+ completedDeliverables += productSummary.completedDeliverables;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ data.spaceDeliverableSummary.overallCompletionRate = totalDeliverables > 0
|
|
|
|
|
+ ? Math.round((completedDeliverables / totalDeliverables) * 100)
|
|
|
|
|
+ : 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 派发阶段完成事件,通知父组件前进
|
|
// 派发阶段完成事件,通知父组件前进
|
|
|
console.log('📡 [确认需求] 派发 stage:completed 事件');
|
|
console.log('📡 [确认需求] 派发 stage:completed 事件');
|
|
|
try {
|
|
try {
|