0


Vue结合Element UI的el-table打造加工工序甘特图可视化解决方案

引言

在玻璃加工行业,高效管理切割、磨边、洗、钢化、丝印等复杂工序对于提升生产效率至关重要。本文将介绍如何利用Vue.js框架结合Element UI组件库,自定义实现一个工序甘特图,以可视化展示各道工序的时间线与进度,为生产调度带来便利。

效果

Vue结合Element UI的el-table打造加工工序甘特图可视化解决方案

小时高度,宽度改变动态效果

Vue结合Element UI的el-table打造加工工序甘特图可视化解决方案

全部代码:

视图部分

<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>
标签: vue.js ui 甘特图

本文转载自: https://blog.csdn.net/qq_42696432/article/details/139931242
版权归原作者 天生我材必有用_吴用 所有, 如有侵权,请联系我们删除。

“Vue结合Element UI的el-table打造加工工序甘特图可视化解决方案”的评论:

还没有评论