引言
在玻璃加工行业,高效管理切割、磨边、洗、钢化、丝印等复杂工序对于提升生产效率至关重要。本文将介绍如何利用Vue.js框架结合Element UI组件库,自定义实现一个工序甘特图,以可视化展示各道工序的时间线与进度,为生产调度带来便利。
效果
小时高度,宽度改变动态效果
全部代码:
视图部分
<template><div class="home group"><el-card
v-loading="loading":span="24"
element-loading-text="正在加载处理数据....":xs="24"class="box-card"
id="boxCard"
ref="tableBox"
append-to-body
><el-row><el-col :span="1.5" style="margin-right: 10px"><el-button
type="primary"
plain
icon="el-icon-view"
size="mini"
@click.native="switchView">切换视图</el-button
></el-col><el-col :span="1.5" style="margin-right: 10px"><el-button type="primary" plain size="mini" icon="el-icon-document">查看物料到货计划</el-button
></el-col><el-col :span="1.5" style="margin-right: 10px"><el-button type="primary" plain size="mini" icon="el-icon-upload2">导出</el-button
></el-col><el-col :span="1.5" style="margin-right: 10px"><el-button type="primary" plain icon="el-icon-printer" size="mini">打印</el-button
></el-col><el-col :span="1.5" style="margin-right: 10px"><el-button type="primary" plain icon="el-icon-lock" size="mini">锁定排产</el-button
></el-col><el-col :span="1.5" style="margin-right: 10px"><el-button type="primary" plain icon="el-icon-unlock" size="mini">解锁排产</el-button
></el-col
><el-col :span="1.5" style="margin-right: 10px"><el-button type="primary" plain icon="el-icon-rank" size="mini">拖拽排产</el-button
></el-col
></el-row><el-table
v-show="isView"class="ganteTable"
ref="ganTeTable":height="tableHeight":style="timeArr.length > 0 ? 'width: 100%;' : 'width:239px;'":key="tableKey":cell-style="iCellStyle":fit="false":data="tableData"
border
align="center"
size="mini":span-method="tableSpanMethod"><el-table-column
fixed
align="center"
prop="index1"
label="工作中心"class="index1"
width="70px"><template slot-scope="scope"><el-popover
placement="top-start"
title="工作中心"
width="200"
trigger="hover":content="scope.row.index1.label"><div
slot="reference":class="rowHeight < 36 ? 'oneLineCls' : 'twoLineCls'">{{ scope.row.index1.label }}</div></el-popover></template></el-table-column><el-table-column
fixed
align="center"
prop="index2"
label="产线名称"class="index1"
width="100px"><template slot-scope="scope"><!--{{ scope.row.index2.label }}--><el-popover
placement="top-start"
title="产线名称"
width="200"
trigger="hover":content="scope.row.index3.label"><div
slot="reference":class="rowHeight < 36 ? 'oneLineCls' : 'twoLineCls'">{{ scope.row.index2.label }}</div></el-popover></template></el-table-column><el-table-column
fixed
height="47px"
align="center"
prop="index3"
label="设备名称"class="index1"
width="100px"><template slot-scope="scope"><!--{{ scope.row.index3.label }}--><el-popover
placement="top-start"
title="设备名称"
width="200"
trigger="hover":content="scope.row.index3.label"><div
slot="reference":class="rowHeight < 36 ? 'oneLineCls' : 'twoLineCls'">{{ scope.row.index3.label }}</div></el-popover></template></el-table-column><!-- 表头遍历日期 --><template v-for="(timeArrItem, index1) in timeArr"><el-table-column
height="47px"
align="center":label="timeArrItem.substr(0, 10)":key="timeArrItem + index1 + ''"
width="500px"><!-- 表头遍历时间 --><template v-for="(hourArrItem, index2) in hourArr"><el-table-column
height="47px"
align="center"class="pc-box":label="hourArrItem + ''":key="index1 + '-' + index2 + 5 + timeArrItem + hourArrItem":width="latticeWidth + 'px;'"><template slot="header"><div @mousemove="updateXY">{{ hourArrItem }}</div><div
ref="pointBox"
id="pointBox"
v-if="index2 === 0 && index1 === 0"></div></template><template
slot-scope="scope"
v-if="index2 === 0 && index1 === 0"><div
id="content-box"
@mousemove="updateXY"class="content-box":ref="index1 + '-' + index2 + 5":style="
'width:'+
timeArr.length *24* latticeWidth +'px;overflow:hidden;'
"
><el-tooltip
:draggable="true"
v-for="(workItem, index3) in scope.row.workPlanList.data":key="
workItem.itemId +
workItem.endTime +
workItem.startTime +
index2 +
index3
"
class="item"
effect="dark"
content="Bottom Right 提示文字"
placement="bottom-end"><div slot="content"><br /><p>信息:</p><p>工作中心名称:{{ scope.row.index3.label }}</p><p>开始时间:{{ workItem.startTime }}</p><p>开始时间:{{ workItem.endTime }}</p><p>工作中心描述:{{ workItem.workCenterDesc }}</p><p>工作中心编码:{{ workItem.workCenterSn }}</p></div><div
:draggable="true"class="AAA":style="
'background-color:'+
workItem.color +';'+'width:'+timeInterval(workItem.startTime, workItem.endTime).widthPx +'px;'+' position: absolute;'+'left:'+timeInterval(workItem.startTime, workItem.endTime).startPx +'px;'
"
></div></el-tooltip></div></template></el-table-column></template></el-table-column></template></el-table><!--<day-table-view v-show="!isView"></day-table-view>--><div class="slider-block" v-show="isView"><div class="slider-block-text">小时高度:</div><!--
v-if="isSlider"--><el-slider
@change="sliderHeightChange"
style="width: 200px"
v-model="rowHeight":min="24":max="72":step="12"
show-stops
></el-slider></div><div class="slider-block" v-show="isView"><div class="slider-block-text">小时宽度:</div><el-slider
v-if="isSlider"
@change="sliderWidthChange"
style="width: 200px"
v-model="latticeWidth":min="minWidth":max="maxWidth":step="12"
show-stops
></el-slider></div></el-card></div></template><script>
js部分
exportdefault{name:"dailyScheduling",components:{// dayTableView},data(){return{loading:false,//表格数据处理isView:true,content:"内容",isSlider:true,//是否显示缩放和拉长minWidth:24,//最小缩放maxWidth:72,//最大缩放rowHeight:24,//每一行的高度pointObj:{pointX:340,pointBoxLeft:0,//指针盒子距离左侧的偏移量},eleData:{dayList:[// 天数"2023-05-08","2023-05-09","2023-05-10",],startTime:"2023-05-08 00:00:00",// 开始时间endTime:"2023-05-10 00:00:00",// 结束时间timeList:[],workcenterList:[],],},tableHeight:0,//table的高度oneHourPx:24,//一小时间隔15px 一分钟间隔0.25pxoneMinutePx:0.4,//一分钟0.4pxtableData:null,//表格数据latticeWidth:30,//一个单元格的宽度最小24pxtimeArr:[],//天数集合hourArr:[//小时集合"00","01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23",// "24",],tableKey:0,//值改变更新tableearliestTime:"",//最早时间latestTime:"",//最晚时间conWidth:0,};},created(){
window.onload=function(){
document.addEventListener("touchstart",function(event){if(event.touches.length >1){
event.preventDefault();}});
document.addEventListener("gesturestart",function(event){
event.preventDefault();});};//初始化表格高度,和初始化指针数据this.$set(this.pointObj,"pointX",0);this.$nextTick(()=>{this.tableHeight =this.$refs.tableBox.offsetHeight -110;});},mounted(){this.getGanttChartData();//禁止ctrl+滚轮缩放letscrollFunc=function(e){
e = e || window.event;if(e.wheelDelta && event.ctrlKey){//IE/Opera/Chrome
event.returnValue =false;}elseif(e.detail){//Firefox
event.returnValue =false;}};/*注册事件*/if(document.addEventListener){
document.addEventListener("DOMMouseScroll", scrollFunc,false);}//W3C
window.onmousewheel = document.onmousewheel = scrollFunc;//IE/Opera/Chrome/Safari//设置表格最大高度沾满全屏this.$nextTick(()=>{this.tableHeight = document.getElementById("boxCard").offsetHeight -110;
window.addEventListener("scroll",this.handleScroll,true);//获取标针盒子距离浏览器左侧的距离// this.pointObj.pointBoxLeft = document.getElementById("pointBox").getBoundingClientRect().left//监听浏览器窗口变化const that =this;
window.onresize=()=>{return(()=>{//计算装有指针的盒子距离浏览器左侧的距离,指针减去这个盒子距离浏览器左侧的偏移量得到正确时间指针this.pointObj.pointBoxLeft =0;
console.log("窗口改变了");})();};//如果日期小于2天 则官渡为39if(this.timeArr.length <=2){this.latticeWidth =39;this.minWidth =39;this.maxWidth =72;}
console.log("我被执行了",this.timeArr.length);if(this.timeArr.length >=3){this.latticeWidth =24;this.minWidth =24;this.maxWidth =72;}if(this.timeArr.length ==1){this.latticeWidth =66;this.isSlider =false;}this.widthAA =this.timeArr.length *24*this.latticeWidth;});},methods:{getGanttChartData(){//判断是否传递过来idlet id =null;if(typeofthis.$route.query.id !=="undefined"){
id =JSON.parse(this.$route.query.id);}this.loading =true;// getGanttChartData({productPlanTaskId:id}).then(res=>{this.timeArr =[];this.eleData.dayList.forEach((element)=>{this.timeArr.push(element +" 00:00:00");});this.eleData.workcenterList =this.eleData.workcenterList;this.treeToTableData();//如果日期小于2天 则为39if(this.timeArr.length <=2){this.latticeWidth =39;this.minWidth =39;this.maxWidth =72;}if(this.timeArr.length >=3){this.latticeWidth =21;this.minWidth =21;this.maxWidth =72;}if(this.timeArr.length ==1){this.latticeWidth =66;this.minWidth =66;this.maxWidth =66;this.isSlider =false;}this.widthAA =this.timeArr.length *24*this.latticeWidth;this.$nextTick(()=>{this.$refs.ganTeTable.doLayout();this.$forceUpdate();});this.loading =false;// })},//切换视图switchView(){this.isView =!this.isView;},//物料信息展开//行高回调iCellStyle(){return"height:"+this.rowHeight +"px";},//改变行高sliderHeightChange(){//重新布局表格this.$nextTick(()=>{this.iCellStyle();this.$refs.ganTeTable.doLayout();// this.tableKey = Math.random()});},//改变行宽sliderWidthChange(){//重新布局表格this.$nextTick(()=>{this.$refs.ganTeTable.doLayout();// this.tableKey = Math.random()});},// 当鼠标移动时触发updateXY(e){let x = e.clientX;//计算装有指针的盒子距离浏览器左侧的距离,指针减去这个盒子距离浏览器左侧的偏移量得到正确时间指针this.pointObj.pointBoxLeft = document
.getElementById("pointBox").getBoundingClientRect().left;this.$nextTick(()=>{this.boble =false;
document.querySelector("#pointBox").innerHTML =`<div v-if="boble" style="width: 1px; height: 25px; position: absolute; background: red;left:${
x -this.pointObj.pointBoxLeft
}px;" id="head-pointer" class="head-pointer"> </div>`;});this.boble =false;},parentW(index1, index2){if(this.$refs[index1 +"-"+ index2 +5]){
console.log(this.$refs[index1 +"-"+ index2 +5][0].clientWidth);returnthis.$refs[index1 +"-"+ index2 +5][0].clientWidth;}else{return0;}},parentH(index1, index2){if(this.$refs[index1 +"-"+ index2 +5]){
console.log(this.$refs[index1 +"-"+ index2 +5][0].clientHeight);returnthis.$refs[index1 +"-"+ index2 +5][0].clientHeight;}else{return0;}},draggableStart(){// console.log(this.tableData[0].workPlanList.data);},draggableEnd(){// console.log(this.tableData[0].workPlanList.data);},/**
* 计算两个时间的间隔
* 入参 开始时间,结束时间
* 回参 返回一个任务距离最开始时间的分钟[距离],和一个任务开始时间和结束时间的分钟[距离],
*/timeInterval(startTime, endTiem){let time =newDate(endTiem)-newDate(startTime);//获取任务开始时间和任务结束时间的相差时间戳let minuteDiff = Math.floor(time /(60*1000));//相差时间间隔let initialTime =newDate(startTime)-newDate(this.timeArr[0]);//获取距离最开始的距离let inittiDiff = Math.floor(initialTime /(60*1000));// console.log("latticeWidth",inittiDiff)return{widthPx: minuteDiff *(this.latticeWidth /60),startPx: inittiDiff *(this.latticeWidth /60),};},treeToTableData(){
console.log("this.eleData.workcenterList",this.eleData.workcenterList);//将树状结构格式转换成二维数组表格形式let ewArr =this.parseTreeToRow(this.eleData.workcenterList);let tableData =[];
ewArr.map((item)=>{let obj ={};
item.map((itemc, indexb)=>{
obj["index"+(indexb +1)]={id: itemc.id,label: itemc.label,};if(typeof itemc.workPlanList !=="undefined"){
obj.workPlanList ={data: itemc.workPlanList };}});
tableData.push(obj);});this.tableData = tableData;// console.log("tableData", this.tableData);},/**
* 递归-----将树结构数据格式,转化为,二维数组 表格形式
* @param node 树的源数据
* @param data 树转化为二维数组的数据
* @param row 临时存储数据
* @returns {*[]}
*/parseTreeToRow(node, data =[], row =[]){
node.map((item)=>{let obj ={id: item.workCenterId || item.lineId || item.machineId,label: item.workCenterName || item.lineName || item.machineDescribe,};if(typeof item.workPlanList !=="undefined"){
obj.workPlanList =
item.workPlanList.length >0? item.workPlanList :[];}if(item.children && item.children.length !=0){this.parseTreeToRow(item.children, data,[...row, obj]);}else{
data.push([...row, obj]);}});return data;},/**
* 合并行或列的计算方法
*/tableSpanMethod({ row, column, rowIndex, columnIndex }){// console.log("row, column, rowIndex, columnIndex");// console.log(// "row, column, rowIndex, columnIndex",// columnIndex,// row,// column,// rowIndex,// columnIndex// );return{rowspan:
columnIndex <3?this.mergeRows(
row[column.property],this.tableData,
rowIndex,
column.property
):1,colspan:1,};},/**
* 表格单元格合并-----行
* @param {Object} value 当前单元格的值
* @param {Object} data 当前表格所有数据
* @param {Object} index 当前单元格的值所在 行 索引
* @param {Object} property 当前列的property
* @returns {number} 待合并单元格数量
*/mergeRows(value, data, index, property){// 判断 当前行的该列数据 与 上一行的该列数据 是否相等if(index !==0&& value.label === data[index -1][property].label){// 返回 0 使表格被跨 行 的那个单元格不会渲染return0;}// 判断 当前行的该列数据 与 下一行的该列数据 是否相等let rowSpan =1;for(let i = index +1; i < data.length; i++){if(value.label !== data[i][property].label){break;}
rowSpan++;}return rowSpan;},},};
样式代码
<style lang="less" scoped>
#pointBox{position: relative;z-index: 2 !important;
// background: red;
// width: 100%;
// height: 10px;}.aaaaa{width: 20px;background: red;height: 25px;position: relative;}//表头指针
.head-pointer{width: 1px;height: 18px;position: absolute;background: red;z-index: 2 !important;}//表头清楚内容
/deep/ .el-table th.el-table__cell{overflow: visible !important;}//占满屏幕
.box-card{height:calc(100vh - 100px);/*示例中顶部区域固定高度190px*/}/deep/ .el-table--enable-row-transition .el-table__body td.el-table__cell{
// height: 47px;}/deep/ .el-table_1_column_1 .el-table_1_column_2 .el-table_1_column_3{z-index: 300 !important;}/deep/ .el-table_1_column_4_column_5_column_6 > .cell{
// width: 3120px !important;padding: 0;}.content-box{
// width: 2000px !important;z-index: 2 !important;text-align: left;position: absolute;top: 0;bottom: 0;}.AAA{
// left: -10px;
// height: 30px;position: relative;width: 15px;height: 100%;z-index: 2 !important;}/deep/ .el-table_1_column_4_column_5_column_6 .is-center .el-table__cell{
// width: 3060px !important;display: flex !important;
// z-index: 1 !important;}//去除鼠标移入
/deep/ .group > .el-table--enable-row-hover .el-table__body tr:hover > td{background-color: white !important;height: 100%;}/deep/
.group
> .el-table--enable-row-hover
.el-table__body
tr:hover
> td
> div{height: 100%;}/deep/ .el-table .cell{overflow: visible !important;padding-left: 0px !important;display: flex; //横向排列
padding-right: 0px !important;width: 100%;text-align: center;}/deep/ .el-table--mini .el-table__cell{
// z-index: 1 !important;padding: 0 !important;}::v-deep .el-table th.el-table__cell > .cell{display: contents;line-height: 15px;}.timeItemBox{display: flex;width: 500px;margin-left: -10px;z-index: 1;z-index: 200 !important;}.timeItem{height: 37.9px;width: 30px;}.wl-real-start{left: 50%;&:after{position: absolute;top: 0;
// left: -5px;left: 0;z-index: 1;content:"";width: 8px;height: 36px;
// border-radius: 50%;background: #fcc300;}}.wl-real-start1{left: 50%;&:after{position: absolute;top: 0;left: 0;z-index: 200 !important;content:"";}}//伸缩加长
.slider-block{margin-top: 5px;margin-left: 20px;float: right;display: flex;line-height: 33px;.slider-block-text{margin-right: 5px;font-size: 16px;}}//超过一行显示
.oneLineCls{text-overflow: -o-ellipsis-lastline;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;line-clamp: 1;-webkit-box-orient: vertical;}.twoLineCls{text-overflow: -o-ellipsis-lastline;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;line-clamp: 2;-webkit-box-orient: vertical;}.ganteTable{margin-top: 20px;}
</style>
本文转载自: https://blog.csdn.net/qq_42696432/article/details/139931242
版权归原作者 天生我材必有用_吴用 所有, 如有侵权,请联系我们删除。
版权归原作者 天生我材必有用_吴用 所有, 如有侵权,请联系我们删除。