当项目进入"售后归档"阶段时,系统自动将项目数据转换并添加到Case(案例库)表中,实现项目到案例的无缝转换。
2025-10-29
ProjectService.updateProjectStage()方法从Project表 + Product表 → Case表的完整映射:
company: Project.company           // 企业指针
isDeleted: false                   // 软删除标记(默认false)
name: Project.title                // 案例名称来自项目标题
project: Project.objectId          // 关联原项目
designer: Project.assignee || Project.designer  // 设计师
team: Project.team || Project.department        // 团队
address: Project.address           // 客户地址(可选)
coverImage: images[0]              // 第一张图片作为封面
images: [
  ...Project.data.images,          // 项目图片
  ...Product.attachments[].url     // 产品附件图片
]
totalPrice: Project.totalAmount || Project.orderAmount || Project.data.budget.total
completionDate: new Date()         // 当前时间作为完工时间
tag: [
  ...Project.tags,                 // 项目标签
  Project.style                    // 风格
]
isPublished: false                 // 默认不发布,需要审核
isExcellent: false                 // 默认非优秀案例
index: 0                          // 默认排序
info: {
  area: Project.data.area || Project.area || 100,
  projectType: Project.data.projectType || "家装",
  roomType: Project.data.roomType || "三居室",
  spaceType: Project.data.spaceType || "平层",
  renderingLevel: Project.data.renderingLevel || "中端"
}
data: {
  // 装修规格信息
  renovationSpec: {
    roomAreas: Project.data.specMap.roomAreas,
    renovationType: Project.data.renovationType,
    renovationScope: Project.data.specMap.renovationScope,
    constructionItems: Project.data.specMap.constructionItems
  },
  
  // 产品详细信息
  productsDetail: Product[].map(p => ({
    productId: p.id,
    productName: p.name,
    category: p.category,
    brand: p.brand,
    quantity: p.quantity,
    unitPrice: p.price,
    totalPrice: p.quantity * p.price,
    spaceArea: p.spaceArea,
    specifications: p.specifications
  })),
  
  // 预算信息
  budget: Project.data.budget,
  
  // 时间线信息
  timeline: Project.data.timeline,
  
  // 设计亮点
  highlights: Project.data.highlights,
  
  // 设计特色
  features: Project.data.features,
  
  // 设计挑战
  challenges: Project.data.challenges,
  
  // 材料信息
  materials: Project.data.materials,
  
  // 客户信息
  clientInfo: Project.data.clientInfo,
  
  // 图片详细信息
  imagesDetail: {
    beforeRenovation: [],
    afterRenovation: Product.attachments[],
    videos: Product.attachments[type='video'],
    panoramas: Product.attachments[type='panorama']
  }
}
文件: yss-project/src/app/services/project-to-case.service.ts
核心方法:
onProjectStageChanged(projectId, newStage) - 监听阶段变化createCaseFromProject(projectId) - 从项目创建案例checkCaseExists(projectId) - 检查是否已创建过案例文件: yss-project/src/app/services/project.service.ts
修改内容:
import { ProjectToCaseService } from './project-to-case.service';
constructor(private projectToCaseService: ProjectToCaseService) {}
.then(savedProject => {
  console.log(`✅ 项目阶段已更新并保存到数据库: ${stage}`);
  
  // 🎯 如果进入"售后归档"阶段,自动创建案例
  if (stage === '售后归档') {
    this.projectToCaseService.onProjectStageChanged(projectId, stage)
      .then(() => {
        console.log('✅ 项目已自动添加到案例库');
      })
      .catch(err => {
        console.error('❌ 自动创建案例失败:', err);
      });
  }
  
  observer.next(project);
  observer.complete();
})
用户操作:项目推进到"售后归档"阶段
   ↓
ProjectService.updateProjectStage('售后归档')
   ↓
保存阶段到Parse数据库
   - Project.currentStage = '售后归档'
   - Project.stage = '售后归档'
   - Project.status = '已完成'
   ↓
触发自动创建案例逻辑
   ↓
ProjectToCaseService.onProjectStageChanged()
   ↓
检查是否已创建过案例
   - Query Case表 where project = projectId
   ↓
如果未创建,执行创建
   ↓
获取项目数据
   - Query Project表 include(assignee, designer, team, customer, address)
   ↓
获取产品数据
   - Query Product表 where project = projectId include(attachments)
   ↓
提取并映射数据
   - 基础信息
   - 关联关系
   - 媒体资源(图片、视频)
   - 数值信息(价格)
   - 标签分类
   - info对象(必填字段)
   - data对象(扩展字段)
   ↓
创建Case对象并保存
   - const caseObj = new CaseClass()
   - caseObj.set(...)
   - await caseObj.save()
   ↓
控制台输出
   ✅ 案例创建成功: caseId
   ✅ 项目已自动添加到案例库
   ↓
案例库自动显示新案例
   - 访问 @case-library/ 即可看到
const query = new Parse.Query('Case');
query.equalTo('company', companyPointer);
query.equalTo('project', projectPointer);
query.notEqualTo('isDeleted', true);
const cases = await query.find();
const query = new Parse.Query('Case');
query.equalTo('company', companyPointer);
query.equalTo('isPublished', true);
query.notEqualTo('isDeleted', true);
query.descending('createdAt');
const cases = await query.find();
const query = new Parse.Query('Case');
query.equalTo('company', companyPointer);
query.containsAll('tag', ['现代简约', '北欧风']);
query.notEqualTo('isDeleted', true);
const cases = await query.find();
案例库页面(@case-library/)已经实现了完整的显示逻辑:
创建案例时会验证以下必填字段:
✅ name: 案例名称(来自项目标题)
✅ project: 关联项目指针
✅ designer: 设计师指针
✅ team: 团队指针
✅ coverImage: 封面图片
✅ images: 图片数组(至少1张)
✅ totalPrice: 总价
✅ completionDate: 完工时间
✅ tag: 标签数组(至少1个)
✅ info.area: 面积
✅ info.projectType: 项目类型
✅ info.roomType: 户型
✅ info.spaceType: 空间类型
✅ info.renderingLevel: 渲染水平
如果某些字段缺失,使用默认值:
area: projectData.area || project.get('area') || 100
projectType: projectData.projectType || '家装'
roomType: projectData.roomType || '三居室'
spaceType: projectData.spaceType || '平层'
renderingLevel: projectData.renderingLevel || '中端'
if (!project) {
  throw new Error('项目不存在');
}
if (!designer) {
  throw new Error('项目缺少设计师信息');
}
if (!team) {
  throw new Error('项目缺少团队信息');
}
const existingCase = await this.checkCaseExists(projectId);
if (existingCase) {
  console.log('项目已有关联案例,跳过创建');
  return;
}
this.projectToCaseService.onProjectStageChanged(projectId, stage)
  .catch(err => {
    console.error('❌ 自动创建案例失败:', err);
    // 不阻塞主流程,仅记录错误
  });
步骤:
预期结果:
✅ 项目阶段已更新并保存到数据库: 售后归档📦 项目 xxx 进入售后归档阶段,准备创建案例...✅ 案例创建成功: caseId✅ 项目已自动添加到案例库步骤:
预期结果:
⚠️ 项目 xxx 已有关联案例,跳过创建步骤:
预期结果:
❌ 创建案例失败: 项目缺少设计师信息步骤:
预期结果:
images字段包含所有产品的附件图片coverImagedata.imagesDetail正确分类图片(装修前/后、视频、全景)访问:http://localhost:4200/customer-service/case-library
案例卡片
详情面板
筛选功能
reviewStatus: '待审核' | '已通过' | '已拒绝'company字段实现多租户隔离isDeleted字段实现软删除isPublished控制案例是否对外显示yss-project/src/app/services/project-to-case.service.tsyss-project/src/app/services/project.service.tsyss-project/src/app/services/case.service.ts - 案例CRUD服务yss-project/src/app/pages/customer-service/case-library/case-library.ts - 案例库页面yss-project/src/app/pages/customer-service/case-library/case-library.html - 案例库模板