更新时间:2026-05-02
负责:
- TipTap 所见即所得编辑器集成
- A4 尺寸编辑画布(CSS 固定 210mm × 297mm)
- 富文本编辑:加粗、斜体、下划线、字号、颜色、对齐、行距
- 列表:有序/无序
- 图片:上传头像、拖拽调整
- Section 拖拽排序
- 原生 undo/redo(ProseMirror 内置)
- 自动保存(debounce 2 秒)
不负责:
- AI 对话(agent 的事)
- 版本管理和 PDF 导出(render 的事)
- 文件解析(parsing 的事)
| 数据 | 来源 | 说明 |
|---|---|---|
drafts.html_content |
模块 parsing/agent | 当前简历 HTML |
Mock:直接用 fixtures/sample_draft.html 加载到编辑器。
编辑后的 HTML 写入 drafts.html_content。
通过 PUT /api/v1/drafts/{draft_id} 保存。
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/drafts/{draft_id} |
获取草稿 HTML |
| PUT | /api/v1/drafts/{draft_id} |
保存草稿 HTML(自动保存) |
| POST | /api/v1/drafts |
为项目创建空白草稿 |
Request:
{
"project_id": 1
}
Response (200):
{
"code": 0,
"data": {
"id": 2,
"project_id": 1,
"html_content": "",
"updated_at": "2026-04-29T12:00:00Z"
}
}
Response (404, project not found):
{
"code": 4003,
"data": null,
"message": "project not found"
}
Response (409, project already has draft):
{
"code": 4004,
"data": null,
"message": "project already has a current draft"
}
为指定项目创建空白草稿并自动设置
project.current_draft_id。 仅当项目无当前草稿时允许创建(current_draft_id为 null)。
Response:
{
"code": 0,
"data": {
"id": 1,
"project_id": 1,
"html_content": "<!DOCTYPE html>...",
"updated_at": "2026-04-23T20:00:00Z"
}
}
Request:
{
"html_content": "<!DOCTYPE html>...编辑后的 HTML...",
"create_version": true,
"version_label": "AI 修改:精简项目经历"
}
Response:
{
"code": 0,
"data": {
"id": 1,
"updated_at": "2026-04-23T20:05:00Z",
"version_id": 5
}
}
create_version(可选,默认 false):自动保存时不传,仅当需要创建版本快照时传 true。version_label(可选,默认 "手动保存"):版本标签,配合create_version使用。自动保存(debounce 2s)不触发版本创建,避免版本爆炸。
| 功能 | TipTap 扩展 | 说明 |
|---|---|---|
| 加粗 | @tiptap/extension-bold |
Ctrl+B |
| 斜体 | @tiptap/extension-italic |
Ctrl+I |
| 下划线 | @tiptap/extension-underline |
Ctrl+U |
| 字号 | 自定义 | 下拉选择 9-14pt |
| 颜色 | @tiptap/extension-color |
颜色选择器 |
| 对齐 | @tiptap/extension-text-align |
左/中/右/两端 |
| 行距 | 自定义 | 1.0 / 1.2 / 1.5 / 1.8 / 2.0 |
| 有序列表 | @tiptap/extension-ordered-list |
— |
| 无序列表 | @tiptap/extension-bullet-list |
— |
| 撤销 | ProseMirror 内置 | Ctrl+Z |
| 重做 | ProseMirror 内置 | Ctrl+Shift+Z |
- 头像上传:通过图片选择器选择本地图片,上传到服务器,插入
<img>标签 - 图片拖拽调整:使用
@tiptap-pro/extension-resize-image或自定义拖拽逻辑
- 使用
@dnd-kit/core或 ProseMirror 原生拖拽实现 section 级别的拖拽排序
- 监听 TipTap 的
update事件 - debounce 2 秒后调用
PUT /api/v1/drafts/{draft_id} - 保存状态指示:保存中(旋转图标) / 已保存(勾号)
.editor-canvas {
width: 210mm;
min-height: 297mm;
padding: 18mm 20mm;
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
margin: 0 auto;
}
/* 缩放适应屏幕 */
.editor-wrapper {
transform-origin: top center;
transform: scale(var(--canvas-scale));
}编辑器内容使用简历 HTML 模板骨架中定义的 CSS class(.resume, .profile, .section, .item 等)。
- 模块 parsing 产出初始 drafts.html_content
- 模块 agent 通过 AI 对话修改 HTML(两种方式):
- 原有:AI 返回 HTML → 前端"应用到简历" →
PUT /api/v1/drafts/{draft_id} - 新增(v2):AI 通过
save_drafttool 直接写入drafts表,workbench 编辑器可通过轮询或 SSE 事件感知更新
- 原有:AI 返回 HTML → 前端"应用到简历" →
- 模块 render 消费 drafts.html_content(创建版本快照、PDF 导出)
- 模块 render(当 create_version=true 时,创建版本快照)
- 不需要 parsing/agent/render 的服务
- 前端可完全独立开发,用 mock HTML 加载编辑器
| 错误码 | HTTP | 含义 |
|---|---|---|
| 4001 | 404 | 草稿不存在 |
| 4002 | 400 | HTML 内容为空 |
| 4003 | 404 | 项目不存在(创建草稿时) |
| 4004 | 409 | 项目已有当前草稿 |
- 用
fixtures/sample_draft.html加载编辑器 - 测试各种编辑操作的正确性
- 测试自动保存逻辑
- 不需要其他模块的服务
- 编辑器渲染:HTML 正确渲染为所见即所得
- 工具栏:各格式按钮功能正确
- 自动保存:编辑后 debounce 2 秒触发保存
- 缩放:A4 画布在不同屏幕尺寸下正确缩放