|
|
@@ -0,0 +1,579 @@
|
|
|
+# Project表阶段截止时间字段设计方案
|
|
|
+
|
|
|
+## 📋 需求背景
|
|
|
+
|
|
|
+为了支持项目负载时间轴的阶段查看功能,需要在Project表中添加各个设计阶段的截止时间信息,包括:
|
|
|
+- 建模阶段
|
|
|
+- 软装阶段
|
|
|
+- 渲染阶段
|
|
|
+- 后期阶段
|
|
|
+
|
|
|
+根据schemas.md说明,这些信息应存储在`Project.data`字段(Object类型)中,可以自由扩展子级属性。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🎯 数据结构设计
|
|
|
+
|
|
|
+### 1. Project.data.phaseDeadlines 字段结构
|
|
|
+
|
|
|
+```typescript
|
|
|
+interface PhaseDeadlines {
|
|
|
+ modeling?: PhaseInfo; // 建模阶段
|
|
|
+ softDecor?: PhaseInfo; // 软装阶段
|
|
|
+ rendering?: PhaseInfo; // 渲染阶段
|
|
|
+ postProcessing?: PhaseInfo; // 后期阶段
|
|
|
+}
|
|
|
+
|
|
|
+interface PhaseInfo {
|
|
|
+ startDate?: Date; // 阶段开始时间
|
|
|
+ deadline: Date; // 阶段截止时间
|
|
|
+ estimatedDays?: number; // 预计工期(天数)
|
|
|
+ status?: 'not_started' | 'in_progress' | 'completed' | 'delayed'; // 阶段状态
|
|
|
+ completedAt?: Date; // 实际完成时间
|
|
|
+ assignee?: Pointer<Profile>; // 负责人
|
|
|
+ priority?: 'low' | 'medium' | 'high' | 'urgent'; // 优先级
|
|
|
+ notes?: string; // 备注信息
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📊 JSON示例
|
|
|
+
|
|
|
+### 完整示例(所有阶段)
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "phaseDeadlines": {
|
|
|
+ "modeling": {
|
|
|
+ "startDate": "2024-12-01T00:00:00.000Z",
|
|
|
+ "deadline": "2024-12-08T23:59:59.999Z",
|
|
|
+ "estimatedDays": 7,
|
|
|
+ "status": "completed",
|
|
|
+ "completedAt": "2024-12-07T18:30:00.000Z",
|
|
|
+ "assignee": {
|
|
|
+ "__type": "Pointer",
|
|
|
+ "className": "Profile",
|
|
|
+ "objectId": "prof001"
|
|
|
+ },
|
|
|
+ "priority": "high",
|
|
|
+ "notes": "客户要求加急,优先处理"
|
|
|
+ },
|
|
|
+ "softDecor": {
|
|
|
+ "startDate": "2024-12-09T00:00:00.000Z",
|
|
|
+ "deadline": "2024-12-13T23:59:59.999Z",
|
|
|
+ "estimatedDays": 4,
|
|
|
+ "status": "in_progress",
|
|
|
+ "assignee": {
|
|
|
+ "__type": "Pointer",
|
|
|
+ "className": "Profile",
|
|
|
+ "objectId": "prof002"
|
|
|
+ },
|
|
|
+ "priority": "medium"
|
|
|
+ },
|
|
|
+ "rendering": {
|
|
|
+ "startDate": "2024-12-14T00:00:00.000Z",
|
|
|
+ "deadline": "2024-12-20T23:59:59.999Z",
|
|
|
+ "estimatedDays": 6,
|
|
|
+ "status": "not_started",
|
|
|
+ "priority": "high",
|
|
|
+ "notes": "需要高质量渲染,预留充足时间"
|
|
|
+ },
|
|
|
+ "postProcessing": {
|
|
|
+ "startDate": "2024-12-21T00:00:00.000Z",
|
|
|
+ "deadline": "2024-12-24T23:59:59.999Z",
|
|
|
+ "estimatedDays": 3,
|
|
|
+ "status": "not_started",
|
|
|
+ "priority": "medium",
|
|
|
+ "notes": "后期处理与润色"
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 简化示例(仅关键字段)
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "phaseDeadlines": {
|
|
|
+ "modeling": {
|
|
|
+ "deadline": "2024-12-08T23:59:59.999Z",
|
|
|
+ "status": "in_progress"
|
|
|
+ },
|
|
|
+ "softDecor": {
|
|
|
+ "deadline": "2024-12-13T23:59:59.999Z",
|
|
|
+ "status": "not_started"
|
|
|
+ },
|
|
|
+ "rendering": {
|
|
|
+ "deadline": "2024-12-20T23:59:59.999Z",
|
|
|
+ "status": "not_started"
|
|
|
+ },
|
|
|
+ "postProcessing": {
|
|
|
+ "deadline": "2024-12-24T23:59:59.999Z",
|
|
|
+ "status": "not_started"
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 💾 Parse Cloud Code 使用示例
|
|
|
+
|
|
|
+### 1. 创建项目时设置阶段截止时间
|
|
|
+
|
|
|
+```javascript
|
|
|
+Parse.Cloud.define("createProjectWithPhases", async (request) => {
|
|
|
+ const { projectTitle, contactId, companyId, phaseConfig } = request.params;
|
|
|
+
|
|
|
+ const Project = Parse.Object.extend("Project");
|
|
|
+ const project = new Project();
|
|
|
+
|
|
|
+ project.set("title", projectTitle);
|
|
|
+ project.set("contact", { __type: "Pointer", className: "ContactInfo", objectId: contactId });
|
|
|
+ project.set("company", { __type: "Pointer", className: "Company", objectId: companyId });
|
|
|
+ project.set("status", "进行中");
|
|
|
+ project.set("currentStage", "建模");
|
|
|
+
|
|
|
+ // 设置阶段截止时间
|
|
|
+ const baseDate = new Date();
|
|
|
+ project.set("data", {
|
|
|
+ phaseDeadlines: {
|
|
|
+ modeling: {
|
|
|
+ startDate: new Date(baseDate),
|
|
|
+ deadline: new Date(baseDate.getTime() + 7 * 24 * 60 * 60 * 1000), // 7天后
|
|
|
+ estimatedDays: 7,
|
|
|
+ status: "in_progress",
|
|
|
+ priority: "high"
|
|
|
+ },
|
|
|
+ softDecor: {
|
|
|
+ startDate: new Date(baseDate.getTime() + 7 * 24 * 60 * 60 * 1000),
|
|
|
+ deadline: new Date(baseDate.getTime() + 11 * 24 * 60 * 60 * 1000), // 11天后
|
|
|
+ estimatedDays: 4,
|
|
|
+ status: "not_started",
|
|
|
+ priority: "medium"
|
|
|
+ },
|
|
|
+ rendering: {
|
|
|
+ startDate: new Date(baseDate.getTime() + 11 * 24 * 60 * 60 * 1000),
|
|
|
+ deadline: new Date(baseDate.getTime() + 17 * 24 * 60 * 60 * 1000), // 17天后
|
|
|
+ estimatedDays: 6,
|
|
|
+ status: "not_started",
|
|
|
+ priority: "high"
|
|
|
+ },
|
|
|
+ postProcessing: {
|
|
|
+ startDate: new Date(baseDate.getTime() + 17 * 24 * 60 * 60 * 1000),
|
|
|
+ deadline: new Date(baseDate.getTime() + 20 * 24 * 60 * 60 * 1000), // 20天后
|
|
|
+ estimatedDays: 3,
|
|
|
+ status: "not_started",
|
|
|
+ priority: "medium"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ await project.save(null, { useMasterKey: true });
|
|
|
+ return project;
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 更新阶段状态
|
|
|
+
|
|
|
+```javascript
|
|
|
+Parse.Cloud.define("updatePhaseStatus", async (request) => {
|
|
|
+ const { projectId, phaseName, status, completedAt } = request.params;
|
|
|
+
|
|
|
+ const projectQuery = new Parse.Query("Project");
|
|
|
+ const project = await projectQuery.get(projectId, { useMasterKey: true });
|
|
|
+
|
|
|
+ const data = project.get("data") || {};
|
|
|
+ const phaseDeadlines = data.phaseDeadlines || {};
|
|
|
+
|
|
|
+ if (!phaseDeadlines[phaseName]) {
|
|
|
+ throw new Error(`Phase ${phaseName} not found`);
|
|
|
+ }
|
|
|
+
|
|
|
+ phaseDeadlines[phaseName].status = status;
|
|
|
+ if (status === "completed") {
|
|
|
+ phaseDeadlines[phaseName].completedAt = completedAt || new Date();
|
|
|
+ }
|
|
|
+
|
|
|
+ data.phaseDeadlines = phaseDeadlines;
|
|
|
+ project.set("data", data);
|
|
|
+
|
|
|
+ await project.save(null, { useMasterKey: true });
|
|
|
+ return project;
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 查询特定阶段的项目
|
|
|
+
|
|
|
+```javascript
|
|
|
+Parse.Cloud.define("getProjectsByPhaseStatus", async (request) => {
|
|
|
+ const { companyId, phaseName, status } = request.params;
|
|
|
+
|
|
|
+ const projectQuery = new Parse.Query("Project");
|
|
|
+ projectQuery.equalTo("company", { __type: "Pointer", className: "Company", objectId: companyId });
|
|
|
+ projectQuery.exists(`data.phaseDeadlines.${phaseName}`);
|
|
|
+
|
|
|
+ const projects = await projectQuery.find({ useMasterKey: true });
|
|
|
+
|
|
|
+ // 前端过滤(Parse Query不支持深层嵌套查询)
|
|
|
+ return projects.filter(project => {
|
|
|
+ const data = project.get("data");
|
|
|
+ return data?.phaseDeadlines?.[phaseName]?.status === status;
|
|
|
+ });
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🎨 前端使用示例(Angular/TypeScript)
|
|
|
+
|
|
|
+### 1. 类型定义
|
|
|
+
|
|
|
+```typescript
|
|
|
+// src/app/models/project-phase.model.ts
|
|
|
+export interface PhaseInfo {
|
|
|
+ startDate?: Date;
|
|
|
+ deadline: Date;
|
|
|
+ estimatedDays?: number;
|
|
|
+ status?: 'not_started' | 'in_progress' | 'completed' | 'delayed';
|
|
|
+ completedAt?: Date;
|
|
|
+ assignee?: {
|
|
|
+ __type: 'Pointer';
|
|
|
+ className: 'Profile';
|
|
|
+ objectId: string;
|
|
|
+ };
|
|
|
+ priority?: 'low' | 'medium' | 'high' | 'urgent';
|
|
|
+ notes?: string;
|
|
|
+}
|
|
|
+
|
|
|
+export interface PhaseDeadlines {
|
|
|
+ modeling?: PhaseInfo;
|
|
|
+ softDecor?: PhaseInfo;
|
|
|
+ rendering?: PhaseInfo;
|
|
|
+ postProcessing?: PhaseInfo;
|
|
|
+}
|
|
|
+
|
|
|
+export interface ProjectData {
|
|
|
+ phaseDeadlines?: PhaseDeadlines;
|
|
|
+ // ... 其他data字段
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 获取阶段信息
|
|
|
+
|
|
|
+```typescript
|
|
|
+// src/app/services/project.service.ts
|
|
|
+getProjectPhaseDeadlines(projectId: string): Observable<PhaseDeadlines | null> {
|
|
|
+ const query = new Parse.Query('Project');
|
|
|
+ return from(query.get(projectId)).pipe(
|
|
|
+ map(project => {
|
|
|
+ const data = project.get('data') as ProjectData;
|
|
|
+ return data?.phaseDeadlines || null;
|
|
|
+ })
|
|
|
+ );
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 项目时间轴组件中使用
|
|
|
+
|
|
|
+```typescript
|
|
|
+// src/app/pages/team-leader/project-timeline/project-timeline.component.ts
|
|
|
+interface TimelineEvent {
|
|
|
+ date: Date;
|
|
|
+ label: string;
|
|
|
+ type: 'start' | 'milestone' | 'deadline';
|
|
|
+ phase: string;
|
|
|
+ status?: string;
|
|
|
+}
|
|
|
+
|
|
|
+generateTimelineEvents(project: any): TimelineEvent[] {
|
|
|
+ const events: TimelineEvent[] = [];
|
|
|
+ const phaseDeadlines = project.get('data')?.phaseDeadlines;
|
|
|
+
|
|
|
+ if (!phaseDeadlines) return events;
|
|
|
+
|
|
|
+ const phaseLabels = {
|
|
|
+ modeling: '建模',
|
|
|
+ softDecor: '软装',
|
|
|
+ rendering: '渲染',
|
|
|
+ postProcessing: '后期'
|
|
|
+ };
|
|
|
+
|
|
|
+ // 为每个阶段生成事件
|
|
|
+ Object.entries(phaseDeadlines).forEach(([phaseName, phaseInfo]: [string, any]) => {
|
|
|
+ // 开始事件
|
|
|
+ if (phaseInfo.startDate) {
|
|
|
+ events.push({
|
|
|
+ date: new Date(phaseInfo.startDate),
|
|
|
+ label: `${phaseLabels[phaseName as keyof typeof phaseLabels]}开始`,
|
|
|
+ type: 'start',
|
|
|
+ phase: phaseName,
|
|
|
+ status: phaseInfo.status
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 截止事件
|
|
|
+ if (phaseInfo.deadline) {
|
|
|
+ events.push({
|
|
|
+ date: new Date(phaseInfo.deadline),
|
|
|
+ label: `${phaseLabels[phaseName as keyof typeof phaseLabels]}截止`,
|
|
|
+ type: 'deadline',
|
|
|
+ phase: phaseName,
|
|
|
+ status: phaseInfo.status
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 完成事件
|
|
|
+ if (phaseInfo.completedAt) {
|
|
|
+ events.push({
|
|
|
+ date: new Date(phaseInfo.completedAt),
|
|
|
+ label: `${phaseLabels[phaseName as keyof typeof phaseLabels]}完成`,
|
|
|
+ type: 'milestone',
|
|
|
+ phase: phaseName,
|
|
|
+ status: 'completed'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 按时间排序
|
|
|
+ return events.sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📈 时间轴可视化建议
|
|
|
+
|
|
|
+### 阶段颜色映射
|
|
|
+
|
|
|
+```typescript
|
|
|
+const phaseColors = {
|
|
|
+ modeling: {
|
|
|
+ bg: '#E3F2FD', // 浅蓝色
|
|
|
+ border: '#2196F3', // 蓝色
|
|
|
+ label: '建模'
|
|
|
+ },
|
|
|
+ softDecor: {
|
|
|
+ bg: '#F3E5F5', // 浅紫色
|
|
|
+ border: '#9C27B0', // 紫色
|
|
|
+ label: '软装'
|
|
|
+ },
|
|
|
+ rendering: {
|
|
|
+ bg: '#FFF3E0', // 浅橙色
|
|
|
+ border: '#FF9800', // 橙色
|
|
|
+ label: '渲染'
|
|
|
+ },
|
|
|
+ postProcessing: {
|
|
|
+ bg: '#E8F5E9', // 浅绿色
|
|
|
+ border: '#4CAF50', // 绿色
|
|
|
+ label: '后期'
|
|
|
+ }
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+### 状态图标映射
|
|
|
+
|
|
|
+```typescript
|
|
|
+const statusIcons = {
|
|
|
+ not_started: '⏸️',
|
|
|
+ in_progress: '▶️',
|
|
|
+ completed: '✅',
|
|
|
+ delayed: '⚠️'
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🔄 数据迁移建议
|
|
|
+
|
|
|
+### 为现有项目添加阶段截止时间
|
|
|
+
|
|
|
+```javascript
|
|
|
+Parse.Cloud.job("migrateProjectPhaseDeadlines", async (request) => {
|
|
|
+ const { params, message } = request;
|
|
|
+
|
|
|
+ const query = new Parse.Query("Project");
|
|
|
+ query.notEqualTo("isDeleted", true);
|
|
|
+ query.limit(1000);
|
|
|
+
|
|
|
+ let count = 0;
|
|
|
+ const projects = await query.find({ useMasterKey: true });
|
|
|
+
|
|
|
+ for (const project of projects) {
|
|
|
+ const data = project.get("data") || {};
|
|
|
+
|
|
|
+ // 如果已有phaseDeadlines,跳过
|
|
|
+ if (data.phaseDeadlines) continue;
|
|
|
+
|
|
|
+ // 根据项目deadline推算各阶段截止时间
|
|
|
+ const deadline = project.get("deadline");
|
|
|
+ if (!deadline) continue;
|
|
|
+
|
|
|
+ const deadlineTime = deadline.getTime();
|
|
|
+ const modelingDeadline = new Date(deadlineTime - 13 * 24 * 60 * 60 * 1000); // 提前13天
|
|
|
+ const softDecorDeadline = new Date(deadlineTime - 9 * 24 * 60 * 60 * 1000); // 提前9天
|
|
|
+ const renderingDeadline = new Date(deadlineTime - 3 * 24 * 60 * 60 * 1000); // 提前3天
|
|
|
+ const postProcessingDeadline = deadline;
|
|
|
+
|
|
|
+ data.phaseDeadlines = {
|
|
|
+ modeling: {
|
|
|
+ deadline: modelingDeadline,
|
|
|
+ estimatedDays: 7,
|
|
|
+ status: "not_started"
|
|
|
+ },
|
|
|
+ softDecor: {
|
|
|
+ deadline: softDecorDeadline,
|
|
|
+ estimatedDays: 4,
|
|
|
+ status: "not_started"
|
|
|
+ },
|
|
|
+ rendering: {
|
|
|
+ deadline: renderingDeadline,
|
|
|
+ estimatedDays: 6,
|
|
|
+ status: "not_started"
|
|
|
+ },
|
|
|
+ postProcessing: {
|
|
|
+ deadline: postProcessingDeadline,
|
|
|
+ estimatedDays: 3,
|
|
|
+ status: "not_started"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ project.set("data", data);
|
|
|
+ await project.save(null, { useMasterKey: true });
|
|
|
+ count++;
|
|
|
+
|
|
|
+ message(`Migrated ${count} projects`);
|
|
|
+ }
|
|
|
+
|
|
|
+ message(`Migration completed: ${count} projects updated`);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## ⚙️ 配置建议
|
|
|
+
|
|
|
+### 默认工期配置
|
|
|
+
|
|
|
+建议在Company.data中添加默认工期配置:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "phaseDefaultDurations": {
|
|
|
+ "modeling": 7, // 建模默认7天
|
|
|
+ "softDecor": 4, // 软装默认4天
|
|
|
+ "rendering": 6, // 渲染默认6天
|
|
|
+ "postProcessing": 3 // 后期默认3天
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 使用配置创建项目
|
|
|
+
|
|
|
+```typescript
|
|
|
+async createProjectWithDefaultPhases(
|
|
|
+ projectData: any,
|
|
|
+ companyId: string
|
|
|
+): Promise<Parse.Object> {
|
|
|
+ // 获取公司配置
|
|
|
+ const companyQuery = new Parse.Query('Company');
|
|
|
+ const company = await companyQuery.get(companyId);
|
|
|
+ const companyData = company.get('data') || {};
|
|
|
+ const durations = companyData.phaseDefaultDurations || {
|
|
|
+ modeling: 7,
|
|
|
+ softDecor: 4,
|
|
|
+ rendering: 6,
|
|
|
+ postProcessing: 3
|
|
|
+ };
|
|
|
+
|
|
|
+ // 计算各阶段截止时间
|
|
|
+ const startDate = new Date();
|
|
|
+ const phaseDeadlines: any = {};
|
|
|
+ let currentDate = new Date(startDate);
|
|
|
+
|
|
|
+ ['modeling', 'softDecor', 'rendering', 'postProcessing'].forEach(phase => {
|
|
|
+ const days = durations[phase];
|
|
|
+ const deadline = new Date(currentDate.getTime() + days * 24 * 60 * 60 * 1000);
|
|
|
+
|
|
|
+ phaseDeadlines[phase] = {
|
|
|
+ startDate: new Date(currentDate),
|
|
|
+ deadline: deadline,
|
|
|
+ estimatedDays: days,
|
|
|
+ status: phase === 'modeling' ? 'in_progress' : 'not_started',
|
|
|
+ priority: 'medium'
|
|
|
+ };
|
|
|
+
|
|
|
+ currentDate = new Date(deadline.getTime() + 1); // 下一阶段从前一阶段结束后开始
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建项目
|
|
|
+ const Project = Parse.Object.extend('Project');
|
|
|
+ const project = new Project();
|
|
|
+ project.set('data', { phaseDeadlines, ...projectData.data });
|
|
|
+ // ... 设置其他字段
|
|
|
+
|
|
|
+ await project.save(null, { useMasterKey: true });
|
|
|
+ return project;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📝 注意事项
|
|
|
+
|
|
|
+### 1. 数据验证
|
|
|
+- 确保`deadline`字段为有效的Date对象
|
|
|
+- 确保阶段顺序逻辑正确(前一阶段结束 < 下一阶段开始)
|
|
|
+- 状态枚举值必须在允许范围内
|
|
|
+
|
|
|
+### 2. 性能优化
|
|
|
+- Parse Query不支持深层嵌套查询,需要在前端过滤
|
|
|
+- 大量项目查询时建议使用Cloud Code
|
|
|
+- 考虑添加索引优化查询性能
|
|
|
+
|
|
|
+### 3. 兼容性
|
|
|
+- 保持向后兼容,旧项目可能没有`phaseDeadlines`字段
|
|
|
+- 代码中需要做空值检查:`project.get('data')?.phaseDeadlines`
|
|
|
+
|
|
|
+### 4. 扩展性
|
|
|
+- 可以根据项目类型(软装/硬装)调整默认工期
|
|
|
+- 可以添加更多阶段(如量房、方案设计等)
|
|
|
+- 可以为每个阶段添加子任务
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🎯 实施步骤
|
|
|
+
|
|
|
+### 第一步:更新schemas.md文档
|
|
|
+在Project表的data字段说明中添加phaseDeadlines结构说明
|
|
|
+
|
|
|
+### 第二步:编写数据迁移脚本
|
|
|
+为现有项目添加默认的阶段截止时间
|
|
|
+
|
|
|
+### 第三步:更新前端类型定义
|
|
|
+添加PhaseInfo和PhaseDeadlines接口定义
|
|
|
+
|
|
|
+### 第四步:修改项目创建逻辑
|
|
|
+在创建项目时自动生成阶段截止时间
|
|
|
+
|
|
|
+### 第五步:更新时间轴组件
|
|
|
+读取并展示阶段截止时间信息
|
|
|
+
|
|
|
+### 第六步:添加阶段管理界面
|
|
|
+允许手动调整各阶段的截止时间和状态
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## ✅ 总结
|
|
|
+
|
|
|
+通过在`Project.data.phaseDeadlines`中存储各阶段截止时间信息:
|
|
|
+
|
|
|
+1. ✅ **灵活性**:Object类型允许自由扩展,易于添加新阶段
|
|
|
+2. ✅ **清晰性**:每个阶段的信息结构一致,便于维护
|
|
|
+3. ✅ **可视化**:为项目负载时间轴提供完整的阶段数据支持
|
|
|
+4. ✅ **兼容性**:不影响现有表结构,易于向后兼容
|
|
|
+5. ✅ **扩展性**:支持添加负责人、优先级、备注等更多信息
|
|
|
+
|
|
|
+建议按照本方案实施,可以有效支持项目负载图的阶段查看功能。
|
|
|
+
|