refactor(wms/coil): 重构钢卷详情页面,拆分组件并优化页面结构
1. 将原钢卷详情页面拆分为多个独立组件,按功能模块划分 2. 调整路由指向,将页面入口指向新的页面文件 3. 新增状态工具类,封装通用格式化和样式
This commit is contained in:
451
klp-ui/src/views/wms/coil/info/index.vue
Normal file
451
klp-ui/src/views/wms/coil/info/index.vue
Normal file
@@ -0,0 +1,451 @@
|
||||
<template>
|
||||
<div class="coil-info-page" v-loading="loading">
|
||||
<div class="content-container">
|
||||
<BasicInfoSection :coilInfo="coilInfo" />
|
||||
|
||||
<CostInfoSection :coilInfo="coilInfo" :traceResult="traceResult"
|
||||
:hoardingDays="hoardingDays" :hoardingCost="hoardingCost" />
|
||||
|
||||
<LifecycleTrace :traceResult="traceResult" :coilInfo="coilInfo" />
|
||||
|
||||
<ContractInfo title="生产合同信息" :info="salesInfo" emptyText="未找到相关生产合同信息" />
|
||||
|
||||
<ContractInfo title="发货合同信息" :info="deliveryOrderInfo" emptyText="未找到相关发货合同信息" />
|
||||
|
||||
<SalesObjectionTable :list="salesObjectionInfo" />
|
||||
|
||||
<TransferRecords :warehouseList="warehouseTranferList" :transferList="tranferList" />
|
||||
|
||||
<div class="section abnormal-section">
|
||||
<div class="section-header">
|
||||
<span class="section-icon">⚠️</span>
|
||||
<span class="section-title">异常信息</span>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<abnormal-table ref="abnormalTable" :list="abmornalList" :editable="false" :show-coil="false"
|
||||
:coil-info="coilInfo" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section abnormal-section">
|
||||
<div class="section-header">
|
||||
<span class="section-icon">📚</span>
|
||||
<span class="section-title">异常历史</span>
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<abnormal-table ref="historyAbnormalTable" :list="allAbmornalList" :editable="false" :show-coil="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<InspectionInfo :taskList="inspectionTaskList" :loading="inspectionLoading" />
|
||||
|
||||
<ProductionCharts v-if="isColdHardCoil"
|
||||
:segData="segData" :gaugeRows="gaugeRows" :shapeRows="shapeRows"
|
||||
:perfSegCount="perfSegCount" :segLoading="segLoading" :realtimeLoading="realtimeLoading" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMaterialCoil, listMaterialCoil, getMaterialCoilTrace, getDeliveryOrderInfo } from '@/api/wms/coil'
|
||||
import { getCoilWarehouseOperationLogByCoilId } from '@/api/wms/coilWarehouseOperationLog'
|
||||
import { listSalesObjection } from "@/api/crm/salesObjection"
|
||||
import { listCoilAbnormal } from '@/api/wms/coilAbnormal'
|
||||
import { listTransferOrderItem } from '@/api/wms/transferOrderItem'
|
||||
import { listCoilQualityRejudge } from '@/api/wms/coilQualityRejudge'
|
||||
import { getTimingSegByEncoilId, getTimingPlanDetailByHotcoilId, getTimingRealtimeData } from '@/api/l2/timing'
|
||||
import { listInspectionTask } from "@/api/mes/qc/inspectionTask"
|
||||
import AbnormalTable from '@/views/wms/coil/components/AbnormalTable.vue'
|
||||
import { formatTime } from './statusUtils'
|
||||
|
||||
import BasicInfoSection from './components/BasicInfoSection.vue'
|
||||
import CostInfoSection from './components/CostInfoSection.vue'
|
||||
import LifecycleTrace from './components/LifecycleTrace.vue'
|
||||
import ContractInfo from './components/ContractInfo.vue'
|
||||
import SalesObjectionTable from './components/SalesObjectionTable.vue'
|
||||
import TransferRecords from './components/TransferRecords.vue'
|
||||
import InspectionInfo from './components/InspectionInfo.vue'
|
||||
import ProductionCharts from './components/ProductionCharts.vue'
|
||||
|
||||
export default {
|
||||
name: 'CoilInfo',
|
||||
components: {
|
||||
AbnormalTable,
|
||||
BasicInfoSection,
|
||||
CostInfoSection,
|
||||
LifecycleTrace,
|
||||
ContractInfo,
|
||||
SalesObjectionTable,
|
||||
TransferRecords,
|
||||
InspectionInfo,
|
||||
ProductionCharts
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
coilInfoLoading: false,
|
||||
traceLoading: false,
|
||||
traceResult: null,
|
||||
coilDetails: {},
|
||||
loadingCoilDetails: false,
|
||||
coilInfo: {},
|
||||
coilList: [],
|
||||
coilId: '',
|
||||
warehouseTranferList: [],
|
||||
abmornalList: [],
|
||||
allAbmornalList: [],
|
||||
transferOrderItemList: [],
|
||||
coilQualityRejudgeList: [],
|
||||
tranferList: [],
|
||||
perfLoading: false,
|
||||
perfSeries: null,
|
||||
perfSegCount: 0,
|
||||
segLoading: false,
|
||||
realtimeLoading: false,
|
||||
segData: null,
|
||||
gaugeRows: null,
|
||||
shapeRows: null,
|
||||
deliveryOrderInfo: {},
|
||||
salesObjectionInfo: [],
|
||||
inspectionTaskList: [],
|
||||
inspectionLoading: false,
|
||||
standardSteps: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
salesInfo() {
|
||||
return this.coilInfo.orderList?.[0] || {}
|
||||
},
|
||||
isColdHardCoil() {
|
||||
return this.coilInfo.itemName && this.coilInfo.itemName.includes('冷硬卷')
|
||||
},
|
||||
hasPerfData() {
|
||||
return this.perfSeries && this.perfSegCount > 0
|
||||
},
|
||||
hoardingDays() {
|
||||
const inboundTime = this.getInboundTime()
|
||||
if (!inboundTime) return 0
|
||||
const inboundDate = new Date(inboundTime)
|
||||
const endDate = this.coilInfo.status == 1
|
||||
? new Date(this.coilInfo.exportTime)
|
||||
: new Date()
|
||||
const diffTime = endDate.getTime() - inboundDate.getTime()
|
||||
return Math.max(0, Math.floor(diffTime / (1000 * 60 * 60 * 24)))
|
||||
},
|
||||
hoardingCost() {
|
||||
const netWeight = parseFloat(this.coilInfo.netWeight) || 0
|
||||
return (this.hoardingDays * netWeight).toFixed(2)
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.coilId = this.$route.params.coilId
|
||||
this.loading = true
|
||||
await this.getCoilInfo()
|
||||
await this.getTraceInfo()
|
||||
await this.getHistoryAbnormalList()
|
||||
await this.getAbnormalList()
|
||||
await this.getWarehouseTransferList()
|
||||
await this.getTransferOrderItemList()
|
||||
await this.getCoilQualityRejudgeList()
|
||||
await this.fetchDeliveryOrderInfo()
|
||||
this.mergeTransferList()
|
||||
await this.getSalesObjectionList()
|
||||
await this.getInspectionTasks()
|
||||
if (this.isColdHardCoil) {
|
||||
await this.loadProductionData()
|
||||
}
|
||||
this.loading = false
|
||||
},
|
||||
methods: {
|
||||
async getCoilInfo() {
|
||||
const res = await getMaterialCoil(this.coilId)
|
||||
this.coilInfo = res.data || {}
|
||||
},
|
||||
async fetchDeliveryOrderInfo() {
|
||||
const res = await getDeliveryOrderInfo(this.coilId)
|
||||
this.deliveryOrderInfo = res.data || {}
|
||||
},
|
||||
async getSalesObjectionList() {
|
||||
const res = await listSalesObjection({ coilIds: this.coilId })
|
||||
this.salesObjectionInfo = res.rows || []
|
||||
},
|
||||
async getTraceInfo() {
|
||||
const res = await getMaterialCoilTrace({
|
||||
coilId: this.coilId,
|
||||
currentCoilNo: this.coilInfo.currentCoilNo
|
||||
})
|
||||
this.traceResult = res.data
|
||||
this.standardSteps = this.traceResult.steps?.map(step => this.formatStep(step)) || []
|
||||
this.fetchCoilDetails()
|
||||
},
|
||||
async getAbnormalList() {
|
||||
const res = await listCoilAbnormal({ coilId: this.coilId })
|
||||
this.abmornalList = res.rows || []
|
||||
},
|
||||
async getHistoryAbnormalList() {
|
||||
const coilIds = this.traceResult.steps?.map(step => step.old_coil_id).filter(Boolean) || []
|
||||
if (coilIds.length === 0) return
|
||||
const res = await listCoilAbnormal({ coilIds: coilIds.join(',') })
|
||||
this.allAbmornalList = res.rows || []
|
||||
},
|
||||
async getWarehouseTransferList() {
|
||||
const res = await getCoilWarehouseOperationLogByCoilId({ coilId: this.coilId })
|
||||
this.warehouseTranferList = res.data || []
|
||||
},
|
||||
async getTransferOrderItemList() {
|
||||
const res = await listTransferOrderItem({ coilId: this.coilId, pageNum: 1, pageSize: 100 })
|
||||
this.transferOrderItemList = res.rows || []
|
||||
},
|
||||
async getCoilQualityRejudgeList() {
|
||||
const res = await listCoilQualityRejudge({ coilId: this.coilId, pageNum: 1, pageSize: 100 })
|
||||
this.coilQualityRejudgeList = res.rows || []
|
||||
},
|
||||
mergeTransferList() {
|
||||
const list = []
|
||||
this.transferOrderItemList.forEach(item => {
|
||||
list.push({
|
||||
type: '批量调拨',
|
||||
before: '逻辑库:' + (item.warehouseNameBefore || '-'),
|
||||
after: '逻辑库:' + (item.warehouseNameAfter || '-'),
|
||||
createTime: item.createTime || '-',
|
||||
remark: item.remark || '-',
|
||||
...item
|
||||
})
|
||||
})
|
||||
this.coilQualityRejudgeList.forEach(item => {
|
||||
list.push({
|
||||
...item,
|
||||
type: '技术部改判',
|
||||
before: '质量状态:' + (item.beforeQuality || '-'),
|
||||
after: '质量状态:' + (item.afterQuality || '-'),
|
||||
createTime: item.createTime || '-',
|
||||
remark: item.rejudgeReason,
|
||||
})
|
||||
})
|
||||
list.sort((a, b) => {
|
||||
const timeA = new Date(a.createTime || 0).getTime()
|
||||
const timeB = new Date(b.createTime || 0).getTime()
|
||||
return timeB - timeA
|
||||
})
|
||||
this.tranferList = list
|
||||
},
|
||||
async getInspectionTasks() {
|
||||
this.inspectionLoading = true
|
||||
try {
|
||||
const res = await listInspectionTask({ enterCoilNos: this.coilInfo.enterCoilNo, pageNum: 1, pageSize: 100 })
|
||||
this.inspectionTaskList = res.rows || []
|
||||
} catch (e) {
|
||||
console.error('获取检验任务异常:', e)
|
||||
this.inspectionTaskList = []
|
||||
} finally {
|
||||
this.inspectionLoading = false
|
||||
}
|
||||
},
|
||||
getInboundTime() {
|
||||
if (!this.traceResult || !this.traceResult.steps) {
|
||||
return this.coilInfo.createTime || null
|
||||
}
|
||||
const createStep = this.traceResult.steps.find(step =>
|
||||
step.action === '新增' || step.action === '创建'
|
||||
)
|
||||
if (createStep) {
|
||||
return createStep.create_time || createStep.update_time || createStep.time
|
||||
}
|
||||
return this.coilInfo.createTime || null
|
||||
},
|
||||
formatTime(timeStamp) {
|
||||
return formatTime(timeStamp)
|
||||
},
|
||||
formatStep(originalStep) {
|
||||
const standardStep = {
|
||||
action: '', time: '-', operation: '-',
|
||||
oldCoilIds: [], newCoilIds: [],
|
||||
changedFields: '', oldCoilInfoList: [], newCoilInfoList: [],
|
||||
deletedCoilInfo: null, restoredCoilInfo: null,
|
||||
original: originalStep
|
||||
}
|
||||
|
||||
if (originalStep.action === '新增') {
|
||||
standardStep.action = '创建'
|
||||
} else if (originalStep.action === '更新') {
|
||||
if (originalStep.operation === '信息更新') standardStep.action = '更新'
|
||||
else if (originalStep.operation === '分卷') standardStep.action = '分卷'
|
||||
else if (originalStep.operation === '合卷') standardStep.action = '合卷'
|
||||
else standardStep.action = '更新'
|
||||
} else if (originalStep.action === '回滚') {
|
||||
standardStep.action = '回滚'
|
||||
} else {
|
||||
standardStep.action = originalStep.action || '-'
|
||||
}
|
||||
|
||||
if (originalStep.update_time || originalStep.create_time) {
|
||||
standardStep.time = this.formatTime(originalStep.update_time || originalStep.create_time)
|
||||
} else if (originalStep.rollback_time) {
|
||||
standardStep.time = this.formatTime(originalStep.rollback_time)
|
||||
}
|
||||
standardStep.operation = originalStep.operator_nickname || originalStep.operator || originalStep.create_by || '-'
|
||||
|
||||
switch (standardStep.action) {
|
||||
case '创建': standardStep.oldCoilIds = []; break
|
||||
case '更新': standardStep.oldCoilIds = originalStep.old_coil_id ? [originalStep.old_coil_id.trim()] : []; break
|
||||
case '退火': standardStep.oldCoilIds = originalStep.old_coil_id ? [originalStep.old_coil_id.trim()] : []; break
|
||||
case '分卷': standardStep.oldCoilIds = originalStep.old_coil_id ? [originalStep.old_coil_id.trim()] : []; break
|
||||
case '合卷':
|
||||
standardStep.oldCoilIds = originalStep.parent_coil_ids
|
||||
? originalStep.parent_coil_ids.split(',').map(id => id.trim()).filter(Boolean) : []
|
||||
break
|
||||
case '回滚':
|
||||
standardStep.oldCoilIds = originalStep.deleted_coil_id ? [originalStep.deleted_coil_id.trim()] : []; break
|
||||
default: standardStep.oldCoilIds = []
|
||||
}
|
||||
|
||||
switch (standardStep.action) {
|
||||
case '创建': standardStep.newCoilIds = originalStep.current_coil_id ? [originalStep.current_coil_id.trim()] : []; break
|
||||
case '更新': standardStep.newCoilIds = originalStep.new_coil_id ? [originalStep.new_coil_id.trim()] : []; break
|
||||
case '退火': standardStep.newCoilIds = originalStep.new_coil_id ? [originalStep.new_coil_id.trim()] : []; break
|
||||
case '分卷':
|
||||
standardStep.newCoilIds = originalStep.child_coil_ids
|
||||
? originalStep.child_coil_ids.split(',').map(id => id.trim()).filter(Boolean) : []
|
||||
break
|
||||
case '合卷': standardStep.newCoilIds = originalStep.new_coil_id ? [originalStep.new_coil_id.trim()] : []; break
|
||||
case '回滚':
|
||||
standardStep.newCoilIds = originalStep.restored_coil_id ? [originalStep.restored_coil_id.trim()] : []; break
|
||||
default: standardStep.newCoilIds = []
|
||||
}
|
||||
|
||||
if (standardStep.action === '更新') {
|
||||
standardStep.changedFields = originalStep.changed_fields || ''
|
||||
}
|
||||
if (standardStep.action === '创建') {
|
||||
listMaterialCoil({ currentCoilNo: originalStep.current_coil_no, enterCoilNo: originalStep.current_coil_no }).then(res => {
|
||||
standardStep.newCoilInfoList = res.rows || []
|
||||
})
|
||||
}
|
||||
standardStep.newCoilInfoList = this.mapCoilInfoList(standardStep.newCoilIds)
|
||||
if (standardStep.action === '回滚') {
|
||||
standardStep.deletedCoilInfo = standardStep.oldCoilInfoList[0] || null
|
||||
standardStep.restoredCoilInfo = standardStep.newCoilInfoList[0] || null
|
||||
}
|
||||
return standardStep
|
||||
},
|
||||
mapCoilInfoList(coilIds) {
|
||||
if (!coilIds || !coilIds.length) return []
|
||||
return coilIds.map(coilId => {
|
||||
const coil = this.coilDetails[coilId] || {}
|
||||
const safeCoil = coil || {}
|
||||
return {
|
||||
...safeCoil,
|
||||
enterCoilNo: safeCoil.enterCoilNo || '-',
|
||||
currentCoilNo: safeCoil.currentCoilNo || '-',
|
||||
materialType: safeCoil.materialType || '-',
|
||||
itemName: safeCoil.itemName || '-',
|
||||
specification: safeCoil.specification || '-',
|
||||
material: safeCoil.material || '-',
|
||||
netWeight: safeCoil.netWeight || 0,
|
||||
warehouseName: safeCoil.warehouseName || '-',
|
||||
actualWarehouseName: safeCoil.actualWarehouseName || '-',
|
||||
manufacturer: safeCoil.manufacturer || '-',
|
||||
zincLayer: safeCoil.zincLayer || '-',
|
||||
qualityStatus: safeCoil.qualityStatus || '-',
|
||||
createTime: safeCoil.createTime || '-',
|
||||
status: safeCoil.status || 0,
|
||||
exportByName: safeCoil.exportByName || '-',
|
||||
exportTime: safeCoil.exportTime || '-',
|
||||
}
|
||||
}).filter(coil => coil)
|
||||
},
|
||||
collectCoilIds() {
|
||||
if (!this.standardSteps.length) return []
|
||||
const coilIds = new Set()
|
||||
this.standardSteps.forEach(step => {
|
||||
step.oldCoilIds.forEach(id => id && coilIds.add(id))
|
||||
step.newCoilIds.forEach(id => id && coilIds.add(id))
|
||||
})
|
||||
return [...coilIds]
|
||||
},
|
||||
async fetchCoilDetails() {
|
||||
const coilIds = this.collectCoilIds().filter(id => id)
|
||||
if (coilIds.length === 0) { this.coilDetails = {}; return }
|
||||
if (this.loadingCoilDetails) return
|
||||
this.loadingCoilDetails = true
|
||||
try {
|
||||
const res = await listMaterialCoil({ coilIds: coilIds.join(',') })
|
||||
if (res && res.code === 200 && res.rows) {
|
||||
const coilIdMap = {}
|
||||
res.rows.forEach(coil => { if (coil.coilId) coilIdMap[coil.coilId] = coil })
|
||||
this.coilDetails = coilIdMap
|
||||
this.standardSteps.forEach(step => {
|
||||
step.oldCoilInfoList = this.mapCoilInfoList(step.oldCoilIds)
|
||||
step.newCoilInfoList = this.mapCoilInfoList(step.newCoilIds)
|
||||
if (step.action === '回滚') {
|
||||
step.deletedCoilInfo = step.oldCoilInfoList[0] || null
|
||||
step.restoredCoilInfo = step.newCoilInfoList[0] || null
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message.warning('获取钢卷详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取钢卷详情接口异常:', error)
|
||||
this.$message.error('获取钢卷详情异常,请刷新重试')
|
||||
} finally {
|
||||
this.loadingCoilDetails = false
|
||||
}
|
||||
},
|
||||
async loadProductionData() {
|
||||
const hotCoilId = this.coilInfo.enterCoilNo
|
||||
if (!hotCoilId) return
|
||||
this.segLoading = true
|
||||
this.realtimeLoading = true
|
||||
try {
|
||||
const detail = await getTimingPlanDetailByHotcoilId(hotCoilId)
|
||||
const encoilId = detail?.data?.firstRow?.coilid || ''
|
||||
|
||||
const [segRes, realtimeRes] = await Promise.all([
|
||||
encoilId ? getTimingSegByEncoilId(encoilId) : Promise.resolve({ data: null }),
|
||||
encoilId ? getTimingRealtimeData(encoilId) : Promise.resolve({ data: null })
|
||||
])
|
||||
|
||||
const series = segRes?.data?.series || null
|
||||
const rows = segRes?.data?.rows || []
|
||||
this.perfSegCount = rows.length
|
||||
this.perfSeries = series
|
||||
this.segData = series
|
||||
|
||||
const g = realtimeRes?.data?.gauge?.result
|
||||
const s = realtimeRes?.data?.shape?.result
|
||||
this.gaugeRows = Array.isArray(g) ? g : null
|
||||
this.shapeRows = Array.isArray(s) ? s : null
|
||||
} catch (error) {
|
||||
console.error('获取生产数据异常:', error)
|
||||
this.perfSeries = null
|
||||
this.perfSegCount = 0
|
||||
this.segData = null
|
||||
this.gaugeRows = null
|
||||
this.shapeRows = null
|
||||
} finally {
|
||||
this.segLoading = false
|
||||
this.realtimeLoading = false
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './coil-info.scss';
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.coil-info-page {
|
||||
background: linear-gradient(180deg, #f0f4f8 0%, #e2e8f0 50%, #f7fafc 100%);
|
||||
min-height: 100vh;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user