|
|
@@ -0,0 +1,378 @@
|
|
|
+<template>
|
|
|
+ <div ref="gantt_scrollbar" class="gantt-box">
|
|
|
+ <div ref="gantt" class="gantt-container"></div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+ import { Gantt } from './gantt';
|
|
|
+ import 'dhtmlx-gantt/codebase/dhtmlxgantt.css';
|
|
|
+ let gantt = new Gantt();
|
|
|
+ let i = 0;
|
|
|
+ export default {
|
|
|
+ name: 'gantt',
|
|
|
+ props: {
|
|
|
+ ganttTasks: {
|
|
|
+ type: Array,
|
|
|
+ default: () => {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ ganttTasks: {
|
|
|
+ handler(val) {
|
|
|
+ this.initData();
|
|
|
+ },
|
|
|
+ deep: true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ ganttData: []
|
|
|
+ };
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ console.log(gantt);
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.initGantt(); // gantt初始化配置
|
|
|
+ this.initData(); // 数据format以及gantt reload
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ initGantt() {
|
|
|
+ let _this = this;
|
|
|
+ // 在初始化前设置配置项
|
|
|
+ // gantt只读
|
|
|
+ //设置图表区域的日期坐标最大值 var date = new Date(dateString.replace(/-/,"/"))
|
|
|
+ // gantt.config.start_date = new Date("2020-04-08".replace(/-/,"/")) ;
|
|
|
+ //gantt.config.end_date = new Date("2020-04-18".replace(/-/,"/")) ; //结束时间需要+1天
|
|
|
+ gantt.config.readonly = true;
|
|
|
+ gantt.config.select_task = false;
|
|
|
+ gantt.config.autofit = false;
|
|
|
+ gantt.config.xml_date = '%Y-%m-%d %H:%i:%s';
|
|
|
+ gantt.config.show_grid = false;
|
|
|
+ // //设置x轴日期
|
|
|
+ // gantt.config.scale_unit = 'day'
|
|
|
+ // gantt.config.step = 1
|
|
|
+ // gantt.config.date_scale = '星期' + '%D'
|
|
|
+ // gantt.config.columns = [
|
|
|
+ // {
|
|
|
+ // name: 'name',
|
|
|
+ // width: 250,
|
|
|
+ // label: '名称',
|
|
|
+ // align: 'left',
|
|
|
+ // // tree: true,
|
|
|
+ // // open: true,
|
|
|
+
|
|
|
+ // // onrender: function (task, node) {
|
|
|
+ // // if (task.rowSpan) {
|
|
|
+ // // node.parentNode.style.height = `${15 * task.rowSpan}px`;
|
|
|
+ // // node.childNodes[
|
|
|
+ // // node.childNodes.length - 1
|
|
|
+ // // ].style.lineHeight = `${15 * task.rowSpan}px`;
|
|
|
+ // // } else {
|
|
|
+ // // node.style.display = 'none';
|
|
|
+ // // node.parentNode.style.display = 'none';
|
|
|
+ // // }
|
|
|
+ // // },
|
|
|
+ // template: function (obj) {
|
|
|
+ // return `
|
|
|
+ // <div style="width:250px;text-overflow:ellipsis;overflow: hidden;">${
|
|
|
+ // obj.name || ''
|
|
|
+ // }</div>
|
|
|
+ // `;
|
|
|
+ // // <div class="gantt-span-${obj.level}" style="width:130px;text-overflow:ellipsis;overflow: hidden;">${obj.name}</div>
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // ];
|
|
|
+ let daysStyle = function (date) {
|
|
|
+ let todayDate = new Date().setHours(0, 0, 0, 0);
|
|
|
+ let paramsDate = new Date(date).setHours(0, 0, 0, 0);
|
|
|
+ if (todayDate === paramsDate) {
|
|
|
+ return 'today';
|
|
|
+ }
|
|
|
+ if (date.getDay() === 0 || date.getDay() === 6) {
|
|
|
+ return 'weekend';
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ };
|
|
|
+ gantt.config.scales = [
|
|
|
+ { unit: 'month', step: 1, format: '%Y/%M',css:()=>'month' },
|
|
|
+ { unit: 'day', step: 1, date:'%d'+ ' 星期' + '%D',css: daysStyle }
|
|
|
+ ];
|
|
|
+ //这里在时间轴表格内的cell上添加class
|
|
|
+ gantt.templates.timeline_cell_class = function (item, date) {
|
|
|
+ if (date.getDay() == 0 || date.getDay() == 6) {
|
|
|
+ return 'weekend';
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 条形图里的文字
|
|
|
+ gantt.templates.task_text = function (start, end, task) {
|
|
|
+ return `<span gantt_task_content-id="${task.id}" style='text-align:left;color:#000;display:inline-block;'> ${task.title}:${task.name}</span>`;
|
|
|
+ };
|
|
|
+ // 条形图自定义class
|
|
|
+ gantt.templates.task_class = function (start, end, task) {
|
|
|
+ return `task-222`;
|
|
|
+ };
|
|
|
+
|
|
|
+ gantt.config.scale_height = 60;
|
|
|
+ gantt.config.task_height = 30;
|
|
|
+ gantt.config.row_height = 30;
|
|
|
+ gantt.config.min_column_width = 25;
|
|
|
+ gantt.config.show_task_cells = false;
|
|
|
+ gantt.plugins({
|
|
|
+ marker: true
|
|
|
+ });
|
|
|
+ let today = new Date();
|
|
|
+ gantt.addMarker({
|
|
|
+ start_date: today,
|
|
|
+ css: 'today',
|
|
|
+ text: ''
|
|
|
+ });
|
|
|
+ gantt.plugins({
|
|
|
+ tooltip: true
|
|
|
+ });
|
|
|
+ // 自定义tooltip内容
|
|
|
+ gantt.templates.tooltip_text = function (start, end, task) {
|
|
|
+ const t = gantt;
|
|
|
+ return `<div style="font-size:14px;padding: 0 10px;width:250px;line-height:20px;white-space:normal;">
|
|
|
+ <p style="font-weight:bold;margin: 8px 0;">${task.text}</p>
|
|
|
+
|
|
|
+ </div>`;
|
|
|
+ };
|
|
|
+ gantt.attachEvent('onTaskClick', function (id, e) {
|
|
|
+ let box = document.querySelector('.gantt_tooltip');
|
|
|
+ if (box) {
|
|
|
+ box.parentNode.removeChild(box);
|
|
|
+ }
|
|
|
+ let classList = e.target.className.split(' ');
|
|
|
+ // 这里自定义了展开/收起树形的点击事件
|
|
|
+ if (classList.includes('gantt_open')) {
|
|
|
+ gantt.open(id); // 展开
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (classList.includes('gantt_close')) {
|
|
|
+ gantt.close(id); // 收起
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ // 这里是其他的点击事件
|
|
|
+ let task = _this.ganttData.find((item) => {
|
|
|
+ return item.id == id;
|
|
|
+ });
|
|
|
+ if (task.taskType === 'stage') {
|
|
|
+ // toDo()
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ gantt.i18n.setLocale('cn');
|
|
|
+
|
|
|
+ // 初始化gantt
|
|
|
+ gantt.init(this.$refs.gantt);
|
|
|
+ // 绑定数据
|
|
|
+ gantt.parse({
|
|
|
+ data: [], // 时间轴上横条的数据
|
|
|
+ link: [] // 连接线的数据
|
|
|
+ });
|
|
|
+ },
|
|
|
+ reload() {
|
|
|
+ console.log('重新渲染', this.ganttData);
|
|
|
+ gantt.clearAll(); // 从甘特图中删除所有任务和其他元素(包括标记)
|
|
|
+ this.ganttData = JSON.parse(JSON.stringify(this.ganttData));
|
|
|
+ gantt.parse({
|
|
|
+ data: this.ganttData,
|
|
|
+ link: []
|
|
|
+ }); // 数据解析
|
|
|
+ gantt.render(); // 呈现整个甘特图
|
|
|
+ },
|
|
|
+ getGanttData() {
|
|
|
+ // toDo
|
|
|
+ // formatGanttData()
|
|
|
+
|
|
|
+ this.ganttData = this.ganttTasks;
|
|
|
+ this.reload();
|
|
|
+ },
|
|
|
+ initData() {
|
|
|
+ this.ganttData = this.ganttTasks.map((current, ind, arry) => {
|
|
|
+ let newObj = {};
|
|
|
+
|
|
|
+ if (current.type == 1) {
|
|
|
+ newObj = Object.assign({}, current, {
|
|
|
+ color: '#02a7f0',
|
|
|
+ title: '计划'
|
|
|
+ });
|
|
|
+ } else if (current.type == 2) {
|
|
|
+ newObj = Object.assign({}, current, {
|
|
|
+ color: '#fec0dc',
|
|
|
+ title: '工序'
|
|
|
+ });
|
|
|
+ } else if (current.type == 3) {
|
|
|
+ newObj = Object.assign({}, current, {
|
|
|
+ color: '#62ddd4',
|
|
|
+ title: '工位'
|
|
|
+ });
|
|
|
+ } else if (current.type == 4) {
|
|
|
+ //计划节点
|
|
|
+ newObj = Object.assign({}, current, {
|
|
|
+ color: '#d1a6ff',
|
|
|
+ title: '计划节点'
|
|
|
+ });
|
|
|
+ } else if (current.type == 5) {
|
|
|
+ //任务
|
|
|
+ newObj = Object.assign({}, current, {
|
|
|
+ color: '#0e85fa',
|
|
|
+ title: '任务'
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ //默认色
|
|
|
+ newObj = Object.assign({}, current, {
|
|
|
+ color: '#62ddd4',
|
|
|
+ title: '计划'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return newObj;
|
|
|
+ });
|
|
|
+ this.$nextTick(() => {
|
|
|
+ let addTop = 0;
|
|
|
+ this.ganttTasks.forEach((item, index) => {
|
|
|
+ let taskElement = document.querySelector(
|
|
|
+ `[data-task-id="${item.id}"]`
|
|
|
+ );
|
|
|
+ let taskLine = document.querySelector(
|
|
|
+ `.gantt_task_line[data-task-id="${item.id}"]`
|
|
|
+ );
|
|
|
+ let taskContent = document.querySelector(
|
|
|
+ `[gantt_task_content-id="${item.id}"]`
|
|
|
+ );
|
|
|
+ if (taskElement) {
|
|
|
+ if (index != 0) {
|
|
|
+ taskElement.style.top =
|
|
|
+ parseInt(taskElement.style.top) + addTop + 'px';
|
|
|
+ if (item.type == 1) {
|
|
|
+ addTop += 15;
|
|
|
+ taskElement.style.height = '40px';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (taskLine) {
|
|
|
+ if (index != 0) {
|
|
|
+ if (item.type != 1) {
|
|
|
+ taskLine.style.top = parseInt(taskLine.style.top) - 2 + 'px';
|
|
|
+ } else {
|
|
|
+ taskLine.style.top =
|
|
|
+ parseInt(taskLine.style.top) + addTop - 2 + 'px';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ taskLine.style.top = 0 + 'px';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (taskContent) {
|
|
|
+ console.log(taskContent.style)
|
|
|
+ // taskContent.parentNode.style.left = -taskContent.clientWidth+ 'px';
|
|
|
+ // taskContent.parentNode.style.textAlign = 'left'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ this.reload();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ activated() {
|
|
|
+ console.log(gantt, i++);
|
|
|
+ gantt.render(); // 呈现整个甘特图
|
|
|
+ }
|
|
|
+ };
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+ .gantt-box {
|
|
|
+ width: calc(100%);
|
|
|
+ height: calc(100%);
|
|
|
+ }
|
|
|
+ .gantt-container {
|
|
|
+ width: calc(100%);
|
|
|
+ height: calc(100%);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 周末高亮 */
|
|
|
+ :deep(.weekend) {
|
|
|
+ background: #f8f8f8;
|
|
|
+ color: #676767 !important;
|
|
|
+ // height: 47px!important;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 今日高亮 */
|
|
|
+ :deep(.gantt_task_scale) {
|
|
|
+ .gantt_scale_line > .gantt_scale_cell {
|
|
|
+ color: #333333;
|
|
|
+
|
|
|
+ &.today {
|
|
|
+ background: #72b9ff;
|
|
|
+ color: #ffffff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 去掉文件夹图标 */
|
|
|
+ :deep(.gantt_tree_icon) {
|
|
|
+ &.gantt_folder_closed,
|
|
|
+ &.gantt_file,
|
|
|
+ &.gantt_folder_open {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 把展开收起图标替换成element-ui的icon */
|
|
|
+ /* 这里没有找到在js中配置图标的方法,为省事,使用css */
|
|
|
+ /* 扒了element-ui的icon样式表 */
|
|
|
+ :deep(.gantt_tree_icon.gantt_open) {
|
|
|
+ background-image: none;
|
|
|
+ font-family: element-icons !important;
|
|
|
+ speak: none;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ font-variant: normal;
|
|
|
+ text-transform: none;
|
|
|
+ vertical-align: baseline;
|
|
|
+ display: inline-block;
|
|
|
+ -webkit-font-smoothing: antialiased;
|
|
|
+ -moz-osx-font-smoothing: grayscale;
|
|
|
+ &::before {
|
|
|
+ content: '\e6df';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ :deep(.gantt_tree_icon.gantt_close) {
|
|
|
+ background-image: none;
|
|
|
+ font-family: element-icons !important;
|
|
|
+ speak: none;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ font-variant: normal;
|
|
|
+ text-transform: none;
|
|
|
+ vertical-align: baseline;
|
|
|
+ display: inline-block;
|
|
|
+ -webkit-font-smoothing: antialiased;
|
|
|
+ -moz-osx-font-smoothing: grayscale;
|
|
|
+ &::before {
|
|
|
+ content: '\e6e1';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ :deep(.gantt_cell) {
|
|
|
+ border-right: 1px solid #ebebeb;
|
|
|
+ }
|
|
|
+ :deep(.task-222) {
|
|
|
+ height: 30px !important;
|
|
|
+ // top: 0px !important;
|
|
|
+ line-height: 30px !important;
|
|
|
+ border: none !important;
|
|
|
+ }
|
|
|
+ :deep(.gantt_split_parent) {
|
|
|
+ opacity: 0;
|
|
|
+ }
|
|
|
+ :deep(.gantt_task_content) {
|
|
|
+ width: auto;
|
|
|
+ }
|
|
|
+ :deep(.gantt_task_row){
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+ :deep(.month){
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+</style>
|