project-database-structure.md 8.0 KB

项目数据库结构说明 - 停滞期和改图期字段

📊 数据存储位置

✅ 正确的存储位置

停滞期和改图期的数据保存在 Parse 数据库的 Project 表的 data 字段中:

Project 表
├── id (字符串)
├── title (字符串) - 项目标题
├── currentStage (字符串) - 当前阶段(如"订单分配"、"确认需求"、"交付执行"等)
├── stage (字符串) - 兼容旧字段,与 currentStage 类似
└── data (JSON 对象) ⬅️ 停滞期和改图期数据在这里
    ├── isStalled (布尔值) - 是否处于停滞期
    ├── isModification (布尔值) - 是否处于改图期
    ├── stagnationReasonType (字符串) - 停滞原因类型
    ├── stagnationCustomReason (字符串) - 自定义停滞原因
    ├── modificationReasonType (字符串) - 改图原因类型
    ├── modificationCustomReason (字符串) - 自定义改图原因
    ├── estimatedResumeDate (日期) - 预计恢复时间
    ├── reasonNotes (字符串) - 备注说明
    ├── markedAt (日期) - 标记时间
    ├── markedBy (字符串) - 标记人
    └── ... (其他项目数据)

❌ 不在这些位置

  • 不在 Project.stage 字段中
  • 不在 Project.currentStage 字段中
  • 不在 ProjectFile 表中

🔍 字段用途说明

1. currentStage 字段

用途:存储项目当前所处的工作流阶段

可能的值

  • "订单分配" - 订单分配阶段
  • "确认需求" - 确认需求阶段
  • "方案深化" - 方案深化阶段
  • "交付执行" / "白模" / "软装" / "渲染" / "后期" - 交付执行阶段
  • "尾款结算" - 售后归档阶段
  • 等等...

示例

{
  "currentStage": "交付执行"
}

2. stage 字段

用途:兼容旧版本的阶段字段,功能与 currentStage 类似

说明:在新代码中主要使用 currentStage,但保留 stage 以兼容旧数据

3. data 字段

用途:存储项目的扩展数据,包括停滞期、改图期等状态信息

完整结构示例

{
  "data": {
    // 停滞期相关
    "isStalled": true,
    "stagnationReasonType": "customer",
    "stagnationCustomReason": "",
    "estimatedResumeDate": "2024-12-15T00:00:00.000Z",
    "reasonNotes": "客户出差暂时无法沟通",
    "markedAt": "2024-12-07T13:42:00.000Z",
    "markedBy": "张组长",
    
    // 改图期相关(互斥,同时只能有一个为 true)
    "isModification": false,
    "modificationReasonType": "",
    "modificationCustomReason": "",
    
    // 其他扩展数据
    "phaseDeadlines": { ... },
    "approvalStatus": "approved",
    "requirementsAnalysis": { ... },
    // ...
  }
}

💾 实际保存代码

组长端标记(dashboard.ts)

private async updateProjectMarkStatus(
  projectId: string, 
  type: 'stagnation' | 'modification', 
  reason: any
): Promise<void> {
  const Parse = (window as any).Parse;
  const query = new Parse.Query('Project');
  const project = await query.get(projectId);
  
  // ✅ 获取 data 字段
  const projectData = project.get('data') || {};
  
  // ✅ 设置停滞期/改图期字段
  if (type === 'stagnation') {
    projectData.isStalled = true;
    projectData.isModification = false;
    projectData.stagnationReasonType = reason.reasonType;
    projectData.stagnationCustomReason = reason.customReason;
    projectData.estimatedResumeDate = reason.estimatedResumeDate;
    projectData.reasonNotes = reason.notes;
    projectData.markedAt = new Date();
    projectData.markedBy = this.currentUser.name;
  } else {
    projectData.isModification = true;
    projectData.isStalled = false;
    projectData.modificationReasonType = reason.reasonType;
    projectData.modificationCustomReason = reason.customReason;
    projectData.reasonNotes = reason.notes;
    projectData.markedAt = new Date();
    projectData.markedBy = this.currentUser.name;
  }
  
  // ✅ 保存回 data 字段
  project.set('data', projectData);
  await project.save();
}

组员端读取(project-detail.component.ts)

// ✅ 从 data 字段读取停滞期状态
get isStalled(): boolean {
  const data = this.project?.get('data') || {};
  return data.isStalled === true;
}

// ✅ 从 data 字段读取改图期状态
get isModification(): boolean {
  const data = this.project?.get('data') || {};
  return data.isModification === true;
}

// ✅ 从 data 字段读取停滞期详情
get stagnationInfo() {
  const data = this.project?.get('data') || {};
  return {
    reasonType: data.stagnationReasonType,
    customReason: data.stagnationCustomReason,
    estimatedResumeDate: data.estimatedResumeDate,
    notes: data.reasonNotes,
    markedAt: data.markedAt,
    markedBy: data.markedBy
  };
}

🔧 数据库查询示例

查询所有停滞期项目

const Parse = require('parse/node');

const query = new Parse.Query('Project');
// 注意:Parse 不支持直接查询嵌套 JSON 字段
// 需要使用特殊语法或在代码中过滤

// 获取所有项目后过滤
const projects = await query.find();
const stalledProjects = projects.filter(p => {
  const data = p.get('data') || {};
  return data.isStalled === true;
});

console.log('停滞期项目数量:', stalledProjects.length);

查询所有改图期项目

const query = new Parse.Query('Project');
const projects = await query.find();
const modificationProjects = projects.filter(p => {
  const data = p.get('data') || {};
  return data.isModification === true;
});

console.log('改图期项目数量:', modificationProjects.length);

更新项目数据

const query = new Parse.Query('Project');
const project = await query.get('项目ID');

const data = project.get('data') || {};
data.isStalled = true;
data.stagnationReasonType = 'customer';
data.markedAt = new Date();

project.set('data', data);
await project.save();

📋 数据验证清单

要验证停滞期/改图期数据是否正确保存,可以检查:

1. Parse Dashboard 检查

  1. 登录 Parse Dashboard
  2. 选择 Project
  3. 找到标记的项目
  4. 查看 data 列(JSON 格式)
  5. ✅ 确认有 isStalledisModification 字段

2. 浏览器控制台检查

// 在浏览器控制台运行
const Parse = window.Parse;
const query = new Parse.Query('Project');
query.get('你的项目ID').then(project => {
  const data = project.get('data');
  console.log('停滞期:', data.isStalled);
  console.log('改图期:', data.isModification);
  console.log('完整data:', data);
});

3. 代码日志检查

标记项目后,控制台应该显示:

✅ [数据库] 停滞期标记已保存到数据库 项目ID

⚠️ 常见问题

Q1: 为什么不保存在 currentStage 字段中?

A: currentStage 表示项目的工作流阶段(如"订单分配"、"交付执行"),与停滞期/改图期的状态标记是不同的概念。一个项目可以同时处于"交付执行"阶段和"停滞期"状态。

Q2: 为什么不保存在 ProjectFile 表中?

A: ProjectFile 表用于存储项目文件(图片、文档等),而停滞期/改图期是项目级别的状态,应该保存在 Project 表中。

Q3: 如何批量查询停滞期项目?

A: 由于 Parse 限制,无法直接查询嵌套 JSON 字段。建议:

  1. 查询所有项目
  2. 在代码中过滤 data.isStalled === true 的项目
  3. 或者在 Project 表添加顶层字段 isStalled(需要同步更新)

Q4: 数据会丢失吗?

A: 不会。所有标记操作都会调用 project.save() 保存到 Parse 数据库。只要保存成功(有日志确认),数据就会持久化。

🎯 总结

停滞期和改图期数据保存在Project.data.isStalled / Project.data.isModification
不在Project.currentStageProject.stage
不在ProjectFile

如需查看实际数据库内容,请访问 Parse Dashboard 查看 Project 表的 data 字段。