第 33 课:任务看板视图(按状态分列)与本地持久化
这一课我们继续沿着“任务管理页个人工作台偏好”主线往下推进。
上一课我们已经让任务列表支持:
- 表格视图
- 卡片视图
- 卡片视图下按状态分组
这一课继续把任务页推进到更接近真实后台系统的一步:
让任务列表支持看板视图,并把全部筛选结果按状态分列展示,同时把这份视图偏好持久化到 localStorage。
这节课一句话在做什么?
这一课我们完成了 7 件事:
- 给任务页新增了第三种主视图模式:
看板视图。 - 把当前任务按
待开始 / 进行中 / 待评审 / 已完成分成稳定列。 - 看板列基于
全部筛选结果 + 当前排序结果生成,而不是基于当前分页切片。 - 切到看板后会隐藏批量操作栏和分页栏,避免交互语义互相打架。
- 把看板视图偏好保存到了
localStorage。 - 刷新任务页后,看板视图会自动恢复。
- 补上了单元测试、E2E 测试和课程文档。
这一课最重要的设计结论
这一课最重要的结论是:
看板视图不是“另一种分页列表”,而是“当前筛选结果的流程总览”。
为什么看板不应该继续沿用分页切片?
这节课最值得你真正想清楚的点,就是:
表格 / 卡片 和 看板,虽然都在展示任务,但它们的产品语义并不完全一样。
1. 表格和卡片更像“列表阅读”
前两种模式里,我们一直在强调一条稳定数据流:
- 原始任务
- 筛选
- 排序
- 分页切片
- 渲染当前页
因为表格和卡片本质上都还是:
- 一页一页地看数据
- 当前页展示一段切片
- 批量选择和分页器都仍然成立
所以它们天然适合:
- 基于
paginatedTasks
2. 看板更像“流程全景图”
但看板不是为了回答:
- 当前第几页有哪些任务
而是为了回答:
- 现在各个流程阶段各有多少任务
- 哪一列有积压
- 哪个状态最值得优先关注
所以它更适合基于:
filteredTaskssortedTasks
也就是:
- 先筛选
- 再排序
- 然后把全部结果按状态分列
这就是为什么这一课里:
- 看板继续遵守筛选和排序
- 但不再使用分页切片
3. 一旦切到看板,就该把分页语义先收起来
如果你一边显示看板,一边还保留:
- 分页栏
- 本页全选
- 批量操作栏
那页面语义会很混乱。
因为用户会产生两个冲突认知:
- 这是完整流程总览
- 还是这只是当前页的一小段?
所以这一课我们明确做了两个决定:
- 看板模式下隐藏批量操作栏
- 看板模式下隐藏分页栏
这不是“功能少了”,而是:
先把语义做清楚。
这一课在useTasksPage里做了什么?
文件:
src/composables/useTasksPage.ts
这一课新增的核心状态仍然放在任务页组合式函数里,因为:
- 主视图模式属于页面级偏好
- 要持久化
- 要同时影响多个展示组件
1. 扩展了任务列表视图模式类型
这次我们把:
TaskListViewMode
从原来的:
table | card
扩展成了:
table | card | kanban
同时也补了对应的:
看板视图选项文案description说明
这一步看起来只是多了一个字符串,但它实际上是在告诉整个项目:
- 页面允许存在第三种主视图
- 所有使用这个类型的地方都必须显式认识它
这就是 TypeScript 在工程里的价值:
当你扩展产品能力时,类型系统会逼你把所有受影响位置都补完整。
2. 新增了isTaskKanbanView
除了原来的:
isTaskTableView
这次还新增了:
isTaskKanbanView
它的作用不是“省几行判断”,而是:
- 让页面模板更清晰
- 让批量栏和分页栏的显隐条件更明确
- 让测试更容易表达意图
这也是一个很典型的小型页面建模动作:
把“重要状态的业务含义”提前计算出来,而不是在模板里到处写字符串比较。
3. 新增了kanbanTaskColumns
这一课最核心的新计算结果是:
kanbanTaskColumns
它的输入不是:
paginatedTasks
而是:
sortedTasks
也就是:
- 看板列会继承当前筛选结果
- 看板列会继承当前排序结果
- 但不会被分页切成一小段
这样做后:
- 列数量和卡片数量更符合“总览”语义
- 每列内部任务顺序仍然稳定
- E2E 也更容易验证真实结果
4. 切到看板时主动清空选择
这一课还在:
handleTaskListViewModeChange()
里补了一条非常实用的规则:
当视图切到 kanban 时,主动 clearTaskSelection()。
为什么这样做?
因为看板模式下我们已经决定:
- 不展示批量操作栏
如果这时候还保留之前在表格/卡片里的选择,就会出现:
- 页面上看不到选择入口
- 却暗中保留了一堆旧选择
这就是典型的“隐藏状态污染”。
所以这一步本质上是在做:
- 状态清理
- 语义收口
这一课在界面层做了什么?
文件:
src/views/TasksView.vuesrc/components/tasks/TaskKanbanBoard.vuesrc/components/tasks/TaskListViewModeSwitch.vuesrc/components/tasks/TaskColumnSettings.vue
1.TasksView.vue继续承担页面级编排职责
这次页面层做了 4 件关键事情:
- 引入新的
TaskKanbanBoard - 根据
taskListViewMode在三种主视图之间切换 - 只在卡片视图下显示
TaskListGroupingSettings - 在看板视图下隐藏批量栏和分页栏
这说明页面层最核心的职责依然是:
- 条件编排
- 状态分发
- 多个功能块之间的协调
它不是“把组件堆在一起”,而是在定义:
- 什么时候该显示什么
- 哪些能力能共存
- 哪些能力应该互斥
2. 新增TaskKanbanBoard.vue
这个组件负责:
- 渲染状态列
- 渲染每列里的任务卡片
- 处理 loading / error / empty
- 把编辑、删除操作继续抛给页面层
它没有处理:
- 本地存储
- 主视图状态
- 分页
- 批量选择
这说明它依然只是一个:
- 展示组件
而不是页面状态中心。
3. 看板卡片继续复用字段显隐偏好
这节课没有重新发明一套“看板字段设置”,而是继续复用:
visibleTaskColumnKeys
所以当前你在列配置面板里关闭:
- 负责人
- 截止日期
- 优先级
- 任务说明
这些偏好也会影响看板卡片。
这背后对应的工程思想是:
用户偏好尽量共享,不要在每种视图里各造一套相互割裂的配置系统。
这一课最值得你学会的前端思想
1. 同样是“列表展示”,不同视图也可能有不同数据语义
很多初学者会觉得:
- 既然都是展示任务,那就共用同一套分页逻辑
但真实项目里不能这么机械。
你更应该先问:
- 这个视图到底想让用户看到什么?
这节课里:
- 表格 / 卡片:强调“当前页读哪几条”
- 看板:强调“全部筛选结果怎么按流程阶段分布”
所以它们虽然共用同一批原始数据,却不一定共用完全一样的处理顺序。
2. 视图切换不仅是“换组件”,还常常伴随状态协调
这一课你要特别注意一件事:
我们做的不是简单的:
v-if切一下组件
而是同时处理了:
- 视图模式持久化
- 批量栏显隐
- 分页栏显隐
- 选择状态清理
这说明真实前端里的“视图切换”通常都是:
- UI 切换
- 状态切换
- 交互规则切换
三件事一起发生。
3. “总览视图”适合减少局部操作,先保留核心阅读能力
这节课我们故意没有在看板里继续支持:
- 勾选
- 批量改状态
- 批量删除
不是因为做不出来,而是因为当前阶段更重要的是:
- 先把总览语义做清楚
- 先把页面边界理顺
- 先把功能做成稳定可测试的能力
这就是很典型的工程取舍:
先做正确,再做更多。
这一课补了哪些测试?
1. 单元测试
文件:
src/composables/__tests__/useTasksPage.spec.ts
新增覆盖:
- 从
localStorage恢复合法看板视图模式 - 非法视图模式自动回退成
table - 切到
kanban后清空选择状态 kanbanTaskColumns是否基于全部筛选结果生成- 看板列内部是否继续保留排序后的相对顺序
这一层主要验证:
- 页面级状态是否正确
- 看板的数据边界是否正确
- 视图切换是否做了必要的状态清理
2. E2E 测试
文件:
e2e/pages/TasksPage.tse2e/app.spec.ts
新增覆盖:
- 切到看板视图
- 断言状态列标题真实出现
- 断言看板里真实出现目标任务卡片
- 断言批量栏和分页栏被隐藏
- 刷新页面
- 再次断言看板视图和状态列仍然保留
这一层主要验证:
- 不只是状态值变了
- 页面结构也真的切成了看板
- 本地持久化在真实浏览器里确实可恢复
这一课改了哪些文件?
src/types/task.tssrc/composables/useTasksPage.tssrc/views/TasksView.vuesrc/components/tasks/TaskKanbanBoard.vuesrc/components/tasks/TaskListViewModeSwitch.vuesrc/components/tasks/TaskColumnSettings.vuesrc/composables/__tests__/useTasksPage.spec.tse2e/pages/TasksPage.tse2e/app.spec.tsdocs/33-task-kanban-view-and-persistence.mddocs/README.md
这一课最值得你真正记住什么?
如果你只记住“多了一个看板视图按钮”,那还不够。
你更应该记住下面这 6 点:
- 看板不是普通分页列表,它更像全部筛选结果的流程总览。
- 同样的数据,在不同视图里可以有不同的数据处理顺序。
- 视图切换不仅会换组件,还会影响分页、批量操作和选择状态。
- 页面级偏好仍然应该放在 composable,而不是塞进最终渲染组件里。
- 用户字段显隐偏好尽量跨视图共享,不要为每种视图各造一套配置。
- 真正像后台系统的能力,不只是能显示,还要语义清晰、状态干净、可持久化、可测试。
这一课的验证命令
完成后至少应该验证:
npmrun test:unit ----runnpmrun type-checknpmrun lintnpmrun test:e2e ----project=chromium