|
|
|
|
@ -14,7 +14,7 @@ |
|
|
|
|
</el-col> |
|
|
|
|
<el-col :span="6" v-if="formLabelAlign.type == '1'"> |
|
|
|
|
<el-form-item label="车间订单号:" label-width="120px"> |
|
|
|
|
<el-input v-model="formLabelAlign.woCode"></el-input> |
|
|
|
|
<el-input v-model="formLabelAlign.woCode" placeholder="请输入"></el-input> |
|
|
|
|
</el-form-item> |
|
|
|
|
</el-col> |
|
|
|
|
<el-col :span="6" v-if="formLabelAlign.type == '2'"> |
|
|
|
|
@ -99,8 +99,12 @@ |
|
|
|
|
<div |
|
|
|
|
v-for="(device, index) in devices" |
|
|
|
|
:key="index" |
|
|
|
|
class="device-item" |
|
|
|
|
:style="{ height: rowHeight + 'px' }" |
|
|
|
|
:style="{ |
|
|
|
|
height: getRowHeight(device) + 'px', |
|
|
|
|
lineHeight: getRowHeight(device) + 'px', |
|
|
|
|
textAlign: 'center', |
|
|
|
|
borderBottom: '1px solid #ccc', |
|
|
|
|
}" |
|
|
|
|
:title="device" |
|
|
|
|
> |
|
|
|
|
{{ device }} |
|
|
|
|
@ -181,24 +185,33 @@ |
|
|
|
|
v-for="(device, devIndex) in devices" |
|
|
|
|
:key="devIndex" |
|
|
|
|
class="device-task-row" |
|
|
|
|
:style="{ height: rowHeight + 'px' }" |
|
|
|
|
:style="{ height: getRowHeight(device) + 'px' }" |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
v-for="(task, taskIndex) in getDeviceTasks(device)" |
|
|
|
|
:key="taskIndex" |
|
|
|
|
class="task-bar" |
|
|
|
|
:style="{ |
|
|
|
|
left: `${getPositionPercent(task.startTime)}%`, |
|
|
|
|
width: `${getWidthPercent(task.startTime, task.endTime)}%`, |
|
|
|
|
backgroundColor: getStatusColor(task.status), |
|
|
|
|
}" |
|
|
|
|
@mouseenter="showTooltip($event, task, device)" |
|
|
|
|
@mouseleave="hideTooltip()" |
|
|
|
|
> |
|
|
|
|
<span class="task-label" v-if="searchType == '1'">{{ task.processName }}</span> |
|
|
|
|
<span class="task-label" v-if="searchType == '2'">{{ task.woCode }}</span> |
|
|
|
|
<span class="task-label" v-if="searchType == '3'">{{ task.woCode }}</span> |
|
|
|
|
</div> |
|
|
|
|
<template v-for="(layer, layerIndex) in getLayeredTasks(device)" :key="layerIndex"> |
|
|
|
|
<div |
|
|
|
|
v-for="(task, taskIndex) in layer" |
|
|
|
|
:key="taskIndex" |
|
|
|
|
class="task-bar" |
|
|
|
|
:style="{ |
|
|
|
|
left: `${getPositionPercent(task.startTime)}%`, |
|
|
|
|
width: `${getWidthPercent(task.startTime, task.endTime)}%`, |
|
|
|
|
backgroundColor: getStatusColor(task), |
|
|
|
|
top: `${getLayerOffset( |
|
|
|
|
layerIndex, |
|
|
|
|
getLayeredTasks(device).length, |
|
|
|
|
device |
|
|
|
|
)}px`, |
|
|
|
|
height: `${getLayerTaskHeight(getLayeredTasks(device).length, device)}px`, |
|
|
|
|
}" |
|
|
|
|
@mouseenter="showTooltip($event, task, device)" |
|
|
|
|
@mouseleave="hideTooltip()" |
|
|
|
|
> |
|
|
|
|
<!-- 任务标签内容不变 --> |
|
|
|
|
<span class="task-label" v-if="searchType == '1'">{{ task.processName }}</span> |
|
|
|
|
<span class="task-label" v-if="searchType == '2'">{{ task.woCode }}</span> |
|
|
|
|
<span class="task-label" v-if="searchType == '3'">{{ task.woCode }}</span> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
@ -293,6 +306,8 @@ export default { |
|
|
|
|
tooltipData: {}, |
|
|
|
|
tooltipX: 0, |
|
|
|
|
tooltipY: 0, |
|
|
|
|
baseRowHeight: 40, // 基础行高(单任务时的高度) |
|
|
|
|
rowHeights: {}, // 存储每个设备的动态行高 |
|
|
|
|
}; |
|
|
|
|
}, |
|
|
|
|
computed: { |
|
|
|
|
@ -322,7 +337,6 @@ export default { |
|
|
|
|
methods: { |
|
|
|
|
getData() { |
|
|
|
|
getData(this.formLabelAlign).then(res => { |
|
|
|
|
console.log(99999, res.data.data); |
|
|
|
|
this.processData(res.data.data); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
@ -435,13 +449,15 @@ export default { |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 根据状态获取颜色 |
|
|
|
|
getStatusColor(status) { |
|
|
|
|
switch (status) { |
|
|
|
|
case '已完成': |
|
|
|
|
getStatusColor(row) { |
|
|
|
|
let staus=this.searchType=='1'?row.planStatus:row.orderStatus |
|
|
|
|
|
|
|
|
|
switch (staus) { |
|
|
|
|
case '3': |
|
|
|
|
return '#28a745'; |
|
|
|
|
case '进行中': |
|
|
|
|
case '2': |
|
|
|
|
return '#007bff'; |
|
|
|
|
case '未开始': |
|
|
|
|
case '1': |
|
|
|
|
return '#6c757d'; |
|
|
|
|
default: |
|
|
|
|
return '#ccc'; |
|
|
|
|
@ -478,23 +494,73 @@ export default { |
|
|
|
|
hideTooltip() { |
|
|
|
|
this.tooltipVisible = false; |
|
|
|
|
}, |
|
|
|
|
// 在methods中添加处理重叠任务的方法 |
|
|
|
|
// 计算每个设备的行高 |
|
|
|
|
getRowHeight(device) { |
|
|
|
|
const layers = this.getLayeredTasks(device); |
|
|
|
|
const layerCount = layers.length; |
|
|
|
|
// 行高 = 基础行高 * 层数(确保至少有基础行高) |
|
|
|
|
const height = Math.max(this.baseRowHeight, layerCount * this.baseRowHeight); |
|
|
|
|
// 缓存计算结果避免重复计算 |
|
|
|
|
this.rowHeights[device] = height; |
|
|
|
|
return height; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 修复层级偏移计算(基于实际行高) |
|
|
|
|
getLayerOffset(layerIndex, totalLayers, device) { |
|
|
|
|
const rowHeight = this.getRowHeight(device); |
|
|
|
|
if (totalLayers <= 1) return 2; // 单层级时的顶部间距 |
|
|
|
|
|
|
|
|
|
// 计算每层可用高度(减去总间距) |
|
|
|
|
const totalSpacing = totalLayers * 4; // 每层4px间距 |
|
|
|
|
const availableHeight = rowHeight - totalSpacing; |
|
|
|
|
const layerHeight = availableHeight / totalLayers; |
|
|
|
|
return layerIndex * (layerHeight + 4) + 2; // 2px顶部边距 |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 修复任务高度计算(基于实际行高) |
|
|
|
|
getLayerTaskHeight(totalLayers, device) { |
|
|
|
|
const rowHeight = this.getRowHeight(device); |
|
|
|
|
if (totalLayers <= 1) { |
|
|
|
|
return rowHeight - 4; // 减去上下间距 |
|
|
|
|
} else { |
|
|
|
|
const totalSpacing = totalLayers * 4; |
|
|
|
|
const availableHeight = rowHeight - totalSpacing; |
|
|
|
|
return availableHeight / totalLayers; |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 优化层级计算逻辑 |
|
|
|
|
getLayeredTasks(device) { |
|
|
|
|
const tasks = this.getDeviceTasks(device); |
|
|
|
|
if (!tasks.length) return []; |
|
|
|
|
|
|
|
|
|
// 按开始时间排序 |
|
|
|
|
// 按开始时间排序,并处理跨天任务 |
|
|
|
|
const sortedTasks = [...tasks].sort((a, b) => { |
|
|
|
|
return this.timeToMinutes(a.startTime) - this.timeToMinutes(b.startTime); |
|
|
|
|
const aStart = this.timeToMinutes(a.startTime); |
|
|
|
|
const bStart = this.timeToMinutes(b.startTime); |
|
|
|
|
// 跨天任务(结束时间小于开始时间)排在前面 |
|
|
|
|
if (this.timeToMinutes(a.endTime) < aStart && this.timeToMinutes(b.endTime) >= bStart) { |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
return aStart - bStart; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const layers = []; |
|
|
|
|
sortedTasks.forEach(task => { |
|
|
|
|
// 尝试找到可以放置当前任务的层级 |
|
|
|
|
let placed = false; |
|
|
|
|
const taskStart = this.timeToMinutes(task.startTime); |
|
|
|
|
const taskEnd = this.timeToMinutes(task.endTime); |
|
|
|
|
|
|
|
|
|
// 处理跨天任务的结束时间(转换为第二天的分钟数) |
|
|
|
|
const adjustedEnd = taskEnd < taskStart ? taskEnd + 24 * 60 : taskEnd; |
|
|
|
|
|
|
|
|
|
for (let i = 0; i < layers.length; i++) { |
|
|
|
|
const lastTask = layers[i][layers[i].length - 1]; |
|
|
|
|
if (this.timeToMinutes(task.startTime) >= this.timeToMinutes(lastTask.endTime)) { |
|
|
|
|
const lastEnd = this.timeToMinutes(lastTask.endTime); |
|
|
|
|
const lastAdjustedEnd = |
|
|
|
|
lastEnd < this.timeToMinutes(lastTask.startTime) ? lastEnd + 24 * 60 : lastEnd; |
|
|
|
|
|
|
|
|
|
if (taskStart >= lastAdjustedEnd) { |
|
|
|
|
layers[i].push(task); |
|
|
|
|
placed = true; |
|
|
|
|
break; |
|
|
|
|
@ -507,20 +573,6 @@ export default { |
|
|
|
|
|
|
|
|
|
return layers; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 计算任务所在层级的垂直偏移 |
|
|
|
|
getLayerOffset(layerIndex, totalLayers) { |
|
|
|
|
if (totalLayers <= 1) return 0; |
|
|
|
|
// 每层高度 = 行高 / 总层数 |
|
|
|
|
const layerHeight = this.rowHeight / totalLayers; |
|
|
|
|
return layerIndex * layerHeight + 2; // 加2px间距 |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 计算任务在层级中的高度 |
|
|
|
|
getLayerTaskHeight(totalLayers) { |
|
|
|
|
if (totalLayers <= 1) return this.rowHeight - 4; // 减4px间距 |
|
|
|
|
return this.rowHeight / totalLayers - 4; |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
</script> |
|
|
|
|
@ -633,7 +685,7 @@ export default { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
.device-item-title { |
|
|
|
|
background: var(--el-color-primary); |
|
|
|
|
background: #284c89 !important; |
|
|
|
|
text-align: center; |
|
|
|
|
color: #fff; |
|
|
|
|
} |
|
|
|
|
@ -659,7 +711,7 @@ export default { |
|
|
|
|
width: 100%; |
|
|
|
|
height: 30px; |
|
|
|
|
display: flex; |
|
|
|
|
background-color: var(--el-color-primary); |
|
|
|
|
background-color: #284c89 !important; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* 主刻度标签(小时) */ |
|
|
|
|
@ -703,7 +755,7 @@ export default { |
|
|
|
|
left: 0; |
|
|
|
|
width: 100%; |
|
|
|
|
height: 6px; |
|
|
|
|
background-color: var(--el-color-primary); |
|
|
|
|
background-color: #284c89 !important; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* 主刻度线(小时) */ |
|
|
|
|
@ -780,13 +832,13 @@ export default { |
|
|
|
|
position: relative; |
|
|
|
|
border-bottom: 1px solid #e9ecef; |
|
|
|
|
box-sizing: border-box; |
|
|
|
|
padding: 0; |
|
|
|
|
margin: 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.task-bar { |
|
|
|
|
position: absolute; |
|
|
|
|
top: 5px; |
|
|
|
|
height: 26px; |
|
|
|
|
border-radius: 4px; |
|
|
|
|
border-radius: 18px; |
|
|
|
|
display: flex; |
|
|
|
|
align-items: center; |
|
|
|
|
padding: 0 10px; |
|
|
|
|
@ -794,6 +846,7 @@ export default { |
|
|
|
|
cursor: pointer; |
|
|
|
|
overflow: hidden; |
|
|
|
|
transition: all 0.2s; |
|
|
|
|
white-space: nowrap; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.task-bar:hover { |
|
|
|
|
@ -857,4 +910,8 @@ export default { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
:deep(.el-button--primary){ |
|
|
|
|
background-color: #284c89 !important; |
|
|
|
|
color:#fff |
|
|
|
|
} |
|
|
|
|
</style> |
|
|
|
|
|