Vue2中后台使用dhtmlx-gantt插件实现复杂甘特图

本文详细介绍了如何使用dhtmlx-gantt库来创建和配置复杂的甘特图,包括设置开始和结束时间、灯箱中的日历、表格列、隐藏按钮、周末和节假日的样式突出等。同时,提到了一些关键配置如`gantt.config`和`gantt.form_blocks`,并展示了如何处理多条数据和自定义任务样式。此外,文章还包含了示例代码,展示如何在Vue组件中集成和初始化甘特图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在工作中由于业务的复杂性,需要使用dhtmlx-gantt来实现复杂表格,以下是甘特图的实现以及一些配置描述。(由于官方文档是英文的,所以对英文不好的不太友好),官方文档:Gantt API Gantt Docs
相关配置:
1、一行需要展示多条数据的操作步骤:需要给父数据的那条添加render:split属性,子数据的parent为父数据的Id即可。
2、配置甘特图的开始和结束时间:

gantt.config.start_date,gantt.config.end_date

3、灯箱中日历设置:

gantt.form_blocks['dhx_calendar'] 

4、表格列设置

gantt.config.columns

5、隐藏某些行的“添加”按钮

gantt.templates.grid_row_class = function (start, end, task) {
    if (task.$level > 1) {
      return 'nested_task'
    }
.nested_task .gantt_add {
  display: none !important;
}
6周末样式突出
gantt.config.work_time = true
    gantt.templates.timeline_cell_class = function (task, date) {
      if (!gantt.isWorkTime(date)) return 'week_end'
    return ''
}
7、节假日样式突出
const holidays = ['2023-03-29']
   const format_date = gantt.date.str_to_date('%Y-%m-%d')
   for (let i = 0; i < holidays.length; i++) {
   const converted_date = format_date(holidays[i])
   gantt.setWorkTime({ date: converted_date, hours: false })
}
注意:dhtmlx.css和dhtmlx.js都要引入index.html

页面代码
<template>
  <div>
    <div ref="ganttYear" id="ganttYearDom" class="gantt-container" style="width: 100%; height: 450px"></div>
  </div>
</template>

<script>
import gantt from 'dhtmlx-gantt'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import moment from 'moment'
export default {
  name: 'resourcePlan',
  data() {
    return {
      //甘特图
      params: {
        deptIds: [],
        startDate: '',
        endDate: '',
        searchValue: '',
        conditions: [],
      },
      htmlUrl: '',
      // 甘特图数据格式
      dataSource: [],
      ganttHeight: innerHeight - 215 + 'px',
      ganttLoading: false,
      // 下拉框选项
      priorityOptions: [
        { key: '1', label: '编制报告', backgroundColor: '#BD3124', textColor: '#FFF' },
        { key: '2', label: '准备进场新项目', backgroundColor: '#BD3124', textColor: '#FFF' },
        { key: '3', label: '请假休整', backgroundColor: '#81B336', textColor: '#FFF' },
        { key: '4', label: '其他', backgroundColor: '#BD3124', textColor: '#FFF' },
      ],
      tasks: {
        data: [], //甘特图数据
        links: [],
      },
      events: [],
    }
  },
  created() {
    gantt.clearAll()
  },
  mounted() {
    this.init()
  },
  methods: {
    moment,
    // 获取资源统计数据
    getResourceInfo() {
      gantt.config.start_date = this.nowDate.format('YYYY-MM-DD')
      gantt.config.end_date = this.newDate.format('YYYY-MM-DD')
    },
    // 初始化
    init() {
      console.log('初始化')
      //中文
      gantt.i18n.setLocale('cn')
      //自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
      gantt.config.autosize = false
      // 只读模式:打开后不可以操作甘特图
      gantt.config.readonly = false
      gantt.config.date_format = '%Y-%m-%d'
      gantt.config.keep_grid_width = false
      gantt.config.grid_resize = true
      gantt.config.initial_scroll = false

      //是否显示左侧树表格
      gantt.config.show_grid = true
      function byId(list, id) {
        for (var i = 0; i < list.length; i++) {
          if (list[i].key == id) return id || ''
        }
        return ''
      }
      window.byId = byId
      let that = this

      var duration = function (a, b, c) {
        var res = gantt.calculateDuration(a.getDate(false), b.getDate(false))
        c.innerHTML = res + '天'
      }

      var calendar_init = function (id, data, date) {
        var obj = new dhtmlXCalendarObject(id)
        obj.setDateFormat(data.date_format ? data.date_format : '')
        obj.setDate(date ? date : new Date())
        obj.hideTime()
        if (data.skin) obj.setSkin(data.skin)
        return obj
      }
      
      gantt.form_blocks['dhx_calendar'] = {
        render: function (sns) {
          return (
            "<div class='dhx_calendar_cont'><input type='text' readonly='true' id='calendar1'/> &#8211; " +
            "<input type='text' readonly='true' id='calendar2'/><label id='duration'></label></div>"
          )
        },
        set_value: function (node, value, task, data) {
          var a = (node._cal_start = calendar_init('calendar1', data, task.start_date))
          var b = (node._cal_end = calendar_init('calendar2', data, task.end_date))
          var c = node.lastChild

          b.setInsensitiveRange(null, new Date(a.getDate(false) - 86400000))

          var a_click = a.attachEvent('onClick', function (date) {
            b.setInsensitiveRange(null, new Date(date.getTime() - 86400000))
            duration(a, b, c)
          })

          var b_click = b.attachEvent('onClick', function (date) {
            duration(a, b, c)
          })

          var a_time_click = a.attachEvent('onChange', function (d) {
            b.setInsensitiveRange(null, new Date(d.getTime() - 86400000))
            duration(a, b, c)
          })

          var b_time_click = b.attachEvent('onChange', function (d) {
            that.changeEnd = false
            task.end_date = that.setTime(d, true)
            duration(a, b, c)
          })

          var id = gantt.attachEvent('onAfterLightbox', function () {
            a.detachEvent(a_click)
            a.detachEvent(a_time_click)
            a.unload()
            b.detachEvent(b_click)
            b.detachEvent(b_time_click)
            b.unload()
            a = b = null
            this.detachEvent(id)
          })

          document.getElementById('calendar1').value = a.getDate(true)
          document.getElementById('calendar2').value = that.setTime(b.getDate(true), false)
          duration(a, b, c)
        },
        get_value: function (node, task) {
          task.start_date = node._cal_start.getDate(false)
          task.end_date = node._cal_end.getDate(false)
          return task
        },
        focus: function (node) {},
      }
      //表格列设置
      gantt.config.columns = [
        {
          //最左侧新增符号列,甘特图内置可选使用列
          name: 'add',
          label: '',
          width: '40',
        },
        {
          name: 'userName',
          label: '姓名',
          tree: true,
          width: '150',
        },
        {
          name: 'deptName',
          label: '部室',
          width: '100',
        },
        {
          name: 'site',
          label: '现场实施人员',
          hide: true,
        },
        {
          name: 'progorderName',
          label: '程序',
          width: '100',
          hide: true,
        },
        {
          name: 'start_date',
          label: '开始时间',
          hide: true,
        },
        {
          name: 'end_date',
          label: '结束时间',
          hide: true,
        },
        {
          name: 'flag',
          label: '是否调配',
          hide: true,
        },
        {
          name: 'reason',
          label: '不可调配原因',
          template: function (item) {
            return byId(gantt.serverList('staff'), item.reason)
          },
          hide: true,
        },
        {
          name: 'state',
          label: '其他说明',
          hide: true,
        },
      ]
      //自适应
      //gantt.config.fit_tasks = true;

      //连线
      gantt.config.show_links = false

      //表头高度
      gantt.config.scale_height = 80

      //开启提示:鼠标悬浮在gantt行上显示
      gantt.plugins({
        tooltip: true,
      })

      // gantt.config.start_date = new Date(2018,1,1);
      //   gantt.config.end_date = new Date(2020,1,1);

      //周末样式突出
      gantt.config.work_time = true
      gantt.templates.timeline_cell_class = function (task, date) {
        if (!gantt.isWorkTime(date)) return 'week_end'
        return ''
      }

      gantt.templates.task_class = function (start, end, task) {
        var css = []
        if (task.flagStr == 0) {
          css.push('blue_task')
        } else if (task.flagStr == 1) {
          css.push('light_blue_task')
        }

        if (task.reason) {
          css = css.filter((item) => item !== 'blue_task' && item !== 'light_blue_task')
          css.push('gantt_resource_task gantt_resource_' + task.reason)
        }
        return css.join(' ')
      }

      //时间轴格式化模版
      var yearScaleTemplate = function (date) {
        return date.getFullYear()
      }
      var monthScaleTemplate = function (date) {
        var year = date.getFullYear()
        var month = date.getMonth()
        month = month + 1 + '月'
        let yearTemplate = `${year}年${month}`
        return yearTemplate
      }
      //时间轴样式
      var yearScaleCss = function () {
        return 'yearScaleStyle'
      }
      var monthScaleCss = function () {
        return 'monthScaleStyle'
      }

      //定义表头日期
      gantt.config.scales = [
        { unit: 'month', step: 1, format: monthScaleTemplate, css: monthScaleCss },
        { unit: 'day', step: 1, format: '%D <br/> %d' },
        //format: function(date){
        // 	return "<strong>Day " + dayNumber(date) + "</strong><br/>" + dateFormat(date);
        // }
      ]

      //鼠标移动显示信息
      gantt.templates.tooltip_text = function (start, end, task) {
        let endTime = that.setTime(gantt.templates.tooltip_date_format(end), false)
        if (task.render == 'split') {
          return ''
        } else if (task.proGid && task.proGid !== null && task.proGid.indexOf(',') >= 0) {
          let viewTask = ''
          task.taskArr.forEach((item) => {
            viewTask += ``
          })
          return viewTask
        } else if (task.reason == null || task.reason == undefined) {
          return ``
        } else if (task.reason !== null) {
          let obj = that.priorityOptions.find((item) => item.key == task.reason)
          if (obj !== undefined) {
            return '不可调配原因:'
          }
        }
      }

      // 弹框命名文字
      gantt.locale.labels.section_priority = '不可调配原因'
      gantt.locale.labels.section_progorder = '项目名称'
      gantt.locale.labels.section_userName = '姓名'
      gantt.locale.labels.section_deptName = '部室'
      gantt.locale.labels.section_other = '其他说明'
      gantt.locale.labels.message_ok = '确定'
      gantt.locale.labels.confirm_deleting = '是否删除?'

      //配置Gantt内置弹出框元素(title内容)
      gantt.templates.lightbox_header = function (start_date, end_date, task) {
        // return `<b>${task.userName}属性信息</b>`
        return `<b>设置不可调配原因</b>`
      }
      gantt.serverList('staff', that.priorityOptions)
      // 添加弹窗属性
      gantt.config.lightbox.sections = [
        { name: 'priority', height: 30, map_to: 'reason', type: 'select', options: gantt.serverList('staff') },
        { name: 'other', height: 50, map_to: 'state', type: 'textarea', focus: true },
        { name: 'time', type: 'dhx_calendar', map_to: 'auto', skin: '', date_format: '%Y-%m-%d' },
      ]
      // //双击事件
      gantt.config.details_on_dblclick = true
      //关闭所有错误提示信息:gantt有自己的异常消息,如果不关闭可能页面会弹出异常消息
      gantt.config.show_errors = false

      //禁止拖动设置任务长度
      gantt.attachEvent('onBeforeTaskDrag', function (id, mode, e) {
        return false
      })
      //禁止拖动任务
      gantt.config.drag_move = false
      //禁止拖动任务进度
      gantt.config.drag_progress = false
      //禁止拖放添加Link
      gantt.config.drag_links = false

      //任务条显示信息
      gantt.templates.task_text = function (syart, end, task) {
        console.log(task, 'taskkkk')
        // var calendar = gantt.getTaskCalendar(task);
        if (task.reason == 3 || task.reason == 1 || task.reason == 2 || task.reason == 4) {
          let obj = that.priorityOptions.find((item) => item.key == task.reason)
          if (obj !== undefined) {
            return obj.label
          }
        } else {
          if (task.progorderName !== undefined) {
            return task.progorderName
          }
          return ''
        }
      }

      gantt.attachEvent('onParse', function () {
        var styleId = 'dynamicGanttStyles'
        var element = document.getElementById(styleId)
        if (!element) {
          element = document.createElement('style')
          element.id = styleId
          document.querySelector('head').appendChild(element)
        }
        var html = []
        var resources = gantt.serverList('staff')

        resources.forEach(function (r) {
          html.push(
            '.gantt_task_line.gantt_resource_' +
              r.key +
              '{' +
              'background-color:' +
              r.backgroundColor +
              '; ' +
              'color:' +
              r.textColor +
              ';' +
              '}'
          )
          html.push(
            '.gantt_row.gantt_resource_' +
              r.key +
              ' .gantt_cell:nth-child(1) .gantt_tree_content{' +
              'background-color:' +
              r.backgroundColor +
              '; ' +
              'color:' +
              r.textColor +
              ';' +
              '}'
          )
        })
        element.innerHTML = html.join('')
      })

      gantt.attachEvent('onTaskDblClick', function (id, e) {
        if (e.target.className.indexOf('task') == -1) {
          return false
        }
        gantt.showLightbox(id)
        return true
      })

      gantt.config.min_column_width = 40

      //监听按钮保存删除事件  updateResourceReason
      let onBeforeTaskAdd = gantt.attachEvent('onBeforeTaskAdd', function (id, item) {
        let endCopy = JSON.parse(JSON.stringify(item.end_date))
        let endTime = that.setTime(endCopy, false)
        var params = {
          userId: item.parent,
          startDate: moment(item.start_date).format('YYYY-MM-DD'),
          endDate: moment(item.end_date).format('YYYY-MM-DD'),
          // endDate: endTime,
          reason: item.reason,
          state: item.state,
        }
        updateResourceReason(params).then((res) => {
          if (res.code == 0) {
            that.$message.success('新增成功')
            that.getData()
            return true
          } else {
            that.$message.warning(res.msg)
            that.getData()
            return false
          }
        })
      })

      this.events.push(onBeforeTaskAdd)

      let onBeforeTaskUpdate = gantt.attachEvent('onBeforeTaskUpdate', function (id, item) {
        console.log('编辑', id, item)
        // let endCopy = JSON.parse(JSON.stringify(item.end_date))
        // let endTime = that.setTime(endCopy, false)
        let endTime, endCopy
        if (that.changeEnd) {
          endCopy = JSON.parse(JSON.stringify(item.end_date))
          endTime = that.setTime(endCopy, false)
        } else {
          endTime = moment(item.end_date).format('YYYY-MM-DD')
        }
        var params = {
          id: item.reasonId,
          userId: item.userId,
          startDate: moment(item.start_date).format('YYYY-MM-DD'),
          // endDate: moment(item.end_date).format('YYYY-MM-DD'),
          endDate: endTime,
          reason: item.reason,
          state: item.state,
        }
        console.log(7777, item.end_date)
        updateResourceReason(params).then((res) => {
          console.log(1112444, res)
          if (res.code == 0) {
            that.$message.success('更新成功')
            that.getData()
            return true
          } else {
            that.$message.warning(res.msg)
            that.getData()
            return false
          }
        })
      })
      this.events.push(onBeforeTaskUpdate)
      // delResourceReason

      //监听按钮保存删除事件
      let onBeforeTaskDelete = gantt.attachEvent('onBeforeTaskDelete', function (id, item) {
        const params = {
          id: item.reasonId,
          userId: item.userId,
        }
        delResourceReason(params).then((res) => {
          console.log(777, res)
          if (res.code == 0) {
            that.$message.success('删除成功')
            var task = gantt.getTask(id)
            that.getData()
            return true
          } else {
            that.$message.warning(res.msg)
            that.getData()
            return false
          }
        })
      })
      this.events.push(onBeforeTaskDelete)

      gantt.attachEvent('onBeforeLightbox', function (id) {
        that.changeEnd = true
        var task = gantt.getTask(id)
        if (task.flagStr == 0) {
          return false
        }
        return true
      }),
        // 初始化
        setTimeout(() => {
          gantt.clearAll()
          gantt.init(that.$refs.ganttYear)
          gantt.parse(that.tasks)
          document.querySelector('.gantt-container').style.height = '500px'
        }, 1000)
    },
    reload() {
      gantt.clearAll() // 从甘特图中删除所有任务和其他元素(包括标记)
      // gantt.init(this.$refs.ganttYear)
      gantt.parse(this.tasks) // 数据解析
      gantt.render() // 呈现整个甘特图
    },
    getData() {
      var arrTaskNew = []
      this.params.startDate = moment(this.nowDate).format('YYYY-MM-DD')
      this.params.endDate = moment(this.newDate).format('YYYY-MM-DD')
      getCalendarInfo(this.params).then((res) => {
        if (res.code == 0) {
          this.dataSource = res.data
          this.dataSource.forEach((item, index) => {
            item.render = 'split'
            item.id = item.userId
            item.start_date = ''
            item.end_date = ''
            item.type = gantt.config.types.task
            arrTaskNew.push(item)
            if (item.planDtoList !== null) {
              item.planDtoList.forEach((item1, index1) => {
                item1.parent = item.id
                item1.start_date = item1.startDate
                item1.end_date = this.setTime(item1.endDate, true)
                let str = ''
                if (item1.proGid !== null && item1.proGid.indexOf(',') == -1) {
                  item1.personMap[item1.proGid].forEach((item2, index2) => {
                    str += item2.names + '<br/>'
                  })
                  item1.site = str
                  // 如果多个时间相同的任务重叠
                } else if (item1.proGid !== null && item1.proGid.indexOf(',') >= 0) {
                  item1.taskArr = []
                  let proGidArr = item1.proGid.split(',')
                  let progorderNameArr = item1.progorderName.split(',')
                  proGidArr.forEach((item3, index3) => {
                    let objtask = {
                      proGid: '',
                      progorderName: '',
                      names: '',
                    }
                    objtask.proGid = item3
                    objtask.progorderName = progorderNameArr[index3]
                    item1.personMap[item3].forEach((item4, index4) => {
                      objtask.names += item4.names + '<br/>'
                    })
                    item1.taskArr.push(objtask)
                  })
                }
                arrTaskNew.push(item1)
              })
            }
          })

          this.tasks.data = arrTaskNew
          // this.init()
          this.reload()
        } else {
          this.$message.warning(res.msg)
        }
      })
    },
    setTime(date, bool) {
      if (date == null || !date) return null
      var dateTime
      if (typeof date == 'string') {
        dateTime = new Date(date)
      } else {
        dateTime = date
      }
      if (bool) {
        dateTime = dateTime.setDate(dateTime.getDate() + 1)
        dateTime = new Date(dateTime)
      } else {
        dateTime = dateTime.setDate(dateTime.getDate() - 1)
        dateTime = new Date(dateTime)
      }
      if (typeof date == 'string') {
        return this.changeDate(dateTime)
      } else {
        return dateTime
      }
    },
    changeDate(chinaTime) {
      if (typeof date == 'string') return chinaTime
      let m = chinaTime.getMonth() + 1
      let d = chinaTime.getDate()
      if (m >= 0 && m <= 9) {
        m = '0' + m
      }
      if (d >= 0 && d <= 9) {
        d = '0' + d
      }
      return chinaTime.getFullYear() + '-' + m + '-' + d
    },
    queryApi() {},
  },
  computed: {
    ...mapState({
      multiTab: (state) => state.app.multiTab,
    }),
    defaultTime() {
      return [this.nowDate, this.newDate]
    },
  },
  beforeDestroy() {
    this.events.forEach((ele) => {
      gantt.detachEvent(ele)
    })
  },
}
</script>

<style scoped lang="less">
.gantt-container {
  height: 500px;
  min-height: 400px;
  max-height: 800px !important;
  overflow-y: auto !important;
}
.radioRow {
  margin: 10px;
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
rsor: pointer;
}
.dhx_calendar_cont input {
  width: 96px;
  padding: 0;
  margin: 3px 10px 10px 10px;
  font-size: 11px;
  height: 17px;
  text-align: center;
  border: 1px solid #ccc;
  color: #646464;
}

.dhtmlxcalendar_dhx_skyblue,
.dhtmlxcalendar_dhx_web,
.dhtmlxcalendar_dhx_terrace {
  z-index: 999999 !important;
}
</style>
Vue使用甘特图插件dhtmlx-gantt的步骤如下: 1. 首先,你需要使用yarn或npm安装dhtmlx-gantt插件。可以通过以下命令之一来安装插件: ```bash yarn install dhtmlx-gantt ``` 2. 在你的Vue组件中,引入dhtmlx-gantt插件。你可以使用以下代码实现引入: ```javascript import { gantt } from 'dhtmlx-gantt'; ``` 3. 在样式中引入dhtmlx-gantt的CSS文件。你可以在style标签中添加以下代码: ```html <style> @import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'; </style> ``` 4. 对于部分组件的使用,你可以使用以下代码定义任务、列和链接: ```javascript const ganttColumns = ref([ { align: 'right', name: 'color', label: '', width: '15', template: function(task) { if (task.color) { return "<div class='tttttt' style='background:" + task.color + "'></div>"; } } }, { align: 'left', name: 'text', label: '', tree: true, width: "*", min_width: 120 }, { align: 'center', name: 'person', label: '负责人', width: '100' }, { align: 'right', name: 'time', label: '时间节点', width: '80' }, ]); gantt.config.columns = ganttColumns.value; const ganttLinks = [ { id: 1, source: 1, target: 3, type: "0" }, { id: 2, source: 12323545, target: 12345453, type: "1" }, { id: 3, source: 12345453, target: 12345437, type: "0" } ]; let ganttData = { data: [...], links: ganttLinks }; ``` 5. 最后,你可以使用dhtmlx-gantt插件的各种配置项和API来创建甘特图。可以根据需要使用不同的配置项来定义任务列、时间轴等。详情可以参考dhtmlx-gantt的官方文档。 通过以上步骤,你就可以在Vue使用甘特图插件dhtmlx-gantt了。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值