最近项目需要甘特图功能又比较特殊(需要与时间联动),网上找的插件和别人写的有点满足不了需求所以自己弄了个简单的
代码写的烂(毕竟是初步功能,以后还要改的),不喜勿喷,欢迎指点
我们的服务宗旨是 能用就行 ,我们的目标是 人和项目有一个能跑就行
废话不多说,代码奉上,拿来即用
功能说明:
1.取整个盒子的宽度获取鼠标的偏移量计算时间(计算精度不是很高,但是能用就行)
2.甘特图宽度通过起始时间和结束时间计算,偏移的位置为数据的起始时间
3.甘特图部分div是反转的(需求是从底部开始显示往上叠加),反转后再把文字反过来就行了
4.时间变化背景随时间增加
5.鼠标移入位置的线也是通过盒子的宽度及鼠标偏移量计算的时间
<template>
<!-- <div style="position: relative; height: 300px;">-->
<div class="relation" ref="relationBox" @mousemove='mousemove'>
<!-- 事件节点 -->
<div class="node_box">
<div class="gradientbg" :style="calcWidth()"></div>
<div>
<div @click="nodeEventClick(item)" v-for="(item, index) in nodeEvent" :style="calcLeft(item)"
class="item" :key="index">{{ item.name }}</div>
</div>
<div>
<div v-for="(item, index) in nodeULDArr" :style="calcLeft(item)" class="ULDbox" :key="index">
<i class="iconfont" :class="item.icons"></i>
</div>
</div>
</div>
<!-- 甘特图 -->
<div class="gant_box">
<div v-for="(item, index) in gantArr" :style="calcdeviation(item)" class="gant_item" :key="index">
<div class="speedbg" :style="calcbgWidth(item)"></div>
<div class="txtLeft">{{ item.evName }}</div>
<div v-for="(i, j) in item.evNode" @click="submitNode(item,i)" :style="calctxt(i,item)" class="txt" :key="j">{{ i.evNodeName }}</div>
</div>
</div>
<!-- 鼠标线 -->
<i class="line" :style="{ left: mouseX + 'px' }">{{ pointerTime() }}</i>
<div class="search">搜索</div>
<!-- <div @click="screen()" class="screen">全屏</div> -->
<div v-if="calc" class="m-div bg-color-1 interval">
<div class="module_header_info" v-drag> <!--这有个拖拽功能-->
<div class="module_title_1">时差计算</div>
<close-btn @click.native="closePage" />
</div>
<div class="subject bg-color-2" ref="elem">
<div v-for="(item,index) in intervalArr" :key="index">
<div class="flex_box">
<div>{{index+1}}</div>
<div class="selected">
{{item.evName}}:{{item.evNodeName}} <br/>
{{item.evNodeTime}}
</div>
</div>
<div class="flex_box difference">
<span>{{brr[index]}}</span>
<span><i class="iconfont icon-shichajisuan-jiantou"></i></span>
</div>
</div>
</div>
</div>
</div>
<!-- </div> -->
</template>
<script>
//这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)
//例如: import 《组件名称》 from '《组件路径》 ';
import closeBtn from "@/components/closeBtn.vue"
export default {
name: 'relation',
//import 引入的组件需要注入到对象中才能使用
components: {
closeBtn
},
props:{
currentTime: {
type: Number,
// required: true,
},
},
data() {
//这里存放数据
return {
mouseX: 0,
mouseY: 0,
isWidth: null,
isHeight: null,
// itmes: null,
// currentTime: 1656604800,
startTime: 1656604800,
endTime: 1656691199,
// 事件节点数组
nodeEvent: [
{
nodeTime: '2022-07-01 00:05:01',
name: '降落',
}, {
nodeTime: '2022-07-01 00:40:01',
name: '停入机位',
}, {
nodeTime: '2022-07-01 02:00:01',
name: '开舱门-开始',
}, {
nodeTime: '2022-07-01 02:05:01',
name: '开舱门-结束',
}, {
nodeTime: '2022-07-01 06:00:01',
name: '机组下机-开始',
}, {
nodeTime: '2022-07-01 07:00:01',
name: '机组下机-结束',
}, {
nodeTime: '2022-07-01 08:00:01',
name: '消杀结束',
}, {
nodeTime: '2022-07-01 10:00:01',
name: '卸机开始',
}, {
nodeTime: '2022-07-01 15:00:01',
name: '加油开始',
}, {
nodeTime: '2022-07-01 16:00:01',
name: '清污开始',
}, {
nodeTime: '2022-07-01 17:00:01',
name: '清污结束',
}, {
nodeTime: '2022-07-01 18:00:01',
name: '加油结束',
}, {
nodeTime: '2022-07-01 20:00:01',
name: '卸机结束',
}, {
nodeTime: '2022-07-01 21:00:01',
name: '起飞',
}
],
// ULD的时间节点数组
nodeULD: [
{
name: '分拣箱',
ev: 'fenjianUp',
time: '2022-07-01 05:00:01'
}, {
name: '转班箱',
ev: 'zhuangbanUp',
time: '2022-07-01 06:00:01'
}, {
name: '经停箱',
ev: 'jingtinUp',
time: '2022-07-01 07:00:01'
}, {
name: '空箱',
ev: 'kongUp',
time: '2022-07-01 08:00:01'
}, {
name: '分拣箱',
ev: 'fenjianLow',
time: '2022-07-01 15:00:01'
}, {
name: '转班箱',
ev: 'zhuangbanLow',
time: '2022-07-01 16:00:01'
}, {
name: '经停箱',
ev: 'jingtinLow',
time: '2022-07-01 17:00:01'
}, {
name: '空箱',
ev: 'kongLow',
time: '2022-07-01 18:00:01'
},
],
// ULD的图片数组
nodeULDImg: [
{ id: 'fenjianUp', img: 'icon-dingwei' },
{ id: 'zhuangbanUp', img: 'icon-huadao' },
{ id: 'jingtinUp', img: 'icon-chedao' },
{ id: 'kongUp', img: 'icon-zhuanbanxiang2' },
{ id: 'fenjianLow', img: 'icon-fenjianxiang2' },
{ id: 'zhuangbanLow', img: 'icon-fenjianxiang' },
{ id: 'jingtinLow', img: 'icon-yingxiang' },
{ id: 'kongLow', img: 'icon-a-shoujizhutizhuti' },
],
// ULD最后渲染的数组
nodeULDArr: [],
// 甘特图的数据
gantArr: [
{
id: '1',
evName: '升降平台车',
startTime: '2022-07-01 01:00:01',
endTime: '2022-07-01 05:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 01:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 02:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 04:00:01', },
{ evNodeName: '到达VP', evNodeTime: '2022-07-01 04:30:01', },
]
}, {
id: '2',
evName: '传送带车',
startTime: '2022-07-01 01:00:01',
endTime: '2022-07-01 07:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 01:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 02:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 04:00:01', },
{ evNodeName: '到达VP', evNodeTime: '2022-07-01 06:30:01', },
]
}, {
id: '3',
evName: '登机梯车',
startTime: '2022-07-01 02:00:01',
endTime: '2022-07-01 04:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 02:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 02:30:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 03:00:01', },
]
}, {
id: '4',
evName: 'TUG1221',
startTime: '2022-07-01 03:00:01',
endTime: '2022-07-01 09:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 03:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 03:30:01', },
{ evNodeName: '装车完成', evNodeTime: '2022-07-01 07:00:01', },
{ evNodeName: '到达拆板口', evNodeTime: '2022-07-01 08:00:01', },
]
}, {
id: '5',
evName: 'TUG1011',
startTime: '2022-07-01 03:30:01',
endTime: '2022-07-01 09:30:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 03:30:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 05:00:01', },
{ evNodeName: '靠接完成', evNodeTime: '2022-07-01 07:00:01', },
]
}, {
id: '6',
evName: '传送带车',
startTime: '2022-07-01 05:00:01',
endTime: '2022-07-01 10:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 05:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 07:00:01', },
{ evNodeName: '装车完成', evNodeTime: '2022-07-01 08:00:01', },
{ evNodeName: '到达拆板口', evNodeTime: '2022-07-01 10:00:01', },
]
}, {
id: '7',
evName: '拖车',
startTime: '2022-07-01 09:00:01',
endTime: '2022-07-01 14:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 09:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 14:00:01', },
]
}, {
id: '8',
evName: '拖车1',
startTime: '2022-07-01 07:00:01',
endTime: '2022-07-01 13:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 07:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 13:00:01', },
]
}, {
id: '9',
evName: '拖车2',
startTime: '2022-07-01 12:00:01',
endTime: '2022-07-01 17:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 14:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 16:00:01', },
]
}, {
id: '10',
evName: '拖车3',
startTime: '2022-07-01 09:00:01',
endTime: '2022-07-01 17:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 09:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 13:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 15:00:01', },
{ evNodeName: '到达VP', evNodeTime: '2022-07-01 17:00:01', },
]
}, {
id: '6',
evName: '传送带车',
startTime: '2022-07-01 05:00:01',
endTime: '2022-07-01 10:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 05:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 07:00:01', },
{ evNodeName: '装车完成', evNodeTime: '2022-07-01 08:00:01', },
{ evNodeName: '到达拆板口', evNodeTime: '2022-07-01 10:00:01', },
]
}, {
id: '7',
evName: '拖车',
startTime: '2022-07-01 09:00:01',
endTime: '2022-07-01 14:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 09:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 14:00:01', },
]
}, {
id: '8',
evName: '拖车1',
startTime: '2022-07-01 07:00:01',
endTime: '2022-07-01 13:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 07:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 13:00:01', },
]
}, {
id: '9',
evName: '拖车2',
startTime: '2022-07-01 12:00:01',
endTime: '2022-07-01 17:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 14:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 16:00:01', },
]
}, {
id: '10',
evName: '拖车3',
startTime: '2022-07-01 09:00:01',
endTime: '2022-07-01 17:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 09:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 13:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 15:00:01', },
{ evNodeName: '到达VP', evNodeTime: '2022-07-01 17:00:01', },
]
}, {
id: '11',
evName: '拖车4',
startTime: '2022-07-01 14:00:01',
endTime: '2022-07-01 19:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 14:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 15:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 18:00:01', },
]
}, {
id: '8',
evName: '拖车1',
startTime: '2022-07-01 07:00:01',
endTime: '2022-07-01 13:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 07:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 13:00:01', },
]
}, {
id: '9',
evName: '拖车2',
startTime: '2022-07-01 12:00:01',
endTime: '2022-07-01 17:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 12:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 14:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 16:00:01', },
]
}, {
id: '10',
evName: '拖车3',
startTime: '2022-07-01 09:00:01',
endTime: '2022-07-01 17:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 09:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 13:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 15:00:01', },
{ evNodeName: '到达VP', evNodeTime: '2022-07-01 17:00:01', },
]
}, {
id: '11',
evName: '拖车4',
startTime: '2022-07-01 14:00:01',
endTime: '2022-07-01 19:00:01',
evNode: [
{ evNodeName: '接收任务', evNodeTime: '2022-07-01 14:00:01', },
{ evNodeName: '到达机位', evNodeTime: '2022-07-01 15:00:01', },
{ evNodeName: '离开机位', evNodeTime: '2022-07-01 18:00:01', },
]
}, {
id: '12',
evName: '拖车5',
startTime: '2022-07-01 15:00:01',
endTime: '2022-07-01 22:00:01',
evNode: [
{ evNodeName: '接收', evNodeTime: '2022-07-01 15:00:01', },
{ evNodeName: '到达', evNodeTime: '2022-07-01 20:00:01', },
{ evNodeName: '离开', evNodeTime: '2022-07-01 22:00:01', },
]
},
],
// 时差计算
calc: false,
brr: [],
intervalArr: [],
};
},
//计算属性 类似于 data 概念
computed: {
},
//监控 data 中的数据变化
watch: {
intervalArr:{
handler(){
this.brr = []
for(let i in this.intervalArr){
if(i>0){
let item = this.conversion.ssss(this.intervalArr[i].evNodeTime)
let items = this.conversion.ssss(this.intervalArr[i-1].evNodeTime)
this.brr.push(this.conversion.formatSeconds(Math.abs(item-items)))
}
}
this.brr.push('请选择事件节点')
if(this.intervalArr.length >= 2){
this.calc = true
}
}
}
},
//方法集合
methods: {
// 时间转换方法this.conversion.ssss()请自己写
// 鼠标移动时跟随的线
mousemove(e) {
let rect = e.currentTarget.getBoundingClientRect();//这样写是为了处理点击事件鼠标能够点到线下面的东西
this.mouseX = e.clientX - rect.left;
this.mouseY = e.clientY - rect.left;
},
// 鼠标线的位置时间
pointerTime() {
return this.conversion.YMDhms((this.endTime - this.startTime) * (this.mouseX / this.isWidth) + this.startTime)
},
// 甘特图方法---------------------------------------------------------------------------------------------------------
// 计算甘特图的每一项的文字位置
calctxt(i,item) {
let t = this.conversion.ssss(i.evNodeTime)
let j = this.conversion.ssss(item.startTime)
let k = this.conversion.ssss(item.endTime)
return { left: ((t - j) / (k - j) * 100).toFixed(3) + '%' }
},
// 计算甘特图的每一项偏移位置和宽度
calcdeviation(item) {
let t = this.conversion.ssss(item.startTime)
let j = this.conversion.ssss(item.startTime)
let k = this.conversion.ssss(item.endTime)
return {
left: ((t - this.startTime) / (this.endTime - this.startTime) * 100).toFixed(3) + '%',
width: ((k - j) / (this.endTime - this.startTime) * 100).toFixed(3) + '%'
}
},
// 计算甘特图盒子的渐变背景宽
calcbgWidth(item) {
let j = this.conversion.ssss(item.startTime)
let k = this.conversion.ssss(item.endTime)
let w = Number(((this.currentTime - j) / (k - j) * 100).toFixed(3))
if(w <= 0){
return { width:0 + '%'}
}else if(w >= 100){
return { width:100 + '%'}
}else{
return { width:w + '%'}
}
// return { width: ((this.currentTime - j) / (k - j) * 100).toFixed(3) > 100 ? 100 : ((this.currentTime - j) / (k - j) * 100).toFixed(3) + '%' }
},
// 事件节点方法---------------------------------------------------------------------------------------------------------
// 计算事件节点盒子的渐变背景宽
calcWidth() {
return { width: ((this.currentTime - this.startTime) / (this.endTime - this.startTime) * 100).toFixed(3) + '%' }
},
// 计算事件节点盒子的偏移位置
calcLeft(item) {
let t = this.conversion.ssss(item.nodeTime || item.time)
return { left: ((t - this.startTime) / (this.endTime - this.startTime) * 100).toFixed(3) + '%' }
},
// 打印节点事件
nodeEventClick(item) {
console.log(item.name);
},
// 甘特图子节点点击
submitNode(item,i){
console.log('甘特图节点',item,i);
this.intervalArr.push({
evName: item.evName,
evNodeName: i.evNodeName,
evNodeTime: i.evNodeTime,
})
setTimeout(()=>{
this.$refs.elem.scrollTop = this.$refs.elem.scrollHeight;
},10)
},
// ULD的图片
getULD() {
this.nodeULDArr = this.nodeULD.map((item) => {
let icons = this.nodeULDImg.find((x) => x.id === item.ev).img;
return Object.assign(item, { icons: icons });
});
},
// 当前时间 我的时间是通过时间轴传过来的,请自行使用定时器模拟
// runTime() {
// this.itmes = setInterval(() => {
// if (this.currentTime > 1656691199) {
// this.currentTime = 1656604800
// } else {
// this.currentTime+=100
// }
// }, 100);
// },
// 获取整个盒子的宽度
screenWidth() {
this.isWidth = this.$refs.relationBox.offsetWidth;
},
// 关闭计算机
closePage(){
this.calc = false
this.intervalArr = []
this.brr = []
}
},
//生命周期 - 创建完成(可以访问当前 this 实例)
created() {
// this.runTime()
// 添加事件监听器
window.addEventListener("resize", this.screenWidth);
},
//生命周期 - 挂载完成(可以访问 DOM 元素)
mounted() {
// 获取整个盒子的宽度
this.screenWidth()
this.getULD()
// this.getCurrentTime()
// this.isWidth = this.$refs.relationBox.offsetWidth
this.viewer.addResponseEventListener("Web", (data) => {
alert(JSON.stringify(data))
this.upDateByTime = data.data.upDateByTime
});
// this.viewer.addResponseEventListener("Web1", (data) => {
// alert('ue的数据WEB1')
// this.uePlanOrPause = 'timePlan'
// });
},
beforeCreate() { }, //生命周期 - 创建之前
beforeMount() { }, //生命周期 - 挂载之前
beforeUpdate() { }, //生命周期 - 更新之前
updated() { }, //生命周期 - 更新之后
beforeDestroy() { }, //生命周期 - 销毁之前
destroyed() {
// 删除事件监听器
window.removeEventListener("resize", this.screenWidth);
}, //生命周期 - 销毁完成
activated() { }, //如果页面有 keep-alive 缓存功能, 这个函数会触发
}
</script>
<style scoped lang="less">
.relation {
width: 100%;
height: 935px;
// background: pink;
position: relative;
user-select: none;
transition: height 2s;
}
// .relation_screen{
// height: 800px;
// transition: height 2s;
// }
.line {
height: 935px;
border-left: 1px solid #fff;
position: absolute;
pointer-events: none;
}
.node_box {
width: 100%;
height: 100px;
// background: greenyellow;
position: absolute;
bottom: 0px;
.gradientbg {
position: absolute;
height: 30px;
// width: 500px;
// background: -webkit-linear-gradient(left, rgb(128, 245, 163), red);
background: linear-gradient(90deg, #49A043 0%, #2B6551 100%);
}
.gradientbg::before{
content: "》";
position: absolute;
line-height: 30px;
right: 5px;
}
.item {
height: 30px;
border: 1px solid #fff;
font-size: 12px;
position: absolute;
max-width: 100px;
padding: 5px;
// background: white;
background: linear-gradient(90deg, #49A043 0%, #2B6551 100%);
}
.ULDbox {
position: absolute;
top: 50px;
}
}
.gant_box {
width: 100%;
height: 800px;
// background: url(../../assets/postyan.jpg) no-repeat;
background-size: 100% 100%;
position: absolute;
// top: 20px;
transition: height 2s;
overflow: hidden;
transform:rotateX(180deg);//反转div让元素从下往上显示
.gant_item {
min-height: 0;
position: relative;
// border: 1px solid red;
margin: 17px 0;
height: 20px;
transform:rotateX(180deg);//反转div后文字也是反的,再把文字反转回去
background: #A0A0A0;
.txtLeft{
position: absolute;
left: -80px;
}
.txt{
position: absolute;
white-space: nowrap;
// height: 20px;
// padding: 1px 4px;
font-size: 12px;
background: #545760;
border: 1px solid #fff;
}
.speedbg{
position: absolute;
height: 20px;
// width: 50px;
// background: -webkit-linear-gradient(left, rgb(128, 245, 163), red);
background: linear-gradient(90deg, #389AB0 0%, #177592 100%);
}
}
}
// .gant_box_screen{
// height: 650px;
// transition: height 2s;
// }
.search{
position: absolute;
width: 80px;
height: 30px;
border: 1px solid black;
background: red;
}
.interval{
width:220px ;
height: 515px;
padding: 10px 5px;
// margin: 0 auto;
// text-align: center;
// border-top:100px solid transparent;
// border-bottom:60px solid yellow;
// border-left:30px solid transparent;
// border-right:30px solid transparent;
// transform:rotateX(180deg);
.subject{
// display: flex;
// transform:rotateX(180deg);
width: 210px;
height: 445px;
color: #fff;
padding: 20px 0;
margin: 5px;
overflow-y: auto;
// background-image: url();
.flex_box{
align-items: center;
display: flex;
justify-content: center;
.selected{
width: 145px;
height: 45px;
margin-left: 10px;
background: rgba(160, 160, 160, .4);
}
}
.difference{
height: 60px;
.icon-shichajisuan-jiantou{
font-size: 30px;
}
}
}
}
</style>