|
|
|
|
@ -152,7 +152,7 @@ |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<!-- 甘特图主体 --> |
|
|
|
|
<div class="gantt-wrapper" > |
|
|
|
|
<div class="gantt-wrapper"> |
|
|
|
|
<!-- 左侧信息列表 - 展示车间订单号等信息 --> |
|
|
|
|
<div class="info-list" :style="{ height: ganttWrapperHeightLeft }"> |
|
|
|
|
<div class="info-item-title"> |
|
|
|
|
@ -193,7 +193,11 @@ |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<!-- 右侧时间轴 @wheel.prevent="handleWheel"--> |
|
|
|
|
<div class="timeline-container" ref="timelineContainer" :style="{ height: ganttWrapperHeight }"> |
|
|
|
|
<div |
|
|
|
|
class="timeline-container" |
|
|
|
|
ref="timelineContainer" |
|
|
|
|
:style="{ height: ganttWrapperHeight }" |
|
|
|
|
> |
|
|
|
|
<!-- 图表X轴区域 --> |
|
|
|
|
<div class="chart-axis"> |
|
|
|
|
<!-- 日期行 --> |
|
|
|
|
@ -323,9 +327,21 @@ |
|
|
|
|
>{{ task.processName }}</span |
|
|
|
|
> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<!-- 为窄任务添加带偏移的文本显示 --> |
|
|
|
|
<div |
|
|
|
|
v-if="getWidthPercent(task.planStartTime, task.planEndTime) < 1" |
|
|
|
|
class="task-overlay-text" |
|
|
|
|
:style="{ |
|
|
|
|
top: `${ |
|
|
|
|
-20 - |
|
|
|
|
getNarrowTaskOffset( |
|
|
|
|
order.woCode, |
|
|
|
|
layer.findIndex(t => t === task), |
|
|
|
|
layerIndex |
|
|
|
|
) |
|
|
|
|
}px`, |
|
|
|
|
}" |
|
|
|
|
> |
|
|
|
|
{{ task.processName }} |
|
|
|
|
</div> |
|
|
|
|
@ -491,11 +507,18 @@ export default { |
|
|
|
|
processing: true, |
|
|
|
|
pending: true, |
|
|
|
|
}, |
|
|
|
|
handleRightScrollBound:null, |
|
|
|
|
handleLeftScrollBound:null, |
|
|
|
|
handleRightScrollBound: null, |
|
|
|
|
handleLeftScrollBound: null, |
|
|
|
|
}; |
|
|
|
|
}, |
|
|
|
|
computed: { |
|
|
|
|
// 通过 Vue Router 获取查询参数 |
|
|
|
|
tsId() { |
|
|
|
|
return this.$route.query.tsId || ''; |
|
|
|
|
}, |
|
|
|
|
tsName() { |
|
|
|
|
return this.$route.query.tsName || ''; |
|
|
|
|
}, |
|
|
|
|
// 计算基准开始时间(今天0点) |
|
|
|
|
baseDate() { |
|
|
|
|
if (this.formLabelAlign.timeRange && this.formLabelAlign.timeRange.length === 2) { |
|
|
|
|
@ -685,6 +708,16 @@ export default { |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
watch: { |
|
|
|
|
// 监听参数变化 |
|
|
|
|
'$route.query': { |
|
|
|
|
handler(newQuery) { |
|
|
|
|
console.log('参数变化:', newQuery); |
|
|
|
|
this.handleParamsChange(); |
|
|
|
|
}, |
|
|
|
|
immediate: true |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
mounted() { |
|
|
|
|
this.getSelectTeam(); |
|
|
|
|
this.getSelectEquip(); |
|
|
|
|
@ -701,6 +734,7 @@ export default { |
|
|
|
|
this.$refs.leftScrollContainer.addEventListener('scroll', this.handleLeftScrollBound); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 定时更新当前时间线位置 |
|
|
|
|
// setInterval(() => { |
|
|
|
|
@ -722,6 +756,96 @@ export default { |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
methods: { |
|
|
|
|
handleParamsChange() { |
|
|
|
|
// 参数变化时的处理逻辑 |
|
|
|
|
console.log('接收到的参数:', { |
|
|
|
|
tsId: this.tsId, |
|
|
|
|
tsName: this.tsName, |
|
|
|
|
userId: this.userId, |
|
|
|
|
userName: this.userName, |
|
|
|
|
timestamp: this.timestamp |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
this.formLabelAlign.teamId = this.tsId |
|
|
|
|
this.formLabelAlign.teamName = this.tsName |
|
|
|
|
// 根据参数加载数据 |
|
|
|
|
this.getData(); |
|
|
|
|
}, |
|
|
|
|
// 计算重叠的窄任务的垂直偏移量 |
|
|
|
|
getNarrowTaskOffset(orderWoCode, taskIndex, layerIndex) { |
|
|
|
|
const tasks = this.getDeviceTasks(orderWoCode); |
|
|
|
|
const currentTask = tasks[taskIndex]; |
|
|
|
|
|
|
|
|
|
// 获取当前任务的时间段 |
|
|
|
|
const currentStart = this.parseTimeToHours(currentTask.planStartTime); |
|
|
|
|
const currentEnd = this.parseTimeToHours(currentTask.planEndTime); |
|
|
|
|
const currentWidth = this.getWidthPercent(currentTask.planStartTime, currentTask.planEndTime); |
|
|
|
|
|
|
|
|
|
// 如果宽度大于等于1%,不需要偏移 |
|
|
|
|
if (currentWidth >= 1) { |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 查找在同一时间段内的其他窄任务 |
|
|
|
|
const overlappingTasks = []; |
|
|
|
|
for (let i = 0; i < tasks.length; i++) { |
|
|
|
|
const task = tasks[i]; |
|
|
|
|
const taskWidth = this.getWidthPercent(task.planStartTime, task.planEndTime); |
|
|
|
|
|
|
|
|
|
if (taskWidth < 1) { |
|
|
|
|
// 只考虑窄任务 |
|
|
|
|
const taskStart = this.parseTimeToHours(task.planStartTime); |
|
|
|
|
const taskEnd = this.parseTimeToHours(task.planEndTime); |
|
|
|
|
|
|
|
|
|
// 检查时间是否重叠(考虑浮点数精度) |
|
|
|
|
if (Math.max(currentStart, taskStart) <= Math.min(currentEnd, taskEnd) + 0.01) { |
|
|
|
|
overlappingTasks.push({ index: i, task, start: taskStart, end: taskEnd }); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 按开始时间排序 |
|
|
|
|
overlappingTasks.sort((a, b) => a.start - b.start); |
|
|
|
|
|
|
|
|
|
// 创建层来分配任务,避免同一层中的任务重叠 |
|
|
|
|
const layers = []; |
|
|
|
|
for (const overlapTask of overlappingTasks) { |
|
|
|
|
let assigned = false; |
|
|
|
|
|
|
|
|
|
// 尝试将任务分配到现有层 |
|
|
|
|
for (let layerIdx = 0; layerIdx < layers.length; layerIdx++) { |
|
|
|
|
const lastTask = layers[layerIdx][layers[layerIdx].length - 1]; |
|
|
|
|
// 检查是否与该层最后一个任务重叠 |
|
|
|
|
if ( |
|
|
|
|
Math.max(lastTask.start, overlapTask.start) > Math.min(lastTask.end, overlapTask.end) |
|
|
|
|
) { |
|
|
|
|
// 不重叠,可以分配到这一层 |
|
|
|
|
layers[layerIdx].push(overlapTask); |
|
|
|
|
assigned = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 如果没有合适的层,创建新层 |
|
|
|
|
if (!assigned) { |
|
|
|
|
layers.push([overlapTask]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 找到当前任务所在的层索引 |
|
|
|
|
const currentTaskLayerIndex = layers.findIndex(layer => |
|
|
|
|
layer.some(item => item.index === taskIndex) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// 根据层索引返回偏移量 |
|
|
|
|
const offsetStep = 20; // 每个任务之间的偏移量 |
|
|
|
|
return currentTaskLayerIndex * offsetStep; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 检查任务是否为窄任务 |
|
|
|
|
isNarrowTask(task) { |
|
|
|
|
return this.getWidthPercent(task.planStartTime, task.planEndTime) < 1; |
|
|
|
|
}, |
|
|
|
|
// 右侧滚动时同步左侧滚动 |
|
|
|
|
handleRightScroll(event) { |
|
|
|
|
if (this.$refs.leftScrollContainer) { |
|
|
|
|
@ -762,6 +886,7 @@ export default { |
|
|
|
|
if (this.legendStatus.pending) { |
|
|
|
|
this.formLabelAlign.planStatusList.push('1'); |
|
|
|
|
} |
|
|
|
|
this.handleParamsChange() |
|
|
|
|
|
|
|
|
|
this.getData(); |
|
|
|
|
}, |
|
|
|
|
@ -1065,7 +1190,7 @@ export default { |
|
|
|
|
|
|
|
|
|
// 左侧行高计算 |
|
|
|
|
getRowHeight(device) { |
|
|
|
|
return this.baseRowHeight-1; |
|
|
|
|
return this.baseRowHeight - 1; |
|
|
|
|
}, |
|
|
|
|
// 右侧行高计算 |
|
|
|
|
getRowChartHeight(device) { |
|
|
|
|
@ -1185,7 +1310,6 @@ export default { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// timeStr 格式是 "YYYY-MM-DD HH:mm" 如 "2025-12-25 18:35" |
|
|
|
|
console.log('timeStr',timeStr) |
|
|
|
|
const [datePart, timePart] = timeStr.split(' '); |
|
|
|
|
const [year, month, day] = datePart.split('-').map(Number); |
|
|
|
|
const [hours, minutes] = timePart.split(':').map(Number); |
|
|
|
|
@ -1391,7 +1515,6 @@ export default { |
|
|
|
|
flex-direction: column; |
|
|
|
|
overflow-y: auto; /* 允许垂直滚动 */ |
|
|
|
|
overflow-x: auto; /* 允许水平滚动 */ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* 图表X轴区域样式 */ |
|
|
|
|
@ -1601,11 +1724,11 @@ export default { |
|
|
|
|
width: 100%; |
|
|
|
|
height: 100%; |
|
|
|
|
text-align: center; |
|
|
|
|
display: inline-block; |
|
|
|
|
display: inline-block; |
|
|
|
|
transform: scale(0.7); |
|
|
|
|
} |
|
|
|
|
.task-label-txt { |
|
|
|
|
position: absolute; |
|
|
|
|
position: absolute; |
|
|
|
|
font-size: 9px; |
|
|
|
|
color: white; |
|
|
|
|
white-space: nowrap; |
|
|
|
|
@ -1617,10 +1740,8 @@ export default { |
|
|
|
|
top: 50%; |
|
|
|
|
left: 50%; |
|
|
|
|
transform: translate(-50%, -50%); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
.task-label-txt-inside { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
.task-overlay-text { |
|
|
|
|
position: absolute; |
|
|
|
|
@ -1634,7 +1755,7 @@ export default { |
|
|
|
|
z-index: 10; |
|
|
|
|
transform: none; |
|
|
|
|
min-width: max-content; |
|
|
|
|
pointer-events: none; /* 避免影响鼠标事件 */ |
|
|
|
|
pointer-events: none; |
|
|
|
|
display: inline-block; |
|
|
|
|
transform: scale(0.7); |
|
|
|
|
} |
|
|
|
|
|