Get the dhtmlx-gantt scheduling interface in one article, use dhtmlxgantt under Vue to design and develop the project Gantt chart module (front-end interface display article (1))

Foreword:

This article is based on the development of the Gantt chart module in a relatively mature and complete project. It does not involve node-related downloads, installations and related uses of vue.

1 Modules to be installed

npm install dhtmlx-gantt
npm install font-awesome

(1) dhtmlxgantt is a plug-in library used in the development of Gantt charts, and it is used for cross-browser and cross-platform applications with relatively complete Gantt charts. Its ancestor component is a JavaScript library that provides a complete set of Ajax-driven UI components.

(2) font-awesome is an icon font library and css framework. Various css styles are provided.

2 import module

    import { gantt } from 'dhtmlx-gantt';
    import "dhtmlx-gantt/codebase/dhtmlxgantt.css";
    import 'font-awesome/css/font-awesome.min.css';

(1) Refer to the dhtmlxgantt.css style to display the plug-in interface;

(2) Reference font-awesome.min.css icons, in order to display various chart plug-ins.

3 Design page format content

(1) Front-end display interface design:

//采用html5的el插件进行前端界面设计
<template>
//建立容器,在容器下存储界面样式与风格
  <div class="app-container">
//容器下设计gantt-container,用以装载甘特图界面的显示内容
    <div ref="gantt" class="gantt-container"></div>
//调用官方在线接口,设置摁钮方式实现甘特图导出(支持多种常见格式)
    <input value="导出PDF" type="button" onclick="gantt.exportToPDF()"/>
    <input value="导出Excel" type="button" onclick='gantt.exportToExcel()'/>
    <input value="导出Png" type="button" onclick="gantt.exportToPNG()"/>
    <input value="载入execl" type="button" onclick="gantt.load()"/>
    //自动导入文件并解析为json格式,便于后续开发导入json数组自动生成甘特图。
<form action="https://export.dhtmlx.com/gantt" method="post"
          enctype="multipart/form-data">
          <input type="file" name="file" />
          <input type="" name="type" value="excel-parse"/>
          <button type="submit">转为json文件</button>
    </form>
  </div>
</template>

(2) Gantt chart display design (please refer to the official document (the content is very complete only for English documents):

The interface sample can be edited online for easy learning: Gantt : Samples (dhtmlx.com)

Official learning documentation: Gantt API Gantt Docs (dhtmlx.com)

The explanation of a website is basically consistent with the official document and is more detailed: dhtmlxGantt tutorial: how to export/import Excel, export to iCal

An official blog, which solves some more complex problems, and has sample codes that can be edited online:

DHTMLX Blog - DHTMLX JavaScript Library - News, tips, and info.

<script>
import { gantt } from 'dhtmlx-gantt';
import "dhtmlx-gantt/codebase/dhtmlxgantt.js";
import "./api.js";
import "dhtmlx-gantt/codebase/ext/dhtmlxgantt_tooltip.js";
import "dhtmlx-gantt/codebase/ext/dhtmlxgantt_marker.js";
import "dhtmlx-gantt/codebase/locale/locale_cn.js";
import "dhtmlx-gantt/codebase/dhtmlxgantt.css";
import 'font-awesome/css/font-awesome.min.css';
export default {
  name: "gantt",
  data() {
    return {
      tasks: {
        data: []
              }
            }
          },
   created() {
    this.getList();
  },
   mounted() {
    const than = this;
    //自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
    gantt.config.autosize = true;
    //允许拖拽
    gantt.config.drag_project = true;
    //只读模式
    //gantt.config.readonly = true;
    //是否显示左侧树表格
    gantt.config.show_grid = true;
    //定义日期编辑器
    var dateEditor = gantt.config.editor_types.date;
    gantt.config.editor_types.end_date = gantt.mixin({
      set_value: function(value, id, column, node){
        var correctedValue = gantt.date.add(value, -1, "day");
        return dateEditor.set_value.apply(this, [correctedValue, id, column, node]);
      },
      get_value: function(id, column, node) {
        var selectedValue = dateEditor.get_value.apply(this, [id, column, node]);
        return gantt.date.add(selectedValue, 1, "day");
      },
    }, dateEditor);
//定义各种编辑器及类型
    var textEditor = {type: "text", map_to: "text"};
    var colorEditor = {type: "color", map_to: "color"};
    var progressEditor={type:"text",map_to:"progress"};
    var startDateEditor = {type: "date", map_to: "start_date"};
    var endDateEditor = {type: "date", map_to: "end_date"};
    var priorityEditor={type: "select", map_to: "priority", options:gantt.serverList("priority")};
    var durationEditor = {type: "number", map_to: "duration", min:0, max: 100};
//设置甘特图中各个列相关配置
    gantt.config.columns = [
      {
        name: 'text',
        /*height:'40',*/
        label: '项目名称',
        editor: textEditor,
        resize: true,
          tree: true,
        width: '230',
       
        }
      },
      {
        name: "add",
        label:"",
        width: 30
      },
      {
        name:'priority',
        align: "center",
        label: "优先级",
        width:50,
        editor: priorityEditor,
        resize:true,
      },
      {
        name: "color",
        align: "center",
        label: "颜色",
        width:40,
        editor: colorEditor,
        resize:true,
      },

      {
        name: 'start_date',
        label: '项目开始时间',
        align: "center",
        editor: startDateEditor,
        resize:true,
        tree: false,
        width: '100',
      },
      {
        name: 'end_date',
        label: '项目结束时间',
        width:100,
        align: 'center',
        editor: endDateEditor,
        resize: true,
      },

      {
        name: 'sDuration',
        label: '任务期',
        align: "center",
        editor: durationEditor,
        resize:true,
        tree: false,
        width: '55',
        template: function (obj) {
          return obj.duration + '天'
        },
        hide: false
      },
      {
        name: 'progress',
        label: '项目进度',
        align: "center",
        tree: false,
        editor: progressEditor,
        resize:true,
        width: '50',
      },
     ]
//配置日期格式
    gantt.templates.task_end_date = function(date){
      return gantt.templates.task_date(new Date(date.valueOf() - 1));
    };
    var gridDateToStr = gantt.date.date_to_str("%Y-%m-%d");
    gantt.templates.grid_date_format = function(date, column){
      if(column === "end_date"){
        return gridDateToStr(new Date(date.valueOf() - 1));
      }else{
        return gridDateToStr(date);
      }
    }
//配置甘特图容器中的行列滚动条
    gantt.config.layout = {
      css: "gantt_container",
      cols: [
        {
          width: 680,
          min_width: 680,
          rows: [{
            view: "grid",
            scrollX: "gridScroll",
            scrollable: true,
            scrollY: "scrollVer"
          },
            {
              view: "scrollbar",
              id: "gridScroll",
              group: "horizontal"
            }
          ]
        },
        {
          resizer: true,
          width: 1
        },
        {
          rows: [{
            view: "timeline",
            scrollX: "scrollHor",
            scrollY: "scrollVer"
          },
            {
              view: "scrollbar",
              id: "scrollHor",
              group: "horizontal"
            }
          ]
        },
        {
          view: "scrollbar",
          id: "scrollVer"
        }
      ]
    };
//配置颜色编辑器提供颜色选择
    gantt.config.editor_types.color = {
      show: function (id, column, config, placeholder) {
        var html = "<div><input type='color' name=''" + column.name + "></div>";
        placeholder.innerHTML = html;
      },
      hide: function () {
      },
      set_value: function (value, id, column, node) {
        this.get_input(node).value = value;
      },
      get_value: function (id, column, node) {
        return this.get_input(node).value || "";
      },
      is_changed: function (value, id, column, node) {
        var input = this.get_input(node);
        return input.value !== value;
      },
      get_input: function (node) {
        return node.querySelector("input");
      },
      is_valid: function (value, id, column, node) {
        var input = this.get_input(node);
        return !!input.value;
      },
      focus: function (node) {
        var input = this.get_input(node);
        input.focus();
      }
    }
//配置时间规模,右上方日历
    gantt.config.subscales = [{
      unit: "year",
      step: 1,
      format: "%Y",
       template: weekScaleTemplate,
    },
    
      {
        unit: "day",
        step: 1,
        format: "%D",
        template:daysStyle,
      }
    ];
    // 初始化
    gantt.init(this.$refs.gantt)
    // 数据解析
    gantt.parse(this.tasks)
     //设置任务条进度内容
    gantt.templates.progress_text = function (start, end, task) {
      return "<div style='text-align:left;color:#fff;padding-left:20px'>" + Math.round(task.progress) +
        "% </div>";
    };
    //任务条显示内容
    gantt.templates.task_text = function (start, end, task) {
      return "<div style='text-align:center;color:#fff'>" + task.text + '(' + task.duration + '天)' +
        "</div>";
    }
    //任务条上的文字大小 以及取消border自带样式
    gantt.templates.task_class = function (start, end, item) {
      return item.$level == 0 ? 'firstLevelTask' : 'secondLevelTask'
    }
     //gantt图任务悬浮窗位置
    gantt.config.tooltip_offset_x = 10;
    gantt.config.tooltip_offset_y = 30;
    //激活列表展开、折叠功能
    gantt.config.open_split_tasks = true;
    //创建新事件通过点击”+“打开灯箱
    gantt.config.details_on_create = true;
    //甘特图图表宽度自适应
    gantt.config.autofit = true;
    //用户可以通过拖拽调整行高
    gantt.config.resize_rows = true;
    //图标项目栏可以任意拖拽
    gantt.config.order_branch = true;
    gantt.config.order_branch_free = true;
    //新增空白列后新增项目
    gantt.config.placeholder_task = true;
    //图标刷新后位置不变
    gantt.config.preserve_scroll = true;
    gantt.config.round_dnd_dates = true;
    //设置甘特图表头高度
    gantt.config.scale_height = 100;
    //是否显示依赖连线(取消)
    gantt.config.show_links = true;
    //点击表头可排序
    gantt.config.sort = true;
    //允许拖放
    gantt.config.drag_project = true;
    // 初始化
    gantt.init(this.$refs.gantt)
    // 数据解析
    gantt.parse(this.tasks)
    gantt.exportToExcel({
      name: "document.xlsx",
      columns: [
        {id: "text", header: "Title", width: 150},
        {id: "start_date", header: "Start date", width: 250, type: "date"}
      ],
      server: "https://myapp.com/myexport/gantt",
      visual: true,
      cellColors: true,
      data: {},
      date_format: "dddd d, mmmm yyyy"
    });

    gantt.exportToPNG({
      name: "gantt.png",      
      locale: "cn",    
      data: {},     
      server: "https://export.dhtmlx.com/gantt",
      raw: false,
      callback: function (res) {
        alert(res.gantt);
      }
    });
      gantt.exportToPDF({
      name: "gantt.pdf",      
      locale: "cn",
      skin: 'terrace',
      data: [],
      server: "https://myapp.com/myexport/gantt",
      raw: false,
      callback: function (res) {
        alert(res.data);
      }
    })
    // 初始化
    gantt.init(this.$refs.gantt)
    // 数据解析
    gantt.parse(this.tasks)
     //表格列宽自适应
    gantt.config.autofit=true;
    //r任务或者连线拖拽到浏览器屏幕外时,自动触发滚动效果
    gantt.config.autoscroll=true;
    //时间轴图表中,任务条形图的高度
    gantt.config.task_height = 28
    //时间轴图表中,甘特图的高度
    gantt.config.row_height = 36
    //时间轴图表中,如果不设置,只有行边框,区分上下的任务,设置之后带有列的边框,整个时间轴变成格子状。
    gantt.config.show_task_cells = true
    //当task的长度改变时,自动调整图表坐标轴区间用于适配task的长度
    gantt.config.fit_tasks = true;
    gantt.config.min_column_width = 40;
    gantt.config.auto_types = true;
    gantt.config.xml_date = "%Y-%m-%d";
    gantt.config.scale_unit = "month";
    gantt.config.step = 1;
    gantt.config.date_scale = "%Y年%M";
    gantt.config.start_on_monday = true;
    gantt.config.scale_height = 90;
    gantt.config.autoscroll = true;
    gantt.config.calendar_property = "start_date";
    gantt.config.calendar_property = "sPend";
    gantt.config.readonly = true;
    // 初始化
    gantt.init(this.$refs.gantt)
    // 数据解析
    gantt.parse(this.tasks)
    gantt.i18n.setLocale('cn');
    // 初始化
    gantt.init(this.$refs.gantt)
    // 数据解析
    gantt.parse(this.tasks)

(3) About css style rendering Gantt chart interface

<style lang="scss">
.firstLevelTask {
  border: none;

  .gantt_task_content {
    font-size: 13px;
  }
}

.secondLevelTask {
  border: none;
}


.weekend{
  background: #f4f7f4 !important;
}
.gantt_selected .weekend{
  background: #f7eb91 !important;
}


.thirdLevelTask {
  border: 2px solid #da645d;
  color: #da645d;
  background: #da645d;
}

.milestone-default {
  border: none;
  background: rgba(0, 0, 0, 0.45);
}

.milestone-unfinished {
  border: none;
  background: #5692f0;
}

.milestone-finished {
  border: none;
  background: #84bd54;
}

.milestone-canceled {
  border: none;
  background: #da645d;
}

html,
body {
  margin: 0px;
  padding: 0px;
  height: 100%;
  overflow: hidden;
}
.task-color-cell{
  margin:10%;
  width:20px;
  height:20px;
  border:1px solid #cecece;
  display:inline-block;
  border-radius:20px;
}

.container {
  height: 100%;
  width: 100%;
  position: relative;

  .gantt_grid_head_cell {
    padding-left: 20px;
    text-align: left !important;
    font-size: 14px;
    color: #333;
  }

  .select-wrap {
    position: absolute;
    top: 25px;
    z-index: 99;
    width: 90px;
    left: 180px;

    .el-input__inner {
      border: none;
    }
  }

  .left-container {
    height: 100%;
  }


  .parent {
    .gantt_tree_icon {
      &.gantt_folder_open {
        // background-image: url(../../../../assets/icons/tree-table.svg) !important;
      }

      &.gantt_folder_closed {
        // background-image: url(../../../../assets/icons/documentation.svg) !important;
      }
    }
  }

  .green,
  .yellow,
  .pink,
  .popular {
    .gantt_tree_icon.gantt_file {
      background: none;
      position: relative;

      &::before {
        content: "";
        width: 10px;
        height: 10px;
        border-radius: 50%;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
      }
    }
  }

  .green {
    .gantt_tree_icon.gantt_file {
      &::before {
        background: #84bd54;
      }
    }
  }

  .yellow {
    .gantt_tree_icon.gantt_file {
      &::before {
        background: #fcca02;
      }
    }
  }

  .pink {
    .gantt_tree_icon.gantt_file {
      &::before {
        background: #da645d;
      }
    }
  }

  .popular {
    .gantt_tree_icon.gantt_file {
      &::before {
        background: #d1a6ff;
      }
    }
  }

}

.left-container {
  height: 100%;
}

.gantt_task_content {
  text-align: left;
  padding-left: 10px;
}



#gantt_here{
  width: 100vw;
  height: 100vh;
}


.fa {
  cursor: pointer;
  font-size: 14px;
  text-align: center;
  opacity: 0.2;
  padding: 5px;
}

.fa:hover {
  opacity: 1;
}

.fa-pencil {
  color: #ffa011;
}

.fa-plus {
  color: #328EA0;
}

.fa-times {
  color: red;
}

.weekend{
  background: #f4f7f4;
}
.gantt_selected .weekend{
  background: #f7eb91;
}


</style>

The final implementation style is as follows:

It supports editable text, click on the date to pop up the calendar to select the date, select different colors for different tasks, and automatically display the progress. The total duration of the progress bar and the current progress are displayed in dark and light colors.

At the same time, it supports the export of files such as png\pdf/execl/.

Guess you like

Origin blog.csdn.net/weixin_44979308/article/details/129280079