项目管理系统开发实践
1. 摘要
使用 TRAE SOLO 开发了一套项目管理辅助Web 应用,实现了任务拆解、关键路径计算(CPM)和项目网络图可视化功能。该系统通过图形化方式展示任务依赖关系,自动计算关键路径,显著提升了项目规划效率。
2. 背景
作为一名全栈开发工程师,在实际项目中经常需要制定项目计划、拆解任务、协调依赖关系。传统方式需要使用 Excel 或专业项目管理软件(如 MS Project),操作繁琐且缺乏可视化。项目团队需要一个轻量级的工具,能够:
- 快速录入任务和工期
- 设置任务依赖关系
- 自动计算关键路径
- 可视化展示项目网络图
3. 实践过程
任务拆解
第一阶段:基础功能实现
- 设计数据库模型(Task、TaskDependency、Setting 表)
- 实现 CRUD API 端点
- 构建响应式前端界面
第二阶段:CPM 计算逻辑
- 正序计算 ES/EF:基于项目最早开始日期,根据前置任务依赖顺序计算
- 倒序计算 LS/LF:以"项目结束"任务的最晚完成期限为基准倒推
- 截止日期约束:确保任务 LF 不晚于自身设置的截止日期
第三阶段:用户体验优化
- 日期输入从文本框改为日历控件(HTML5 date input)
- 实现数据库迁移方案(Flask-Migrate),保留历史数据
- 网络图采用分层布局,前置任务在左,后继任务在右
使用 SOLO 能力
代码生成与重构
- 使用 SOLO 生成 Flask 路由、SQLAlchemy 模型、CPM 计算逻辑
- 自动处理日期格式转换、数据库迁移等复杂逻辑
问题排查
- 遇到
_calculate_slack方法缺失错误时,使用 SOLO 分析堆栈跟踪 - 通过诊断脚本定位"项目结束"任务识别逻辑问题
持续迭代
- 根据测试反馈快速调整网络图布局算法
- 优化日期计算函数,支持动态基准日期
关键 Prompt 示例
任务的最晚完成期限使用日历控件选择日期,而非输入字符串 每次变更后,数据库表结构自行变更,保留历史数据,而非删库重建
踩过的坑
- 日期格式混乱:内部存储"X月Y日"格式,前端显示需转换,曾因基准日期不一致导致显示错误
- 任务识别逻辑:
_find_end_task()曾要求is_milestone=True,导致遗漏"项目结束"任务 - CPM 计算顺序:必须先设置结束任务 LF,再倒序计算其他任务,否则依赖链断裂
4. 成果展示
在线演示截图:
核心功能:
- 任务管理:增删改查、设置工期和前置依赖
- 关键路径计算:自动识别关键任务(红色标记)
- 项目网络图:分层布局,依赖关系一目了然
- 日期配置:日历控件选择,数据库自动迁移
技术栈:
- 后端:Python Flask + SQLAlchemy + Flask-Migrate
- 前端:HTML5 + JavaScript(原生)
- 可视化:NetworkX + Matplotlib
- 数据库:SQLite
关键代码示例(CPM 倒序计算):
def _forward_pass(self):
"""正序计算ES/EF:从项目最早开始日期开始,根据前置任务顺序计算
规则:
1. 没有前置任务的任务:ES = 0(相对于项目最早开始日期)
2. 有前置任务的任务:ES = max(所有前置任务的EF)
3. EF = ES + 工期
"""
try:
sorted_tasks = list(nx.topological_sort(self.graph))
except:
return
for task_id in sorted_tasks:
task = Task.query.get(task_id)
if not task:
continue
predecessors = list(task.predecessors)
if not predecessors:
task.es = 0
else:
task.es = max(p.ef for p in predecessors)
task.ef = task.es + task.duration
def _backward_pass(self):
"""倒序计算LS/LF:从项目结束任务的最晚完成期限开始,倒序计算
规则:
1. 项目结束任务的 LF = 其最晚完成期限(或 EF)
2. 项目结束任务的 LS = LF - 工期
3. 其他任务:
- 有后继任务:LF = min(所有后继任务的 LS)
- 无后继任务:LF = 项目结束任务的 LF
4. 如果任务本身设置了最晚完成期限,LF = min(计算出的LF, 任务截止日期)
5. LS = LF - 工期
"""
try:
sorted_tasks = list(nx.topological_sort(self.graph))
except:
return
sorted_tasks.reverse()
if self.end_task:
self.end_task.lf = self.project_lf
self.end_task.ls = self.end_task.lf - self.end_task.duration
print(f"设置结束任务 {self.end_task.name} LF={self.end_task.lf}, LS={self.end_task.ls}")
for task_id in sorted_tasks:
task = Task.query.get(task_id)
if not task:
continue
if task.is_project_end:
continue
if self.end_task and task.id == self.end_task.id:
continue
successors = list(task.successors)
if not successors:
if self.end_task:
task.lf = self.end_task.lf
else:
task.lf = self.project_lf
else:
valid_ls = [s.ls for s in successors if s.ls is not None]
if valid_ls:
task.lf = min(valid_ls)
else:
if self.end_task:
task.lf = self.end_task.lf
else:
task.lf = self.project_lf
if task.deadline:
deadline_days = parse_date_to_days(task.deadline, self.project_start_date)
if deadline_days is not None and deadline_days < task.lf:
print(f"任务 {task.name} deadline约束: {task.lf} -> {deadline_days}")
task.lf = deadline_days
task.ls = task.lf - task.duration
5. 效果与总结
效率提升:
- 原本使用 Excel 手动计算关键路径需要 1-2 小时,现在系统自动计算仅需几秒
- 日期配置从手动输入改为点选,减少输入错误
SOLO 在流程中的作用:
- 快速原型开发:从需求到可运行 Demo 仅需 1-2 小时
- 智能代码补全:熟悉 Flask 生态,提供正确的 API 使用建议
- 错误定位:帮助快速识别
_find_end_task等逻辑问题
可复用方法:
- 渐进式开发:先实现核心功能(任务 CRUD + CPM 计算),再优化用户体验(日历控件、网络图布局)
- 诊断优先:遇到问题时先写诊断脚本(如
diagnose.py)定位问题根源 - 配置外部化:日期基准等可变配置存储在数据库 Setting 表,而非硬编码
改进空间:
- 当前仅支持单用户,可扩展为多用户协作
- 网络图可增加交互功能(点击节点查看详情)
- 可导出 PDF/Excel 格式的项目计划文档

