Files
klp-oa/klp-ui/src/views/wms/coil/panels/CoilTraceResult.vue
砂糖 e5f034eb41 refactor(wms): 移除钢卷追踪结果中已注释的回滚相关代码
优化代码结构,删除不再使用的回滚专属代码块
同时改进操作时间和操作人的显示逻辑
2026-03-04 09:53:22 +08:00

568 lines
21 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">
<!-- 操作步骤基于标准化step渲染 -->
<el-card shadow="hover" class="mb20" v-if="standardSteps && standardSteps.length > 0">
<div slot="header" class="card-header">
<span class="title-dot"></span>
<span class="title-text">钢卷追溯操作步骤</span>
</div>
<el-timeline v-loading="loadingCoilDetails">
<el-timeline-item v-for="(step, index) in standardSteps" :key="index"
:timestamp="`步骤 ${step.original.display_step || step.original.step}`" placement="top">
<el-card shadow="hover">
<div class="step-header">
<span class="step-action">{{ step.action }}</span>
<el-tag size="mini" :type="getStepTagType(step.action)">{{ step.original.operation || step.action
}}</el-tag>
<el-tag size="mini" type="info" v-if="step.operation">
操作人{{ step.operation }}
</el-tag>
</div>
<!-- 标准化步骤详情 - 核心展示旧钢卷/新钢卷关键信息 -->
<div class="step-details">
<!-- 核心操作信息 -->
<el-row class="detail-row" v-if="step.time">
<el-col :span="8" class="detail-label">操作时间</el-col>
<el-col :span="16" class="detail-value">{{ step.time }}</el-col>
</el-row>
<!-- 旧钢卷关键信息操作前- 新增优化展示核心字段hover弹窗更多信息 -->
<el-row class="detail-row" v-if="step.oldCoilInfoList && step.oldCoilInfoList.length">
<el-col :span="8" class="detail-label">操作前钢卷</el-col>
<el-col :span="16" class="detail-value">
<div class="coil-info-item" v-for="(coil, idx) in step.oldCoilInfoList" :key="idx">
<el-popover placement="right" trigger="hover" width="400" v-if="coil.currentCoilNo != '-'"
:loading="loadingCoilDetails">
<div class="coil-detail-item">
<p><b>入场卷号</b>{{ coil.enterCoilNo || '-' }}</p>
<p><b>当前卷号</b>{{ coil.currentCoilNo || '-' }}</p>
<p><b>物料类型</b>{{ coil.materialType || '-' }}</p>
<p><b>物料名称</b>{{ coil.itemName || '-' }}</p>
<p><b>规格</b>{{ coil.specification || '-' }}</p>
<p><b>材质</b>{{ coil.material || '-' }}</p>
<p><b>生产厂家</b>{{ coil.manufacturer || '-' }}</p>
<p><b>净重</b>{{ coil.netWeight }} kg</p>
<p><b>逻辑库区</b>{{ coil.warehouseName || '-' }}</p>
<p><b>实际库存</b>{{ coil.actualWarehouseName || '-' }}</p>
<p><b>镀层质量</b>{{ coil.zincLayer || '-' }}</p>
<p><b>质量状态</b>{{ coil.qualityStatus || '-' }}</p>
<p><b>创建时间</b>{{ coil.createTime || '-' }}</p>
</div>
<div slot="reference" class="coil-info-summary">
{{ coil.currentCoilNo || '-' }} {{ coil.itemName }}{{ coil.specification }}- {{
coil.materialType }} - {{ coil.netWeight }}kg
</div>
</el-popover>
<div class="coil-info-summary coil-info-deleted" v-else>该钢卷已被回滚操作删除无法查询到信息</div>
</div>
</el-col>
</el-row>
<!-- 新钢卷关键信息操作后- 新增优化展示核心字段hover弹窗更多信息 -->
<el-row class="detail-row" v-if="step.newCoilInfoList && step.newCoilInfoList.length">
<el-col :span="8" class="detail-label">操作后钢卷</el-col>
<el-col :span="16" class="detail-value">
<div class="coil-info-item" v-for="(coil, idx) in step.newCoilInfoList" :key="idx">
<el-popover placement="right" trigger="hover" width="400" v-if="coil.currentCoilNo != '-'"
:loading="loadingCoilDetails">
<div class="coil-detail-item">
<p><b>入场卷号</b>{{ coil.enterCoilNo || '-' }}</p>
<p><b>当前卷号</b>{{ coil.currentCoilNo || '-' }}</p>
<p><b>物料类型</b>{{ coil.materialType || '-' }}</p>
<p><b>物料名称</b>{{ coil.itemName || '-' }}</p>
<p><b>规格</b>{{ coil.specification || '-' }}</p>
<p><b>材质</b>{{ coil.material || '-' }}</p>
<p><b>生产厂家</b>{{ coil.manufacturer || '-' }}</p>
<p><b>净重</b>{{ coil.netWeight }} kg</p>
<p><b>逻辑库区</b>{{ coil.warehouseName || '-' }}</p>
<p><b>实际库存</b>{{ coil.actualWarehouseName || '-' }}</p>
<p><b>镀层质量</b>{{ coil.zincLayer || '-' }}</p>
<p><b>质量状态</b>{{ coil.qualityStatus || '-' }}</p>
<p><b>创建时间</b>{{ coil.createTime || '-' }}</p>
</div>
<div slot="reference" class="coil-info-summary">
{{ coil.currentCoilNo || '-' }} {{ coil.itemName }}{{ coil.specification }}- {{
coil.materialType }} - {{ coil.netWeight }}kg
</div>
</el-popover>
<div class="coil-info-summary coil-info-deleted" v-else>该钢卷已被回滚操作删除无法查询到信息</div>
</div>
</el-col>
</el-row>
<!-- 更新专属修改内容保留原有逻辑适配上下文 -->
<el-row class="detail-row" v-if="step.changedFields">
<el-col :span="8" class="detail-label">修改内容</el-col>
<el-col :span="16" class="detail-value">
<div class="changed-field-item" v-for="(item, idx) in parseChangedFields(step.changedFields)"
:key="idx">
{{ item.field }}<span class="old-value">{{ item.oldVal }}</span> <span class="new-value">{{
item.newVal }}</span>
</div>
</el-col>
</el-row>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</el-card>
<!-- 无记录提示 -->
<div class="empty-tip" v-if="!standardSteps || standardSteps.length === 0">
<el-empty description="未找到相关钢卷记录"></el-empty>
</div>
</div>
</template>
<script>
import { listMaterialCoil } from '@/api/wms/coil';
export default {
name: 'CoilTraceResult',
props: {
// 追溯结果数据
traceResult: {
type: Object,
default: null
}
},
data() {
return {
qrcodeDialogVisible: false,
currentQrcodeContent: '',
coilDetails: {}, // 钢卷详情缓存:{coilId: 详情对象, ...}仅按coilId缓存移除coilNo缓存
loadingCoilDetails: false, // 钢卷详情加载状态
};
},
computed: {
// 生成标准化步骤列表核心基于原始steps转换新增旧/新钢卷信息列表)
standardSteps() {
if (!this.traceResult || !this.traceResult.steps || this.traceResult.steps.length === 0) {
return [];
}
// 遍历原始步骤,转换为标准化步骤(包含旧/新钢卷关键信息)
return this.traceResult.steps.map(step => this.formatStep(step));
}
},
watch: {
traceResult: {
handler(newVal) {
if (newVal) {
console.log('追溯结果更新,已生成标准化步骤:', this.standardSteps);
// 步骤更新后,防抖获取钢卷详情(避免频繁请求)
this.debounceFetchCoilDetails();
} else {
// 无追溯结果时,清空缓存
this.coilDetails = {};
}
},
deep: true
}
},
methods: {
// 根据操作类型获取标签样式
getStepTagType(action) {
const typeMap = {
'创建': 'success',
'更新': 'primary',
'分卷': 'warning',
'合卷': 'info',
'回滚': 'danger'
};
return typeMap[action] || 'default';
},
// 格式化时间戳毫秒为YYYY-MM-DD HH:mm:ss
formatTime(timeStamp) {
if (!timeStamp) return '-';
const date = new Date(timeStamp);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
},
// 解析修改字段字符串为结构化数据
parseChangedFields(changedFieldsStr) {
if (!changedFieldsStr) return [];
// 拆分每个修改项(分号分隔)
const items = changedFieldsStr.split(';').filter(item => item.trim());
return items.map(item => {
const [fieldPart, valuePart] = item.split(':').map(part => part.trim());
if (!valuePart) return { field: fieldPart, oldVal: '-', newVal: '-' };
// 拆分新旧值(→分隔)
const [oldVal, newVal] = valuePart.split('→').map(val => {
const trimmedVal = val.trim();
return trimmedVal === 'null' ? '-' : trimmedVal;
});
return {
field: fieldPart,
oldVal: oldVal || '-',
newVal: newVal || '-'
};
});
},
// 核心补全formatStep将原始step转换为标准化step新增旧/新钢卷信息列表)
formatStep(originalStep) {
// 初始化标准化step结构移除coilNo相关冗余字段新增钢卷信息列表
const standardStep = {
// 基础字段
action: '', // 创建/更新/分卷/合卷/回滚
time: '-', // 操作时间
operation: '-', // 操作人
oldCoilIds: [], // 操作前钢卷ID列表替换原oldId适配多钢卷场景
newCoilIds: [], // 操作后钢卷ID列表替换原newId适配多钢卷场景
changedFields: '', // 更新操作的修改字段
// 新增:钢卷关键信息列表(用于展示)
oldCoilInfoList: [], // 操作前钢卷关键信息列表
newCoilInfoList: [], // 操作后钢卷关键信息列表
deletedCoilInfo: null, // 回滚删除的钢卷关键信息
restoredCoilInfo: null, // 回滚恢复的钢卷关键信息
// 保留原始step用于兼容原有逻辑
original: originalStep
};
// 1. 映射操作类型核心统一action命名
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 || '-';
}
// 2. 操作时间(优先取更新时间/回滚时间)
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);
}
// 3. 操作人(优先昵称,其次账号)
standardStep.operation = originalStep.operator_nickname || originalStep.operator || originalStep.create_by || '-';
// 4. 核心ID映射oldCoilIds操作前钢卷ID列表
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 '合卷':
// 合卷操作前钢卷为多个来源ID
standardStep.oldCoilIds = originalStep.parent_coil_ids
? originalStep.parent_coil_ids.split(',').map(id => id.trim()).filter(Boolean)
: [];
break;
case '回滚':
// 回滚操作前钢卷为删除的钢卷ID
standardStep.oldCoilIds = originalStep.deleted_coil_id ? [originalStep.deleted_coil_id.trim()] : [];
break;
default:
standardStep.oldCoilIds = [];
}
// 5. 核心ID映射newCoilIds操作后钢卷ID列表
switch (standardStep.action) {
case '创建':
standardStep.newCoilIds = originalStep.current_coil_id ? [originalStep.current_coil_id.trim()] : [];
break;
case '更新':
console.log('更新操作后钢卷ID:', originalStep.new_coil_id, originalStep);
standardStep.newCoilIds = originalStep.new_coil_id ? [originalStep.new_coil_id.trim()] : [];
break;
case '分卷':
// 分卷后钢卷为多个子钢卷ID
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 '回滚':
// 回滚后钢卷为恢复的钢卷ID
standardStep.newCoilIds = originalStep.restored_coil_id ? [originalStep.restored_coil_id.trim()] : [];
break;
default:
standardStep.newCoilIds = [];
}
// 6. 更新专属changedFields修改字段
if (standardStep.action === '更新') {
standardStep.changedFields = originalStep.changed_fields || '';
}
// 7. 映射旧/新钢卷关键信息(基于缓存的钢卷详情)
standardStep.oldCoilInfoList = this.mapCoilInfoList(standardStep.oldCoilIds);
standardStep.newCoilInfoList = this.mapCoilInfoList(standardStep.newCoilIds);
// 8. 回滚专属:删除/恢复钢卷信息映射
if (standardStep.action === '回滚') {
standardStep.deletedCoilInfo = standardStep.oldCoilInfoList[0] || null;
standardStep.restoredCoilInfo = standardStep.newCoilInfoList[0] || null;
}
return standardStep;
},
// 映射钢卷ID列表为关键信息列表适配接口返回结构
mapCoilInfoList(coilIds) {
if (!coilIds || !coilIds.length) return [];
return coilIds.map(coilId => {
const coil = this.coilDetails[coilId] || {};
// 提取关键信息对应list接口返回结构
return {
enterCoilNo: coil.enterCoilNo || '-',
currentCoilNo: coil.currentCoilNo || '-',
materialType: coil.materialType || '-',
itemName: coil.itemName || '-',
specification: coil.specification || '-',
material: coil.material || '-',
netWeight: coil.netWeight || 0,
warehouseName: coil.warehouseName || '-',
actualWarehouseName: coil.actualWarehouseName || '-',
manufacturer: coil.manufacturer || '-',
zincLayer: coil.zincLayer || '-',
qualityStatus: coil.qualityStatus || '-',
createTime: coil.createTime || '-',
};
});
},
// 收集所有需要查询的coilIds基于标准化step仅保留coilId逻辑
collectCoilIds() {
if (!this.standardSteps.length) return [];
const coilIds = new Set();
this.standardSteps.forEach(step => {
// 操作前钢卷ID
step.oldCoilIds.forEach(id => id && coilIds.add(id));
// 操作后钢卷ID
step.newCoilIds.forEach(id => id && coilIds.add(id));
});
return [...coilIds];
},
// 防抖函数:避免频繁调用接口
debounce(func, delay = 300) {
let timer = null;
return (...args) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
},
// 防抖版获取钢卷详情
debounceFetchCoilDetails: function () {
return this.debounce(this.fetchCoilDetails)();
},
// 核心批量获取钢卷详情仅按coilId查询移除coilNo相关逻辑
async fetchCoilDetails() {
// 1. 收集所有唯一的coilId
const coilIds = this.collectCoilIds().filter(id => id);
if (coilIds.length === 0) {
this.coilDetails = {};
return;
}
// 2. 避免重复请求(加载中则返回)
if (this.loadingCoilDetails) return;
this.loadingCoilDetails = true;
try {
// 3. 调用listMaterialCoil接口传递coilIds参数适配接口要求
const res = await listMaterialCoil({ coilIds: coilIds.join(',') });
if (res && res.code === 200 && res.rows) {
const coilList = res.rows;
// 4. 构建缓存仅按coilId缓存移除coilNo缓存
const coilIdMap = {};
coilList.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;
}
});
console.log('更新后的标准化步骤:', this.standardSteps);
} else {
this.$message.warning('获取钢卷详情失败');
}
} catch (error) {
console.error('获取钢卷详情接口异常:', error);
this.$message.error('获取钢卷详情异常,请刷新重试');
} finally {
this.loadingCoilDetails = false;
}
},
},
// 组件销毁前清空缓存,避免内存泄漏
beforeDestroy() {
this.coilDetails = {};
}
};
</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;
}
/* 操作步骤样式增强 */
.step-header {
display: flex;
align-items: center;
margin-bottom: 12px;
flex-wrap: wrap;
gap: 8px;
}
.step-action {
font-size: 15px;
font-weight: 600;
color: #333;
margin-right: 8px;
}
.step-details {
padding: 10px 0;
}
.detail-row {
margin-bottom: 12px;
align-items: flex-start;
}
.detail-label {
color: #666;
font-size: 14px;
padding-top: 4px;
}
.detail-value {
color: #333;
font-size: 14px;
}
.mr8 {
margin-right: 8px;
margin-bottom: 8px;
}
/* 修改字段样式 */
.changed-field-item {
margin-bottom: 4px;
line-height: 1.5;
}
.old-value {
color: #F56C6C;
}
.new-value {
color: #67C23A;
}
/* 空提示样式 */
.empty-tip {
text-align: center;
padding: 40px 0;
}
/* 新增:钢卷详情弹窗样式(优化排版,展示更多信息) */
.coil-detail-item {
font-size: 13px;
line-height: 1.8;
color: #333;
}
.coil-detail-item p {
margin: 0;
padding: 2px 0;
display: flex;
justify-content: space-between;
}
.coil-detail-item p b {
color: #666;
min-width: 80px;
}
/* 新增钢卷关键信息摘要样式hover触发弹窗 */
.coil-info-item {
margin-bottom: 8px;
display: inline-block;
margin-right: 12px;
}
.coil-info-summary {
cursor: pointer;
color: #409EFF;
background: #f5faff;
padding: 4px 8px;
border-radius: 4px;
border: 1px solid #e6f7ff;
white-space: nowrap;
}
.coil-info-deleted {
color: #F56C6C;
background: #fff5f5;
}
.coil-info-summary.deleted:hover {
background: #e6f7ff;
}
</style>