<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: 100%; font-size: 12px"></div>
|
</div>
|
</template>
|
|
<script>
|
import axios from "axios";
|
import { gantt } from "dhtmlx-gantt";
|
import "dhtmlx-gantt/codebase/dhtmlxgantt.css";
|
import { HomeAPI } from "@/api/home";
|
|
export default {
|
name: "Gantt",
|
components: {},
|
props: {
|
selectedId: {
|
type: String,
|
default: "",
|
},
|
},
|
data() {
|
return {
|
taskslist: [],
|
// 甘特图配置
|
tasks: {
|
data: [],
|
},
|
columnsShow: false,
|
};
|
},
|
watch: {
|
selectedId: {
|
handler(newVal) {
|
console.log("甘特图接收到的数据:", newVal);
|
// 处理数据变化的逻辑
|
this.getProjectqryDataColl(newVal);
|
},
|
deep: true, // 深度监听对象内部变化
|
immediate: true, // 立即执行一次
|
},
|
},
|
mounted() {
|
this.init(); //初始化
|
},
|
methods: {
|
formatDateTime(date = new Date()) {
|
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} ${hours}:${minutes}:${seconds}`;
|
},
|
// 获取两个时间相减的天数
|
getDays(strDateStart, strDateEnd) {
|
var strDateS = new Date(strDateStart);
|
var strDateE = new Date(strDateEnd);
|
var iDays = parseInt(Math.abs(strDateS.getTime() - strDateE.getTime()) / 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)); // 将时间差转换为天数
|
},
|
clickdataAll() {
|
let clickdata = [];
|
let colors = "";
|
this.taskslist.map((item) => {
|
var arr = item.PlanBegin.split(" ")[0].split("-");
|
var arr1 = item.PlanEnd.split(" ")[0].split("-");
|
var startTime = arr[2] + "-" + arr[1] + "-" + arr[0];
|
var endTime = arr1[2] + "-" + arr1[1] + "-" + arr1[0];
|
var startTime1 = item.RealBegin;
|
var endTime1 = item.RealEnd;
|
var duration1 = "";
|
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.TaskName,
|
start_date: startTime,
|
end_date: endTime,
|
parent: item.ParentId,
|
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.ParentId) {
|
item.used = true;
|
item.baseTitle = "[" + item.TaskName + "]";
|
baseList.push(item);
|
}
|
});
|
baseList.map((item) => {
|
this.taskslist.map((item2) => {
|
if (!item2.used && item2.ParentId == item.Id) {
|
item2.used = true;
|
item2.baseTitle = item.baseTitle + "->[" + item2.TaskName + "]";
|
baseList2.push(item2);
|
}
|
});
|
});
|
|
baseList2.map((item) => {
|
this.taskslist.map((item2) => {
|
if (!item2.used && item2.ParentId == item.Id) {
|
item2.used = true;
|
item2.baseTitle = item.baseTitle + "->[" + item2.TaskName + "]";
|
baseList3.push(item2);
|
}
|
});
|
});
|
|
baseList3.map((item) => {
|
this.taskslist.map((item2) => {
|
if (!item2.used && item2.ParentId == item.Id) {
|
item2.used = true;
|
item2.baseTitle = item.baseTitle + "->[" + item2.TaskName + "]";
|
}
|
});
|
});
|
|
let copyTaskslist = [];
|
this.taskslist.map((item) => {
|
if (item.baseTitle) {
|
copyTaskslist.push(item);
|
}
|
});
|
this.taskslist = copyTaskslist;
|
},
|
/**
|
* 获取项目进度数据
|
*
|
* begin1 ---> PlanBegin
|
* over1 ---> PlanEnd
|
*
|
* begin2 ---> RealBegin
|
* over2 ---> RealEnd
|
*/
|
getProjectqryDataColl(bindId) {
|
const params = {
|
bindId,
|
};
|
HomeAPI.GetJSCProgress(params).then((res) => {
|
if (res.Ret === 1) {
|
const result = res.Data;
|
if (result.length > 0) {
|
this.taskslist = result;
|
this.clearDirtyData();
|
let cache = [];
|
|
this.taskslist.map((item, index) => {
|
item.zIndex = index + 1;
|
// 重新判断状态
|
let nowTime = this.formatDateTime();
|
if (!item.RealBegin) {
|
//未开始
|
item.zt = 0;
|
} else {
|
if (!item.RealEnd) {
|
//未结束
|
if (item.PlanEnd >= nowTime) {
|
//判断预计工期是否超过当前时间
|
item.zt = 1; //进行中
|
} else {
|
item.zt = 5; //延期未完工
|
}
|
} else {
|
if (item.PlanEnd >= item.RealEnd) {
|
//判断预计工期是否超过实际工期
|
item.zt = 3; //提前完工2、3
|
} else {
|
item.zt = 4; //延期完工
|
}
|
}
|
}
|
if (item.zt == "5") {
|
cache.push([cache.length + 1, item.TaskName, this.getIntervalDays(item.PlanEnd)]);
|
}
|
});
|
|
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);
|
} else {
|
gantt.clearAll();
|
}
|
}
|
});
|
},
|
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 {
|
height: calc(100% - 52px);
|
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>
|