419 lines
12 KiB
Vue
419 lines
12 KiB
Vue
<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> |