当前位置:   article > 正文

Vue 甘特图 gantt 安装使用(dhtmlx-gantt)_vue gantt

vue gantt

Vue 甘特图 gantt 安装使用

(gantt-elastic)参考文章@shenjuncaci

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

dhtmlx@官方文档

安装

npm i dhtmlx-gantt
  • 1

使用

创建一个容器

  <div ref="gantt" class="gantt-container"></div>
  • 1

引入依赖

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

初始化及数据解析

        //  初始化
          gantt.init(this.$refs.gantt)
          //  数据解析
          gantt.parse(this.tasks)
  • 1
  • 2
  • 3
  • 4

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

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 +
            "<br/>" +
            "阶段:" +
            task.text +
            "<br/>" +
            gantt.templates.tooltip_date_format(start)
          );
        };
      });

      //设置任务条进度内容
      gantt.templates.progress_text = function (start, end, task) {
        return (
          "<div style='text-align:left;color:#fff;padding-left:20px'>" +
          Math.round(task.progress * 100) +
          "% </div>"
        );
      };

      //任务条显示内容
      gantt.templates.task_text = function (start, end, task) {
        // return task.text + '(' + task.duration + '天)';
        return (
          "<div style='text-align:center;color:#fff'>" +
          task.text +
          "(" +
          task.duration +
          "天)" +
          "</div>"
        );
      };

      // 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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565

踩坑记录

样式不生效问题

再给 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)
      })
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

甘特图 数据叠加

解决办法

  • 调用 gantt 的 clearAll 方法.
// gantt 实例添加自定义方法 customEvent
gantt.attachEvent("CustomEvent", function (param1, param2) {
      gantt.clearAll()
});

// 在组件销毁的时候  调用 gantt 实例的自定义方法 customEvent
  destroyed() {
    gantt.callEvent('CustomEvent')
  }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

甘特图 悬浮框不消失(tooltip 一直展示)

解决办法

  • 可以使用 gantt 实例添加一个 自定义方法.
  • 自定义方法中 调用 tooltips 的 hide 方法.

具体代码如下:

// gantt 实例添加自定义方法 customEvent
gantt.attachEvent("CustomEvent", function (param1, param2) {
  gantt.ext.tooltips.tooltip.hide();
});

// 在组件销毁的时候  调用 gantt 实例的自定义方法 customEvent
  destroyed() {
    gantt.callEvent('CustomEvent')
  }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/499566
推荐阅读
相关标签