Super Productivity 标签视图(Tag View)完全指南:跨项目分类、筛选与虚拟标签机制
【免费下载链接】super-productivitySuper Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, GitLab, GitHub and Open Project.项目地址: https://gitcode.com/GitHub_Trending/su/super-productivity
标签(Tag)是 Super Productivity 中用于跨项目灵活分类的核心轻量级机制:每个任务必须归属于恰好一个项目(Project),但可以携带零个、一个或多个标签。本篇指南以官方 wiki 的 Tag View 文档为骨架,结合仓库源码(src/app/features/tag/与src/app/features/tasks/)深入讲解标签的定位、创建方式、筛选逻辑,以及 “Today” 虚拟标签的底层实现,读完后你将掌握完整的标签使用与扩展能力。
标签解决什么问题:项目的结构性 vs 标签的横切性
Super Productivity 中每个任务都必须且只能属于一个项目(Project),项目提供的是结构性组织(backlog、备注、主题、集成等一整套工作上下文)。这种强约束保证了任务归属清晰,但无法表达跨项目的共同属性——比如一个任务属于 "Backend API" 项目,同时又带有#urgent、#bug、#needs-review这类横切属性。
标签正是为此设计的:它允许你在不改变项目结构的前提下,从多个维度对任务打标,实现:
- 多维分类:用项目做结构组织(每个任务恰好一个),用标签做横切组织(每个任务零到多个);
- 灵活筛选:跨项目查看所有 "urgent" 任务、所有 "bug" 任务,而不必关心它们各自属于哪个项目;
- 轻量管理:标签就是简单的标签——没有 backlog、备注、主题等复杂配置,创建和使用成本极低。
标签 vs 项目对比
| 维度 | 标签(Tags) | 项目(Projects) |
|---|---|---|
| 与任务的关系 | 每个任务零个或多个(可选) | 每个任务恰好一个(必填) |
| 用途 | 跨项目灵活分类的横切标签 | 主要的结构性组织单元 |
| 功能特性 | 简单的筛选与分组标签 | Backlog、备注、主题、集成等完整工作上下文 |
在数据模型上,这种区别体现在源码中:标签实体Tag继承自WorkContextCommon(与项目共享工作上下文公共字段),并通过Task.tagIds: string[]与任务建立多对多关联,而项目通过Task.projectId与任务建立一对多关联。相关模型定义见 tag.model.ts。
多标签:为一个任务打上多个标签
任务可以携带多个标签,主要途径有三种:
- 任务标题短语法(Short Syntax):在标题中直接输入
#tagname,例如"Fix login bug #urgent #bug #backend"; - 添加任务栏(Add Task Bar):通过复选框一次勾选多个标签;
- 标签编辑对话框:在编辑任务时添加或移除多个标签。
这样你就能按紧迫度、类型、领域或任何适合自己工作流的维度对任务进行多维分类。
底层实现:短语法标签解析
短语法#tagname的解析实现在 short-syntax.ts 中。其核心正则如下:
const CH_TAG = '#'; const ALL_SPECIAL = `(\\${CH_PRO}|\\${CH_TAG}|\\${CH_DUE}|\\${CH_DEADLINE})`; const SHORT_SYNTAX_TAGS_REG_EX = new RegExp(`\\${CH_TAG}[^${ALL_SPECIAL}|\\s]+`, 'gi');也就是说:#后跟任意非空白、非特殊符号(+、#、@、!、|)的连续字符会被识别为一个标签 token。解析器parseTagChanges随后会:
- 大小写不敏感匹配:将输入标签与现有标签做
newTagTitle.toLowerCase() === tag.title.toLowerCase()匹配,命中则复用已有标签 ID; - 自动创建新标签:未匹配到的标签名进入
newTagTitlesToCreate列表,由后续逻辑自动创建; - 从标题中剥离:被识别的标签 token 会从任务标题中移除,确保最终标题干净,只保留语义文本。
一个值得注意的细节是Fun title#blu不会被当作标签——解析器会检查#前一个字符,若它不是空格则拒绝解析,避免把普通文本误识别为标签。此外,纯数字标签(如#123)在标题开头以及 issue 任务上会被屏蔽,相关规则见parseTagChanges中的isNumericOnly判断。
在添加任务栏中与语法联动
添加任务栏的实时解析由 add-task-bar-parser.service.ts 完成。当你输入#tag时,解析器会维护tagIds与newTagTitles两个状态,并在你通过控件勾选标签时,通过removeShortSyntaxFromInput('tags', specificTag)精确移除输入文本中对应的#tag片段——这里采用解析器记录的 token 范围(_lastParsedRanges)而非简单的正则替换,避免多词 token 被截断。
按标签筛选:跨项目查看任务
你可以按标签筛选任务,查看所有项目中带有特定标签的任务。筛选能力包括:
- 标签名搜索:输入标签名的部分内容即可匹配(大小写不敏感);
- 无标签筛选:筛出所有未打任何标签的任务。
查看某个标签时,你会看到来自多个项目的任务,每个任务以项目徽章(badge)形式展示其所属项目,便于一眼确认来源。
底层实现:标签成员关系的单一事实源
从源码看,标签与任务的关系采用“hybrid pattern”设计(见 tag.reducer.ts 中的computeOrderedTaskIdsForTag):
- 成员关系:以
task.tagIds为单一事实源(single source of truth),只要任务的tagIds包含该标签 ID,任务就属于该标签; - 排序保持:
tag.taskIds仅用于保存用户自定义的排序,不参与成员判定; - 自愈能力:
tag.taskIds中的过期任务 ID 会被自动过滤,而带标签但未出现在排序列表中的任务会被自动追加到末尾。
这种设计让成员关系始终正确,同时保留用户拖拽排序的能力。筛选“无标签任务”正是基于task.tagIds为空数组这一事实实现的。
特殊场景:Today 虚拟标签
"Today"(今日)视图使用一种特殊的虚拟标签(virtual tag)模式。其成员关系不是从任务的标签列表中读取 "Today" 值,而是由任务的到期日(due day)或到期时间(due time)结合配置的逻辑日边界(logical-day boundary)实时计算得出。
这种设计的意义在于:Today 视图专注于基于时间的组织,而标签保持基于分类的组织,两者职责分离、互不干扰。Today 视图的详细工作方式见 4.01-The-Today-View。
底层实现:TODAY_TAG 的虚拟性
TODAY_TAG的定义与设计约束见 tag.const.ts,其注释明确列出了三条规则:
- 不应出现在
task.tagIds中——成员关系由task.dueDay决定; TODAY_TAG.taskIds仅存储今日任务的排序;- 移动操作(拖拽、Ctrl+↑/↓)通过
tag.reducer.ts对包括 TODAY 在内的所有标签统一生效。
export const TODAY_TAG: Tag = { color: null, created: Date.now(), ...WORK_CONTEXT_DEFAULT_COMMON, icon: 'wb_sunny', title: 'Today', id: 'TODAY', theme: { ...WORK_CONTEXT_DEFAULT_THEME, isAutoContrast: true, huePrimary: '400', hueAccent: '500', hueWarn: '500', primary: DEFAULT_TODAY_TAG_COLOR, isDisableBackgroundTint: true, }, };对应地,reducer 顶部同样以注释强调:“TODAY_TAG (ID: 'TODAY') 是虚拟标签,绝不应出现在 task.tagIds 中,成员关系由 task.dueDay 决定”。同时tag.reducer.ts中保留了selectTodayTagTaskIds选择器(标注@deprecated),并建议改用work-context.selectors.ts中的selectTodayTaskIds——后者直接从task.dueDay计算成员关系,具备自愈能力。这正印证了文档中“成员由到期日计算、而非标签列表”的描述。
标签的扩展用法
wiki 提供了两套基于标签的成熟工作流:
- 4.07a-Tags_Eat-the-Frog —— 基于优先级的 A/B/C/D 打标法(吃青蛙法);
- 4.07b-Tags_Ordinal-Priorities —— 用标签近似表达优先级顺序。
这两篇文章都依赖本文的“多标签 + 标签筛选”能力来实现:先创建代表优先级的标签(如#a、#b),再通过给任务打标并在 Tag View 中筛选,即可获得跨项目的优先级视图。
标签的高级数据特性
除了文档中的基础能力,仓库源码还揭示了标签模型更丰富的维度(tag.model.ts、tag.service.ts):
- 主题与颜色:每个标签都可以配置主题(
theme.primary、huePrimary、hueAccent等)或直接指定color,并通过TagComponent(见 tag/tag.component.ts)渲染为带颜色的徽章,同时支持 emoji 图标(isSingleEmoji判断); - 系统标签排除:
SYSTEM_TAG_IDS(TODAY、EM_URGENT、EM_IMPORTANT、KANBAN_IN_PROGRESS)用于在统计用户自建标签时排除系统自动创建的标签; - 按标签统计时间:tasks-by-tag.component.ts 会汇总每个标签下任务当日(或含昨日)的
timeSpentOnDay,并按耗时降序排列,让你直观看到每个标签消耗了多少时间; - 排序管理:通过
updateOrder/updateTagOrderaction 持久化标签在菜单中的树形排序(buildTagListInTreeOrder)。
相关阅读
- 4.06-Project-View —— 项目如何提供结构性组织(必填)vs 标签(可选);
- 4.05-Board-View —— 看板视图,可基于标签进行筛选与列组织;
- 4.01-The-Today-View —— 基于时间的 Today 视图(使用虚拟标签模式);
- 3.04-Short-Syntax —— 完整的短语法参考,包括
#tagname标签语法及其他 token。
【免费下载链接】super-productivitySuper Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, GitLab, GitHub and Open Project.项目地址: https://gitcode.com/GitHub_Trending/su/super-productivity
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考