2023-03-15
2023-03-14 本文已影响0人
大佬教我写程序
<template>
<div class="gantt" v-loading="loading" ref="ganttRoot">
<div id="wrapper" class="gantt-content" @click="hiddenBlockMenu($event)" @mouseup="ganttMainUp($event)">
<!-- @mouseleave="ganttMainLeave($event)" -->
<!-- @mousemove="ganttMainMove($event)" -->
<!-- @mousedown="ganttMainDown($event)" -->
<!-- @scroll="wrapperScroll($event)" -->
<div class="gantt-block">
<div></div>
<div>资源</div>
</div>
<div class="gantt-calendar">
<div class="calendar-dom">
<div
class="calendar-li"
v-for="(item, index) in timeList"
:key="index"
:style="{ width: parseInt(setWidth * ganttRate) + 'px' }"
>
<div class="calendar-day" :style="{ color: item.color }">{{ item.time }}</div>
<div class="calendar-time">
<div class="calendar-h" v-for="(item, index) in hourList" :key="index">
<template v-if="ganttRate > 0.192">
{{ item }}
</template>
<template v-else-if="ganttRate == 0.192">
{{ parseInt(item) % 4 == 0 ? item : '' }}
</template>
</div>
</div>
<div class="gantt-time"></div>
</div>
<div
class="gantt-dom-range"
v-show="ganttDomRange.width > 0"
:style="{
width: ganttDomRange.width + 'px',
left: ganttDomRange.left + 'px'
}"
></div>
<div
class="gantt-dom-move"
v-show="ganttDomMove.width > 0"
:style="{
width: ganttDomMove.width + 'px',
left: ganttDomMove.left + 'px',
backgroundColor: ganttDomMove.color
}"
></div>
</div>
</div>
<div class="gantt-aside">
<div class="aside-list">
<div
class="aside-li"
v-for="(item, index) in asideList"
:key="index"
:processId="item.resourceId"
@drop="ganttRowDrop($event)"
@dragover="allowDrop($event)"
:class="{
mainType: item.mainType == 'MAIN',
adjustOptional: adjustOptional.indexOf(item.resourceId) > -1
}"
>
<span>{{ item.resourceCode }}</span>
</div>
</div>
</div>
<div
class="gantt-main"
:style="{
width: setWidth * timeList.length * ganttRate + 100 + 'px',
height: asideList.length * 31 + 60 + 'px'
}"
@dragend="mainDragEnd"
@mousedown="maindDown($event)"
@mousemove="maindMove($event)"
@mouseleave="maindLeave($event)"
@mouseup="maindUp"
>
<div class="nodata" v-if="asideList.length == 0">暂无数据!</div>
<div class="gantt-col-bg">
<div
class="gantt-col-ul"
:class="{ 'gantt-col-ol': ganttLi == 0 }"
v-for="(item, index) in ganttCol"
:key="index"
:style="{ width: parseInt(setWidth * ganttRate) + 'px' }"
>
<div
class="gantt-col-li"
:style="{ width: (1 / ganttLi) * 100 + '%' }"
v-for="(item, index) in ganttLi"
:key="index"
></div>
</div>
</div>
<div
class="gantt-row"
v-for="(item, index) in ganttRowData"
:key="index"
:processId="item.resourceId"
@drop="ganttRowDrop($event)"
@dragover="allowDrop($event)"
@mouseup="ganttRowUp($event)"
:class="{ adjustOptional: adjustOptional.indexOf(item.resourceId) > -1 }"
>
<template v-if="item.restData">
<template v-for="info in item.restData.blocks">
<div
v-if="info.startTime != info.endTime"
class="rest-dom"
:key="info.index"
:style="{
left: ganttDomLeft(info.startTime) + 'px',
width: ganttDomWidth(info.startTime, info.endTime) + 'px'
}"
></div>
</template>
</template>
<template v-if="item.ganttData">
<template v-for="info in item.ganttData.blocks">
<div
v-if="info.startTime != info.endTime"
class="gantt-dom"
:id="item.ganttData.processId + '&' + info.blockId"
:key="info.blockId"
:blockId="info.blockId"
:top="index * 31 + 5"
:style="{
left: ganttDomLeft(info.startTime) + 'px',
width: ganttDomWidth(info.startTime, info.endTime) + 'px',
height:
info.properties.multipleCount == 1
? 13 + 'px'
: 31 / info.properties.multipleCount - info.properties.multipleCount * 3 + 'px',
top:
(31 / info.properties.multipleCount - info.properties.multipleCount * 3 + 3) *
info.properties.multipleSort +
3 +
'px',
backgroundColor: info.properties.status =='PLANNED' && info.properties.lockStatus == 'LOCKED' ? '#e5994b' : info.blockColor,
borderColor: info.borderColor
}"
:class="{ 'gantt-dom-act': actblockId.includes(item.ganttData.processId + '&' + info.blockId) }"
:title="ganttDetails(info)"
draggable="true"
@dragstart="ganttDragStart($event, item, info)"
@drag="getGanttMove($event)"
@contextmenu.stop="blocksContextmenu($event, info, item.ganttData.processId + '&' + info.blockId)"
@click="getGanttDom($event, item.ganttData.processId + '&' + info.blockId)"
>
{{ info.blockName }}
<div
v-for="(sub, subindex) in info.properties.subBlocks"
:key="subindex"
style="position: absolute; height: 100%; top: 0px"
:style="{
width: ganttDomWidth(sub.startTime, sub.endTime) + 'px',
left: ganttDomLeft(sub.startTime) - ganttDomLeft(info.startTime) + 'px',
backgroundColor: sub.subBlockColor
}"
></div>
<div v-if="info.properties.alarm" class="trangle"></div>
</div>
</template>
</template>
</div>
<div
v-if="planStartDate < baseDate && baseDate < planStartDate + 24 * 3600 * 1000 * afterDays"
class="base-time"
:style="{ left: ganttDomLeft(baseDate) + 100 + 'px' }"
></div>
<div v-show="isShowBlockMenu" class="block-menu">
<div @click="blockMenu('选中工序')">选中工序</div>
<div @click="blockMenu('强调')">强调</div>
<div @click="blockMenu('取消强调')">取消强调</div>
<div @click="blockMenu('冻结')">冻结</div>
<div @click="blockMenu('解锁')">解锁</div>
<div class="gotoNewDom">
跳转至页面
<div class="gotoNew" @click="blockMenu('制造订单展开')">制造订单展开</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {
getScheduleperiod,
getResource,
getGanttInfo,
getCodeToMain,
getRest,
getGanttline,
handworkschedule
} from '@/api/planSchedule/gantt';
import { lockOperation, unlockOperation } from '@/api/planSchedule/productPeriod';
// import { restData, ganttData } from './ganttData';
import moment from 'moment'; // moment(text).format('YYYY-MM-DD HH:mm:ss')
import bus from '@/utils/bus';
export default {
name: 'gantt',
data() {
return {
loading: false,
setWidth: 720,
domWidth: 0,
timeRange: 0,
ganttRate: 0.456,
ganttCol: 8,
ganttLi: 8,
preDays: 0,
afterDays: 7,
planStartDate: null,
startDate: null,
endDate: null,
baseDate: null,
onlyHasTasks: false,
onlyMain: false,
resourceCodeForGantt: '',
dates: [],
hourList: ['02', '04', '06', '08', '10', '12', '14', '16', '18', '20', '22'],
asideList: [],
asideListCopy: [],
timeList: [],
restData: [],
ganttData: [],
ganttRowData: [],
isShowBlockMenu: null,
moveStartX: 0,
moveStartY: 0,
queryStartDate: null,
queryEndDate: null,
resourceIds: '',
actblockId: '',
adjustOptional: '',
subProcess: {},
ganttDomRange: {},
ganttDomMove: {},
isGanttDomMove: true,
isSelect: false,
selectBox: null,
downX: 0,
downY: 0,
moveX: 0,
moveY: 0,
ganttTop: 0
};
},
props: {
draggleType: String,
lineType: String,
searchInfo: {
type: Object,
default: () => {
return {};
}
}
},
mounted() {
// this.getScheduleperiod();
bus.$on('adjustOptional', e => {
console.log('onbus----->', e);
this.ganttMainEnter(e);
});
this.ganttTop = document.querySelector('.yhl-table-productPeriod').offsetHeight + 183
},
beforeDestroy() {
bus.$off('adjustOptional');
},
watch: {
draggleType() {
if (this.draggleType === 'all') {
this.$emit('resetAllData');
this.blockMenu('取消强调');
}
},
lineType() {
this.blockMenu('取消强调');
}
},
methods: {
initGanttData(e) {
this.baseDate = e.baseDate;
// this.lockEndDate = e.lockEndDate;
let startDate = moment(e.planStartDate).format('YYYY-MM-DD');
this.queryStartDate = startDate;
this.planStartDate = new Date(startDate + ' 00:00:00').getTime();
this.queryEndDate = moment(e.planStartDate + 24 * 3600 * 1000 * this.afterDays).format('YYYY-MM-DD');
this.getResource();
this.unstress();
},
setSubProcess(e) {
// 工序表格子数据点击,强调甘特图
let obj = { queryDate: e.processStart };
this.subProcess = e;
this.queryGanttDate(obj);
},
getScheduleperiod() {
getScheduleperiod()
.then(res => {
if (res.data.success) {
const { baseDate, endDate, lockEndDate, planStartDate } = res.data.data;
// this.endDate = endDate
this.baseDate = baseDate;
this.lockEndDate = lockEndDate;
this.planStartDate = planStartDate;
this.queryStartDate = moment(this.planStartDate).format('YYYY-MM-DD');
this.queryEndDate = moment(this.planStartDate + 24 * 3600 * 1000 * this.afterDays).format('YYYY-MM-DD');
this.getResource();
}
})
.catch(err => {
console.log(err);
});
},
queryGanttDate(e) {
this.queryStartDate = e.queryDate;
this.onlyMain = e.onlyMain;
this.onlyHasTasks = e.onlyHasTasks;
this.resourceCodeForGantt = e.resourceCodeForGantt;
let time = new Date(e.queryDate + ' 00:00:00').getTime();
this.planStartDate = time;
this.queryEndDate = moment(time + 24 * 3600 * 1000 * this.afterDays).format('YYYY-MM-DD');
this.unstress();
if (e.mainType == 'onlyMain') {
this.getGanttRowData();
return;
}
this.getResource();
},
getResource() {
let info = {
startDate: this.queryStartDate,
endDate: this.queryEndDate,
resourceCode: this.resourceCodeForGantt,
hasTask: this.onlyHasTasks
};
this.loading = true;
getResource(info)
.then(res => {
this.loading = false;
if (res.data.success) {
let _resourceData = res.data.data;
this.startDate = _resourceData.startDate;
this.endDate = this.planStartDate + this.ganttCol * 24 * 3600 * 1000;
this.dates = _resourceData.dates;
let categories = _resourceData.categories;
let ids = [];
let arr = categories.filter(e => {
if (!ids.includes(e.resourceId)) {
ids.push(e.resourceId);
return e;
}
});
let _arr = arr.sort((a, b) => {
return a.indexNum - b.indexNum;
});
this.asideList = _arr;
this.asideListCopy = _arr;
// 分页延迟请求
this.ganttData = [];
this.restData = [];
let len = Math.ceil(ids.length / 20);
for (let x = 0; x < len; x++) {
setTimeout(() => {
this.resourceIds = ids.slice(x * 20, (x + 1) * 20).join(',');
this.getGanttInfo();
this.getTimeList();
}, x * 1500);
}
} else {
this.$message.warning(res.data.data ? res.data.data.msg : '获取甘特资源失败!');
}
})
.catch(err => {
this.loading = false;
console.log(err);
});
},
getGanttInfo(ids) {
let form = new FormData();
form.append('startDate', this.queryStartDate);
form.append('endDate', this.queryEndDate);
form.append('resourceIds', ids || this.resourceIds);
getGanttInfo(form)
.then(res => {
if (res.data.success) {
if (ids) {
this.setGanttRowData(res.data.processes);
return;
}
this.getRest();
this.ganttData = this.ganttData.concat(res.data.processes);
}
})
.catch(err => {
console.log(err);
});
},
getRest() {
let form = new FormData();
form.append('startDate', this.queryStartDate);
form.append('endDate', this.queryEndDate);
form.append('resourceIds', this.resourceIds);
getRest(form)
.then(res => {
if (res.data.success) {
this.restData = this.restData.concat(res.data.processes);
this.getGanttRowData();
}
})
.catch(err => {
console.log(err);
});
},
getTimeList() {
let list = [];
let planStartDate = this.planStartDate;
for (let i = 0; i < this.ganttCol; i++) {
let date = planStartDate + i * 24 * 3600 * 1000;
let _date = new Date(date);
let day = _date.getDay();
let dayStr = '';
let obj = {};
switch (day) {
case 0:
dayStr = 'Sun';
obj.color = 'red';
break;
case 1:
dayStr = 'Mon';
break;
case 2:
dayStr = 'Tues';
break;
case 3:
dayStr = 'Wed';
break;
case 4:
dayStr = 'Thur';
break;
case 5:
dayStr = 'Fri';
break;
case 6:
dayStr = 'Sat';
obj.color = 'red';
break;
}
if (this.ganttRate < 0.065) {
obj.time = moment(_date).format('DD');
} else if (this.ganttRate == '0.097') {
obj.time = moment(_date).format('MM-DD');
} else if (this.ganttRate == '0.192') {
obj.time = moment(_date).format('MM-DD') + dayStr;
} else {
obj.time = moment(_date).format('YYYY-MM-DD') + dayStr;
}
list.push(obj);
}
this.timeList = list;
this.domWidth = this.setWidth * list.length * this.ganttRate;
this.timeRange = this.endDate - this.planStartDate;
console.log(this.planStartDate, this.domWidth, this.timeRange);
},
getGanttRowData() {
let arr = [];
this.ganttRowData = [];
this.asideList = this.asideListCopy.filter(e => {
if (!this.onlyMain || e.mainType == 'MAIN') {
let obj = {};
obj.resourceId = e.resourceId;
obj.mainType = e.mainType;
obj.restData = this.restData.find(n => {
return e.resourceId == n.processId;
});
obj.ganttData = this.ganttData.find(n => {
return e.resourceId == n.processId;
});
arr.push(obj);
}
return !this.onlyMain || e.mainType == 'MAIN';
});
console.log(arr);
this.ganttRowData = arr;
// 子工序强调甘特
if (this.subProcess.operationId) {
setTimeout(() => {
this.stress();
}, 50);
}
},
ganttDomLeft(time) {
return ((time - this.planStartDate) / this.timeRange) * this.domWidth;
},
ganttDomWidth(start, end) {
if (end - start < 1) return 0;
return ((end - start) / this.timeRange) * this.domWidth;
},
ganttDragStart(e, item, info) {
// 显示可拖拽行
// this.removeMainMove();
this.isSelect = false;
this.ganttDomRange = {
width: this.ganttDomWidth(info.properties.earliestStartTime, info.properties.latestEndTime) + 10,
left: this.ganttDomLeft(info.properties.earliestStartTime) - 5
};
let ids = info.properties.optionalResources || [];
let arr = [];
this.asideListCopy.forEach(e => {
if (ids.indexOf(e.resourceId) > -1 && e.mainType == item.mainType) {
arr.push(e.resourceId);
}
});
this.adjustOptional = arr.join(',');
// 过滤工序
let statusObj = {
FINISHED: '已完工',
STARTED: '已开始',
PLAN_IDENTIFIED: '已确定计划'
};
let status = info.properties.status;
if (status == 'FINISHED' || status == 'STARTED' || status == 'PLAN_IDENTIFIED') {
this.$message.warning(statusObj[info.properties.status] + ' 的工序不可以操作!');
return;
}
// 自定义拖拽样式
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
canvas.setAttribute('id', 'dragCanvas');
context.fillStyle = '#65C16F';
context.fillRect(0, 0, 100, 21);
context.font = '12px calibri';
context.fillStyle = '#fff';
context.fillText(info.blockName, 15, 15);
document.body.append(canvas);
e.dataTransfer.setDragImage(canvas, 50, 15);
let obj = {
blockIds: [info.blockId], //待排任务[调整的]
sourceProcessId: item.resourceId //原始process,起点
};
e.dataTransfer.setData('ganttObj', JSON.stringify(obj));
},
ganttRowDrop(e) {
this.adjustOptional = '';
let obj = e.dataTransfer.getData('ganttObj') || '{}';
let processid = e.target.getAttribute('processid') || '';
if (!processid) {
processid = e.target.parentNode.parentNode.getAttribute('processid');
}
obj = JSON.parse(obj);
(obj.adjustmentType = 'ADJUSTMENT'), //取消CANCEL,调整 ADJUSTMENT,新增ADD
(obj.startDate = this.queryStartDate), //开始日期[没拖到任务上时传]
(obj.endDate = this.queryEndDate), //结束日期[没拖到任务上时传]
(obj.operType = 'PROCESS'), //操作类型:排在资源上 RESOURCE,排在process上 PROCESS
(obj.processId = processid), //目标process,终点
console.log('ganttRowDrop===>', obj);
this.handworkschedule([obj]);
document.getElementById('dragCanvas').remove();
return;
},
allowDrop(ev) {
ev.stopPropagation();
ev.preventDefault();
},
getGanttMove(ev) {
if (this.isGanttDomMove) {
this.isGanttDomMove = false;
let color = '#409EFF';
let x = parseInt(ev.target.offsetLeft + ev.layerX - ev.target.offsetWidth / 2);
let _x = parseInt(this.ganttDomRange.left + 5);
if (x < _x || x + ev.target.offsetWidth + 5 > _x + this.ganttDomRange.width) {
color = '#f00';
}
this.ganttDomMove = {
left: x,
color: color,
width: ev.target.offsetWidth
};
setTimeout(() => {
this.isGanttDomMove = true;
}, 100);
}
},
mainDragEnd() {
this.ganttDomRange = {};
this.ganttDomMove = {};
},
maindDown(ev) {
if (ev.target.className !== 'gantt-row') {
return
}
// 鼠标按下时才允许处理鼠标的移动事件
this.isSelect = true;
let selectBox = null;
selectBox = document.createElement('div');
// 框选div 样式
selectBox.style.cssText =
'position:absolute;width:0px;height:0px;border:1px dashed #0099FF;background-color:#C3D5ED;z-index:999;opacity:0.4;display:none;';
// 添加到gantt-main下
document.querySelector('.gantt-main').appendChild(selectBox);
// 取得鼠标按下时的坐标位置
let top = document.getElementById('wrapper').scrollTop;
let left = document.getElementById('wrapper').scrollLeft;
this.downX = ev.clientX - 213 + left;
this.downY = ev.clientY - this.ganttTop + top;
//设置你要画的矩形框的起点位置
selectBox.style.left = this.downX + 'px';
selectBox.style.top = this.downY + 'px';
this.selectBox = selectBox;
ev.stopPropagation();
ev.preventDefault();
},
maindMove(ev) {
if (this.isSelect) {
// 取得鼠标移动时的坐标位置
let top = document.getElementById('wrapper').scrollTop;
let left = document.getElementById('wrapper').scrollLeft;
this.moveX = ev.clientX - 213 + left;
this.moveY = ev.clientY - this.ganttTop + top;
// 显示框选元素
let selectBox = this.selectBox;
if (selectBox.style.display == 'none') {
selectBox.style.display = '';
}
selectBox.style.left = Math.min(this.moveX, this.downX) + 'px';
selectBox.style.top = Math.min(this.moveY, this.downY) + 'px';
selectBox.style.width = Math.abs(this.moveX - this.downX) + 'px';
selectBox.style.height = Math.abs(this.moveY - this.downY) + 'px';
// A part
if (this.moveX < this.downX && this.moveY < this.downY) {
selectBox.style.left = this.moveX;
selectBox.style.top = this.moveY;
}
// B part
if (this.moveX > this.downX && this.moveY < this.downY) {
selectBox.style.left = this.downX;
selectBox.style.top = this.moveY;
}
// C part
if (this.moveX < this.downX && this.moveY > this.downY) {
selectBox.style.left = this.moveX;
selectBox.style.top = this.downY;
}
// D part
if (this.moveX > this.downX && this.moveY > this.downY) {
selectBox.style.left = this.downX;
selectBox.style.top = this.downY;
}
ev.stopPropagation();
ev.preventDefault();
}
},
maindUp() {
//鼠标抬起,就不允许在处理鼠标移动事件
this.isSelect = false;
let selectBox = this.selectBox;
if (!selectBox || selectBox.offsetWidth < 1 || selectBox.offsetHeight < 1) {
return
}
let list = document.getElementsByClassName('gantt-dom');
for (let i = 0; i < list.length; i++) {
// 将移动的div的四个点和和div元素的四个点进行比较
if (
//判断div元素 右边框的位置大于移动div的左起始点
selectBox.offsetLeft - 100 < list[i].offsetLeft + list[i].offsetWidth &&
//判断div元素 下边框的位置大于移动div的上起始点
parseInt(list[i].getAttribute('top')) + list[i].offsetHeight > selectBox.offsetTop - 60 &&
// 判断div元素左边框的位置小于移动div的右起始点
selectBox.offsetLeft - 100 + selectBox.offsetWidth > list[i].offsetLeft &&
// 判断div元素上边框的位置小于移动div的下起始点
selectBox.offsetTop - 60 + selectBox.offsetHeight > parseInt(list[i].getAttribute('top'))
) {
//将已选中的样式改变
if (list[i].className.indexOf('gantt-dom-act') == -1) {
// list[i].className = list[i].className + ' gantt-dom-act';
this.actblockId += '#' + list[i].getAttribute('id')
}
} else {
//如果没有选中则清除样式
if (list[i].className.indexOf('gantt-dom-act') != -1) {
// list[i].className = 'gantt-dom';
let id = list[i].getAttribute('id')
this.actblockId = this.actblockId.replace(id, '');
}
}
}
//隐藏图层
if (this.selectBox) {
document.querySelector('.gantt-main').removeChild(this.selectBox);
this.selectBox = null
}
},
maindLeave() {
//鼠标移出main div 清除框选div
this.isSelect = false;
//隐藏图层
if (this.selectBox) {
document.querySelector('.gantt-main').removeChild(this.selectBox);
this.selectBox = null
}
},
wrapperScroll(ev) {
if (ev.target.scrollTop + ev.target.clientHeight == ev.target.scrollHeight) {
console.log('触底了!');
// this.resourceIdsIndex = this.resourceIdsIndex + 10;
// let ids = this.resourceIdsCopy.slice(this.resourceIdsIndex, this.resourceIdsIndex + 10).join(',');
// if (ids) {
// // this.resourceIds = ids;
// console.log(ids)
// }
}
},
handworkschedule(info, tableType) {
// adjustmentType: 'ADJUSTMENT', //取消CANCEL,调整 ADJUSTMENT,新增ADD
// blockIds: sourceProcessObj[key], //待排任务[调整的]
// preBlockId: preBlockId, //前一个任务
// nextBlockId: '', //下一个任务
// sourceProcessId: key, //原始process,起点
// startDate: this.queryStartDate, //开始日期[没拖到任务上时传]
// endDate: this.queryEndDate, //结束日期[没拖到任务上时传]
// operType: operType, //操作类型:排在资源上 RESOURCE,排在process上 PROCESS
// processId: processId, //目标process,终点
this.loading = true;
handworkschedule(info)
.then(res => {
this.loading = false;
if (res.data.success) {
if (res.data.data.success) {
let ids = res.data.data.resourceIds.join(',');
this.clearGanttRowData(res.data.data.resourceIds);
this.getGanttInfo(ids);
if (tableType) {
bus.$emit('handworkscheduleSuccess', true);
}
this.$message.success(res.data.data.msg || '操作成功!');
} else {
this.$message.warning(res.data.data.msg || '操作失败!');
}
} else {
this.$message.warning(res.data.msg || '操作失败!');
}
})
.catch(err => {
this.loading = false;
console.log(err);
});
},
setGanttRowData(arr) {
arr.map(n => {
for (let i = 0; i < this.ganttRowData.length; i++) {
if (this.ganttRowData[i].resourceId === n.processId) {
this.ganttRowData[i].ganttData = n;
continue;
}
}
});
},
clearGanttRowData(arr) {
arr.map(n => {
for (let i = 0; i < this.ganttRowData.length; i++) {
if (this.ganttRowData[i].resourceId === n) {
this.ganttRowData[i].ganttData = {};
continue;
}
}
});
},
ganttDetails(e) {
let p = e.properties;
let str =
'制造订单代码:' +
(p.workOrderCode || '') +
'\n物品代码:' +
(p.workOrderCodeproductCode || '') +
'\n物品名称:' +
(p.productName || '') +
'\n工艺路径代码:' +
(p.routingStepCode || '') +
'\n工序代码:' +
(p.operationCode || '') +
'\n顺序号:' +
(p.routingStepSequenceNr || '') +
'\n工艺代码:' +
(p.routingStepCode || '') +
'\n计划状态:' +
(p.status || '') +
'\n数量:' +
(p.qty || '') +
'\n齐套状态:' +
(p.allsetStatus || '') +
'\n最早开始时刻:' +
(moment(p.earliestStartTime).format('MM-DD HH:mm') || '') +
'\n最晚结束时刻:' +
(moment(p.latestEndTime).format('MM-DD HH:mm') || '') +
'\n开始时刻:' +
(moment(e.startTime).format('MM-DD HH:mm') || '') +
'\n结束时刻:' +
(moment(e.endTime).format('MM-DD HH:mm') || '') +
'\n冻结状态:' +
(p.lockStatus || '') +
(p.alarmInfo ? '\n告警信息:' + p.alarmInfo : '');
return str;
},
setGanttDom(e) {
let obj = JSON.parse(e);
this.ganttRate = obj.value;
this.ganttLi = parseInt(24 / Number(obj.hours));
this.ganttCol = parseInt(obj.days) < 8 ? 8 : parseInt(obj.days) + 1;
this.getResource();
},
blocksContextmenu(e, val, id) {
e.preventDefault();
this.isShowBlockMenu = val;
let clientY = e.clientY;
let clientX = e.clientX;
// if (clientY < 100) {
// clientY = clientY + 80
// }
// if (clientX - 130 < 100) {
// clientX = clientX + 135
// }
let block = document.querySelector('.block-menu');
block.setAttribute('domId', id)
block.style.top = clientY + 'px';
block.style.left = clientX + 'px';
},
getGanttDom(event, e) {
if (event.ctrlKey) {
if (this.actblockId.includes(e)) {
this.actblockId = this.actblockId.replace(e, '');
} else {
this.actblockId += '#' + e;
}
return;
}
if (this.actblockId.includes(e)) {
this.actblockId = '';
this.unstress();
return;
}
this.actblockId = e;
this.drawLine(e.split('&')[1]);
},
hiddenBlockMenu() {
this.isShowBlockMenu = null;
},
blockMenu(e) {
// if (e === '连线') {
// this.drawLine();
// return;
// }
// if (e === '取消连线') {
// this.clearLine();
// return;
// }
if (e === '选中工序') {
bus.$emit('selectProcedure', this.isShowBlockMenu.blockId);
return;
}
if (e === '强调') {
this.stress();
return;
}
if (e === '取消强调') {
this.unstress();
return;
}
if (e === '冻结') {
this.freeze();
return;
}
if (e === '解锁') {
this.unfreeze();
return;
}
if (e === '制造订单展开') {
this.$router.push({
path: '/planSchedule/ProductionPlan/manufacturingOrder',
query: {
supplyOrderId: this.isShowBlockMenu.blockName
}
});
return;
}
},
ganttMainMove(ev) {
// if (sessionStorage.tableData) {
// if (this.isGanttDomMove) {
// this.isGanttDomMove = false;
// let color = '#409EFF';
// console.log(ev.target.offsetWidth);
// let x = parseInt(ev.target.offsetLeft + ev.layerX - ev.target.offsetWidth / 2);
// let _x = parseInt(this.ganttDomRange.left + 5);
// if (x < _x || x > _x) {
// color = '#f00';
// }
// this.ganttDomMove = {
// left: x,
// color: color,
// width: ev.target.offsetWidth
// };
// setTimeout(() => {
// this.isGanttDomMove = true;
// }, 100);
// }
// }
// earliestStartCalc
// latestEndCalc
},
ganttMainDown(event) {
// 手势操作鼠标移动事件监听
if (event.target.className === 'gantt-dom') {
return;
}
let that = this;
this.moveStartX = event.clientX;
this.moveStartY = event.clientY;
let wrapper = document.getElementById('wrapper');
wrapper.addEventListener('mousemove', that.setMainMove);
},
setMainMove(event) {
// 手势操作鼠标移动处理
if (event.button != 0) {
return;
}
let wrapper = document.getElementById('wrapper');
let x = event.clientX - this.moveStartX;
let y = event.clientY - this.moveStartY;
wrapper.scrollLeft = wrapper.scrollLeft - x;
wrapper.scrollTop = wrapper.scrollTop - y;
if (this.moveStartX != event.clientX) {
this.moveStartX = event.clientX;
}
if (this.moveStartY != event.clientY) {
this.moveStartY = event.clientY;
}
},
ganttRowUp(e) {
this.adjustOptional = '';
if (sessionStorage.tableData) {
let table = JSON.parse(sessionStorage.tableData);
console.log(sessionStorage.tableData);
let ids = table.map(n => {
return n.operationId;
});
let processid = e.target.getAttribute('processid') || '';
let obj = {};
(obj.blockIds = ids), //取消CANCEL,调整 ADJUSTMENT,新增ADD
(obj.adjustmentType = 'ADD'),
(obj.startDate = this.queryStartDate), //开始日期[没拖到任务上时传]
(obj.endDate = this.queryEndDate), //结束日期[没拖到任务上时传]
(obj.operType = 'PROCESS'), //操作类型:排在资源上 RESOURCE,排在process上 PROCESS
(obj.processId = processid), //目标process,终点
(obj.nextBlockId = ''), //下一个任务
(obj.sourceProcessId = ''), //原始process,起点
this.handworkschedule([obj], 'table');
}
},
ganttMainEnter(e) {
// 查找甘特中匹配从表格拖拽过来的数据
if (!e) {
this.clearTabData();
return;
}
if (sessionStorage.tableData) {
let data = JSON.parse(sessionStorage.tableData)[0];
let end = new Date(this.queryEndDate + ' 00:00:00').getTime();
let _end = data.latestEndCalc > end ? end : data.latestEndCalc;
let w = this.ganttDomWidth(data.earliestStartCalc, _end) + 10;
this.ganttDomRange = {
width: w,
left: this.ganttDomLeft(data.earliestStartCalc) - 5
};
}
// 给符合的甘特条加上符合样式,滚动条到第一条符合的数据位置
let ids = e.split(',');
this.adjustOptional = e;
let doms = document.getElementsByClassName('aside-li');
for (let i = 0; i < doms.length; i++) {
if (ids[0] == doms[i].getAttribute('processid')) {
document.getElementById('wrapper').scrollTop = doms[i].offsetTop - 31;
break;
}
}
},
ganttMainUp() {
this.clearTabData();
// this.removeMainMove();
},
ganttMainLeave() {
// this.removeMainMove();
},
clearTabData() {
this.adjustOptional = '';
this.ganttDomRange = {};
sessionStorage.tableData = '';
},
removeMainMove() {
// 移除鼠标移动事件监听
let that = this;
let wrapper = document.getElementById('wrapper');
wrapper.removeEventListener('mousemove', that.setMainMove);
},
stress() {
let dom = document.getElementsByClassName('gantt-dom');
let len = dom.length;
for (let i = 0; i < len; i++) {
dom[i].style.opacity = 0.3;
}
let block = document.querySelector('.block-menu').getAttribute('domId');
document.getElementById(block).style.opacity = 1;
this.drawLine();
},
unstress() {
if (this.draggleType === 'afterOnly') {
this.ganttRowData = [...this.allGanttRowData];
this.asideList = [...this.allAsideList];
}
let dom = document.getElementsByClassName('gantt-dom');
let len = dom.length;
for (let i = 0; i < len; i++) {
dom[i].style.opacity = 1;
}
this.actblockId = '';
this.clearLine();
},
freeze() {
if (!this.actblockId) {
this.$message.warning('请选择要冻结的工序!');
return;
}
let ids = this.actblockId
.split('#')
.map(e => {
return e.split('&')[1];
})
.filter(n =>{
return n
})
.join(',');
lockOperation({
operationIds: ids
}).then(res => {
if (res.data.success) {
this.actblockId = '';
this.getResource();
this.$message.success(res.data.msg);
} else {
this.$message.error(res.data.msg);
}
});
},
unfreeze() {
if (!this.actblockId) {
this.$message.warning('请选择要解锁的工序!');
return;
}
let ids = this.actblockId
.split('#')
.map(e => {
return e.split('&')[1];
})
.filter(n =>{
return n
})
.join(',');
unlockOperation({
operationIds: ids
}).then(res => {
if (res.data.success) {
this.actblockId = '';
this.getResource();
this.$message.success(res.data.msg);
} else {
this.$message.error(res.data.msg);
}
});
},
drawLine(e) {
this.clearLine();
let id = e || this.subProcess.operationId || this.isShowBlockMenu.blockId;
let info = {
operationId: id
};
getGanttline(info)
.then(res => {
if (res.data.success) {
if (res.data.lines.length == 0) {
this.$message.warning('未查到连线信息!');
this.unstress();
return;
}
if (res.data.processes.length > 0) {
this.setLineGantt(res.data.processes);
}
this.$nextTick(() => {
let targetBlock = {};
let index = 0;
for (let i = 0; i < res.data.lines.length; i++) {
if (res.data.lines[i].blockId === id) {
targetBlock = { ...res.data.lines[i] };
index = i;
}
}
let lines = [targetBlock];
if (this.lineType === 'all' || !e) {
lines = [...res.data.lines];
} else {
let preBlock = res.data.lines.find(x => x.nextBlockId === targetBlock.blockId);
let nextBlock = res.data.lines.find(x => x.blockId === targetBlock.nextBlockId);
if(preBlock) {
lines.unshift(preBlock)
}
if(this.lineType !== 'one') {
const contrast = {
one: 1,
two: 2,
three: 3,
four: 4,
five: 5,
ten: 10,
twenty: 20
};
for (let i = 1; i <= (contrast[this.lineType]-1); i++) {
if(preBlock && res.data.lines.some(x => x.nextBlockId === preBlock.blockId)) {
lines = lines.concat(res.data.lines.find(x => x.nextBlockId === preBlock.blockId));
preBlock = res.data.lines.find(x => x.nextBlockId === preBlock.blockId);
}
if(nextBlock && res.data.lines.some(x => x.blockId === nextBlock.nextBlockId)) {
lines.push(nextBlock)
nextBlock = res.data.lines.find(x => x.blockId === nextBlock.nextBlockId)
}
}
}
}
console.log(lines)
lines.map(n => {
this.setLineDom(n.processId + '&' + n.blockId, n.nextProcessId + '&' + n.nextBlockId);
});
if (this.subProcess.operationId) {
this.setWrapperScroll(this.subProcess.plannedResourceId + '&' + this.subProcess.operationId);
this.subProcess = {};
}
});
}
})
.catch(err => {
console.log(err);
});
},
setLineGantt(arr) {
const hideArr = [];
arr.map(n => {
for (let i = 0; i < this.ganttRowData.length; i++) {
if (this.ganttRowData[i].resourceId === n.processId) {
let ganttData = this.ganttRowData[i].ganttData;
if (ganttData) {
let isto = ganttData.blocks.includes(item => {
return item.block !== n.blocks[0].blockId;
});
if (isto) {
this.ganttRowData[i].ganttData.blocks.push(n.blocks[0]);
}
}
break;
}
}
});
if (this.draggleType === 'afterOnly') {
this.allGanttRowData = [...this.ganttRowData];
this.allAsideList = [...this.asideList];
this.ganttRowData = this.ganttRowData.filter(x => arr.some(y => y.processId === x.resourceId));
this.asideList = this.asideList.filter(x => arr.some(y => y.processName === x.resourceName));
}
},
setWrapperScroll(id) {
let wrapper = document.getElementById('wrapper');
let dom = document.getElementById(id);
if (!dom) {
return;
}
wrapper.scrollTop = dom.parentNode.offsetTop - 60;
wrapper.scrollLeft = dom.offsetLeft - 30;
},
setLineDom(startId, endId) {
let startObj = document.getElementById(startId);
let endObj = document.getElementById(endId);
if (startObj) {
startObj.style.opacity = 1;
}
if (endObj) {
endObj.style.opacity = 1;
}
if (!startObj || !endObj) {
return;
}
//起点元素中心坐标
let y_start = startObj.parentNode.offsetTop + 15;
let x_start = startObj.offsetLeft + startObj.offsetWidth + 100;
//终点元素中心坐标
let y_end = endObj.parentNode.offsetTop + 15;
let x_end = endObj.offsetLeft + 100;
//用勾股定律计算出斜边长度及其夹角(即连线的旋转角度)
let lx = x_end - x_start;
let ly = y_end - y_start;
//计算连线长度
let length = Math.sqrt(lx * lx + ly * ly);
//弧度值转换为角度值
let c = (360 * Math.atan2(ly, lx)) / (2 * Math.PI);
//连线中心坐标
let midX = (x_end + x_start) / 2;
let midY = (y_end + y_start) / 2;
let deg = c <= -90 ? 360 + c : c; //负角转换为正角
let node = document.createElement('div');
node.className = 'line';
node.style.zIndex = 2;
node.style.position = 'absolute';
node.style.borderTop = '1px solid #3500ff';
node.style.top = midY + 'px';
node.style.left = midX - length / 2 + 'px';
node.style.width = length + 'px';
node.style.transform = 'rotate(' + deg + 'deg)';
document.querySelector('.gantt-main').appendChild(node);
},
clearLine() {
let dom = document.getElementsByClassName('line');
let len = dom.length;
for (let i = 0; i < len; i++) {
dom[0].remove();
}
},
setGanttHeight(height) {
this.$refs.ganttRoot.style.height = height;
setTimeout(() => {
this.ganttTop = document.querySelector('.yhl-table-productPeriod').offsetHeight + 183
}, 500)
}
}
};
</script>
<style lang="scss" scoped>
.gantt {
width: 100%;
height: calc(40vh - 35px);
position: relative;
background: #fff;
border: 1px solid #eeeeee;
cursor: pointer;
.gantt-content {
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
overflow: auto;
.gantt-block {
position: sticky;
top: 0;
left: 0;
float: left;
width: 100px;
height: 60px;
border-right: 1px solid #eeeeee;
border-bottom: 1px solid #eeeeee;
z-index: 9;
background-color: #fff;
div {
text-align: center;
line-height: 30px;
height: 30px;
font-weight: bold;
border-bottom: 1px solid #eeeeee;
}
}
.gantt-aside {
position: sticky;
top: 0;
left: 0;
float: left;
width: 100px;
min-height: 100%;
overflow: hidden;
border-right: 1px solid #eeeeee;
z-index: 8;
background-color: #fff;
.aside-list {
width: 100%;
.aside-li {
height: 31px;
position: relative;
border-bottom: 1px solid #eeeeee;
span {
display: inline-block;
height: 25px;
line-height: 25px;
text-align: left;
font-size: 12px;
transform: scale(0.9);
margin-left: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.mainType::before {
content: '*';
color: red;
position: absolute;
top: 5px;
left: 0;
font-weight: bold;
}
.adjustOptional::after {
content: '';
position: absolute;
right: 0;
height: 100%;
width: 6px;
background: #3500ff;
}
}
}
.gantt-calendar {
position: sticky;
top: 0;
float: left;
width: calc(100% - 100px);
height: 60px;
z-index: 8;
.calendar-dom {
display: flex;
font-size: 12px;
height: 50px;
position: relative;
.calendar-li {
width: 720px;
flex-grow: 0;
flex-shrink: 0;
display: inline-block;
border-right: 1px solid #eeeeee;
background-color: #fff;
.calendar-day {
text-align: center;
height: 30px;
line-height: 30px;
border-bottom: 1px solid #eeeeee;
}
.calendar-time {
display: flex;
height: 20px;
line-height: 20px;
padding: 0 4%;
border-bottom: 1px solid #eeeeee;
.calendar-h {
width: 9.1%;
text-align: center;
}
}
.gantt-time {
width: calc(100% + 1px);
height: 10px;
background-color: #fff;
border-bottom: 1px solid #eeeeee;
}
}
.gantt-dom-range {
width: 200px;
height: 10px;
position: absolute;
bottom: -10px;
}
.gantt-dom-range::before {
content: '';
position: absolute;
top: 0;
left: 0;
border-style: solid;
border-color: transparent;
border-width: 5px 0 5px 5px;
border-left-color: #f00;
}
.gantt-dom-range::after {
content: '';
position: absolute;
top: 0;
right: 0;
border-style: solid;
border-color: transparent;
border-width: 5px 5px 5px 0;
border-right-color: #f00;
}
.gantt-dom-move {
width: 200px;
height: 10px;
background-color: #409eff;
position: absolute;
bottom: -10px;
}
}
}
.gantt-main {
padding-top: 60px;
padding-left: 100px;
position: absolute;
overflow: hidden;
.gantt-row {
position: relative;
width: 100%;
height: 31px;
border-bottom: 1px solid #eeeeee;
z-index: 1;
user-select: none;
content-visibility: auto;
overflow: hidden;
.gantt-dom {
position: absolute;
top: 15%;
left: 400px;
width: 30px;
height: 70%;
background: #f2f2f2;
box-shadow: 0 0 3px #666;
// display: flex;
// justify-content: space-between;
color: #fff;
line-height: 18px;
font-size: 12px;
content-visibility: auto;
z-index: 2;
text-align: center;
line-height: 21px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.trangle {
width: 0;
height: 0;
border-top: 10px solid #db1111;
border-right: 10px solid transparent;
position: absolute;
top: -2px;
left: -2px;
}
}
.gantt-dom:hover {
box-shadow: 0 0 3px 3px #aaaaaa;
z-index: 99;
}
.gantt-dom-act {
outline: 2px dashed #3500ff;
}
// .gantt-dom-choice {
// border: 2px solid #06f;
// }
}
.adjustOptional {
box-shadow: rgb(221, 221, 221) 0px 0px 8px inset;
animation: animate 1s linear infinite;
}
@keyframes animate {
0% {
box-shadow: inset 0 0 10px rgba(91, 0, 255, 0.5);
}
50% {
box-shadow: inset 0 0 10px rgba(91, 0, 255, 1);
}
100% {
box-shadow: inset 0 0 10px rgba(91, 0, 255, 0.5);
}
}
.gantt-row:hover {
box-shadow: #eeeeee 0 0 8px inset;
}
.rest-dom {
position: absolute;
height: 100%;
background: rgba(0, 0, 0, 0.25);
z-index: 1;
content-visibility: auto;
}
.block-menu {
position: fixed;
top: 11vw;
left: 50vw;
width: 90px;
background-color: #ffffff;
box-shadow: 0 0 5px #000;
z-index: 8;
div {
padding: 4px 0 4px 5px;
font-size: 12px;
text-align: left;
color: #333;
border-bottom: 1px solid #eeeeee;
}
div:hover {
background-color: #dddddd;
}
.gotoNewDom:hover {
.gotoNew {
display: block;
}
}
.gotoNew {
width: 110px;
display: none;
position: absolute;
right: -110px;
bottom: 0;
border: 1px solid #aaaaaa;
background-color: #ffffff;
}
}
.gantt-col-bg {
position: absolute;
width: calc(100% - 100px);
height: calc(100% - 60px);
display: flex;
.gantt-col-ul {
width: 600px;
height: 100%;
display: flex;
flex-grow: 0;
flex-shrink: 0;
content-visibility: auto;
.gantt-col-li {
width: 9.1;
height: 100%;
border-right: 1px solid #eeeeee;
}
}
.gantt-col-ol:nth-child(2n) {
border-right: 1px solid #eeeeee;
}
}
.base-time {
position: absolute;
top: 60px;
border-left: 2px solid rgba(255, 0, 0, 0.5);
height: calc(100% - 60px);
z-index: 6;
}
.nodata {
width: 200px;
text-align: center;
position: absolute;
top: 160px;
left: 39vw;
font-size: 16px;
color: #999;
}
}
}
/* 定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸 */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/* 定义滚动条轨道 内阴影+圆角 */
::-webkit-scrollbar-track {
background-color: #fff;
}
/* 定义滑块 内阴影+圆角 */
::-webkit-scrollbar-thumb {
border-radius: 6px;
background-color: #ddd;
}
}
</style>
<style>
#dragCanvas {
position: absolute;
left: -100%;
}
</style>