feat: update MES pages and tracking docs
This commit is contained in:
544
src/views/PlanManagement/TimelyKitTrackingResult/index.vue
Normal file
544
src/views/PlanManagement/TimelyKitTrackingResult/index.vue
Normal file
@@ -0,0 +1,544 @@
|
||||
<template>
|
||||
<div class="timely-kit-page">
|
||||
<el-card>
|
||||
<div class="search-container" @keyup.enter="searchTable">
|
||||
<span class="show-text">生产订单:</span>
|
||||
<el-input v-model="orderNo" clearable placeholder="请输入生产订单" class="filter-control" />
|
||||
<span class="show-text">销售订单:</span>
|
||||
<el-input v-model="contractNo" clearable placeholder="请输入销售订单" class="filter-control" />
|
||||
<span class="show-text">物料编码:</span>
|
||||
<el-input v-model="productCode" clearable placeholder="请输入产品编码" class="filter-control" />
|
||||
<span class="show-text">计划号:</span>
|
||||
<el-input v-model="planNo" clearable placeholder="请输入计划号" class="filter-control" />
|
||||
<span class="show-text">发货状态:</span>
|
||||
<el-select v-model="shipmentStatus" clearable placeholder="请选择" class="filter-control">
|
||||
<el-option label="全部" value="全部" />
|
||||
<el-option label="已下达发货通知" value="已发货" />
|
||||
<el-option label="未下达发货通知" value="未发货" />
|
||||
</el-select>
|
||||
<span class="show-text">齐套:</span>
|
||||
<el-select v-model="complete" clearable placeholder="请选择" class="small-filter">
|
||||
<el-option label="全部" value="全部" />
|
||||
<el-option label="是" value="是" />
|
||||
<el-option label="否" value="否" />
|
||||
</el-select>
|
||||
<span class="show-text">完成状态:</span>
|
||||
<el-select v-model="checkStatus" clearable placeholder="请选择" class="filter-control">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="已完成" value="已完成" />
|
||||
<el-option label="未完成" value="未完成" />
|
||||
</el-select>
|
||||
<span class="show-text">发料状态:</span>
|
||||
<el-select v-model="sendStatus" clearable placeholder="请选择" class="filter-control">
|
||||
<el-option label="全部" value="全部" />
|
||||
<el-option label="发料齐套" value="发料齐套" />
|
||||
<el-option label="发料缺件" value="发料缺件" />
|
||||
<el-option label="未发料" value="未发料" />
|
||||
</el-select>
|
||||
<span class="show-text">自制件属性:</span>
|
||||
<el-select v-model="selfStatus" clearable placeholder="请选择" class="filter-control">
|
||||
<el-option label="全部" value="全部" />
|
||||
<el-option label="机加" value="机加" />
|
||||
<el-option label="装配" value="装配" />
|
||||
</el-select>
|
||||
<span class="show-text">计划开始:</span>
|
||||
<el-date-picker
|
||||
v-model="planStart"
|
||||
clearable
|
||||
format="yyyy-MM-dd"
|
||||
placeholder="选择日期"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
class="filter-control"
|
||||
/>
|
||||
<el-button :disabled="loading" icon="el-icon-search" plain type="primary" @click="searchTable">查询</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
:height="'78vh'"
|
||||
border
|
||||
element-loading-background="rgba(0, 0, 0, 0.2)"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
highlight-current-row
|
||||
size="mini"
|
||||
style="width: 100%; margin-top: 16px"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<el-table-column type="expand">
|
||||
<template slot-scope="scope">
|
||||
<el-table
|
||||
:data="scope.row.缺件明细"
|
||||
border
|
||||
size="mini"
|
||||
class="detail-table"
|
||||
:row-class-name="detailRowClassName"
|
||||
>
|
||||
<el-table-column align="center" label="序号" type="index" width="50" />
|
||||
<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="100" />
|
||||
<el-table-column align="center" label="进度" prop="进度" width="130" show-overflow-tooltip />
|
||||
<el-table-column align="center" label="工艺路线/采购状态" min-width="520">
|
||||
<template slot-scope="detail">
|
||||
<div v-if="detail.row.缺件属性 === '外购'" class="purchase-route">
|
||||
{{ detail.row.工艺路线 }}
|
||||
</div>
|
||||
<div v-else class="process-route" v-html="formatProcessRoute(detail.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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">
|
||||
<template slot-scope="detail">
|
||||
<div :style="getStatusStyle(detail.row.质检状态)" class="score-cell">{{ detail.row.质检状态 }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="序号" type="index" width="50" />
|
||||
<el-table-column align="center" prop="合同号" label="销售订单" width="110" show-overflow-tooltip />
|
||||
<el-table-column align="center" prop="计划号" label="计划号" width="100" show-overflow-tooltip />
|
||||
<el-table-column align="center" prop="订单号" label="生产订单" width="90" />
|
||||
<el-table-column align="center" prop="产品名称" label="产品名称" width="160" show-overflow-tooltip />
|
||||
<el-table-column align="center" prop="产品编码" label="产品编码" min-width="210" show-overflow-tooltip />
|
||||
<el-table-column align="center" prop="计划数量订单" label="计划数量" width="80" />
|
||||
<el-table-column align="center" prop="入库数量" label="入库数量" width="80" />
|
||||
<el-table-column align="center" label="要求完工日" width="120">
|
||||
<template slot-scope="scope">{{ formatDate(scope.row.要求完工日期) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="要求发货日" width="120">
|
||||
<template slot-scope="scope">{{ formatDate(scope.row.要求发货日期) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="预计齐套时间" width="130">
|
||||
<template slot-scope="scope">{{ formatDate(scope.row.预计齐套时间) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="齐套" width="80">
|
||||
<template slot-scope="scope">
|
||||
<div :style="getStatusStyle(scope.row.齐套)" class="score-cell">{{ scope.row.齐套 }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="拣配状态" width="90">
|
||||
<template slot-scope="scope">
|
||||
<div :style="getStatusStyle(scope.row.拣配状态)" class="score-cell">{{ scope.row.拣配状态 }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="发料状态" width="90">
|
||||
<template slot-scope="scope">
|
||||
<div :style="getStatusStyle(scope.row.发料状态)" class="score-cell">{{ scope.row.发料状态 }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="装配开工" width="90">
|
||||
<template slot-scope="scope">
|
||||
<div :style="getStatusStyle(scope.row.装配开工)" class="score-cell">{{ scope.row.装配开工 }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" prop="完成数量" label="送检数量" width="90" />
|
||||
<el-table-column align="center" label="终检" width="70">
|
||||
<template slot-scope="scope">
|
||||
<div :style="getStatusStyle(scope.row.终检)" class="score-cell">{{ scope.row.终检 }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="工艺" width="70">
|
||||
<template slot-scope="scope">
|
||||
<div :style="getStatusStyle(scope.row.生产工艺)" class="score-cell">{{ scope.row.生产工艺 }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="缺件项" width="80">
|
||||
<template slot-scope="scope">{{ scope.row.缺件明细.length }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TimelyKitTrackingResult',
|
||||
data() {
|
||||
return {
|
||||
orderNo: '',
|
||||
contractNo: '',
|
||||
productCode: '',
|
||||
productName: '',
|
||||
processName: '',
|
||||
planNo: '',
|
||||
shipmentStatus: '全部',
|
||||
complete: '全部',
|
||||
checkStatus: '',
|
||||
sendStatus: '全部',
|
||||
selfStatus: '全部',
|
||||
planStart: '',
|
||||
tableData: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.searchTable()
|
||||
},
|
||||
methods: {
|
||||
async searchTable() {
|
||||
this.loading = true
|
||||
this.tableData = []
|
||||
|
||||
const param = []
|
||||
param.push(['订单号', this.orderNo || 0])
|
||||
param.push(['物料类型', '自制件'])
|
||||
param.push(['合同号', this.contractNo])
|
||||
param.push(['产品编码', this.productCode])
|
||||
param.push(['产品名称', this.productName])
|
||||
param.push(['工序名称', this.processName])
|
||||
param.push(['计划开始', ''])
|
||||
param.push(['计划完成', this.planStart])
|
||||
param.push(['排产状态', '全部'])
|
||||
param.push(['指派对象', '全部'])
|
||||
param.push(['计划号', this.planNo])
|
||||
param.push(['发货状态', this.shipmentStatus])
|
||||
param.push(['齐套', this.complete])
|
||||
param.push(['检验状态', this.checkStatus])
|
||||
param.push(['发料状态', this.sendStatus])
|
||||
param.push(['自制件属性', this.selfStatus])
|
||||
|
||||
const data = this.CreateData('11', '生产管理_及时齐套跟踪结果_查询', param)
|
||||
try {
|
||||
const response = await this.ExecDatabase(data)
|
||||
this.tableData = this.mergeRows(response.data || [])
|
||||
if (this.tableData.length === 0) {
|
||||
this.$message.info('未查询到及时齐套跟踪结果')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('及时齐套跟踪结果查询失败:', error)
|
||||
this.$message.error('查询失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
mergeRows(rows) {
|
||||
const map = new Map()
|
||||
rows.forEach(row => {
|
||||
const key = [
|
||||
row.订单号 || '',
|
||||
row.合同号 || '',
|
||||
row.计划号 || '',
|
||||
row.产品编码 || ''
|
||||
].join('|')
|
||||
|
||||
if (!map.has(key)) {
|
||||
map.set(key, {
|
||||
计划号: row.计划号,
|
||||
合同号: row.合同号,
|
||||
订单号: row.订单号,
|
||||
产品编码: row.产品编码,
|
||||
产品名称: row.产品名称,
|
||||
计划数量订单: this.formatQuantity(row.计划数量订单),
|
||||
入库数量: this.formatQuantity(row.入库数量),
|
||||
要求完工日期: row.要求完工日期,
|
||||
要求发货日期: row.要求发货日期,
|
||||
预计齐套时间: row.预计齐套时间,
|
||||
齐套: row.齐套,
|
||||
拣配状态: row.拣配状态,
|
||||
发料状态: row.发料状态,
|
||||
装配开工: row.装配开工,
|
||||
完成数量: this.formatQuantity(row.完成数量),
|
||||
终检: row.终检,
|
||||
生产工艺: row.生产工艺,
|
||||
缺件明细: []
|
||||
})
|
||||
}
|
||||
|
||||
const detailKey = [
|
||||
row.缺件生产订单号 || '',
|
||||
row.缺件物料编码 || '',
|
||||
row.缺件属性 || ''
|
||||
].join('|')
|
||||
const current = map.get(key)
|
||||
if (current.缺件明细.some(item => item.detailKey === detailKey)) {
|
||||
return
|
||||
}
|
||||
|
||||
current.缺件明细.push({
|
||||
detailKey,
|
||||
缺件物料编码: row.缺件物料编码,
|
||||
缺件物料名称: row.缺件物料名称,
|
||||
缺件数量: this.formatQuantity(row.缺件数量),
|
||||
缺件属性: row.缺件属性,
|
||||
缺件生产订单号: row.缺件生产订单号,
|
||||
进度: row.进度,
|
||||
工艺路线: row.工艺路线,
|
||||
工艺路线明细: this.parseRouteDetails(row.工艺路线明细),
|
||||
预计完成时间: row.预计完成时间,
|
||||
采购员: row.采购员,
|
||||
采购未清数量: this.formatQuantity(row.采购未清数量),
|
||||
到货草稿: row.到货草稿,
|
||||
质检状态: row.质检状态,
|
||||
SAP单据: row.SAP单据,
|
||||
SAP行号: row.SAP行号
|
||||
})
|
||||
})
|
||||
return Array.from(map.values())
|
||||
},
|
||||
detailRowClassName() {
|
||||
return 'detail-row'
|
||||
},
|
||||
parseRouteDetails(value) {
|
||||
if (!value) return []
|
||||
if (Array.isArray(value)) return value
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
return Array.isArray(parsed) ? parsed : []
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
toProcessNumber(value) {
|
||||
const num = Number(value)
|
||||
return Number.isFinite(num) ? num : 0
|
||||
},
|
||||
isValidProcessDate(value) {
|
||||
if (!value) return false
|
||||
const date = new Date(value)
|
||||
return !Number.isNaN(date.getTime()) && date > new Date('1900-01-01 00:00:00')
|
||||
},
|
||||
getProcessStatusNum(value) {
|
||||
const num = parseInt(value)
|
||||
if (Number.isFinite(num)) return num
|
||||
const statusMap = {
|
||||
辅助开始: 2,
|
||||
辅助结束: 3,
|
||||
开始加工: 4,
|
||||
暂停: 5,
|
||||
报工: 6
|
||||
}
|
||||
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)
|
||||
},
|
||||
getProcessClass(process, index, processes) {
|
||||
if (this.isProcessComplete(process)) {
|
||||
return 'process-route-blue'
|
||||
}
|
||||
const statusNum = this.getProcessStatusNum(process.加工状态)
|
||||
if (this.isValidProcessDate(process.开工时间) || [2, 4].includes(statusNum) || this.toProcessNumber(process.进度) > 0) {
|
||||
return 'process-route-green'
|
||||
}
|
||||
if (index > 0 && this.isProcessComplete(processes[index - 1])) {
|
||||
return 'process-route-orange'
|
||||
}
|
||||
return 'process-route-red'
|
||||
},
|
||||
getRouteProcessName(process) {
|
||||
const name = String(process.工序名称 || '')
|
||||
const assignee = String(process.指派对象 || '')
|
||||
if (!assignee || name.includes(`(${assignee})`) || name.includes(`(${assignee})`)) {
|
||||
return name
|
||||
}
|
||||
return `${name}(${assignee})`
|
||||
},
|
||||
escapeProcessHtml(value) {
|
||||
return String(value == null ? '' : value)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
},
|
||||
formatProcessRoute(detail) {
|
||||
const processes = Array.isArray(detail.工艺路线明细) ? detail.工艺路线明细 : []
|
||||
if (processes.length === 0) {
|
||||
return this.escapeProcessHtml(detail.工艺路线 || '')
|
||||
}
|
||||
|
||||
const maxPerRow = 8
|
||||
const rows = Math.ceil(processes.length / maxPerRow)
|
||||
let html = '<div class="process-route-wrap"><table class="process-route-table"><tbody>'
|
||||
|
||||
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
|
||||
const startIndex = rowIndex * maxPerRow
|
||||
const rowProcesses = processes.slice(startIndex, startIndex + maxPerRow)
|
||||
if (rowIndex > 0) {
|
||||
html += `<tr class="process-route-spacer"><td colspan="${maxPerRow * 2 - 1}"></td></tr>`
|
||||
}
|
||||
|
||||
html += '<tr>'
|
||||
rowProcesses.forEach((process, index) => {
|
||||
const className = this.getProcessClass(process, startIndex + index, processes)
|
||||
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)
|
||||
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 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>'
|
||||
})
|
||||
html += '</tr>'
|
||||
}
|
||||
|
||||
html += '</tbody></table></div>'
|
||||
return html
|
||||
},
|
||||
formatDate(value) {
|
||||
if (!value) return ''
|
||||
return String(value).split('T')[0].split(' ')[0]
|
||||
},
|
||||
formatQuantity(value) {
|
||||
if (value === null || value === undefined || value === '') return ''
|
||||
const numberValue = Number(value)
|
||||
if (Number.isNaN(numberValue)) return value
|
||||
return Number.isInteger(numberValue) ? String(numberValue) : String(numberValue).replace(/0+$/, '').replace(/\.$/, '')
|
||||
},
|
||||
getStatusStyle(value) {
|
||||
if (value === '是' || value === '发料齐套' || value === '已拣配' || value === '已开工' || value === '已完成') {
|
||||
return {
|
||||
backgroundColor: '#f0f9eb',
|
||||
color: '#67c23a'
|
||||
}
|
||||
}
|
||||
if (value === '否' || value === '发料缺件' || value === '未拣配' || value === '待执行' || value === '未完成') {
|
||||
return {
|
||||
backgroundColor: '#fdf6ec',
|
||||
color: '#e6a23c'
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.timely-kit-page {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 0;
|
||||
}
|
||||
|
||||
.show-text {
|
||||
line-height: 32px;
|
||||
margin-right: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.filter-control {
|
||||
margin-right: 10px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.small-filter {
|
||||
margin-right: 10px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.score-cell {
|
||||
border-radius: 3px;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.detail-table {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.purchase-route {
|
||||
line-height: 22px;
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.process-route {
|
||||
overflow-x: auto;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
::v-deep .process-route-wrap {
|
||||
min-width: 480px;
|
||||
}
|
||||
|
||||
::v-deep .process-route-table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
::v-deep .process-route-table td {
|
||||
border-radius: 2px;
|
||||
line-height: 20px;
|
||||
min-width: 72px;
|
||||
padding: 2px 5px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
::v-deep .process-route-date,
|
||||
::v-deep .process-route-count {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
::v-deep .process-route-arrow,
|
||||
::v-deep .process-route-arrow-hidden {
|
||||
background: transparent;
|
||||
color: #606266;
|
||||
min-width: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
::v-deep .process-route-arrow-hidden {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
::v-deep .process-route-spacer td {
|
||||
height: 6px;
|
||||
line-height: 6px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::v-deep .process-route-green {
|
||||
background: #f0f9eb;
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
::v-deep .process-route-blue {
|
||||
background: #ecf5ff;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
::v-deep .process-route-orange {
|
||||
background: #fdf6ec;
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
::v-deep .process-route-red {
|
||||
background: #fef0f0;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
::v-deep .detail-row td {
|
||||
background-color: #f0f9eb !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user