//"dhtmlx-gantt": "^8.0.6",
index.vue
<template>
<div class="app-container">
<!-- <dragDemo/> -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="部门名称:">
<el-input
maxlength="20"
v-model="queryParams.deptName"
placeholder="请输入部门名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label-width="100px" label="创建时间:">
<el-date-picker v-model="queryParams.dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<Gtu ref="ganttChar" :tasks="tasks" @djsj="djsj"/>
<el-dialog title="详情" :visible.sync="showgtinfo" width="780px" append-to-body>
<el-form ref="form" :model="form" label-width="80px">
<el-row>
<el-col :span="12">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input v-model="form.text" placeholder="请输入公告标题" disabled/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import Gtu from "./common/gtu.vue";
import dragDemo from "../../../views/des/dragDemo/index.vue";
export default {
name: "Company",
components: { Gtu,dragDemo},
data () {
return {
loading: true,
showgtinfo:false,
form:{},
// 显示搜索条件
showSearch: true,
// 查询参数
queryParams: {
deptName: undefined,
dateRange: undefined
},
tasks:{
data: [],
links: []
},
};
},
created () {
// this.getList();
},
mounted(){
this.getGanttTasks();
},
methods: {
getGanttTasks(){
// listGanttTaskList(this.queryParams).then(response =>{
// // status:"2", color: '#AC96FF',根据不同状态 显示不同颜色
this.tasks.data = [
{id:1, text:"工单1", start_date:"2023-12-20", end_date:"2024-12-23", status:"1", duration:18, progress:0.2, color: '#05B964'},
{id:2, text:"任务1-1", start_date:"2023-12-20", end_date:"2023-12-21", status:"2", duration:8, color: '#AC96FF',
progress:0.6, parent:1},
{id:3, text:"任务1-2", start_date:"2023-12-22",end_date:"2023-12-23", status:"2", duration:8, color: '#AC96FF',
progress:0.6, parent:1},
// type: "project", render:"split",
// {id: 17, text: "Stage #1", start_date: "2023-12-22 00:00",end_date:"2023-12-22 10:00", duration: 0, parent: "3", progress: 0, open: true},
// {id: 18, text: "Stage #2", start_date: "2023-12-23 00:00", duration: 2, parent: "3", progress: 0, open: true},
{id:4, text:"工单2", start_date:"2023-12-20", status:"4", duration:18, progress:0.2, color: '#05B964'},
{id:5, text:"任务2-1", start_date:"2023-12-20", status:"4", duration:4, color: 'red',
progress:0.6, parent:4},
{id:6, text:"任务2-2", start_date:"2023-12-21", status:"4", duration:6, color: '#AC96FF',
progress:0.6, parent:4},
];
this.tasks.links = [];
this.$refs.ganttChar.reload();
// });
},
//单击事件
djsj(taskId){
// this.tasks.data.map((item) => {
// if (item.id == taskId) {
// item.color="red"
// }
// })
// this.$refs.ganttChar.reload();
let obj=this.tasks.data.find(item=>item.id==taskId)
this.form=obj
console.log(this.form,"===========this.form=")
this.showgtinfo=true
},
//关闭详情
cancel(){
this.showgtinfo=false
},
/** 搜索按钮操作 */
handleQuery() {
this.getGanttTasks();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
}
};
</script>
common gtu.vue
<template>
<div class="container">
<div ref="gantt" class="gantt-container"/>
</div>
</template>
<script>
import { gantt } from 'dhtmlx-gantt';
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
import {parseTime} from "@/utils/ruoyi";
export default {
name: 'index',
data() {
return {
newObj: {},
input3:""
}
},
props: {
tasks: {
type: Object,
default () {
return {data: [], links: [
/* { id:1, source:1, target:2, type:1},
{ id:2, source:2, target:3, type:0} */
]}
}
},
optType: {
type: String,
default (){
return 'view'
}
},
ids: {
type: Array,
default (){
return []
}
}
},
created() {
},
mounted() {
// 初始化甘特图配置
this.initConfig();
gantt.plugins({
marker: true
});
// 甘特图初始化和导入数据
gantt.init(this.$refs.gantt);
gantt.parse(this.tasks);
},
methods: {
//
reload() {
gantt.clearAll();
this.addTodayLine();
gantt.parse(this.$props.tasks);
gantt.render();
},
addTodayLine() {
// 时间线
var date_to_str = gantt.date.date_to_str(gantt.config.task_date);
var today = new Date();
gantt.addMarker({
start_date: today,
css: "todaybjx",
text: "今天",
title: "今天: " + date_to_str(today)
});
},
// 初始化甘特图配置
initConfig() {
// 1 基础配置
// // 1.1 甘特图是否只读
// if(this.optType =='view'){
// gantt.config.readonly = false;
// }else{
// gantt.config.readonly = false;
// }
// 1.2 表格列设置
gantt.config.duration_unit="hour";
gantt.config.duration_step=8;
gantt.config.grid_width=400;
// var colHeader = '<div class="seachk"><input placeholder="请输入关键词搜索" v-model="input3" onblur="gantt.seach()"><i class="icon-search"></i></input></div>';
gantt.config.columns = [
// {name: "",label: colHeader,width:'400',align:"center",},
{name:"text", label:"生产工单", tree:true, width:'*' },
{name:"start_date",label:"工序",width:'*'},
{name:"start_date", label:"开始时间", width:'*' },
{name:"end_date", label:"结束时间", width:'*'},
// { name: 'statusName', label: '状态', min_width: 50, template: function(item) {
// let templateDiv = ''
// templateDiv = `<div class="${item.statusType === 'father' ? 'father-status-box' : 'child-status-box'} "><div class="status-box${item.status} status-box">${item.statusName}</div></div>`
// return templateDiv
// }
// }
];
// 1.3 设置中文
gantt.i18n.setLocale("cn");
// 1.4 鼠标悬浮框
gantt.plugins({tooltip: true});// 启用tooltip悬浮框
gantt.templates.tooltip_text = function(start, end, task) {
if(task.type=='project'){
return "<b style='text-align:left;'>生产工单:</b> " + task.text +" <span style='text-align:left;'>" +" 完成比例:"+ Math.round(task.progress * 100) + "% </span>";
}else{
return "<div> <div style='text-align:left;'>任务名称: " +task.text +"</div>"
+"<div style='text-align:left;'>" +"任务编号:"+ task.status + "</div>"
+"<div style='text-align:left;'>" +"任务状态:"+ task.status + "</div>"
+"<div style='text-align:left;'>" +"计划完工时间:"+ parseTime(task.start_date, '{y}-{m}-{d}') + "</div>"
+"<div style='text-align:left;'>" +"计划完工时间:"+ parseTime(task.end_date, '{y}-{m}-{d}') + "</div>";
}
};
// 设置任务条进度内容
gantt.templates.progress_text = function(start, end, task) {
return ''
}
// // 任务条显示内容
// gantt.templates.task_text = function(start, end, task) {
// return ''
// }
// 1.6 显示到任务条上的文本
gantt.templates.task_text = function (start, end, task) {
if(task.type=='project'){
// return "<b style='text-align:left;'>物料1:</b> " + task.text +" <span style='text-align:left;'>" +" 完成比例:"+ Math.round(task.progress * 100) + "% </span>";
return "";
}else{
// return "<span style='text-align:left;'>物料2:</span> 20/100 <span style='text-align:left;'>" +" 完成比例:"+ Math.round(task.progress * 100) + "% </span>";
return "<span style='text-align:center;'>物料2:" + " 20/100" +" </span>";
}
};
// 任务条上的文字大小 以及取消border自带样式,和任务状态的样式,动态添加标签
gantt.templates.task_class = function(start, end, item) {
let taskClass = ''
if (item.$level === 0) {//父级样式调整
if (item.status * 1 === 2 && new Date() < item.end_date) {
// 办理中
taskClass = 'firstLevelTask processing-progress-father'
} else if (item.status * 1 === 4 && new Date() < item.end_date) {
// 逾期
taskClass = 'firstLevelTask overdue-progress-father'
} else {
taskClass = 'firstLevelTask'
}
} else {//子级样式调整
if ((item.status * 1 === 0 || item.status * 1 === 1) && new Date() < item.end_date) {
taskClass = 'secondLevelTask processing-progress-son'
} else if (item.status * 1 === 4 && new Date() < item.end_date) {
taskClass = 'secondLevelTask overdue-progress-son'
} else {
taskClass = 'secondLevelTask'
}
}
return taskClass
}
// 滚动条的配置和设置左边树图的固定宽度
gantt.config.layout = {
css: 'gantt_container',
cols: [
{
width: 400,
min_width: 400,
rows: [{
view: 'grid',
scrollX: 'gridScroll',
scrollable: true,
scrollY: 'scrollVer'
},
{
view: 'scrollbar',
id: 'gridScroll',
group: 'horizontal'
}
]
},
{
resizer: true,
width: 1
},
{
rows: [{
view: 'timeline',
scrollX: 'scrollHor',
scrollY: 'scrollVer'
},
{
view: 'scrollbar',
id: 'scrollHor',
group: 'horizontal'
}
]
},
{
view: 'scrollbar',
id: 'scrollVer'
}
]
}
// 1.5 初始化的时候就展开树结构
gantt.config.open_tree_initially = true;
// 1.7 显示单元格
gantt.config.show_task_cells = true;
// 2 时间配置
// 2.1 时间坐标轴单位 minute/hour/day/week/quarter/month/year
// gantt.config.scale_unit = "hour";
// 2.2 日期格式
// gantt.config.date_scale = "%H";
// 2.3 时间坐标为月份的时候 先显示年份再月份
// gantt.config.subscales = [{unit: "month", step: 1, date: "%Y,%F"}];
var weekScaleTemplate = function (date) {
// var dateToStr = gantt.date.date_to_str("Y% %M %d" );
// var dateToStr = gantt.date.date_to_str("%d/%m/%Y" );
// var endDate = gantt.date.add(gantt.date.add(date, 1, "week"), -1, "day");
// return "dasdsad11" + dateToStr(date) + " - " + dateToStr(endDate);
// width: 200px;white-space: pre-wrap;;color: #262626;opacity: 0.7;line-height: 20px;font-size: 12px;padding: 6px 4px 12px 4px;border-bottom: 1px solid #e4e8ed;
return `
<div style="display: flex;align-items: center;justify-content: start;">
<div style="display: flex;align-items: center;justify-content: start;">
<div style="color:#4E5251;">生产任务:</div>
<div style="display: flex;align-items: center;justify-content: start;">
<div style="">
<span>计划</span>
<span style="height: 10px;background-color:#C6EBE0;margin-left: 5px;border-radius: 5px;width: 15px;display: inline-block;"></span>
</div>
<div style="">
<span style="margin-left: 10px;">实际</span>
<span style="height: 10px;background-color:#0BB57C;margin-left: 5px;border-radius: 5px;width: 15px;display: inline-block;"></span>
</div>
</div>
</div>
<div style="display: flex;align-items: center;justify-content: start;margin-left: 15px;">
<div style="color:#4E5251;">延迟:</div>
<div style="display: flex;align-items: center;justify-content: start;">
<div style="">
<span>开始延迟</span>
<span style="height: 10px;background-color:#F9AB1A;margin-left: 5px;border-radius: 5px;width: 10px;display: inline-block;"></span>
</div>
<div style="">
<span style="margin-left: 10px;">结束延迟</span>
<span style="height: 10px;background-color:#FD3D35;margin-left: 5px;border-radius: 5px;width: 10px;display: inline-block;"></span>
</div>
</div>
</div>
</div>
`
};
var dayTemplate = function(date){
var dateToStr = gantt.date.date_to_str("%Y/%m/%d");
// var weekDay = gantt.date.date_to_str("%D");
return dateToStr(date);
// return dateToStr(date) + "(" + weekDay(date) + ")";
};
var daysStyle = function(date){
// you can use gantt.isWorkTime(date)
// when gantt.config.work_time config is enabled
// In this sample it's not so we just check week days
if(date.getDay() === 0 || date.getDay() === 6){
return "weekend";
}
return "";
};
gantt.config.scales =[
{unit:"week", step:1,format: weekScaleTemplate},
{unit:"day", step:1,format: dayTemplate,css: daysStyle},
{unit:"hour", step:8,format: "%H:%i"}, //这里的step要根据当前的班次设置来。如果是三班倒则是8,如果是两班倒则是12。
]
gantt.config.start_date = new Date('2020-08-10');
// gantt.config.end_date = new Date('2030-12-30');
gantt.config.scale_height = 50;
// 2.4 定义从后端获取或发送到后端的日期数据解析格式
gantt.config.xml_date = "%Y-%m-%d %H:%i:%s";
// 3 拖动配置
// 3.1 自动调整类型,当存在子节点时自动升级为project
gantt.config.auto_types = false;
// 3.2 设置不可以拖动进度
gantt.config.drag_progress = false;
// 3.3 设置Task不可以拖动
gantt.config.drag_move = true;
// 3.4 设置不可以拖动关系
// gantt.config.drag_links = true;
// 3.5 设置不可拖动Task 大小
gantt.config.drag_resize = true;
// 3.6 单击显示添加详情
gantt.config.details_on_create = true;
// 3.7 双击显示明细
gantt.config.details_on_dblclick = false;
//时间范围自动适应
gantt.config.fit_tasks = true;
// 3.8 任务垂直拖动,同时保存树级位置,同级之间操作,可跨父级拖动
gantt.config.order_branch = true;
// 如果甘特图包括大量任务,重新排序可能会降低性能,可以考虑使用下面这种
// gantt.config.order_branch = "marker";
// 3.9 通过拖动进度按钮,改变任务进度
// gantt.config.drag_progress = true;
let t = this.$props.tasks;
let c = this.$props.ids;
gantt.attachEvent("onAfterTaskUpdate",function(id,obj){
debugger;
let tt = t.data.filter( item=> item.id == id);
tt=obj;
c.push(id);
});
// gantt.attachEvent("onTaskOpened", function(id, e) {
// alert("You've just clicked an item with id="+id);
// });
// gantt.attachEvent("onTaskClick", function (id,e) {
// alert(JSON.stringify(e))
// });
gantt.attachEvent("onAfterTaskDrag",function(id,mode,e){
if (e.target.className === 'gantt_task_content') {
const taskId = e.target.parentElement.dataset.taskId
// console.log(e,"=e.target.parentElement.dataset")
console.log(taskId,"=======拖动事件1")
// this.$emit("tdsj", taskId);
}
})
// // 拖动后触发事件
// document.addEventListener('mouseup', (e) => {
// if (e.target.className === 'gantt_task_content') {
// const taskId = e.target.parentElement.dataset.taskId
// // console.log(e,"=e.target.parentElement.dataset")
// this.$emit("tdsj", taskId);
// }
// })
// 给右边甘特图添加点击事件
document.addEventListener('click', (e) => {
if (e.target.className === 'gantt_task_content') {
const taskId = e.target.parentElement.dataset.taskId
this.$emit("djsj", taskId);
}
})
},
}
}
</script>
<style lang="scss">
// .firstLevelTask {
// border: none;
// .gantt_task_content {
// font-size: 12px;
// height: 16px;
// display: flex;
// align-items: center;
// }
// }
.firstLevelTask {
border: none;
.gantt_task_content {
font-size: 14px;
text-align: center;
}
}
.secondLevelTask {
border: none;
}
.container {
height: 500px;
width: 100%;
position: relative;
.gantt-container {
height: 100%!important;
}
.gantt_grid_head_cell {
padding-left: 20px;
text-align: left !important;
border-bottom: 0;
font-size: 14px!important;
font-weight: 500;
color: #000000!important;
height: 30px;
// border: 1px solid red;
display: flex;
align-items: center;
input{
border: 1px solid #EDEDED;
height: 25px;
line-height: 25px;
border-radius: 5px;
padding: 0px 5px;
outline: none; // 去除选中状态边框
background-color: rgba(0, 0, 0, 0);// 透明背景
font-size: 12px;
color: #999999 !important;
}
// input:focus{
// outline:1px solid #EDEDED;
// }
}
// .gantt_row_task {
// .gantt_cell_tree {
// padding-left: 20px;
// }
// }
.left-container {
height: 100%;
}
.parent {
.gantt_tree_icon {
&.gantt_folder_open {
background-image: none !important;
}
&.gantt_folder_closed{
background-image: none !important;
}
}
}
}
.left-container {
height: 100%;
}
.gantt_task_content {
text-align: left;
padding-left: 10px;
height: 15px;
line-height: 15px;
text-align: center;
}
.gantt_tree_icon.gantt_folder_open {
display: none !important;
}
.gantt_tree_icon.gantt_folder_closed {
display: none !important;
}
.gantt_tree_icon.gantt_file {
display: none !important;
}
.gantt_tree_icon.gantt_blank {
width: 3px!important;
}
.gantt_grid_head_start_date,.gantt_grid_head_end_date,.gantt_grid_head_duration {
padding-left: 6px !important;
}
.gantt_tree_icon.gantt_close {
// background-image: url(@/assets/images/close.svg)!important;
}
.gantt_tree_icon.gantt_open {
// background-image: url(@/assets/images/open.svg)!important;
}
.gantt_tree_content {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.secondLevelTask {
height: 15px !important;
margin-top: 10px;
border-radius: 10px;
min-width: 2.5px!important;
}
.firstLevelTask {
height: 15px !important;
margin-top: 8px;
border-radius: 15px;
min-width: 2.5px!important;
}
.todaybjx {
background: #0270E0!important;
width: 1px !important;
}
.gantt_task_row, .gantt_task_row.odd {
background: #f5f7fa!important;
// border-bottom: 0;
}
.gantt_task_cell {
border: 0;
// border-right: 1px solid #EBEDF0;
}
//左侧表头样式
.gantt_grid_scale {
width: 400px!important;
height: 60px!important;
display: flex;
padding: 13px;
// flex-wrap: wrap;
// padding: 10px 8px;
// border-bottom: 0;
}
.gantt_grid_scale, .gantt_row {
// border-bottom: 0;
}
.gantt_grid_data{
width: 400px!important;
}
.gantt_grid_data .gantt_row.gantt_selected, .gantt_grid_data .gantt_row.odd.gantt_selected, .gantt_grid_data .gantt_row.odd:hover, .gantt_grid_data .gantt_row:hover {
background: rgba(2,112,224,0.04)!important;
}
.gantt_row_project {
.gantt_cell_tree {
font-size: 16px!important;
color: #212b36!important;
}
.gantt_cell {
font-size: 12px;
font-weight: 400;
color: #999999;
}
}
.gantt_row_task {
.gantt_cell_tree {
font-size: 14px!important;
color: #262626!important;
}
.gantt_cell {
font-size: 12px;
font-weight: 400;
color: #999999;
}
}
.gridScroll_cell {
height: 0!important;
.gantt_layout_content {
height: 0!important;
.gantt_layout_cell {
height: 0!important;
}
}
}
.gantt_layout_cell_border_right {
// border-right: 0;
}
// .gantt_layout_cell_border_bottom {
// border-bottom: 0;
// // border-bottom: 1px solid #DCE1E6!important;
// }
// .gantt_layout_cell_border_top {
// border-top: 1px solid #DCE1E6!important;
// }
// .gantt_layout_cell_border_left {
// border-left: 1px solid #DCE1E6!important;
// }
// .container {
// border-bottom: 1px solid #DCE1E6!important;
// }
.gantt_grid_head_statusName {
padding-left: 7px!important;
}
.father-status-box {
.status-box2 {
color: #17a514;
background: #f0f9eb;
// border: 1px solid #e1f3d8;
}
.status-box3 {
color: #262626;
background: #EDEDED;
// border: 1px solid rgba(102,102,102,0.06);
}
.status-box4 {
font-size: 14px;
font-weight: 400;
text-align: left;
color: #E20000;
background: #feebeb;
// border: 1px solid rgba(226,0,0,0.06);
border-radius: 4px;
height: 24px;
line-height: 24px;
width: 46px;
text-align: center;
}
}
.child-status-box {
.status-box0 {
color: #17a514;
background: #f0f9eb;
// border: 1px solid #e1f3d8;
}
.status-box1 {
color: #F47D06;
background: #fef4eb;
// border: 1px solid rgba(244,125,6,0.06);
}
.status-box2 {
color: #262626;
background: #EDEDED;
// border: 1px solid rgba(102,102,102,0.06);
}
.status-box4 {
font-size: 14px;
font-weight: 400;
text-align: left;
color: #E20000;
background: #feebeb;
// border: 1px solid rgba(226,0,0,0.06);
border-radius: 4px;
height: 24px;
line-height: 24px;
width: 46px;
text-align: center;
}
}
.status-box {
font-size: 14px;
font-weight: 400;
border-radius: 4px;
height: 24px;
line-height: 24px;
text-align: center;
margin-top: 4px;
}
.gantt_task_progress {
border-radius: 10px;
}
.gantt_task_line.gantt_task_inline_color.processing-progress-father {
.gantt_task_progress {
background: #51A6FB!important;
opacity: 1!important;
border-radius: 10px;
}
}
.gantt_task_line.gantt_task_inline_color.processing-progress-son {
.gantt_task_progress {
background: #51A6FB!important;
opacity: 1!important;
border-radius: 10px;
}
}
// .gantt_task_line.gantt_task_inline_color {
// border: 0;
// }
// 右侧表头样式
.gantt_task .gantt_task_scale .gantt_scale_cell {
text-align: left;
padding-left: 10px;
height: 20px!important;
line-height: 20px!important;
// border-right: 1px solid #EBEDF0;
}
.gantt_task_scale {
// border-bottom: 0px solid #EBEDF0;
height: 60px!important;
}
.gantt_scale_line {
// border-top: 1px solid #EBEDF0;
height: 20px!important;
line-height: 20px!important;
}
// 提示框
.gantt_tooltip {
border-radius: 4px;
background-color: #595959;
color: #ffffff;
// border: 0;
}
.gantt_scale_cell {
color: #0270E0;
}
.chart-content-box {
// border-right: 1px solid #E4E8ED;
}
.gantt_task_row.gantt_selected .gantt_task_cell {
border-right-color: #E4E8ED;
}
// .gantt_grid_scale .gantt_grid_head_cell:last-child {
// border-right: 1px solid #E4E8ED!important;
// // border-bottom: 1px solid #E4E8ED!important;
// }
// .gantt_data_area {
// background: #F5F7FA;
// }
</style>