feat(wms): 添加冷硬卷生产工艺数据图表展示
添加生产工艺数据图表展示功能,包括速度趋势、轧机出口速度和张力趋势图表 修复钢卷信息显示时的空值判断问题
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
<span class="card-label">📦 入库</span>
|
<span class="card-label">📦 入库</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(coil, idx) in getInboundCoil(step, index)" :key="idx" class="coil-card-futuristic"
|
<div v-for="(coil, idx) in getInboundCoil(step, index)" :key="idx" class="coil-card-futuristic"
|
||||||
v-if="coil.currentCoilNo !== '-'">
|
v-if="coil && coil.currentCoilNo !== '-'">
|
||||||
<div class="coil-futuristic-header">
|
<div class="coil-futuristic-header">
|
||||||
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
||||||
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="getInboundCoil(step, index).length === 0 || getInboundCoil(step, index).every(c => c.currentCoilNo === '-')"
|
v-if="getInboundCoil(step, index).length === 0 || getInboundCoil(step, index).every(c => !c || c.currentCoilNo === '-')"
|
||||||
class="empty-coil">
|
class="empty-coil">
|
||||||
<span>无钢卷信息</span>
|
<span>无钢卷信息</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
<span class="card-label">变更前</span>
|
<span class="card-label">变更前</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(coil, idx) in step.oldCoilInfoList" :key="idx" class="coil-card-futuristic"
|
<div v-for="(coil, idx) in step.oldCoilInfoList" :key="idx" class="coil-card-futuristic"
|
||||||
v-if="coil.currentCoilNo != '-'">
|
v-if="coil && coil.currentCoilNo !== '-'">
|
||||||
<div class="coil-futuristic-header">
|
<div class="coil-futuristic-header">
|
||||||
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
||||||
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
||||||
@@ -347,7 +347,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="step.oldCoilInfoList.length === 0 || step.oldCoilInfoList.every(c => c.currentCoilNo === '-')"
|
v-if="step.oldCoilInfoList.length === 0 || step.oldCoilInfoList.every(c => !c || c.currentCoilNo === '-')"
|
||||||
class="empty-coil">
|
class="empty-coil">
|
||||||
<span>无钢卷信息</span>
|
<span>无钢卷信息</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -371,7 +371,7 @@
|
|||||||
<span class="card-label">变更后</span>
|
<span class="card-label">变更后</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(coil, idx) in step.newCoilInfoList" :key="idx" class="coil-card-futuristic"
|
<div v-for="(coil, idx) in step.newCoilInfoList" :key="idx" class="coil-card-futuristic"
|
||||||
v-if="coil.currentCoilNo != '-'">
|
v-if="coil && coil.currentCoilNo !== '-'">
|
||||||
<div class="coil-futuristic-header">
|
<div class="coil-futuristic-header">
|
||||||
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
||||||
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
||||||
@@ -517,7 +517,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="step.newCoilInfoList.length === 0 || step.newCoilInfoList.every(c => c.currentCoilNo === '-')"
|
v-if="step.newCoilInfoList.length === 0 || step.newCoilInfoList.every(c => !c || c.currentCoilNo === '-')"
|
||||||
class="empty-coil">
|
class="empty-coil">
|
||||||
<span>无钢卷信息</span>
|
<span>无钢卷信息</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -727,6 +727,24 @@
|
|||||||
<abnormal-table ref="abnormalTable" :list="abmornalList" :editable="false" :show-coil="false" />
|
<abnormal-table ref="abnormalTable" :list="abmornalList" :editable="false" :show-coil="false" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 生产工艺数据图表 -->
|
||||||
|
<div v-if="isColdHardCoil" class="section production-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<span class="section-icon">📈</span>
|
||||||
|
<span class="section-title">生产工艺数据</span>
|
||||||
|
<el-tag v-if="perfLoading" size="mini" type="info" style="margin-left:8px">加载中…</el-tag>
|
||||||
|
<span v-if="hasPerfData" class="perf-count">({{ perfSegCount }} 段)</span>
|
||||||
|
</div>
|
||||||
|
<div class="section-body">
|
||||||
|
<div v-if="hasPerfData" class="charts-wrap">
|
||||||
|
<div ref="chartSpeed" class="chart-box" />
|
||||||
|
<div ref="chartMillSpeed" class="chart-box" />
|
||||||
|
<div ref="chartTension" class="chart-box" />
|
||||||
|
</div>
|
||||||
|
<el-empty v-else-if="!perfLoading" description="暂无生产工艺数据" :image-size="56" style="margin-top: 24px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -739,6 +757,9 @@ import { listCoilAbnormal } from '@/api/wms/coilAbnormal'
|
|||||||
import { listTransferOrderItem } from '@/api/wms/transferOrderItem'
|
import { listTransferOrderItem } from '@/api/wms/transferOrderItem'
|
||||||
// 查询技术部改判调拨的记录
|
// 查询技术部改判调拨的记录
|
||||||
import { listCoilQualityRejudge } from '@/api/wms/coilQualityRejudge'
|
import { listCoilQualityRejudge } from '@/api/wms/coilQualityRejudge'
|
||||||
|
// 引入 ECharts 和 L2 时序数据 API
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import { getTimingSegByEncoilId } from '@/api/l2/timing'
|
||||||
|
|
||||||
import AbnormalTable from '@/views/wms/coil/components/AbnormalTable.vue';
|
import AbnormalTable from '@/views/wms/coil/components/AbnormalTable.vue';
|
||||||
import FileList from "@/components/FileList";
|
import FileList from "@/components/FileList";
|
||||||
@@ -768,15 +789,28 @@ export default {
|
|||||||
abmornalList: [],
|
abmornalList: [],
|
||||||
transferOrderItemList: [], // 批量调拨记录
|
transferOrderItemList: [], // 批量调拨记录
|
||||||
coilQualityRejudgeList: [], // 技术部改判记录
|
coilQualityRejudgeList: [], // 技术部改判记录
|
||||||
tranferList: [] // 合并后的调拨记录
|
tranferList: [], // 合并后的调拨记录
|
||||||
|
// 生产数据相关
|
||||||
|
perfLoading: false,
|
||||||
|
perfSeries: null,
|
||||||
|
perfSegCount: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
salesInfo() {
|
salesInfo() {
|
||||||
return this.coilInfo.orderList?.[0] || {};
|
return this.coilInfo.orderList?.[0] || {};
|
||||||
|
},
|
||||||
|
// 判断是否为冷硬卷
|
||||||
|
isColdHardCoil() {
|
||||||
|
return this.coilInfo.itemName && this.coilInfo.itemName.includes('冷硬卷');
|
||||||
|
},
|
||||||
|
hasPerfData() {
|
||||||
|
return this.perfSeries && this.perfSegCount > 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
this.chartInstances = [];
|
||||||
|
this.resizeHandler = null;
|
||||||
this.coilId = this.$route.params.coilId;
|
this.coilId = this.$route.params.coilId;
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
await this.getCoilInfo();
|
await this.getCoilInfo();
|
||||||
@@ -786,8 +820,15 @@ export default {
|
|||||||
await this.getTransferOrderItemList();
|
await this.getTransferOrderItemList();
|
||||||
await this.getCoilQualityRejudgeList();
|
await this.getCoilQualityRejudgeList();
|
||||||
this.mergeTransferList();
|
this.mergeTransferList();
|
||||||
|
// 如果是冷硬卷,加载生产数据
|
||||||
|
if (this.isColdHardCoil) {
|
||||||
|
await this.loadProductionData();
|
||||||
|
}
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
},
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.disposeCharts();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async getCoilInfo() {
|
async getCoilInfo() {
|
||||||
const res = await getMaterialCoil(this.coilId);
|
const res = await getMaterialCoil(this.coilId);
|
||||||
@@ -992,7 +1033,7 @@ export default {
|
|||||||
|
|
||||||
if (standardStep.action === '创建') {
|
if (standardStep.action === '创建') {
|
||||||
listMaterialCoil({ currentCoilNo: originalStep.current_coil_no, enterCoilNo: originalStep.current_coil_no }).then(res => {
|
listMaterialCoil({ currentCoilNo: originalStep.current_coil_no, enterCoilNo: originalStep.current_coil_no }).then(res => {
|
||||||
standardStep.newCoilInfoList = res.rows[0] || [];
|
standardStep.newCoilInfoList = res.rows || [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1009,26 +1050,28 @@ export default {
|
|||||||
if (!coilIds || !coilIds.length) return [];
|
if (!coilIds || !coilIds.length) return [];
|
||||||
return coilIds.map(coilId => {
|
return coilIds.map(coilId => {
|
||||||
const coil = this.coilDetails[coilId] || {};
|
const coil = this.coilDetails[coilId] || {};
|
||||||
|
// 确保 coil 不为 null 或 undefined
|
||||||
|
const safeCoil = coil || {};
|
||||||
return {
|
return {
|
||||||
...coil,
|
...safeCoil,
|
||||||
enterCoilNo: coil.enterCoilNo || '-',
|
enterCoilNo: safeCoil.enterCoilNo || '-',
|
||||||
currentCoilNo: coil.currentCoilNo || '-',
|
currentCoilNo: safeCoil.currentCoilNo || '-',
|
||||||
materialType: coil.materialType || '-',
|
materialType: safeCoil.materialType || '-',
|
||||||
itemName: coil.itemName || '-',
|
itemName: safeCoil.itemName || '-',
|
||||||
specification: coil.specification || '-',
|
specification: safeCoil.specification || '-',
|
||||||
material: coil.material || '-',
|
material: safeCoil.material || '-',
|
||||||
netWeight: coil.netWeight || 0,
|
netWeight: safeCoil.netWeight || 0,
|
||||||
warehouseName: coil.warehouseName || '-',
|
warehouseName: safeCoil.warehouseName || '-',
|
||||||
actualWarehouseName: coil.actualWarehouseName || '-',
|
actualWarehouseName: safeCoil.actualWarehouseName || '-',
|
||||||
manufacturer: coil.manufacturer || '-',
|
manufacturer: safeCoil.manufacturer || '-',
|
||||||
zincLayer: coil.zincLayer || '-',
|
zincLayer: safeCoil.zincLayer || '-',
|
||||||
qualityStatus: coil.qualityStatus || '-',
|
qualityStatus: safeCoil.qualityStatus || '-',
|
||||||
createTime: coil.createTime || '-',
|
createTime: safeCoil.createTime || '-',
|
||||||
status: coil.status || 0,
|
status: safeCoil.status || 0,
|
||||||
exportByName: coil.exportByName || '-',
|
exportByName: safeCoil.exportByName || '-',
|
||||||
exportTime: coil.exportTime || '-',
|
exportTime: safeCoil.exportTime || '-',
|
||||||
};
|
};
|
||||||
});
|
}).filter(coil => coil); // 过滤掉 null/undefined 的项
|
||||||
},
|
},
|
||||||
collectCoilIds() {
|
collectCoilIds() {
|
||||||
if (!this.standardSteps.length) return [];
|
if (!this.standardSteps.length) return [];
|
||||||
@@ -1101,6 +1144,105 @@ export default {
|
|||||||
}
|
}
|
||||||
return step.newCoilInfoList;
|
return step.newCoilInfoList;
|
||||||
},
|
},
|
||||||
|
// ECharts 辅助函数
|
||||||
|
makeLine(name, data) {
|
||||||
|
return { name, type: 'line', smooth: true, symbol: 'none', data };
|
||||||
|
},
|
||||||
|
baseOption(title, xData, series, yName) {
|
||||||
|
return {
|
||||||
|
title: { text: title, textStyle: { fontSize: 12, fontWeight: 'normal' }, top: 4, left: 8 },
|
||||||
|
tooltip: { trigger: 'axis' },
|
||||||
|
legend: { top: 4, right: 8, textStyle: { fontSize: 11 } },
|
||||||
|
grid: { top: 36, bottom: 28, left: 8, right: 8, containLabel: true },
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xData,
|
||||||
|
name: 'pos(m)',
|
||||||
|
nameTextStyle: { fontSize: 10 },
|
||||||
|
axisLabel: { fontSize: 10 }
|
||||||
|
},
|
||||||
|
yAxis: { type: 'value', name: yName, nameTextStyle: { fontSize: 10 }, axisLabel: { fontSize: 10 } },
|
||||||
|
series
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// 加载生产数据
|
||||||
|
async loadProductionData() {
|
||||||
|
const encoilId = this.coilInfo.currentCoilNo;
|
||||||
|
if (!encoilId) return;
|
||||||
|
|
||||||
|
this.perfLoading = true;
|
||||||
|
try {
|
||||||
|
const res = await getTimingSegByEncoilId(encoilId);
|
||||||
|
const series = res?.data?.series || null;
|
||||||
|
const rows = res?.data?.rows || [];
|
||||||
|
this.perfSegCount = rows.length;
|
||||||
|
this.perfSeries = series;
|
||||||
|
|
||||||
|
if (series && rows.length) {
|
||||||
|
await this.$nextTick();
|
||||||
|
this.renderCharts(series);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取生产数据异常:', error);
|
||||||
|
this.perfSeries = null;
|
||||||
|
this.perfSegCount = 0;
|
||||||
|
} finally {
|
||||||
|
this.perfLoading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 销毁图表
|
||||||
|
disposeCharts() {
|
||||||
|
if (this.resizeHandler) {
|
||||||
|
window.removeEventListener('resize', this.resizeHandler);
|
||||||
|
this.resizeHandler = null;
|
||||||
|
}
|
||||||
|
if (this.chartInstances && this.chartInstances.length) {
|
||||||
|
this.chartInstances.forEach(c => { if (c) c.dispose(); });
|
||||||
|
this.chartInstances = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 渲染图表
|
||||||
|
renderCharts(series) {
|
||||||
|
this.disposeCharts();
|
||||||
|
if (!this.$refs.chartSpeed || !this.$refs.chartMillSpeed || !this.$refs.chartTension) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pick = key => (series[key] || []).map(v => v == null ? null : Number(v).toFixed(2));
|
||||||
|
const xData = (series.startpos || []).map(v => v == null ? '' : Number(v).toFixed(1));
|
||||||
|
|
||||||
|
const c1 = echarts.init(this.$refs.chartSpeed);
|
||||||
|
c1.setOption(this.baseOption(
|
||||||
|
'速度趋势 (m/min)', xData,
|
||||||
|
[
|
||||||
|
this.makeLine('轧制速度 plspeed', pick('plspeed')),
|
||||||
|
this.makeLine('剪切速度 trimspeed', pick('trimspeed'))
|
||||||
|
],
|
||||||
|
'm/min'
|
||||||
|
));
|
||||||
|
|
||||||
|
const c2 = echarts.init(this.$refs.chartMillSpeed);
|
||||||
|
c2.setOption(this.baseOption(
|
||||||
|
'轧机出口速度 (m/min)', xData,
|
||||||
|
[this.makeLine('millexitspeed', pick('millexitspeed'))],
|
||||||
|
'm/min'
|
||||||
|
));
|
||||||
|
|
||||||
|
const c3 = echarts.init(this.$refs.chartTension);
|
||||||
|
c3.setOption(this.baseOption(
|
||||||
|
'张力趋势 (N)', xData,
|
||||||
|
[
|
||||||
|
this.makeLine('出口张力 pltens', pick('pltens')),
|
||||||
|
this.makeLine('入口张力 enltens', pick('enltens')),
|
||||||
|
this.makeLine('cxltens', pick('cxltens'))
|
||||||
|
],
|
||||||
|
'N'
|
||||||
|
));
|
||||||
|
|
||||||
|
this.chartInstances = [c1, c2, c3];
|
||||||
|
this.resizeHandler = () => this.chartInstances.forEach(c => { if (c) c.resize(); });
|
||||||
|
window.addEventListener('resize', this.resizeHandler);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -1966,4 +2108,23 @@ export default {
|
|||||||
border: 1px solid rgba(59, 130, 246, 0.2);
|
border: 1px solid rgba(59, 130, 246, 0.2);
|
||||||
letter-spacing: 0.6px;
|
letter-spacing: 0.6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 生产数据样式 */
|
||||||
|
.perf-count {
|
||||||
|
font-weight: normal;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.charts-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user