Bootstrap

基于dhtmlx-gantt和vue开发的甘特图

     我当时公司需求是要求在甘特图上能显示任务情况的,即显示开始和结束时间,和实际任务开始和结束时间,还有请假,出差,加班,节假日情况,在网上找了一圈发现dhtmlx-gantt,dhtmlx-gantt付费不能完全能满足需求,但是小人不敢提,结果摸索后发现这是使用html生成的图表,修改起来很方便,所以我来分享一下免费版的,又满足要求的甘特图

一.文档地址

官方文档

二.安装

npm i dhtmlx-gantt

三.分析部分

任务情况无非有就几种:(蓝色是实际时间,红色是计划时间)

    1. 实际开始时间早于计划开始时间,实际结束时间也早于计划开始时间(l21)

    2. 实际开始时间早于计划开始时间,实际结束时间在计划时间之内 (j21)

    3. 实际开始时间早于计划开始时间,实际结束时间也晚于计划结束时间 (b21)

    4. 实际开始和结束时间都在计划时间之内(b12)

    5. 实际开始时间在计划时间之内,实际结束时间也晚于计划结束时间 (j12)

    6. 实际开始和结束时间都晚于计划结束时间(l12)

四.效果图

 先上效果图

五.代码部分

  

 dhtmlx-gantt参数方法什么的就自己看官网了哈,这里就不多做解释了,直接上代码

index.vue 部分

头部样式和定义甘特图容器

<template>
  <div class="about">
  <div id="dhtmlgantt">
     <div class="gantt">
       <div class="legend">
          <div class="legendBox">
            <div class="legendSml legendColor1"></div>
            <div class="text">计划时间</div>
          </div>
          <!-- <div class="legendBox">
            <div class="legendSml legendColor2"></div>
            <div class="text">相交时间</div>
          </div> -->
          <div class="legendBox">
            <div class="legendSml legendColor3"></div>
            <div class="text">实际时间</div>
          </div>
       </div>
       <div class="gantt_render" v-if="!tasks.data.length == 0  && loading == false">
         <!-- <a-button @click="getLongStyle()">变化</a-button> -->
         <!-- 甘特图 -->
        <div id="custom" ref="dxgantt" class="left-container" />
       </div>
       <div class="simpleImage" v-if="tasks.data.length == 0 && loading == false">
         <a-empty description="暂无数据" :image="simpleImage"></a-empty>
       </div>
       <div v-else-if="loading == true" class="spin">
         <a-spin class="a-spin" tip="Loading..."></a-spin>
       </div>
     </div>
  </div>
  </div>
</template>

引入

import moment from 'moment';
// import { Empty } from 'ant-design-vue';
import gantt from "dhtmlx-gantt"; // 引入模块
import "dhtmlx-gantt/codebase/dhtmlxgantt.css"; //皮肤
import {data} from './data.js'

处理甘特图右侧进度条类型样式方法和判断

        // 设置每一部分的颜色
      renderLabel(progress, type, state,val,num,objText,status) {
         // progress, type, state,val实际还是计划,num,objText完成度,status状态
        // const self =this
        let hour = moment().format("k"); 
          var relWidth = progress * 100;
          var n=num*100
          var cssClass = "custom_progress ";
          let otherLength = '0px' // 额外长度
          // let doingLenght = 34
          // 实际
          if(val==='progress3'){
            if(status === 'doing'){
              if(objText==='100%'){
                cssClass += "nearly_done1";
                otherLength = '34px'
              }else{
                cssClass += "near_done1"
                if(Number(hour)<8){
                  otherLength = '0px'
                }else if(Number(hour)>=8 && Number(hour)<18){
                  let num=34*(Number(hour) -8)/8
                  otherLength = num+'px'
                }else{
                  otherLength = '34px'
                }
              }
              
            }else{
              if (type === 1) {
                cssClass += "nearly_done1";
              } else if (type === 2) {
                if (state) {
                  cssClass += "in_progress1";
                } else {
                  cssClass += "in_progress_w1";
                }
              } else {
                cssClass += "idle1";
              }
            }

          }else{
            if (type === 1) {
              cssClass += "nearly_done";
            } else if (type === 2) {
              if (state) {
                cssClass += "in_progress";
              } else {
                cssClass += "in_progress_w";
              }
            } else {
              cssClass += "idle";
            }
          }
          if(val==='progress3'){
            let widthLenght
            if(status === 'doing'){
              widthLenght = `calc(${relWidth+'%'} + ${otherLength} - 34px)`
            }else{
              widthLenght = `calc(${relWidth+'%'} + ${otherLength})`
            } 
            return (
              "<div class='" +
              cssClass +
              "' style='width:" +widthLenght +";margin-left:"+n+"%'>" +
              "</div>"
            );
          }else{
            return (
              `<div class='${cssClass}' style='width:${relWidth}%;margin-left:${n}%'>${objText!=undefined?objText:''}</div>`
            );
          }

      }
        // 根据定义类型判断颜色顺序
        gantt.templates.task_text = (start, end, task)=> {
          let colorType = task.colorType
          if (colorType === 'j12' || colorType === 'one') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',0,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 3, task.state,'progress3',task.pro.cprogress1,task.ratio,task.taskStatus) // 实际
            );
          } else if (colorType === 'j21') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',task.pro.cprogress1,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 1, task.state,'progress3',0,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'b12') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',0,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 1, task.state,'progress3',task.pro.cprogress1,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'b21') {
            return (
              this.renderLabel(task.progress1, 2, task.state,'progress1',task.pro.cprogress1,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 2, task.state,'progress3',0,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'l12') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',0,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 3, task.state,'progress3',task.pro.cprogress1+task.pro.cprogress2,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'l21') {
            return (
              this.renderLabel(task.progress1, 3, task.state,'progress1',task.pro.cprogress2+task.pro.cprogress1,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 1, task.state,'progress3',0,task.ratio,task.taskStatus)
            );
          } else {
            return (
              this.renderLabel(task.progress1, 3, task.state,'progress1',task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 3, task.state,'progress3',task.ratio,task.taskStatus)
            );
          }
        };

 请假样式方法

      // 请假放假情况
      getLeave(){
        // let year = this.year
        gantt.templates.timeline_cell_class = function(task,date){
                  if(date.getDay()==0||date.getDay()==6){
                      return "weekend" ;
                  }
        }
        // axios.get(`请假url`).then(res=>{
          // if(res.code===0){
              let leaveList = [
                {
                  realname:'王A',
                  '2022-01-20':2,
                  '2022-01-21':3,
                  '2022-01-24':4,
                  '2022-01-25':5,
                }
              ]
              // 请假设置
              gantt.templates.timeline_cell_class = function(task,date){
                  if(date.getDay()==0||date.getDay()==6){
                      return "weekend" ;
                  }
                // // if(self.date11){
                  for(let i=0;i<=leaveList.length-1;i++){
                    if(leaveList[i].realname === task.principal){
                      for(let key in leaveList[i]){
                        if(key!=='realname' && leaveList[i][key]!=0 && leaveList[i][key]!=1){
                          if(moment(date).format('YYYY-MM-DD')===key){
                            if(leaveList[i][key]===2){
                                 return "weekend1" ;
                            }
                            if(leaveList[i][key]===3){
                                 return "weekend3" ;
                            }
                            if(leaveList[i][key]===4){
                                 return "weekend4" ;
                            }
                            if(leaveList[i][key]===5){
                                 return "weekend5" ;
                            }
                          }
                        }
                      }
                    }
                //     // for(let j=0;j<=self.date11[i].supy.length-1;j++){
                //     //   if(task.id===self.date11[i].id && moment(date).format('YYYY-MM-DD')===self.date11[i].supy[j]){
                //     //       return "weekend1" ;
                //     //   }
                //     // }
                  }
                // }
              };
          // }else{

          //   // this.$message.error(res.msg)
          // }

        // })
      }

方法,数据部分

export default {
  name: 'Home',
  components: {
    // HelloWorld
  },
    data(){
      return{
        phaseTime:'2022-02',
        tasks:{
          data:[]
        },
        date11:[],
        simpleImage: '',
        loading: true,
        year:'2022-02',
        searchMessage:{
            principal:'',
            projectName:'',
            targetName:''
        },
        sortType:'', // 排序方式
        showType:'projectName' //默认projectName 甘特图展现形式  负责人 principal  项目 projectName
      }
    },
    methods:{
      // 请假放假情况
      getLeave(){
        // let year = this.year
        gantt.templates.timeline_cell_class = function(task,date){
                  if(date.getDay()==0||date.getDay()==6){
                      return "weekend" ;
                  }
        }
        // axios.get(`请假url`).then(res=>{
          // if(res.code===0){
              let leaveList = [
                {
                  realname:'王A',
                  '2022-01-20':2,
                  '2022-01-21':3,
                  '2022-01-24':4,
                  '2022-01-25':5,
                }
              ]
              // 请假设置
              gantt.templates.timeline_cell_class = function(task,date){
                  if(date.getDay()==0||date.getDay()==6){
                      return "weekend" ;
                  }
                // // if(self.date11){
                  for(let i=0;i<=leaveList.length-1;i++){
                    if(leaveList[i].realname === task.principal){
                      for(let key in leaveList[i]){
                        if(key!=='realname' && leaveList[i][key]!=0 && leaveList[i][key]!=1){
                          if(moment(date).format('YYYY-MM-DD')===key){
                            if(leaveList[i][key]===2){
                                 return "weekend1" ;
                            }
                            if(leaveList[i][key]===3){
                                 return "weekend3" ;
                            }
                            if(leaveList[i][key]===4){
                                 return "weekend4" ;
                            }
                            if(leaveList[i][key]===5){
                                 return "weekend5" ;
                            }
                          }
                        }
                      }
                    }
                //     // for(let j=0;j<=self.date11[i].supy.length-1;j++){
                //     //   if(task.id===self.date11[i].id && moment(date).format('YYYY-MM-DD')===self.date11[i].supy[j]){
                //     //       return "weekend1" ;
                //     //   }
                //     // }
                  }
                // }
              };
          // }else{

          //   // this.$message.error(res.msg)
          // }

        // })
      },
      // 查询数据
      initData() {
        const self = this
        // let year = self.year
        // 处理数据
        self.date11 =[{
          id:'1',
          supy:['2022-06-01','2022-06-02']
        },{
          id:'2',
          supy:['2022-06-02','2022-06-03']
        },]
        this.tasks.data = []
        this.loading = true
        // 是按人搜索还是项目搜索
        if(this.searchMessage.principal==''|| this.searchMessage.principal==null ){
          this.showType = 'projectName'
        }else{
          this.showType = 'principal'
        }
        // http://10.20.11.218:5566
        // axios.get(`/target/month/ganttChart?month=${year}&&principal=${self.searchMessage.principal}&&projectName=${self.searchMessage.projectName}&&targetName=${self.searchMessage.targetName}`).then(res=>{
            this.loading = false
            console.log(data, '000')
           if(data){
             let arr = data
            // 假期设置
            gantt.templates.scale_cell_class = function(date){
                if(date.getDay()==0||date.getDay()==6){
                    return "weekend";
                }
            };
            // 请假
            this.getLeave()
            // 处理数据
            let newArr = []
              // 处理数据
            // 若含用户 searchMessage.principal 是用户搜索 如无 是 项目默认状态
            if(this.searchMessage.principal==''|| this.searchMessage.principal==null ){
                for(let i=0;i<arr.length;i++){
                  let obj1= this.getDate(arr[i].startDate,arr[i].endDate,null,null,1)
                  // 获取当月天数
                  let minMouth = this.year+'-01'
                  let StartminTime
                  if(moment(minMouth).format("YYYY-MM-DD")>moment(arr[i].startDate).format("YYYY-MM-DD")){
                    StartminTime = moment(minMouth).format("MM-DD-YYYY,00:00:00")
                  }else{
                    StartminTime = moment(arr[i].startDate).format("MM-DD-YYYY,00:00:00")
                  }
                  newArr.push({
                    calendar_id:"custom",
                    id:arr[i].id,
                    start_date: new Date(StartminTime),
                    duration:obj1.duration,
                    projectName:arr[i].projectName,
                    progress1: Math.abs(obj1.progress1),
                    text:arr[i].name,
                    planStart: arr[i].startDate,
                    planEnd: arr[i].endDate,
                    open:true
                  })
                  for(let j=0; j<arr[i].monthTargetGanttChartDOList.length;j++){
                    let monthList = arr[i].monthTargetGanttChartDOList[j]
                                  // 参数 计划开始 计划结束 实际开始 实际结束 是否是父级(父级判断开始结束是否在当前月内) 状态
                    let obj = this.getDate(monthList.estStarted, monthList.estEndTed, monthList.realStarted, monthList.realEndTed,0,monthList.taskStatus)
                    gantt.addCalendar({
                      id:"custom", // optional
                      worktime: {
                        hours: ["8:00-17:00"],
                        days: [ 1, 1, 1, 1, 1, 1 ,1]
                      }
                    });
                        const calendar = gantt.getCalendar("custom");
                        calendar.setWorkTime({
                          date:new Date(2021,9,1),
                          hours:false
                        });
                      newArr.push({
                        id: i+1+'-'+j+1,
                        text: monthList.targetName,
                        targetName:monthList.targetName,
                        calendar_id:"custom",
                        start_date: new Date(moment(obj.minTime).format("YYYY-MM-DD,00:00:00")),
                        progress1: Math.abs(obj.progress1),
                        progress2: monthList.targetName,
                        progress3: Math.abs(obj.progress3),
                        duration: obj.duration,
                        projectName:monthList.projectName,
                        principal:monthList.principal,
                        taskName:monthList.taskName,
                        taskStatusName:monthList.taskStatusName,
                        taskStatus: monthList.taskStatus,
                        status: `<span class='${monthList.taskStatusName==='已延期'?'over':monthList.taskStatus}'>${monthList.taskStatusName}</span>`,
                        planStart: monthList.estStarted,
                        planEnd: `<span class='${monthList.taskStatusName==='已延期'?'overing':''}'>${monthList.estEndTed}</span>`,
                        actualStart: monthList.realStarted,
                        actualEnd: monthList.realEndTed,
                        ratio: monthList.ratio,
                        state: obj.state,
                        parent:monthList.targetId,
                        colorType: obj.colorType,
                        pro:obj.progress,
                        open:true
                      })


                  }

              }
            }else{
              // 根据用户进行搜索
              let userList =[]
              let newBrr =[]
              for(let i=0;i<arr.length;i++){
                  for(let j=0; j<arr[i].monthTargetGanttChartDOList.length;j++){
                     let monthList = arr[i].monthTargetGanttChartDOList[j]
                    // 统计人名
                    // userList.push(monthList.principal)
                    // newBrr 数组 estStarted
                    newBrr.push(monthList)
                  }
              }
              // 排序
              for(var i=0;i<newBrr.length-1;i++){//确定轮数
                for(var j=0;j<newBrr.length-i-1;j++){//确定每次比较的次数
                  if(!(moment(newBrr[j].estStarted).isBefore(newBrr[j+1].estStarted))){
                    let tem = JSON.parse(JSON.stringify(newBrr[j]));
                    newBrr[j] = JSON.parse(JSON.stringify(newBrr[j+1]));
                    newBrr[j+1] = JSON.parse(JSON.stringify(tem));
                  }
                }
              }
              newBrr.forEach((item,index)=>{
                let monthList = item
                    // let monthList = arr[i].monthTargetGanttChartDOList[j]
                    // 统计人名
                    userList.push(monthList.principal)
                                  // 参数 计划开始 计划结束 实际开始 实际结束 是否是父级(父级判断开始结束是否在当前月内) 状态
                    let obj = this.getDate(monthList.estStarted, monthList.estEndTed, monthList.realStarted, monthList.realEndTed,0,monthList.taskStatus)
                    gantt.addCalendar({
                      id:"custom", // optional
                      worktime: {
                        hours: ["8:00-17:00"],
                        days: [ 1, 1, 1, 1, 1, 1 ,1]
                      }
                    });
                        const calendar = gantt.getCalendar("custom");
                        calendar.setWorkTime({
                          date:new Date(2021,9,1),
                          hours:false
                        });
                      newArr.push({
                        // id: i+1+'-'+j+1,
                         id: index+1,
                        text: monthList.targetName,
                        targetName:monthList.targetName,
                        calendar_id:"custom",
                        start_date: new Date(moment(obj.minTime).format("YYYY-MM-DD,00:00:00")), //YYYY-MM-DD,h:mm:ss
                        progress1: Math.abs(obj.progress1),
                        progress2: monthList.targetName,
                        progress3: Math.abs(obj.progress3),
                        duration: obj.duration,
                        projectName:monthList.projectName,
                        principal:monthList.principal,
                        taskName:monthList.taskName,
                        taskStatusName:monthList.taskStatusName,
                        taskStatus: monthList.taskStatus,
                        status: `<span class='${monthList.taskStatusName==='已延期'?'over':monthList.taskStatus}'>${monthList.taskStatusName}</span>`,
                        planStart: monthList.estStarted,
                        planEnd: `<span class='${monthList.taskStatusName==='已延期'?'overing':''}'>${monthList.estEndTed}</span>`,
                        actualStart: monthList.realStarted,
                        actualEnd: monthList.realEndTed,
                        ratio: monthList.ratio,
                        state: obj.state,
                        parent:monthList.principal,
                        colorType: obj.colorType,
                        pro:obj.progress,
                        open:true
                      })
                    let newUserList = new Set(userList)
                    newUserList.forEach(value=>{
                    // 添加父级
                      newArr.push({
                        calendar_id:"custom",
                        id:value,
                        principal:value,
                        open:true
                      })
                    })
              })
            }
            this.tasks.data = newArr
            if(this.tasks.data.length>0){
              this.getGantt()
            }
           }else{
            //  this.$message.error(res.msg)
            //  this.loading = true
           }
        // })


      },
      // 处理百分比
      percenToString(num) {
          return Math.floor(num * 100) + "%";
      },
        // 设置每一部分的颜色
      renderLabel(progress, type, state,val,num,objText,status) {
         // progress, type, state,val实际还是计划,num,objText完成度,status状态
        // const self =this
        let hour = moment().format("k"); 
          var relWidth = progress * 100;
          var n=num*100
          var cssClass = "custom_progress ";
          let otherLength = '0px' // 额外长度
          // let doingLenght = 34
          // 实际
          if(val==='progress3'){
            if(status === 'doing'){
              if(objText==='100%'){
                cssClass += "nearly_done1";
                otherLength = '34px'
              }else{
                cssClass += "near_done1"
                if(Number(hour)<8){
                  otherLength = '0px'
                }else if(Number(hour)>=8 && Number(hour)<18){
                  let num=34*(Number(hour) -8)/8
                  otherLength = num+'px'
                }else{
                  otherLength = '34px'
                }
              }
              
            }else{
              if (type === 1) {
                cssClass += "nearly_done1";
              } else if (type === 2) {
                if (state) {
                  cssClass += "in_progress1";
                } else {
                  cssClass += "in_progress_w1";
                }
              } else {
                cssClass += "idle1";
              }
            }

          }else{
            if (type === 1) {
              cssClass += "nearly_done";
            } else if (type === 2) {
              if (state) {
                cssClass += "in_progress";
              } else {
                cssClass += "in_progress_w";
              }
            } else {
              cssClass += "idle";
            }
          }
          if(val==='progress3'){
            let widthLenght
            if(status === 'doing'){
              widthLenght = `calc(${relWidth+'%'} + ${otherLength} - 34px)`
            }else{
              widthLenght = `calc(${relWidth+'%'} + ${otherLength})`
            } 
            return (
              "<div class='" +
              cssClass +
              "' style='width:" +widthLenght +";margin-left:"+n+"%'>" +
              "</div>"
            );
          }else{
            return (
              `<div class='${cssClass}' style='width:${relWidth}%;margin-left:${n}%'>${objText!=undefined?objText:''}</div>`
            );
          }

      },
      // gantt配置
      getGantt(){
        const self =  this
        gantt.clearAll();
        gantt.config.show_progress = true;
        gantt.config.initial_scroll = false;
        // 根据定义类型判断颜色顺序
        gantt.templates.task_text = (start, end, task)=> {
          let colorType = task.colorType
          if (colorType === 'j12' || colorType === 'one') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',0,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 3, task.state,'progress3',task.pro.cprogress1,task.ratio,task.taskStatus) // 实际
            );
          } else if (colorType === 'j21') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',task.pro.cprogress1,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 1, task.state,'progress3',0,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'b12') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',0,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 1, task.state,'progress3',task.pro.cprogress1,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'b21') {
            return (
              this.renderLabel(task.progress1, 2, task.state,'progress1',task.pro.cprogress1,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 2, task.state,'progress3',0,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'l12') {
            return (
              this.renderLabel(task.progress1, 1, task.state,'progress1',0,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 3, task.state,'progress3',task.pro.cprogress1+task.pro.cprogress2,task.ratio,task.taskStatus)
            );
          } else if (colorType === 'l21') {
            return (
              this.renderLabel(task.progress1, 3, task.state,'progress1',task.pro.cprogress2+task.pro.cprogress1,task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 1, task.state,'progress3',0,task.ratio,task.taskStatus)
            );
          } else {
            return (
              this.renderLabel(task.progress1, 3, task.state,'progress1',task.ratio) +
              // renderLabel(task.progress2, 2, task.state) +
              this.renderLabel(task.progress3, 3, task.state,'progress3',task.ratio,task.taskStatus)
            );
          }
        };
        gantt.plugins({ marker: true, tooltip: true }); // 开启marker插件

        var dateToStr = gantt.date.date_to_str(gantt.config.task_date);
        var today = new Date(moment(new Date()).format('YYYY-MM-DD 12:00:00'));
        // 添加固定时间线
        gantt.addMarker({
          start_date: today,
          css: 'today',
          text: '今日:' + moment(new Date()).format('YYYY-MM-DD'),
          title: 'Today: ' + dateToStr(today)
        });
        // 提示框内容
        gantt.templates.tooltip_text = function(start, end, task){
          return (task.principal?`<b>责任人:${task.principal}</b><br/>`:'')+
          (task.text?`<b>阶段目标:${task.text}</b>`:'')+
          (task.projectName?`<br/><b>所属项目:${task.projectName}</b>`:'')+
          (task.taskName?`<br/><b>任务内容:${task.taskName}</b>`:'')+
          (task.planStart?`<br/><b>计划开始:</b>${task.planStart}`:'') +
          (task.planEnd?`<b style="margin-left:16px;margin-right:12px;">计划结束:</b>${task.planEnd}`:'') +
          (task.actualStart?`<br/><b>实际开始:</b>${task.actualStart}`:'') +
          (task.actualEnd?`<b style="margin-left:16px;margin-right:12px;">实际结束:</b>${task.actualEnd}`:'')
        };
        // 渲染甘特图后触发
        gantt.attachEvent("onGanttRender", function(){
          gantt.showDate(new Date());
          // 绑定计划目标
          // document.getElementById('text-title').addEventListener("click",()=>{
          // //  alert("Gantt chart is completely rendered on the page...")
          // })
          // self.outOrNo()
      });
        // 工期计算基本单位
        gantt.config.duration_unit = "day"
        // 设置x轴日期
        gantt.config.scale_unit = "day";
        gantt.config.step = 1;
        gantt.config.date_scale = "%d";
        gantt.config.min_column_width = 34
        // 当右侧不止显示年份时,可以添加展示月日,添加一个就加一行
        gantt.config.subscales = [
          { unit: "month", step: 1, date: "%m" },
        ];
        //甘特图右侧表头的高度
        gantt.config.scale_height = 60;
        //使用中文
        gantt.i18n.setLocale("cn");
        //自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
        gantt.config.autosize = false;
        //只读模式
        gantt.config.readonly = true;
       // 调节网格宽度
        // gantt.config.grid_width = 400;
        // gantt.config.resize_rows = true;
        // gantt.config.grid_resize =true
        // 显示网格
        gantt.config.show_grid = true;

        // gantt.config.grid_resize = true;
        // 点击表格可排序
        // gantt.config.sort = true
        //表格列设置
        if(self.showType==='projectName' ){
          gantt.config.columns = [
            { name: "text",tree:true, resize:true, label: "<span id='text-title'>目标</span>", width: 210, align: "left" },
            { name: "projectName", resize:true, label: "<span id='projectName-title'>项目</span>", width: 190, align: "left" },
            { name: "principal", resize:true, label: "<span id='principal-title'>负责人</span>", width: 70, align: "center" },
            { name: "taskName", resize:true, label: "任务", width: 100, align: "center" },
            { name: "planStart", resize:true, label: "计划开始", width: 80, align: "center" },
            { name: "planEnd", resize:true, label: "计划结束", width: 80, align: "center" },
            // { name: "actualStart", resize:true, label: "实际开始", width: 80, align: "center" },
            // { name: "actualEnd", resize:true, label: "实际结束", width: 80, align: "center" },
            { name: "status", resize:true, label: "状态", width: 60, align: "center" },
            { name: "ratio", resize:true, label: "完成度", width: 50, align: "center" },
          ];
        }else{
          gantt.config.columns = [
            { name: "principal",tree:true, resize:true, label: "<span id='principal-title'>负责人</span>", width: 120, align: "center" },
            { name: "text", resize:true, label: "<span id='text-title'>目标</span>", width: 180, align: "left" },
            { name: "projectName", resize:true, label: "<span id='projectName-title'>项目</span>", width: 160, align: "left" },
            { name: "taskName", resize:true, label: "任务", width: 100, align: "center" },
            { name: "planStart", resize:true, label: "计划开始", width: 80, align: "center" },
            { name: "planEnd", resize:true, label: "计划结束", width: 80, align: "center" },
            // { name: "actualStart", resize:true, label: "实际开始", width: 80, align: "center" },
            // { name: "actualEnd", resize:true, label: "实际结束", width: 80, align: "center" },
            { name: "status", resize:true, label: "状态", width: 60, align: "center" },
            { name: "ratio", resize:true, label: "完成度", width: 60, align: "center" },
          ];
        }
        gantt.templates.grid_folder = function(item) {
            return "<div class='gantt_tree_icon gantt_folder_" +
            (item.$open ? "open" : "closed") + "'></div>";
        };

        gantt.config.work_time = true;
        //任务条上的文字大小 以及取消border自带样式
        gantt.templates.task_class = function() {
          return "firstLevelTask"
        };
        // 初始化
        this.$nextTick(()=>{
          gantt.init(self.$refs.dxgantt);
        })
        // gantt.init(self.$refs.dxgantt);
        // 数据解析
        gantt.parse(this.tasks);
        gantt.render()
        // if(document.querySelectorAll('.weekend1').length>0){
        //   document.querySelectorAll('.weekend1')[0].innerHTML = '请假'
        // }
      },
      //
      // 时间计算 ,status
      getDate(Atime, Btime, Ctime, Dtime,n) {
        let obj = {};
        let minTime
        let maxTime
        let duration
        let progress1 = 0;
        let progress3 = 0;
        let cprogress1 = 0;
        let cprogress2 = 0;
        let cprogress3 = 0;
        let state = true;
        let colorType = true;
        // 获取当月天数
        let maxMouth = this.year+'-'+moment(this.year, "YYYY-MM").daysInMonth()
        let minMouth = this.year+'-01'
        if(Ctime===null && Dtime===null){
          // 未开始 或者 项目分类
          if(n===1){
            if(moment(maxMouth).format("YYYY-MM-DD")<moment(Btime).format("YYYY-MM-DD")){
              maxTime = moment(maxMouth).add(1,'days').format("YYYY-MM-DD,00:00:00")
            }else{
              maxTime = moment(Btime).add(1,'days').format("YYYY-MM-DD,00:00:00")
            }
            if(moment(minMouth).format("YYYY-MM-DD")>moment(Atime).format("YYYY-MM-DD")){
              minTime = moment(minMouth).format("YYYY-MM-DD,00:00:00")
            }else{
              minTime = moment(Atime).format("YYYY-MM-DD,00:00:00")
            }
          }else{
            // 未开始
            maxTime = moment(Btime).add(1,'days').format("YYYY-MM-DD,00:00:00")
            minTime = moment(Atime).format("YYYY-MM-DD,00:00:00")
          }

          duration = this.difference(minTime, maxTime);
          progress1 = 1
          progress3 = 0
          cprogress1 = 1
          cprogress2 = 0
          cprogress3 = 0
          colorType = 'j12'
        }else{
          // 已结束 或 正在进行中
            let cAtime = moment(Atime).format("YYYY-MM-DD,00:00:00")
            let cBtime = moment(Btime).add(1,'days').format("YYYY-MM-DD,00:00:00")
            let cCtime = moment(Ctime).format("YYYY-MM-DD,00:00:00")
            let cDtime
            if(Dtime==null){
              // 正在进行中 .add(1,'days')
              cDtime = moment(new Date()).add(1,'days').format("YYYY-MM-DD,00:00:00")
            }else{
              // 已结束 或 已完成
              cDtime = moment(Dtime).add(1,'days').format("YYYY-MM-DD,00:00:00")
            }
            let arr = [cAtime, cBtime, cCtime, cDtime];
            let timeArr = [];
            arr.forEach((item) => {
              timeArr.push(new Date(item));
            });
            minTime = moment(Math.min(...timeArr)).format("MM-DD-YYYY");
            maxTime = moment(Math.max(...timeArr)).format("YYYY-MM-DD");
            duration = this.difference(minTime, maxTime);


            progress1 = (this.difference(cAtime, cBtime) / duration)
            progress3 = (this.difference(cCtime, cDtime) / duration)
          if (cAtime < cCtime && cCtime < cBtime &&  cBtime < cDtime) {
            // console.log('12相交')
            colorType = 'j12'
            cprogress2 = (this.difference(cCtime, cBtime) / duration)
            cprogress1 = (this.difference(cAtime, cCtime) / duration)
            cprogress3 = (this.difference(cBtime, cDtime) / duration)
          } else if (cBtime > cCtime && cBtime >= cDtime && cCtime >= cAtime && cDtime > cAtime) {
            // console.log('1包含2')
            colorType = 'b12'
            state = true
            cprogress2 = (this.difference(cCtime, cDtime) / duration)
            cprogress1 = (this.difference(cAtime, cCtime) / duration)
            cprogress3 = (this.difference(cDtime, cBtime) / duration)
          } else if (cDtime >= cBtime && cDtime > cAtime && cAtime >= cCtime && cBtime > cCtime) {
            // console.log('2包含1')
            colorType = 'b21'
            state = true
            cprogress2 = (this.difference(cAtime, cBtime) / duration)
            cprogress1 = (this.difference(cCtime, cAtime) / duration)
            cprogress3 = (this.difference(cBtime, cDtime) / duration)
          } else if (cBtime > cDtime && cDtime > cAtime && cAtime > cCtime) {
          //  console.log('21相交')
            colorType = 'j21'
            state = true
            cprogress2 = (this.difference(cAtime, cDtime) / duration)
            cprogress1 = (this.difference(cCtime, cAtime) / duration)
            cprogress3 = (this.difference(cDtime, cBtime) / duration)
          } else if (cBtime <= cCtime) {
            // console.log('12相离')
            colorType = 'l12'
            state = false
            cprogress2 = (this.difference(cBtime, cCtime) / duration)
            cprogress1 = (this.difference(cAtime, cBtime) / duration)
            cprogress3 = (this.difference(cCtime, cDtime) / duration)
          } else if (cDtime <= cAtime) {
            // console.log('21相离')
            colorType = 'l21'
            state = false
            cprogress2 = (this.difference(cDtime, cAtime) / duration)
            cprogress3 = (this.difference(cAtime, cBtime) / duration)
            cprogress1 = (this.difference(cCtime, cDtime) / duration)
          } else {
            colorType = 'one'
            console.log('状态错误')
          }
        }

        obj = {
          state: state,
          minTime: minTime,
          // maxTime: maxTime
          duration: duration * 1,
          progress1: progress1 * 1,
          // progress2: progress2 * 1,
          progress: {
            cprogress1:cprogress1 * 1,
            cprogress2:cprogress2 * 1,
            cprogress3:cprogress3 * 1,
          },
          progress3: progress3 * 1,
          colorType: colorType,
        };
        return obj;
      },
      // 计算时间差
      difference(beginTime, endTime) {
        var dateBegin = new Date(beginTime);
        var dateEnd = new Date(endTime);
        var dateDiff = dateEnd.getTime() - dateBegin.getTime(); //时间差的毫秒数
        var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数
        return dayDiff;
      },
      // 搜索
      onSearch(msg){
        if(msg){
          this.searchMessage = JSON.parse(JSON.stringify(msg))
        }
        this.initData()
      },
      // 重置
      onResert(){
        this.searchMessage ={
          principal:'',
          projectName:'',
          targetName:''
        }
        this.showType = 'projectName'
        this.initData()
      }
    },
    activated(){
      this.initData()
    },
    mounted () {
      this.initData()
    }
}

最后是样式部分

<style lang="less">
.about{
  height: 500px;
  width: 100%;
  background: #00000038;
}
.spin{
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.type-check{
  position: absolute;
  top: 10px;
  right: 63px;
  display: flex;
  align-items: center;
  flex-direction: row;
  span{
    font-size: 14px;
    font-weight: bold;
    line-height: 25px;
    margin-right: 8px;
  }
}
#dhtmlgantt {
  width: 100%;
  height: 100%;
  padding: 0px 1% 20px 1%;
  background: #efefef;
  .gantt{
    width: 100%;
    min-height: 103%;
    height: auto;
    background: #fff;
    /*margin-top: 20px;*/
    border-radius: 2px;
    // display: flex;
    // justify-content: center;
    // align-items: center;
    // padding-top: 12px;
    .gantt_title{
      font-size: 14px;
      font-weight: bold;
      color: #3c4353;
      margin-left: 20px;
    }
    .gantt_render{
      position: relative;
      width: 97%;
      height: 90%;
      /*margin-top: 12px;*/
      margin-left: 20px;
    }
    .simpleImage{
      margin-top: 140px;
    }
    .a-spin{
      margin-top: 240px;
    }
  }
}
.legend {
  padding: 5px 16px 10px 22px;
  display: flex;

  .legendBox {
    display: flex;
    align-items: center;
    margin-right: 20px;

    .legendSml {
      width: 30px;
      height: 16px;
      border-radius: 5px;
      margin-right: 4px;
    }

    .legendColor1 {
        border-radius: 16px;
        border: 1px dashed #035faf;
        background-color: #0086fb36 !important;
    }
    .legendColor2 {
      background: #01bd1a;
    }
    .legendColor3 {
      border-radius: 16px;
      background-color: #80c0f7 !important;
    }
  }
}

.gantt_task_content {
  display: flex;
  align-items: center;
}

.gantt_task_line {
  background: #fff;
}

.custom_progress {
  display: inline-block;
  vertical-align: top;
  text-align: center;
  height: 100%;
}
.nearly_done1 {
  height: 80%;
  border-radius: 16px;
  background-color: #80c0f7 !important;
}
// 正在进行时
.near_done1{
  height: 80%;
  // border-radius: 16px;
  border-bottom-left-radius: 16px;
  border-top-left-radius: 16px;
  background-color: #80c0f7 !important;
}
.nearly_done{
  height: 80%;
  position: absolute;
  border-radius: 16px;
  border: 1px dashed #035faf;
  background-color: #0086fb36 !important;
}

.in_progress1 {
    height: 80%;
  border-radius: 16px;
  // border-bottom-left-radius: 16px;
  // border-top-left-radius: 16px;
  background-color: #80c0f7 !important;
}
.in_progress {
  height: 80%;
  position: absolute;
  border-radius: 16px;
  border: 1px dashed #035faf;
  background-color: #0086fb36 !important;
}
.in_progress_w1 {
  height: 80%;
  border-radius: 16px;
  background-color: #80c0f7 !important;
}
.in_progress_w {
  height: 80%;
  position: absolute;
  border-radius: 16px;
  border: 1px dashed #035faf;
  background-color: #0086fb36 !important;
}
.idle1 {
    height: 80%;
  border-radius: 16px;
  background-color: #80c0f7 !important;
}
.idle {
  height: 80%;
  position: absolute;
  border-radius: 16px;
  border: 1px dashed #035faf;
  background-color: #0086fb36 !important;
}
.firstLevelTask {
  border: none;
}

.secondLevelTask {
  border: none;
}
// 修改
.left-container {
  height: 656px;
}
.weekend{   background: #c9c9c9bf !important;}
.weekend1{
    z-index: 999;
    background: #ffa01165 !important;
    // border-radius: 30px;
}
.weekend3{
    z-index: 999;
    background: #68ff1149 !important;
    // border-radius: 30px;
}
.weekend4{
    z-index: 999;
    background: #20d2ff52 !important;
    // border-radius: 30px;
}
.weekend5{
    z-index: 999;
    background: #b411ff56 !important;
    // border-radius: 30px;
}
.weekend1::before{
      content: ' ';
      display: inline-block;
      height: 22px;
      width: 22px;
      background: url(./img/leave2.png) no-repeat;
      background-size: 22px;
      vertical-align: top;
      padding-right: 10px;
    }
.weekend3::before{
      content: ' ';
      display: inline-block;
      height: 22px;
      width: 22px;
      background: url(./img/leave3.png) no-repeat;
      background-size: 22px;
      vertical-align: top;
      padding-right: 10px;
    }
.weekend4::before{
      content: ' ';
      display: inline-block;
      height: 22px;
      width: 22px;
      background: url(./img/leave4.png) no-repeat;
      background-size: 22px;
      vertical-align: top;
      padding-right: 10px;
    }
.weekend5::before{
      content: ' ';
      display: inline-block;
      height: 22px;
      width: 22px;
      background: url(./img/leave5.png) no-repeat;
      background-size: 22px;
      vertical-align: top;
      padding-right: 10px;
    }
.waring{
    display: flex;
    align-items: center;
    font-size: 14px;
    .waring-text{
      display: flex;
      align-items: center;
      margin-left: 12px;
    }
}
.waring1{
      display: flex;
    align-items: center;
}
.gantt_grid_scale .gantt_grid_head_cell {
    color: #a6a6a6;
    // border-top: 1px solid #cecece !important;
    // border-right: 1px solid #cecece!important;
    border: 1px solid #cecece!important;
}
.gantt_tree_content {
    overflow: hidden;
    height: 100%;
    white-space: nowrap;
    text-overflow: ellipsis;
    min-width: 0;
}
// 进行中 doing   已完成 done  已暂停 pause 未开始 wait 已关闭 closed
.doing{
  padding: 4px 4px;
  color: #0086fba8;
  background: #bbefff9c;
  border:1px solid #93d2fa;
  border-radius: 4px;
  font-size: 12px;

}
.done{
  padding: 4px 4px;
  color: #52c41a;
  background: #f6ffed;
  border:1px solid #b7eb8f;
  border-radius: 4px;
  font-size: 12px;

}
.pause{
  padding: 4px 4px;
  color: #fa8c16;
  background: #fff7e6;
  border:1px solid #ffd591;
  border-radius: 4px;
  font-size: 12px;

}
.wait{
  padding: 4px 4px;
  color: #0a07b3;
  background: #c5c4ff;
  border:1px solid #8a88ff;
  border-radius: 4px;
  font-size: 12px;

}
.closed{
  padding: 4px 4px;
  color: rgb(107, 105, 105);
  background: #fafafa;
  border:1px solid #d9d9d9;
  border-radius: 4px;
  font-size: 12px;

}
.over{
  padding: 4px 4px;
  color: #f5222d;
  background: #fff1f0;
  border:1px solid #ffa39e;
  border-radius: 4px;
  font-size: 12px;
}
.overing{
  color: #f5222d;
}
.gantt_file{
  display: none !important;
}
</style>

最后我在贴上自己使用的数据部分data.js

const data=[
    {
        "id": "id1234w",
        "name": "任务1",
        "projectName": "项目1",
        "startDate": "2022-01-01",
        "endDate": "2022-06-30",
        "monthTargetGanttChartDOList": [
            {
                "targetId": "id1234w",
                "targetName": "任务1",
                "projectName": "项目1",
                "principal": "王A",
                "taskName": "任务12",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-06",
                "realStarted": "2022-01-10",
                "estEndTed": "2022-01-14",
                "realEndTed": "2022-01-11",
                "taskStatusName": "已关闭",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "closed"
            },
            {
                "targetId": "id1234w",
                "targetName": "任务1",
                "projectName": "项目1",
                "principal": "王A",
                "taskName": "任务123",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-12",
                "realStarted": "2022-01-13",
                "estEndTed": "2022-01-14",
                "realEndTed": "2022-01-13",
                "taskStatusName": "已关闭",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "closed"
            },
            {
                "targetId": "id1234w",
                "targetName": "任务1",
                "projectName": "项目1",
                "principal": "王A",
                "taskName": "任务124",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-12",
                "realStarted": "2022-01-12",
                "estEndTed": "2022-01-14",
                "realEndTed": "2022-01-14",
                "taskStatusName": "已关闭",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "closed"
            }
        ]
    },
    {
        "id": "id1234w3",
        "name": "任務1",
        "projectName": "項目2",
        "startDate": "2022-01-01",
        "endDate": "2022-12-31",
        "monthTargetGanttChartDOList": [
            {
                "targetId": "id1234w3",
                "targetName": "任務1",
                "projectName": "項目2",
                "principal": "王A",
                "taskName": "任务22",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-04",
                "realStarted": "2022-01-11",
                "estEndTed": "2022-01-14",
                "realEndTed": "2022-01-14",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-21",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w3",
                "targetName": "任務1",
                "projectName": "項目2",
                "principal": "王A",
                "taskName": "任务223",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-04",
                "realStarted": "2022-01-04",
                "estEndTed": "2022-01-07",
                "realEndTed": "2022-01-14",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-21",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w3",
                "targetName": "任務1",
                "projectName": "項目2",
                "principal": "王A",
                "taskName": "任务224",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-04",
                "realStarted": "2022-01-03",
                "estEndTed": "2022-01-06",
                "realEndTed": "2022-01-17",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-21",
                "ratio": "100%",
                "taskStatus": "done"
            }
        ]
    },
    {
        "id": "id1234w34",
        "name": "任務3",
        "projectName": "项目3",
        "startDate": "2022-01-03",
        "endDate": "2022-01-28",
        "monthTargetGanttChartDOList": [
            {
                "targetId": "id1234w34",
                "targetName": "任務3",
                "projectName": "项目3",
                "principal": "王A",
                "taskName": "任务31",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-03",
                "realStarted": "2022-01-03",
                "estEndTed": "2022-01-11",
                "realEndTed": "2022-03-24",
                "taskStatusName": "已关闭",
                "lastEditedDate": "2022-03-24",
                "ratio": "100%",
                "taskStatus": "closed"
            }
        ]
    },
    {
        "id": "id1234w35",
        "name": "任务4",
        "projectName": "项目4",
        "startDate": "2022-01-04",
        "endDate": "2022-01-31",
        "monthTargetGanttChartDOList": [
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务32",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-04",
                "realStarted": "2022-01-06",
                "estEndTed": "2022-01-05",
                "realEndTed": "2022-01-06",
                "taskStatusName": "已关闭",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "closed"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务33",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-10",
                "realStarted": "2022-01-12",
                "estEndTed": "2022-01-14",
                "realEndTed": "2022-01-18",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务34",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-11",
                "realStarted": "2022-01-11",
                "estEndTed": "2022-01-12",
                "realEndTed": "2022-01-14",
                "taskStatusName": "已关闭",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "closed"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务35",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-11",
                "realStarted": "2022-01-12",
                "estEndTed": "2022-01-18",
                "realEndTed": "2022-01-20",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务36",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-17",
                "realStarted": "2022-01-18",
                "estEndTed": "2022-01-18",
                "realEndTed": "2022-01-18",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务37",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-17",
                "realStarted": "2022-01-19",
                "estEndTed": "2022-01-20",
                "realEndTed": "2022-01-20",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-20",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务38",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-19",
                "realStarted": "2022-01-19",
                "estEndTed": "2022-01-21",
                "realEndTed": "2022-01-21",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-25",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务39",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-25",
                "realStarted": "2022-01-27",
                "estEndTed": "2022-01-27",
                "realEndTed": "2022-01-27",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-27",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务40",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-25",
                "realStarted": "2022-01-22",
                "estEndTed": "2022-01-27",
                "realEndTed": "2022-01-22",
                "taskStatusName": "已完成",
                "lastEditedDate": "2022-01-22",
                "ratio": "100%",
                "taskStatus": "done"
            },
            {
                "targetId": "id1234w35",
                "targetName": "任务4",
                "projectName": "项目4",
                "principal": "王A",
                "taskName": "任务51",
                "freeTime": "",
                "anomalyMarker": "",
                "estWork": "",
                "realWork": "",
                "estStarted": "2022-01-25",
                "realStarted": "2022-01-22",
                "estEndTed": "2022-01-27",
                // "realEndTed": "",
                "taskStatusName": "已暂停",
                "lastEditedDate": "2022-01-22",
                "ratio": "100%",
                "taskStatus": "pause"
            }
        ]
    }
]
export { data }

一个甘特图就完成啦

;