甘特图实现代码
<template>
<div class="box">
<!-- 头部筛选框 -->
<div class="boxTitle">
<div></div>
<div></div>
<div class="plantSelect">
<c-date-picker
style="width:120px"
@change="getCalendarData"
v-model="data.year"
format='yyyy' value-format='yyyy'
type="year">
</c-date-picker>
<div class="kong"></div>
<c-select style="width:180px" v-model="data.workshop" @change="getCalendarData" multiple>
<c-option key="ASSEMBLY" value="ASSEMBLY" label='Assembly' ></c-option>
<c-option key="BIW" label='BIW' value="BIW" ></c-option>
</c-select>
<div class="kong"></div>
<c-select style="width:220px" v-model="data.plant" @change="getCalendarData" multiple>
<c-option
v-for="plant in plantList"
:key="plant"
:value="plant"
></c-option>
</c-select>
</div>
</div>
<!-- 月份信息 -->
<div class='gantt-title'>
<div class="project-title">Project</div>
<div class="header">
<div class="month" v-for="(month,index) in months" :key="index">{{ month }}</div>
</div>
</div>
<!-- 甘特图实现 -->
<div class="gantt-chart">
<div class="project">
<div class="project-item" v-for="(item) in projectList" :key="item">{{item}}</div>
</div>
<div class="gantt">
<div class="chart-container-box">
<div v-for="(item, index) in bars" :key="index" class="chart-container">
<div class="gantt-item" v-for="(item,index) in months" :key='item+index'>
</div>
<div
class="bar"
v-for="(bar, index) in item"
:key="bar.buildPhase+index+bar.type"
>
<div
v-if="bar.type === '0'"
class="bar"
:style="{
left: `${getleft(bar.start)}px`,
width: `${getwidth(bar.start,bar.end)}px`,
}">
<span class="context">
<span class="buildPhase">{{bar.buildPhase}}</span>
<span class="time">{{getShowTime(bar.start)+' - '+getShowTime(bar.end)}}</span>
</span>
</div>
<div
v-if="bar.type === '1'"
class="dropbar"
:style="{
left: `${getleft(bar.start)}px`,
}">
<div class="drop"></div>
<span class="buildPhase">{{bar.buildPhase}}</span>
<span class="time">{{getShowTime(bar.start)}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from 'moment';
import { removeDecimalH } from '@/utils/utils.js';//处理小数点方法
export default {
data() {
return {
months: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
],
bars: [],
projectList:[],
barWidth: 0, // 根据需要调整条形的宽度
data:{
plant: ["33","44"],
workshop: ["22","11"],
year: "2023"
},
plantList: ['aa', 'bb', 'cc'],
};
},
created(){
this.getCalendarData();
},
mounted() {
//获取div宽度信息
const header = this.$el.querySelector('.header');
//计算每个格子的宽度
this.barWidth = removeDecimalH(header.offsetWidth/this.months.length)
//避免误差 重新设置宽度
header.style.width = header.offsetWidth + 'px'; // 设置容器宽度为总宽度
const chartContainer = this.$el.querySelector('.chart-container-box');
console.log(header.offsetWidth + 'px')
//设置甘特图div总体宽度
chartContainer.style.width = `${header.offsetWidth}px`; // 设置容器宽度为总宽度
},
methods: {
getCalendarData: _.debounce(function() {
//获取数据
}, 300),
//获取元素位置
getleft(start) {
let left = 0;
const date = moment(start);
const month = date.month();
const day = date.date();
const daysInMonth = date.endOf("month").format("DD")
left = removeDecimalH(month * this.barWidth+(day/daysInMonth*this.barWidth));
return left;
},
//转换日期
getShowTime(time){
const date = moment(time);
return date.format("MM/DD")
},
//获取元素宽度
getwidth(start, end) {
let width = 0;
let startwidth = 0;
let endwidth = 0;
const startdate = moment(start);
const enddata = moment(end);
const startmonth = startdate.month();
const endmonth = enddata.month();
const startday = startdate.date();
const endday = enddata.date();
const startdaysInMonth = startdate.endOf("month").format("DD")
const enddaysInMonth = enddata.endOf("month").format("DD")
if(endmonth - startmonth >=2){
width = parseInt(removeDecimalH((endmonth - startmonth -2) *this.barWidth))
startwidth = parseInt(removeDecimalH((1-startday/startdaysInMonth)*this.barWidth));
endwidth = parseInt(removeDecimalH((endday/enddaysInMonth)*this.barWidth));
}else if(endmonth - startmonth === 1){
startwidth = parseInt(removeDecimalH((1-startday/startdaysInMonth)*this.barWidth));
endwidth = parseInt(removeDecimalH((endday/enddaysInMonth)*this.barWidth));
}else if(endmonth - startmonth === 0){
let day = endday - startday;
width = parseInt(removeDecimalH(day*(this.barWidth/startdaysInMonth)));
}
return width+startwidth+endwidth
}
}
};
</script>
<style lang="scss" scoped>
$header-height: 50px;
$item-height:50px;
$gantt-item-height:51px;
$bar-height:30px;
$back-color: #F7F9FC;
$border-color:#DBE2F6;
$bar-back-color:#D1E6FD;
.box{
border-radius: 12px;
height: 616px;
background-color: $back-color;
}
.boxTitle{
border-top-right-radius: 12px;
border-top-left-radius: 12px;
height: 60px;
background-color: $back-color;
display: flex;
justify-content: space-between;
>:nth-child(1){
flex: 0 0 550px;
}
>:nth-child(2){
flex: 1;
}
.plantSelect{
flex: 0 0 550px;
display: flex;
padding: 10px;
.kong{
width: 10px;
}
}
}
.gantt-title{
display: flex !important;
justify-content: space-between;
align-items: flex-start;
height: $gantt-item-height;
}
.gantt-chart {
display: flex !important;
justify-content: space-between;
align-items: flex-start;
width: 100%; /* 根据需要调整甘特图的宽度 */
width: calc(100% - 8px);
height: calc(100% - 110px);
overflow-y: auto;
padding-right: 8px;
overflow-x: clip;
border-bottom-right-radius: 12px;
border-bottom-left-radius: 12px;
}
.project{
flex: 0 0 180px;
}
.project-title{
flex: 0 0 180px;
background-color: $back-color;
text-align: center;
line-height: $header-height;
height: $header-height; /* 根据需要调整头部的height */
border-bottom: 1px $border-color solid;
}
.project-item{
background-color: $back-color;
text-align: center;
line-height: $item-height;
height: $item-height; /* 根据需要调整头部的height */
border-bottom: 1px $border-color solid;
border-right: 1px $border-color solid;
}
.gantt{
flex: 1;
}
.header {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
height: $header-height; /* 根据需要调整头部的height */
background-color: $back-color; /* 根据需要调整头部的背景色 */
border-bottom: 1px $border-color solid;
}
.month {
font-weight: bold;
/* margin-right: 10px; 根据需要调整月份标签的间距 */
flex: 1;
text-align: center;
}
.chart-container {
position: relative;
width: 100%;
display: flex;
align-items: flex-start;
height: $gantt-item-height; /* 根据需要调整条形的container高度 */
background-color: $back-color; /* 根据需要调整条形的container背景色 */
}
.gantt-item{
background-color: $back-color;
height: $item-height; /* 根据需要调整头部的height */
border-bottom: 1px $border-color solid;
border-right: 1px $border-color solid;
flex: 1;
}
.bar {
top: 5px;
display: flex; /* 使条形可伸缩 */
align-items: center; /* 使条形内的文本垂直居中 */
height: $bar-height; /* 根据需要调整条形的height */
background-color: $bar-back-color; /* 根据需要调整条形的背景色 */
border-radius: 10px; /* 根据需要调整条形的圆角 */
position: absolute;
}
.dropbar{
top: 5px;
display: flex; /* 使条形可伸缩 */
align-items: center; /* 使条形内的文本垂直居中 */
height: $bar-height; /* 根据需要调整条形的height */
border-radius: 10px; /* 根据需要调整条形的圆角 */
position: absolute;
.drop{
height: 26px;
width: 26px;
background-image: url('~@/assets/images/diamond.png');
background-repeat: no-repeat;
background-size: 100% 100%;
}
}
.buildPhase{
font-weight: bold;
padding: 0px 2px;
}
.context{
white-space: nowrap;
}
</style>
原创代码,转发请注明出处