STAGNATION-MODIFICATION-IMPLEMENTATION.md 7.8 KB

停滞期和改图期功能实现说明

功能概述

在组长端的紧急事件中标记项目为"停滞"或"改图"后,该项目会在项目监控看板中的"停滞期"或"改图期"列以卡片形式显示,并注明停滞或改图的原因。

实现的关键修改

1. Dashboard主组件 (dashboard.ts)

新增变量

// 停滞/改图原因弹窗控制
showStagnationModal: boolean = false;
stagnationModalType: 'stagnation' | 'modification' = 'stagnation';
stagnationModalProject: Project | null = null;

核心方法

标记紧急事件时同步更新项目对象

  • markEventAsStagnant(): 标记紧急事件为停滞时,调用 updateProjectMarkStatus() 同步更新对应的项目对象
  • markEventAsModification(): 标记紧急事件为改图时,调用 updateProjectMarkStatus() 同步更新对应的项目对象

从看板直接标记时弹出原因输入弹窗

  • markProjectAsStalled(): 弹出停滞原因弹窗
  • markProjectAsModification(): 弹出改图原因弹窗

处理原因输入

  • onStagnationReasonConfirm(): 确认原因后调用 updateProjectMarkStatus() 更新项目
  • closeStagnationModal(): 关闭原因输入弹窗

项目状态更新核心方法

private updateProjectMarkStatus(projectId: string, type: 'stagnation' | 'modification', reason: any): void {
  // 更新项目的 isStalled/isModification 标志
  // 保存原因类型、自定义原因、预计恢复时间、备注等信息
  // 重新应用筛选
}

2. Dashboard HTML (dashboard.html)

新增停滞/改图原因弹窗组件:

<app-stagnation-reason-modal
  [isOpen]="showStagnationModal"
  [eventType]="stagnationModalType"
  [projectName]="stagnationModalProject?.name || ''"
  (confirm)="onStagnationReasonConfirm($event)"
  (cancel)="closeStagnationModal()">
</app-stagnation-reason-modal>

3. 项目看板组件 (project-kanban.component.ts)

修改了 getProjectsByCorePhase() 方法,实现了以下逻辑:

getProjectsByCorePhase(coreId: string): Project[] {
  return this.projects.filter(p => {
    // 优先判断是否被标记为停滞或改图
    if (p.isStalled && coreId === 'stalled') {
      return true;
    }
    if (p.isModification && coreId === 'modification') {
      return true;
    }
    
    // 如果被标记为停滞或改图,不应该出现在其他常规列中
    if (p.isStalled || p.isModification) {
      return false;
    }
    
    // 否则,根据 currentStage 映射到常规核心阶段
    return this.mapStageToCorePhase(p.currentStage) === coreId;
  });
}

4. 看板卡片显示 (project-kanban.component.html)

卡片中已有完善的原因显示逻辑(第42-77行):

停滞原因显示

@if (project.isStalled && project.stagnationReasonType) {
  <div class="reason-label stagnant">
    <span class="reason-text">
      @if (project.stagnationReasonType === 'designer') { 设计师原因停滞 }
      @if (project.stagnationReasonType === 'customer') { 客户原因停滞 }
      @if (project.stagnationReasonType === 'custom') { {{ project.stagnationCustomReason }} }
    </span>
    @if (project.estimatedResumeDate) {
      <span class="resume-date">({{ project.estimatedResumeDate | date:'MM-dd' }}恢复)</span>
    }
  </div>
}

改图原因显示

@if (project.isModification && project.modificationReasonType) {
  <div class="reason-label modification">
    <span class="reason-text">
      @if (project.modificationReasonType === 'customer') { 客户要求改图 }
      @if (project.modificationReasonType === 'designer') { 设计师优化 }
      @if (project.modificationReasonType === 'custom') { {{ project.modificationCustomReason }} }
    </span>
  </div>
}

备注显示

@if ((project.isStalled || project.isModification) && project.reasonNotes) {
  <div class="reason-notes">
    {{ project.reasonNotes }}
  </div>
}

5. 样式 (project-kanban.component.scss)

已有完善的样式(第214-269行):

  • .reason-label.stagnant: 红色背景,用于停滞原因
  • .reason-label.modification: 黄色背景,用于改图原因
  • .reason-notes: 灰色背景,用于备注

6. 常量定义 (dashboard.constants.ts)

核心阶段已包含停滞期和改图期:

export const CORE_PHASES: ProjectStage[] = [
  { id: 'order', name: '订单分配', order: 1 },
  { id: 'requirements', name: '确认需求', order: 2 },
  { id: 'delivery', name: '交付执行', order: 3 },
  { id: 'stalled', name: '停滞期', order: 3.5 },       // 停滞期
  { id: 'modification', name: '改图期', order: 3.8 },  // 改图期
  { id: 'aftercare', name: '售后', order: 4 }
];

数据流

从紧急事件标记

  1. 用户在"紧急事件"中点击"标记为停滞/改图"
  2. 弹出 StagnationReasonModalComponent 原因输入弹窗
  3. 用户填写原因信息并确认
  4. 触发 markEventAsStagnant()markEventAsModification()
  5. 调用 updateProjectMarkStatus() 更新项目对象的以下字段:
    • isStalled / isModification
    • stagnationReasonType / modificationReasonType
    • stagnationCustomReason / modificationCustomReason
    • estimatedResumeDate(仅停滞)
    • reasonNotes
    • markedAt, markedBy
  6. 重新应用筛选,项目出现在对应的看板列中

从看板直接标记

  1. 用户在项目卡片上点击"⏸️"(停滞)或"✏️"(改图)按钮
  2. 触发 markProjectAsStalled()markProjectAsModification()
  3. 弹出 StagnationReasonModalComponent 原因输入弹窗
  4. 用户填写原因信息并确认
  5. 触发 onStagnationReasonConfirm()
  6. 直接调用 updateProjectMarkStatus() 更新项目对象
  7. 重新应用筛选,项目出现在对应的看板列中

项目数据模型

Project 接口中包含以下相关字段(在 interfaces.ts 中定义):

export interface Project {
  // ... 其他字段
  isStalled?: boolean;                      // 是否停滞
  isModification?: boolean;                 // 是否改图
  stagnationReasonType?: 'designer' | 'customer' | 'custom';
  stagnationCustomReason?: string;
  modificationReasonType?: 'designer' | 'customer' | 'custom';
  modificationCustomReason?: string;
  estimatedResumeDate?: Date;               // 预计恢复时间(仅停滞)
  reasonNotes?: string;                     // 备注说明
  markedAt?: Date;                          // 标记时间
  markedBy?: string;                        // 标记人
}

用户体验流程

  1. 标记操作

    • 从紧急事件标记:点击"标记为停滞/改图" → 弹窗填写原因 → 确认
    • 从看板标记:点击卡片上的按钮 → 弹窗填写原因 → 确认
  2. 原因选择

    • 停滞原因:设计师原因 / 客户原因 / 自定义
    • 改图原因:客户要求 / 设计师优化 / 自定义
    • 可选填写:预计恢复时间(停滞)、备注说明
  3. 看板显示

    • 项目自动移动到"停滞期"或"改图期"列
    • 卡片显示原因标签(红色/黄色)
    • 显示预计恢复时间(如有)
    • 显示备注说明(如有)

注意事项

  1. 互斥关系:项目不能同时处于停滞期和改图期
  2. 列显示控制:默认情况下,"停滞期"和"改图期"列始终可见(订单和需求阶段可通过切换隐藏)
  3. 数据持久化:目前通过 saveEventMarkToDatabase() 方法预留了持久化接口,需要后续实现真正的数据库保存逻辑

后续优化建议

  1. 实现 saveEventMarkToDatabase() 方法,将标记信息保存到 Parse 数据库
  2. 在项目加载时从数据库读取停滞/改图标记信息
  3. 添加"取消标记"功能,允许将项目移出停滞期/改图期
  4. 添加停滞/改图历史记录追踪
  5. 在项目详情页显示完整的标记历史