时间轴原型:从 CSV 静态展示到拖动编辑的三阶段计划
一个面向个人项目计划维护的最小时间轴工具方案:先完成 CSV 驱动的静态展示,再加入界面编辑,最后实现拖动与缩放。
1. 目标
这个原型不试图替代 Microsoft Project、ProductPlan 或完整的项目管理平台。
目标只解决一个明确问题:
用一行表示一个 Workstream,并在同一行中显示多个任务块,从而更直观地维护 Hardware、Firmware、Software、Certification 等跨团队计划。
预期界面:
┌──────────────┬──────────────────────────────────────────────┐
│ Workstream │ Aug 1 Aug 8 Aug 15 Aug 22 │
├──────────────┼──────────────────────────────────────────────┤
│ Hardware │ █ Requirement █ Schematic █ PCB █ EVT │
│ Firmware │ █ Architecture █ Driver █ Test │
│ Software │ █ Design █ Development █ Verify │
│ Certification│ █ EMC █ Safety │
└──────────────┴──────────────────────────────────────────────┘
开发分为三个阶段:
- CSV 驱动的静态展示。
- 在展示界面直接编辑。
- 支持拖动和 Resize。
这样可以先验证时间轴展示是否真的有用,再逐步增加交互复杂度。
2. 技术边界
第一版采用纯前端方案:
React
TypeScript
Vite
Papa Parse
date-fns
普通 HTML / CSS
localStorage
暂时不需要:
- 后端服务
- 数据库
- 用户登录
- 多人协作
- AI
- 复杂资源管理
- 自动关键路径
- Jira 或 Azure DevOps 集成
数据来源是 CSV。程序将 CSV 解析成内部任务数组,再绘制时间轴。
CSV 文本或文件
↓
CSV Parser
↓
Task[]
↓
Timeline View
↓
重新生成 CSV
localStorage 只作为浏览器内的临时保存,避免刷新页面后丢失当前 CSV 内容。真正的可移植备份仍然是导出的 CSV 文件。
3. CSV 数据格式
第一版统一使用以下字段:
id,workstream,name,start,end
HW-001,Hardware,Requirement,2026-08-01,2026-08-05
HW-002,Hardware,Schematic,2026-08-06,2026-08-14
HW-003,Hardware,PCB Layout,2026-08-15,2026-08-25
FW-001,Firmware,Driver Development,2026-08-12,2026-08-28
SW-001,Software,Integration Test,2026-08-24,2026-09-05
CERT-001,Certification,EMC Test,2026-09-01,2026-09-08
内部数据模型:
type Task = {
id: string;
workstream: string;
name: string;
start: string;
end: string;
};
约束:
id必须唯一。- 日期统一使用
YYYY-MM-DD。 end不能早于start。workstream相同的任务显示在同一行。- CSV 中的任务顺序不决定横向位置,日期决定位置。
id 从第一阶段就必须保留,因为第二阶段编辑和第三阶段拖动都需要稳定识别同一个任务。
第一阶段:CSV 编辑与静态时间轴
4. 第一阶段目标
第一阶段只完成数据展示,不支持直接操作任务块。
界面分成左右两个区域:
┌──────────── CSV 编辑区 ────────────┬──────── 时间轴预览 ────────┐
│ id,workstream,name,start,end │ Hardware █ Req █ PCB │
│ HW-001,Hardware,Requirement,... │ Firmware █ Driver │
│ HW-002,Hardware,Schematic,... │ Software █ Test │
└────────────────────────────────────┴─────────────────────────────┘
用户流程:
导入 CSV
↓
网页内显示 CSV 文本
↓
用户修改 CSV 文本
↓
程序重新解析
↓
时间轴自动刷新
↓
导出新的 CSV
网页不能稳定、跨浏览器地持续监控 Excel 中正在编辑的本地 CSV。因此第一阶段的“自动刷新”指:
在网页内的 CSV 编辑器中修改内容,右侧时间轴实时刷新。
用户在 Excel 中修改后,需要重新导入文件。
5. 第一阶段功能需求
5.1 CSV 输入
- 提供文件导入按钮。
- 支持拖入
.csv文件。 - 提供内置示例 CSV。
- 在文本编辑区中显示完整 CSV。
- 输入变化后进行短暂 debounce,再重新解析。
5.2 时间轴展示
- 左侧显示 Workstream 名称。
- 每个 Workstream 占一行。
- 同一 Workstream 支持多个任务块。
- 任务块显示任务名称。
- 横轴显示日期。
- 支持跨月份显示。
- 时间轴范围根据最早开始日期和最晚结束日期自动计算。
- 页面支持横向滚动。
- 左侧 Workstream 列在横向滚动时保持固定。
5.3 数据校验
错误不能让整个页面崩溃。
需要识别:
- 缺失必填列
- 重复
id - 无效日期
end < start- 空 Workstream
- 空任务名称
- 多余列
错误提示应包含 CSV 行号,例如:
第 4 行:end 不能早于 start
第 7 行:任务 ID “HW-002” 重复
存在错误时:
- 保留用户输入。
- 显示错误列表。
- 只渲染可安全解析的数据,或者停止刷新并保留上一次有效预览。
建议第一版采用“保留上一次有效预览”,避免错误输入导致时间轴频繁闪烁。
5.4 导出与恢复
- 导出当前 CSV。
- 文件名包含日期,例如
timeline-2026-08-03.csv。 - 将当前 CSV 文本保存到
localStorage。 - 页面刷新后恢复上一次内容。
- 提供“恢复示例数据”按钮。
6. 第一阶段开发任务
Task 1:建立项目
- 创建 Vite + React + TypeScript 项目。
- 配置 ESLint 和基础测试。
- 创建页面布局。
- 准备示例 CSV。
Task 2:实现 CSV 解析
- 使用 Papa Parse。
- 将 CSV 转换为
Task[]。 - 增加字段校验。
- 返回结构化错误信息。
- 增加解析单元测试。
Task 3:实现日期与坐标转换
type TimelineScale = {
startDate: Date;
endDate: Date;
pixelsPerDay: number;
};
需要实现:
- 日期转 X 坐标。
- 起止日期转任务块宽度。
- 自动计算时间轴边界。
- 至少增加前后各 3 天留白。
Task 4:实现静态时间轴
组件建议:
src/
├── components/
│ ├── CsvEditor.tsx
│ ├── Timeline.tsx
│ ├── TimelineHeader.tsx
│ ├── WorkstreamRow.tsx
│ ├── TaskBar.tsx
│ └── ValidationPanel.tsx
├── models/
│ └── task.ts
├── utils/
│ ├── csv.ts
│ ├── dates.ts
│ └── timeline.ts
├── data/
│ └── sample.csv
└── App.tsx
即使 TaskBar 第一阶段不可操作,也应独立成组件,便于后续加入编辑和拖动。
Task 5:导入、导出和本地保存
- 文件选择器导入。
- 拖放导入。
- Blob 下载导出。
- localStorage 自动保存。
- 初始化时恢复。
Task 6:完成基础样式
- 固定左侧 Workstream 列。
- 时间轴水平滚动。
- 表头与任务行对齐。
- 任务块宽度过小时显示 tooltip。
- 长任务名称省略显示。
7. 第一阶段完成标准
第一阶段完成时应满足:
- 可以导入 CSV。
- 可以在网页内编辑 CSV。
- 编辑后时间轴自动刷新。
- 同一 Workstream 的多个任务显示在同一行。
- 能正确显示跨月份日期表头。
- 错误日期和缺失字段有明确提示。
- 可以导出修改后的 CSV。
- 刷新页面后能恢复上一次内容。
- 没有后端和数据库依赖。
npm run build和测试全部通过。
预计开发时间:3—6 小时。
第二阶段:在展示界面直接编辑
8. 第二阶段目标
第二阶段不再要求用户必须编辑 CSV 文本。
用户可以点击时间轴中的任务块,通过表单编辑:
点击任务块
↓
打开右侧编辑面板
↓
修改名称、Workstream、开始日期和结束日期
↓
保存
↓
时间轴更新
↓
CSV 文本同步更新
CSV 仍然是可导入、可导出的交换格式,但程序内部的主状态变为 Task[]。
9. 第二阶段功能需求
- 点击任务块选中任务。
- 右侧显示任务编辑表单。
- 修改任务名称。
- 修改 Workstream。
- 修改开始和结束日期。
- 新建任务。
- 删除任务。
- 新建 Workstream。
- 复制任务。
- 保存后同步生成 CSV。
- CSV 文本编辑与界面编辑保持双向同步。
- 表单校验复用第一阶段规则。
为了避免循环更新,状态流应保持单一方向:
CSV 导入
↓
Task[] 作为主状态
↓
Timeline + Form
↓
用户编辑 Task[]
↓
重新生成 CSV 文本
当用户直接编辑 CSV 文本并通过校验后,才用新的 Task[] 替换当前主状态。
10. 第二阶段开发任务
Task 1:建立统一状态模型
- 将
Task[]设为应用主状态。 - CSV 文本作为派生数据或待解析输入。
- 明确“最后一次有效 CSV”与“当前编辑文本”的区别。
Task 2:任务选择
- TaskBar 支持点击。
- 高亮当前任务。
- 空白区域点击取消选择。
Task 3:任务编辑面板
- 文本字段。
- Workstream 下拉框。
- 日期字段。
- 保存和取消。
- 删除确认。
Task 4:新增与复制
- 新建任务时自动生成唯一 ID。
- 默认日期使用当前时间轴可见范围。
- 复制任务时生成新 ID。
Task 5:同步 CSV
Task[]变化后重新生成规范 CSV。- 保持固定列顺序。
- 正确处理逗号、双引号和换行。
Task 6:Undo 基础
第二阶段可以加入简单 Undo:
type HistoryState = {
past: Task[][];
present: Task[];
future: Task[][];
};
第一版只需支持最近 20—50 次修改。
11. 第二阶段完成标准
- 可以点击并编辑任务。
- 可以新增、删除和复制任务。
- 可以修改任务所属 Workstream。
- 修改后时间轴立即更新。
- CSV 同步更新并可导出。
- 无效输入无法保存。
- 刷新后保留最新状态。
- 至少支持一次 Undo。
预计开发时间:4—8 小时。
第三阶段:拖动和 Resize
12. 第三阶段目标
第三阶段增加直接操作时间轴的能力:
- 拖动任务改变日期。
- 从左侧 Resize 改变开始日期。
- 从右侧 Resize 改变结束日期。
- 所有变化同步到任务状态和 CSV。
13. 拖动需求
横向拖动规则:
- 只改变日期,不改变 Workstream。
- 按完整自然日吸附。
- 保持任务持续时间不变。
- 拖动中显示新的开始和结束日期。
- 拖动结束后才正式写入状态。
Escape取消当前拖动。- 拖动后可以 Undo。
处理流程:
drag start
↓
保存原始任务状态
↓
drag move
↓
计算像素偏移对应的天数
↓
显示预览位置和日期
↓
drag end
↓
提交一次 Task[] 更新
不要在每一个 pointer move 事件中重写 CSV 或 localStorage。
14. Resize 需求
任务块左右两侧增加 Resize Handle:
◄████████████►
规则:
- 左侧手柄修改开始日期。
- 右侧手柄修改结束日期。
- 最短持续时间为 1 天。
- 不能出现
end < start。 - 按完整日吸附。
- Resize 时显示日期预览。
- 完成后同步 CSV。
- 支持 Undo。
15. 第三阶段开发任务
Task 1:Pointer Event 基础
优先使用 Pointer Events,而不是分别处理 mouse 和 touch:
pointerdownpointermovepointeruppointercancel- pointer capture
Task 2:拖动状态
type DragState = {
taskId: string;
originX: number;
currentX: number;
originalStart: string;
originalEnd: string;
};
Task 3:像素与日期换算
- 使用当前
pixelsPerDay。 - 将 X 偏移转换为整数天。
- 处理横向滚动后的坐标。
- 处理浏览器缩放。
Task 4:Resize
- 左右手柄独立事件。
- 阻止 TaskBar 拖动与 Resize 事件冲突。
- 增加最小宽度。
Task 5:滚动与边界
- 拖到视口边缘时可以后续增加自动滚动。
- 第一版可以限制在已有时间轴范围内。
- 任务移出当前范围后,自动扩展时间轴边界。
Task 6:测试
重点测试:
- 跨月份拖动。
- 闰年和月份天数。
- 时区导致的日期偏移。
- 横向滚动后的拖动。
- 连续多次 Undo/Redo。
- 拖动中按 Escape。
- Resize 到 1 天。
16. 第三阶段完成标准
- 任务可以按天横向拖动。
- 拖动保持持续时间不变。
- 左右手柄可以修改开始和结束日期。
- 拖动和 Resize 的日期预览正确。
- 修改后 CSV 自动同步。
- 支持 Undo/Redo。
- 横向滚动后仍能正确计算日期。
- 跨月份操作没有日期偏移。
预计开发时间:1—2 天。
17. 建议的开发顺序
Phase 1A Vite 项目与页面骨架
Phase 1B CSV 解析和校验
Phase 1C 静态时间轴
Phase 1D 导入、导出、localStorage
↓
Phase 2A 统一 Task[] 状态
Phase 2B 任务选择和编辑面板
Phase 2C 新增、删除、复制
Phase 2D CSV 双向同步和 Undo
↓
Phase 3A 拖动预览
Phase 3B 拖动提交
Phase 3C 左右 Resize
Phase 3D 边界测试和稳定性处理
每个阶段都应该能够独立运行和交付,不要在第一阶段预先实现第三阶段的复杂交互。
18. Codex 开发方式
可以直接使用 Codex 开发,但应按阶段给任务,而不是一次要求完成完整项目。
第一阶段提示词可以是:
Create a Vite project using React and TypeScript.
Build phase 1 of a project timeline prototype.
Requirements:
1. Import a CSV file with columns id, workstream, name, start, end.
2. Show the CSV in an editable text area.
3. Re-parse the CSV after edits and automatically refresh the timeline.
4. Display one row per workstream.
5. Display multiple task bars in the same workstream row.
6. Use normal HTML and CSS, not Canvas.
7. Add validation for required columns, duplicate IDs, invalid dates, and end dates earlier than start dates.
8. Add CSV export.
9. Save the current CSV text in localStorage.
10. Do not add a backend, database, authentication, drag-and-drop, or task editing forms.
11. Add tests for CSV parsing and date-to-pixel conversion.
12. Run npm test and npm run build, and fix all errors.
第二阶段和第三阶段应在第一阶段验收后分别提交新的 Codex 任务。
19. 总体时间估计
| 阶段 | 预计时间 | 交付结果 |
|---|---|---|
| 第一阶段 | 3—6 小时 | CSV 可编辑、静态时间轴、导入导出 |
| 第二阶段 | 4—8 小时 | 时间轴内新增、修改、删除任务 |
| 第三阶段 | 1—2 天 | 拖动、Resize、Undo/Redo |
| 样式和稳定性 | 0.5—1 天 | 处理边界情况并改善实际使用体验 |
整体预计:2—4 天可以完成一个实际可用的个人原型。
最重要的验收顺序是:
先证明静态时间轴比原始 Excel 更容易阅读,再证明界面编辑比修改 CSV 更方便,最后才证明拖动操作值得增加其开发和维护成本。