Files
jordium-gantt-vue3/src/utils/taskTreeUtils.ts
2025-12-06 20:34:33 +08:00

138 lines
3.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.

import type { Task } from '../models/classes/Task'
/**
* 任务树操作工具函数
*/
/**
* 从任务树中查找任务的父任务
*/
export function findTaskParent(
taskList: Task[],
targetId: number,
parent: Task | null = null,
): Task | null {
for (const task of taskList) {
if (task.id === targetId) {
return parent
}
if (task.children && task.children.length > 0) {
const found = findTaskParent(task.children, targetId, task)
if (found !== null) return found
}
}
return null
}
/**
* 从任务树中移除指定任务
* @returns 被移除的任务,如果未找到则返回 null
*/
export function removeTaskFromTree(taskList: Task[], taskId: number): Task | null {
for (let i = 0; i < taskList.length; i++) {
if (taskList[i].id === taskId) {
return taskList.splice(i, 1)[0]
}
if (taskList[i].children && taskList[i].children!.length > 0) {
const removed = removeTaskFromTree(taskList[i].children!, taskId)
if (removed) return removed
}
}
return null
}
/**
* 将任务插入到任务树的指定位置
* @param taskList 任务列表
* @param targetId 目标任务ID
* @param taskToInsert 要插入的任务
* @param position 插入位置:'after' 表示在目标任务之后,'child' 表示作为目标任务的子任务
* @returns 是否插入成功
*/
export function insertTaskInTree(
taskList: Task[],
targetId: number,
taskToInsert: Task,
position: 'after' | 'child',
): boolean {
for (let i = 0; i < taskList.length; i++) {
if (taskList[i].id === targetId) {
if (position === 'after') {
// 算法#1: 放置在目标任务之后(同级)
// 更新 parentId 为目标任务的 parentId
taskToInsert.parentId = taskList[i].parentId
taskList.splice(i + 1, 0, taskToInsert)
} else {
// 算法#2: 作为子任务插入(第一个子任务位置)
// 重要里程碑组milestone-group不能添加子任务只能在其后插入
if (taskList[i].type === 'milestone-group') {
// 降级为 'after' 逻辑
taskToInsert.parentId = taskList[i].parentId
taskList.splice(i + 1, 0, taskToInsert)
} else {
// 更新 parentId 为目标任务的 id
taskToInsert.parentId = targetId
if (!taskList[i].children) {
taskList[i].children = []
}
taskList[i].children!.unshift(taskToInsert)
}
}
return true
}
if (taskList[i].children && taskList[i].children!.length > 0) {
if (insertTaskInTree(taskList[i].children!, targetId, taskToInsert, position)) {
return true
}
}
}
return false
}
/**
* 执行任务移动操作(直接修改传入的 taskList
* @returns 移动信息,如果移动失败则返回 null
*/
export function moveTask(
taskList: Task[],
draggedTaskId: number,
targetTaskId: number,
position: 'after' | 'child',
): {
movedTask: Task
oldParent: Task | null
newParent: Task | null
} | null {
// 1. 记录原始父任务
const oldParent = findTaskParent(taskList, draggedTaskId)
// 2. 从原位置移除任务
const removedTask = removeTaskFromTree(taskList, draggedTaskId)
if (!removedTask) {
return null
}
// 3. 插入到新位置
const inserted = insertTaskInTree(taskList, targetTaskId, removedTask, position)
if (!inserted) {
// 插入失败,需要恢复任务到原位置
// 如果有父任务,恢复到父任务的 children 中
if (oldParent && oldParent.children) {
oldParent.children.push(removedTask)
} else {
// 否则恢复到根级别
taskList.push(removedTask)
}
return null
}
// 4. 计算新的父任务
const newParent = findTaskParent(taskList, draggedTaskId)
return {
movedTask: removedTask,
oldParent,
newParent,
}
}