如上图所示,本示例是基于viewui,echarts 4的一个简单的研发资源-项目的甘特图,当然可以根据自己需要,实现更复杂的效果。
示例中的源码,用固定数据代替了axios调用服务端接口。
<template>
<YdLayout>
<Content
:style="{
padding: '0',
minHeight: windowHeight - 80 + 'px',
background: '#fff',
}"
>
<Row>
<Col span="24">
<div style="padding: 0 15%">
<div
id="main"
:style="{
width: '100%',
height: tabHeight + 'px',
marginTop: padCanvas + 'px',
}"
></div>
</div>
</Col>
<Col span="24" style="padding:20px">
<Button type="primary" @click="exportData">
<Icon type="ios-download-outline"></Icon>导出数据
</Button>
<br />
<Table ref="tb" class="ivu-m-8" border :columns="columns" :data="tbData"></Table>
</Col>
</Row>
</Content>
</YdLayout>
</template>
<script>
import dayjs from "dayjs"
import echarts from "echarts";
import mixinsAutoSize from "../../mixins/auto-size";
import { deepCopy } from "../../utils/assist";
import YdLayout from "../yd-layout";
const stats = () => {
const data = { "minStartTime": "2022-01-01", "maxEndTime": "2022-03-31", "users": [{ "userId": 1, "userName": "研发1", "projects": [{ "projectId": 1, "projectName": "项目1", "startTime": "2022-01-01", "endTime": "2022-02-26" }, { "projectId": 2, "projectName": "项目2", "startTime": "2022-01-01", "endTime": "2022-03-31" }] }, { "userId": 2, "userName": "研发2", "projects": [{ "projectId": 1, "projectName": "项目1", "startTime": "2022-01-26", "endTime": "2022-02-27" }, { "projectId": 2, "projectName": "项目2", "startTime": "2022-01-29", "endTime": "2022-02-28" }] }], "projects": [{ "projectId": 1, "projectName": "项目1", "startTime": "2022-01-01", "endTime": "2022-02-26" }, { "projectId": 2, "projectName": "项目2", "startTime": "2022-01-01", "endTime": "2022-03-31" }] }
return new Promise(function (resolve, reject) {
resolve(data)
})
}
export default {
name: "YdoProjectStats",
components: { YdLayout },
mixins: [mixinsAutoSize],
data() {
return {
statsChart: null,
padCanvas: "30",
tabHeight: "",
columns: [{
title: "人员",
key: "userName",
width: 200
},
{
title: "项目",
key: "projects",
minWidth: 200
},
{
title: "开始时间",
key: "startTime",
width: 100
}, {
title: "结束时间",
key: "endTime",
width: 100
}],
tbData: []
};
},
created() {
this.tabHeight = this.windowHeight - 200;
this.init();
},
methods: {
init() {
this.stats();
},
stats() {
stats()
.then((response) => {
console.log(response)
const minTime = response.minStartTime
const maxTime = response.maxEndTime
const projectUsers = response.users.slice(0)
const projects = response.projects.slice(0)
const users = projectUsers.map(e => e.userName)
const serieData = [];
projects.forEach(project => {
const endDates = []
const startDates = []
projectUsers.forEach(user => {
const t = user.projects.find(e => e.projectId == project.projectId)
if (t != undefined) {
endDates.push(t.endTime)
startDates.push(t.startTime)
} else {
endDates.push("")
startDates.push("")
}
})
serieData.push(
{
name: project.projectName,
type: "bar",
stack: project.projectName,
normal: {
borderColor: "#fff",
borderWidth: 2
},
zlevel: -1,
data: endDates
}
)
serieData.push(
{
name: project.projectName,
type: "bar",
stack: project.projectName,
itemStyle: {
normal: {
color: "white",
}
},
zlevel: -1,
z: 3,
data: startDates
}
)
})
let statsChartOption = {
title: {
text: "研发资源"
},
legend: {
y: "top",
},
grid: {
containLabel: true
},
xAxis: {
type: "time",
min: minTime,
max: maxTime
},
yAxis: {
axisLabel: {
show: true,
interval: 0,
formatter: function (value, index) {
var last = ""
var max = 5;
var len = value.length;
var hang = Math.ceil(len / max);
if (hang > 1) {
for (var i = 0; i < hang; i++) {
var start = i * max;
var end = start + max;
var temp = value.substring(start, end) + "\n";
last += temp;
}
return last;
} else {
return value;
}
}
},
data: users
},
tooltip: {
trigger: "axis",
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
var res = "";
var name = "";
var start0 = "";
var start = "";
var end0 = "";
var end = "";
for (var i in params) {
var k = i % 2;
if (!k) { //奇数
name = params[i].seriesName;
end0 = params[i].data;
if (end0 != null && end0.length > 0) {
end = end0
}
}
if (k) { //偶数
start0 = params[i].data;
if (start0 != null && start0.length > 0) {
start = start0
}
res += name + " : " + start + "~" + end + "</br>";
}
}
return res;
}
},
series: serieData
}
this.statsChart = echarts.init(document.getElementById("main"));
this.statsChart.setOption(statsChartOption);
this.renderTable(projectUsers)
}).catch((error) => this.handleSearchError(error));
},
renderTable(data) {
let tbData = []
data.forEach(user => {
let minTime = user.projects[0].startTime;
let maxTime = user.projects[0].endTime;
user.projects.forEach(project => {
if (minTime.length > 0 && project.startTime.length > 0 && dayjs(project.startTime).isBefore(dayjs(minTime))) {
minTime = project.startTime
}
if (maxTime.length > 0 && project.endTime.length > 0 && dayjs(project.endTime).isAfter(dayjs(maxTime))) {
maxTime = project.endTime
}
})
tbData.push({
userName: user.userName,
projects: user.projects.map(e => e.projectName).join(" "),
startTime: minTime,
endTime: maxTime
})
})
this.tbData = tbData
},
handleSearchError(error) {
console.log(error);
this.tbData = [];
if (
error.response &&
error.response.data &&
error.response.data.message
) {
this.$Notice.warning({ title: error.response.data.message });
} else {
this.$Notice.warning({ title: "无法加载数据" });
}
},
exportData() {
this.$refs.tb.exportCsv({
filename: 'project-stats'
})
}
},
};
</script>
网友评论