排程甘特图 v1.0
<template>
<div id="gante">
<el-button @click="refresh" style="margin-bottom:5px">刷新(测试)</el-button>
<table border="1" cellpadding="8px" class="gante-table" v-loading="loading">
<tr>
<th style="width:200px"></th>
<th style="width:100px" colspan="2" v-for="item in headerData" :key="item.key">{{ item.value }}</th>
</tr>
<tr v-for="(item, index) in rows" :key="index" :class="{ firstline: index == 0}">
<template v-if="index == 0">
<td class="cell_td">设备</td>
<td class="cell_td" colspan="2" v-for="item in headerData" :key="item.id"></td>
</template>
<template v-else>
<td>资源 {{index}}</td>
<template v-for="(r, index) in item.row">
<td :key="index" :style="{ position: index % 2 == 0 ? 'relative' : 'static' }">
<div :class="{'contant_block_hover': colorMap.get(r.status).length}" @mouseover="mouseover(item.id, r.iid, r.status == 'Danger')" @mouseleave="mouseleave(item.id, r.iid, r.status == 'Danger')" :style="{backgroundColor: colorMap.get(r.status)}" class="center contant_block" v-if="index % 2 == 0">
{{colorMap.get(r.status) ? (r.status=="Danger"? '' : '100%') : '0%'}}
<div class="contant_hover" v-show="r.showContant" @mouseleave.stop @mouseover.stop >
设备:QG#01切割机 <br>
故障起始时间:2023-2-27 8:00 <br>
故障修复时间:2023-2-27 12:00 <br>
影响任务单个数:10 <br>
</div>
</div>
</td>
</template>
</template>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'gantt',
data() {
return {
rows: [],
bodyData: [],
headerData: [],
loading: true,
colorMap: new Map()
};
},
props: {
},
created() {
this.colorMap.set('Success', '#67C23A')
this.colorMap.set('Warning', '#E6A23C')
this.colorMap.set('Danger', '#F56C6C')
this.colorMap.set('Info', '#909399')
this.colorMap.set('none', '')
this.createData()
},
beforeDestroy() {
},
watch: {
},
methods: {
createData() {
const colorMap = ['Success', 'Warning', 'Danger', 'Info', 'none']
this.loading = true
new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000)
}).then(() => {
this.headerData = []
this.rows = [];
for (let index = 0; index < 6; index++) {
const obj = { row: [] };
obj.id = this.uuid()
for (let index = 0; index < 22; index++) {
const num = Math.floor(Math.random()*Math.floor(5));
const _obj = {}
_obj.value = 'contant' + '-' + index
_obj.iid = this.uuid()
_obj.showContant = false;
_obj.status = colorMap[num]
obj.row.push(_obj)
}
this.rows.push(obj);
}
for (let index = 0; index < 11; index++) {
const obj = {};
obj.value = this.getDateFun(index)
obj.key = this.uuid()
this.headerData.push(obj)
}
}).finally(() => {
this.loading = false
})
},
uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
refresh() {
this.createData();
},
mouseover(id, iid, key) {
if(!key) return
const index = this.rows.findIndex(item => item.id == id);
if(index != -1) {
const i = this.rows[index].row.findIndex(item => item.iid == iid)
if(i != -1) {
this.rows[index].row[i].showContant = true
}
}
},
mouseleave(id, iid, key) {
if(!key) return
console.log('mouseleave')
const index = this.rows.findIndex(item => item.id == id);
if(index != -1) {
const i = this.rows[index].row.findIndex(item => item.iid == iid)
if(i != -1) {
this.rows[index].row[i].showContant = false
}
}
},
getDateFun(index) {
const day = new Date();
day.setTime(day.getTime() + index * 24*60*60*1000);
return day.getFullYear()+"-" + (day.getMonth()+1) + "-" + day.getDate();
},
bgcFun(status) {
console.log('???????????????????????????????')
return "background-color: #67C23A"
}
}
}
</script>
<style lang="scss" scoped>
#gante {
margin-top: 10px;
padding: 10px;
padding-bottom: 30px;
overflow-x: auto;
background-color: #fff;
.gante-table {
border: none;
width: 1300px;
}
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
.contant_block {
cursor: pointer;
width:90px;
height:30px;
border-radius: 3px;
position: absolute;
top: 3px;
left: 5px;
}
.contant_block_hover:hover {
// transform: scale(1.02);
border: 2px solid #cccccc;
}
.firstline {
line-height: 6px;
}
.cell_td {
width: 150px;
}
.contant_hover {
z-index:9999;
position:absolute;
left:100px;
width:220px;
height:100px;
padding: 5px;
background-color:#ffffff;
border: 1px solid #cccccc;
}
</style>
排程甘特图 v2.0
<template>
<div id="gante">
<el-button @click="refresh" style="margin-bottom:5px">刷新(测试)</el-button>
<table border="1" cellpadding="8px" class="gante-table" v-loading="loading">
<tr style="text-align:center;">
<th style="width:200px"></th>
<th style="width:200px" colspan="2" v-for="item in headerData" :key="item.key">{{ item.value }}</th>
</tr>
<tr v-for="(item, index) in rows" :key="index" :class="{ firstline: index == 0}">
<template v-if="index == 0">
<td>设备</td>
<td colspan="2" v-for="item in headerData" :key="item.id">
<div style="display:flex;justify-content:space-between;">
<span class="time_item">02</span>
<span class="time_item">04</span>
<span class="time_item">06</span>
<span class="time_item">08</span>
<span class="time_item">10</span>
<span class="time_item">12</span>
<span class="time_item">14</span>
<span class="time_item">16</span>
<span class="time_item">18</span>
<span class="time_item">20</span>
<span class="time_item">22</span>
</div>
</td>
</template>
<template v-else>
<td>资源 {{index}}</td>
<template v-for="(r, index) in item.row">
<td :key="index" :style="{ position: index % 2 == 0 ? 'relative' : 'static' }">
<template v-if="index != item.row.length - 2 && index % 2 == 0" >
<div :class="{'contant_block_hover': colorMap.get(r.am.status).length}" @mouseover="mouseover(item.id, r.am.iid, r.am.status == 'Danger','am')" @mouseleave="mouseleave(item.id, r.am.iid, r.am.status == 'Danger', 'am')" :style="{border: '1px ' + 'solid ' + colorMap.get(r.am.status)}" class="center contant_block">
<div :style="{backgroundColor: colorMap.get(r.am.status),height: r.am.percentage * 100 + '%', width: '100%' }">
</div>
<div style="position: absolute;left:50%;transform: translateX(-50%);">
{{r.am.percentage * 100 }}%
</div>
<div class="contant_hover" v-show="r.am.showContant" @mouseleave.stop @mouseover.stop >
设备:QG#01切割机 <br>
故障起始时间:2023-2-27 8:00 <br>
故障修复时间:2023-2-27 12:00 <br>
影响任务单个数:10 <br>
</div>
</div>
<div style="left:196px" :class="{'contant_block_hover': colorMap.get(r.pm.status).length}" @mouseover="mouseover(item.id, r.pm.iid, r.pm.status == 'Danger','pm')" @mouseleave="mouseleave(item.id, r.pm.iid, r.pm.status == 'Danger','pm')" :style="{border: '1px ' + 'solid ' + colorMap.get(r.pm.status), width: '117px'}" class="center contant_block">
<div :style="{backgroundColor: colorMap.get(r.pm.status),height: r.pm.percentage * 100 + '%', width: '100%' }">
</div>
<div style="position: absolute;left:50%;transform: translateX(-50%);">
{{r.pm.percentage * 100 }}%
</div>
<div class="contant_hover" v-show="r.pm.showContant" @mouseleave.stop @mouseover.stop >
设备:QG#01切割机 <br>
故障起始时间:2023-2-27 8:00 <br>
故障修复时间:2023-2-27 12:00 <br>
影响任务单个数:10 <br>
</div>
</div>
</template>
</td>
</template>
</template>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'gantt',
data() {
return {
rows: [],
bodyData: [],
headerData: [],
loading: true,
colorMap: new Map()
};
},
props: {
},
created() {
this.colorMap.set('Success', '#67C23A')
this.colorMap.set('Warning', '#E6A23C')
this.colorMap.set('Danger', '#F56C6C')
this.colorMap.set('Info', '#909399')
this.colorMap.set('none', '')
this.createData()
},
methods: {
createData() {
this.loading = true
new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000)
}).then(() => {
this.headerData = []
this.rows = [];
for (let index = 0; index < 6; index++) {
this.rows.push(this.createBlockData());
}
for (let index = 0; index < 6; index++) {
const obj = {};
obj.value = this.getDateFun(index)
obj.key = this.uuid()
this.headerData.push(obj)
}
}).finally(() => {
this.loading = false
})
},
uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
createBlockData() {
const obj = { row: [] };
obj.id = this.uuid()
obj.row = this.createBlockDataItem()
return obj
},
createBlockDataItem() {
const colorMap = ['Success', 'Warning', 'Danger', 'Info', 'none']
const row = []
for (let index = 0; index < 12; index++) {
const _obj = {am:{},pm:{}}
_obj.am.value = 'contant' + '-' + index
_obj.am.iid = this.uuid()
_obj.am.showContant = false;
_obj.am.status = colorMap[Math.floor(Math.random()*Math.floor(5))]
if(_obj.am.status !== 'none') {
_obj.am.percentage = Math.random().toFixed(1)
}else {
_obj.am.percentage = 0
}
_obj.pm.value = 'contant' + '-' + index
_obj.pm.iid = this.uuid()
_obj.pm.showContant = false;
_obj.pm.status = colorMap[Math.floor(Math.random()*Math.floor(5))]
if(_obj.pm.status !== 'none') {
_obj.pm.percentage = Math.random().toFixed(1)
}else {
_obj.pm.percentage = 0
}
row.push(_obj)
}
return row
},
refresh() {
this.createData();
},
mouseover(id, iid, key, mark) {
console.log('mouseover')
if(!key) return
const index = this.rows.findIndex(item => item.id == id);
if(index != -1) {
const i = this.rows[index].row.findIndex(item => item[mark].iid == iid)
if(i != -1) {
this.rows[index].row[i][mark].showContant = true
}
}
},
mouseleave(id, iid, key, mark) {
if(!key) return
console.log('mouseleave')
const index = this.rows.findIndex(item => item.id == id);
if(index != -1) {
const i = this.rows[index].row.findIndex(item => item[mark].iid == iid)
if(i != -1) {
this.rows[index].row[i][mark].showContant = false
}
}
},
getDateFun(index) {
const day = new Date();
day.setTime(day.getTime() + index * 24*60*60*1000);
return day.getFullYear()+"-" + (day.getMonth()+1) + "-" + day.getDate();
},
}
}
</script>
<style lang="scss" scoped>
#gante {
margin-top: 10px;
padding: 10px;
padding-bottom: 30px;
overflow-x: auto;
background-color: #fff;
.gante-table {
border: none;
width: 1600px;
// overflow: hidden;
}
}
.center {
display: flex;
// justify-content: center;
align-items: end;
}
.contant_block {
z-index: 9;
cursor: pointer;
width:116px;
height:30px;
border-radius: 3px;
position: absolute;
top: 3px;
left: 80px;
}
.contant_block_hover:hover {
z-index: 99999;
border: 2px solid #cccccc;
}
.firstline {
line-height: 6px;
}
.contant_hover {
z-index:9999;
position: absolute;
left:120px;
width:220px;
height:100px;
padding: 5px;
background-color:#ffffff;
border: 1px solid #cccccc;
}
.time_item {
flex:1;
text-align:center
}
</style>