vue+dhtmlx-gantt 實(shí)現(xiàn)甘特圖(快速入門(mén)甘特圖)
一、前言
dhtmlxGantt 是一款功能強(qiáng)大的甘特圖組件,支持 Vue 3 集成。它提供了豐富的功能,適合復(fù)雜的項(xiàng)目管理需求。
1 什么是甘特圖
甘特圖(Gantt chart)又稱(chēng)為橫道圖、條狀圖(Bar chart)。以提出者亨利·L·甘特先生的名字命名,是項(xiàng)目管理、生產(chǎn)排程、節(jié)點(diǎn)管理中非常常見(jiàn)的一個(gè)功能。
甘特圖內(nèi)在思想簡(jiǎn)單,即以圖示的方式通過(guò)活動(dòng)列表和時(shí)間刻度形象地表示出任何特定項(xiàng)目的活動(dòng)順序與持續(xù)時(shí)間?;臼且粭l線(xiàn)條圖,橫軸表示時(shí)間,縱軸表示活動(dòng)(項(xiàng)目),線(xiàn)條表示在整個(gè)期間上計(jì)劃和實(shí)際的活動(dòng)完成情況。它直觀地表明任務(wù)計(jì)劃在什么時(shí)候進(jìn)行,及實(shí)際進(jìn)展與計(jì)劃要求的對(duì)比。管理者由此可便利地弄清一項(xiàng)任務(wù)(項(xiàng)目)還剩下哪些工作要做,并可評(píng)估工作進(jìn)度。
2 為什么要用甘特圖
在很多較大且時(shí)間跨度較長(zhǎng)的工程、IT、市場(chǎng)營(yíng)銷(xiāo)、電商運(yùn)營(yíng)等項(xiàng)目中,都會(huì)涉及諸多對(duì)人員、時(shí)間、質(zhì)量等方面的控制,而且很多時(shí)候還需要跨部門(mén)進(jìn)行協(xié)作,所以,如何把控整個(gè)項(xiàng)目管理流程就顯得非常重要。
而使用甘特圖就可以實(shí)現(xiàn)這樣一個(gè)目的。

特點(diǎn)
- 支持拖放操作
- 多種視圖模式(天、周、月、年)
- 數(shù)據(jù)導(dǎo)出功能(PDF、PNG、Excel)
- 任務(wù)依賴(lài)關(guān)系管理
使用場(chǎng)景
適合需要高度定制化和復(fù)雜功能的企業(yè)級(jí)項(xiàng)目管理工具。
資源
- GitHub: dhtmlxGantt
- 文檔: dhtmlxGantt 文檔
二、使用說(shuō)明
2.1 引入依賴(lài)
npm install dhtmlx-gantt
2.2 引入組件
<template>
<div>
<div ref="gantt" style="height:500px;" />
</div>
</template>
2.3 引入dhtmlx-gantt
import gantt from 'dhtmlx-gantt' import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
2.4 甘特圖數(shù)據(jù)配置
- 父級(jí)時(shí)間是根據(jù)子級(jí)
start_date以及duration自動(dòng)計(jì)算 progress:完成度的最大值為1open:是否展開(kāi)文件parent:父級(jí)idstart_date:開(kāi)始時(shí)間(日月年)text:左邊數(shù)據(jù)展示文件名稱(chēng)(可以自定義添加展示字段,在后面列配置項(xiàng)可以配置)
??注意: 數(shù)據(jù)格式類(lèi)似于樹(shù)形組件,子級(jí)需要父級(jí)的
id
tasks: {
data: [
// {
// id: 11,
// text: 'Project #1',
// // type: gantt.config.types.project,
// progress: 0.5,//完成度
// open: true,//默認(rèn)打開(kāi)
// number: '20240227',//顯示字段
// },
// {
// toolTipsTxt: '任務(wù)#101-001',
// id: 12,//任務(wù)id
// text: '任務(wù)#1',//任務(wù)名稱(chēng)
// start_date: '03-04-2022',//開(kāi)始時(shí)間 日月年
// duration: '5',//任務(wù)時(shí)常
// parent: '11',//父級(jí)id
// progress: 1,//完成度
// open: true,//默認(rèn)打開(kāi)
// },
// {
// id: 13,
// text: '任務(wù)#2',
// start_date: '03-04-2022',
// // type: gantt.config.types.project,
// parent: '11',
// progress: 0.255,
// open: true,
// },
// {
// id: 14,
// text: '任務(wù)#3',
// start_date: '01-04-2022',
// duration: '6',
// parent: '11',
// progress: 0.8,
// open: true,
// },
// {
// id: 15,
// text: '任務(wù)#4',
// // type: gantt.config.types.project,
// parent: '11',
// progress: 0.2,
// open: true,
// },
// {
// id: 16,
// text: 'Final milestone',
// start_date: '15-04-2022',
// // type: gantt.config.types.milestone,
// parent: '11',
// progress: 0,
// open: true,
// },
// {
// id: 17,
// text: '任務(wù)#2.1',
// start_date: '03-04-2022',
// duration: '2',
// parent: '13',
// progress: 1,
// open: true,
// },
// {
// id: 18,
// text: '任務(wù)#2.2',
// start_date: '06-04-2022',
// duration: '3',
// parent: '13',
// progress: 0.8,
// open: true,
// },
// {
// id: 19,
// text: '任務(wù)#2.3',
// start_date: '10-04-2022',
// duration: '4',
// parent: '13',
// progress: 0.2,
// open: true,
// },
// {
// id: 20,
// text: '任務(wù)#2.4',
// start_date: '10-04-2022',
// duration: '4',
// parent: '13',
// progress: 0,
// open: true,
// },
// {
// id: 21,
// text: '任務(wù)#4.1',
// start_date: '03-04-2022',
// duration: '4',
// parent: '15',
// progress: 0.5,
// open: true,
// },
// {
// id: 22,
// text: '任務(wù)#4.2',
// start_date: '03-04-2022',
// duration: '4',
// parent: '15',
// progress: 0.1,
// open: true,
// },
// {
// id: 23,
// text: 'Mediate milestone',
// start_date: '14-04-2022',
// // type: gantt.config.types.milestone,
// parent: '15',
// progress: 0,
// open: true,
// },
],tasks 中 link 連線(xiàn)配置
tasks: {
// #字段解釋
// 格式 id:數(shù)據(jù)id
// source:開(kāi)始鏈接的項(xiàng)目id ----為tasks.data中數(shù)據(jù)的id
// target:要鏈接項(xiàng)目的id ----為tasks.data中數(shù)據(jù)的id
// type: 0--進(jìn)行-開(kāi)始 `尾部鏈接頭部`
// 1--開(kāi)始-開(kāi)始 `頭部鏈接頭部`
// 2--進(jìn)行-進(jìn)行 `尾部鏈接尾部`
// 3--開(kāi)始-進(jìn)行 `頭部鏈接尾部`
// 任務(wù)之間連接
links: [
{ id: '10', source: '11', target: '12', type: '1' },
{ id: '11', source: '11', target: '13', type: '1' },
{ id: '12', source: '11', target: '14', type: '1' },
{ id: '13', source: '11', target: '15', type: '1' },
{ id: '14', source: '23', target: '16', type: '0' },
{ id: '15', source: '13', target: '17', type: '1' },
{ id: '16', source: '17', target: '18', type: '0' },
{ id: '17', source: '18', target: '19', type: '0' },
{ id: '18', source: '19', target: '20', type: '0' },
{ id: '19', source: '15', target: '21', type: '2' },
{ id: '20', source: '15', target: '22', type: '2' },
{ id: '21', source: '15', target: '23', type: '0' },
],
},
2.5 初始化配置
彈窗漢化
gantt.locale.labels = {
dhx_cal_today_button: "今天",
day_tab: "日",
week_tab: "周",
month_tab: "月",
new_event: "新建日程",
icon_save: "保存",
icon_cancel: "關(guān)閉",
icon_details: "詳細(xì)",
icon_edit: "編輯",
icon_delete: "刪除",
confirm_closing: "請(qǐng)確認(rèn)是否撤銷(xiāo)修改!", //Your changes will be lost, are your sure?
confirm_deleting: "是否刪除計(jì)劃?",
section_description: "描述:",
section_time: "時(shí)間范圍:",
section_type: "類(lèi)型:",
section_text: "計(jì)劃名稱(chēng):",
section_test: "測(cè)試:",
section_projectClass: "項(xiàng)目類(lèi)型:",
taskProjectType_0: "項(xiàng)目任務(wù)",
taskProjectType_1: "普通任務(wù)",
section_head: "負(fù)責(zé)人:",
section_priority: '優(yōu)先級(jí):',
taskProgress: '任務(wù)狀態(tài)',
taskProgress_0: "未開(kāi)始",
taskProgress_1: "進(jìn)行中",
taskProgress_2: "已完成",
taskProgress_3: "已延期",
taskProgress_4: "擱置中",
section_template: 'Details',
/* grid columns */
column_text: "計(jì)劃名稱(chēng)",
column_start_date: "開(kāi)始時(shí)間",
column_duration: "持續(xù)時(shí)間",
column_add: "",
column_priority: "難度",
/* link confirmation */
link: "關(guān)聯(lián)",
confirm_link_deleting: "將被刪除",
message_ok: '確定',
message_cancel: '取消',
link_start: " (開(kāi)始)",
link_end: " (結(jié)束)",
type_task: "任務(wù)",
type_project: "項(xiàng)目",
type_milestone: "里程碑",
minutes: "分鐘",
hours: "小時(shí)",
days: "天",
weeks: "周",
months: "月",
years: "年"
}

清空舊數(shù)據(jù)
gantt.clearAll(); // 清空舊數(shù)據(jù)
??注意:其中值得一提的就是更新數(shù)據(jù),需要清空舊數(shù)
初始化數(shù)據(jù)
// 初始化
init() {
// 格式化日期
gantt.locale.date = {
month_full: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
month_short: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
day_full: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
day_short: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
}
console.log(gantt);
//自適應(yīng)甘特圖的尺寸大小, 使得在不出現(xiàn)滾動(dòng)條的情況下, 顯示全部任務(wù)
gantt.config.autosize = true
//只讀模式
gantt.config.readonly = false
//是否顯示左側(cè)樹(shù)表格
gantt.config.show_grid = true
// //表格列設(shè)置
gantt.config.columns = [
{ name: 'text', label: '階段名字', tree: true, width: '150', align: 'center', },
// { name: 'number', label: '工單號(hào)', tree: false, width: '120', align: 'center', },
{
name: 'duration',
label: '工時(shí)',
align: 'center',
template: function (obj) {
return obj.duration + '天'
},
},
/*{name:"start_date", label:"開(kāi)始時(shí)間", align: "center" },
{name:"end_date", label:"結(jié)束時(shí)間", align: "center" },*/
]
// 自動(dòng)延長(zhǎng)時(shí)間刻度
gantt.config.fit_tasks = true
// 允許拖放
gantt.config.drag_project = true
// 定義時(shí)間格式
gantt.config.scales = [
{ unit: 'month', step: 1, date: ' %Y,%F' },
{ unit: 'day', step: 1, date: ' %D ,%j' },
]
// //當(dāng)task的長(zhǎng)度改變時(shí),自動(dòng)調(diào)整圖表坐標(biāo)軸區(qū)間用于適配task的長(zhǎng)度
gantt.config.fit_tasks = true
// 添加彈窗屬性
gantt.config.lightbox.sections = [
{
name: 'description',
height: 70,
map_to: 'text',
type: 'textarea',
focus: true,
},
{ name: 'type', type: 'typeselect', map_to: 'type' },
{ name: 'time', type: 'duration', map_to: 'auto' },
];
console.log(this.tasks.data, '檢查任務(wù)數(shù)據(jù)'); // 檢查任務(wù)數(shù)據(jù)
// 初始化
gantt.init(this.$refs.gantt)
/* *******重點(diǎn)******* */
gantt.clearAll(); // 清空舊數(shù)據(jù)
/* ****************** */
// 數(shù)據(jù)解析
gantt.parse(this.tasks)
},
更新數(shù)據(jù)
loadData(arg) {
if (!this.url.list) {
this.$message.error("請(qǐng)?jiān)O(shè)置url.list屬性!")
return
}
//加載數(shù)據(jù) 若傳入?yún)?shù)1則加載第一頁(yè)的內(nèi)容
let params = {
planId: this.planId,
}
this.loading = true;
this.tasks.data = []
getAction(this.url.list, params).then((res) => {
if (res.success) {
console.log(res, '甘特圖數(shù)據(jù)');
res.result.forEach(obj => {
obj.open = false
})
this.tasks.data = res.result
this.init()
}
if (res.code === 510) {
this.$message.warning(res.message)
}
this.loading = false;
})
},
三、代碼示例
3.1 Vue2完整示例
<template>
<div>
<div ref="gantt" style="height:500px;" />
</div>
</template>
<script>
import gantt from 'dhtmlx-gantt'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import { getAction, putAction } from '@/api/manage'
export default {
props: {
planId: {
type: String,
required: true,
}
},
// mixins: [JeecgListMixin],
data() {
return {
// 甘特圖配置
tasks: {
data: [
// {
// id: 11,
// text: 'Project #1',
// // type: gantt.config.types.project,
// progress: 0.5,//完成度
// open: true,//默認(rèn)打開(kāi)
// number: '20240227',//顯示字段
// },
// {
// toolTipsTxt: '任務(wù)#101-001',
// id: 12,//任務(wù)id
// text: '任務(wù)#1',//任務(wù)名稱(chēng)
// start_date: '03-04-2022',//開(kāi)始時(shí)間 日月年
// duration: '5',//任務(wù)時(shí)常
// parent: '11',//父級(jí)id
// progress: 1,//完成度
// open: true,//默認(rèn)打開(kāi)
// },
// {
// id: 13,
// text: '任務(wù)#2',
// start_date: '03-04-2022',
// // type: gantt.config.types.project,
// parent: '11',
// progress: 0.255,
// open: true,
// },
// {
// id: 14,
// text: '任務(wù)#3',
// start_date: '01-04-2022',
// duration: '6',
// parent: '11',
// progress: 0.8,
// open: true,
// },
// {
// id: 15,
// text: '任務(wù)#4',
// // type: gantt.config.types.project,
// parent: '11',
// progress: 0.2,
// open: true,
// },
// {
// id: 16,
// text: 'Final milestone',
// start_date: '15-04-2022',
// // type: gantt.config.types.milestone,
// parent: '11',
// progress: 0,
// open: true,
// },
// {
// id: 17,
// text: '任務(wù)#2.1',
// start_date: '03-04-2022',
// duration: '2',
// parent: '13',
// progress: 1,
// open: true,
// },
// {
// id: 18,
// text: '任務(wù)#2.2',
// start_date: '06-04-2022',
// duration: '3',
// parent: '13',
// progress: 0.8,
// open: true,
// },
// {
// id: 19,
// text: '任務(wù)#2.3',
// start_date: '10-04-2022',
// duration: '4',
// parent: '13',
// progress: 0.2,
// open: true,
// },
// {
// id: 20,
// text: '任務(wù)#2.4',
// start_date: '10-04-2022',
// duration: '4',
// parent: '13',
// progress: 0,
// open: true,
// },
// {
// id: 21,
// text: '任務(wù)#4.1',
// start_date: '03-04-2022',
// duration: '4',
// parent: '15',
// progress: 0.5,
// open: true,
// },
// {
// id: 22,
// text: '任務(wù)#4.2',
// start_date: '03-04-2022',
// duration: '4',
// parent: '15',
// progress: 0.1,
// open: true,
// },
// {
// id: 23,
// text: 'Mediate milestone',
// start_date: '14-04-2022',
// // type: gantt.config.types.milestone,
// parent: '15',
// progress: 0,
// open: true,
// },
],
// #字段解釋
// 格式 id:數(shù)據(jù)id
// source:開(kāi)始鏈接的項(xiàng)目id ----為tasks.data中數(shù)據(jù)的id
// target:要鏈接項(xiàng)目的id ----為tasks.data中數(shù)據(jù)的id
// type: 0--進(jìn)行-開(kāi)始 `尾部鏈接頭部`
// 1--開(kāi)始-開(kāi)始 `頭部鏈接頭部`
// 2--進(jìn)行-進(jìn)行 `尾部鏈接尾部`
// 3--開(kāi)始-進(jìn)行 `頭部鏈接尾部`
// 任務(wù)之間連接
links: [
{ id: '10', source: '11', target: '12', type: '1' },
{ id: '11', source: '11', target: '13', type: '1' },
{ id: '12', source: '11', target: '14', type: '1' },
{ id: '13', source: '11', target: '15', type: '1' },
{ id: '14', source: '23', target: '16', type: '0' },
{ id: '15', source: '13', target: '17', type: '1' },
{ id: '16', source: '17', target: '18', type: '0' },
{ id: '17', source: '18', target: '19', type: '0' },
{ id: '18', source: '19', target: '20', type: '0' },
{ id: '19', source: '15', target: '21', type: '2' },
{ id: '20', source: '15', target: '22', type: '2' },
{ id: '21', source: '15', target: '23', type: '0' },
],
},
url: {
list: "/projectManage/projectPlan/queryProjectPlanGTT",
// delete: "/projectManage/projectModule/delete",
// deleteBatch: "/projectManage/projectModule/deleteBatch",
// exportXlsUrl: "/projectManage/projectModule/exportXls",
// importExcelUrl: "/projectManage/projectModule/importExcel",
// budgetExportXlsUrl: "/projectManage/projectModule/budgetExportXls",
// budgetImportUrl: "/projectManage/projectModule/budgetImportExcel",
},
}
},
watch: {
},
created() {
console.log(this.planId, '參數(shù)');
},
mounted() {
this.loadData();
},
methods: {
// 初始化
init() {
// 格式化日期
gantt.locale.date = {
month_full: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
month_short: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
day_full: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
day_short: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
}
gantt.locale.labels = {
dhx_cal_today_button: "今天",
day_tab: "日",
week_tab: "周",
month_tab: "月",
new_event: "新建日程",
icon_save: "保存",
icon_cancel: "關(guān)閉",
icon_details: "詳細(xì)",
icon_edit: "編輯",
icon_delete: "刪除",
confirm_closing: "請(qǐng)確認(rèn)是否撤銷(xiāo)修改!", //Your changes will be lost, are your sure?
confirm_deleting: "是否刪除計(jì)劃?",
section_description: "描述:",
section_time: "時(shí)間范圍:",
section_type: "類(lèi)型:",
section_text: "計(jì)劃名稱(chēng):",
section_test: "測(cè)試:",
section_projectClass: "項(xiàng)目類(lèi)型:",
taskProjectType_0: "項(xiàng)目任務(wù)",
taskProjectType_1: "普通任務(wù)",
section_head: "負(fù)責(zé)人:",
section_priority: '優(yōu)先級(jí):',
taskProgress: '任務(wù)狀態(tài)',
taskProgress_0: "未開(kāi)始",
taskProgress_1: "進(jìn)行中",
taskProgress_2: "已完成",
taskProgress_3: "已延期",
taskProgress_4: "擱置中",
section_template: 'Details',
/* grid columns */
column_text: "計(jì)劃名稱(chēng)",
column_start_date: "開(kāi)始時(shí)間",
column_duration: "持續(xù)時(shí)間",
column_add: "",
column_priority: "難度",
/* link confirmation */
link: "關(guān)聯(lián)",
confirm_link_deleting: "將被刪除",
message_ok: '確定',
message_cancel: '取消',
link_start: " (開(kāi)始)",
link_end: " (結(jié)束)",
type_task: "任務(wù)",
type_project: "項(xiàng)目",
type_milestone: "里程碑",
minutes: "分鐘",
hours: "小時(shí)",
days: "天",
weeks: "周",
months: "月",
years: "年"
}
console.log(gantt);
//自適應(yīng)甘特圖的尺寸大小, 使得在不出現(xiàn)滾動(dòng)條的情況下, 顯示全部任務(wù)
gantt.config.autosize = true
//只讀模式
gantt.config.readonly = false
//是否顯示左側(cè)樹(shù)表格
gantt.config.show_grid = true
// //表格列設(shè)置
gantt.config.columns = [
{ name: 'text', label: '階段名字', tree: true, width: '150', align: 'center', },
// { name: 'number', label: '工單號(hào)', tree: false, width: '120', align: 'center', },
{
name: 'duration',
label: '工時(shí)',
align: 'center',
template: function (obj) {
return obj.duration + '天'
},
},
/*{name:"start_date", label:"開(kāi)始時(shí)間", align: "center" },
{name:"end_date", label:"結(jié)束時(shí)間", align: "center" },*/
]
// 自動(dòng)延長(zhǎng)時(shí)間刻度
gantt.config.fit_tasks = true
// 允許拖放
gantt.config.drag_project = true
// 定義時(shí)間格式
gantt.config.scales = [
{ unit: 'month', step: 1, date: ' %Y,%F' },
{ unit: 'day', step: 1, date: ' %D ,%j' },
]
// //當(dāng)task的長(zhǎng)度改變時(shí),自動(dòng)調(diào)整圖表坐標(biāo)軸區(qū)間用于適配task的長(zhǎng)度
gantt.config.fit_tasks = true
// 添加彈窗屬性
gantt.config.lightbox.sections = [
{
name: 'description',
height: 70,
map_to: 'text',
type: 'textarea',
focus: true,
},
{ name: 'type', type: 'typeselect', map_to: 'type' },
{ name: 'time', type: 'duration', map_to: 'auto' },
];
console.log(this.tasks.data, '檢查任務(wù)數(shù)據(jù)'); // 檢查任務(wù)數(shù)據(jù)
// 初始化
gantt.init(this.$refs.gantt)
/* *******重點(diǎn)******* */
gantt.clearAll(); // 清空舊數(shù)據(jù)
/* ****************** */
// 數(shù)據(jù)解析
gantt.parse(this.tasks)
},
loadData(arg) {
if (!this.url.list) {
this.$message.error("請(qǐng)?jiān)O(shè)置url.list屬性!")
return
}
//加載數(shù)據(jù) 若傳入?yún)?shù)1則加載第一頁(yè)的內(nèi)容
let params = {
planId: this.planId,
}
this.loading = true;
this.tasks.data = []
getAction(this.url.list, params).then((res) => {
if (res.success) {
console.log(res, '甘特圖數(shù)據(jù)');
res.result.forEach(obj => {
obj.open = false
})
this.tasks.data = res.result
this.init()
}
if (res.code === 510) {
this.$message.warning(res.message)
}
this.loading = false;
})
},
},
}
</script>
<style lang="less" scoped>
.firstLevelTask {
border: none;
.gantt_task_content {
// font-weight: bold;
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: 900px;
.left-container {
height: 100%;
}
}
.left-container {
height: 600px;
}
.gantt_scale_line {
border-top: 0;
}
.weekend {
//background:#f4f7f4!important;
color: #000000 !important;
}
.gantt_selected .weekend {
background: #f7eb91 !important;
}
.gantt_task_content {
text-align: left;
padding-left: 10px;
}
//上面任務(wù)條樣式
.gantt_task_scale {
height: 45px !important;
}
.gantt_task .gantt_task_scale .gantt_scale_cell {
line-height: 30px !important;
height: 28px !important;
}
</style>
3.2 Vue3 完整示例
<template>
<div style="height: 100%; background-color: white">
<div ref="ganttRef" style="width: 100%; height: 600px"></div>
</div>
</template>
<script setup name="gantt-widget">
import { ref, reactive, onMounted } from 'vue'
import { gantt } from 'dhtmlx-gantt'
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import { formatDate } from '@/utils/util.js'
import { defineProps } from 'vue'
const props = defineProps({
widgetObj: {
type: Object,
required: true,
},
})
const ganttRef = ref()
const tasks = ref({})
//動(dòng)態(tài)加載數(shù)據(jù)
const fetchData = () => {
tasks.value = tasks.value = {
tasks: [
{
id: 10,
text: 'RFQ&項(xiàng)目啟動(dòng)',
type: 'project',
progress: 0.1,
open: true,
person: '張三',
},
{
id: 12,
text: '產(chǎn)品需求 #1.0.1',
start_date: '02-01-2025',
duration: 3,
parent: 10,
progress: 1,
person: '張三',
},
{
id: 13,
text: '產(chǎn)品數(shù)據(jù) #1.0.2',
start_date: '05-01-2025',
duration: 3,
parent: 10,
progress: 0.8,
person: '張三',
},
{
id: 14,
text: '環(huán)境數(shù)據(jù) #1.0.3',
start_date: '08-01-2025',
duration: 3,
parent: 10,
progress: 0,
person: '張三',
},
{
id: 15,
text: '項(xiàng)目評(píng)估指令 #1.1',
start_date: '11-01-2025',
duration: 3,
parent: 10,
progress: 0,
person: '張三',
},
{
id: 16,
text: '成立項(xiàng)目小組 #1.2.1',
start_date: '12-01-2025',
duration: 2,
parent: 10,
progress: 0,
person: '張三',
},
{
id: 17,
text: '可行性評(píng)估 #1.2.2',
start_date: '13-01-2025',
duration: 3,
parent: 10,
progress: 0,
person: '張三',
},
{
id: 18,
text: '輸入評(píng)審 #1.2.3',
start_date: '14-01-2025',
duration: 2,
parent: 10,
progress: 0,
person: '張三',
},
{
id: 19,
text: '初始產(chǎn)品方案 #1.2.4',
start_date: '16-01-2025',
duration: 2,
parent: 10,
progress: 0,
person: '張三',
},
{
id: 20,
text: '產(chǎn)品設(shè)計(jì)&開(kāi)發(fā)',
type: 'project',
progress: 0,
person: '張三',
open: false,
},
{
id: 21,
text: '設(shè)計(jì)輸入信息管理#3.0.1',
start_date: '18-01-2025',
duration: 2,
parent: 20,
progress: 0,
person: '張三',
},
{
id: 22,
text: '產(chǎn)品設(shè)計(jì)過(guò)往教訓(xùn)展開(kāi) #3.0.2',
start_date: '20-01-2025',
duration: 2,
parent: 20,
progress: 0,
person: '張三',
},
{
id: 23,
text: '產(chǎn)品設(shè)計(jì)進(jìn)度管理 #3.0.3',
start_date: '22-01-2025',
duration: 2,
parent: 20,
progress: 0,
person: '張三',
},
{
id: 24,
text: '產(chǎn)品設(shè)計(jì)方案 #3.0.4',
start_date: '24-01-2025',
duration: 2,
parent: 20,
progress: 0,
person: '張三',
},
{
id: 25,
text: '產(chǎn)品特殊特性識(shí)別 #3.0.5',
start_date: '26-01-2025',
duration: 2,
parent: 20,
progress: 0,
person: '張三',
},
{
id: 26,
text: '產(chǎn)品設(shè)計(jì)方案評(píng)審 #3.0.6',
start_date: '28-01-2025',
duration: 2,
parent: 20,
progress: 0,
person: '張三',
},
{
id: 30,
text: '過(guò)程設(shè)計(jì)&開(kāi)發(fā)',
type: 'project',
progress: 0,
person: '張三',
open: false,
},
{
id: 31,
text: '場(chǎng)地規(guī)劃 #5.0.1',
start_date: '28-02-2025',
duration: 3,
parent: 30,
progress: 0,
person: '張三',
},
{
id: 32,
text: '場(chǎng)地評(píng)審 #5.0.2',
start_date: '28-02-2025',
duration: 3,
parent: 30,
progress: 0,
person: '張三',
},
{
id: 33,
text: '過(guò)程檢驗(yàn)標(biāo)準(zhǔn) #5.0.3',
start_date: '29-02-2025',
duration: 3,
parent: 30,
progress: 0,
person: '張三',
},
{
id: 40,
text: '產(chǎn)品&過(guò)程驗(yàn)證',
type: 'project',
open: false,
progress: 0,
person: '張三',
},
{
id: 41,
text: '量具重復(fù)再現(xiàn)性分析 #6.0.1',
start_date: '29-02-2025',
duration: 3,
parent: 40,
progress: 0,
person: '張三',
},
{
id: 42,
text: '檢具使用驗(yàn)收 #6.0.2',
start_date: '01-03-2025',
duration: 3,
parent: 40,
progress: 0,
person: '張三',
},
{
id: 43,
text: '工裝-廠外預(yù)驗(yàn)收 #6.1.1',
start_date: '02-03-2025',
duration: 3,
parent: 40,
progress: 0,
person: '張三',
},
{
id: 44,
text: '設(shè)備-廠外預(yù)驗(yàn)收 #6.2.1',
start_date: '03-03-2025',
duration: 3,
parent: 40,
progress: 0,
person: '張三',
},
{
id: 45,
text: '模具-廠外預(yù)驗(yàn)收 #6.3.1',
start_date: '04-03-2025',
duration: 3,
parent: 40,
progress: 0,
person: '張三',
},
{
id: 50,
text: '過(guò)程驗(yàn)證',
type: 'project',
open: false,
progress: 0,
person: '張三',
},
{
id: 51,
text: '小批量試生產(chǎn)總結(jié) #7.0.1',
start_date: '28-04-2025',
duration: 3,
parent: 50,
progress: 0,
person: '張三',
},
{
id: 52,
text: '產(chǎn)品尺寸記錄 #7.0.2',
start_date: '29-04-2025',
duration: 3,
parent: 50,
progress: 0,
person: '張三',
},
{
id: 52,
text: '過(guò)程能力研究 #7.0.3',
start_date: '30-04-2025',
duration: 3,
parent: 50,
progress: 0,
person: '張三',
},
{
id: 60,
text: '反饋,糾正和改進(jìn)',
type: 'project',
open: false,
progress: 0,
person: '張三',
},
{
id: 61,
text: '模工檢移交 #8.0.1',
start_date: '28-05-2025',
duration: 3,
parent: 60,
progress: 0,
person: '張三',
},
{
id: 62,
text: '項(xiàng)目移交會(huì)議 #8.0.2',
start_date: '29-05-2025',
duration: 3,
parent: 60,
progress: 0,
person: '張三',
},
{
id: 63,
text: '取得量產(chǎn)交付計(jì)劃 #8.1.1',
start_date: '30-05-2025',
duration: 3,
parent: 60,
progress: 0,
person: '張三',
},
],
links: [
{ id: 10, source: 12, target: 13, type: 1 },
{ id: 11, source: 13, target: 14, type: 1 },
{ id: 12, source: 14, target: 15, type: 1 },
],
}
}
//初始化配置
const initGantt = () => {
gantt.plugins({ tooltip: true, quick_info: true })
// 漢化窗口
gantt.locale.labels = {
dhx_cal_today_button: '今天',
day_tab: '日',
week_tab: '周',
month_tab: '月',
new_event: '新建日程',
icon_save: '保存',
icon_cancel: '關(guān)閉',
icon_details: '詳細(xì)',
icon_edit: '編輯',
icon_delete: '刪除',
confirm_closing: '請(qǐng)確認(rèn)是否撤銷(xiāo)修改!', //Your changes will be lost, are your sure?
confirm_deleting: '是否刪除計(jì)劃?',
section_description: '描述:',
section_time: '時(shí)間范圍:',
section_type: '類(lèi)型:',
section_text: '計(jì)劃名稱(chēng):',
section_test: '測(cè)試:',
section_projectClass: '項(xiàng)目類(lèi)型:',
taskProjectType_0: '項(xiàng)目任務(wù)',
taskProjectType_1: '普通任務(wù)',
section_head: '負(fù)責(zé)人:',
section_priority: '優(yōu)先級(jí):',
taskProgress: '任務(wù)狀態(tài)',
taskProgress_0: '未開(kāi)始',
taskProgress_1: '進(jìn)行中',
taskProgress_2: '已完成',
taskProgress_3: '已延期',
taskProgress_4: '擱置中',
section_template: 'Details',
/* grid columns */
column_text: '計(jì)劃名稱(chēng)',
column_start_date: '開(kāi)始時(shí)間',
column_duration: '持續(xù)時(shí)間',
column_add: '',
column_priority: '難度',
/* link confirmation */
link: '關(guān)聯(lián)',
confirm_link_deleting: '將被刪除',
message_ok: '確定',
message_cancel: '取消',
link_start: ' (開(kāi)始)',
link_end: ' (結(jié)束)',
type_task: '任務(wù)',
type_project: '項(xiàng)目',
type_milestone: '里程碑',
minutes: '分鐘',
hours: '小時(shí)',
days: '天',
weeks: '周',
months: '月',
years: '年',
}
// 格式化日期
gantt.locale.date = {
month_full: [
'1月',
'2月',
'3月',
'4月',
'5月',
'6月',
'7月',
'8月',
'9月',
'10月',
'11月',
'12月',
],
month_short: [
'1月',
'2月',
'3月',
'4月',
'5月',
'6月',
'7月',
'8月',
'9月',
'10月',
'11月',
'12月',
],
day_full: [
'星期日',
'星期一',
'星期二',
'星期三',
'星期四',
'星期五',
'星期六',
],
day_short: [
'星期日',
'星期一',
'星期二',
'星期三',
'星期四',
'星期五',
'星期六',
],
}
// 當(dāng)task的長(zhǎng)度改變時(shí),自動(dòng)調(diào)整圖表坐標(biāo)軸區(qū)間用于適配task的長(zhǎng)度
gantt.config.fit_tasks = true
// 允許拖放
gantt.config.drag_project = true
// 定義時(shí)間格式
gantt.config.scales = [
{ unit: 'month', step: 1, date: '%F, %Y' },
{ unit: 'day', step: 1, date: '%j, %D' },
]
// gantt.config.scale_height = 80
// gantt.config.row_height = 60
// gantt.config.bar_height = 40
gantt.i18n.setLocale('cn')
// gantt.config.autosize = true
// gantt.config.readonly = true
gantt.config.show_grid = true
gantt.config.show_task_tooltips = true
gantt.config.show_progress = true
gantt.config.branches = {
open: 'open',
closed: 'closed',
}
gantt.templates.tooltip_text = (start, end, task) => `
<div>
<div>任務(wù):${task.text}</div>
<div>開(kāi)始時(shí)間:${formatDate(task.start_date, '{y}-{m}-e88muiy')}</div>
<div>結(jié)束時(shí)間:${formatDate(task.end_date, '{y}-{m}-os8qgio')}</div>
<div>進(jìn)度:${task.progress * 100}%</div>
</div>`
gantt.config.columns = [
{
name: 'text',
label: '任務(wù)名稱(chēng)',
width: '250',
tree: true,
align: 'left',
},
{ name: 'start_date', label: '起始時(shí)間', width: '100', align: 'center' },
{ name: 'duration', label: '持續(xù)時(shí)間', width: '80', align: 'center' },
{
name: 'progress',
label: '進(jìn)度',
width: '100',
align: 'center',
template: function (obj) {
return obj.progress * 100 + '%'
},
},
{ name: 'person', label: '負(fù)責(zé)人', width: '80', align: 'center' },
]
gantt.config.lightbox_zindex = 10000
// 添加彈窗屬性
gantt.config.lightbox.sections = [
{
name: 'description',
height: 70,
map_to: 'text',
type: 'textarea',
focus: true,
},
{ name: 'type', type: 'typeselect', map_to: 'type' },
{ name: 'time', type: 'duration', map_to: 'auto' },
]
// 初始化
gantt.init(ganttRef.value)
// 清空舊數(shù)據(jù)
gantt.clearAll()
// 數(shù)據(jù)解析
gantt.parse(tasks.value)
}
onMounted(() => {
fetchData()
initGantt()
})
</script>
<style lang="scss" scoped>
.gantt_cal_light {
z-index: 9999 !important;
}
.gantt_cal_cover {
z-index: 10000 !important;
}
</style>四、效果圖

到此這篇關(guān)于vue+dhtmlx-gantt 實(shí)現(xiàn)甘特圖-快速入門(mén)【甘特圖】的文章就介紹到這了,更多相關(guān)vue dhtmlx-gantt 甘特圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- vue前端實(shí)現(xiàn)dhtmlxgantt甘特圖代碼示例(個(gè)人需求)
- Vue項(xiàng)目的甘特圖組件之dhtmlx-gantt使用教程和實(shí)現(xiàn)效果展示(推薦)
- 基于vue3和element plus實(shí)現(xiàn)甘特圖
- 前端vue實(shí)現(xiàn)甘特圖功能
- Vue echarts繪制甘特圖的示例代碼
- Vue+Echarts實(shí)現(xiàn)繪制多設(shè)備狀態(tài)甘特圖
- vue2結(jié)合element-ui的gantt圖實(shí)現(xiàn)可拖拽甘特圖
- Vue echarts畫(huà)甘特圖流程詳細(xì)講解
- 詳解gantt甘特圖可拖拽、編輯(vue、react都可用?highcharts)
相關(guān)文章
vue-pdf實(shí)現(xiàn)pdf在線(xiàn)預(yù)覽并實(shí)現(xiàn)自定義預(yù)覽框高度
這篇文章主要介紹了vue-pdf實(shí)現(xiàn)pdf在線(xiàn)預(yù)覽并實(shí)現(xiàn)自定義預(yù)覽框高度方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
Vue 3自定義指令開(kāi)發(fā)的相關(guān)總結(jié)
這篇文章主要介紹了Vue 3自定義指令開(kāi)發(fā)的相關(guān)總結(jié),幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下2021-01-01
vue3?+?element-plus?的?upload?+?axios?+?django?實(shí)現(xiàn)文件上
這篇文章主要介紹了vue3?+?element-plus?的?upload?+?axios?+?django?文件上傳并保存,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01
vue 添加和編輯用同一個(gè)表單,el-form表單提交后清空表單數(shù)據(jù)操作
這篇文章主要介紹了vue 添加和編輯用同一個(gè)表單,el-form表單提交后清空表單數(shù)據(jù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
在Vue3中使用Vue Tour實(shí)現(xiàn)頁(yè)面導(dǎo)覽
Vue Tour 是一個(gè)方便的 Vue.js 插件,它可以幫助我們?cè)诰W(wǎng)站或應(yīng)用中實(shí)現(xiàn)簡(jiǎn)單而靈活的頁(yè)面導(dǎo)覽功能,本文我們將介紹如何在 Vue 3 中使用 Vue Tour,并通過(guò)示例代碼演示其基本用法,需要的朋友可以參考下2024-04-04
vue3+pinia用戶(hù)信息持久緩存token的問(wèn)題解決
本文主要介紹了vue3+pinia用戶(hù)信息持久緩存token的問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
基于Vue3+TypeScript實(shí)現(xiàn)鼠標(biāo)框選功能
這篇文章主要介紹了基于Vue3+TypeScript實(shí)現(xiàn)鼠標(biāo)框選功能,文中通過(guò)代碼示例給大家講解的非常纖細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-07-07

