1. 页面概览
1.1 是什么
「任务看板」页面(页面内标题为 Gotham 任务看板,TAD-11)是 LightGotham 的项目任务协作看板:选择一个「我参与的」项目,把项目内分析任务按 待办 → 进行中 → 审核 → 完成 四列排布,支持卡片拖拽流转、新建/编辑任务、按成员指派负责人并关联图实体。它是项目协作页的延续——项目管「人」,看板管「事」。
1.2 核心价值
| 维度 | 说明 |
|---|---|
| 四列看板 | todo(待办)/ in_progress(进行中)/ review(审核)/ done(完成),每列带任务计数 |
| 拖拽流转 | HTML5 原生拖拽把卡片拖到目标列即调用状态机流转;失败可点卡片「置为」下拉兜底(与拖拽同接口) |
| 渲染层分页 | 后端任务列表无 limit/offset,页面按每列 20 条做本地切片分页 |
| 任务编辑 | 标题/描述/优先级/负责人/关联实体 ID/截止日期,新建与编辑共用抽屉 |
| 负责人指派 | assignee 选项来自项目成员列表,指派后任务状态变更会通知负责人 |
| 状态机约束 | 后端强制 todo→in_progress→review→done(含回退),非法流转返回 409 |
1.3 一句话总结
2. 访问入口
2.1 路由与菜单
- 路由:
/gotham/tasks;路由名称:GothamTasks - 路由 meta:
title: Gotham 任务看板,requiresAuth: true,挂在父路由/gotham(GothamLayout)下 - 菜单位置:Gotham 左侧边栏「协作工作流」分组下的「任务看板」
- 前端源码:
action/web/src/views/GothamTasksPage.vue - API 客户端:
action/web/src/api/gothamClient.js
2.2 认证与权限
- 路由挂
requiresAuth: true,未登录访问被全局守卫重定向到/login。 - 请求走 gothamClient:请求拦截器自动附带
Authorization: Bearer <aip_token>;响应拦截器遇 401 时用gotham_refresh_token换发新 token 并重放原请求。 - 后端 collab 服务按成员角色鉴权:读任务需项目成员,写任务(创建/流转/编辑/删除)需 owner/editor。
2.3 端口与 API 前缀
- Gotham 后端端口:18083(Vite 将
/gotham-api前缀代理到该端口并重写为/api/v1)。 - API 前缀:
/gotham-api/v1(gothamClient 的 baseURL)。
3. 界面布局
页面为「顶部选择栏 + 四列看板」布局:
┌──────────────────────────────────────────────────────────────┐
│ Gotham 任务看板 [选择项目▾] [刷新] [新建任务] │
│ [alert 操作结果提示条(可关闭)] │
│ ┌ 待办(2) ┐ ┌ 进行中(1) ┐ ┌ 审核(0) ┐ ┌ 完成(3) ┐ │
│ │ [任务卡] │ │ [任务卡] │ │ │ │ [任务卡] │ │
│ │ 标题 │ │ 标题 │ │ 拖拽任务 │ │ 标题 │ │
│ │ 优先级@人 │ │ 优先级@人 │ │ 到此列 │ │ 优先级@人 │ │
│ │ 编辑置为▾│ │ 编辑置为▾ │ │ │ │ 编辑置为▾│ │
│ │ 删除 │ │ 删除 │ │ │ │ 删除 │ │
│ └─────────┘ └──────────┘ └─────────┘ └─────────┘ │
│ [分页 ‹ 1/2 ›](某列任务数 > 每页 20 时出现) │
│ [board-note:后端任务列表无 limit/offset,本页按列渲染层分页] │
└──────────────────────────────────────────────────────────────┘
┌ 任务编辑抽屉:新建任务 / 编辑任务 [关闭] ────────┐
│ 标题 */描述/优先级/负责人/关联实体ID(JSON数组)/截止日期 │
│ [创建任务|保存修改] │
└──────────────────────────────────────────────────┘
- 顶部选择栏:项目下拉 + 「刷新」+「新建任务」(未选项目时禁用)。
- 四列看板:每列列头为状态名 + 计数;未选项目时整块显示「请先选择项目加载任务看板。」某列任务数超过每页 20 条时,列底出现「‹ 上一页 / 第 n 页 / 下一页 ›」渲染层分页(保留四列语义,不改变后端加载行为)。
- 任务卡片:标题、优先级徽标、负责人
@id,下方「编辑 / 置为▾ / 删除」。 - 编辑抽屉:右侧滑出,新建与编辑共用表单;关联实体 ID 为 JSON 数组输入。
4. 交互元素
| 控件 | 位置 | 含义与作用 |
|---|---|---|
| 项目下拉「选择项目」 | 页头左侧 | 列出「我参与的」项目(#id 名称),切换即加载该项目的任务与成员 |
| 「刷新」按钮 | 页头 | 重载项目、任务与成员列表 |
| 「新建任务」按钮 | 页头 | 打开任务编辑抽屉(未选项目时置灰) |
| 任务卡片(拖拽) | 看板 | HTML5 拖拽到目标列后调用状态流转接口;目标列拖入时高亮(col-over) |
| 「置为▾」下拉 | 卡片操作列 | 拖拽失败兜底:只列出后端状态机允许的目标状态(如 todo→进行中;in_progress→待办/审核;review→进行中/完成),选中即调用与拖拽同一个 POST /collab/tasks/:id/transition;done 等终态显示「终态」不可选 |
| 「编辑」 | 卡片操作列 | 打开编辑抽屉并回填任务字段 |
| 「删除」 | 卡片操作列 | confirm 确认「确认删除任务「title」?」后删除 |
| 分页器 | 各列底部 | 该列任务数 > 每页 20 条时出现「‹ / 第 n 页 / ›」;翻页只切本地切片,不请求后端(后端任务列表无 limit/offset) |
| 编辑抽屉表单 | 抽屉 | 标题 *、描述、优先级(high/medium/low)、负责人 assignee(选项来自项目成员,含「(未分配)」)、关联实体 ID(JSON 数组字符串,如 ["graph:org:xuanwu"])、截止日期(date) |
| 「创建任务」「保存修改」 | 抽屉底部 | 提交创建/更新;标题必填,关联实体 ID 提交前做 JSON 数组与字符串元素格式校验;成功后提示「任务已创建/任务已更新」并关闭抽屉 |
5. 后端关联
5.1 API 客户端
- 文件:
action/web/src/api/gothamClient.js;baseURL/gotham-api/v1,超时 30000ms。 - 加载任务与成员并行(
Promise.allSettled),单个失败不阻断另一个;统一响应体{code: 0, data: ...}。
5.2 端点表
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /collab/projects | 项目列表(我参与的,下拉选项来源) |
| GET | /collab/projects/:id/tasks | 列出项目任务(支持 status/assignee_id 过滤) |
| POST | /collab/projects/:id/tasks | 创建任务 |
| GET | /collab/tasks/:id | 任务详情 |
| PUT | /collab/tasks/:id | 更新任务 |
| DELETE | /collab/tasks/:id | 删除任务 |
| POST | /collab/tasks/:id/transition | 任务状态流转,body {to} |
| GET | /collab/projects/:id/members | 项目成员列表(负责人下拉选项来源) |
5.3 响应结构
统一响应体 {code: 0, data: ...}。任务记录示例:
{ "code": 0, "data": [ { "id": 1, "project_id": 1, "title": "核实北京大额转账",
"description": "关联张远账户", "status": "in_progress", "priority": "high",
"assignee_id": "alice", "related_entity_ids": "[\"graph:person:zhangyuan\"]",
"due_date": "2026-09-10T00:00:00Z", "created_by": "alice" } ] }
5.4 关键机制
- 任务状态机:后端
taskTransitions(action/products/gotham/collab/service.go:88-92):todo→in_progress;in_progress→todo,review;review→in_progress,done;done 为终态(无去向)。非法流转返回 409(GOTHAM_COLLAB_INVALID_TRANSITION)。前端拖拽可拖到任意列,后端拒绝时报「流转失败:{err}(状态机 todo→in_progress→review→done)」;「置为▾」下拉与拖拽调用同一个流转函数,选项即上表允许的目标状态。 - 任务字段:title/description/priority(low|medium|high,缺省 medium)/assignee_id(须为项目成员)/related_entity_ids(JSON 数组字符串,编辑抽屉为 JSON 数组输入框,提交前校验必须是合法 JSON 数组且元素为字符串)/due_date(前端拼
T00:00:00Z提交)。 - 渲染层分页:后端
GET /collab/projects/:id/tasks(collab/service.go:717-733 ListTasks)不支持 limit/offset,整项目任务一次性返回;页面按每列 20 条做本地切片分页,翻页不发请求,仅保证单列不无限拉长。 - 通知联动:状态流转写 Activity(
task_moved)并给负责人发task_status通知;指派任务时发task_assigned通知,均经 ws.Hub 实时推送。 - 本地乐观更新:拖拽流转成功后直接改本地任务状态(
t.status = toStatus)再提示,无需整表刷新。
6. 权限与安全
- 认证:全部
/collab/*端点位于 protected 组,JWT 无效一律 401,前端自动刷新/跳登录。 - 项目级隔离:任务读取/流转要求项目成员,写操作要求 owner/editor(requireWrite),非成员 403。
- 写操作防护:删除任务经
window.confirm二次确认;流转操作即时生效,误拖可再拖回(允许回退路径内)。 - 负责人校验:assignee_id 选项来自项目成员列表,后端会校验负责人是项目成员,避免指派外部用户。
7. 常见问题与排错
问题一:拖拽任务到另一列后报「流转失败」
现象:拖拽后出现红色错误提示。原因:跨过了非法的状态(如 done 拖回 todo,或跳过中间态回退超范围)。处理:用卡片「置为▾」下拉按状态机允许的目标逐格流转;或先拖回合法前置状态再前进。
问题二:「置为▾」下拉没有可选项(显示「终态」)
现象:卡片操作列只有「终态」提示,无可选状态。原因:任务已是 done(终态),后端状态机无去向。处理:done 任务不可再流转,需要修改请点「编辑」;如需回退只能在 review↔in_progress 等允许回退的路径内操作。
问题三:新建任务后看板列里没有出现该任务
现象:创建成功但卡片未出现。原因:创建成功但 loadTasks 未刷新成功,或项目选错了。处理:点「刷新」重载;确认当前项目下拉选中的项目与创建时一致;用 GET /api/v1/collab/projects/{id}/tasks 直接查询。
问题四:负责人下拉为空,只有「(未分配)」
现象:assignee 无选项。原因:项目还没有成员(除 owner 外),或成员加载失败。处理:到「项目协作」页添加成员后返回刷新;查看网络请求中 /members 是否 200。
问题五:保存任务时提示「关联实体需为合法 JSON 数组」
现象:保存被前端拦截。原因:related_entity_ids 输入不是合法 JSON 数组(如误用逗号分隔、元素为数字、含空字符串)。处理:改写成 ["graph:org:xuanwu","graph:person:zhangyuan"] 形式;本页只做格式校验(合法 JSON 数组 + 元素为非空字符串),不校验图节点是否存在——后端没有批量节点存在性端点(仅有单节点 GET /graph/nodes/:id),故无法在提交前逐一查证。
问题六:某列任务很多,看不到后面的卡片
现象:列内卡片超出可视区且无滚动到头。原因:该列任务超过每页 20 条。处理:用列底分页器翻页;注意这是前端渲染层分页,后端仍一次性返回整项目任务。
8. 已知缺陷与边界
| 边界 | 说明 |
|---|---|
| 状态机 | 前端拖拽不做本地预校验,依赖后端 409 拒绝;「置为▾」下拉只列后端合法目标 |
| 卡片列表 | 后端任务列表无 limit/offset,整项目全量返回;本页只做每列 20 条渲染层分页,数据量极大时仍会一次性拉全量 |
| 关联实体 | related_entity_ids 前端仅校验 JSON 数组格式与元素非空字符串,不校验图节点是否存在(后端无批量节点端点) |
| 截止日期 | 前端 date 输入拼 T00:00:00Z 提交,后端不强制校验逾期 |
| 乐观更新 | 拖拽成功后本地改状态,若后端实际失败但响应异常时可能出现状态不一致(需刷新校正) |
| WebSocket | 本页不主动建立 WS 连接,任务通知依赖后端推送,需其他页面/协同动态页建立连接后可见 |
| 拖拽依赖 | 卡片流转依赖 HTML5 拖放 API;触屏设备已由「置为▾」下拉兜底(与拖拽同接口) |
注:「置为」done 列按钮与空列「新建到此列」已于 2026-09-06 修复(done 列按钮修正,列头新建并预填状态)。
注:2026-09-13 三处修订——(1) 看板列补渲染层分页(每列 20 条 + 上一页/下一页,后端无 limit/offset);(2) 卡片「置为」由固定前移一格改为下拉,选项取自后端 taskTransitions(collab/service.go:88-92),与拖拽调用同一个 POST /collab/tasks/:id/transition;(3) related_entity_ids 编辑器改为 JSON 数组输入并在提交前做格式校验(元素须为非空字符串),节点存在性未校验。