|
@@ -13,6 +13,7 @@ import { DashboardNavbarComponent } from './components/dashboard-navbar/dashboar
|
|
|
import { WorkloadGanttComponent } from './components/workload-gantt/workload-gantt.component';
|
|
import { WorkloadGanttComponent } from './components/workload-gantt/workload-gantt.component';
|
|
|
import { TodoSectionComponent } from './components/todo-section/todo-section.component';
|
|
import { TodoSectionComponent } from './components/todo-section/todo-section.component';
|
|
|
import { SmartMatchModalComponent } from './components/smart-match-modal/smart-match-modal.component';
|
|
import { SmartMatchModalComponent } from './components/smart-match-modal/smart-match-modal.component';
|
|
|
|
|
+import { StagnationReasonModalComponent } from './components/stagnation-reason-modal/stagnation-reason-modal.component';
|
|
|
import { DashboardFilterBarComponent } from './components/dashboard-filter-bar/dashboard-filter-bar.component';
|
|
import { DashboardFilterBarComponent } from './components/dashboard-filter-bar/dashboard-filter-bar.component';
|
|
|
import { ProjectKanbanComponent } from './components/project-kanban/project-kanban.component';
|
|
import { ProjectKanbanComponent } from './components/project-kanban/project-kanban.component';
|
|
|
import { DashboardAlertsComponent } from './components/dashboard-alerts/dashboard-alerts.component';
|
|
import { DashboardAlertsComponent } from './components/dashboard-alerts/dashboard-alerts.component';
|
|
@@ -51,6 +52,7 @@ import {
|
|
|
WorkloadGanttComponent,
|
|
WorkloadGanttComponent,
|
|
|
TodoSectionComponent,
|
|
TodoSectionComponent,
|
|
|
SmartMatchModalComponent,
|
|
SmartMatchModalComponent,
|
|
|
|
|
+ StagnationReasonModalComponent,
|
|
|
DashboardFilterBarComponent,
|
|
DashboardFilterBarComponent,
|
|
|
ProjectKanbanComponent,
|
|
ProjectKanbanComponent,
|
|
|
DashboardAlertsComponent
|
|
DashboardAlertsComponent
|
|
@@ -100,6 +102,11 @@ export class Dashboard implements OnInit, OnDestroy {
|
|
|
showSmartMatch: boolean = false;
|
|
showSmartMatch: boolean = false;
|
|
|
selectedProject: any = null;
|
|
selectedProject: any = null;
|
|
|
recommendations: any[] = [];
|
|
recommendations: any[] = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 🆕 停滞/改图原因弹窗
|
|
|
|
|
+ showStagnationModal: boolean = false;
|
|
|
|
|
+ stagnationModalType: 'stagnation' | 'modification' = 'stagnation';
|
|
|
|
|
+ stagnationModalProject: Project | null = null;
|
|
|
// 新增:关键词搜索
|
|
// 新增:关键词搜索
|
|
|
searchTerm: string = '';
|
|
searchTerm: string = '';
|
|
|
|
|
|
|
@@ -949,6 +956,8 @@ export class Dashboard implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
markEventAsStagnant(payload: {event: UrgentEvent, reason: any}): void {
|
|
markEventAsStagnant(payload: {event: UrgentEvent, reason: any}): void {
|
|
|
const { event, reason } = payload;
|
|
const { event, reason } = payload;
|
|
|
|
|
+
|
|
|
|
|
+ // 更新紧急事件
|
|
|
this.urgentEvents = this.urgentEvents.map(item => {
|
|
this.urgentEvents = this.urgentEvents.map(item => {
|
|
|
if (item.id !== event.id) return item;
|
|
if (item.id !== event.id) return item;
|
|
|
const labels = new Set(item.labels || []);
|
|
const labels = new Set(item.labels || []);
|
|
@@ -969,6 +978,10 @@ export class Dashboard implements OnInit, OnDestroy {
|
|
|
followUpNeeded: true
|
|
followUpNeeded: true
|
|
|
};
|
|
};
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+ // 🆕 同步更新对应的项目对象
|
|
|
|
|
+ this.updateProjectMarkStatus(event.projectId, 'stagnation', reason);
|
|
|
|
|
+
|
|
|
this.cdr.markForCheck();
|
|
this.cdr.markForCheck();
|
|
|
|
|
|
|
|
// TODO: 持久化到后端数据库
|
|
// TODO: 持久化到后端数据库
|
|
@@ -977,6 +990,8 @@ export class Dashboard implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
markEventAsModification(payload: {event: UrgentEvent, reason: any}): void {
|
|
markEventAsModification(payload: {event: UrgentEvent, reason: any}): void {
|
|
|
const { event, reason } = payload;
|
|
const { event, reason } = payload;
|
|
|
|
|
+
|
|
|
|
|
+ // 更新紧急事件
|
|
|
this.urgentEvents = this.urgentEvents.map(item => {
|
|
this.urgentEvents = this.urgentEvents.map(item => {
|
|
|
if (item.id !== event.id) return item;
|
|
if (item.id !== event.id) return item;
|
|
|
const labels = new Set(item.labels || []);
|
|
const labels = new Set(item.labels || []);
|
|
@@ -993,12 +1008,53 @@ export class Dashboard implements OnInit, OnDestroy {
|
|
|
labels: Array.from(labels)
|
|
labels: Array.from(labels)
|
|
|
};
|
|
};
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+ // 🆕 同步更新对应的项目对象
|
|
|
|
|
+ this.updateProjectMarkStatus(event.projectId, 'modification', reason);
|
|
|
|
|
+
|
|
|
this.cdr.markForCheck();
|
|
this.cdr.markForCheck();
|
|
|
|
|
|
|
|
// TODO: 持久化到后端数据库
|
|
// TODO: 持久化到后端数据库
|
|
|
this.saveEventMarkToDatabase(event, 'modification', reason);
|
|
this.saveEventMarkToDatabase(event, 'modification', reason);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 更新项目的停滞/改图标记及原因信息
|
|
|
|
|
+ */
|
|
|
|
|
+ private updateProjectMarkStatus(projectId: string, type: 'stagnation' | 'modification', reason: any): void {
|
|
|
|
|
+ this.projects = this.projects.map(project => {
|
|
|
|
|
+ if (project.id !== projectId) return project;
|
|
|
|
|
+
|
|
|
|
|
+ if (type === 'stagnation') {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...project,
|
|
|
|
|
+ isStalled: true,
|
|
|
|
|
+ isModification: false,
|
|
|
|
|
+ stagnationReasonType: reason.reasonType,
|
|
|
|
|
+ stagnationCustomReason: reason.customReason,
|
|
|
|
|
+ estimatedResumeDate: reason.estimatedResumeDate,
|
|
|
|
|
+ reasonNotes: reason.notes,
|
|
|
|
|
+ markedAt: new Date(),
|
|
|
|
|
+ markedBy: this.currentUser.name
|
|
|
|
|
+ };
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...project,
|
|
|
|
|
+ isModification: true,
|
|
|
|
|
+ isStalled: false,
|
|
|
|
|
+ modificationReasonType: reason.reasonType,
|
|
|
|
|
+ modificationCustomReason: reason.customReason,
|
|
|
|
|
+ reasonNotes: reason.notes,
|
|
|
|
|
+ markedAt: new Date(),
|
|
|
|
|
+ markedBy: this.currentUser.name
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 重新应用筛选
|
|
|
|
|
+ this.applyFilters();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private saveEventMarkToDatabase(event: UrgentEvent, type: 'stagnation' | 'modification', reason: any): void {
|
|
private saveEventMarkToDatabase(event: UrgentEvent, type: 'stagnation' | 'modification', reason: any): void {
|
|
|
// TODO: 实现数据持久化逻辑
|
|
// TODO: 实现数据持久化逻辑
|
|
|
// 可以保存到 Parse 数据库的 ProjectEvent 或 UrgentEventMark 表
|
|
// 可以保存到 Parse 数据库的 ProjectEvent 或 UrgentEventMark 表
|
|
@@ -1044,20 +1100,45 @@ export class Dashboard implements OnInit, OnDestroy {
|
|
|
console.log(`✅ 标记问题为已读: ${task.title}`);
|
|
console.log(`✅ 标记问题为已读: ${task.title}`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 标记项目为停滞
|
|
|
|
|
|
|
+ // 标记项目为停滞(从看板触发)
|
|
|
markProjectAsStalled(project: Project): void {
|
|
markProjectAsStalled(project: Project): void {
|
|
|
- project.isStalled = true;
|
|
|
|
|
- project.isModification = false; // 互斥
|
|
|
|
|
- this.applyFilters();
|
|
|
|
|
- window?.fmode?.alert('已标记为停滞项目');
|
|
|
|
|
|
|
+ // 🆕 弹出原因输入弹窗
|
|
|
|
|
+ this.stagnationModalType = 'stagnation';
|
|
|
|
|
+ this.stagnationModalProject = project;
|
|
|
|
|
+ this.showStagnationModal = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 标记项目为改图
|
|
|
|
|
|
|
+ // 标记项目为改图(从看板触发)
|
|
|
markProjectAsModification(project: Project): void {
|
|
markProjectAsModification(project: Project): void {
|
|
|
- project.isModification = true;
|
|
|
|
|
- project.isStalled = false; // 互斥
|
|
|
|
|
- this.applyFilters();
|
|
|
|
|
- window?.fmode?.alert('已标记为改图项目');
|
|
|
|
|
|
|
+ // 🆕 弹出原因输入弹窗
|
|
|
|
|
+ this.stagnationModalType = 'modification';
|
|
|
|
|
+ this.stagnationModalProject = project;
|
|
|
|
|
+ this.showStagnationModal = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 🆕 确认标记停滞/改图原因
|
|
|
|
|
+ onStagnationReasonConfirm(reason: any): void {
|
|
|
|
|
+ if (!this.stagnationModalProject) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 直接调用 updateProjectMarkStatus 更新项目
|
|
|
|
|
+ this.updateProjectMarkStatus(
|
|
|
|
|
+ this.stagnationModalProject.id,
|
|
|
|
|
+ this.stagnationModalType,
|
|
|
|
|
+ reason
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 关闭弹窗
|
|
|
|
|
+ this.closeStagnationModal();
|
|
|
|
|
+
|
|
|
|
|
+ // 显示确认消息
|
|
|
|
|
+ const message = this.stagnationModalType === 'stagnation' ? '已标记为停滞项目' : '已标记为改图项目';
|
|
|
|
|
+ window?.fmode?.alert(message);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 🆕 关闭停滞/改图原因弹窗
|
|
|
|
|
+ closeStagnationModal(): void {
|
|
|
|
|
+ this.showStagnationModal = false;
|
|
|
|
|
+ this.stagnationModalProject = null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 切换前期阶段显示
|
|
// 切换前期阶段显示
|