引言
在玻璃加工行业,高效管理切割、磨边、洗、钢化、丝印等复杂工序对于提升生产效率至关重要。本文将介绍如何利用Vue.js框架结合Element UI组件库,自定义实现一个工序甘特图,以可视化展示各道工序的时间线与进度,为生产调度带来便利。
渲染效果
同产品高亮
拖拽滚动,同产品高亮
小时高度,宽度改变动态效果
全部代码:
优化
优化内容:减少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"> </div>`;
});
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;
}
/* 在你的全局样式或组件的<style>标签内 */
.fullscreen-table {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
margin: 0 auto;
z-index: 1002;
}
</style>