基于dhtmlxgantt+Laravel的父子甘特图子任务覆盖问题求助
问题:dhtmlxGantt + Laravel 父子甘特图子任务显示异常
基于dhtmlxGantt与Laravel搭建的父子结构甘特图基础功能正常,但每次新增子任务都会覆盖原有子任务,仅能显示一个子任务,求解决办法。
相关实现代码
<div id="gantt-chart" style="width: 100%; height: 500px;"></div> @vite('node_modules/dhtmlx-gantt/codebase/sources/dhtmlxgantt.css') <script src="{{Vite::asset('node_modules/dhtmlx-gantt/codebase/sources/dhtmlxgantt.js')}}"></script> <script> const parentData = @json($projectOptionttmJalon); // Données des tâches parents const childData = @json($demandeByJalon); // Données des tâches enfants let taskGantt = []; const links = []; const childTasks = []; parentData.forEach(parent => { const parentId = parent.id; let echeance = new Date(parent.echeance); let debutDate = new Date(parent.debutDate); let diffMonth = echeance - debutDate; let diffDays = diffMonth/86400000; const jalonId = parent.jalon_id; const jalon = @json($jalons).find(j => j.id === jalonId); // Faire une recherche dans le tableau des jalons pour trouver celui correspondant const contributors=@json($contributeurs); // Créer la tâche parent taskGantt.push({ id: jalon.id, text: jalon.designation, start_date: debutDate, duration: diffDays, progress: 0.6, open: true, jalonId: jalon.id }); // Créer les tâches enfants liées childData.forEach(child => { const deadLineNoFormat = child.deadLine; const deadLine = parseInt(deadLineNoFormat, 10); let startDate = new Date(child.date_prevue); if (child.jalon_id === jalonId ) { childTasks.push({ id: `${jalonId}-${child.id}`, // Utilisation d'un identifiant composé text: child.description + ', Assignée à : ' + child.contributeur, start_date: startDate, duration: deadLine, parent: jalonId }); links.push({ id: `${jalonId}-${child.id}`, // Utilisation du même identifiant composé pour les liens source: jalonId, target: `${jalonId}-${child.id}`, type: "1" }); } }); console.log(childTasks); //taskGantt.push(...childTasks); //taskGantt= [...taskGantt, ...childTasks]; }); //console.log('task', taskGantt); gantt.init("gantt-chart"); gantt.config.date_format = "%Y-%m-%d"; gantt.parse({ data: taskGantt, links: links }); </script>
问题根源分析
- 子任务未注入甘特图数据:代码中合并子任务到总任务列表的
taskGantt.push(...childTasks);被注释,导致子任务从未真正加入到甘特图的数据源中。 - 父任务重复添加:若
parentData中存在多个条目对应同一个jalon.id,会重复添加相同ID的父任务,dhtmlxGantt会以最后一条父任务覆盖之前的,关联的子任务仅绑定到最终的父任务,造成“覆盖”假象。 - 子任务列表作用域错误:全局定义的
childTasks会累积所有父任务的子任务,若循环内重复合并,会导致子任务重复添加,ID冲突时被覆盖。
修复方案及代码
修复要点
- 将
childTasks移到父任务循环内部,每次处理单个父任务时重新初始化,避免子任务累积。 - 启用子任务合并代码,确保子任务被加入到总任务列表。
- 添加父任务重复检查,防止相同ID的父任务被多次添加。
- 优化JSON解析逻辑,避免循环内重复解析
@json($jalons)。
修复后完整代码
<div id="gantt-chart" style="width: 100%; height: 500px;"></div> @vite('node_modules/dhtmlx-gantt/codebase/sources/dhtmlxgantt.css') <script src="{{Vite::asset('node_modules/dhtmlx-gantt/codebase/sources/dhtmlxgantt.js')}}"></script> <script> const parentData = @json($projectOptionttmJalon); // 父任务数据 const childData = @json($demandeByJalon); // 子任务数据 let taskGantt = []; const links = []; const allJalons = @json($jalons); // 提取到循环外,避免重复解析 const contributors = @json($contributeurs); parentData.forEach(parent => { const jalonId = parent.jalon_id; const jalon = allJalons.find(j => j.id === jalonId); if (!jalon) return; // 找不到对应jalon时跳过,避免报错 // 检查是否已存在该父任务,防止重复添加 const hasExistingParent = taskGantt.some(task => task.id === jalon.id); if (!hasExistingParent) { const echeance = new Date(parent.echeance); const debutDate = new Date(parent.debutDate); const diffDays = (echeance - debutDate) / 86400000; // 添加父任务 taskGantt.push({ id: jalon.id, text: jalon.designation, start_date: debutDate, duration: diffDays, progress: 0.6, open: true, jalonId: jalon.id }); } // 初始化当前父任务的子任务列表(循环内定义,避免累积) const childTasks = []; // 遍历生成子任务 childData.forEach(child => { const deadLine = parseInt(child.deadLine, 10); const startDate = new Date(child.date_prevue); if (child.jalon_id === jalonId ) { const childTaskId = `${jalonId}-${child.id}`; childTasks.push({ id: childTaskId, text: `${child.description}, Assignée à : ${child.contributeur}`, start_date: startDate, duration: deadLine, parent: jalon.id }); links.push({ id: childTaskId, source: jalon.id, target: childTaskId, type: "1" }); } }); // 将当前父任务的子任务合并到总任务列表 taskGantt.push(...childTasks); }); gantt.init("gantt-chart"); gantt.config.date_format = "%Y-%m-%d"; gantt.parse({ data: taskGantt, links: links }); </script>
内容的提问来源于stack exchange,提问作者AliceBerg
相关产品推荐
相关产品推荐

