// 任务模块: 看板列 与 任务状态 的联动裁决 (唯一口径) // 对应需求: T-BD-04/05/06/07/08/13/14/15/16 // // 两个正交维度: // Task.columnId 空间 (哪一列) // Task.status 属性 (todo/doing/done) // 列上 boundStatus 决定二者是否联动: // null 该列与状态完全独立 // todo等 该列绑定到该状态 // // 三种场景: // A 拖拽换列 -> 只看目标列: 目标列绑定则状态跟随, 不绑定则保留原状态 // B 改状态 -> 当前列已匹配则不改列; 否则按列序找第一个绑定该状态的列 (找不到就不动) // C 子任务 -> 跳过全部联动 /** 列按 sortOrder 升序 (调用方保证已排序, 这里再兜底一次) */ export function sortColumns(columns) { return [...columns].sort((a, b) => (a.sortOrder - b.sortOrder) || (a.id - b.id)) } /** * 场景 A: 任务从任意列拖到 targetColumn * @returns {{ status: string }} 新状态 */ export function statusOnColumnChange(currentStatus, targetColumn) { if (!targetColumn) return { status: currentStatus } if (targetColumn.boundStatus) return { status: targetColumn.boundStatus } // 目标列不绑定 => 保留原状态 (T-BD-07) return { status: currentStatus } } /** * 场景 B: 任务状态改为 newStatus 后, 应该落在哪一列 * @returns {{ columnId: number, moved: boolean }} */ export function columnOnStatusChange(task, newStatus, columns) { // 已匹配 (当前列就绑定该状态) => 原地不动 if (task.column && task.column.boundStatus === newStatus) { return { columnId: task.columnId, moved: false } } // 按当前列顺序取第一个绑定该状态的列 (T-BD-06, T-BD-15) const ordered = sortColumns(columns || []) const target = ordered.find((c) => c.boundStatus === newStatus) if (target) return { columnId: target.id, moved: target.id !== task.columnId } // 无匹配列 => 不移动, 保留原列 (T-BD-16) return { columnId: task.columnId, moved: false } } /** 子任务豁免: 不参与任何列/状态联动 (T-BD-13) */ export function isSubtask(task) { return task.parentId != null } /** * 统一裁决入口: 写接口调用它算出最终的 status 与 columnId * * @param {object} task 现有任务 (含 columnId, status, parentId, column) * @param {object} patch 本次提交 { columnId?, status? } * @param {object[]} columns 项目全部列 * @returns {{ status: string, columnId: number }} */ export function resolveTaskWrite(task, patch, columns) { let status = patch.status !== undefined ? patch.status : task.status let columnId = patch.columnId !== undefined ? patch.columnId : task.columnId // 子任务: 原样落库 if (isSubtask(task)) return { status, columnId } const ordered = sortColumns(columns || []) const targetColumn = ordered.find((c) => c.id === columnId) // 场景 A: 显式换列 if (patch.columnId !== undefined && targetColumn) { status = statusOnColumnChange(status, targetColumn).status } // 场景 B: 状态变了(或换列后状态变了) => 检查是否需要归位 // 注意: 只在"状态发生变化"或"显式改状态"时才归位, 单纯拖拽已由 A 处理 if (patch.status !== undefined) { const next = columnOnStatusChange({ ...task, columnId, column: targetColumn }, status, ordered) columnId = next.columnId } return { status, columnId } }