Files
klp-oa/klp-ui/src/views/wms/coil/panels/CoilTraceResult.vue
2025-11-07 14:33:28 +08:00

419 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="trace-result-container">
<!-- 二维码信息 -->
<el-card shadow="hover" class="mb20" v-if="traceResult && traceResult.qrcode">
<div slot="header" class="card-header">
<span class="title-dot"></span>
<span class="title-text">二维码信息</span>
</div>
<div class="qrcode-info">
<el-row class="info-row" :gutter="10">
<el-col :span="6" class="info-label">主序列号</el-col>
<el-col :span="18" class="info-value">{{ traceResult.qrcode.serialNumber || '-' }}</el-col>
</el-row>
<el-row class="info-row" :gutter="10">
<el-col :span="6" class="info-label">创建时间</el-col>
<el-col :span="18" class="info-value">{{ traceResult.qrcode.createTime || '-' }}</el-col>
</el-row>
<el-row class="info-row" :gutter="10" v-if="traceResult.all_qrcodes && traceResult.all_qrcodes.length > 1">
<el-col :span="6" class="info-label">相关二维码</el-col>
<el-col :span="18" class="info-value">{{ traceResult.all_qrcodes.length }} </el-col>
</el-row>
</div>
</el-card>
<!-- 操作步骤 -->
<el-card shadow="hover" class="mb20" v-if="traceResult && traceResult.steps && traceResult.steps.length > 0">
<div slot="header" class="card-header">
<span class="title-dot"></span>
<span class="title-text">操作步骤</span>
</div>
<el-timeline>
<el-timeline-item
v-for="(step, index) in traceResult.steps"
:key="index"
:timestamp="step.display_step || step.step"
placement="top"
>
<el-card shadow="hover">
<div class="step-header">
<span class="step-action">{{ step.action }}</span>
<el-tag size="mini" type="primary" v-if="step.operation">{{ step.operation }}</el-tag>
</div>
<div class="step-details">
<el-row class="detail-row" v-if="step.current_coil_no">
<el-col :span="8" class="detail-label">当前钢卷号</el-col>
<el-col :span="16" class="detail-value">{{ step.current_coil_no }}</el-col>
</el-row>
<el-row class="detail-row" v-if="step.old_current_coil_no">
<el-col :span="8" class="detail-label">原钢卷号</el-col>
<el-col :span="16" class="detail-value">{{ step.old_current_coil_no }}</el-col>
</el-row>
<el-row class="detail-row" v-if="step.new_current_coil_no">
<el-col :span="8" class="detail-label">新钢卷号</el-col>
<el-col :span="16" class="detail-value">{{ step.new_current_coil_no }}</el-col>
</el-row>
<el-row class="detail-row" v-if="step.new_current_coil_nos">
<el-col :span="8" class="detail-label">分卷列表</el-col>
<el-col :span="16" class="detail-value">
<el-tag
v-for="coilNo in step.new_current_coil_nos.split(',')"
:key="coilNo"
type="warning"
size="mini"
class="mr8"
>
{{ coilNo.trim() }}
</el-tag>
</el-col>
</el-row>
<el-row class="detail-row" v-if="step.parent_coil_nos">
<el-col :span="8" class="detail-label">合卷来源</el-col>
<el-col :span="16" class="detail-value">
<el-tag
v-for="coilNo in step.parent_coil_nos.split(',')"
:key="coilNo"
type="success"
size="mini"
class="mr8"
>
{{ coilNo.trim() }}
</el-tag>
</el-col>
</el-row>
<el-row class="detail-row" v-if="step.child_coils && step.child_coils.length > 0">
<el-col :span="8" class="detail-label">子钢卷</el-col>
<el-col :span="16" class="detail-value">
<el-tag
v-for="coilNo in step.child_coils"
:key="coilNo"
type="info"
size="mini"
class="mr8"
>
{{ coilNo }}
</el-tag>
</el-col>
</el-row>
<el-row class="detail-row" v-if="step.qrcode_serial">
<el-col :span="8" class="detail-label">二维码序列</el-col>
<el-col :span="16" class="detail-value">{{ step.qrcode_serial }}</el-col>
</el-row>
<el-row class="detail-row" v-if="step.operator">
<el-col :span="8" class="detail-label">操作者</el-col>
<el-col :span="16" class="detail-value">{{ step.operator }}</el-col>
</el-row>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</el-card>
<!-- 钢卷分支图 -->
<el-card shadow="hover" class="mb20" v-if="traceResult && traceResult.records && traceResult.records.length > 0">
<div slot="header" class="card-header">
<span class="title-dot"></span>
<span class="title-text">钢卷分支图</span>
</div>
<div class="branch-container">
<div
class="branch-group"
v-for="(group, index) in groupedRecords"
:key="index"
>
<div class="branch-group-header">
<el-tag :type="getGroupTypeTag(group.groupColor)" size="medium">{{ group.title }}</el-tag>
<span class="branch-count">{{ group.coils.length }} 个钢卷</span>
</div>
<el-row :gutter="20" class="branch-coils">
<el-col
:span="8"
v-for="coil in group.coils"
:key="coil.coilId"
>
<el-card shadow="hover" class="coil-card">
<div class="coil-header">
<span class="coil-no">{{ coil.currentCoilNo }}</span>
<el-tag :type="coil.dataType === 1 ? 'success' : 'danger'" size="mini">
{{ coil.dataType === 1 ? '当前' : '历史' }}
</el-tag>
</div>
<div class="coil-info">
<p class="coil-detail">入场号{{ coil.enterCoilNo }}</p>
<p class="coil-detail" v-if="coil.team">班组{{ coil.team }}</p>
<p class="coil-detail" v-if="coil.warehouse && coil.warehouse.warehouseName">
库区{{ coil.warehouse.warehouseName }}
</p>
<!-- 显示母卷/子卷关系 -->
<p class="coil-detail" v-if="coil.parentCoilNos && coil.hasMergeSplit === 1">
<el-tag type="warning" size="mini">来自母卷{{ coil.parentCoilNos }}</el-tag>
</p>
<p class="coil-detail" v-if="coil.parentCoilNos && coil.hasMergeSplit === 0 && coil.dataType === 0">
<el-tag type="info" size="mini">分为子卷{{ coil.parentCoilNos }}</el-tag>
</p>
<p class="coil-detail" v-if="coil.parentCoilNos && coil.hasMergeSplit === 2">
<el-tag type="success" size="mini">合并自{{ coil.parentCoilNos }}</el-tag>
</p>
<p class="coil-detail">{{ coil.createTime }}</p>
</div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</el-card>
<!-- 无记录提示 -->
<div class="empty-tip" v-if="!traceResult || (traceResult && !traceResult.records && !traceResult.steps)">
<el-empty description="未找到相关钢卷记录"></el-empty>
</div>
</div>
</template>
<script>
export default {
name: 'CoilTraceResult',
props: {
// 追溯结果数据
traceResult: {
type: Object,
default: null
}
},
computed: {
// 按时间线和分支关系分组钢卷记录
groupedRecords() {
if (!this.traceResult || !this.traceResult.records) {
return [];
}
const groups = [];
// 按创建时间排序所有记录
const sortedRecords = [...this.traceResult.records].sort((a, b) =>
new Date(a.createTime) - new Date(b.createTime)
);
// 按数据类型分组,但保持时间顺序
const currentCoils = sortedRecords.filter(record => record.dataType === 1);
const historyCoils = sortedRecords.filter(record => record.dataType === 0);
// 当前数据分组
if (currentCoils.length > 0) {
const currentByOperation = this.groupByOperation(currentCoils);
groups.push(...currentByOperation);
}
// 历史数据分组
if (historyCoils.length > 0) {
const historyByOperation = this.groupByOperation(historyCoils, true);
groups.push(...historyByOperation);
}
return groups;
}
},
methods: {
// 按操作类型分组
groupByOperation(records, isHistory = false) {
const operationGroups = {};
for (const record of records) {
let operationType = '原始数据';
let groupColor = 'default';
if (record.hasMergeSplit === 1) {
operationType = '分卷结果';
groupColor = 'split';
} else if (record.hasMergeSplit === 2) {
operationType = '合卷结果';
groupColor = 'merge';
}
const groupKey = operationType;
if (!operationGroups[groupKey]) {
operationGroups[groupKey] = {
operationType: operationType,
groupColor: groupColor,
coils: []
};
}
operationGroups[groupKey].coils.push(record);
}
// 转换为数组
const groups = [];
for (const key in operationGroups) {
const group = operationGroups[key];
groups.push({
type: isHistory ? 'history' : 'current',
operationType: group.operationType,
groupColor: group.groupColor,
title: `${group.operationType}${isHistory ? '(历史)' : '(当前)'}`,
coils: group.coils
});
}
return groups;
},
// 获取分组标签类型
getGroupTypeTag(color) {
switch(color) {
case 'split': return 'warning';
case 'merge': return 'success';
default: return 'primary';
}
}
}
};
</script>
<style scoped>
/* 溯源结果样式 */
.trace-result-container {
padding: 10px 0;
}
.card-header {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 600;
}
.title-dot {
display: inline-block;
width: 4px;
height: 16px;
background: #409EFF;
border-radius: 2px;
margin-right: 8px;
}
.title-text {
color: #333;
}
.mb20 {
margin-bottom: 20px;
}
/* 二维码信息样式 */
.qrcode-info {
padding: 10px 0;
}
.info-row {
margin-bottom: 12px;
align-items: center;
}
.info-label {
color: #666;
font-weight: 500;
}
.info-value {
color: #333;
font-weight: 500;
}
/* 操作步骤样式 */
.step-header {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.step-action {
font-size: 15px;
font-weight: 600;
color: #333;
margin-right: 8px;
}
.step-details {
padding: 10px 0;
}
.detail-row {
margin-bottom: 8px;
align-items: center;
}
.detail-label {
color: #666;
font-size: 14px;
}
.detail-value {
color: #333;
font-size: 14px;
}
.mr8 {
margin-right: 8px;
margin-bottom: 8px;
}
/* 钢卷分支图样式 */
.branch-container {
padding: 10px 0;
}
.branch-group {
margin-bottom: 20px;
}
.branch-group-header {
display: flex;
align-items: center;
margin-bottom: 12px;
justify-content: space-between;
}
.branch-count {
color: #666;
font-size: 14px;
}
.branch-coils {
margin-bottom: 10px;
}
.coil-card {
height: 100%;
display: flex;
flex-direction: column;
}
.coil-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.coil-no {
font-size: 15px;
font-weight: 600;
color: #333;
}
.coil-info {
flex: 1;
}
.coil-detail {
font-size: 13px;
color: #666;
margin-bottom: 4px;
margin: 0;
line-height: 1.5;
}
/* 空提示样式 */
.empty-tip {
text-align: center;
padding: 40px 0;
}
</style>