452 lines
17 KiB
Vue
452 lines
17 KiB
Vue
<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>
|