Vue 甘特图 gantt 安装使用

Vue 甘特图 gantt 安装使用

(gantt-elastic)参考文章@shenjuncaci

(dhtmlx)参考文章@秃头的铲屎官

dhtmlx@官方文档

安装

npm i dhtmlx-gantt

使用

创建一个容器

  

引入依赖

import { gantt } from "dhtmlx-gantt";
import "dhtmlx-gantt/codebase/dhtmlxgantt.css";

初始化及数据解析

        //  初始化
          gantt.init(this.$refs.gantt)
          //  数据解析
          gantt.parse(this.tasks)

其他配置可根据自己需求参考官网添加。

dhtmlx 实操案例 (简易 demo)

<template>
  <div class="container">
    <div class="select-wrap">
      <el-select v-model="value" placeholder="请选择" @change="selectChange">
        <el-option
          v-for="item in options"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        >
        el-option>
      el-select>
    div>
    <div ref="gantt" class="gantt-container">div>
  div>
template>
<script>
  import { gantt } from "dhtmlx-gantt";
  import "dhtmlx-gantt/codebase/dhtmlxgantt.css";

  export default {
    name: "gantt",
    data() {
      return {
        tasks: {
          data: [],
        },
        options: [
          {
            value: "1",
            label: "全部",
          },
          {
            value: "2",
            label: "完成",
          },
          {
            value: "3",
            label: "正常",
          },
          {
            value: "4",
            label: "异常",
          },
          {
            value: "5",
            label: "未启动",
          },
        ],
        value: "1",
      };
    },
    methods: {
      //开始时间-结束时间参数
      DateDifference: function (strDateStart, strDateEnd) {
        var begintime_ms = Date.parse(
          new Date(strDateStart.replace(/-/g, "/"))
        ); //begintime 为开始时间
        var endtime_ms = Date.parse(new Date(strDateEnd.replace(/-/g, "/"))); // endtime 为结束时间
        var date3 = endtime_ms - begintime_ms; //时间差的毫秒数
        var days = Math.floor(date3 / (24 * 3600 * 1000));
        return days;
      },
      initData: function () {
        this.tasks.data = [
          {
            id: 1,
            text: "概念设计",
            start_date: "2020-04-08",
            duration: 10,
            open: true, //默认打开,
            toolTipsTxt: "xxx项目概念设计",
            progress: 0.6,
            status: "parent",
          },
          {
            toolTipsTxt: "xxx项目-项目启动会",
            text: "项目启动会-外部", // 任务名
            start_date: "2020-04-08", // 开始时间
            id: 11, // 任务id
            duration: 3, // 任务时长,从start_date开始计算
            parent: 1, // 父任务ID
            type: 1,
            progress: 0.5,
            status: "yellow",
          },
          {
            toolTipsTxt: "xxx项目-项目启动会议",
            text: "项目启动会-内部",
            start_date: "2020-04-11",
            id: 12,
            duration: 2,
            parent: 1,
            type: 2,
            progress: 0.6,
            status: "pink",
          },
          {
            toolTipsTxt: "xxx项目开工会",
            text: "项目开工会",
            start_date: "2020-04-13",
            id: 13,
            duration: 4,
            parent: 1,
            type: 3,
            progress: 1,
            status: "green",
          },
          {
            toolTipsTxt: "xxx项目-项目分析",
            text: "项目分析",
            start_date: "2020-04-13",
            id: 14,
            duration: 4,
            parent: 1,
            type: 4,
            progress: 0.6,
            status: "popular",
          },

          {
            id: 2,
            text: "方案设计",
            start_date: "2020-04-08",
            duration: 8,
            open: true,
            toolTipsTxt: "xxx方案设计",
            state: "default",
            // color:"#409EFF", //设置颜色
            progress: 0.6,
            status: "parent",
          },
          {
            toolTipsTxt: "xxx新项目原型图设计",
            text: "原型图设计",
            start_date: "2020-04-08",
            id: 21,
            duration: 2,
            parent: 2,
            type: 1,
            progress: 0.6,
            status: "yellow",
          },
          {
            toolTipsTxt: "xxx项目-项目设计图",
            text: "设计图设计",
            start_date: "2020-04-09",
            id: 22,
            duration: 2,
            parent: 2,
            type: 2,
            progress: 0.6,
            status: "pink",
          },
          {
            toolTipsTxt: "xxx项目-项目确认",
            text: "项目确认",
            start_date: "2020-04-11",
            id: 23,
            duration: 2,
            parent: 2,
            type: 3,
            progress: 1,
            status: "green",
          },
        ].map(function (current, ind, arry) {
          var newObj = {};
          if (current.type) {
            //存在type字段 说明非一级菜单,判断阶段的具体类型 设置不同颜色
            if (current.type == 1) {
              //冒烟
              newObj = Object.assign({}, current, {
                color: "#fcca02",
              });
            } else if (current.type == 2) {
              //单元
              newObj = Object.assign({}, current, {
                color: "#fec0dc",
              });
            } else if (current.type == 3) {
              //回归
              newObj = Object.assign({}, current, {
                color: "#62ddd4",
              });
            } else if (current.type == 4) {
              newObj = Object.assign({}, current, {
                color: "#d1a6ff",
              });
            }
          } else {
            //一级菜单是蓝色的
            newObj = Object.assign({}, current, {
              color: "#5692f0",
            });
          }

          return newObj;
        });
      },
      selectChange(val) {
        console.log(val);

        //测试用例
        var obj = {
          toolTipsTxt: "新增任务",
          text: "新增任务", // 任务名
          start_date: "2020-04-15", // 开始时间
          id: 24, // 任务id
          duration: 2, // 任务时长,从start_date开始计算
          parent: 2, // 父任务ID
          type: 4,
          progress: 0,
          status: "popular",
        };
        this.tasks.data.push(obj);

        // 数据解析
        gantt.parse(this.tasks);
        // 刷新数据
        gantt.refreshData();
      },
    },
    mounted() {
      this.initData();

      //自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
      gantt.config.autosize = true;
      //只读模式
      gantt.config.readonly = true;
      //是否显示左侧树表格
      gantt.config.show_grid = true;
      //表格列设置
      gantt.config.columns = [
        {
          name: "text",
          label: "阶段名字",
          tree: true,
          width: "280",
          onrender: function (task, node) {
            node.setAttribute(
              "class",
              "gantt_cell gantt_last_cell gantt_cell_tree " + task.status
            );
          },
        },
        {
          name: "duration",
          label: "时长",
          align: "center",
          template: function (obj) {
            return obj.duration + "天";
          },
          hide: true,
        },
      ];

      var weekScaleTemplate = function (date) {
        var dateToStr = gantt.date.date_to_str("%m %d");
        var endDate = gantt.date.add(
          gantt.date.add(date, 1, "week"),
          -1,
          "day"
        );
        var weekNum = gantt.date.date_to_str("第 %W 周");
        return weekNum(date);
      };
      var daysStyle = function (date) {
        var dateToStr = gantt.date.date_to_str("%D");
        if (dateToStr(date) == "六" || dateToStr(date) == "日")
          return "weekend";
        return "";
      };
      gantt.config.subscales = [
        {
          unit: "week",
          step: 1,
          template: weekScaleTemplate,
        },
        {
          unit: "day",
          step: 1,
          format: "%d",
        },
      ];

      gantt.plugins({
        tooltip: true,
      });
      gantt.attachEvent("onGanttReady", function () {
        var tooltips = gantt.ext.tooltips;
        gantt.templates.tooltip_text = function (start, end, task) {
          return (
            task.toolTipsTxt +
            "
"
+ "阶段:" + task.text + "
"
+ gantt.templates.tooltip_date_format(start) ); }; }); //设置任务条进度内容 gantt.templates.progress_text = function (start, end, task) { return ( "
" + Math.round(task.progress * 100) + "%
"
); }; //任务条显示内容 gantt.templates.task_text = function (start, end, task) { // return task.text + '(' + task.duration + '天)'; return ( "
" + task.text + "(" + task.duration + "天)" + "
"
); }; // gantt.templates.scale_cell_class = function(date) { // /*if(date.getDay()== 0 || date.getDay()== 6){ // return "weekend"; // }*/ // return 'weekend' // } //任务栏周末亮色 /*gantt.templates.task_cell_class = function(item,date){ if(date.getDay()== 0 || date.getDay()== 6){ return "weekend"; } };*/ //任务条上的文字大小 以及取消border自带样式 gantt.templates.task_class = function (start, end, item) { return item.$level == 0 ? "firstLevelTask" : "secondLevelTask"; }; gantt.config.layout = { css: "gantt_container", cols: [ { width: 280, min_width: 280, 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.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 = 50; 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 = "end_date"; gantt.config.readonly = true; gantt.i18n.setLocale("cn"); // 初始化 gantt.init(this.$refs.gantt); // 数据解析 gantt.parse(this.tasks); }, };
script> <style lang="scss"> .firstLevelTask { border: none; .gantt_task_content { font-size: 13px; } } .secondLevelTask { border: none; } .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; } .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/gantt-icon.svg) !important; // } // &.gantt_folder_closed { // background-image: url(assets/gantt-icon-up.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; } style>

踩坑记录

样式不生效问题

再给 style 标签添加了 scoped 属性后 可能会出现样式不生效的问题

解决办法

  • scss 环境使用 ::v-deep进行样式穿透
  • less 环境使用 /deep/ 进行样式穿透
  • 删掉 scoped 属性。

甘特图数据未渲染

再调用接口的数据赋值后,甘特图的数据为渲染。

可能原因:

gant 在实例的时候 还没有获取到 data 数据

解决办法:

  • 使用 async await 在获取的数据之后,再让 gant 进行实例
  • 使用 this.$nextTick(()=>{}) 再拿到最新的数据后 进行更新。
//  数据初始化处理的方法
   initData: function () {
      this.tasks.data = this.jsondata.map((item) => {
        return {
          id: item.id,
          text: item.workItem,
          start_date: transitionYmdTime(item.planStartDate),
          end_date: transitionYmdTime(item.planCompletedDate),
          open: true, // 默认打开,
          toolTipsTxt: item.workItem
        }
      })
    },
//  甘特图数据接口
 gantDataSearch() {
      let bodyData = { apqpKey: this.apqpKey }
      API.apqpPowerMeeting(bodyData).then((res) => {
        this.jsondata = res.workItems
        this.$nextTick(() => {
            // 获取到数据后 进行数据处理
          this.initData()
          // 使用gantt实例 进行 初始化
          gantt.init(this.$refs.gantt)
          // 使用gantt实例  数据解析
          gantt.parse(this.tasks)
        })
        console.log('gant数据', res)
      })
    }

你可能感兴趣的:(vue.js,甘特图,前端)