You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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>

问题根源分析

  1. 子任务未注入甘特图数据:代码中合并子任务到总任务列表的taskGantt.push(...childTasks);被注释,导致子任务从未真正加入到甘特图的数据源中。
  2. 父任务重复添加:若parentData中存在多个条目对应同一个jalon.id,会重复添加相同ID的父任务,dhtmlxGantt会以最后一条父任务覆盖之前的,关联的子任务仅绑定到最终的父任务,造成“覆盖”假象。
  3. 子任务列表作用域错误:全局定义的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:29:53