fix(TaskItem,TaskList): 修复子任务嵌套层级丢失和渲染异常问题

1.  修复API返回平面子任务DTO时,直接替换任务丢失后代子任务的问题
2.  重构子任务创建逻辑,改用重新拉取全量任务树的方式解决深层嵌套任务的响应式渲染问题
3.  修改子任务添加方式为新数组引用赋值,确保Vue3可以正确检测嵌套层级的变更
4.  添加缺失的父任务未找到的警告日志和异常捕获处理
This commit is contained in:
ShaoHua
2026-06-14 05:17:20 +08:00
parent 14868c45c7
commit 46db04e43e
2 changed files with 28 additions and 3 deletions
@@ -201,6 +201,11 @@ const handleSubTaskUpdated = (updatedTask: Task) => {
if (props.task.subTasks) { if (props.task.subTasks) {
const index = props.task.subTasks.findIndex(t => t.id === updatedTask.id); const index = props.task.subTasks.findIndex(t => t.id === updatedTask.id);
if (index !== -1) { if (index !== -1) {
// 保留现有子任务:API 返回的 DTO 是平面的(subTasks=[]),直接替换会丢失该任务已有的所有后代
const existing = props.task.subTasks[index];
if (existing.subTasks?.length && !updatedTask.subTasks?.length) {
updatedTask.subTasks = existing.subTasks;
}
props.task.subTasks[index] = updatedTask; props.task.subTasks[index] = updatedTask;
emit('updated', props.task); emit('updated', props.task);
} }
+22 -2
View File
@@ -402,6 +402,10 @@ const handleTaskUpdated = (updatedTask: Task) => {
const updateTaskInTree = (tasks: Task[], updatedTask: Task): boolean => { const updateTaskInTree = (tasks: Task[], updatedTask: Task): boolean => {
for (let i = 0; i < tasks.length; i++) { for (let i = 0; i < tasks.length; i++) {
if (tasks[i].id === updatedTask.id) { if (tasks[i].id === updatedTask.id) {
// 保留现有子任务:API 返回的 DTO 是平面的(subTasks=[]),直接替换会丢失该任务已有的所有后代
if (tasks[i].subTasks?.length && !updatedTask.subTasks?.length) {
updatedTask.subTasks = tasks[i].subTasks;
}
tasks[i] = updatedTask; tasks[i] = updatedTask;
return true; return true;
} }
@@ -434,8 +438,22 @@ const deleteTaskFromTree = (tasks: Task[], taskId: string): boolean => {
return false; return false;
}; };
const handleSubTaskCreated = (subTask: Task) => { const handleSubTaskCreated = async (subTask: Task) => {
try {
// 直接从 API 重新加载完整任务树,保证所有层级的嵌套关系正确且响应式链路完整。
// 深层嵌套(3+层)时,原地修改树(addSubTaskToTree)无法可靠触发 TaskItem 的 re-render
// 因为 filteredTasks 计算属性中的浅拷贝({ ...task })在替换 subTasks 引用时会断开追踪。
const response = await taskApi.getTasks();
if (response.success && response.data) {
tasks.value = response.data;
} else {
console.warn('[handleSubTaskCreated] API 返回异常,尝试就地添加');
addSubTaskToTree(tasks.value, subTask); addSubTaskToTree(tasks.value, subTask);
}
} catch (error) {
console.error('[handleSubTaskCreated] 加载任务失败,使用就地添加:', error);
addSubTaskToTree(tasks.value, subTask);
}
lastSyncTime.value = Date.now(); lastSyncTime.value = Date.now();
}; };
@@ -445,7 +463,8 @@ const addSubTaskToTree = (tasks: Task[], subTask: Task): boolean => {
if (!tasks[i].subTasks) { if (!tasks[i].subTasks) {
tasks[i].subTasks = []; tasks[i].subTasks = [];
} }
tasks[i].subTasks.push(subTask); // 使用新数组引用替换而非 push,确保 Vue 3 响应式系统无论嵌套多深都能检测到变更
tasks[i].subTasks = [...tasks[i].subTasks, subTask];
return true; return true;
} }
if (tasks[i].subTasks && tasks[i].subTasks.length > 0) { if (tasks[i].subTasks && tasks[i].subTasks.length > 0) {
@@ -454,6 +473,7 @@ const addSubTaskToTree = (tasks: Task[], subTask: Task): boolean => {
} }
} }
} }
console.warn(`[addSubTaskToTree] 未找到父任务 id="${subTask.parentTaskId}",子任务 id="${subTask.id}" 未能加入树中`);
return false; return false;
}; };