排产看板样式调整

dev-scheduling
zhangdi 2 days ago
parent 480217af12
commit 446784a596
  1. 2
      src/page/index/top/index.vue
  2. 244
      src/views/productionSchedulingPlan/schedulingDashboard/index.vue

@ -113,7 +113,7 @@
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<top-setting></top-setting> <!-- <top-setting></top-setting> -->
<el-dialog title="请选择身份信息后切换" append-to-body v-model="userBox" width="400px"> <el-dialog title="请选择身份信息后切换" append-to-body v-model="userBox" width="400px">
<avue-form :option="userOption" v-model="userForm" @submit="toAll" /> <avue-form :option="userOption" v-model="userForm" @submit="toAll" />
</el-dialog> </el-dialog>

@ -3,9 +3,15 @@
<el-form label-width="80px" :model="formLabelAlign"> <el-form label-width="80px" :model="formLabelAlign">
<el-row> <el-row>
<!-- 新增查询条件 --> <!-- 新增查询条件 -->
<el-col :span="4"> <el-col :span="5">
<el-form-item label="班组:"> <el-form-item label="班组:">
<el-select v-model="formLabelAlign.teamName" clearable filterable placeholder="请选择"> <el-select
v-model="formLabelAlign.teamName"
clearable
filterable
placeholder="请选择"
size="small"
>
<el-option <el-option
v-for="(item, index) in selectTeamOptions" v-for="(item, index) in selectTeamOptions"
:label="item" :label="item"
@ -15,9 +21,15 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="5">
<el-form-item label="设备:"> <el-form-item label="设备:">
<el-select v-model="formLabelAlign.equipName" clearable filterable placeholder="请选择"> <el-select
v-model="formLabelAlign.equipName"
clearable
filterable
placeholder="请选择"
size="small"
>
<el-option <el-option
v-for="(item, index) in selectEquipOptions" v-for="(item, index) in selectEquipOptions"
:label="item" :label="item"
@ -27,10 +39,16 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="5">
<el-form-item label="工序:"> <el-form-item label="工序:">
<!-- <el-input v-model="formLabelAlign.processName" placeholder="请输入"></el-input> --> <!-- <el-input v-model="formLabelAlign.processName" placeholder="请输入"></el-input> -->
<el-select v-model="formLabelAlign.processName" clearable filterable placeholder="请选择"> <el-select
v-model="formLabelAlign.processName"
clearable
filterable
placeholder="请选择"
size="small"
>
<el-option <el-option
v-for="(item, index) in selectProcessOptions" v-for="(item, index) in selectProcessOptions"
:label="item.name" :label="item.name"
@ -40,20 +58,23 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="5">
<el-form-item label="时间:"> <el-form-item label="时间:">
<el-date-picker <el-date-picker
v-model="formLabelAlign.startTime" v-model="formLabelAlign.startTime"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择日期" placeholder="选择日期"
size="small"
></el-date-picker> ></el-date-picker>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="4">
<div style="float: right"> <div style="float: right">
<el-button type="primary" icon="el-icon-search" @click="handleSubmit"> 搜索 </el-button> <el-button type="primary" icon="el-icon-search" @click="handleSubmit" size="small">
<el-button icon="el-icon-delete" @click="handleReset"> 清空 </el-button> 搜索
</el-button>
<el-button icon="el-icon-delete" @click="handleReset" size="small"> 清空 </el-button>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -87,23 +108,25 @@
<div class="info-title-cell info-title-no">零件号</div> <div class="info-title-cell info-title-no">零件号</div>
<div class="info-title-cell">批次号</div> <div class="info-title-cell">批次号</div>
<div class="info-title-cell info-title-num">数量</div> <div class="info-title-cell info-title-num">数量</div>
<div class="info-title-cell">质量等级</div> <div class="info-title-cell info-title-num">质量等级</div>
</div> </div>
<div <div class="info-container">
v-for="(order, index) in currentPageOrders" <div
:key="index" v-for="(order, index) in currentPageOrders"
:style="{ :key="index"
height: getRowHeight(order.woCode) + 'px', :style="{
borderBottom: '1px solid #ccc', height: getRowHeight(order.woCode) + 'px',
lineHeight: getRowHeight(order.woCode) + 'px', borderBottom: '1px solid #ccc',
}" lineHeight: getRowHeight(order.woCode) + 'px',
> }"
<div class="info-item"> >
<div class="info-cell info-title-no">{{ order.woCode }}</div> <div class="info-item">
<div class="info-cell info-title-no">{{ order.partCode }}</div> <div class="info-cell info-title-no">{{ order.woCode }}</div>
<div class="info-cell">{{ order.batchNo }}</div> <div class="info-cell info-title-no">{{ order.partCode }}</div>
<div class="info-cell info-title-num">{{ order.makeQty }}</div> <div class="info-cell">{{ order.batchNo }}</div>
<div class="info-cell">{{ order.productIdent }}</div> <div class="info-cell info-title-num">{{ order.makeQty }}</div>
<div class="info-cell info-title-num">{{ order.productIdent }}</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -131,6 +154,16 @@
{{ time }} {{ time }}
</div> </div>
</div> </div>
<div v-if="zoomLevel >= 3" class="quarter-labels">
<div
v-for="(time, index) in quarterTickLabels"
:key="index"
class="quarter-label"
:style="{ left: `${(index / (24 * 4)) * 100}%` }"
>
{{ time }}
</div>
</div>
</div> </div>
<div class="tick-lines" :style="{ width: `${timelineWidth}%` }"> <div class="tick-lines" :style="{ width: `${timelineWidth}%` }">
<div <div
@ -147,6 +180,14 @@
:style="{ left: `${(index / (24 * 2)) * 100}%` }" :style="{ left: `${(index / (24 * 2)) * 100}%` }"
></div> ></div>
</div> </div>
<div v-if="zoomLevel >= 3" class="quarter-tick-lines">
<div
v-for="(time, index) in quarterTickLabels"
:key="index"
class="quarter-tick-line"
:style="{ left: `${(index / (24 * 4)) * 100}%` }"
></div>
</div>
<div class="axis-base-line"></div> <div class="axis-base-line"></div>
<!-- 当前时间线 --> <!-- 当前时间线 -->
<div class="current-time-line" :style="{ left: `${currentTimePosition}%` }"></div> <div class="current-time-line" :style="{ left: `${currentTimePosition}%` }"></div>
@ -169,7 +210,7 @@
v-for="(order, index) in currentPageOrders" v-for="(order, index) in currentPageOrders"
:key="index" :key="index"
class="device-task-row" class="device-task-row"
:style="{ height: getRowHeight(order.woCode) + 'px' }" :style="{ height: getRowChartHeight(order.woCode) + 'px' }"
> >
<template <template
v-for="(layer, layerIndex) in getLayeredTasks(order.woCode)" v-for="(layer, layerIndex) in getLayeredTasks(order.woCode)"
@ -205,7 +246,7 @@
</div> </div>
</div> </div>
<!-- 分页控件 sizes :page-sizes="[10, 20, 50]"--> <!-- 分页控件 sizes :page-sizes="[10, 20, 50]" ,sizes-->
<div class="pagination-container"> <div class="pagination-container">
<el-pagination <el-pagination
@size-change="handleSizeChange" @size-change="handleSizeChange"
@ -289,11 +330,7 @@
</template> </template>
<script> <script>
import { import { getData, selectEquip, selectTeam } from '@/api/productionSchedulingPlan/scheduling';
getData,
selectEquip,
selectTeam,
} from '@/api/productionSchedulingPlan/scheduling';
import { getProcessSet } from '@/api/productionSchedulingPlan/basic'; import { getProcessSet } from '@/api/productionSchedulingPlan/basic';
export default { export default {
name: 'GanttChart', name: 'GanttChart',
@ -306,7 +343,7 @@ export default {
processName: '', // processName: '', //
woCode: '', // woCode: '', //
}, },
zoomLevel: 3, // (1-4) zoomLevel: 12, // (1-4)
minZoom: 1, minZoom: 1,
maxZoom: 4, maxZoom: 4,
@ -318,7 +355,7 @@ export default {
// //
currentPage: 1, currentPage: 1,
pageSize: 7, pageSize: 10,
// //
tooltipVisible: false, tooltipVisible: false,
@ -328,6 +365,7 @@ export default {
// //
baseRowHeight: 36, baseRowHeight: 36,
baseRowChartHeight: 37,
rowHeights: {}, rowHeights: {},
selectTeamOptions: [], selectTeamOptions: [],
selectEquipOptions: [], selectEquipOptions: [],
@ -352,6 +390,30 @@ export default {
} }
return labels; return labels;
}, },
quarterTickLabels() {
const labels = [];
for (let hour = 0; hour < 24; hour++) {
labels.push(''); // 0
labels.push(`${hour}:15`);
labels.push(''); // 30
labels.push(`${hour}:45`);
}
return labels;
},
tenMinuteTickLabels() {
const labels = [];
for (let hour = 0; hour < 24; hour++) {
// 6100,10,20,30,40,50
// 030
labels.push(''); // 0
labels.push(`${hour}:10`);
labels.push(`${hour}:20`);
labels.push(''); // 30
labels.push(`${hour}:40`);
labels.push(`${hour}:50`);
}
return labels;
},
}, },
mounted() { mounted() {
this.formLabelAlign.startTime = new Date().toISOString().substr(0, 10); this.formLabelAlign.startTime = new Date().toISOString().substr(0, 10);
@ -361,9 +423,9 @@ export default {
this.getData(); this.getData();
this.calcCurrentTimePosition(); this.calcCurrentTimePosition();
// 线 // 线
setInterval(() => { // setInterval(() => {
this.calcCurrentTimePosition(); // this.calcCurrentTimePosition();
}, 60000); // // }, 60000); //
}, },
methods: { methods: {
// //
@ -442,6 +504,7 @@ export default {
partCode: firstTask.partCode, partCode: firstTask.partCode,
batchNo: firstTask.batchNo, batchNo: firstTask.batchNo,
makeQty: firstTask.makeQty, makeQty: firstTask.makeQty,
productIdent: firstTask.productIdent,
}); });
} }
// //
@ -584,7 +647,7 @@ export default {
this.tooltipVisible = false; this.tooltipVisible = false;
}, },
// //
getRowHeight(device) { getRowHeight(device) {
const layers = this.getLayeredTasks(device); const layers = this.getLayeredTasks(device);
const layerCount = layers.length; const layerCount = layers.length;
@ -592,21 +655,29 @@ export default {
this.rowHeights[device] = height; this.rowHeights[device] = height;
return height; return height;
}, },
//
getRowChartHeight(device) {
const layers = this.getLayeredTasks(device);
const layerCount = layers.length;
const height = Math.max(this.baseRowChartHeight, layerCount * this.baseRowChartHeight);
this.rowHeights[device] = height;
return height;
},
getLayerOffset(layerIndex, totalLayers, device) { getLayerOffset(layerIndex, totalLayers, device) {
const rowHeight = this.getRowHeight(device); const rowHeight = this.getRowChartHeight(device);
if (totalLayers <= 1) return 2; if (totalLayers <= 1) return 2;
const totalSpacing = totalLayers * 4; const totalSpacing = totalLayers * 4;
const availableHeight = rowHeight - totalSpacing; const availableHeight = rowHeight - totalSpacing;
const layerHeight = availableHeight / totalLayers; const layerHeight = availableHeight / totalLayers;
return layerIndex * (layerHeight + 18) + 2; return layerIndex * (layerHeight + 18) + 4;
}, },
getLayerTaskHeight(totalLayers, device) { getLayerTaskHeight(totalLayers, device) {
const rowHeight = this.getRowHeight(device); const rowHeight = this.getRowChartHeight(device);
if (totalLayers <= 1) { if (totalLayers <= 1) {
return rowHeight - 18; return rowHeight - 18;
} else { } else {
const totalSpacing = totalLayers * 4; const totalSpacing = totalLayers * 18;
const availableHeight = rowHeight - totalSpacing; const availableHeight = rowHeight - totalSpacing;
return availableHeight / totalLayers; return availableHeight / totalLayers;
} }
@ -662,10 +733,11 @@ export default {
padding: 20px; padding: 20px;
box-sizing: border-box; box-sizing: border-box;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
height: calc(100% - 72px);
} }
.gantt-header { .gantt-header {
height: 40px; height: 15px;
margin-bottom: 10px; margin-bottom: 10px;
} }
@ -701,33 +773,37 @@ export default {
.gantt-wrapper { .gantt-wrapper {
display: flex; display: flex;
height: calc(100% - 120px); height: calc(100% - 180px);
border: 1px solid #eee; /* border: 1px solid #eee; */
overflow: hidden; overflow: hidden;
} }
/* 左侧信息列表样式 */ /* 左侧信息列表样式 */
.info-list { .info-list {
width: 450px; width: 480px;
background-color: #f8f9fa; background-color: #f8f9fa;
border-right: 1px solid #eee; /* border-right: 1px solid #eee; */
flex-shrink: 0; flex-shrink: 0;
} }
.info-container {
/* margin-bottom:-16px;
padding-bottom:16px */
}
.info-item-title { .info-item-title {
display: flex; display: flex;
background: #284c89; background: #284c89;
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
height: 36px; height: 25px;
} }
.info-title-cell { .info-title-cell {
flex: 1; flex: 1;
text-align: center; text-align: center;
line-height: 36px; line-height: 25px;
border-right: 1px solid #eee; border-right: 1px solid #eee;
font-size:14px; font-size: 12px;
} }
.info-title-num { .info-title-num {
width: 50px; width: 50px;
@ -746,7 +822,7 @@ export default {
.info-cell { .info-cell {
flex: 1; flex: 1;
text-align: center; text-align: center;
padding: 5px; /* padding: 5px; */
box-sizing: border-box; box-sizing: border-box;
border-right: 1px solid #eee; border-right: 1px solid #eee;
overflow: hidden; overflow: hidden;
@ -760,11 +836,13 @@ export default {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-y: hidden; overflow-y: hidden;
/* 添加固定高度,确保滚动条不会挤压内容 */
/* height: calc(100vh - 240px); */
} }
/* 图表X轴区域样式 */ /* 图表X轴区域样式 */
.chart-axis { .chart-axis {
height: 36px; height: 25px;
position: relative; position: relative;
} }
@ -773,7 +851,7 @@ export default {
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 30px; height: 25px;
display: flex; display: flex;
background-color: #284c89; background-color: #284c89;
} }
@ -782,11 +860,11 @@ export default {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
font-size: 16px; font-size: 14px;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
white-space: nowrap; white-space: nowrap;
line-height: 30px; line-height: 25px;
} }
.minor-labels { .minor-labels {
@ -801,10 +879,10 @@ export default {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
font-size: 13px; font-size: 12px;
color: #fff; color: #fff;
white-space: nowrap; white-space: nowrap;
line-height: 30px; line-height: 25px;
padding: 0 2px; padding: 0 2px;
} }
@ -833,12 +911,47 @@ export default {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
/* 15分钟刻度样式 */
.quarter-labels {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.quarter-label {
position: absolute;
top: 0;
left: 0;
font-size: 11px;
color: #e0e0e0;
white-space: nowrap;
line-height: 30px;
padding: 0 2px;
}
.quarter-tick-lines {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
.quarter-tick-line {
position: absolute;
bottom: 0;
width: 1px;
height: 2px;
background-color: #e0e0e0;
transform: translateX(-50%);
}
.minor-tick-line { .minor-tick-line {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
width: 1px; width: 1px;
height: 4px; height: 3px;
background-color: #fff; background-color: #fff;
transform: translateX(-50%); transform: translateX(-50%);
} }
@ -855,13 +968,13 @@ export default {
/* 当前时间线样式 */ /* 当前时间线样式 */
.current-time-line { .current-time-line {
position: absolute; position: absolute;
top: 0; top: 0px;
bottom: 0; bottom: 0;
width: 2px; width: 2px;
/* background-color: #ff4d4f; */ /* background-color: #ff4d4f; */
transform: translateX(-50%); transform: translateX(-50%);
z-index: 10; z-index: 10;
height: 100vh; height: calc(100vh - 130px);
border-left: 1px dashed #ccc; border-left: 1px dashed #ccc;
} }
@ -871,6 +984,9 @@ export default {
position: relative; position: relative;
overflow-y: auto; overflow-y: auto;
overflow-x: auto; overflow-x: auto;
/* 预留横向滚动条高度 */
/* padding-bottom: 16px;
margin-bottom: -16px; */
} }
.grid-lines { .grid-lines {
@ -893,8 +1009,9 @@ export default {
.tasks-container { .tasks-container {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; min-height: 100%;
/* overflow:hidden; */ /* height:500px; */
overflow-x: hidden; overflow-x: hidden;
} }
@ -990,6 +1107,7 @@ export default {
background-color: #fff; /* 增加背景色避免与内容重叠时看不清 */ background-color: #fff; /* 增加背景色避免与内容重叠时看不清 */
padding: 10px; /* 增加内边距 */ padding: 10px; /* 增加内边距 */
z-index: 10; z-index: 10;
/* width:100%; */
} }
:deep(.el-button--primary) { :deep(.el-button--primary) {

Loading…
Cancel
Save