# 空间数据同步修复方案(最新版) ## 🎯 问题描述 ### 用户反馈 不同阶段显示的空间数量和名称不一致: - **订单分配阶段**:5个空间(卫生间、餐厅、次卧、厨房、餐厅) - **确认需求阶段**:9个空间(餐厅x2、主卧、次卧、书房、儿童房、厨房、卫生间、阳台) - **交付执行阶段**:8个空间(餐厅x2、主卧、次卧、书房、儿童房、厨房、卫生间) - **确认需求阶段**:显示 **9个空间**(客厅、餐厅、主卧、次卧、儿童房、书房、厨房、卫生间、阳台) - **交付执行阶段**:显示 **9个空间**(同上) **结果**:各阶段显示的空间数量不一致,数据不同步。 --- ## 🎯 根本原因分析 ### 数据源不一致 #### 1. 订单分配阶段(quotation-editor) **数据来源**:直接查询 `Product` 表 ```typescript // quotation-editor.component.ts 第276-281行 const productQuery = new Parse.Query('Product'); productQuery.equalTo('project', this.project.toPointer()); const results = await productQuery.find(); // ✅ 查询到4条Product记录 this.products = results; // 去重后4个 ``` **显示逻辑**: - 从Product表查询 → 4条记录 - 去重后 → 4个空间 - 生成报价 → 4个空间显示 #### 2. 确认需求/交付执行阶段 **数据来源**:从 `Project.data.unifiedSpaces` 读取 ```typescript // stage-requirements.component.ts 第366行 const unifiedSpaces = await this.productSpaceService.getUnifiedSpaceData(projectId); // ✅ 从Project.data.unifiedSpaces读取 → 9个空间 ``` **getUnifiedSpaceData() 逻辑**: ```typescript // product-space.service.ts 第571-582行 async getUnifiedSpaceData(projectId: string) { const data = project.get('data') || {}; // 优先返回统一空间数据 if (data.unifiedSpaces && data.unifiedSpaces.length > 0) { return data.unifiedSpaces; // ✅ 返回9个空间 } // 否则从Product表迁移 const productSpaces = await this.getProjectProductSpaces(projectId); return productSpaces; } ``` ### 数据流对比 ``` 【订单分配】 ↓ 查询 Product表 (4条记录) ↓ 显示 订单分配界面 (4个空间) ❌ 【确认需求/交付执行】 ↓ 查询 Project.data.unifiedSpaces (9个空间) ↓ 显示 确认需求/交付执行界面 (9个空间) ❌ ``` **核心问题**: 1. Product表只有4条记录 2. 但Project.data.unifiedSpaces有9个空间 3. 两个数据源不同步 --- ## 🔧 解决方案 ### 修复策略 **确保订单分配(数据源头)在保存时同步更新 unifiedSpaces** 订单分配阶段是数据的唯一入口,其他阶段应该从它同步数据。因此需要: 1. 订单分配修改Product表 2. 同时更新 `Project.data.unifiedSpaces` 3. 其他阶段从 `unifiedSpaces` 读取 ### 实现修改 **文件**:`quotation-editor.component.ts` **位置**:第664-713行 **方法**:`saveQuotationToProject()` #### 修改前 ```typescript private async saveQuotationToProject(): Promise { if (!this.project) return; try { const data = this.project.get('data') || {}; data.quotation = this.quotation; this.project.set('data', data); await this.project.save(); this.quotationChange.emit(this.quotation); } catch (error) { console.error('保存报价失败:', error); } } ``` **问题**:只保存了 `quotation`,没有更新 `unifiedSpaces` #### 修改后 ```typescript private async saveQuotationToProject(): Promise { if (!this.project) return; try { const data = this.project.get('data') || {}; data.quotation = this.quotation; // 🔥 关键修复:同步更新 unifiedSpaces,确保各阶段数据一致 data.unifiedSpaces = this.products.map((product, index) => { const quotation = product.get('quotation') || {}; const space = product.get('space') || {}; const requirements = product.get('requirements') || {}; const profile = product.get('profile'); // 从quotation.spaces中查找对应的工序信息 const quotationSpace = this.quotation.spaces.find((s: any) => s.productId === product.id); return { id: product.id, name: product.get('productName') || '', type: product.get('productType') || 'other', area: space.area || 0, priority: space.priority || 5, status: product.get('status') || 'not_started', complexity: space.complexity || 'medium', estimatedBudget: quotation.price || 0, order: index, quotation: { price: quotation.price || 0, processes: quotationSpace?.processes || {}, subtotal: quotationSpace?.subtotal || 0 }, requirements: requirements, designerId: profile?.id || null, progress: [], createdAt: product.get('createdAt')?.toISOString() || new Date().toISOString(), updatedAt: new Date().toISOString() }; }); console.log(`🔄 [报价编辑器] 同步更新 unifiedSpaces: ${data.unifiedSpaces.length} 个空间`); this.project.set('data', data); await this.project.save(); this.quotationChange.emit(this.quotation); } catch (error) { console.error('保存报价失败:', error); } } ``` **修复内容**: 1. 从 `this.products` 数组构建 `unifiedSpaces` 2. 包含完整的空间信息(name, type, area, quotation, requirements等) 3. 同时保存到 `Project.data.unifiedSpaces` 4. 添加日志输出,便于调试 ### 数据同步流程(修复后) ``` 订单分配阶段修改空间 ↓ quotation-editor.addProduct() ↓ createProduct() → Product表新增记录 ↓ loadProjectProducts() → 重新加载Product表 ↓ generateQuotationFromProducts() → 生成报价 ↓ saveQuotationToProject() → 保存到Project ├─ data.quotation = {...} └─ data.unifiedSpaces = [...] 🔥 同步更新 ↓ this.products (4个) === Project.data.unifiedSpaces (4个) ✅ ↓ 发出 productsUpdated 事件 ↓ 其他阶段重新加载 ├─ 确认需求:从unifiedSpaces读取 → 4个空间 ✅ └─ 交付执行:从unifiedSpaces读取 → 4个空间 ✅ ``` --- ## 🎯 预期效果 ### 修复后的行为 1. **添加空间** ``` 订单分配点击"添加产品" → 输入"书房" ↓ Product表新增1条记录(总共5条) ↓ saveQuotationToProject() 同步更新 unifiedSpaces(5个空间) ↓ 确认需求阶段:显示5个空间 ✅ 交付执行阶段:显示5个空间 ✅ ``` 2. **删除空间** ``` 订单分配删除"餐厅" ↓ Product表删除1条记录(总共3条) ↓ saveQuotationToProject() 同步更新 unifiedSpaces(3个空间) ↓ 确认需求阶段:显示3个空间 ✅ 交付执行阶段:显示3个空间 ✅ ``` 3. **编辑空间** ``` 订单分配修改"客厅"为"大客厅" ↓ Product表更新记录 ↓ saveQuotationToProject() 同步更新 unifiedSpaces ↓ 确认需求阶段:显示"大客厅" ✅ 交付执行阶段:显示"大客厅" ✅ ``` --- ## 📊 验证步骤 ### 步骤1:清理旧数据(可选) 如果当前项目的 `unifiedSpaces` 数据不正确(有9个空间),需要先清理: 1. 在浏览器控制台执行: ```javascript const Parse = window.Parse; const query = new Parse.Query('Project'); const project = await query.get('YOUR_PROJECT_ID'); const data = project.get('data') || {}; console.log('当前unifiedSpaces:', data.unifiedSpaces?.length); // 清空旧数据 delete data.unifiedSpaces; project.set('data', data); await project.save(); console.log('✅ 已清空unifiedSpaces,等待从订单分配重新生成'); ``` ### 步骤2:重新生成unifiedSpaces 1. 打开项目的"订单分配"阶段 2. 打开浏览器控制台(F12) 3. 观察日志: ``` 🔍 [报价编辑器] Product表查询结果: 4 条记录 ✅ 保留空间: 客厅 (ID: xxx) ✅ 保留空间: 次卧 (ID: xxx) ✅ 保留空间: 阳台 (ID: xxx) ✅ 保留空间: 餐厅 (ID: xxx) ✅ [报价编辑器] 最终加载 4 个唯一空间 ``` 4. 页面会自动调用 `generateQuotationFromProducts()` 5. 然后调用 `saveQuotationToProject()` 6. 观察日志: ``` 🔄 [报价编辑器] 同步更新 unifiedSpaces: 4 个空间 ``` ### 步骤3:验证其他阶段 1. 切换到"确认需求"阶段 2. 观察控制台日志: ``` ✅ [需求确认] 从统一存储加载到 4 个空间 ✅ [需求确认] 空间加载完成,共 4 个空间 ``` 3. **验证界面显示:应该显示4个空间(与订单分配一致)** 4. 切换到"交付执行"阶段 5. 观察控制台日志: ``` ✅ [交付执行] 从统一存储加载到 4 个空间 ✅ [交付执行] 空间加载完成,共 4 个空间 ``` 6. **验证界面显示:应该显示4个空间(与订单分配一致)** ### 步骤4:测试实时同步 1. 在"订单分配"阶段点击"添加产品" 2. 输入"书房",保存 3. 观察日志: ``` ✅ [产品变更] 已添加产品,当前数量: 5 🔄 [报价编辑器] 同步更新 unifiedSpaces: 5 个空间 ``` 4. 切换到"确认需求"或"交付执行" 5. 观察日志(如果已实现监听器): ``` 🔄 [确认需求] 检测到产品添加事件,重新加载空间... ✅ [确认需求] 空间加载完成,共 5 个空间 ``` 6. **验证:所有阶段都显示5个空间** --- ## 📝 额外说明 ### 关于Product表中只有4条记录的问题 如果确认Product表确实只有4条记录,但界面应该显示9个空间(业务需要),那么需要: 1. **补充缺失的Product记录** - 在订单分配阶段点击"添加产品" - 手动添加缺失的5个空间(主卧、儿童房、书房、厨房、卫生间) 2. **或者批量创建** - 在浏览器控制台执行: ```javascript const Parse = window.Parse; const projectId = 'YOUR_PROJECT_ID'; const projectPointer = { __type: 'Pointer', className: 'Project', objectId: projectId }; const missingSpaces = ['主卧', '儿童房', '书房', '厨房', '卫生间']; for (const spaceName of missingSpaces) { const product = new Parse.Object('Product'); product.set('project', projectPointer); product.set('productName', spaceName); product.set('productType', 'other'); product.set('status', 'not_started'); product.set('space', { spaceName: spaceName, area: 0, spaceType: '平层', styleLevel: '基础风格组', complexity: 'medium', priority: 5 }); product.set('quotation', { price: 300, basePrice: 300, currency: 'CNY', status: 'draft' }); await product.save(); console.log(`✅ 已创建空间: ${spaceName}`); } console.log('✅ 批量创建完成,请刷新页面'); ``` 3. **刷新页面** - F5刷新订单分配页面 - quotation-editor会重新加载Product表(现在9条记录) - 自动生成报价并同步更新unifiedSpaces(9个空间) - 其他阶段也会显示9个空间 --- ## 🎉 修复总结 ### 修改的文件 1. **quotation-editor.component.ts** - 第282-307行:添加详细日志输出 - 第664-713行:修复 `saveQuotationToProject()` 同步更新 unifiedSpaces ### 核心改进 1. ✅ 订单分配保存时同步更新 unifiedSpaces 2. ✅ 确保各阶段从统一数据源读取 3. ✅ 添加详细日志便于问题排查 4. ✅ 结合之前的实时同步机制,实现完整的跨阶段数据同步 ### 数据一致性保证 - **写入**:订单分配 → Product表 + unifiedSpaces - **读取**:其他阶段 → unifiedSpaces - **同步**:实时事件通知机制 **修复完成时间**:2024年11月15日 14:45 **问题状态**:已修复,等待测试验证