/** * 领域类型与常量(T03) * * 设计约定(见 docs/adr.md): * - 列固定为三列,不使用可配置列,因此 status 直接用字面量联合类型而非 enum * - dueDate 仅表示「日期」,格式 YYYY-MM-DD,不含时刻,以此规避时区问题 */ export const COLUMN_IDS = ['todo', 'doing', 'done'] as const export type ColumnId = (typeof COLUMN_IDS)[number] /** 优先级:1 = 低,2 = 中,3 = 高 */ export type Priority = 1 | 2 | 3 /** * 键盘移动方向:左右换列,上下调同列顺序。 * 用户可以在卡片上聚焦后用方向键调整,不必依赖拖拽。 */ export type MoveDirection = 'left' | 'right' | 'up' | 'down' export interface Task { id: string title: string description: string status: ColumnId priority: Priority tags: string[] /** 仅日期,格式 YYYY-MM-DD;无截止日期时为 null */ dueDate: string | null /** 同列内排序用的浮点数,采用相邻中点插入 */ sortOrder: number createdAt: string updatedAt: string completedAt: string | null /** 归档时间;null 表示未归档。归档任务默认不在看板上显示 */ archivedAt: string | null /** * 删除时间;null 表示未删除。 * * 删除是「软删除」:任务仍留在数据里,只是从看板、统计、标签等 * 所有常规视图里剔除,直到用户在回收站里恢复或永久删除。 */ deletedAt: string | null } export interface ColumnDef { readonly id: ColumnId readonly title: string } /** 看板列定义,顺序即展示顺序 */ export const COLUMNS: readonly ColumnDef[] = [ { id: 'todo', title: '待办' }, { id: 'doing', title: '进行中' }, { id: 'done', title: '已完成' }, ] export const PRIORITY_LABELS: Readonly> = { 1: '低', 2: '中', 3: '高', } /** 新建任务时的默认值 */ export const DEFAULT_PRIORITY: Priority = 2 /** 判断某个值是否为合法的列 id */ export function isColumnId(value: unknown): value is ColumnId { return typeof value === 'string' && (COLUMN_IDS as readonly string[]).includes(value) } /** 判断某个值是否为合法的优先级 */ export function isPriority(value: unknown): value is Priority { return value === 1 || value === 2 || value === 3 }