使用trae solo辅助项目关键路径计算

项目管理系统开发实践

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 示例

任务的最晚完成期限使用日历控件选择日期,而非输入字符串 每次变更后,数据库表结构自行变更,保留历史数据,而非删库重建

踩过的坑

  1. 日期格式混乱:内部存储"X月Y日"格式,前端显示需转换,曾因基准日期不一致导致显示错误
  2. 任务识别逻辑_find_end_task() 曾要求 is_milestone=True,导致遗漏"项目结束"任务
  3. 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 等逻辑问题

可复用方法

  1. 渐进式开发:先实现核心功能(任务 CRUD + CPM 计算),再优化用户体验(日历控件、网络图布局)
  2. 诊断优先:遇到问题时先写诊断脚本(如 diagnose.py)定位问题根源
  3. 配置外部化:日期基准等可变配置存储在数据库 Setting 表,而非硬编码

改进空间

  • 当前仅支持单用户,可扩展为多用户协作
  • 网络图可增加交互功能(点击节点查看详情)
  • 可导出 PDF/Excel 格式的项目计划文档