公司的甘特图需求,研究了几个组件后,选择使用 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>