1703 lines
60 KiB
Vue
1703 lines
60 KiB
Vue
|
|
<template>
|
|||
|
|
<div class="coil-info-page" v-loading="loading">
|
|||
|
|
<div class="content-container">
|
|||
|
|
<div class="section basic-info-section">
|
|||
|
|
<div class="section-header">
|
|||
|
|
<span class="section-icon">📦</span>
|
|||
|
|
<span class="section-title">基本信息</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="section-body">
|
|||
|
|
<CoilInfoRender :coilInfo="coilInfo" :column="5" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="section trace-section">
|
|||
|
|
<div class="section-header">
|
|||
|
|
<span class="section-icon">🔄</span>
|
|||
|
|
<span class="section-title">生命周期追踪</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="section-body">
|
|||
|
|
<div v-if="standardSteps && standardSteps.length > 0" class="trace-content">
|
|||
|
|
<div v-for="(step, index) in standardSteps" :key="index" class="step-item">
|
|||
|
|
<!-- 第一个步骤是入库(创建) -->
|
|||
|
|
<div v-if="index === 0 && step.action === '创建'" class="step-content step-content-inbound">
|
|||
|
|
<!-- 入库钢卷卡片 -->
|
|||
|
|
<div class="coil-card-wrapper inbound-coil-wrapper">
|
|||
|
|
<div class="coil-card-header inbound-header">
|
|||
|
|
<span class="card-label">📦 入库</span>
|
|||
|
|
</div>
|
|||
|
|
<div v-for="(coil, idx) in getInboundCoil(step, index)" :key="idx" class="coil-card-futuristic" v-if="coil.currentCoilNo !== '-'">
|
|||
|
|
<div class="coil-futuristic-header">
|
|||
|
|
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
|||
|
|
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="coil-futuristic-body">
|
|||
|
|
<!-- 钢卷图标 -->
|
|||
|
|
<div class="coil-icon-container">
|
|||
|
|
<svg class="coil-svg" viewBox="0 0 200 200">
|
|||
|
|
<defs>
|
|||
|
|
<linearGradient id="coilGradInbound1" x1="0%" y1="0%" x2="100%" y2="100%">
|
|||
|
|
<stop offset="0%" style="stop-color:#3b82f6;stop-opacity:0.5" />
|
|||
|
|
<stop offset="50%" style="stop-color:#2563eb;stop-opacity:0.4" />
|
|||
|
|
<stop offset="100%" style="stop-color:#3b82f6;stop-opacity:0.5" />
|
|||
|
|
</linearGradient>
|
|||
|
|
<linearGradient id="coilGradInbound2" x1="0%" y1="0%" x2="100%" y2="0%">
|
|||
|
|
<stop offset="0%" style="stop-color:#93c5fd;stop-opacity:0.4" />
|
|||
|
|
<stop offset="100%" style="stop-color:#bfdbfe;stop-opacity:0.3" />
|
|||
|
|
</linearGradient>
|
|||
|
|
</defs>
|
|||
|
|
|
|||
|
|
<!-- 外圈 -->
|
|||
|
|
<circle cx="100" cy="100" r="70" fill="none" stroke="url(#coilGradInbound1)" stroke-width="2.5">
|
|||
|
|
<animate attributeName="r" values="70;72;70" dur="2s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
<circle cx="100" cy="100" r="60" fill="none" stroke="url(#coilGradInbound2)" stroke-width="1.8" opacity="0.6">
|
|||
|
|
<animate attributeName="stroke-dashoffset" values="0;377" dur="4s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
|
|||
|
|
<!-- 内层钢卷 -->
|
|||
|
|
<circle cx="100" cy="100" r="45" fill="url(#coilGradInbound1)" opacity="0.15">
|
|||
|
|
<animate attributeName="opacity" values="0.15;0.3;0.15" dur="3s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
<circle cx="100" cy="100" r="35" fill="url(#coilGradInbound2)" opacity="0.2" />
|
|||
|
|
<circle cx="100" cy="100" r="25" fill="url(#coilGradInbound1)" opacity="0.25" />
|
|||
|
|
<circle cx="100" cy="100" r="15" fill="white" opacity="0.4" />
|
|||
|
|
|
|||
|
|
<!-- 装饰线条 -->
|
|||
|
|
<line x1="100" y1="100" x2="100" y2="30" stroke="url(#coilGradInbound1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="170" y2="100" stroke="url(#coilGradInbound1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="100" y2="170" stroke="url(#coilGradInbound1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="30" y2="100" stroke="url(#coilGradInbound1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
|
|||
|
|
<!-- 中心点 -->
|
|||
|
|
<circle cx="100" cy="100" r="4" fill="#3b82f6">
|
|||
|
|
<animate attributeName="r" values="4;6;4" dur="1.5s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
</svg>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 属性标签 -->
|
|||
|
|
<div class="coil-attr-tags">
|
|||
|
|
<!-- 顶部 - 材质 -->
|
|||
|
|
<div class="attr-tag attr-top">
|
|||
|
|
<div class="attr-line attr-line-top"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">材质</span>
|
|||
|
|
<span class="attr-value">{{ coil.material || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右侧 - 规格 -->
|
|||
|
|
<div class="attr-tag attr-right">
|
|||
|
|
<div class="attr-line attr-line-right"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">规格</span>
|
|||
|
|
<span class="attr-value">{{ coil.specification || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左侧 - 质量状态 -->
|
|||
|
|
<div class="attr-tag attr-left">
|
|||
|
|
<div class="attr-line attr-line-left"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">质量状态</span>
|
|||
|
|
<span class="attr-value" :class="getFuturisticStatusClass(coil.qualityStatus)">{{ coil.qualityStatus }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左上角 - 入场卷号 -->
|
|||
|
|
<div class="attr-tag attr-top-left" v-if="coil.enterCoilNo && coil.enterCoilNo !== '-'">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">入场卷号</span>
|
|||
|
|
<span class="attr-value">{{ coil.enterCoilNo }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右上角 - 厂家原料号 -->
|
|||
|
|
<div class="attr-tag attr-top-right" v-if="coil.supplierCoilNo && coil.supplierCoilNo !== '-'">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">厂家原料号</span>
|
|||
|
|
<span class="attr-value">{{ coil.supplierCoilNo }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左下角 - 班组 -->
|
|||
|
|
<div class="attr-tag attr-bottom-left">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">班组</span>
|
|||
|
|
<span class="attr-value">{{ coil.team || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右下角 - 厂家 -->
|
|||
|
|
<div class="attr-tag attr-bottom-right">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">厂家</span>
|
|||
|
|
<span class="attr-value">{{ coil.manufacturer || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 备注信息在底部 -->
|
|||
|
|
<div class="attr-tag attr-remark">
|
|||
|
|
<div class="attr-content attr-content-remark">
|
|||
|
|
<span class="attr-label">备注</span>
|
|||
|
|
<span class="attr-value">{{ coil.remark || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 底部信息 -->
|
|||
|
|
<div class="coil-futuristic-footer">
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">镀层</span>
|
|||
|
|
<span class="footer-value">{{ coil.zincLayer || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">表面处理</span>
|
|||
|
|
<span class="footer-value">{{ coil.surfaceTreatmentDesc || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">逻辑库位</span>
|
|||
|
|
<span class="footer-value">{{ coil.warehouseName || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div v-if="getInboundCoil(step, index).length === 0 || getInboundCoil(step, index).every(c => c.currentCoilNo === '-')" class="empty-coil">
|
|||
|
|
<span>无钢卷信息</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 中间入库信息 -->
|
|||
|
|
<div class="action-center">
|
|||
|
|
<div class="action-arrow action-arrow-inbound">
|
|||
|
|
<i class="el-icon-download"></i>
|
|||
|
|
</div>
|
|||
|
|
<div class="action-info">
|
|||
|
|
<el-tag size="mini" type="primary" class="action-tag">入库</el-tag>
|
|||
|
|
<span class="action-operator">{{ step.operation }}</span>
|
|||
|
|
<span class="action-time">{{ step.time }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 其他步骤是变更 -->
|
|||
|
|
<div v-if="index !== 0 && step.action !== '创建'" class="step-content">
|
|||
|
|
<!-- 左侧旧钢卷卡片 -->
|
|||
|
|
<div class="coil-card-wrapper old-coil-wrapper">
|
|||
|
|
<div class="coil-card-header">
|
|||
|
|
<span class="card-label">变更前</span>
|
|||
|
|
</div>
|
|||
|
|
<div v-for="(coil, idx) in step.oldCoilInfoList" :key="idx" class="coil-card-futuristic" v-if="coil.currentCoilNo != '-'">
|
|||
|
|
<div class="coil-futuristic-header">
|
|||
|
|
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
|||
|
|
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="coil-futuristic-body">
|
|||
|
|
<!-- 钢卷图标 -->
|
|||
|
|
<div class="coil-icon-container">
|
|||
|
|
<svg class="coil-svg" viewBox="0 0 200 200">
|
|||
|
|
<defs>
|
|||
|
|
<linearGradient id="coilGrad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
|||
|
|
<stop offset="0%" style="stop-color:#6366f1;stop-opacity:0.5" />
|
|||
|
|
<stop offset="50%" style="stop-color:#8b5cf6;stop-opacity:0.4" />
|
|||
|
|
<stop offset="100%" style="stop-color:#6366f1;stop-opacity:0.5" />
|
|||
|
|
</linearGradient>
|
|||
|
|
<linearGradient id="coilGrad2" x1="0%" y1="0%" x2="100%" y2="0%">
|
|||
|
|
<stop offset="0%" style="stop-color:#a78bfa;stop-opacity:0.4" />
|
|||
|
|
<stop offset="100%" style="stop-color:#c084fc;stop-opacity:0.3" />
|
|||
|
|
</linearGradient>
|
|||
|
|
</defs>
|
|||
|
|
|
|||
|
|
<!-- 外圈 -->
|
|||
|
|
<circle cx="100" cy="100" r="70" fill="none" stroke="url(#coilGrad1)" stroke-width="2.5">
|
|||
|
|
<animate attributeName="r" values="70;72;70" dur="2s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
<circle cx="100" cy="100" r="60" fill="none" stroke="url(#coilGrad2)" stroke-width="1.8" opacity="0.6">
|
|||
|
|
<animate attributeName="stroke-dashoffset" values="0;377" dur="4s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
|
|||
|
|
<!-- 内层钢卷 -->
|
|||
|
|
<circle cx="100" cy="100" r="45" fill="url(#coilGrad1)" opacity="0.15">
|
|||
|
|
<animate attributeName="opacity" values="0.15;0.3;0.15" dur="3s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
<circle cx="100" cy="100" r="35" fill="url(#coilGrad2)" opacity="0.2" />
|
|||
|
|
<circle cx="100" cy="100" r="25" fill="url(#coilGrad1)" opacity="0.25" />
|
|||
|
|
<circle cx="100" cy="100" r="15" fill="white" opacity="0.4" />
|
|||
|
|
|
|||
|
|
<!-- 装饰线条 -->
|
|||
|
|
<line x1="100" y1="100" x2="100" y2="30" stroke="url(#coilGrad1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="170" y2="100" stroke="url(#coilGrad1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="100" y2="170" stroke="url(#coilGrad1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="30" y2="100" stroke="url(#coilGrad1)" stroke-width="1" opacity="0.4" />
|
|||
|
|
|
|||
|
|
<!-- 中心点 -->
|
|||
|
|
<circle cx="100" cy="100" r="4" fill="#6366f1">
|
|||
|
|
<animate attributeName="r" values="4;6;4" dur="1.5s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
</svg>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 属性标签 -->
|
|||
|
|
<div class="coil-attr-tags">
|
|||
|
|
<!-- 顶部 - 材质 -->
|
|||
|
|
<div class="attr-tag attr-top">
|
|||
|
|
<div class="attr-line attr-line-top"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">材质</span>
|
|||
|
|
<span class="attr-value">{{ coil.material || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右侧 - 规格 -->
|
|||
|
|
<div class="attr-tag attr-right">
|
|||
|
|
<div class="attr-line attr-line-right"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">规格</span>
|
|||
|
|
<span class="attr-value">{{ coil.specification || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左侧 - 质量状态 -->
|
|||
|
|
<div class="attr-tag attr-left">
|
|||
|
|
<div class="attr-line attr-line-left"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">状态</span>
|
|||
|
|
<span class="attr-value" :class="getFuturisticStatusClass(coil.qualityStatus)">{{ coil.qualityStatus || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左上角 - 入场卷号 -->
|
|||
|
|
<div class="attr-tag attr-top-left">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">入场卷号</span>
|
|||
|
|
<span class="attr-value">{{ coil.enterCoilNo || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右上角 - 厂家原料号 -->
|
|||
|
|
<div class="attr-tag attr-top-right">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">厂家原料号</span>
|
|||
|
|
<span class="attr-value">{{ coil.supplierCoilNo || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左下角 - 班组 -->
|
|||
|
|
<div class="attr-tag attr-bottom-left">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">班组</span>
|
|||
|
|
<span class="attr-value">{{ coil.team || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右下角 - 厂家 -->
|
|||
|
|
<div class="attr-tag attr-bottom-right">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">厂家</span>
|
|||
|
|
<span class="attr-value">{{ coil.manufacturer || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 备注信息在底部 -->
|
|||
|
|
<div class="attr-tag attr-remark">
|
|||
|
|
<div class="attr-content attr-content-remark">
|
|||
|
|
<span class="attr-label">备注</span>
|
|||
|
|
<span class="attr-value">{{ coil.remark || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 底部信息 -->
|
|||
|
|
<div class="coil-futuristic-footer">
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">镀层</span>
|
|||
|
|
<span class="footer-value">{{ coil.zincLayer || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">表面处理</span>
|
|||
|
|
<span class="footer-value">{{ coil.surfaceTreatmentDesc || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">逻辑库位</span>
|
|||
|
|
<span class="footer-value">{{ coil.warehouseName || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div v-if="step.oldCoilInfoList.length === 0 || step.oldCoilInfoList.every(c => c.currentCoilNo === '-')" class="empty-coil">
|
|||
|
|
<span>无钢卷信息</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 中间操作信息 -->
|
|||
|
|
<div class="action-center">
|
|||
|
|
<div class="action-arrow">
|
|||
|
|
<i class="el-icon-right"></i>
|
|||
|
|
</div>
|
|||
|
|
<div class="action-info">
|
|||
|
|
<el-tag size="mini" type="info" class="action-tag">{{ step.action }}</el-tag>
|
|||
|
|
<span class="action-operator">{{ step.operation }}</span>
|
|||
|
|
<span class="action-time">{{ step.time }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右侧新钢卷卡片 -->
|
|||
|
|
<div class="coil-card-wrapper new-coil-wrapper">
|
|||
|
|
<div class="coil-card-header">
|
|||
|
|
<span class="card-label">变更后</span>
|
|||
|
|
</div>
|
|||
|
|
<div v-for="(coil, idx) in step.newCoilInfoList" :key="idx" class="coil-card-futuristic" v-if="coil.currentCoilNo != '-'">
|
|||
|
|
<div class="coil-futuristic-header">
|
|||
|
|
<span class="coil-futuristic-no">{{ coil.currentCoilNo }}</span>
|
|||
|
|
<span class="coil-futuristic-weight">{{ coil.netWeight ? coil.netWeight + ' t' : '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="coil-futuristic-body">
|
|||
|
|
<!-- 钢卷图标 -->
|
|||
|
|
<div class="coil-icon-container">
|
|||
|
|
<svg class="coil-svg" viewBox="0 0 200 200">
|
|||
|
|
<defs>
|
|||
|
|
<linearGradient id="coilGrad3" x1="0%" y1="0%" x2="100%" y2="100%">
|
|||
|
|
<stop offset="0%" style="stop-color:#10b981;stop-opacity:0.5" />
|
|||
|
|
<stop offset="50%" style="stop-color:#34d399;stop-opacity:0.4" />
|
|||
|
|
<stop offset="100%" style="stop-color:#10b981;stop-opacity:0.5" />
|
|||
|
|
</linearGradient>
|
|||
|
|
<linearGradient id="coilGrad4" x1="0%" y1="0%" x2="100%" y2="0%">
|
|||
|
|
<stop offset="0%" style="stop-color:#a7f3d0;stop-opacity:0.4" />
|
|||
|
|
<stop offset="100%" style="stop-color:#fbcfe8;stop-opacity:0.3" />
|
|||
|
|
</linearGradient>
|
|||
|
|
</defs>
|
|||
|
|
|
|||
|
|
<!-- 外圈 -->
|
|||
|
|
<circle cx="100" cy="100" r="70" fill="none" stroke="url(#coilGrad3)" stroke-width="2.5">
|
|||
|
|
<animate attributeName="r" values="70;72;70" dur="2s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
<circle cx="100" cy="100" r="60" fill="none" stroke="url(#coilGrad4)" stroke-width="1.8" opacity="0.6" stroke-dasharray="50 50">
|
|||
|
|
<animate attributeName="stroke-dashoffset" values="0;100" dur="3s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
|
|||
|
|
<!-- 内层钢卷 -->
|
|||
|
|
<circle cx="100" cy="100" r="45" fill="url(#coilGrad3)" opacity="0.15">
|
|||
|
|
<animate attributeName="opacity" values="0.15;0.3;0.15" dur="3s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
<circle cx="100" cy="100" r="35" fill="url(#coilGrad4)" opacity="0.2" />
|
|||
|
|
<circle cx="100" cy="100" r="25" fill="url(#coilGrad3)" opacity="0.25" />
|
|||
|
|
<circle cx="100" cy="100" r="15" fill="white" opacity="0.4" />
|
|||
|
|
|
|||
|
|
<!-- 装饰线条 -->
|
|||
|
|
<line x1="100" y1="100" x2="100" y2="30" stroke="url(#coilGrad3)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="170" y2="100" stroke="url(#coilGrad3)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="100" y2="170" stroke="url(#coilGrad3)" stroke-width="1" opacity="0.4" />
|
|||
|
|
<line x1="100" y1="100" x2="30" y2="100" stroke="url(#coilGrad3)" stroke-width="1" opacity="0.4" />
|
|||
|
|
|
|||
|
|
<!-- 中心点 -->
|
|||
|
|
<circle cx="100" cy="100" r="4" fill="#10b981">
|
|||
|
|
<animate attributeName="r" values="4;6;4" dur="1.5s" repeatCount="indefinite" />
|
|||
|
|
</circle>
|
|||
|
|
</svg>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 属性标签 -->
|
|||
|
|
<div class="coil-attr-tags">
|
|||
|
|
<!-- 顶部 - 材质 -->
|
|||
|
|
<div class="attr-tag attr-top">
|
|||
|
|
<div class="attr-line attr-line-top"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">材质</span>
|
|||
|
|
<span class="attr-value">{{ coil.material || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右侧 - 规格 -->
|
|||
|
|
<div class="attr-tag attr-right">
|
|||
|
|
<div class="attr-line attr-line-right"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">规格</span>
|
|||
|
|
<span class="attr-value">{{ coil.specification || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左侧 - 质量状态 -->
|
|||
|
|
<div class="attr-tag attr-left">
|
|||
|
|
<div class="attr-line attr-line-left"></div>
|
|||
|
|
<div class="attr-content">
|
|||
|
|
<span class="attr-label">状态</span>
|
|||
|
|
<span class="attr-value" :class="getFuturisticStatusClass(coil.qualityStatus || '-')">{{ coil.qualityStatus || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左上角 - 入场卷号 -->
|
|||
|
|
<div class="attr-tag attr-top-left">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">入场卷号</span>
|
|||
|
|
<span class="attr-value">{{ coil.enterCoilNo || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右上角 - 厂家原料号 -->
|
|||
|
|
<div class="attr-tag attr-top-right">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">厂家原料号</span>
|
|||
|
|
<span class="attr-value">{{ coil.supplierCoilNo || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 左下角 - 班组 -->
|
|||
|
|
<div class="attr-tag attr-bottom-left">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">班组</span>
|
|||
|
|
<span class="attr-value">{{ coil.team || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右下角 - 厂家 -->
|
|||
|
|
<div class="attr-tag attr-bottom-right">
|
|||
|
|
<div class="attr-content attr-content-small">
|
|||
|
|
<span class="attr-label">厂家</span>
|
|||
|
|
<span class="attr-value">{{ coil.manufacturer || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 备注信息在底部 -->
|
|||
|
|
<div class="attr-tag attr-remark">
|
|||
|
|
<div class="attr-content attr-content-remark">
|
|||
|
|
<span class="attr-label">备注</span>
|
|||
|
|
<span class="attr-value">{{ coil.remark || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 底部信息 -->
|
|||
|
|
<div class="coil-futuristic-footer">
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">镀层</span>
|
|||
|
|
<span class="footer-value">{{ coil.zincLayer || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">表面处理</span>
|
|||
|
|
<span class="footer-value">{{ coil.surfaceTreatmentDesc || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="footer-item">
|
|||
|
|
<span class="footer-label">逻辑库位</span>
|
|||
|
|
<span class="footer-value">{{ coil.warehouseName || '-' }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div v-if="step.newCoilInfoList.length === 0 || step.newCoilInfoList.every(c => c.currentCoilNo === '-')" class="empty-coil">
|
|||
|
|
<span>无钢卷信息</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div v-else class="empty-state">
|
|||
|
|
<i class="el-icon-document"></i>
|
|||
|
|
<span>未找到相关钢卷记录</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="section sales-section">
|
|||
|
|
<div class="section-header">
|
|||
|
|
<span class="section-icon">💰</span>
|
|||
|
|
<span class="section-title">销售信息</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="section-body">
|
|||
|
|
<el-descriptions :column="3" border size="small">
|
|||
|
|
<el-descriptions-item label="合同号">{{ salesInfo.contractCode || '-' }}</el-descriptions-item>
|
|||
|
|
<el-descriptions-item label="客户名称">{{ salesInfo.customer || '-' }}</el-descriptions-item>
|
|||
|
|
<el-descriptions-item label="销售人员">{{ salesInfo.salesman || '-' }}</el-descriptions-item>
|
|||
|
|
<el-descriptions-item label="签订时间">{{ salesInfo.signTime || '-' }}</el-descriptions-item>
|
|||
|
|
<el-descriptions-item label="交货时间">{{ salesInfo.deliveryTime || '-' }}</el-descriptions-item>
|
|||
|
|
<el-descriptions-item label="订单总额">{{ salesInfo.orderAmount || '-' }}</el-descriptions-item>
|
|||
|
|
</el-descriptions>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="section combined-section">
|
|||
|
|
<div class="section-header">
|
|||
|
|
<span class="section-icon">📋</span>
|
|||
|
|
<span class="section-title">移库记录 & 调拨记录</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="section-body tables-row">
|
|||
|
|
<!-- 移库记录 - 占3份 -->
|
|||
|
|
<div class="table-wrapper warehouse-table">
|
|||
|
|
<div class="table-title">移库记录</div>
|
|||
|
|
<div class="table-container">
|
|||
|
|
<el-table :data="warehouseTranferList" size="small" border stripe style="width: 100%">
|
|||
|
|
<el-table-column prop="createTime" label="操作时间" width="170"></el-table-column>
|
|||
|
|
<el-table-column prop="operationType" label="操作类型" width="90">
|
|||
|
|
<template slot-scope="scope">
|
|||
|
|
<span v-if="scope.row.operationType === 1">收货</span>
|
|||
|
|
<span v-else-if="scope.row.operationType === 2">加工</span>
|
|||
|
|
<span v-else-if="scope.row.operationType === 3">调拨</span>
|
|||
|
|
<span v-else-if="scope.row.operationType === 4">发货</span>
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
<el-table-column prop="inOutType" label="出入库" width="80">
|
|||
|
|
<template slot-scope="scope">
|
|||
|
|
{{ scope.row.inOutType === 1 ? '入库' : '出库' }}
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
<el-table-column prop="warehouse.actualWarehouseName" label="库位" width="140">
|
|||
|
|
<template slot-scope="scope">
|
|||
|
|
{{ scope.row.warehouse.actualWarehouseName || '-' }}
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
<el-table-column prop="remark" label="备注" min-width="120"></el-table-column>
|
|||
|
|
</el-table>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 调拨记录 - 占2份 -->
|
|||
|
|
<div class="table-wrapper transfer-table">
|
|||
|
|
<div class="table-title">调拨记录</div>
|
|||
|
|
<div class="table-container">
|
|||
|
|
<el-table :data="tranferList" size="small" border stripe style="width: 100%">
|
|||
|
|
<el-table-column label="调拨前">
|
|||
|
|
<template slot-scope="scope">
|
|||
|
|
{{ scope.row.createTime }}
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
<el-table-column label="调拨后">
|
|||
|
|
<template slot-scope="scope">
|
|||
|
|
{{ scope.row.createTime }}
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
</el-table>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</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="abnormalTable" :list="abmornalList" :editable="false" :show-coil="false" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import { getMaterialCoil, listMaterialCoil, getMaterialCoilTrace } from '@/api/wms/coil';
|
|||
|
|
import { getCoilWarehouseOperationLogByCoilId } from '@/api/wms/coilWarehouseOperationLog';
|
|||
|
|
import { listCoilAbnormal } from '@/api/wms/coilAbnormal'
|
|||
|
|
|
|||
|
|
import CoilInfoRender from '@/views/wms/coil/components/CoilInfo.vue';
|
|||
|
|
import AbnormalTable from '@/views/wms/coil/components/AbnormalTable.vue';
|
|||
|
|
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
name: 'CoilInfo',
|
|||
|
|
components: {
|
|||
|
|
CoilInfoRender,
|
|||
|
|
AbnormalTable
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
loading: false,
|
|||
|
|
coilInfoLoading: false,
|
|||
|
|
traceLoading: false,
|
|||
|
|
traceResult: null,
|
|||
|
|
coilDetails: {},
|
|||
|
|
loadingCoilDetails: false,
|
|||
|
|
coilInfo: {},
|
|||
|
|
coilList: [],
|
|||
|
|
wipList: [],
|
|||
|
|
annealList: [],
|
|||
|
|
standardSteps: [],
|
|||
|
|
coilId: '',
|
|||
|
|
warehouseTranferList: [],
|
|||
|
|
abmornalList: []
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
computed: {
|
|||
|
|
salesInfo() {
|
|||
|
|
return this.coilInfo.orderList?.[0] || {};
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
async created() {
|
|||
|
|
this.coilId = this.$route.params.coilId;
|
|||
|
|
this.loading = true;
|
|||
|
|
await this.getCoilInfo();
|
|||
|
|
await this.getTraceInfo();
|
|||
|
|
await this.getAbnormalList();
|
|||
|
|
await this.getWarehouseTransferList();
|
|||
|
|
this.loading = false;
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
async getCoilInfo() {
|
|||
|
|
const res = await getMaterialCoil(this.coilId);
|
|||
|
|
this.coilInfo = res.data;
|
|||
|
|
},
|
|||
|
|
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 getCoilList() {
|
|||
|
|
const res = await listMaterialCoil({ enterCoilNo: this.coilInfo.enterCoilNo, pageNum: 1, pageSize: 100 });
|
|||
|
|
this.coilList = res.rows;
|
|||
|
|
},
|
|||
|
|
async getAbnormalList() {
|
|||
|
|
const res = await listCoilAbnormal({
|
|||
|
|
coilId: this.coilId
|
|||
|
|
});
|
|||
|
|
this.abmornalList = res.rows || [];
|
|||
|
|
},
|
|||
|
|
async getWarehouseTransferList() {
|
|||
|
|
const res = await getCoilWarehouseOperationLogByCoilId({
|
|||
|
|
coilId: this.coilId
|
|||
|
|
});
|
|||
|
|
this.warehouseTranferList = res.data || [];
|
|||
|
|
},
|
|||
|
|
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(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[0] || [];
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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] || {};
|
|||
|
|
return {
|
|||
|
|
...coil,
|
|||
|
|
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 || '-',
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
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 coilList = res.rows;
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
this.$message.warning('获取钢卷详情失败');
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取钢卷详情接口异常:', error);
|
|||
|
|
this.$message.error('获取钢卷详情异常,请刷新重试');
|
|||
|
|
} finally {
|
|||
|
|
this.loadingCoilDetails = false;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
getMiniStatusClass(status) {
|
|||
|
|
if (!status) return '';
|
|||
|
|
const statusLower = status.toLowerCase();
|
|||
|
|
if (statusLower.includes('合格')) return 'mini-status-success';
|
|||
|
|
if (statusLower.includes('不合格')) return 'mini-status-danger';
|
|||
|
|
if (statusLower.includes('待检')) return 'mini-status-warning';
|
|||
|
|
return 'mini-status-default';
|
|||
|
|
},
|
|||
|
|
getFuturisticStatusClass(status) {
|
|||
|
|
if (!status) return '';
|
|||
|
|
const statusLower = status.toLowerCase();
|
|||
|
|
if (statusLower.includes('合格')) return 'futuristic-status-success';
|
|||
|
|
if (statusLower.includes('不合格')) return 'futuristic-status-danger';
|
|||
|
|
if (statusLower.includes('待检')) return 'futuristic-status-warning';
|
|||
|
|
return 'futuristic-status-default';
|
|||
|
|
},
|
|||
|
|
getInboundCoil(step, index) {
|
|||
|
|
// 如果只有一个步骤,用当前步骤的newCoilInfoList
|
|||
|
|
if (this.standardSteps.length === 1) {
|
|||
|
|
return step.newCoilInfoList;
|
|||
|
|
}
|
|||
|
|
// 如果有多个步骤,用第二个步骤的oldCoilInfoList
|
|||
|
|
if (index === 0 && this.standardSteps[1]) {
|
|||
|
|
return this.standardSteps[1].oldCoilInfoList;
|
|||
|
|
}
|
|||
|
|
return step.newCoilInfoList;
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.coil-info-page {
|
|||
|
|
background: linear-gradient(135deg, #e8eef5 0%, #f5f7fa 50%, #ffffff 100%);
|
|||
|
|
min-height: 100vh;
|
|||
|
|
padding: 20px 28px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.page-header {
|
|||
|
|
margin-bottom: 24px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-title {
|
|||
|
|
font-size: 22px;
|
|||
|
|
font-weight: 700;
|
|||
|
|
color: #2c3e50;
|
|||
|
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-divider {
|
|||
|
|
height: 4px;
|
|||
|
|
width: 56px;
|
|||
|
|
background: linear-gradient(90deg, #cd7f32 0%, #ffd700 50%, #cd7f32 100%);
|
|||
|
|
border-radius: 2px;
|
|||
|
|
margin-top: 10px;
|
|||
|
|
box-shadow: 0 0 12px rgba(205, 127, 50, 0.4);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.content-container {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 20px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section {
|
|||
|
|
border: 1px solid rgba(200, 200, 200, 0.4);
|
|||
|
|
overflow: hidden;
|
|||
|
|
position: relative;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-header {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 16px 24px;
|
|||
|
|
border-bottom: 1px solid rgba(200, 200, 200, 0.5);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-icon {
|
|||
|
|
font-size: 18px;
|
|||
|
|
margin-right: 10px;
|
|||
|
|
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.15));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-title {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 700;
|
|||
|
|
color: #334155;
|
|||
|
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
|
|||
|
|
letter-spacing: 0.5px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-body {
|
|||
|
|
padding: 20px 24px;
|
|||
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0.5) 0%, rgba(248, 250, 252, 0.8) 100%);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.trace-content {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.step-item {
|
|||
|
|
background: linear-gradient(145deg, #ffffff 0%, #f8fafc 50%, #f1f5f9 100%);
|
|||
|
|
border-radius: 10px;
|
|||
|
|
padding: 18px 22px;
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
box-shadow:
|
|||
|
|
0 4px 12px rgba(0, 0, 0, 0.06),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
|||
|
|
inset 0 -1px 0 rgba(0, 0, 0, 0.03);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.step-content {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: stretch;
|
|||
|
|
gap: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-card-wrapper {
|
|||
|
|
flex: 1;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-card-header {
|
|||
|
|
padding: 8px 16px;
|
|||
|
|
background: linear-gradient(145deg, rgba(241, 245, 249, 0.9) 0%, rgba(226, 232, 240, 1) 100%);
|
|||
|
|
border-radius: 8px 8px 0 0;
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
border-bottom: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.card-label {
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: 700;
|
|||
|
|
color: #334155;
|
|||
|
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-card {
|
|||
|
|
padding: 12px;
|
|||
|
|
background: linear-gradient(145deg, #ffffff 0%, #f8fafc 50%, #f1f5f9 100%);
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
border-radius: 0 0 8px 8px;
|
|||
|
|
box-shadow:
|
|||
|
|
0 2px 8px rgba(0, 0, 0, 0.05),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.9);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.old-coil-wrapper .coil-card-header {
|
|||
|
|
background: linear-gradient(145deg, #fef3c7 0%, #fde68a 100%);
|
|||
|
|
border-color: rgba(217, 119, 6, 0.4);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.new-coil-wrapper .coil-card-header {
|
|||
|
|
background: linear-gradient(145deg, #dcfce7 0%, #bbf7d0 100%);
|
|||
|
|
border-color: rgba(22, 163, 74, 0.4);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.inbound-header {
|
|||
|
|
background: linear-gradient(145deg, #dbeafe 0%, #bfdbfe 100%) !important;
|
|||
|
|
border-color: rgba(59, 130, 246, 0.4) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.step-content-inbound {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: stretch;
|
|||
|
|
gap: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.inbound-coil-wrapper {
|
|||
|
|
flex: 1;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-arrow-inbound {
|
|||
|
|
color: #3b82f6 !important;
|
|||
|
|
font-size: 32px;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
text-shadow: 0 0 10px rgba(59, 130, 246, 0.5);
|
|||
|
|
animation: bounce-in 2s ease-in-out infinite !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@keyframes bounce-in {
|
|||
|
|
0%, 100% {
|
|||
|
|
transform: translateY(0);
|
|||
|
|
}
|
|||
|
|
50% {
|
|||
|
|
transform: translateY(-5px);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-coil {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
padding: 40px 20px;
|
|||
|
|
background: linear-gradient(145deg, #ffffff 0%, #f8fafc 50%, #f1f5f9 100%);
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
border-radius: 0 0 8px 8px;
|
|||
|
|
color: #94a3b8;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-center {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
min-width: 120px;
|
|||
|
|
padding: 16px 12px;
|
|||
|
|
background: linear-gradient(145deg, rgba(241, 245, 249, 0.9) 0%, rgba(226, 232, 240, 1) 100%);
|
|||
|
|
border-radius: 10px;
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
box-shadow:
|
|||
|
|
0 2px 8px rgba(0, 0, 0, 0.05),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.9);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-arrow {
|
|||
|
|
color: #f59e0b;
|
|||
|
|
font-size: 32px;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|||
|
|
animation: pulse 2s ease-in-out infinite;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@keyframes pulse {
|
|||
|
|
0%, 100% {
|
|||
|
|
transform: scale(1);
|
|||
|
|
}
|
|||
|
|
50% {
|
|||
|
|
transform: scale(1.1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-info {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-tag {
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-operator {
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #334155;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-time {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #64748b;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-state {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
padding: 48px 0;
|
|||
|
|
color: #64748b;
|
|||
|
|
font-size: 15px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.empty-state i {
|
|||
|
|
font-size: 56px;
|
|||
|
|
margin-bottom: 16px;
|
|||
|
|
color: #94a3b8;
|
|||
|
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-descriptions--small .el-descriptions__cell {
|
|||
|
|
padding: 12px 18px;
|
|||
|
|
background: linear-gradient(145deg, rgba(255, 255, 255, 0.6) 0%, rgba(248, 250, 252, 0.9) 100%);
|
|||
|
|
border-color: rgba(180, 180, 180, 0.4) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-descriptions__label {
|
|||
|
|
background: linear-gradient(145deg, rgba(241, 245, 249, 0.9) 0%, rgba(226, 232, 240, 1) 100%) !important;
|
|||
|
|
color: #334155 !important;
|
|||
|
|
font-weight: 600;
|
|||
|
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-descriptions__content {
|
|||
|
|
color: #1e293b !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-table {
|
|||
|
|
background: transparent !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-table th,
|
|||
|
|
::v-deep .el-table td {
|
|||
|
|
padding: 12px 0;
|
|||
|
|
background: transparent !important;
|
|||
|
|
border-color: rgba(180, 180, 180, 0.4) !important;
|
|||
|
|
color: #1e293b !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-table th {
|
|||
|
|
background: linear-gradient(180deg, rgba(241, 245, 249, 0.95) 0%, rgba(226, 232, 240, 1) 100%) !important;
|
|||
|
|
color: #0f172a !important;
|
|||
|
|
font-weight: 700;
|
|||
|
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-table--striped .el-table__body tr.el-table__row--striped td {
|
|||
|
|
background: rgba(248, 250, 252, 0.6) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-table--border,
|
|||
|
|
::v-deep .el-table--group {
|
|||
|
|
border-color: rgba(180, 180, 180, 0.5) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
::v-deep .el-tag {
|
|||
|
|
background: linear-gradient(145deg, #f1f5f9 0%, #e2e8f0 100%) !important;
|
|||
|
|
border: 1px solid #cbd5e1 !important;
|
|||
|
|
color: #334155 !important;
|
|||
|
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* CoilInfo组件样式优化 */
|
|||
|
|
.coil-card ::v-deep .el-descriptions--small .el-descriptions__cell {
|
|||
|
|
padding: 8px 10px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-card ::v-deep .el-descriptions__label {
|
|||
|
|
background: linear-gradient(145deg, rgba(241, 245, 249, 0.9) 0%, rgba(226, 232, 240, 1) 100%) !important;
|
|||
|
|
color: #475569 !important;
|
|||
|
|
font-weight: 600;
|
|||
|
|
font-size: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-card ::v-deep .el-descriptions__content {
|
|||
|
|
color: #1e293b !important;
|
|||
|
|
font-size: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 炫酷版钢卷卡片样式 */
|
|||
|
|
.coil-card-futuristic {
|
|||
|
|
padding: 10px;
|
|||
|
|
background: linear-gradient(145deg, #ffffff 0%, #f8f9ff 50%, #f0f4ff 100%);
|
|||
|
|
border: 1px solid rgba(100, 100, 255, 0.2);
|
|||
|
|
border-radius: 0 0 10px 10px;
|
|||
|
|
box-shadow:
|
|||
|
|
0 4px 16px rgba(0, 0, 0, 0.1),
|
|||
|
|
0 0 30px rgba(100, 100, 255, 0.08),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.8);
|
|||
|
|
position: relative;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 发光边框效果 */
|
|||
|
|
.coil-card-futuristic::before {
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
top: -50%;
|
|||
|
|
left: -50%;
|
|||
|
|
width: 200%;
|
|||
|
|
height: 200%;
|
|||
|
|
background: radial-gradient(circle, rgba(100, 100, 255, 0.05) 0%, transparent 70%);
|
|||
|
|
animation: rotateGlow 8s linear infinite;
|
|||
|
|
pointer-events: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@keyframes rotateGlow {
|
|||
|
|
0% { transform: rotate(0deg); }
|
|||
|
|
100% { transform: rotate(360deg); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-futuristic-header {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
position: relative;
|
|||
|
|
z-index: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-futuristic-no {
|
|||
|
|
font-size: 18px;
|
|||
|
|
font-weight: 700;
|
|||
|
|
color: #1e293b;
|
|||
|
|
text-shadow: 0 0 10px rgba(100, 100, 255, 0.3);
|
|||
|
|
letter-spacing: 0.5px;
|
|||
|
|
font-family: 'Courier New', monospace;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-futuristic-weight {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #d97706;
|
|||
|
|
padding: 5px 14px;
|
|||
|
|
background: linear-gradient(145deg, rgba(255, 215, 0, 0.15) 0%, rgba(255, 165, 0, 0.2) 100%);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
border: 1px solid rgba(217, 119, 6, 0.3);
|
|||
|
|
text-shadow: 0 0 6px rgba(255, 215, 0, 0.4);
|
|||
|
|
box-shadow: 0 0 12px rgba(255, 215, 0, 0.15);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-futuristic-body {
|
|||
|
|
position: relative;
|
|||
|
|
height: 220px;
|
|||
|
|
margin-bottom: 10px;
|
|||
|
|
z-index: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* SVG钢卷图标容器 */
|
|||
|
|
.coil-icon-container {
|
|||
|
|
position: absolute;
|
|||
|
|
top: 50%;
|
|||
|
|
left: 50%;
|
|||
|
|
transform: translate(-50%, -50%);
|
|||
|
|
width: 100px;
|
|||
|
|
height: 100px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-svg {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
filter: drop-shadow(0 0 10px rgba(99, 102, 241, 0.25));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 属性标签容器 */
|
|||
|
|
.coil-attr-tags {
|
|||
|
|
position: absolute;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
pointer-events: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 通用属性标签样式 */
|
|||
|
|
.attr-tag {
|
|||
|
|
position: absolute;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
pointer-events: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-content {
|
|||
|
|
background: linear-gradient(145deg, rgba(255, 255, 255, 0.95) 0%, rgba(248, 249, 255, 0.98) 100%);
|
|||
|
|
border: 1px solid rgba(100, 100, 255, 0.25);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 6px 10px;
|
|||
|
|
backdrop-filter: blur(6px);
|
|||
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
|||
|
|
min-width: 80px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-label {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 11px;
|
|||
|
|
color: #6366f1;
|
|||
|
|
text-transform: uppercase;
|
|||
|
|
letter-spacing: 0.6px;
|
|||
|
|
margin-bottom: 2px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-value {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 13px;
|
|||
|
|
color: #1e293b;
|
|||
|
|
font-weight: 600;
|
|||
|
|
word-break: break-all;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 属性连接线 */
|
|||
|
|
.attr-line {
|
|||
|
|
position: absolute;
|
|||
|
|
background: linear-gradient(90deg, transparent, rgba(100, 100, 255, 0.8));
|
|||
|
|
animation: linePulse 2s ease-in-out infinite;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@keyframes linePulse {
|
|||
|
|
0%, 100% { opacity: 0.5; }
|
|||
|
|
50% { opacity: 1; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 顶部属性标签 */
|
|||
|
|
.attr-top {
|
|||
|
|
top: 0;
|
|||
|
|
left: 50%;
|
|||
|
|
transform: translateX(-50%);
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-top .attr-line-top {
|
|||
|
|
width: 2px;
|
|||
|
|
height: 20px;
|
|||
|
|
background: linear-gradient(180deg, transparent, rgba(100, 100, 255, 0.7));
|
|||
|
|
margin-bottom: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-top .attr-content {
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 右侧属性标签 */
|
|||
|
|
.attr-right {
|
|||
|
|
right: 0;
|
|||
|
|
top: 50%;
|
|||
|
|
transform: translateY(-50%);
|
|||
|
|
flex-direction: row-reverse;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-right .attr-line-right {
|
|||
|
|
width: 20px;
|
|||
|
|
height: 2px;
|
|||
|
|
background: linear-gradient(90deg, rgba(100, 100, 255, 0.7), transparent);
|
|||
|
|
margin-left: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 底部属性标签 */
|
|||
|
|
.attr-bottom {
|
|||
|
|
bottom: 0;
|
|||
|
|
left: 50%;
|
|||
|
|
transform: translateX(-50%);
|
|||
|
|
flex-direction: column-reverse;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-bottom .attr-line-bottom {
|
|||
|
|
width: 2px;
|
|||
|
|
height: 20px;
|
|||
|
|
background: linear-gradient(0deg, transparent, rgba(100, 100, 255, 0.7));
|
|||
|
|
margin-top: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-bottom .attr-content {
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 左侧属性标签 */
|
|||
|
|
.attr-left {
|
|||
|
|
left: 0;
|
|||
|
|
top: 50%;
|
|||
|
|
transform: translateY(-50%);
|
|||
|
|
flex-direction: row;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-left .attr-line-left {
|
|||
|
|
width: 20px;
|
|||
|
|
height: 2px;
|
|||
|
|
background: linear-gradient(270deg, rgba(100, 100, 255, 0.7), transparent);
|
|||
|
|
margin-right: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 左上角标签 */
|
|||
|
|
.attr-top-left {
|
|||
|
|
position: absolute;
|
|||
|
|
top: 8px;
|
|||
|
|
left: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 右上角标签 */
|
|||
|
|
.attr-top-right {
|
|||
|
|
position: absolute;
|
|||
|
|
top: 8px;
|
|||
|
|
right: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 左下角标签 */
|
|||
|
|
.attr-bottom-left {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 8px;
|
|||
|
|
left: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 右下角标签 */
|
|||
|
|
.attr-bottom-right {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 8px;
|
|||
|
|
right: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 小尺寸标签样式 */
|
|||
|
|
.attr-content-small {
|
|||
|
|
background: linear-gradient(145deg, rgba(255, 255, 255, 0.95) 0%, rgba(248, 249, 255, 0.98) 100%);
|
|||
|
|
border: 1px solid rgba(100, 100, 255, 0.25);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 5px 8px;
|
|||
|
|
backdrop-filter: blur(6px);
|
|||
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|||
|
|
min-width: 70px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-content-small .attr-label {
|
|||
|
|
font-size: 10px;
|
|||
|
|
letter-spacing: 0.5px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-content-small .attr-value {
|
|||
|
|
font-size: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 备注标签 */
|
|||
|
|
.attr-remark {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: -5px;
|
|||
|
|
left: 50%;
|
|||
|
|
transform: translateX(-50%);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-content-remark {
|
|||
|
|
background: linear-gradient(145deg, rgba(255, 255, 255, 0.98) 0%, rgba(248, 249, 255, 1) 100%);
|
|||
|
|
border: 1px solid rgba(100, 100, 255, 0.3);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 6px 10px;
|
|||
|
|
backdrop-filter: blur(6px);
|
|||
|
|
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
|
|||
|
|
max-width: 180px;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.attr-content-remark .attr-value {
|
|||
|
|
word-break: break-word;
|
|||
|
|
font-size: 12px;
|
|||
|
|
line-height: 1.4;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 状态标签颜色 */
|
|||
|
|
.futuristic-status-success {
|
|||
|
|
color: #22c55e !important;
|
|||
|
|
text-shadow: 0 0 8px rgba(34, 197, 94, 0.4) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.futuristic-status-danger {
|
|||
|
|
color: #ef4444 !important;
|
|||
|
|
text-shadow: 0 0 8px rgba(239, 68, 68, 0.4) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.futuristic-status-warning {
|
|||
|
|
color: #f59e0b !important;
|
|||
|
|
text-shadow: 0 0 8px rgba(245, 158, 11, 0.4) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.futuristic-status-default {
|
|||
|
|
color: #64748b !important;
|
|||
|
|
text-shadow: 0 0 8px rgba(100, 116, 139, 0.3) !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 底部信息 */
|
|||
|
|
.coil-futuristic-footer {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-around;
|
|||
|
|
padding-top: 10px;
|
|||
|
|
border-top: 1px solid rgba(100, 100, 255, 0.15);
|
|||
|
|
position: relative;
|
|||
|
|
z-index: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.footer-item {
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.footer-label {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 11px;
|
|||
|
|
color: #64748b;
|
|||
|
|
text-transform: uppercase;
|
|||
|
|
letter-spacing: 0.6px;
|
|||
|
|
margin-bottom: 3px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.footer-value {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 13px;
|
|||
|
|
color: #475569;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 简化版钢卷卡片样式(保留用于其他地方使用)
|
|||
|
|
.coil-card-mini {
|
|||
|
|
padding: 16px;
|
|||
|
|
background: linear-gradient(145deg, #ffffff 0%, #f8fafc 50%, #f1f5f9 100%);
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
border-radius: 0 0 8px 8px;
|
|||
|
|
box-shadow:
|
|||
|
|
0 2px 8px rgba(0, 0, 0, 0.05),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.9);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-mini-main {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-mini-no {
|
|||
|
|
font-size: 18px;
|
|||
|
|
font-weight: 700;
|
|||
|
|
color: #1e293b;
|
|||
|
|
letter-spacing: 0.5px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-mini-weight {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #f59e0b;
|
|||
|
|
padding: 4px 12px;
|
|||
|
|
background: linear-gradient(145deg, #fef3c7 0%, #fde68a 100%);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-mini-sub {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 8px;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-mini-item {
|
|||
|
|
font-size: 13px;
|
|||
|
|
color: #64748b;
|
|||
|
|
line-height: 1.4;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.coil-mini-status {
|
|||
|
|
padding-top: 12px;
|
|||
|
|
border-top: 1px dashed rgba(180, 180, 180, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mini-status-success {
|
|||
|
|
display: inline-block;
|
|||
|
|
padding: 4px 12px;
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #22c55e;
|
|||
|
|
background: linear-gradient(145deg, #dcfce7 0%, #bbf7d0 100%);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mini-status-danger {
|
|||
|
|
display: inline-block;
|
|||
|
|
padding: 4px 12px;
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #ef4444;
|
|||
|
|
background: linear-gradient(145deg, #fee2e2 0%, #fecaca 100%);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mini-status-warning {
|
|||
|
|
display: inline-block;
|
|||
|
|
padding: 4px 12px;
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #f59e0b;
|
|||
|
|
background: linear-gradient(145deg, #fef3c7 0%, #fde68a 100%);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mini-status-default {
|
|||
|
|
display: inline-block;
|
|||
|
|
padding: 4px 12px;
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #64748b;
|
|||
|
|
background: linear-gradient(145deg, #f1f5f9 0%, #e2e8f0 100%);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 表格行布局 */
|
|||
|
|
.tables-row {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 20px;
|
|||
|
|
min-height: 400px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-wrapper {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-wrapper.warehouse-table {
|
|||
|
|
flex: 3;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-wrapper.transfer-table {
|
|||
|
|
flex: 2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-title {
|
|||
|
|
padding: 8px 16px;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
background: linear-gradient(145deg, rgba(241, 245, 249, 0.9) 0%, rgba(226, 232, 240, 1) 100%);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: 700;
|
|||
|
|
color: #334155;
|
|||
|
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-container {
|
|||
|
|
flex: 1;
|
|||
|
|
overflow: hidden;
|
|||
|
|
background: linear-gradient(145deg, #ffffff 0%, #f8fafc 50%, #f1f5f9 100%);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
border: 1px solid rgba(180, 180, 180, 0.4);
|
|||
|
|
box-shadow:
|
|||
|
|
0 2px 8px rgba(0, 0, 0, 0.05),
|
|||
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.9);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 确保表格高度一致 */
|
|||
|
|
.table-container ::v-deep .el-table {
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-container ::v-deep .el-table__body-wrapper {
|
|||
|
|
flex: 1;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
}
|
|||
|
|
</style>
|