feat: update MES tracking and reporting workflows

This commit is contained in:
2026-06-30 17:41:40 +08:00
parent e0e1b5d2bb
commit 1399b9a80a
47 changed files with 4465 additions and 90 deletions

View File

@@ -79,6 +79,7 @@
<el-table-column align="center" label="物料编码" prop="缺件物料编码" min-width="180" show-overflow-tooltip />
<el-table-column align="center" label="物料名称" prop="缺件物料名称" width="150" show-overflow-tooltip />
<el-table-column align="center" label="缺件数量" prop="缺件数量" width="90" />
<el-table-column align="center" label="库存数量" prop="库存数量" width="90" />
<el-table-column align="center" label="属性" prop="缺件属性" width="90" />
<el-table-column align="center" label="生产订单号" prop="缺件生产订单号" width="100" />
<el-table-column align="center" label="进度" prop="进度" width="130" show-overflow-tooltip />
@@ -93,7 +94,6 @@
<el-table-column align="center" label="预计完成时间" width="130">
<template slot-scope="detail">{{ formatDate(detail.row.预计完成时间) }}</template>
</el-table-column>
<el-table-column align="center" label="采购员" prop="采购员" width="90" show-overflow-tooltip />
<el-table-column align="center" label="采购未清数量" prop="采购未清数量" width="110" />
<el-table-column align="center" label="到货草稿" prop="到货草稿" width="90" />
<el-table-column align="center" label="质检状态" width="90">
@@ -269,13 +269,13 @@ export default {
缺件物料编码: row.缺件物料编码,
缺件物料名称: row.缺件物料名称,
缺件数量: this.formatQuantity(row.缺件数量),
库存数量: this.formatQuantity(row.库存数量),
缺件属性: row.缺件属性,
缺件生产订单号: row.缺件生产订单号,
进度: row.进度,
工艺路线: row.工艺路线,
工艺路线明细: this.parseRouteDetails(row.工艺路线明细),
预计完成时间: row.预计完成时间,
采购员: row.采购员,
采购未清数量: this.formatQuantity(row.采购未清数量),
到货草稿: row.到货草稿,
质检状态: row.质检状态,
@@ -315,39 +315,88 @@ export default {
辅助结束: 3,
开始加工: 4,
暂停: 5,
报工: 6
报工: 6,
装配加工: 4
}
return statusMap[value] || 0
},
isProcessComplete(process) {
const progress = this.toProcessNumber(process.进度)
const planCount = this.toProcessNumber(process.计划数量)
const finishCount = this.toProcessNumber(process.完成数量)
const checkedCount = this.toProcessNumber(process.收检合格数) + this.toProcessNumber(process.收检不合格数)
return progress >= 100 ||
(planCount > 0 && finishCount >= planCount) ||
(planCount > 0 && checkedCount >= planCount)
isOutsourceProcess(process) {
return process.指派对象 === '外协' ||
String(process.工序名称 || '').includes('(外协)') ||
String(process.工序名称 || '').includes('(外协)')
},
getProcessClass(process, index, processes) {
if (this.isProcessComplete(process)) {
return 'process-route-blue'
}
isBlueProcess(process) {
const statusNum = this.getProcessStatusNum(process.加工状态)
if (this.isValidProcessDate(process.开工时间) || [2, 4].includes(statusNum) || this.toProcessNumber(process.进度) > 0) {
const countNum = parseInt(process.收检合格数)
return statusNum === 6 || statusNum === 3 || countNum > 0
},
isGreenProcess(process) {
return this.isOutsourceProcess(process) &&
this.toProcessNumber(process.收料数量) > this.toProcessNumber(process.收检合格数) + this.toProcessNumber(process.收检不合格数)
},
getProcessBaseClass(process) {
if (this.isGreenProcess(process)) {
return 'process-route-green'
}
if (index > 0 && this.isProcessComplete(processes[index - 1])) {
return 'process-route-orange'
if (this.isBlueProcess(process)) {
return 'process-route-blue'
}
const statusNum = this.getProcessStatusNum(process.加工状态)
if (statusNum === 2 || statusNum === 4) {
return 'process-route-green'
}
return 'process-route-red'
},
getRouteProcessName(process) {
const name = String(process.工序名称 || '')
const assignee = String(process.指派对象 || '')
if (!assignee || name.includes(`(${assignee})`) || name.includes(`${assignee}`)) {
return name
getOutsourceGroupClassState(processes) {
const classes = new Map()
let currentIndexes = []
let lastProcess = null
const flushOutsourceRun = () => {
if (currentIndexes.length > 0 && lastProcess) {
const className = this.getProcessBaseClass(lastProcess)
currentIndexes.forEach(index => classes.set(index, className))
}
currentIndexes = []
lastProcess = null
}
return `${name}(${assignee})`
const isSameContinuousGroup = process => {
if (!lastProcess) {
return true
}
const lineNo = this.toProcessNumber(process.订单行号)
const lastLineNo = this.toProcessNumber(lastProcess.订单行号)
return lineNo === lastLineNo + 1 &&
String(process.外协分组 || '') === String(lastProcess.外协分组 || '')
}
processes.forEach((process, index) => {
if (!this.isOutsourceProcess(process)) {
flushOutsourceRun()
return
}
if (!isSameContinuousGroup(process)) {
flushOutsourceRun()
}
currentIndexes.push(index)
lastProcess = process
})
flushOutsourceRun()
return classes
},
getProcessClass(process, index, outsourceGroupClasses) {
if (this.isOutsourceProcess(process)) {
return outsourceGroupClasses.get(index) || this.getProcessBaseClass(process)
}
return this.getProcessBaseClass(process)
},
getRouteProcessName(process) {
return String(process.工序名称 || '')
},
escapeProcessHtml(value) {
return String(value == null ? '' : value)
@@ -365,6 +414,7 @@ export default {
const maxPerRow = 8
const rows = Math.ceil(processes.length / maxPerRow)
const outsourceGroupClasses = this.getOutsourceGroupClassState(processes)
let html = '<div class="process-route-wrap"><table class="process-route-table"><tbody>'
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
@@ -376,20 +426,20 @@ export default {
html += '<tr>'
rowProcesses.forEach((process, index) => {
const className = this.getProcessClass(process, startIndex + index, processes)
const className = this.getProcessClass(process, startIndex + index, outsourceGroupClasses)
const date = this.formatDate(process.计划开始时间 || process.计划完成时间)
html += `<td class="process-route-date ${className}">${this.escapeProcessHtml(date)}</td>`
if (index < rowProcesses.length - 1) html += '<td class="process-route-arrow-hidden"></td>'
})
html += '</tr><tr>'
rowProcesses.forEach((process, index) => {
const className = this.getProcessClass(process, startIndex + index, processes)
const className = this.getProcessClass(process, startIndex + index, outsourceGroupClasses)
html += `<td class="${className}">${this.escapeProcessHtml(this.getRouteProcessName(process))}</td>`
if (index < rowProcesses.length - 1) html += '<td class="process-route-arrow">→</td>'
})
html += '</tr><tr>'
rowProcesses.forEach((process, index) => {
const className = this.getProcessClass(process, startIndex + index, processes)
const className = this.getProcessClass(process, startIndex + index, outsourceGroupClasses)
const count = this.formatQuantity(process.收检合格数)
html += `<td class="process-route-count ${className}">合格${this.escapeProcessHtml(count)}</td>`
if (index < rowProcesses.length - 1) html += '<td class="process-route-arrow-hidden"></td>'
@@ -473,39 +523,53 @@ export default {
.process-route {
overflow-x: auto;
padding: 2px 0;
padding: 0;
text-align: left;
}
::v-deep .process-route-wrap {
min-width: 480px;
text-align: left;
}
::v-deep .process-route-table {
border-collapse: separate;
border-spacing: 0;
margin: 0 auto;
border-collapse: collapse;
margin: 0;
text-align: left;
table-layout: auto;
}
::v-deep .process-route-table td {
border-radius: 2px;
line-height: 20px;
min-width: 72px;
padding: 2px 5px;
text-align: center;
line-height: 1.4;
min-width: 35px;
padding: 2px 2px;
text-align: left;
white-space: nowrap;
}
::v-deep .process-route-date,
::v-deep .process-route-date {
color: #8899aa !important;
font-size: 10px !important;
padding: 2px 2px !important;
}
::v-deep .process-route-count {
font-size: 12px;
font-size: 12px !important;
font-weight: 700;
}
::v-deep .process-route-arrow,
::v-deep .process-route-arrow-hidden {
background: transparent;
color: #606266;
min-width: 18px;
width: 18px;
min-width: 8px;
padding: 2px 0 !important;
width: 8px;
}
::v-deep .process-route-arrow {
color: rgba(0, 164, 255, 0.6) !important;
font-size: 10px !important;
text-align: center !important;
}
::v-deep .process-route-arrow-hidden {
@@ -513,29 +577,24 @@ export default {
}
::v-deep .process-route-spacer td {
height: 6px;
line-height: 6px;
padding: 0;
height: 4px;
line-height: 1 !important;
padding: 0 !important;
}
::v-deep .process-route-green {
background: #f0f9eb;
color: #67c23a;
color: #28d961;
font-weight: 700;
}
::v-deep .process-route-blue {
background: #ecf5ff;
color: #409eff;
}
::v-deep .process-route-orange {
background: #fdf6ec;
color: #e6a23c;
color: #09a8ff;
font-weight: 700;
}
::v-deep .process-route-red {
background: #fef0f0;
color: #f56c6c;
color: #ff3f37;
font-weight: 700;
}
::v-deep .detail-row td {