首页 前端知识 dhtmlx-gantt甘特图

dhtmlx-gantt甘特图

2024-05-25 09:05:32 前端知识 前端哥 788 424 我要收藏

需求:

1、不同状态的任务用不同颜色展示

2、当前日期添加竖线标志

3、周末设置背景颜色

4、可按小时、日、周切换(切换时间范围也需同步修改)

官方文档:Gantt API Gantt Docs

官方Demo Gantt : Samples

 一、安装依赖

npm install dhtmlx-gantt

二、实现

<template>
  <div class="app-container">
    <!-- 操作按钮 -->
    <div class="ope-wrap">
      <div class="ope-left">
        <el-form ref="form" :model="form" label-width="75px">
          <el-form-item label="车间名称">
            <el-select v-model="form.workShop" placeholder="请选择" clearable @change="handleWorkSopChange"
              @clear="handleClear">
              <el-option v-for="item in options" :key="item.workshopId" :label="item.workshopName"
                :value="item.workshopId">
              </el-option>
            </el-select>
          </el-form-item>
        </el-form>
        <div class="e-btn">
          <el-button type="primary" @click="handleEditClick">编辑</el-button>
        </div>
      </div>
      <div class="ope-right">
        <el-button-group>
          <el-button v-for="item in headUnitList" :key="item.value" @click="handleUnitClick(item)"
            :type="activeUnit===item.value ? 'primary' : 'default'">{{ item.label }}</el-button>
        </el-button-group>
      </div>
    </div>
    <div ref='ganttContainer' class='ganttContainer'></div>
  </div>
</template>

<script>
  const proroderStatus = {
    "CJ": "创建",
    "SX": "生效",
    "KG": "开工",
    "ZT": "暂停"
  };
  const priorityList = {
    "ZC": "正常",
    "YX": "优先",
    "JJ": "加急",
    "TJ": "特急"
  };
  import gantt from 'dhtmlx-gantt';
  import {
    listWorkshop
  } from "@/api/mes/md/workshop";
  import {
    selectWorkOrderByGantt
  } from "@/api/mes/pro/proWorkOrder";
  export default {
    name: 'gantt',
    data() {
      return {
        form: {
          workShop: ""
        },
        options: [],
        headUnitList: [{
          value: "HOUR",
          label: "小时"
        }, {
          value: "DAY",
          label: "日"
        }, {
          value: "WEEK",
          label: "周"
        }],
        activeUnit: "DAY", // 默认以日为表头单位 可选:HOUR、DAY、WEEK
        // 示例数据
        // [{
        //   id: 1,
        //   dome1: '项目一',
        //   unscheduled: true, // 配合显示计划外的任务
        //   render: 'split', // 这个是一行能够展示多个任务的关键点
        //   parent: 0, // 0 作为独立项目 这个是一行能够展示多个任务的关键点
        // }, {
        //   id: 3,
        //   text: '这是一个开工工单',
        //   start_date: '2023-11-17',
        //   duration: 7,
        //   progress: 0.4,
        //   parent: 1
        // }]
        tasks: [], // 储存甘特图 - 内容数据集合
        selectedTaskId: undefined,
      }
    },
    methods: {
      getWorkShopList() {
        listWorkshop().then(res => {
          this.options = res.rows;
        }).catch(err => null);
      },
      getTasksList() {
        selectWorkOrderByGantt({
          workshopId: this.form.workShop
        }).then(res => {
          this.tasks = res.data || [];
          // 根据不同状态设置颜色
          this.setBarColor();
          this.initGantt()
        }).catch(err => null);
      },
      handleWorkSopChange(val) {
        this.getTasksList();
      },
      handleClear() {
        this.getTasksList();
      },
      initGantt() {
        gantt.i18n.setLocale('cn'); // 汉化-默认是英文
        gantt.plugins({
          tooltip: true, // 启用tooltip悬浮框
          marker: true, // 时间标记
          // drag_timeline: true, // 拖动图
        });
        gantt.config.scale_height = 40; // 设置表头高度
        // 显示计划外的任务 一般情况下刚开始时,数据是不存在任务开始时间的start_date的,不打开这个属性,则数据则无法显示。开启后需要数据配合设置:unscheduled: true
        gantt.config.show_unscheduled = true;
        // 隐藏进度条拖动按钮 任务中默认会有一个能够拖动的进度按钮
        gantt.config.show_progress = true;
        // 配置 甘特图 表头
        // 小时 默认展示 当前日期前8点-明天8点  最大展示 2天前-5天后
        // 日 默认展示 当前日期前4天-后10天  最大展示 7天前-30天后
        // 周 默认展示 当前日期前2周-后3周  最大展示 4周前-未来12周
        const startTime = this.getDay(-7);
        const endTime = this.getDay(30);
        gantt.config.start_date = new Date(startTime);
        gantt.config.end_date = new Date(endTime);
        // 设置表头维度,默认以日为单位
        gantt.config.scales = [{
          unit: 'day',
          step: 1,
          date: '%d',
          format: this.dayTemplate
        }];
        gantt.config.scale_unit = 'day';
        gantt.config.date_scale = '%D/%m.%d';
        gantt.config.xml_date = '%Y-%m-%d %H:%i:%s'; // 格式化日期匹配格式
        // 周末背景颜色设置
        gantt.templates.scale_cell_class = function (date) {
          if (date.getDay() == 0 || date.getDay() == 6) {
            return "weekend";
          }
        };
        // 日的时候表头左对齐
        if (this.activeUnit === "DAY") {
          gantt.templates.scale_row_class = function (date) {
            return "day-label";
          };
        }
        // 配置甘特图 左侧表头
        gantt.config.columns = [{
          name: 'dome1',
          label: '制造单元',
          width: 100
        }];
        // 点击空白事件
        // gantt.attachEvent("onEmptyClick", function (e) {
        //   const task_id = e.target.parentNode.attributes.task_id.value; // id
        //   const targetLeft = e.target.style['left'].replace('px', ''); // 当前触发对象的位置
        //   const [datenode, weeksnode] = gantt.$task_scale['children']; // 获取日期所有节点数据
        //   let dateActive = null; // 存储点击位置对应的日期值

        //   for (let key in datenode.children) {
        //     if (datenode.children[key].style && datenode.children[key].style['left']) {
        //       let dateNodeLeft = datenode.children[key].style['left'].replace('px', '');
        //       if (dateNodeLeft == targetLeft) {
        //         dateActive = datenode.children[key].innerHTML
        //       }
        //     }
        //   };
        //   gantt.createTask({
        //     text: '',
        //     typeId: '',
        //     start_date: `2023-8-${dateActive}`,
        //     duration: 1,
        //   }, task_id)
        // });

        // 选择任务时触发
        gantt.attachEvent("onTaskSelected", (id) => {
          this.selectedTaskId = id;
        });
        // 任务被拖拽后处理逻辑
        gantt.attachEvent("onAfterTaskDrag", (id, mode, e) => {
          this.tasks.map(v => {
            if (v.id == id) {
              console.log(v, '----------------ccc')
            }
          });
        });

        // 显示到任务上的文本
        gantt.templates.task_text = function (start, end, task) {
          return "" + task.productionWorkorderCode + "<span style='margin-left:20px;'></span>" + task
            .completedQuantity + "/" + task.planQuantity;
        };
        // 鼠标悬浮工具提示文本配置
        gantt.templates.tooltip_text = function (start, end, task) {
          if (task.parent === 0) {
            return task.dome1;
          } else {
            return `
            <div style='display:flex;flex-wrap:wrap;align-items: center;width:300px;'>
              <div style='width: 60%;line-height: 18px;'>工单编号:${task.productionWorkorderCode}</div>
              <div style='width: 40%;line-height: 18px;'>状态:${proroderStatus[task.status]}</div>
              <div style='width: 60%;line-height: 18px;'>设备号:${task.deviceCode}</div>
              <div style='width: 40%;line-height: 18px;'>物料编码:${task.itemCode}</div>
              <div style='width: 60%;line-height: 18px;'>数量:${task.completedQuantity}/${task.planQuantity}</div>
              <div style='width: 40%;line-height: 18px;'>生产班组:${task.teamName}</div>
              <div style='width: 60%;line-height: 18px;'>工序名称:${task.processName}</div>
              <div style='width: 40%;line-height: 18px;'>优先级:${priorityList[task.priority]}</div>
              <div style='width: 60%;line-height: 18px;'>计划时间:${gantt.templates.tooltip_date_format(start)} ~ ${gantt.templates.tooltip_date_format(end)}</div>
            </div>
            `;
          }
        };

        gantt.clearAll(); //  清除缓存
        gantt.init(this.$refs.ganttContainer); // 初始化
        // 配置数据
        gantt.parse({
          data: this.tasks
        });
        // 绘制今天的竖线
        this.todayMaker();
      },


      todayMaker() {
        const date_to_str = gantt.date.date_to_str('%Y/%m/%d');
        const today = new Date();
        gantt.addMarker({
          start_date: today,
          css: 'today',
          text: '今天',
          title: "今天: " + date_to_str(today)
        });
      },

      weekScaleTemplate(date) {
        var dateToStr = gantt.date.date_to_str("%M %d");
        var endDate = gantt.date.add(gantt.date.add(date, 1, "week"), -1, "day");
        return dateToStr(date) + "~" + dateToStr(endDate);
      },
      dayTemplate(date) {
        var dateToStr = gantt.date.date_to_str("%M %d");
        var weekDay = gantt.date.date_to_str("%D");
        return weekDay(date) + "/" + dateToStr(date);
      },

      setBarColor() {
        this.tasks.map(v => {
          var newObj = {};
          if (v.status === "CJ") {
            newObj = Object.assign(v, {
              'color': '#aaa8eb'
            });
          } else if (v.status === "SX") {
            newObj = Object.assign(v, {
              'color': '#7cbbff'
            });
          } else if (v.status === "KG") {
            newObj = Object.assign(v, {
              'color': '#aadab4'
            });
          } else {
            // 暂停
            newObj = Object.assign(v, {
              'color': '#ffc97c'
            });
          }
          return newObj;
        });
      },

      handleUnitClick(obj) {
        this.activeUnit = obj.value;
        gantt.config.scales = [];
        gantt.config.subscales = [];
        switch (obj.value) {
          case "HOUR":
            gantt.config.start_date = new Date(this.getDay(-2));
            gantt.config.end_date = new Date(this.getDay(5));
            gantt.config.subscales = [{
              unit: "hour",
              step: 2,
              format: "%H"
            }];
            gantt.templates.scale_cell_class = "";
            gantt.templates.scale_row_class = function (date) {
              return "hour-label";
            };
            gantt.config.scale_unit = 'day';
            gantt.config.date_scale = '%m/%d';
            gantt.config.scale_height = 50;
            gantt.config.duration_unit = "hour";
            gantt.config.duration_step = 2;
            gantt.render();
            break;
          case 'DAY':
            gantt.config.start_date = new Date(this.getDay(-7));
            gantt.config.end_date = new Date(this.getDay(30));
            gantt.config.scales = [{
              unit: 'day',
              step: 1,
              format: this.dayTemplate
            }];
            gantt.templates.scale_cell_class = function (date) {
              if (date.getDay() == 0 || date.getDay() == 6) {
                return "weekend";
              }
            };
            gantt.templates.scale_row_class = function (date) {
              return "day-label";
            };
            gantt.config.scale_unit = 'day';
            gantt.config.date_scale = '%D/%m.%d';
            gantt.config.scale_height = 40;
            gantt.config.duration_unit = "day";
            gantt.config.duration_step = 1;
            gantt.render();
            break;
          case 'WEEK':
            gantt.config.start_date = new Date(this.getDay(-28));
            gantt.config.end_date = new Date(this.getDay(84));
            gantt.config.subscales = [{
              unit: 'week',
              step: 1,
              template: this.weekScaleTemplate,
            }];
            gantt.templates.scale_cell_class = "";
            gantt.templates.scale_row_class = function (date) {
              return "";
            };
            gantt.config.scale_unit = 'week';
            gantt.config.date_scale = '%F';
            gantt.config.scale_height = 50;
            gantt.config.duration_unit = "week";
            gantt.config.duration_step = 1;
            gantt.render();
            break;
          default:
            return {};
        }
      },
      getDay(day) {
        var today = new Date();
        var targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day;
        today.setTime(targetday_milliseconds); //注意,这行是关键代码

        var tYear = today.getFullYear();
        var tMonth = today.getMonth();
        var tDate = today.getDate();
        tMonth = this.doHandleMonth(tMonth + 1);
        tDate = this.doHandleMonth(tDate);
        return tYear + "-" + tMonth + "-" + tDate;
      },
      doHandleMonth(month) {
        var m = month;
        if (month.toString().length == 1) {
          m = "0" + month;
        }
        return m;
      },
      handleEditClick() {
        this.tasks.map(v => {
          if (v.id == this.selectedTaskId) {
            this.$router.push({
              path: "/proWorkOrder/editProWorkOrder",
              query: {
                operate: "edit",
                productionWorkorderId: v.productionWorkorderId,
                status: v.status,
                editType: "schedule"
              },
            });
          }
        });
      },

    },
    mounted() {
      this.getWorkShopList();
      this.getTasksList();
    },
    created() {}
  }

</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  .ganttContainer {
    width: 100%;
    min-height: calc(100vh - 200px);
  }

  .ope-wrap {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 60px;

    .ope-left {
      display: flex;
      align-items: center;

      ::v-deep .el-form-item {
        margin-bottom: 0px !important;
      }

      .e-btn {
        margin-left: 15px;
      }
    }

    .ope-right {}
  }

</style>
<style scoped>
  @import "~dhtmlx-gantt/codebase/dhtmlxgantt.css";

  /* 周末背景颜色 */
  ::v-deep .weekend {
    background: #dedede !important;
  }

  /* 工作日背景颜色 */
  ::v-deep .weekday {
    background: #c9e8f9 !important;
  }

  /* 日期的对齐方式 */
  ::v-deep .day-label .gantt_scale_cell {
    text-align: left !important;
  }

  /* 时间 小时 样式 */
  ::v-deep .hour-label:nth-child(2) .gantt_scale_cell {
    text-align: left !important;
  }

</style>

三、效果展示

四、补充

甘特图事件

一开始事件我是这么写的,但是后面开发过程中发现事件会重复触发。于是查了些资料得知切换页面时vue是会销毁页面的,但是甘特图不会被销毁,重复添加事件会重复执行。所以要在vue页面销毁时删除甘特图事件,用 gantt.detachEvent 进行删除

1)在data中定义一个数组用来存放甘特图事件

2)甘特图事件处理函数写法如下,把事件处理函数push到events数组中

3)页面销毁时删除甘特图事件

 这世界很喧嚣,做你自己就好

转载请注明出处或者链接地址:https://www.qianduange.cn//article/9361.html
标签
甘特图
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!