<template>
|
<div class="gantt-box">
|
<div class="gantt-header">
|
<div>
|
<el-button size="small" type="primary" @click="yearClick">年</el-button>
|
<el-button size="small" type="primary" @click="monthClick">月</el-button>
|
<el-button size="small" type="primary" @click="weekClick">周</el-button>
|
<!-- <el-button size="small" type="primary" @click="dayClick">日</el-button> -->
|
</div>
|
<div>
|
<el-button style="margin-right: 20px" size="small" type="primary" v-if="!columnsShow" @click="toggle('1')">展开详情</el-button>
|
<el-button style="margin-right: 20px" size="small" type="primary" v-else @click="toggle('2')">关闭详情</el-button>
|
<span>备注:</span>
|
<span>进行中</span><span class="color" style="background-color: rgb(211, 211, 0)"></span>, <span>待进行</span
|
><span class="color" style="background-color: rgb(170, 170, 127)"></span>, <span>延期未完工</span
|
><span class="color" style="background-color: rgb(255, 0, 0)"></span>, <span>延期已完工</span
|
><span class="color" style="background-color: #8bc34a"></span>, <span>已完工/提前完工</span
|
><span class="color" style="background-color: rgb(14, 172, 81)"></span>
|
</div>
|
</div>
|
<div ref="gantt" style="height: 400px; font-size: 12px"></div>
|
</div>
|
</template>
|
|
<script>
|
import axios from "axios";
|
import { gantt } from "dhtmlx-gantt";
|
import "dhtmlx-gantt/codebase/dhtmlxgantt.css";
|
|
export default {
|
name: "Gantt",
|
components: {},
|
data() {
|
return {
|
taskslist: [],
|
// 甘特图配置
|
tasks: {
|
data: [],
|
},
|
columnsShow: false,
|
};
|
},
|
mounted() {
|
this.init(); //初始化
|
this.getProjectqryDataColl(); //获取数据
|
},
|
methods: {
|
// 将毫秒值转换为普通的日期格式 yyyy-MM-dd
|
formatDate(time) {
|
const myTime = new Date(time);
|
const yyyy = myTime.getFullYear();
|
let MM = myTime.getMonth() + 1;
|
if (MM < 10) {
|
MM = "0" + MM;
|
}
|
let dd = myTime.getDate();
|
if (dd < 10) {
|
dd = "0" + dd;
|
}
|
const str = yyyy + "-" + MM + "-" + dd;
|
return str;
|
},
|
// 获取两个时间相减的天数
|
getDays(strDateStart, strDateEnd) {
|
var strSeparator = "-";
|
//日期分隔符 var oDate1; var oDate2;
|
var iDays;
|
var oDate1 = strDateStart.split(strSeparator);
|
var oDate2 = strDateEnd.split(strSeparator);
|
var strDateS = new Date(oDate1[0], oDate1[1] - 1, oDate1[2]);
|
var strDateE = new Date(oDate2[0], oDate2[1] - 1, oDate2[2]);
|
var iDays = parseInt(Math.abs(strDateS - strDateE) / 1000 / 60 / 60 / 24);
|
//把相差的毫秒数转换为天数
|
return iDays;
|
},
|
getIntervalDays(timestamp) {
|
const date1 = new Date();
|
const date2 = new Date(timestamp);
|
const diff = Math.abs(date2.getTime() - date1.getTime()); // 计算时间差(毫秒)
|
return Math.floor(diff / (1000 * 60 * 60 * 24)); // 将时间差转换为天数
|
},
|
// 计算时间进度
|
getIntervalDays2(timestamp1, timestamp2) {
|
const now = new Date();
|
const date1 = new Date(timestamp1);
|
const date2 = new Date(timestamp2);
|
const diff = Math.abs(date2.getTime() - date1.getTime()); // 计算时间差(毫秒)
|
const total = Math.floor(diff / (1000 * 60 * 60 * 24)); // 将时间差转换为天数
|
const diff2 = Math.abs(now.getTime() - date1.getTime()); // 计算时间差(毫秒)
|
const real = Math.floor(diff2 / (1000 * 60 * 60 * 24)); // 将时间差转换为天数
|
return Math.floor((real / total) * 100);
|
},
|
|
clickdataAll() {
|
let clickdata = [];
|
let colors = "";
|
this.taskslist.map((item) => {
|
var arr = this.formatDate(item.begin1).split("-");
|
var arr1 = this.formatDate(item.over1).split("-");
|
var startTime = arr[2] + "-" + arr[1] + "-" + arr[0];
|
var endTime = arr1[2] + "-" + arr1[1] + "-" + arr1[0];
|
|
var arr2 = [];
|
var arr3 = [];
|
var startTime1 = "";
|
var endTime1 = "";
|
var duration1 = "";
|
if (item.begin2 != null) {
|
startTime1 = this.formatDate(item.begin2);
|
}
|
if (item.over2 != null) {
|
endTime1 = this.formatDate(item.over2);
|
}
|
|
if (startTime1 != "" && endTime1 != "") {
|
duration1 = this.getDays(startTime1, endTime1);
|
}
|
if (item.zt == "0") {
|
colors = "#aaaa7f";
|
}
|
if (item.zt == "1") {
|
colors = "#d3d300";
|
}
|
if (item.zt == "2" || item.zt == "3") {
|
colors = "#0eac51";
|
}
|
if (item.zt == "5") {
|
colors = "#ff0000";
|
}
|
if (item.zt == "4") {
|
colors = "#8bc34a";
|
}
|
clickdata.push({
|
id: item.id,
|
text: item.project,
|
start_date: startTime,
|
end_date: endTime,
|
parent: item.parent,
|
duration: "4",
|
start_date1: startTime1,
|
end_date1: endTime1,
|
duration1: duration1,
|
progress: 0,
|
open: true,
|
color: colors,
|
remark: item.remark,
|
});
|
});
|
gantt.clearAll();
|
this.tasks.data = clickdata;
|
gantt.parse(this.tasks);
|
gantt.refreshData();
|
this.ganttLoading = false;
|
},
|
|
clearDirtyData() {
|
let baseList = [];
|
let baseList2 = [];
|
let baseList3 = [];
|
this.taskslist.map((item) => {
|
item.used = false;
|
item.baseTitle = "";
|
});
|
// 先筛选父级
|
this.taskslist.map((item) => {
|
if (!item.used && !item.parent) {
|
item.used = true;
|
item.baseTitle = "[" + item.project + "]";
|
baseList.push(item);
|
}
|
});
|
baseList.map((item) => {
|
this.taskslist.map((item2) => {
|
if (!item2.used && item2.parent == item.id) {
|
item2.used = true;
|
item2.baseTitle = item.baseTitle + "->[" + item2.project + "]";
|
baseList2.push(item2);
|
}
|
});
|
});
|
|
baseList2.map((item) => {
|
this.taskslist.map((item2) => {
|
if (!item2.used && item2.parent == item.id) {
|
item2.used = true;
|
item2.baseTitle = item.baseTitle + "->[" + item2.project + "]";
|
baseList3.push(item2);
|
}
|
});
|
});
|
|
baseList3.map((item) => {
|
this.taskslist.map((item2) => {
|
if (!item2.used && item2.parent == item.id) {
|
item2.used = true;
|
item2.baseTitle = item.baseTitle + "->[" + item2.project + "]";
|
}
|
});
|
});
|
|
let copyTaskslist = [];
|
this.taskslist.map((item) => {
|
if (item.baseTitle) {
|
copyTaskslist.push(item);
|
}
|
});
|
this.taskslist = copyTaskslist;
|
},
|
// 获取工程进度项目列表
|
getProjectqryDataColl() {
|
axios.get("https://api.zhihuibuild.com/zuul/zuul/jinchan-device/project/qryProjectProgress").then(({ data }) => {
|
// 接口获取data
|
if (data.code == "200") {
|
if (data.body.length != 0) {
|
this.taskslist = data.body;
|
this.clearDirtyData();
|
let cache = [];
|
|
this.taskslist.map((item, index) => {
|
item.zIndex = index + 1;
|
// 重新判断状态
|
let nowTime = new Date().getTime();
|
if (!item.begin2) {
|
//未开始
|
item.zt = 0;
|
} else {
|
if (!item.over2) {
|
//未结束
|
if (item.over1 >= nowTime) {
|
//判断预计工期是否超过当前时间
|
item.zt = 1; //进行中
|
} else {
|
item.zt = 5; //延期未完工
|
}
|
} else {
|
if (item.over1 >= item.over2) {
|
//判断预计工期是否超过实际工期
|
item.zt = 3; //提前完工2、3
|
} else {
|
item.zt = 4; //延期完工
|
}
|
}
|
}
|
if (item.zt == "5") {
|
cache.push([cache.length + 1, item.project, this.getIntervalDays(item.over1)]);
|
}
|
});
|
|
cache.sort(function (a, b) {
|
return b[2] - a[2];
|
});
|
cache.map((item, index) => {
|
item[0] = index + 1;
|
item[2] = item[2] + "天";
|
});
|
|
setTimeout(() => {
|
this.clickdataAll();
|
}, 1000);
|
}
|
}
|
});
|
},
|
yearClick() {
|
gantt.config.scales = [
|
{
|
unit: "year",
|
step: 1,
|
date: " %Y",
|
},
|
];
|
gantt.init(this.$refs.gantt);
|
},
|
monthClick() {
|
gantt.config.scales = [
|
{
|
unit: "year",
|
step: 1,
|
date: " %Y",
|
},
|
{
|
unit: "month",
|
step: 1,
|
date: "%F",
|
},
|
];
|
gantt.init(this.$refs.gantt);
|
},
|
weekClick() {
|
gantt.config.scales = [
|
{
|
unit: "year",
|
step: 1,
|
date: " %Y",
|
},
|
{
|
unit: "month",
|
step: 1,
|
date: "%F",
|
},
|
{
|
unit: "week",
|
step: 1,
|
date: "%W周",
|
},
|
];
|
gantt.init(this.$refs.gantt);
|
},
|
dayClick() {
|
gantt.config.scales = [
|
{
|
unit: "year",
|
step: 1,
|
date: " %Y",
|
},
|
{
|
unit: "month",
|
step: 1,
|
date: "%F",
|
},
|
{
|
unit: "day",
|
step: 1,
|
date: "%j日",
|
},
|
];
|
gantt.init(this.$refs.gantt);
|
},
|
riliClick() {
|
gantt.config.scales = [
|
{
|
unit: "month",
|
step: 1,
|
date: " %Y - %F",
|
},
|
{
|
unit: "day",
|
step: 1,
|
date: "%j日 周%D",
|
},
|
];
|
gantt.init(this.$refs.gantt);
|
},
|
toggle(val) {
|
if (val == 1) {
|
this.columnsShow = true;
|
} else {
|
this.columnsShow = false;
|
}
|
//左侧显示列名
|
if (val == "1") {
|
gantt.config.columns = [
|
{
|
name: "text",
|
label: "任务名称",
|
tree: true,
|
align: "left",
|
resize: true,
|
width: "*",
|
min_width: 220,
|
},
|
{
|
name: "start_date",
|
label: "计划开始",
|
align: "center",
|
resize: true,
|
width: "*",
|
min_width: 100,
|
},
|
{
|
name: "end_date",
|
label: "计划结束",
|
align: "center",
|
resize: true,
|
width: "*",
|
min_width: 100,
|
},
|
{
|
name: "duration",
|
label: "工期",
|
align: "center",
|
},
|
{
|
name: "start_date1",
|
label: "实际开始",
|
align: "center",
|
resize: true,
|
width: "*",
|
min_width: 100,
|
},
|
{
|
name: "end_date1",
|
label: "实际结束",
|
align: "center",
|
resize: true,
|
width: "*",
|
min_width: 100,
|
},
|
{
|
name: "duration1",
|
label: "实际工期",
|
align: "center",
|
},
|
{
|
name: "zt",
|
label: "",
|
align: "center",
|
resize: false,
|
},
|
];
|
} else {
|
gantt.config.columns = [
|
{
|
name: "text",
|
label: "任务名称",
|
tree: true,
|
align: "left",
|
resize: true,
|
width: 250,
|
},
|
];
|
}
|
|
// 初始化
|
gantt.init(this.$refs.gantt);
|
// 数据解析
|
gantt.parse(this.tasks);
|
},
|
// 初始化
|
init() {
|
// 自动延长时间刻度
|
gantt.config.fit_tasks = true;
|
gantt.config.show_links = false;
|
gantt.config.drag_progress = false; // 取消进度条
|
gantt.config.row_height = 25; //进度条容器高
|
gantt.config.scale_height = 50;
|
gantt.config.autofit = true; //左侧是否自适应
|
gantt.i18n.setLocale("cn"); // 设置中文
|
gantt.config.readonly = true; // 设置为只读
|
//自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
|
gantt.config.autosize = false;
|
gantt.config.open_split_tasks = true;
|
// 允许拖放
|
gantt.config.drag_project = true;
|
// 设置甘特图时间的起始结束时间,并允许显示超过时间刻度任务
|
// gantt.config.start_date = new Date(`${new Date().getFullYear()-1}`,'01');
|
// gantt.config.end_date = new Date(`${new Date().getFullYear()+1}`,'01');
|
gantt.config.show_tasks_outside_timescale = true;
|
//开启提示:鼠标悬浮在gantt行上显示
|
gantt.plugins({
|
tooltip: true,
|
// quick_info: true,// 快速信息框
|
multiselect: true, // 激活多任务选择
|
});
|
|
gantt.templates.tooltip_text = function (start, end, task) {
|
return (
|
"<b>项目: <span style='color:" +
|
task.color +
|
"'>" +
|
task.text +
|
"</span><br/><span>实际开始:" +
|
task.start_date1 +
|
"</span> " +
|
"</span><br/><span>实际结束:" +
|
task.end_date1 +
|
"</span> " +
|
"</span><br/><br/><span>计划开始:" +
|
gantt.templates.tooltip_date_format(start) +
|
"</span> " +
|
"<br/><span>计划结束:" +
|
gantt.templates.tooltip_date_format(end) +
|
"</span> " +
|
(task.remark ? `<br/><span>备注:${task.remark}</span>` : "")
|
);
|
};
|
// 按月
|
gantt.config.scales = [
|
{
|
unit: "year",
|
step: 1,
|
date: " %Y",
|
},
|
{
|
unit: "month",
|
step: 1,
|
date: "%F",
|
},
|
];
|
|
//左侧显示列名
|
gantt.config.columns = [
|
{
|
name: "text",
|
label: "任务名称",
|
tree: true,
|
align: "left",
|
resize: true,
|
width: 250,
|
},
|
];
|
// 初始化
|
gantt.init(this.$refs.gantt);
|
|
// 数据解析
|
gantt.parse(this.tasks);
|
},
|
},
|
};
|
</script>
|
<style lang="scss" scoped>
|
.gantt-box {
|
background-color: rgba(0, 0, 0, 0.2);
|
margin: 10px;
|
color: #fff;
|
|
.gantt-header {
|
padding-top: 5px;
|
margin: 10px;
|
height: 40px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.color {
|
width: 36px;
|
height: 16px;
|
vertical-align: text-top;
|
display: inline-block;
|
margin-right: 5px;
|
margin-left: 5px;
|
}
|
}
|
|
/* 滚动条样式*/
|
::-webkit-scrollbar {
|
width: 10px;
|
height: 10px;
|
background-color: transparent;
|
}
|
|
::-webkit-scrollbar-thumb {
|
background-color: #73abb1;
|
border-radius: 6px;
|
}
|
|
::-webkit-scrollbar-track {
|
background-color: #373f4a;
|
opacity: 0.9;
|
}
|
}
|
</style>
|
<style lang="scss">
|
body {
|
background-color: rgb(19, 90, 144);
|
}
|
|
/* 自定义甘特图样式 */
|
.gantt_grid_data .gantt_row.gantt_selected,
|
.gantt_grid_data .gantt_row.odd.gantt_selected,
|
.gantt_task_row.gantt_selected {
|
background-color: #409eff !important;
|
}
|
|
.gantt_grid_data .gantt_row.odd:hover,
|
.gantt_grid_data .gantt_row:hover {
|
background-color: #409eff !important;
|
}
|
|
.gantt_grid_scale .gantt_grid_head_cell {
|
color: #fff !important;
|
}
|
|
.gantt_grid_scale,
|
.gantt_task_scale,
|
.gantt_task_vscroll {
|
background-color: transparent;
|
}
|
|
/* 大背景透明 */
|
.gantt_container {
|
background-color: transparent;
|
}
|
|
/* 左标题文字白色 */
|
.gantt_grid_data .gantt_cell {
|
color: #fff;
|
}
|
|
/* 顶部日期白色 */
|
.gantt_task .gantt_task_scale .gantt_scale_cell {
|
color: #fff;
|
}
|
|
/* 偶数行背景透明 */
|
.gantt_row.odd,
|
.gantt_task_row.odd {
|
background-color: transparent;
|
}
|
|
/* 奇数行背景透明 */
|
.gantt_row,
|
.gantt_task_row {
|
background-color: transparent;
|
}
|
|
/* 表格边框*/
|
.gantt_cell {
|
border-right: 1px solid #0de8ec;
|
}
|
.gantt_task_cell {
|
border-right: 1px solid #0de8ec;
|
}
|
|
.gantt_row,
|
.gantt_task_row {
|
border-bottom: 1px solid #0de8ec;
|
}
|
|
.gantt_grid_scale,
|
.gantt_task_scale {
|
border-bottom: 1px solid #0de8ec;
|
}
|
|
.gantt_scale_line {
|
border-top: 1px solid #0de8ec;
|
}
|
|
.gantt_layout_cell_border_right {
|
border-right: 1px solid #0de8ec;
|
}
|
|
.gantt_layout_cell_border_bottom {
|
border-bottom: 1px solid #0de8ec;
|
}
|
|
.gantt_layout_cell_border_left {
|
border-left: 1px solid #0de8ec;
|
}
|
|
.gantt_layout_cell_border_top {
|
border-top: 1px solid #0de8ec;
|
}
|
|
.gantt_task_content {
|
text-shadow: 0 0 4px #333;
|
overflow: visible;
|
transform: translateY(-12px);
|
}
|
|
/* 进度条高度 */
|
.gantt_task_line {
|
height: 10px !important;
|
transform: translateY(10px);
|
}
|
|
.gantt_tooltip {
|
width: 180px;
|
}
|
</style>
|