如何去实现一个简易版的甘特图,下面是相关代码,也需要下载依赖有 Element UI和 dayjs
<template>
<basic-container>
<div class="gant-content">
<th-page-button-group
class="button-group"
style="width:100%"
v-if="!isPrint"
>
<el-date-picker
v-model="currentTime"
type="month"
placeholder="选择月"
@change="changeMonth"
:clearable="false"
style="float:right"
>
</el-date-picker>
</th-page-button-group>
<div :class="`plan-item plan-item-0`">
<el-table
:class="`table-0`"
:data="planList"
v-loading="loading"
:header-cell-style="{textAlign: 'center', background:'#00aa94 !important', color: '#fff !important'}"
height="100%"
>
<el-table-column
type="index"
align="center"
width="40"
label="序号"
>
</el-table-column>
<el-table-column
align="center"
prop="serial"
label="编号"
width="120"
>
</el-table-column>
<el-table-column
align="center"
width="120"
prop="equipment"
label="设备"
class-name="equip"
>
</el-table-column>
<el-table-column
align="center"
prop="planStartTime"
label="开始时间"
width="100"
>
</el-table-column>
<el-table-column
align="center"
width="100"
prop="planEndTime"
label="结束时间"
>
</el-table-column>
<el-table-column
align="center"
prop="jobContent"
width="120"
label="工作内容"
>
</el-table-column>
<el-table-column
align="center"
prop="date"
:label="currentTimes"
>
<el-table-column
v-for="(col, day) in days"
:key="day"
align="center"
class-name="gantt-item"
:label="`${day + 1}`"
width="32"
>
<template slot-scope="scope">
<div
id="yidongdiv"
:class="hasTime(scope.row) ? 'hasTime' : ''"
:style="{background: checkBg(scope.row, day + 1)}"
>
<span :class="day == 0 ? 'first-span' : ''">{{showText(scope.row, day + 1)}}</span>
</div>
</template>
</el-table-column>
</el-table-column>
</el-table>
</div>
<!--endprint-->
</div>
</basic-container>
</template>
<script>
import { getGtViewInfoByDate } from '@/api/chart.js'
export default {
name: 'gantt',
data () {
return {
days: [],
planList: [],
currentTime: new Date().toString(),
currentTimes: "",
propsData: {
planCategory: '',
type: '',
month: "",
year: ''
},
isPrint: false,
loading: true
};
},
created () {
this.changeMonth()
// this.fetchData();
},
methods: {
//页面渲染天数
getDates () {
this.days = []
for (let i = 0; i < this.getCountDays(this.currentTime); i++) {
this.days.push(i);
}
},
//选择月份发送请求
changeMonth () {
this.loading = true
this.currentTimes = this.dayjs(new Date(this.currentTime)).format('YYYY-MM')
this.getDates()
this.getGtViewInfo()
},
//获取每月有多少天
getCountDays (time) {
return this.dayjs(time).daysInMonth()
},
//发送请求获取数据
async getGtViewInfo () {
const { data } = await getGtViewInfoByDate({ currentTime: this.currentTimes })
if (data.code == 0) {
this.planList = data.data
}
this.loading = false
},
//背景色
checkBg (data, day) {
let { year, month } = this.propsData;
month = new Date(this.currentTime).getMonth() + 1
year = new Date(this.currentTime).getFullYear()
let currentData = this.dayjs(`${ year }-${ month }-${ day }`).valueOf();
let startData = this.dayjs(data.planStartTime.substring(0, 10)).valueOf();
let endData = this.dayjs(data.planEndTime.substring(0, 10)).valueOf();
if (currentData >= startData && currentData <= endData) {
return '#00CCFF'
}
},
showText (data, day) {
let { year, month } = this.propsData;
month = new Date(this.currentTime).getMonth() + 1
year = new Date(this.currentTime).getFullYear()
let currentData = this.dayjs(`${ year }-${ month }-${ day }`).valueOf();
if (day == 1) {
if (currentData > this.dayjs(data.planStartTime.substring(0, 10)).valueOf()) {
return data.planStartTime.substring(0, 10);
}
} else if (day == this.days.length) {
if (currentData < this.dayjs(data.planEndTime.substring(0, 10)).valueOf()) {
return data.planEndTime.substring(0, 10);
}
}
},
hasTime (data) {
let { year, month } = this.propsData;
let startData = this.dayjs(data.planStartTime.substring(0, 10)).valueOf();
let endData = this.dayjs(data.planEndTime.substring(0, 10)).valueOf();
let yearStartData = this.dayjs(`${ year }-${ month }-${ 1 }`).valueOf();
let yearEndData = this.dayjs(`${ year }-${ month }-${ this.days.length }`).valueOf();
return startData < yearStartData || endData > yearEndData;
}
}
};
</script>
<style scoped lang="scss">
.gant-content {
padding-bottom: 20px;
height: 100%;
}
/deep/ .el-table td,
.el-table th {
padding: 8px 0;
min-height: 32px;
}
.gant-title {
width: 1484px;
border-bottom: 1px solid #ebeef5;
text-align: center;
line-height: 40px;
font-weight: bold;
background: #f3f4f7;
color: #000;
}
/deep/ .el-table--border td {
border-color: #e3e3e3;
}
/deep/ .el-table__header-wrapper {
display: none;
}
/deep/ .table-0 .el-table__header-wrapper {
display: block;
}
.plan-item {
// box-sizing: border-box;
width: 100%;
height: calc(100% - 50px);
position: relative;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
.plan-name {
height: 100%;
width: 100px;
font-weight: bold;
display: flex;
.plan-text {
padding: 0 10px;
font-size: 13px;
text-align: center;
color: #000;
flex: 1;
}
}
&.plan-item-0 {
.plan-text {
transform: translateY(33px);
}
}
}
/deep/ .el-table {
border-left: 1px solid #ebeef5;
.el-table__row:last-child td {
border-bottom: none;
}
&::before {
height: 0;
}
.cell {
padding: 0 !important;
font-size: 12px;
}
.equip .cell {
padding: 0 10px !important;
}
th {
padding: 4px 0;
}
.gantt-item {
position: relative;
}
}
/deep/ .el-table--border,
.el-table--group {
border-bottom: none;
border-top: none;
}
.plan-title {
height: 65px;
line-height: 65px;
font-weight: bold;
text-align: center;
color: #000;
background: rgb(243, 244, 247) !important;
position: absolute;
top: 0;
font-size: 12px;
width: 100px;
border-bottom: 1px solid #ebeef5;
}
#yidongdiv {
width: 100%;
color: #000;
line-height: 18px;
min-height: 18px;
font-size: 10px;
span {
position: absolute;
left: -40px;
top: 50%;
transform: translateY(-10px);
display: inline-block;
z-index: 5;
&.first-span {
left: unset;
right: -40px;
}
}
}
.el-date-editor {
margin-bottom: 10px;
}
</style>