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

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


引言

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

目录

    • 引言
    • 渲染效果
    • 拖拽滚动,同产品高亮
      • 小时高度,宽度改变动态效果
    • 全部代码:
    • 优化
      • 优化内容:减少timeInterval的调用,拖动滚动效果,同产品高亮效果。

渲染效果

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

拖拽滚动,同产品高亮

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

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

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

全部代码:

优化

优化内容:减少timeInterval的调用,拖动滚动效果,同产品高亮效果。

<template> <div class=\"home group\"> <el-card :span=\"24\" :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 icon=\"el-icon-s-tools\" size=\"mini\" @click.native=\"startSchedulingProductionFun\" >开始排产</el-button > </el-col> <el-col :span=\"1.5\" style=\"margin-right: 10px\"> <el-button type=\"primary\" plain icon=\"el-icon-s-tools\" size=\"mini\" @click.native=\"proposalFun\" >负荷调整建议</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 @mousedown.native=\"startDrag\" @mousemove.native=\"handleDrag\" @mouseup.native=\"endDrag\" @mouseleave.native=\"endDrag\" v-loading=\"loading\" element-loading-text=\"正在加载处理数据....\" v-if=\"isView\" :virtual-scroll=\"true\" class=\"ganteTable\" :class=\"isFillScreen ? \'fullscreen-table ganteTable\' : \'ganteTable\'\" ref=\"ganTeTable\" :height=\"tableHeight\" :style=\" timeArr.length > 0 ? \'width:\' + tableWidth + \'px;\' : \'width:239px;height:100%\' \" :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\" > <template slot-scope=\"scope\"> <el-popover  placement=\"top-start\"  title=\"工作中心\"  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\" > <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\" > <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> <!-- 表头遍历日期 --> <div v-for=\"(timeArrItem, index1) in timeArr\" :key=\"timeArrItem + index1 + \'\'\" > <el-table-column height=\"47px\" align=\"center\" :label=\"timeArrItem.substr(0, 10)\" > <!-- 表头遍历时间 --> <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 class=\"hour-item\" @mousemove=\"updateXY\">  <span>{{ hourArrItem }}</span>  <div class=\"hour-ten-scale-box\"><div class=\"hour-ten-scale\" v-for=\"x in 5\" :key=\"x\"></div>  </div>  <div class=\"hour-ten-side-box\"><div class=\"hour-ten-side-box-left\"></div><div class=\"hour-ten-side-box-right\"></div>  </div>  </div>  <div  class=\"minute-scale\"  v-if=\"index2 === 0 && index1 === 0\"  :style=\"{ width: tableWidth + \'px\' }\"  ></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 in scope.row.workPlanList.data\":key=\"workItem.onlyId\"class=\"item\"style=\"z-index: 99999\"effect=\"dark\"content=\"Bottom Right 提示文字\"placement=\"bottom-end\"  ><div slot=\"content\"> <p>信息</p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 工序:{{ workItem.workOrder }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 产品名称:{{ workItem.materialName }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 产品编码:{{ workItem.materialNo }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 产线名称:{{ workItem.productLineName }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 产线编码:{{ workItem.productLineSn }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 设备名称:{{ scope.row.index3.label }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 开始时间:{{ workItem.startTime }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 结束时间:{{ workItem.endTime }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 交期时间:{{ workItem.deliverTime }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 工作中心描述:{{ workItem.workCenterDesc }} </p> <p v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" > 工作中心编码:{{ workItem.workCenterSn }} </p> <p v-if=\"workItem.lineChangeFlag === true\"> 状态:换线 </p> <p v-if=\"workItem.restFlag === true\">状态:休息</p></div><div v-if=\" workItem.lineChangeFlag === null && workItem.restFlag === null \" @click=\" highlightSimilarElements( \'A\' + workItem.materialNo + workItem.deliverTime ) \" :draggable=\"true\" :class=\" \'AAA A\' + workItem.materialNo + workItem.deliverTime + \'\' \" :style=\" \'background-color:\' + workItem.color + \';\' + \' position: absolute;\' + timeInterval( workItem.startTime, workItem.endTime, workItem.onlyId ) \"></div><div v-if=\"workItem.lineChangeFlag === true\" @click=\" highlightSimilarElements( \'A\' + workItem.materialNo + workItem.deliverTime ) \" :draggable=\"true\" :class=\" \'AAA A\' + workItem.materialNo + workItem.deliverTime + \'\' \" :style=\" \' position: relative; top: 50%; bottom: 50%;height: 3px\' + \';\' + \'background-color:\' + \'#FF0000\' + \';\' + \' position: absolute;\' + timeInterval( workItem.startTime, workItem.endTime, workItem.onlyId ) \"></div><div v-if=\"workItem.restFlag === true\" @click=\" highlightSimilarElements( \'A\' + workItem.materialNo + workItem.deliverTime ) \" :draggable=\"true\" :class=\" \'AAA A\' + workItem.materialNo + workItem.deliverTime + \'\' \" :style=\" \'background-color:\' + \'#cedcf0;\' + \' position: absolute;\' + timeInterval( workItem.startTime, workItem.endTime, workItem.onlyId ) \"></div>  </el-tooltip>  </div> </template>  </el-table-column> </template> </el-table-column> </div> </el-table> <day-table-view v-if=\"!isView\"></day-table-view> <scheduling-window ref=\"schedulingWindow\" @openSchedulingResultsWindow=\"openSchedulingResultsWindow\" ></scheduling-window> <scheduling-results-window ref=\"schedulingResultsWindow\" @switchView=\"switchView\" ></scheduling-results-window> <suggestions-load-adjustment ref=\"suggestionsLoadAdjustment\" @reScheduleProduction=\"getGanttChartData\" ></suggestions-load-adjustment> <div class=\"slider-block\" v-if=\"isView\"> <div class=\"slider-block-text\">小时高度:</div> <el-slider @change=\"sliderHeightChange\" style=\"width: 200px\" v-model=\"rowHeight\" :min=\"24\" :max=\"72\" :step=\"12\" show-stops > </el-slider> </div> <div class=\"slider-block1\" v-if=\"isView\"> <div v-if=\"isSlider\" 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> <!-- <div class=\"slider-block1-btn\" v-show=\"isView\"> <el-button @click=\"fullScreenFunc\" size=\"mini\"> {{ isFillScreen ? \"退出全屏\" : \"全屏\" }} </el-button> </div> --> </el-card> </div></template><script>import { getGanttChart } from \"@/api/ganttChart/ganttChart\";import dayTableView from \"./gentterTable.vue\";import schedulingWindow from \"./startSchedulingWindow.vue\";import schedulingResultsWindow from \"./schedulingResultsWindow.vue\";import suggestionsLoadAdjustment from \"./suggestionsLoadAdjustment.vue\";export default { name: \"dailyScheduling\", components: { dayTableView, schedulingWindow, schedulingResultsWindow, suggestionsLoadAdjustment, }, data() { return { styleCache: {}, //存放缓存结果 highlightedClass: null, dragging: false, startX: 0, startY: 0, scrollLeft: 0, scrollTop: 0, ganTeTable: null, // 初始化表格引用 isFillScreen: false, // 是否全屏 loading: false, //表格数据处理 isView: true, content: \"内容\", isSlider: true, //是否显示缩放和拉长 minWidth: 24, //最小缩放 maxWidth: 72, //最大缩放 rowHeight: 24, //每一行的高度 tableWidth: 0, pointObj: { pointX: 340, pointBoxLeft: 0, //指针盒子距离左侧的偏移量 }, eleData: { dayList: [], startTime: \"\", // 开始时间 endTime: \"\", // 结束时间 workcenterList: [], }, tableHeight: 0, //table的高度 oneHourPx: 24, //一小时间隔15px 一分钟间隔0.25px oneMinutePx: 0.4, //一分钟0.4px tableData: null, //表格数据 latticeWidth: 30, //一个单元格的宽度最小24px timeArr: [], //天数集合 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\", ], tableKey: 0, //值改变更新table earliestTime: \"\", //最早时间 latestTime: \"\", //最晚时间 conWidth: 0, usedKeys: new Set(), }; }, 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+滚轮缩放 let scrollFunc = function (e) { e = e || window.event; if (e.wheelDelta && event.ctrlKey) { //IE/Opera/Chrome event.returnValue = false; } else if (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天 则官渡为39 if (this.timeArr.length <= 2) { this.latticeWidth = 24; this.minWidth = 24; this.maxWidth = 72; } // console.log(\"我被执行了\", this.timeArr.length); if (this.timeArr.length >= 2) { 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; this.tableWidth = this.widthAA + 240; }); this.ganTeTable = this.$refs.ganTeTable.$el.querySelector( \".el-table__body-wrapper\" ); }, computed: { // timeInterval() { // return (startTime, endTime,id) => { // console.log(\"我被执行了\", startTime, endTime,id); // let time = new Date(endTime) - new Date(startTime); // 获取任务开始时间和任务结束时间的相差时间戳 // let minuteDiff = Math.floor(time / (60 * 1000)); // 相差时间间隔 // let initialTime = new Date(startTime) - new Date(this.timeArr[0]); // 获取距离最开始的距离 // let inittiDiff = Math.floor(initialTime / (60 * 1000)); // let obj = { // widthPx: minuteDiff * (this.latticeWidth / 60), // startPx: inittiDiff * (this.latticeWidth / 60), // }; // return \"width:\" + obj.widthPx + \"px;left:\" + obj.startPx + \"px;\"; // }; // }, }, methods: { timeInterval(startTime, endTime, id) { // Check cache first const cacheKey = `${startTime}_${endTime}_${id}`; if (this.styleCache[cacheKey]) { return this.styleCache[cacheKey]; } console.log(\"我被执行了\", startTime, endTime, id); let time = new Date(endTime) - new Date(startTime); // 获取任务开始时间和任务结束时间的相差时间戳 let minuteDiff = Math.floor(time / (60 * 1000)); // 相差时间间隔 let initialTime = new Date(startTime) - new Date(this.timeArr[0]); // 获取距离最开始的距离 let inittiDiff = Math.floor(initialTime / (60 * 1000)); let obj = { widthPx: minuteDiff * (this.latticeWidth / 60), startPx: inittiDiff * (this.latticeWidth / 60), }; const style = `width:${obj.widthPx}px;left:${obj.startPx}px;`; // Store in cache this.styleCache[cacheKey] = style; return style; }, generateRandomKey() { let key; do { key = Math.random().toString(36).substr(2, 9); // Generate a random string key } while (this.usedKeys.has(key)); // Ensure key is unique this.usedKeys.add(key); // Add key to usedKeys set return key; }, // 负荷调整建议 proposalFun() { this.$refs.suggestionsLoadAdjustment.open(); }, // 开始排产弹窗 openSchedulingResultsWindow() { this.showDialogVisible = false; this.$refs.schedulingResultsWindow.open(); }, highlightSimilarElements(targetClass) { // 先移除所有元素的高亮状态 if (this.highlightedClass) { document.querySelectorAll(`.${this.highlightedClass}`).forEach((el) => { el.classList.remove(\"highlighted\"); }); } // 更新当前要高亮的类名 this.highlightedClass = targetClass; // 查找所有具有目标类名的元素并应用高亮 document.querySelectorAll(`.${targetClass}`).forEach((el) => { el.classList.add(\"highlighted\"); }); }, // 开始排程的英文 startSchedulingProductionFun() { this.$refs.schedulingWindow.showDialogVisible = true; }, // 当鼠标按下时触发,记录起始位置和滚动条位置。 startDrag(e) { this.dragging = true; this.startX = e.pageX; this.startY = e.pageY; this.scrollLeft = this.ganTeTable.scrollLeft; this.scrollTop = this.ganTeTable.scrollTop; }, // 当鼠标移动时触发,计算鼠标移动距离并更新滚动条位置。 handleDrag: _.throttle(function (e) { if (this.dragging) { const dx = e.pageX - this.startX; const dy = e.pageY - this.startY; this.ganTeTable.scrollLeft = this.scrollLeft - dx; this.ganTeTable.scrollTop = this.scrollTop - dy; } }, 16), // 使用节流函数,16ms对应60fps的更新频率 // 鼠标松开,移出 endDrag() { this.dragging = false; }, //全屏退出全屏 fullScreenFunc() { if (!document.fullscreenElement) { this.enterFullScreen(); this.isFillScreen = true; this.latticeWidth = 72; this.sliderWidthChange(); } else { this.exitFullScreen(); this.latticeWidth = 39; this.sliderWidthChange(); this.isFillScreen = false; } }, //进入全屏 enterFullScreen() { let element = document.documentElement; if (element.requestFullscreen) { element.requestFullscreen(); } else if (element.mozRequestFullScreen) { /* Firefox */ element.mozRequestFullScreen(); } else if (element.webkitRequestFullscreen) { /* Chrome, Safari & Opera */ element.webkitRequestFullscreen(); } else if (element.msRequestFullscreen) { /* IE/Edge */ element.msRequestFullscreen(); } }, //退出全屏 exitFullScreen() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { /* Firefox */ document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */ document.webkitExitFullscreen(); } else if (document.msExitFullscreen) { /* IE/Edge */ document.msExitFullscreen(); } this.isFillScreen = false; }, async getGanttChartData() { this.loading = true; console.log(\"开始\"); //判断是否传递过来id let id = null; if (typeof this.$route.query.id !== \"undefined\") { id = JSON.parse(this.$route.query.id); } let repos = null; await getGanttChart() .then((res) => { repos = res; this.processGanttData(repos); this.loading = false; }) .catch((error) => { // 请求失败的处理 console.error(\"请求数据失败:\", error); this.loading = false; // 可选:设置加载状态为false // 可以进行错误处理或者用户提示 }); }, processGanttData(repos) { // 在获取到数据后进行处理 this.timeArr = repos.data.dayList.map((element) => element + \" 00:00:00\"); this.eleData.workcenterList = repos.data.workcenterList; this.treeToTableData(); for (let i = 0; i < this.tableData.length; i++) { for (let j = 0; j < this.tableData[i].workPlanList.data.length; j++) { this.tableData[i].workPlanList.data[j].onlyId = this.generateRandomKey(); // this.tableData[i].workPlanList.data[j].pxObj={...this.timeInterval(this.tableData[i].workPlanList.data[j].startTime,this.tableData[i].workPlanList.data[j].endTime)} } } // 根据时间长度设置 latticeWidth if (this.timeArr.length <= 2) { this.latticeWidth = 24; this.minWidth = 24; this.maxWidth = 72; } else if (this.timeArr.length >= 3) { this.latticeWidth = 21; this.minWidth = 21; this.maxWidth = 72; } else 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.tableWidth = this.widthAA + 240; // 更新表格布局 this.$nextTick(() => { if (this.$refs.ganTeTable) { this.$refs.ganTeTable.doLayout(); } this.$forceUpdate(); }); }, //切换视图 switchView() { this.isView = !this.isView; if (this.isView === true) { this.getGanttChartData(); } }, //物料信息展开 //行高回调 iCellStyle() { return \"height:\" + this.rowHeight + \"px\"; }, //改变行高 sliderHeightChange() { //重新布局表格 this.$nextTick(() => { this.styleCache = {}; this.iCellStyle(); this.$refs.ganTeTable.doLayout(); // this.tableKey = Math.random(); }); }, //改变行宽 sliderWidthChange() { //重新布局表格 this.$nextTick(() => { this.styleCache = {}; this.widthAA = this.timeArr.length * 24 * this.latticeWidth; this.tableWidth = this.widthAA + 240; 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 style=\"width: 1px; height: 225px; position: absolute; background: red;top:-18px; left:${ x - this.pointObj.pointBoxLeft }px;\" id=\"head-pointer\" class=\"head-pointer\"> 
`; }); this.boble = false; }, parentW(index1, index2) { if (this.$refs[index1 + \"-\" + index2 + 5]) { // console.log(this.$refs[index1 + \"-\" + index2 + 5][0].clientWidth); return this.$refs[index1 + \"-\" + index2 + 5][0].clientWidth; } else { return 0; } }, parentH(index1, index2) { if (this.$refs[index1 + \"-\" + index2 + 5]) { // console.log(this.$refs[index1 + \"-\" + index2 + 5][0].clientHeight); return this.$refs[index1 + \"-\" + index2 + 5][0].clientHeight; } else { return 0; } }, draggableStart() { // console.log(this.tableData[0].workPlanList.data); }, draggableEnd() { // console.log(this.tableData[0].workPlanList.data); }, /** * 计算两个时间的间隔 * 入参 开始时间,结束时间 * 回参 返回一个任务距离最开始时间的分钟[距离],和一个任务开始时间和结束时间的分钟[距离], */ // timeInterval(startTime, endTiem) { // console.log(\"我被执行了\",startTime, endTiem) // let time = new Date(endTiem) - new Date(startTime); //获取任务开始时间和任务结束时间的相差时间戳 // let minuteDiff = Math.floor(time / (60 * 1000)); //相差时间间隔 // let initialTime = new Date(startTime) - new Date(this.timeArr[0]); //获取距离最开始的距离 // // ,new Date(startTime),new Date(this.timeArr[0]) // // console.log(\"~~~~~~~~~~~\", 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\") { // for(let i=0;i<itemc.workPlanList.length;i++){ // itemc.workPlanList[i].pxObj = null; // itemc.workPlanList[i].pxObj = this.timeInterval(itemc.workPlanList[i].startTime,itemc.workPlanList[i].endTime) // } obj.workPlanList = { data: itemc.workPlanList }; } }); tableData.push(obj); }); this.tableData = tableData; }, /** * 递归-----将树结构数据格式,转化为,二维数组 表格形式 * @param node 树的源数据 * @param data 树转化为二维数组的数据 * @param row 临时存储数据 * @returns {*[]} */ parseTreeToRow(node, data = [], row = []) { console.log(\"parseTreeToRow执行中\"); 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 使表格被跨 行 的那个单元格不会渲染 return 0; } // 判断 当前行的该列数据 与 下一行的该列数据 是否相等 let rowSpan = 1; for (let i = index + 1; i < data.length; i++) { if (value.label !== data[i][property].label) { break; } rowSpan++; } return rowSpan; }, },};</script><style>.highlighted { box-shadow: inset 0 0 0 3px yellow !important; /* 内置阴影,用作边框 */}</style><style lang=\"less\" scoped>.hour-item span { position: relative; bottom: -9px;}.hour-ten-side-box { width: 100%; height: 10px; position: relative; bottom: -6px; .hour-ten-side-box-left { width: 1px; height: 14px; background: #263c59; position: relative; left: -1px; float: left; } .hour-ten-side-box-right { width: 1px; height: 14px; background: #263c59; position: relative; right: -1px; float: right; }}.hour-ten-scale-box { width: 100%; display: flex; justify-content: space-evenly; position: relative; bottom: -16px;}.hour-ten-scale { height: 5px; width: 1px; background: #263c59;}#pointBox { position: relative; z-index: 2 !important;}.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; position: fixed; z-index: 10002; bottom: 0; right: 20px; display: flex; line-height: 33px; .slider-block-text { margin-right: 5px; font-size: 16px; }}.slider-block1 { margin-top: 5px; margin-left: 20px; z-index: 10002; float: right; position: fixed; bottom: 0; right: 344px; display: flex; line-height: 33px; .slider-block-text { margin-right: 5px; font-size: 16px; }}.slider-block1-btn { margin-top: 5px; margin-left: 20px; z-index: 10002; float: right; position: fixed; display: flex; line-height: 33px; bottom: 9px; right: 639px;}//超过一行显示.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;}.minute-scale { position: absolute; z-index: 2 !important;}/* 在你的全局样式或组件的标签内 */.fullscreen-table { position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 100%; height: 100%; margin: 0 auto; z-index: 1002;}</style>