在报价页面中发现存在重复的空间报价条目,例如:
这导致页面显示混乱,报价计算不准确。
Product表中可能存在同名空间的重复记录位置: quotation-editor.component.ts - generateQuotationFromProducts() 方法
改进内容:
Map 数据结构确保同名空间只保留第一个在控制台输出详细的去重日志
// 使用 Map 去重,key 为空间名称,value 为空间数据
const spaceMap = new Map<string, any>();
const duplicateProductIds: string[] = [];
for (const product of this.products) {
const productName = product.get('productName');
  
// 如果该空间名称已存在,记录重复的产品ID
if (spaceMap.has(productName)) {
console.log(`⚠️ 检测到重复空间: ${productName} (产品ID: ${product.id})`);
duplicateProductIds.push(product.id);
continue;
}
// ... 处理唯一空间
}
// 如果检测到重复产品,提示用户清理
if (duplicateProductIds.length > 0) {
console.warn(`⚠️ 检测到 ${duplicateProductIds.length} 个重复产品,建议清理`);
if (this.canEdit && await window?.fmode?.confirm(`检测到 ${duplicateProductIds.length} 个重复空间产品,是否自动清理?`)) {
await this.removeDuplicateProducts(duplicateProductIds);
return; // 清理后重新生成报价
}
}
方法: removeDuplicateProducts(productIds: string[])
功能:
提供详细的操作日志
async removeDuplicateProducts(productIds: string[]): Promise<void> {
console.log(`🗑️ 开始清理 ${productIds.length} 个重复产品...`);
  
// 批量删除重复产品
for (const productId of productIds) {
const product = this.products.find(p => p.id === productId);
if (product) {
  await product.destroy();
  console.log(`  ✓ 已删除: ${product.get('productName')} (${productId})`);
}
}
// 重新加载产品列表并生成报价
await this.loadProjectProducts();
await this.generateQuotationFromProducts();
  
console.log('✅ 重复产品清理完成');
}
方法: cleanupDuplicateProducts()
功能:
用户确认后执行清理操作
async cleanupDuplicateProducts(): Promise<void> {
// 使用 Map 检测重复
const productNameMap = new Map<string, any[]>();
  
for (const product of this.products) {
const productName = product.get('productName');
if (!productNameMap.has(productName)) {
  productNameMap.set(productName, []);
}
productNameMap.get(productName)!.push(product);
}
// 找出所有重复的产品
const duplicateProductIds: string[] = [];
const duplicateNames: string[] = [];
  
for (const [name, products] of productNameMap.entries()) {
if (products.length > 1) {
  duplicateNames.push(name);
  // 保留第一个,删除其余的
  for (let i = 1; i < products.length; i++) {
    duplicateProductIds.push(products[i].id);
  }
}
}
if (duplicateProductIds.length === 0) {
window?.fmode?.alert('没有检测到重复产品');
return;
}
const message = `检测到以下空间存在重复:\n${duplicateNames.join('、')}\n\n共 ${duplicateProductIds.length} 个重复产品,是否清理?`;
  
if (await window?.fmode?.confirm(message)) {
await this.removeDuplicateProducts(duplicateProductIds);
}
}
位置: quotation-editor.component.html
在产品管理工具栏添加"清理重复"按钮:
<button class="btn-outline" (click)="cleanupDuplicateProducts()" title="清理重复产品">
  <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
    <path fill="currentColor" d="..."/>
  </svg>
  清理重复
</button>
productName 字段作为唯一标识加载产品列表 
  → 检测重复 
  → 提示用户 
  → 删除重复记录 
  → 重新加载 
  → 生成唯一报价
系统会在控制台输出详细日志,方便调试:
⚠️ 检测到重复空间: 发现重复时🗑️ 开始清理: 开始删除操作✓ 已删除: 每个产品删除成功✅ 报价空间生成完成: 显示最终的唯一空间数量本次修复完全保留了原有的UI样式:
功能测试:
边界测试:
数据验证:
canEdit = true)的用户才能看到清理按钮src/modules/project/components/quotation-editor.component.ts - 核心逻辑src/modules/project/components/quotation-editor.component.html - UI界面src/modules/project/components/quotation-editor.component.scss - 样式(无改动)