|
|
|
@ -167,8 +167,13 @@ |
|
|
|
<div class="todo-main-title"> |
|
|
|
{{ item.orderNo || '-' }} |
|
|
|
</div> |
|
|
|
<div class="todo-process-chip" :title="buildProcessExceptionLabel(item)"> |
|
|
|
{{ buildProcessExceptionLabel(item) }} |
|
|
|
<div class="todo-process-metrics"> |
|
|
|
<div class="todo-process-chip" :title="buildProcessExceptionLabel(item)"> |
|
|
|
{{ buildProcessExceptionLabel(item) }} |
|
|
|
</div> |
|
|
|
<div class="todo-rate-chip" :title="buildMinTriggerTotalYieldRateLabel(item)"> |
|
|
|
{{ buildMinTriggerTotalYieldRateLabel(item) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
@ -247,9 +252,14 @@ |
|
|
|
append-to-body> |
|
|
|
<div slot="title" class="todo-detail-dialog-title"> |
|
|
|
<span class="todo-detail-dialog-title-main">{{ detailDialogTitle }}</span> |
|
|
|
<span class="todo-detail-dialog-title-process" :title="buildProcessExceptionLabel({ mrbInspectionReport: detailProcessExceptionNo })"> |
|
|
|
{{ buildProcessExceptionLabel({ mrbInspectionReport: detailProcessExceptionNo }) }} |
|
|
|
</span> |
|
|
|
<div class="todo-detail-dialog-title-metrics"> |
|
|
|
<span class="todo-detail-dialog-title-process" :title="buildProcessExceptionLabel({ mrbInspectionReport: detailProcessExceptionNo })"> |
|
|
|
{{ buildProcessExceptionLabel({ mrbInspectionReport: detailProcessExceptionNo }) }} |
|
|
|
</span> |
|
|
|
<span class="todo-detail-dialog-title-rate" :title="buildMinTriggerTotalYieldRateLabel({ minTriggerTotalYieldRate: detailMinTriggerTotalYieldRate })"> |
|
|
|
{{ buildMinTriggerTotalYieldRateLabel({ minTriggerTotalYieldRate: detailMinTriggerTotalYieldRate }) }} |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div v-loading="detailDialogLoading" class="todo-detail-content"> |
|
|
|
<div v-if="detailSections.length === 0" class="todo-detail-empty-tip"> |
|
|
|
@ -288,7 +298,8 @@ |
|
|
|
:data="section.rowList" |
|
|
|
border |
|
|
|
style="width: 100%; margin-top: 10px;" |
|
|
|
max-height="320"> |
|
|
|
max-height="320" |
|
|
|
:span-method="detailObjectSpanMethod"> |
|
|
|
<el-table-column prop="rowNumber" label="NO." width="50" align="center"></el-table-column> |
|
|
|
<el-table-column label="良品数" width="80" align="center"> |
|
|
|
<template slot-scope="scope"> |
|
|
|
@ -323,6 +334,11 @@ |
|
|
|
<div class="readonly-number yield">{{ scope.row.yieldRate }}</div> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="总良率" width="88" align="center"> |
|
|
|
<template slot-scope="scope"> |
|
|
|
<div class="readonly-number total-yield">{{ scope.row.totalYieldRate }}</div> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="总数" width="80" align="right"> |
|
|
|
<template slot-scope="scope"> |
|
|
|
<div class="readonly-number" style="text-align: right; padding-right: 10px;"> |
|
|
|
@ -418,6 +434,7 @@ export default { |
|
|
|
detailDialogLoading: false, |
|
|
|
detailDialogTitle: '创建分卷详情', |
|
|
|
detailProcessExceptionNo: '', |
|
|
|
detailMinTriggerTotalYieldRate: '', |
|
|
|
detailSections: [], |
|
|
|
showMrbRegisterFlag: false, |
|
|
|
currentAuditTodo: null, |
|
|
|
@ -565,6 +582,7 @@ export default { |
|
|
|
resetDetailData () { |
|
|
|
this.detailSections = [] |
|
|
|
this.detailProcessExceptionNo = '' |
|
|
|
this.detailMinTriggerTotalYieldRate = '' |
|
|
|
}, |
|
|
|
resolveProcessExceptionNo (row) { |
|
|
|
if (!row) { |
|
|
|
@ -573,10 +591,56 @@ export default { |
|
|
|
const value = row.mrbInspectionReport || row.processExceptionNo || '' |
|
|
|
return String(value).trim() |
|
|
|
}, |
|
|
|
normalizePercentLabel (value) { |
|
|
|
if (value === null || value === undefined) { |
|
|
|
return '' |
|
|
|
} |
|
|
|
const text = String(value).trim().replace('%', '') |
|
|
|
if (!text) { |
|
|
|
return '' |
|
|
|
} |
|
|
|
const num = Number(text) |
|
|
|
if (Number.isNaN(num)) { |
|
|
|
return '' |
|
|
|
} |
|
|
|
return num.toFixed(2) + '%' |
|
|
|
}, |
|
|
|
resolveMinTriggerTotalYieldRate (row) { |
|
|
|
if (!row) { |
|
|
|
return '' |
|
|
|
} |
|
|
|
const value = row.minTriggerTotalYieldRate || row.triggerMinTotalYieldRate || row.minTotalYieldRate || '' |
|
|
|
return this.normalizePercentLabel(value) |
|
|
|
}, |
|
|
|
resolveMinTriggerTotalYieldRateFromRows (rowList) { |
|
|
|
const list = Array.isArray(rowList) ? rowList : [] |
|
|
|
let minRate = null |
|
|
|
for (let i = 0; i < list.length; i++) { |
|
|
|
const formattedRate = this.normalizePercentLabel(list[i] && list[i].totalYieldRate) |
|
|
|
if (!formattedRate) { |
|
|
|
continue |
|
|
|
} |
|
|
|
const num = Number(formattedRate.replace('%', '')) |
|
|
|
if (Number.isNaN(num)) { |
|
|
|
continue |
|
|
|
} |
|
|
|
if (minRate === null || num < minRate) { |
|
|
|
minRate = num |
|
|
|
} |
|
|
|
} |
|
|
|
if (minRate === null) { |
|
|
|
return '' |
|
|
|
} |
|
|
|
return minRate.toFixed(2) + '%' |
|
|
|
}, |
|
|
|
buildProcessExceptionLabel (row) { |
|
|
|
const processExceptionNo = this.resolveProcessExceptionNo(row) |
|
|
|
return processExceptionNo || '-' |
|
|
|
}, |
|
|
|
buildMinTriggerTotalYieldRateLabel (row) { |
|
|
|
const minTriggerTotalYieldRate = this.resolveMinTriggerTotalYieldRate(row) |
|
|
|
return minTriggerTotalYieldRate || '-' |
|
|
|
}, |
|
|
|
toInt (value) { |
|
|
|
const num = Number(value) |
|
|
|
if (Number.isNaN(num)) { |
|
|
|
@ -598,8 +662,88 @@ export default { |
|
|
|
} |
|
|
|
return ((goodQty / totalQty) * 100).toFixed(2) + '%' |
|
|
|
}, |
|
|
|
pickRollTextValue (rows, fieldName) { |
|
|
|
const groupRows = Array.isArray(rows) ? rows : [] |
|
|
|
for (let i = 0; i < groupRows.length; i++) { |
|
|
|
const current = groupRows[i] || {} |
|
|
|
const value = current[fieldName] |
|
|
|
if (value !== null && value !== undefined && String(value).trim() !== '') { |
|
|
|
return String(value) |
|
|
|
} |
|
|
|
} |
|
|
|
return '' |
|
|
|
}, |
|
|
|
applyRollTotalYieldRate (rowList, rollCount) { |
|
|
|
const list = Array.isArray(rowList) ? rowList.map(item => ({ ...item })) : [] |
|
|
|
if (list.length === 0) { |
|
|
|
return list |
|
|
|
} |
|
|
|
|
|
|
|
const normalizedRollCount = this.toInt(rollCount) |
|
|
|
if (!normalizedRollCount || normalizedRollCount <= 0) { |
|
|
|
return list.map(item => ({ |
|
|
|
...item, |
|
|
|
totalYieldRate: item.yieldRate || this.calcYieldRate(this.toNum(item.goodQty), this.toNum(item.defectQty)), |
|
|
|
rollRowspan: 1 |
|
|
|
})) |
|
|
|
} |
|
|
|
|
|
|
|
const rowsPerRoll = Math.floor(list.length / normalizedRollCount) |
|
|
|
const remainingRows = list.length % normalizedRollCount |
|
|
|
let currentIndex = 0 |
|
|
|
for (let i = 0; i < normalizedRollCount; i++) { |
|
|
|
const currentRollRows = rowsPerRoll + (i < remainingRows ? 1 : 0) |
|
|
|
if (currentRollRows <= 0 || currentIndex >= list.length) { |
|
|
|
continue |
|
|
|
} |
|
|
|
const endIndex = Math.min(currentIndex + currentRollRows, list.length) |
|
|
|
let rollGoodQty = 0 |
|
|
|
let rollDefectQty = 0 |
|
|
|
for (let idx = currentIndex; idx < endIndex; idx++) { |
|
|
|
rollGoodQty += this.toNum(list[idx].goodQty) |
|
|
|
rollDefectQty += this.toNum(list[idx].defectQty) |
|
|
|
} |
|
|
|
const totalYieldRate = this.calcYieldRate(rollGoodQty, rollDefectQty) |
|
|
|
const rollRows = list.slice(currentIndex, endIndex) |
|
|
|
const mergedPackingList = this.pickRollTextValue(rollRows, 'packingList') |
|
|
|
const mergedRemark = this.pickRollTextValue(rollRows, 'remark') |
|
|
|
for (let idx = currentIndex; idx < endIndex; idx++) { |
|
|
|
list[idx].totalYieldRate = totalYieldRate |
|
|
|
list[idx].packingList = mergedPackingList |
|
|
|
list[idx].remark = mergedRemark |
|
|
|
list[idx].rollRowspan = idx === currentIndex ? (endIndex - currentIndex) : 0 |
|
|
|
} |
|
|
|
currentIndex = endIndex |
|
|
|
} |
|
|
|
|
|
|
|
// 兜底:异常分组情况下,未赋值行按自身良率显示 |
|
|
|
for (let i = 0; i < list.length; i++) { |
|
|
|
if (!list[i].totalYieldRate) { |
|
|
|
list[i].totalYieldRate = list[i].yieldRate || this.calcYieldRate(this.toNum(list[i].goodQty), this.toNum(list[i].defectQty)) |
|
|
|
} |
|
|
|
if (this.toInt(list[i].rollRowspan) === null) { |
|
|
|
list[i].rollRowspan = 1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return list |
|
|
|
}, |
|
|
|
detailObjectSpanMethod ({ row, column }) { |
|
|
|
if (!row || !column) { |
|
|
|
return |
|
|
|
} |
|
|
|
const needMerge = column.label === '总量率' || column.label === 'Packing List' || column.label === '备注' |
|
|
|
if (!needMerge) { |
|
|
|
return |
|
|
|
} |
|
|
|
const rowspan = this.toInt(row.rollRowspan) |
|
|
|
if (rowspan !== null && rowspan > 0) { |
|
|
|
return { rowspan: rowspan, colspan: 1 } |
|
|
|
} |
|
|
|
return { rowspan: 0, colspan: 0 } |
|
|
|
}, |
|
|
|
mapCacheDetailRows (cacheList) { |
|
|
|
return (cacheList || []).map(item => { |
|
|
|
const mappedRows = (cacheList || []).map(item => { |
|
|
|
const goodQty = this.toNum(item.goodQty) |
|
|
|
const defectQty = this.toNum(item.defectQty) |
|
|
|
const totalQty = goodQty + defectQty |
|
|
|
@ -615,18 +759,21 @@ export default { |
|
|
|
remark: item.remark || '' |
|
|
|
} |
|
|
|
}) |
|
|
|
return mappedRows.sort((a, b) => this.toInt(a.rowNumber) - this.toInt(b.rowNumber)) |
|
|
|
}, |
|
|
|
buildDetailSection (key, title, detailList) { |
|
|
|
const list = detailList || [] |
|
|
|
const first = list.length > 0 ? list[0] : {} |
|
|
|
const rollCount = this.toInt(first.rollCount) || 0 |
|
|
|
const rowList = this.mapCacheDetailRows(list) |
|
|
|
return { |
|
|
|
key: key, |
|
|
|
title: title, |
|
|
|
cacheTime: this.formatDateTime(first.createdTime), |
|
|
|
fixture: first.fixtureNo || '', |
|
|
|
rowCount: this.toInt(first.rowCount) || list.length, |
|
|
|
rollCount: this.toInt(first.rollCount) || 0, |
|
|
|
rowList: this.mapCacheDetailRows(list) |
|
|
|
rollCount: rollCount, |
|
|
|
rowList: this.applyRollTotalYieldRate(rowList, rollCount) |
|
|
|
} |
|
|
|
}, |
|
|
|
openTodoAuditModal (row) { |
|
|
|
@ -737,6 +884,7 @@ export default { |
|
|
|
this.detailDialogLoading = true |
|
|
|
this.resetDetailData() |
|
|
|
this.detailProcessExceptionNo = this.resolveProcessExceptionNo(row) |
|
|
|
this.detailMinTriggerTotalYieldRate = this.resolveMinTriggerTotalYieldRate(row) |
|
|
|
|
|
|
|
const query = { |
|
|
|
site: row.site || this.searchData.site || this.$store.state.user.site, |
|
|
|
@ -766,6 +914,10 @@ export default { |
|
|
|
sections.push(this.buildDetailSection('report', '审核后最终报告数据', reportList)) |
|
|
|
} |
|
|
|
this.detailSections = sections |
|
|
|
const triggerSection = sections.find(section => section.key === 'trigger') |
|
|
|
const triggerRateByRows = this.resolveMinTriggerTotalYieldRateFromRows(triggerSection ? triggerSection.rowList : []) |
|
|
|
const triggerRateByResult = this.resolveMinTriggerTotalYieldRate(resultMap) |
|
|
|
this.detailMinTriggerTotalYieldRate = triggerRateByRows || triggerRateByResult || this.detailMinTriggerTotalYieldRate |
|
|
|
if (sections.length === 0) { |
|
|
|
this.$message.warning('当前代办暂无详情数据') |
|
|
|
return |
|
|
|
@ -1089,8 +1241,17 @@ export default { |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-process-chip { |
|
|
|
.todo-process-metrics { |
|
|
|
max-width: 52%; |
|
|
|
min-width: 0; |
|
|
|
display: inline-flex; |
|
|
|
align-items: center; |
|
|
|
gap: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-process-chip { |
|
|
|
min-width: 0; |
|
|
|
flex: 1 1 auto; |
|
|
|
font-size: 11px; |
|
|
|
color: #2f7ed8; |
|
|
|
border: 1px solid #b3d8ff; |
|
|
|
@ -1103,6 +1264,18 @@ export default { |
|
|
|
text-overflow: ellipsis; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-rate-chip { |
|
|
|
flex: 0 0 auto; |
|
|
|
font-size: 11px; |
|
|
|
color: #3f51b5; |
|
|
|
border: 1px solid #c5cae9; |
|
|
|
background: #e8eaf6; |
|
|
|
border-radius: 999px; |
|
|
|
line-height: 18px; |
|
|
|
padding: 0 8px; |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-detail-line { |
|
|
|
margin-top: 6px; |
|
|
|
display: flex; |
|
|
|
@ -1213,8 +1386,17 @@ export default { |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-detail-dialog-title-process { |
|
|
|
.todo-detail-dialog-title-metrics { |
|
|
|
flex-shrink: 0; |
|
|
|
min-width: 0; |
|
|
|
max-width: 380px; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-detail-dialog-title-process { |
|
|
|
min-width: 0; |
|
|
|
max-width: 310px; |
|
|
|
color: #2f7ed8; |
|
|
|
font-size: 12px; |
|
|
|
@ -1228,6 +1410,18 @@ export default { |
|
|
|
text-overflow: ellipsis; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-detail-dialog-title-rate { |
|
|
|
flex: 0 0 auto; |
|
|
|
color: #3f51b5; |
|
|
|
font-size: 12px; |
|
|
|
border: 1px solid #c5cae9; |
|
|
|
background: #e8eaf6; |
|
|
|
border-radius: 999px; |
|
|
|
padding: 2px 10px; |
|
|
|
line-height: 18px; |
|
|
|
white-space: nowrap; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-detail-content { |
|
|
|
min-height: 120px; |
|
|
|
} |
|
|
|
@ -1309,6 +1503,11 @@ export default { |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-cache-detail-dialog .readonly-number.total-yield { |
|
|
|
color: #409eff; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
|
|
|
|
.todo-cache-detail-dialog /deep/ .todo-detail-table td.remark-column, |
|
|
|
.todo-cache-detail-dialog /deep/ .todo-detail-table td.packing-list-column { |
|
|
|
padding: 0 !important; |
|
|
|
|