首页 前端知识 Vue项目的甘特图组件:dhtmlx-gantt使用教程和实现效果展示

Vue项目的甘特图组件:dhtmlx-gantt使用教程和实现效果展示

2024-10-29 11:10:43 前端知识 前端哥 310 803 我要收藏

公司的甘特图需求,研究了几个组件后,选择使用 dhtmlx-gantt 进行实现,dhtmlx-gantt使用其实是偏简单的,文档虽然是英文,但配合翻译也是可以看懂的,下面将公司需求的代码实现粘贴出来,并简单介绍一下使用方法,希望对你有帮助。

看一下目前实现的效果:

需求是不需要bar连线的,所以将bar连线注释掉了,连线也是可以有的

组件官网地址: https://dhtmlx.com/

目录

一、首先 npm 安装插件

二、创建一个vue组件

三、业务页面内 引用自定义组件:

四、dhtmlx-gantt 基本配置项

格式化表头日期展示:

甘特图的尺寸自适应

只读模式

是否显示左侧表格

设置表头高度

设置bar的高度

设置行的高度

设置时间识别格式

表格列设置

 为每个bar增加class

自动延长时间刻度

允许拖放

 定义x轴时间维度

自动调整坐标轴

启用 tooltip 功能

性能提升

增加事件

五、完整代码


下面正式进入教程:

一、首先 npm 安装插件

npm i dhtmlx-gantt

二、创建一个vue组件

我这里命名为gantt.vue ,放在项目根目录的 /components 目录下

             gantt.vue文件:

<template>
	<div>
		<div ref="gantt"/>
	</div>
</template>

<script>
    import gantt from 'dhtmlx-gantt'; // 引入包
    import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'; // 引入自带的css文件
    
    export default { 
      data() {
		return {
			tasks: {
				data: [
                 
					{
						id: 1,
						text: 'DFB24019',
						progress: 0.8, //完成度
                        start_date: '2021-10-16', //开始时间 日月年
                        end_date: '2021-10-15',
                        projectStatus: '进行中',
						open: true, //默认打开=
						number: '', //显示字段
                        person: '韩鸿风',
                        post: 'BA',
                        department: '数字化一部',
                        task: '0/20'
					},
                    {
						// toolTipsTxt: '任务#101-001',
						id: 21, //任务id
						text: '任务1的撒的防守打法士大夫', //任务名称
						start_date: '2021-10-16', //开始时间 日月年
                        end_date: '2021-12-26',
						parent: 1, //父级id
						progress: 1, //完成度
						open: true, //默认打开
						status: '已完成',
					},
                    {
						// toolTipsTxt: '任务#101-001',
						id: 22, //任务id
						text: '第二个逾期阶段', //任务名称
						start_date: '2021-12-16', //开始时间 日月年
						end_date: '2022-01-26',
						parent: 1, //父级id
						progress: 1, //完成度
						open: true, //默认打开
						status: '逾期'
					},
                    {
						// toolTipsTxt: '任务#101-001',
						id: 23, //任务id
						text: '第三个进行中阶段', //任务名称
						start_date: '2022-01-20', //开始时间 日月年
                        end_date: '2022-03-03',
						parent: 1, //父级id
						progress: 0.7, //完成度
						open: true, //默认打开
						status: '进行中'
					},
					{
						id: 2,
						text: 'DFB45113',
						progress: 0.7, //完成度
                        start_date: '2021-10-16', //开始时间 日月年
                        projectStatus: '已完成',
                        end_date: '2021-10-15',
						open: true, //默认打开
						number: '哈哈哈' //显示字段
					},
					{
						// toolTipsTxt: '任务#101-001',
						id: 11, //任务id
						text: '项目启动阶段', //任务名称
						start_date: '2022-04-06', //开始时间 日月年
                        end_date: '2022-06-06',
						parent: 2, //父级id
						progress: 1, //完成度
						open: true, //默认打开
						status: '已完成'
					},
					{
						// toolTipsTxt: '任务#101-001',
						id: 12, //任务id
						text: '设计阶段', //任务名称
						start_date: '2022-04-20', //开始时间 日月年
                        end_date: '2022-06-26',
						parent: 2, //父级id
						progress: 0.9, //完成度
						open: true, //默认打开
						status: '进行中'
					},
					{
						// toolTipsTxt: '任务#101-001',
						id: 13, //任务id
						text: '采购阶段', //任务名称
						start_date: '2022-05-14', //开始时间 日月年
                        end_date: '2022-07-26',
						parent: 2, //父级id
						progress: 1, //完成度
						open: true, //默认打开
						status: '未开始'
					}
				],
			
				// 任务之间连接线,目前注释掉了,需要的话打开
				// 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' }
				// ]
			},

		};
	},
    mounted() {
        this.init();
    },
    methods: {
        init() {
            // 设置时间识别格式
            gantt.config.xml_date = "%Y-%m-%d"
			// //表格列设置
			gantt.config.columns = [
                { name: 'person', label: '项目成员', width: '100', align: 'center' }
			];

             gantt.config.scales = [{ unit: 'month', step: 1, date: ' %Y 年  %F' }, { unit: 'day', step: 1, date: '%d' }];
            // 清空旧数据
			gantt.clearAll(); 
            // 销毁gantt实例   按需开启
            // gantt.destructor()
			// 初始化
			gantt.init(this.$refs.gantt);
			// 数据解析
			gantt.parse(this.tasks);
		},
    }
</script>

三、业务页面内 引用自定义组件:

<template>
        <!-- 使用甘特图组件 -->
		<div style="padding: 10px;background-color: #fff;">
			<gantt></gantt>
		</div>
</template>

<script>
import gantt from '@/components/gantt.vue';
components: { gantt },
</script>

如果你的页面能展示出来基本样式,那么就成功啦,咱们继续下一步

下面讲一下  dhtmlx-gantt 的一些配置项,也可以说是我用到的配置项,更多的就要参考官方文档了

四、dhtmlx-gantt 基本配置项

(注意,都要放在组件的 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.config.autosize = false;

只读模式

为false时支持编辑

gantt.config.readonly = true;

是否显示左侧表格

gantt.config.show_grid = true;

设置表头高度

gantt.config.scale_height = 50;

设置bar的高度

gantt.config.bar_height = 26;

设置行的高度

gantt.config.row_height = 32;

设置时间识别格式

很重要,必须和你数据的格式一样

gantt.config.xml_date = "%Y-%m-%d %H:%i"

表格列设置

(配置项不用细说了吧,template 可以自定义列模板)

gantt.config.columns = [
				{ name: 'text', label: '项目名称', tree: true, width: '200', align: 'left', template: (task)=>{
                    if(task.parent) {
                        return task.text
                    } else {
                        return `<div style="font-weight: 700">${task.text}</div>`
                    }
                }},
                { name: 'person', label: '项目成员', width: '100', align: 'center' },
                // { name: 'post', label: '岗位名称', width: '100', align: 'center' },
                // { name: 'department', label: '部门名称', width: '100', align: 'center' },
                { name: 'task', label: '项目任务', width: '100', align: 'center' },
				// { name: 'number', label: '工单号', tree: false, width: '120', align: 'center', },
				// {
				// 	name: 'duration',
				// 	label: '工期',
				// 	align: 'center',
				// 	template: function(obj) {
				// 		return obj.duration + '天';
				// 	}
				// }
				// {name:"start_date", label:"开始时间", align: "center" },
				// {name:"end_date",   label:"结束时间",   align: "center" },
			];

 为每个bar增加class

(希望不同的bar展示不同的颜色)

gantt.templates.task_class = function(start, end, item) {
	switch (item.status) {
		case '400': // 已完成
			return 'gantt_success';
		case '100': // 未开始
			return 'gantt_begined';
		case '200': // 进行中
			return 'gantt_primary';
		case '300': // 暂停
			return 'gantt_warning';
		default: // 已终止 500
			return 'gantt_info';
	}
};

然后在css内定义样式就好啦

<style lang="less" scoped>
    /deep/ .gantt_success .gantt_task_progress {
	    background: #13C400 !important;
        border: none !important;
    }
    /deep/ .gantt_primary .gantt_task_progress {
	    background:  #3A84FF!important;
        border: none !important;
    }
    /deep/ .gantt_begined .gantt_task_progress {
	    background: #9a9a9a !important;
        border: none !important;
    }
    /deep/ .gantt_info .gantt_task_progress {
	    background: #FE0000 !important;
        border: none !important;
    }
    /deep/ .gantt_warning .gantt_task_progress {
	    background: #FF7700 !important;
        border: none !important;
    }
</style>

自动延长时间刻度

gantt.config.fit_tasks = true;

允许拖放

gantt.config.drag_project = true;

 定义x轴时间维度

做视图切换

// 年 格式
gantt.config.scales = [{ unit: 'year', step: 1, date: ' %Y 年' }];
// 月 格式
gantt.config.scales = [{ unit: 'year', step: 1, date: ' %Y 年' }, { unit: 'month', step: 1, date: '%F' }];
 // 日 格式
gantt.config.scales = [{ unit: 'month', step: 1, date: ' %Y 年  %F' }, { unit: 'day', step: 1, date: '%d' }];

自动调整坐标轴

当task的长度改变时,自动调整图表坐标轴区间用于适配task的长度

gantt.config.fit_tasks = true;

启用 tooltip 功能

gantt.plugins({
	tooltip: true // 启用 tooltip 插件
});

gantt.templates.tooltip_text = (start, end, task) => {
		
};

性能提升

// 仅仅渲染在屏幕可见的那部分时间轴。在处理时间轴非常长的时候,可以提升性能
gantt.config.smart_scales = true
// 按需渲染, 仅仅渲染在屏幕可见的那部分任务和依赖线。这个在显示大量的任务时,性能比较高。
gantt.config.smart_rendering = true

增加事件

事件很多,具体看官方文档,我这里加了双击事件

// 给每行增加双击事件 ,亲测事件会重复注册,用这个方法拦截一下
if (this.onTaskDblClick) gantt.detachEvent(this.onTaskDblClick);
// 双击bar任务事件(单击会有问题,点击展开时也会触发)
this.onTaskDblClick = gantt.attachEvent("onTaskDblClick", (id, e) => {
    this.$emit('rowDbClick',id)
    return true;
}, { id: 'onTaskDblClick' })
            

五、完整代码

ganttPerson.vue

<template>
	<div>
		<div ref="gantt" :style="'height:' + (tabheight - 80) + 'px'" />
	</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 {
    name: 'ganttPerson',
    props: ['ganttData', 'dateType'],
    watch: {
        ganttData: {
            handler(val) {
                this.tasks = {
                    data: val
                }
                this.init();
            },
            deep: true
        }
    },
    mounted() {
        let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
        this.tabheight = h - 170;
        if (this.height) {
			this.tabheight = this.height;
		}
    },
	// mixins: [JeecgListMixin],
	data() {
		return {
            // 注册事件拦截
            onTaskDblClick: null,
			// 甘特图配置
			tasks: {
				data: [
                    //  把父节点的开始结束设置为同一天,就可以实现隐藏父节点的bar
                    // # 字段解释
                    //  id:   数据id  必须是唯一值,父子也不能重复
                    //  text: 会显示在bar上的字段,如不显示就设为 ''
                    //  progress: 完成度, 0 - 1
                    //  start_date: 开始的日期,格式在js里设置,
                    //  end_date: 结束的日期  要时分秒! 只给日期会视为日期的 00:00:00  要特殊处理一下!!
                    //  open: 如果是父节点,是否默认展开
                    //  parent:  子节点必须有,设置为父节点的id,会自动处理,数据顺序无所谓
                    // #=================================================================
				]
				// #字段解释
				// 格式 id:数据id
				//     source:开始链接的项目id  ----为tasks.data中数据的id
				//     target:要链接项目的id  ----为tasks.data中数据的id
				//     type: 0--进行-开始  `尾部链接头部`
				//           1--开始-开始  `头部链接头部`
				//           2--进行-进行  `尾部链接尾部`
				//           3--开始-进行  `头部链接尾部`
				// 任务之间连接线,目前注释掉了,需要的话打开
				// 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",
			},
            tabheight: 0
		};
	},
	methods: {
		// 初始化
		init() {
			gantt.i18n.setLocale('cn'); // 汉化 - 默认是英文
			// 格式化日期
			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: '关闭',
				icon_details: '详细',
				icon_edit: '编辑',
				icon_delete: '删除',
				confirm_closing: '请确认是否撤销修改!', //Your changes will be lost, are your sure?
				confirm_deleting: '是否删除计划?',
				section_description: '描述:',
				section_time: '时间范围:',
				section_type: '类型:',
				section_text: '计划名称:',
				section_test: '测试:',
				section_projectClass: '项目类型:',
				taskProjectType_0: '项目任务',
				taskProjectType_1: '普通任务',
				section_head: '负责人:',
				section_priority: '优先级:',
				taskProgress: '任务状态',
				taskProgress_0: '未开始',
				taskProgress_1: '进行中',
				taskProgress_2: '已完成',
				taskProgress_3: '已延期',
				taskProgress_4: '搁置中',
				section_template: 'Details',
				/* grid columns */
				column_text: '计划名称',
				column_start_date: '开始时间',
				column_duration: '持续时间',
				column_add: '',
				column_priority: '难度',
				/* link confirmation */
				link: '关联',
				confirm_link_deleting: '将被删除',
				message_ok: '确定',
				message_cancel: '取消',
				link_start: ' (开始)',
				link_end: ' (结束)',

				type_task: '任务',
				type_project: '项目',
				type_milestone: '里程碑',
				minutes: '分钟',
				hours: '小时',
				days: '天',
				weeks: '周',
				months: '月',
				years: '年'
			};

			//自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
			gantt.config.autosize = false;
			//只读模式
			gantt.config.readonly = true;
			//是否显示左侧树表格
			gantt.config.show_grid = true;
			// 设置表头高度
			gantt.config.scale_height = 50;
            // 设置bar的高度
            gantt.config.bar_height = 26;
            // 设置行的高度
            gantt.config.row_height = 32;
            // 设置时间识别格式
            gantt.config.xml_date = "%Y-%m-%d %H:%i"
			// //表格列设置
			gantt.config.columns = [
				{ name: 'text', label: '项目名称', tree: true, width: '200', align: 'left', template: (task)=>{
                    if(task.parent) {
                        return task.text
                    } else {
                        return `<div style="font-weight: 700">${task.text}</div>`
                    }
                }},
                { name: 'person', label: '项目成员', width: '100', align: 'center' },
                // { name: 'post', label: '岗位名称', width: '100', align: 'center' },
                // { name: 'department', label: '部门名称', width: '100', align: 'center' },
                { name: 'task', label: '项目任务', width: '100', align: 'center' },
				// { name: 'number', label: '工单号', tree: false, width: '120', align: 'center', },
				// {
				// 	name: 'duration',
				// 	label: '工期',
				// 	align: 'center',
				// 	template: function(obj) {
				// 		return obj.duration + '天';
				// 	}
				// }
				// {name:"start_date", label:"开始时间", align: "center" },
				// {name:"end_date",   label:"结束时间",   align: "center" },
			];
            // 为每个bar增加class
			gantt.templates.task_class = function(start, end, item) {
				switch (item.status) {
					case '400': // 已完成
						return 'gantt_success';
					case '100': // 未开始
						return 'gantt_begined';
					case '200': // 进行中
						return 'gantt_primary';
					case '300': // 暂停
						return 'gantt_warning';
					default: // 已终止 500
						return 'gantt_info';
				}
			};
			// 自动延长时间刻度
			gantt.config.fit_tasks = true;
			// 允许拖放
			gantt.config.drag_project = true;
			// 定义时间格式
            if(this.dateType === 'year') {
                // 年 格式
                gantt.config.scales = [{ unit: 'year', step: 1, date: ' %Y 年' }];
            } else if(this.dateType === 'month') {
                // 月 格式
			   gantt.config.scales = [{ unit: 'year', step: 1, date: ' %Y 年' }, { unit: 'month', step: 1, date: '%F' }];
            } else {
                 // 日 格式
                gantt.config.scales = [{ unit: 'month', step: 1, date: ' %Y 年  %F' }, { unit: 'day', step: 1, date: '%d' }];
            }
			// //当task的长度改变时,自动调整图表坐标轴区间用于适配task的长度
			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' }
			];
                
            // 给每行增加双击事件 ,亲测事件会重复注册,用这个方法拦截一下
            if (this.onTaskDblClick) gantt.detachEvent(this.onTaskDblClick);
             // 双击bar任务事件(单击会有问题,点击展开时也会触发)
            this.onTaskDblClick = gantt.attachEvent("onTaskDblClick", (id, e) => {
                this.$emit('rowDbClick',id)
                return true;
            }, { id: 'onTaskDblClick' })
            
            // 清空旧数据
			gantt.clearAll(); 
            // 销毁gantt实例   按需开启
            // gantt.destructor()
			// 初始化
			gantt.init(this.$refs.gantt);
			// 数据解析
			gantt.parse(this.tasks);
		},
	}
};
</script>

<style lang="less" scoped>
/deep/ .gantt_row.gantt_row_project:hover {
	background: #e4e4e4 !important;
}

/deep/ .gantt_row.gantt_row_task:hover {
	background: #e4e4e4 !important;
}
/deep/ .gantt_selected {
	background: #ececec !important;
}
/deep/ .gantt_task_row.gantt_selected .gantt_task_cell {
	background: #ececec !important;
	border-right-color: #ebebeb !important;
}

/deep/ .gantt_grid_head_cell {
	background-color: #f7f7f7;
	font-weight: 700;
	font-size: 13px;
	color: #000000;
}
/deep/ .gantt_scale_cell {
	background-color: #f7f7f7;
	font-weight: 700;
	color: #000000 !important;
	border-bottom: 1px solid #ebebeb;
}
/deep/ .gantt_task_line {
    border: none !important;
    box-shadow: none !important;
}
/deep/ .gantt_task_progress_wrapper {
    border: none !important;
    background-color: #E1E1E1;
    border-radius: 8px;
}
/deep/ .gantt_task_content {
 
}
/deep/ .gantt_task_line {
    border: none;
    border-radius: 8px;
    background-color: transparent;
}
/deep/ .gantt_success .gantt_task_progress {
	background: #13C400 !important;
    border: none !important;
}
/deep/ .gantt_primary .gantt_task_progress {
	background:  #3A84FF!important;
    border: none !important;
}
/deep/ .gantt_begined .gantt_task_progress {
	background: #9a9a9a !important;
    border: none !important;
}
/deep/ .gantt_info .gantt_task_progress {
	background: #FE0000 !important;
    border: none !important;
}
/deep/ .gantt_warning .gantt_task_progress {
	background: #FF7700 !important;
    border: none !important;
}
</style>

业务代码:

<template>
	<div style="padding: 10px">
		<more-search :searchdata="searchdata" :searchform="searchform" @submit="submit" :needChangeCard="true"></more-search>
        <!-- 甘特图组件 -->
		<div style="padding: 10px;background-color: #fff;">
			<gantt v-loading="tableLoading" :ganttData="ganttData" :dateType="searchform.DataType" @rowDbClick="ganttDbClick"></gantt>
            
            <div style="margin-top: 10px;text-align: right;">
                <el-pagination @current-change="handleCurrentChange" @size-change="handleSizeChange" :current-page="page"
                    background layout="total, sizes,prev, pager, next" :page-size="pageSize" :total="total" :page-sizes="[30, 50, 100, 200]">
                </el-pagination>
            </div>
		</div>
        <!-- 详情弹窗 -->
		<el-drawer title="任务详情" :visible.sync="leftDialogVisible" direction="rtl">
			<div style="padding: 20px;border-top: 1px #ccc solid;">
				<div style="display: flex;flex-wrap: wrap;">
					<div v-for="propItem in detailProp" :style="propItem.width > 200 ? 'width:100%' : 'width: 50%'" :key="propItem.prop" class="text item">
						<div style="width: 110px;text-align: center;color:#94999F; border: 1px #EBEEF5 solid;flex-shrink: 0;padding: 5px;background-color: #FAFAFA;padding-left: 10px; display: flex;align-items: center;">
							{{ propItem.label }}
						</div>
						<div style="border: 1px #EBEEF5 solid;padding: 5px 0 5px 10px;overflow: hidden;width: 100%;">
							<div class="wordhidden">
								<span v-if="propItem.formatter">
									<div v-html="propItem.formatter(detailData[propItem.prop])"></div>
								</span>
								<span v-else>{{ detailData[propItem.prop] }}</span>
							</div>
						</div>
					</div>
				</div>
			</div>
		</el-drawer>
	</div>
</template>

<script>
import moreSearch from '@/components/moreSearch.vue';
import gantt from '@/components/ganttPerson.vue';
import { GetList, GetUsers, GetAllDepts, GetAllPosts, GetProjectList } from '@/api/personUtilSituation.js';
export default {
	components: { moreSearch, gantt },
	data() {
		return {
            tableLoading: false,
            page: 1,
            total: 0,
            pageSize: 30,
			leftDialogVisible: false,
			detailData: {},
			detailProp: [
				{
					label: '任务名称',
					prop: 'text',
					width: 300
				},
				{
					label: '项目名称',
					prop: 'project',
					width: 300
				},
				{
					label: '项目成员',
					prop: 'personName',
					width: 300
				},
				{
					label: '成员部门',
					prop: 'departmentName',
					width: 300
				},
				{
					label: '成员岗位',
					prop: 'postName',
					width: 300
				},
				{
					label: '开始日期',
					prop: 'start_date',
					width: 300,
					formatter: (val) => {
						return  `<div>${ this.formatDate(val) }</div>`
					}
				},
				{
					label: '结束日期',
					prop: 'end_date',
					width: 300,
					formatter: (val) => {
						return  `<div>${ this.formatDate(val) }</div>`
					}
				},
				{
					label: '任务状态',
					prop: 'status',
					width: 300,
					formatter: (val) => {
						switch (val) {
                            case '400': // 已完成
                                return `<div style="color: #13C400; font-weight: 700;">已完成</div>`;
                            case '100': // 未开始
                                return `<div style="color: #9a9a9a; font-weight: 700;">未开始</div>`;
                            case '200': // 进行中
                                return `<div style="color: #3A84FF; font-weight: 700;">进行中</div>`;
                            case '300': // 暂停
                                return `<div style="color: #FF7700; font-weight: 700;">暂停</div>`;
                            default: // 已终止 500
                                return `<div style="color: #FE0000; font-weight: 700;">已终止</div>`;
                        }
					}
				}
			],
			ganttData: [],
			searchdata: [
				{
					label: '展示形式',
					type: 'select',
					key: 'DataType',
					shortcut: true,
					options: [
						{
							label: '年',
							value: 'year'
						},
						{
							label: '月',
							value: 'month'
						},
						{
							label: '日',
							value: 'day'
						}
					]
					// namei18n: 'CommercialQuotationNumber',
				},
				{
					label: '日期范围',
					type: 'datepicker',
					options: [],
					key: 'Date',
					shortcut: true
				},
				{
					label: '项目名称',
					type: 'select',
					key: 'ProjectId',
					shortcut: true,
					options: []
					// namei18n: 'CommercialQuotationNumber',
				},
				{
					label: '项目成员',
					type: 'select',
					key: 'PersonId',
					shortcut: false,
					options: []
					// namei18n: 'CommercialQuotationNumber',
				},
				{
					label: '岗位名称',
					type: 'select',
					key: 'PostName',
					shortcut: false,
					options: []
					// namei18n: 'CommercialQuotationNumber',
				},
				{
					label: '部门名称',
					type: 'select',
					key: 'DepartmentName',
					shortcut: false,
					options: []
					// namei18n: 'CommercialQuotationNumber',
				}
			],
			searchform: {
				DataType: 'day',
				Date: [],
				ProjectId: '',
				PersonId: '',
				PostName: '',
				DepartmentName: ''
			},
			page: 1
		};
	},
	mounted() {
		this.getSelectList();
		this.getList();
	},
	methods: {
		ganttDbClick(id) {
			console.log('接收到', id);
			let clickRow = this.ganttData.filter((item) => {
				return item.id === id;
			});
			console.log('点击了', clickRow);
			this.detailData = clickRow[0];
            if(!this.detailData.project) return
			this.leftDialogVisible = true;
		},
		submit(val) {
			this.searchform = val;
			this.page = 1;
			this.getList();
		},
		getList() {
            this.tableLoading = true
			this.ganttData = [];
			let para = {
				Start: this.searchform.Date ? this.searchform.Date[0] : '',
				End: this.searchform.Date ? this.searchform.Date[1] : '',
				ProjectId: this.searchform.ProjectId,
				PersonId: this.searchform.PersonId,
				PostName: this.searchform.PostName,
				SkipCount: (this.page -1) * this.pageSize,
				MaxResultCount: this.pageSize
			};
			GetList(para).then((res) => {
                this.total = res.response.totalCount;
				let data = res.response.items;
				let arr = [];
				data.forEach((item) => {
					// 父节点
					arr.push({
						id: item.id,
						text: item.projectName, // 第一项 项目名称
						task: item.finishedCount + ' / ' + item.totalCount, // 项目任务数字
						start_date: item.tasks[0].planStartDate + ' 00:00',
						end_date: item.tasks[0].planStartDate + ' 00:00',
						progress: 1,
						open: true,
						person: item.personName
					});
					// 子节点
					if (item.tasks) {
						item.tasks.forEach((task) => {
							arr.push({
								id: task.id,
								text: task.taskName,
								start_date: task.planStartDate + ' 00:00',
								end_date: task.planFinishDate + ' 23:59',
								progress: 1,
								parent: item.id,
								status: task.status,
								project: item.projectName,
								departmentName: item.departmentName,
								personName: item.personName,
								postName: item.postName
							});
						});
					}
				});
				this.ganttData = arr;
                this.tableLoading = false
			}).catch(rej=>{
                this.tableLoading = false
            });
		},
        handleCurrentChange(val) {
			this.page = val
            this.getList()
		},
		handleSizeChange(val) {
            this.page = 1
			this.pageSize = val
            this.getList()
		},
		getSelectList() {
			GetUsers().then((res) => {
				this.searchdata.forEach((item) => {
					if (item.key === 'PersonId') {
						item.options = res.response.map((item) => {
							return {
								value: item.id,
								label: item.name
							};
						});
					}
				});
			});
			GetAllDepts().then((res) => {
				this.searchdata.forEach((item) => {
					if (item.key === 'DepartmentName') {
						item.options = res.response.map((item) => {
							return {
								value: item.id,
								label: item.name
							};
						});
					}
				});
			});
			GetAllPosts().then((res) => {
				this.searchdata.forEach((item) => {
					if (item.key === 'PostName') {
						item.options = res.response.map((item) => {
							return {
								value: item.id,
								label: item.name
							};
						});
					}
				});
			});
			GetProjectList().then((res) => {
				this.searchdata.forEach((item) => {
					if (item.key === 'ProjectId') {
						item.options = res.response.map((item) => {
							return {
								value: item.id,
								label: item.projectName
							};
						});
					}
				});
			});
		},
		formatDate(date) {
			if (!date) return '';
			const year = date.getFullYear();
			const month = String(date.getMonth() + 1).padStart(2, '0');
			const day = String(date.getDate()).padStart(2, '0');
			// const hours = String(date.getHours()).padStart(2, '0');
			// const minutes = String(date.getMinutes()).padStart(2, '0');
			// const seconds = String(date.getSeconds()).padStart(2, '0');

			return `${year}-${month}-${day}`;
		}
	}
};
</script>

<style scoped>
.text {
	font-size: 13px;
}

.item {
	display: flex;
}
</style>

转载请注明出处或者链接地址:https://www.qianduange.cn//article/19435.html
标签
甘特图
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!