Files
Kanban/src/types/task.ts
T
chenshoulin 65e98199ba feat: 回收站、批量编辑、合并导入与标签治理
- 数据:Task 增加 deletedAt,schema v2→v3;删除改为软删除,保留 30 天后自动清理
- 回收站:支持恢复、永久删除、二次确认清空;导航栏入口带数量角标
- 批量编辑:多选后统一移动列、改优先级、标签增删、设置截止日、归档
- 合并导入:按 id 匹配、updatedAt 新者胜;覆盖/合并二选一,执行前自动快照
- 标签治理:全局重命名、合并、删除;回收站任务不参与改写
- 看板语义读取统一改用 activeTasks,避免已删除任务泄漏到统计、今日与标签下拉
- UI:回收站图标与备份统一尺寸;批量编辑条统一控件高度并分组
- 测试:705 个单测通过,补充迁移、回收站、批量编辑、合并与标签用例
2026-10-19 18:32:42 +08:00

77 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 领域类型与常量(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<Record<Priority, string>> = {
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
}