vue2.X 中使用 echarts5.4.0实现项目进度甘特图
效果图:
![vue2.X 中使用 echarts5.4.0实现项目进度甘特图_第1张图片](http://img.e-com-net.com/image/info8/03d90002a16a4323814428149414c19f.jpg)
左侧
都是名称
,上面
是时间
,当中的内容是日志内容
- 组件:
gantt.vue
<template>
<div id="main" style="width: 100%; height: 100%"></div>
</template>
<script>
import * as echarts from "echarts";
export default {
name: "Gantt",
props: {
baseDate: {
type: String,
default: "",
},
ganttData: {
type: Array,
default: () => [],
},
roomData: {
type: Array,
default: () => [],
},
},
data() {
return {
minHours: '08:00',
maxHours: '24:00',
};
},
created() {},
mounted() {
this.myEcharts();
},
watch: {
ganttData(newVal) {
this.myEcharts();
},
},
methods: {
getTimes() {
let baseDate = `${this.baseDate}`;
this.$http.post(`/sys/task/times`, {taskDate: baseDate}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.minHours = res.data.minTime
this.maxHours = res.data.maxTime
}).catch(() => {})
},
myEcharts() {
this.getTimes();
const container = document.getElementById("main");
this.$echarts.init(container).dispose();
var myChart = this.$echarts.init(container);
var colors= ['#8dddfa','#f98e72', '#f7b84f', '#a872f9', '#d6a9d1','#a7e56d', '#ff73c7', '#d6a9d1', '#b1e7fb', '#d3b3af', '#2859b1', '#1f6cb0']
var option = {
color: "#0A8BFF",
backgroundColor: "#fff",
title: {},
tooltip: {
trigger: "item",
show: true,
hideDelay: 100,
backgroundColor: "rgba(255,255,255,1)",
borderRadius: 5,
confine: true,
textStyle: {
color: "#000"
},
formatter: function (params) {
for(var i = 0; i < params.data.value.length; i++) {
var content = (
params.data.value[i].content +
"
" +
params.data.value[i].stime +
" - " +
params.data.value[i].etime
);
var tooltipHtml = ''+content+'
';
return tooltipHtml;
}
},
},
legend: {
top: "1%",
itemWidth: 16,
itemHeight: 16,
show: true,
textStyle: {
color: "rgba(0, 0, 0, 0.45)",
fontSize: 14,
},
},
grid: {
left: "2%",
right: "3%",
top: "10%",
bottom: "10%",
containLabel: true,
},
xAxis: {
type: "time",
position: "top",
minInterval: 3600 * 1000 ,
maxInterval: 3600 * 1000 ,
min: `${this.baseDate} ` + this.minHours,
max: `${this.baseDate} ` + this.maxHours,
axisLabel: {
showMaxLabel: true,
formatter: function (value, index) {
var data = new Date(value);
var hours = data.getHours();
var minutes = data.getMinutes();
if ((index !== 0 && hours === 0) || index === 25){
return "23:59"
} else {
if (minutes === 0) {
return hours + ":00";
} else {
return hours + ":" + minutes;
}
}
},
textStyle: {
color: "rgba(0,0,0,0.65)",
fontSize: 14,
},
},
axisLine: {
lineStyle: {
color: "#e5e5e5",
},
onZero: false,
},
splitLine: {
show: true,
lineStyle: {
type: "dashed",
},
},
},
yAxis: {
inverse: true,
type: "category",
axisTick:{
show: true
},
splitLine: {
"show": true
},
axisLine: {
show: true,
lineStyle: {
color: "#e5e5e5",
},
},
data: this.roomData,
axisLabel: {
textStyle: {
color: "rgba(0, 0, 0, 0.65)",
fontSize: 14,
},
},
},
series: [
{
type: "custom",
clickable: false,
renderItem: function (params, api) {
var categoryIndex = api.value(0).index;
var start = api.coord([api.value(0).startTime, categoryIndex]);
var end = api.coord([api.value(0).endTime, categoryIndex]);
var height = 26;
return {
type: "rect",
shape: echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: 27,
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height,
}
),
style: api.style(),
};
},
label: {
normal: {
show: true,
position: "insideBottom",
formatter: function (params) {
let value = params.value[0].content;
if (!value) return "";
if (value.length > 6) {
return value.slice(0, 6) + "...";
}
return value;
},
textStyle: {
align: "center",
fontSize: 14,
fontWeight: "400",
lineHeight: "20",
},
},
},
encode: {
x: 1,
y: 0,
},
itemStyle: {
normal: {
color: function (params) {
const randomIndex = Math.floor(Math.random() * colors.length);
return colors[randomIndex];
},
},
},
data: this.ganttData,
},
],
};
myChart.setOption(option);
window.onresize = function () {
myChart.resize();
};
},
},
computed: {},
};
</script>
<style scoped lang="less">
</style>
js文件
import Gantt from './src/gantt'
Gantt.install = function (Vue) {
Vue.component(Gantt.name, Gantt)
}
export default Gantt
- main.js中组件引用组件
![在这里插入图片描述](http://img.e-com-net.com/image/info8/dfc6d0537dd244d2a340d9c10236e533.jpg)
![在这里插入图片描述](http://img.e-com-net.com/image/info8/14bb9a2cea1c4f3097bd71052784acfe.jpg)
- log页面
<template>
<div class="appointment">
<div class="a-gantt">
<el-row style="padding: 12px 10px; background-color: #fff">
<el-col :span="12" align="left" style="font-weight: 700">
日志
</el-col>
<el-col :span="12" align="right">
<el-date-picker
v-model="baseDate"
type="date"
@change="handleSelect"
placeholder="选择日期"
value-format="yyyy-MM-dd"
>
</el-date-picker>
</el-col>
</el-row>
</div>
<div class="f-gantt">
<Gantt
:baseDate="baseDate"
ref="gantt"
:ganttData="ganttData"
@getInfoCallback="getGanttInfo"
:roomData="roomData"
></Gantt>
</div>
<!-- 新增编辑框 -->
<!-- <el-dialog :title="formTitle" :visible.sync="dialogVisible" width="30%">
<el-form :model="form" :label-width="formLabelWidth">
<el-form-item label="会议室">
<el-input
disabled
v-model="usernameData[form.index]"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item label="内容">
<el-input v-model="form.content" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="时间" :label-width="formLabelWidth">
<el-date-picker
v-model="form.startTime"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd HH:mm"
>
</el-date-picker>
-
<el-date-picker
v-model="form.endTime"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd HH:mm"
>
</el-date-picker>
</el-form-item>
<el-form-item label="状态" :label-width="formLabelWidth">
<el-select v-model="form.status" style="width: 100%">
<el-option label="进行中" value="0"></el-option>
<el-option label="已完成" value="1"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="saveData">确 定</el-button>
</span>
</el-dialog> -->
</div>
</template>
<script>
export default {
data() {
return {
baseDate: `${new Date().getFullYear()}-${
new Date().getMonth() + 1
}-${new Date().getDate()}`,
roomData: [],
ganttData: [],
dialogVisible: false,
formLabelWidth: "120px",
formTitle: "",
form: {
id: "",
index: "",
content: "",
endTime: "",
status: "",
startTime: "",
},
};
},
created() {
this.getDataList()
},
mounted() {
this.getDataList();
},
methods: {
handleSelect() {
this.getDataList()
this.$refs.gantt.myEcharts();
},
getDataList() {
this.$http.post(`/sys/task/ganteLog`, {taskDate: this.baseDate}).then(({ data: res }) => {
if (res.code !== 0) {
return this.$message.error(res.msg)
}
this.roomData = res.data.usernameList
this.ganttData = res.data.data
}).catch(() => {})
},
getGanttInfo(data) {
this.dialogVisible = true;
if (data.length === 2) {
this.formTitle = "新增";
this.form = this.$options.data().form;
this.$set(this.form, "index", data[1]);
} else {
this.formTitle = "修改";
this.form = data[0];
}
},
saveData() {
if (this.formTitle === "修改") {
this.ganttData = this.ganttData.filter((item) => {
return item.value[0].id !== this.form.id;
});
} else {
this.$set(this.form, "status", "0");
}
const obj = Object.assign({}, this.form);
this.ganttData.push({ value: [obj] });
this.$refs.gantt.myEcharts();
this.dialogVisible = false;
},
},
};
</script>
<style scoped>
.f-gantt {
position: absolute;
bottom: 10px;
top: 80px;
width: 100%;
box-sizing: border-box;
}
</style>
注意数据结构
![vue2.X 中使用 echarts5.4.0实现项目进度甘特图_第2张图片](http://img.e-com-net.com/image/info8/4cd95b805aaa4c6f8bcac5d67c86ce58.jpg)