Files
DevFlow/src/constants/project.ts

126 lines
4.8 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.
//! 项目 & 任务状态映射常量
//!
//! 统一各视图(Projects/ProjectDetail/Tasks/Dashboard)的 label / badge / 阶段进度,
//! 根治此前三套状态映射互相矛盾、任务文案两处不一致的问题。
// ── 项目状态 ──
// 值为 i18n key,实际文案走 $t('projects.status.<key>')(见 src/i18n/{zh-CN,en}/projects.ts)
// F-09 对齐:删 in_progress/paused/cancelled(project 维度无数据产生源、无 UI 入口、无消费方),
// 保留与后端真实生命周期一致的最小集(planning 常态 + 软删 deleted_at 由 list_deleted 单独处理)。
export const PROJECT_STATUS_LABELS: Record<string, string> = {
planning: 'projects.status.planning',
active: 'projects.status.active',
completed: 'projects.status.completed',
}
/** 项目状态 → 卡片 badge 样式 class */
export const PROJECT_STATUS_BADGE_CLASS: Record<string, string> = {
planning: 'stage-design',
active: 'stage-coding',
completed: 'stage-release',
}
/** 项目状态 → 阶段/进度信息(详情页 pipeline + Dashboard 进度条共用) */
export interface ProjectStageInfo {
/** pipeline 步骤索引 0-4: idea/requirement/coding/testing/release */
stepIndex: number
/** 进度百分比 */
progress: number
/** Dashboard dot/chip 颜色档: coding/testing/release */
stage: string
}
export const PROJECT_STAGE_INFO: Record<string, ProjectStageInfo> = {
planning: { stepIndex: 0, progress: 20, stage: 'planning' },
active: { stepIndex: 2, progress: 55, stage: 'coding' },
completed: { stepIndex: 4, progress: 100, stage: 'release' },
}
export function projectStatusLabel(status: string): string {
return PROJECT_STATUS_LABELS[status] ?? status
}
export function projectBadgeClass(status: string): string {
return PROJECT_STATUS_BADGE_CLASS[status] ?? 'stage-design'
}
export function projectStageInfo(status: string): ProjectStageInfo {
// F-09:兜底用字面量而非 PROJECT_STAGE_INFO.planning,避免已删键的隐式依赖
return PROJECT_STAGE_INFO[status] ?? { stepIndex: 0, progress: 0, stage: 'planning' }
}
// ── 任务状态 ──
// D-260616-01:前端对齐后端 7 态纯状态机(crates/df-core/src/types.rs TaskStatus)
// 删旧 5 态 Git 工作流导向(review_ready/merged/abandoned)。
// 后端 task.rs update_task 写 status 经 TaskStatus::is_valid 拦截,旧 5 态无法落库;
// migrations.rs V1 无 seed,create_task 默认 todo → 新 DB 无旧 5 态数据,安全对齐。
//
// 值为 i18n key,实际文案走 $t('tasks.status.<key>')(见 src/i18n/{zh-CN,en}/tasks.ts)
export const TASK_STATUS_LABELS: Record<string, string> = {
todo: 'tasks.status.todo',
in_progress: 'tasks.status.in_progress',
in_review: 'tasks.status.in_review',
testing: 'tasks.status.testing',
done: 'tasks.status.done',
blocked: 'tasks.status.blocked',
cancelled: 'tasks.status.cancelled',
}
// class 名对齐既有 css(Tasks/TaskDetail/ProjectDetail 均有 status-todo/progress/review/done/abandoned):
// - todo/in_progress/in_review/done 复用既有 class(保持跨视图样式一致,不破坏指派外文件)
// - cancelled 复用 status-abandoned(同为 danger 红色,语义一致)
// - testing/blocked 新增(Tasks.vue 自身样式补充;TaskDetail/ProjectDetail 遇此值兜底 status-todo 灰色,
// 非破坏——仅样式保守,文案经 $t 正常渲染)
export const TASK_STATUS_CLASS: Record<string, string> = {
todo: 'status-todo',
in_progress: 'status-progress',
in_review: 'status-review',
testing: 'status-testing',
done: 'status-done',
blocked: 'status-blocked',
cancelled: 'status-abandoned',
}
// D-260616-01 删旧 5 态前的老 DB 数据兼容映射(老 DB 可能存 completed/review_ready/merged/abandoned)
// 新 DB 经 TaskStatus::is_valid 拦截不会有,但老 DB 未迁移清理时兜底显示而非 $t() 报错
const LEGACY_STATUS_MAP: Record<string, string> = {
completed: 'done',
review_ready: 'in_review',
merged: 'done',
abandoned: 'cancelled',
}
/** 老DB 旧态映射completed→done / review_ready→in_review 等),新 DB 无此数据 */
function mapLegacyStatus(status: string): string {
return LEGACY_STATUS_MAP[status] ?? status
}
export function taskStatusLabel(status: string): string {
return TASK_STATUS_LABELS[mapLegacyStatus(status)] ?? 'tasks.status.todo'
}
export function taskStatusClass(status: string): string {
return TASK_STATUS_CLASS[mapLegacyStatus(status)] ?? 'status-todo'
}
// ── 任务优先级 ──
export const PRIORITY_LABELS: Record<number, string> = { 0: 'P0', 1: 'P1', 2: 'P2', 3: 'P3' }
export const PRIORITY_CLASSES: Record<number, string> = {
0: 'priority-critical',
1: 'priority-high',
2: 'priority-medium',
3: 'priority-low',
}
export function priorityLabel(p: number): string {
return PRIORITY_LABELS[p] ?? `P${p}`
}
export function priorityClass(p: number): string {
return PRIORITY_CLASSES[p] ?? 'priority-low'
}