# 停滞期和改图期功能实现说明
## 功能概述
在组长端的紧急事件中标记项目为"停滞"或"改图"后,该项目会在项目监控看板中的"停滞期"或"改图期"列以卡片形式显示,并注明停滞或改图的原因。
## 实现的关键修改
### 1. Dashboard主组件 (`dashboard.ts`)
#### 新增变量
```typescript
// 停滞/改图原因弹窗控制
showStagnationModal: boolean = false;
stagnationModalType: 'stagnation' | 'modification' = 'stagnation';
stagnationModalProject: Project | null = null;
```
#### 核心方法
**标记紧急事件时同步更新项目对象**
- `markEventAsStagnant()`: 标记紧急事件为停滞时,调用 `updateProjectMarkStatus()` 同步更新对应的项目对象
- `markEventAsModification()`: 标记紧急事件为改图时,调用 `updateProjectMarkStatus()` 同步更新对应的项目对象
**从看板直接标记时弹出原因输入弹窗**
- `markProjectAsStalled()`: 弹出停滞原因弹窗
- `markProjectAsModification()`: 弹出改图原因弹窗
**处理原因输入**
- `onStagnationReasonConfirm()`: 确认原因后调用 `updateProjectMarkStatus()` 更新项目
- `closeStagnationModal()`: 关闭原因输入弹窗
**项目状态更新核心方法**
```typescript
private updateProjectMarkStatus(projectId: string, type: 'stagnation' | 'modification', reason: any): void {
// 更新项目的 isStalled/isModification 标志
// 保存原因类型、自定义原因、预计恢复时间、备注等信息
// 重新应用筛选
}
```
### 2. Dashboard HTML (`dashboard.html`)
新增停滞/改图原因弹窗组件:
```html
```
### 3. 项目看板组件 (`project-kanban.component.ts`)
修改了 `getProjectsByCorePhase()` 方法,实现了以下逻辑:
```typescript
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行):
**停滞原因显示**
```html
@if (project.isStalled && project.stagnationReasonType) {
@if (project.stagnationReasonType === 'designer') { 设计师原因停滞 }
@if (project.stagnationReasonType === 'customer') { 客户原因停滞 }
@if (project.stagnationReasonType === 'custom') { {{ project.stagnationCustomReason }} }
@if (project.estimatedResumeDate) {
({{ project.estimatedResumeDate | date:'MM-dd' }}恢复)
}
}
```
**改图原因显示**
```html
@if (project.isModification && project.modificationReasonType) {
@if (project.modificationReasonType === 'customer') { 客户要求改图 }
@if (project.modificationReasonType === 'designer') { 设计师优化 }
@if (project.modificationReasonType === 'custom') { {{ project.modificationCustomReason }} }
}
```
**备注显示**
```html
@if ((project.isStalled || project.isModification) && project.reasonNotes) {
{{ project.reasonNotes }}
}
```
### 5. 样式 (`project-kanban.component.scss`)
已有完善的样式(第214-269行):
- `.reason-label.stagnant`: 红色背景,用于停滞原因
- `.reason-label.modification`: 黄色背景,用于改图原因
- `.reason-notes`: 灰色背景,用于备注
### 6. 常量定义 (`dashboard.constants.ts`)
核心阶段已包含停滞期和改图期:
```typescript
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` 中定义):
```typescript
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. 在项目详情页显示完整的标记历史