refactor(material): 扁平布局 + 修复 SVG 总图 + 彻底消除横向溢出

- SVG: viewBox 改回正向坐标 (0,0,1900,310),所有 y 整体下移 30,
  段位色带在顶部 4-26 区,避免负坐标渲染异常导致设备图形丢失
- 布局: 去掉所有 sub-card 嵌套,扁平为 sec-title-bar + pane(kpi-row auto-fit)
- 酸洗/清洗各槽改为 tank-card 自适应排列;所有表格包 tbl-scroll 防止溢出
- 出口段抛弃表格,改 KPI 网格统一处理三辊 VFD + 平整 + 收卷
- 段位色带 + 标题左边框 + sec-pill 一致着色

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 14:15:49 +08:00
parent 00c8615f29
commit 86b2f277e1

View File

@@ -36,30 +36,30 @@
<div class="line-wrap card">
<div class="card-header">推拉酸洗线 - 物料跟踪总图</div>
<div class="line-body">
<svg viewBox="0 -32 1900 312" preserveAspectRatio="xMidYMid meet" class="line-svg">
<rect x="0" y="-32" width="1900" height="312" fill="#0a1218" />
<svg viewBox="0 0 1900 310" preserveAspectRatio="xMidYMid meet" class="line-svg">
<rect x="0" y="0" width="1900" height="310" fill="#0a1218" />
<!-- 段位标签带 -->
<g v-for="s in sections" :key="'sec-'+s.name">
<rect :x="s.bandX" y="-28" :width="s.bandW" height="22" :fill="s.color" opacity="0.18" rx="3"/>
<rect :x="s.bandX" y="-28" :width="s.bandW" height="22" fill="none" :stroke="s.color" stroke-width="1" opacity="0.7" rx="3"/>
<text :x="s.labelX" y="-13" text-anchor="middle" font-size="12" font-weight="bold" :fill="s.color"
<rect :x="s.bandX" y="4" :width="s.bandW" height="22" :fill="s.color" opacity="0.18" rx="3"/>
<rect :x="s.bandX" y="4" :width="s.bandW" height="22" fill="none" :stroke="s.color" stroke-width="1" opacity="0.7" rx="3"/>
<text :x="s.labelX" y="19" text-anchor="middle" font-size="12" font-weight="bold" :fill="s.color"
font-family="Arial,sans-serif">{{ s.name }}</text>
</g>
<!-- 顶部标签 -->
<!-- 顶部设备标签 -->
<g v-for="eq in equipments" :key="'lab-'+eq.k" font-family="Arial,sans-serif">
<text :x="eq.x" y="20" text-anchor="middle" font-size="10.5" fill="#c8d4e0">{{ eq.label }}</text>
<text :x="eq.x" y="44" text-anchor="middle" font-size="10.5" fill="#c8d4e0">{{ eq.label }}</text>
</g>
<!-- 主带钢线 -->
<path d="M 40 160 L 1860 160" stroke="#5a6a75" stroke-width="3" fill="none"/>
<path d="M 40 160 L 1860 160" stroke="#aabbcc" stroke-width="1.2" fill="none" stroke-dasharray="6 10">
<path d="M 40 190 L 1860 190" stroke="#5a6a75" stroke-width="3" fill="none"/>
<path d="M 40 190 L 1860 190" stroke="#aabbcc" stroke-width="1.2" fill="none" stroke-dasharray="6 10">
<animate attributeName="stroke-dashoffset" from="16" to="0" dur="0.7s" repeatCount="indefinite"/>
</path>
<!-- 各设备图形 -->
<g v-for="eq in equipments" :key="eq.k" :transform="`translate(${eq.x}, 160)`">
<g v-for="eq in equipments" :key="eq.k" :transform="`translate(${eq.x}, 190)`">
<!-- 开卷机 -->
<template v-if="eq.type==='coiler'">
<circle r="38" fill="#1a232c" stroke="#3a4a55" stroke-width="2"/>
@@ -213,7 +213,7 @@
</g>
<!-- 焊缝标记 -->
<g :transform="`translate(${weldX}, 160)`">
<g :transform="`translate(${weldX}, 190)`">
<circle r="11" fill="#ffdd00" opacity="0.35">
<animate attributeName="r" values="9;22;9" dur="1.0s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.7;0.05;0.7" dur="1.0s" repeatCount="indefinite"/>
@@ -225,7 +225,7 @@
</g>
<!-- 图例 -->
<g transform="translate(20,260)" font-size="10" fill="#8b949e">
<g transform="translate(20,295)" font-size="10" fill="#8b949e">
<circle cx="6" cy="-3" r="5" fill="#ffee44"/>
<text x="18" y="0">焊缝位置 {{ (weld.position * 100).toFixed(1) }}%</text>
<rect x="160" y="-7" width="12" height="8" fill="#ffaa44" opacity="0.5"/>
@@ -242,52 +242,39 @@
<!-- 入口段 -->
<section class="sec">
<div class="sec-title-bar">入口段
<span class="ch-badge">在线 {{ onlinePlans.length }} / 生产中 {{ producingPlan ? 1 : 0 }}</span>
<div class="sec-title-bar" :style="{ borderLeftColor: sectionColor('入口段') }">
<span class="sec-pill" :style="{ background: sectionColor('入口段') }">入口段</span>
在线 {{ onlinePlans.length }} / 生产中 {{ producingPlan ? 1 : 0 }}
</div>
<div class="pane">
<div class="pane-grid entry-grid">
<!-- 在线计划 + 移动按钮 -->
<div class="sub-card">
<div class="sub-header">在线计划 · 入口移动
<span class="ch-badge">在线 {{ onlinePlans.length }} / 生产中 {{ producingPlan ? 1 : 0 }}</span>
</div>
<div class="sub-body">
<div v-if="producingPlan" class="producing-row">
<span class="badge badge-yellow">生产中</span>
<span class="kv-label">冷卷号</span><span class="kv-value">{{ producingPlan.cold_coil_no || producingPlan.plan_no }}</span>
<span class="kv-label">钢种</span><span class="kv-value">{{ producingPlan.steel_grade || '—' }}</span>
<span class="kv-label">规格</span><span class="kv-value">{{ fmt(producingPlan.product_thickness) }}×{{ fmt(producingPlan.product_width, 0) }}</span>
</div>
<table class="data-table compact" v-if="onlinePlans.length">
<thead><tr><th>冷卷号</th><th>钢种</th><th>厚度</th><th>宽度</th><th>分卷</th><th>操作</th></tr></thead>
<tbody>
<tr v-for="p in onlinePlans" :key="p.id">
<td class="td-num">{{ p.cold_coil_no || p.plan_no }}</td>
<td>{{ p.steel_grade || '—' }}</td>
<td class="td-num">{{ fmt(p.product_thickness) }}</td>
<td class="td-num">{{ fmt(p.product_width, 0) }}</td>
<td class="td-num">{{ p.split_count || 1 }}</td>
<td>
<button class="btn btn-primary btn-sm" :disabled="moving" @click="movePlan(p)">移动 </button>
</td>
</tr>
</tbody>
</table>
<div v-else-if="!producingPlan" class="td-muted empty-row">暂无在线计划</div>
</div>
</div>
<!-- 入口段实时参数 -->
<div class="sub-card">
<div class="sub-header">入口段实时参数</div>
<div class="sub-body">
<div class="kpi-grid">
<div v-for="it in entryItems" :key="it.k" class="kpi">
<div class="kpi-label">{{ it.label }}</div>
<div class="kpi-value">{{ it.val }}<span class="kpi-unit" v-if="it.unit">{{ it.unit }}</span></div>
</div>
</div>
</div>
<!-- 在线计划 / 移动 -->
<div v-if="producingPlan" class="producing-row">
<span class="badge badge-yellow">生产中</span>
<span class="kv-label">冷卷号</span><span class="kv-value">{{ producingPlan.cold_coil_no || producingPlan.plan_no }}</span>
<span class="kv-label">钢种</span><span class="kv-value">{{ producingPlan.steel_grade || '—' }}</span>
<span class="kv-label">规格</span><span class="kv-value">{{ fmt(producingPlan.product_thickness) }}×{{ fmt(producingPlan.product_width, 0) }}</span>
</div>
<div class="tbl-scroll">
<table class="data-table compact" v-if="onlinePlans.length">
<thead><tr><th>冷卷号</th><th>钢种</th><th>厚度</th><th>宽度</th><th>分卷</th><th style="width:90px;">移动</th></tr></thead>
<tbody>
<tr v-for="p in onlinePlans" :key="p.id">
<td class="td-num">{{ p.cold_coil_no || p.plan_no }}</td>
<td>{{ p.steel_grade || '—' }}</td>
<td class="td-num">{{ fmt(p.product_thickness) }}</td>
<td class="td-num">{{ fmt(p.product_width, 0) }}</td>
<td class="td-num">{{ p.split_count || 1 }}</td>
<td><button class="btn btn-primary btn-sm" :disabled="moving" @click="movePlan(p)">移动 </button></td>
</tr>
</tbody>
</table>
<div v-else-if="!producingPlan" class="td-muted empty-row">暂无在线计划</div>
</div>
<!-- 入口实时参数 -->
<div class="kpi-row">
<div v-for="it in entryItems" :key="it.k" class="kpi">
<div class="kpi-label">{{ it.label }}</div>
<div class="kpi-value">{{ it.val }}<span class="kpi-unit" v-if="it.unit">{{ it.unit }}</span></div>
</div>
</div>
</div>
@@ -295,154 +282,139 @@
<!-- 酸洗段 -->
<section class="sec">
<div class="sec-title-bar">酸洗段5 </div>
<div class="sec-title-bar" :style="{ borderLeftColor: sectionColor('酸洗段') }">
<span class="sec-pill" :style="{ background: sectionColor('酸洗段') }">酸洗段</span>
5 槽串联
</div>
<div class="pane">
<div class="tank-grid">
<div v-for="(a, i) in acid" :key="'a'+i" class="sub-card">
<div class="sub-header acid">{{ i+1 }}# 酸洗槽</div>
<div class="sub-body">
<div class="kpi-grid two">
<div class="kpi"><div class="kpi-label">槽温度</div><div class="kpi-value">{{ fix(a.temp,1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">罐液位</div><div class="kpi-value">{{ fix(a.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">浓度</div><div class="kpi-value">{{ fix(a.conc,1) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">槽电导率</div><div class="kpi-value">{{ fix(a.cond,1) }}<span class="kpi-unit">mS/cm</span></div></div>
<div class="kpi"><div class="kpi-label">浓度</div><div class="kpi-value">{{ fix(a.tank_conc,1) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">罐电导率</div><div class="kpi-value">{{ fix(a.tank_cond,1) }}<span class="kpi-unit">mS/cm</span></div></div>
</div>
</div>
</div>
<div class="sub-card">
<div class="sub-header">酸雾塔 + 冷凝水罐</div>
<div class="sub-body">
<div class="kpi-grid two">
<div class="kpi"><div class="kpi-label">酸雾塔 PH</div><div class="kpi-value">{{ fix(acid_mist.ph,2) }}</div></div>
<div class="kpi"><div class="kpi-label">变频器频率</div><div class="kpi-value">{{ fix(acid_mist.vfd_speed,1) }}<span class="kpi-unit">Hz</span></div></div>
<div class="kpi"><div class="kpi-label">变频器电流</div><div class="kpi-value">{{ fix(acid_mist.vfd_current,1) }}<span class="kpi-unit">A</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝罐液位</div><div class="kpi-value">{{ fix(acid_cond.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝罐温度</div><div class="kpi-value">{{ fix(acid_cond.temp,1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝电导率</div><div class="kpi-value">{{ fix(acid_cond.cond,1) }}<span class="kpi-unit">μS/cm</span></div></div>
</div>
<div class="tank-row">
<div v-for="(a, i) in acid" :key="'a'+i" class="tank-card">
<div class="tank-title" :style="{ color: sectionColor('酸洗段') }">{{ i+1 }}# 酸洗槽</div>
<div class="kpi-row two">
<div class="kpi"><div class="kpi-label">槽温度</div><div class="kpi-value">{{ fix(a.temp,1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">罐液位</div><div class="kpi-value">{{ fix(a.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">槽浓度</div><div class="kpi-value">{{ fix(a.conc,1) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">电导率</div><div class="kpi-value">{{ fix(a.cond,1) }}<span class="kpi-unit">mS/cm</span></div></div>
<div class="kpi"><div class="kpi-label">罐浓度</div><div class="kpi-value">{{ fix(a.tank_conc,1) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">电导率</div><div class="kpi-value">{{ fix(a.tank_cond,1) }}<span class="kpi-unit">mS/cm</span></div></div>
</div>
</div>
</div>
<div class="kpi-row tight">
<div class="kpi"><div class="kpi-label">酸雾塔 PH</div><div class="kpi-value">{{ fix(acid_mist.ph,2) }}</div></div>
<div class="kpi"><div class="kpi-label">雾塔变频频率</div><div class="kpi-value">{{ fix(acid_mist.vfd_speed,1) }}<span class="kpi-unit">Hz</span></div></div>
<div class="kpi"><div class="kpi-label">雾塔变频电流</div><div class="kpi-value">{{ fix(acid_mist.vfd_current,1) }}<span class="kpi-unit">A</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝罐液位</div><div class="kpi-value">{{ fix(acid_cond.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝罐温度</div><div class="kpi-value">{{ fix(acid_cond.temp,1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝电导率</div><div class="kpi-value">{{ fix(acid_cond.cond,1) }}<span class="kpi-unit">μS/cm</span></div></div>
</div>
</div>
</section>
<!-- 漂洗 -->
<!-- 清洗段 + 烘干 -->
<section class="sec">
<div class="sec-title-bar">漂洗段5 + 烘干</div>
<div class="sec-title-bar" :style="{ borderLeftColor: sectionColor('清洗段') }">
<span class="sec-pill" :style="{ background: sectionColor('清洗段') }">清洗段</span>
<span class="sec-pill" :style="{ background: sectionColor('烘干段') }">烘干段</span>
5 级逆流 + 3 段热风
</div>
<div class="pane">
<div class="tank-grid">
<div v-for="(r, i) in rinse" :key="'r'+i" class="sub-card">
<div class="sub-header rinse">{{ i+1 }}# 漂洗</div>
<div class="sub-body">
<div class="kpi-grid two">
<div class="kpi"><div class="kpi-label">槽温度</div><div class="kpi-value">{{ fix(rinse_tank_temp[i],1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">罐液位</div><div class="kpi-value">{{ fix(r.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">浓度</div><div class="kpi-value">{{ fix(r.conc,2) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">槽电导率</div><div class="kpi-value">{{ fix(r.cond,2) }}<span class="kpi-unit">μS/cm</span></div></div>
<div class="kpi"><div class="kpi-label">浓度</div><div class="kpi-value">{{ fix(r.tank_conc,2) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">罐电导率</div><div class="kpi-value">{{ fix(r.tank_cond,2) }}<span class="kpi-unit">μS/cm</span></div></div>
</div>
</div>
</div>
<div class="sub-card">
<div class="sub-header">漂洗酸雾塔 + 冷凝罐 + 烘干</div>
<div class="sub-body">
<div class="kpi-grid two">
<div class="kpi"><div class="kpi-label">雾塔 PH</div><div class="kpi-value">{{ fix(rinse_mist.ph,2) }}</div></div>
<div class="kpi"><div class="kpi-label">变频器频率</div><div class="kpi-value">{{ fix(rinse_mist.vfd_speed,1) }}<span class="kpi-unit">Hz</span></div></div>
<div class="kpi"><div class="kpi-label">变频器电流</div><div class="kpi-value">{{ fix(rinse_mist.vfd_current,1) }}<span class="kpi-unit">A</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝液位</div><div class="kpi-value">{{ fix(rinse_cond.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝温度</div><div class="kpi-value">{{ fix(rinse_cond.temp,1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝电导率</div><div class="kpi-value">{{ fix(rinse_cond.cond,2) }}<span class="kpi-unit">μS/cm</span></div></div>
<div class="kpi"><div class="kpi-label">烘干 1 </div><div class="kpi-value">{{ fix(dryer.t1,0) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">烘干 2 </div><div class="kpi-value">{{ fix(dryer.t2,0) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">烘干 3 </div><div class="kpi-value">{{ fix(dryer.t3,0) }}<span class="kpi-unit">°C</span></div></div>
</div>
<div class="tank-row">
<div v-for="(r, i) in rinse" :key="'r'+i" class="tank-card">
<div class="tank-title" :style="{ color: sectionColor('清洗段') }">{{ i+1 }}# 漂洗</div>
<div class="kpi-row two">
<div class="kpi"><div class="kpi-label">槽温度</div><div class="kpi-value">{{ fix(rinse_tank_temp[i],1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">罐液位</div><div class="kpi-value">{{ fix(r.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">槽浓度</div><div class="kpi-value">{{ fix(r.conc,2) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">电导率</div><div class="kpi-value">{{ fix(r.cond,2) }}<span class="kpi-unit">μS/cm</span></div></div>
<div class="kpi"><div class="kpi-label">罐浓度</div><div class="kpi-value">{{ fix(r.tank_conc,2) }}<span class="kpi-unit">g/L</span></div></div>
<div class="kpi"><div class="kpi-label">电导率</div><div class="kpi-value">{{ fix(r.tank_cond,2) }}<span class="kpi-unit">μS/cm</span></div></div>
</div>
</div>
</div>
<div class="kpi-row tight">
<div class="kpi"><div class="kpi-label">漂洗雾塔 PH</div><div class="kpi-value">{{ fix(rinse_mist.ph,2) }}</div></div>
<div class="kpi"><div class="kpi-label">雾塔变频频率</div><div class="kpi-value">{{ fix(rinse_mist.vfd_speed,1) }}<span class="kpi-unit">Hz</span></div></div>
<div class="kpi"><div class="kpi-label">雾塔变频电流</div><div class="kpi-value">{{ fix(rinse_mist.vfd_current,1) }}<span class="kpi-unit">A</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝液位</div><div class="kpi-value">{{ fix(rinse_cond.level,2) }}<span class="kpi-unit">m</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝温度</div><div class="kpi-value">{{ fix(rinse_cond.temp,1) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label">冷凝电导率</div><div class="kpi-value">{{ fix(rinse_cond.cond,2) }}<span class="kpi-unit">μS/cm</span></div></div>
<div class="kpi"><div class="kpi-label" :style="{ color: sectionColor('烘干段') }">烘干 1 </div><div class="kpi-value">{{ fix(dryer.t1,0) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label" :style="{ color: sectionColor('烘干段') }">烘干 2 </div><div class="kpi-value">{{ fix(dryer.t2,0) }}<span class="kpi-unit">°C</span></div></div>
<div class="kpi"><div class="kpi-label" :style="{ color: sectionColor('烘干段') }">烘干 3 </div><div class="kpi-value">{{ fix(dryer.t3,0) }}<span class="kpi-unit">°C</span></div></div>
</div>
</div>
</section>
<!-- 出口段 -->
<section class="sec">
<div class="sec-title-bar">出口段</div>
<div class="sec-title-bar" :style="{ borderLeftColor: sectionColor('出口段') }">
<span class="sec-pill" :style="{ background: sectionColor('出口段') }">出口段</span>
三辊张力 + 平整 + 涂油 + 收卷
</div>
<div class="pane">
<div class="pane-grid two">
<div class="sub-card">
<div class="sub-header">三辊张力装置</div>
<div class="sub-body">
<table class="data-table compact">
<thead><tr><th>变频器</th><th>速度 m/min</th><th>电流 A</th><th>扭矩 kN·m</th></tr></thead>
<tbody>
<tr v-for="(v, i) in tension_vfd" :key="i">
<td>VFD-{{ i+1 }}</td>
<td class="td-num">{{ fix(v.speed,1) }}</td>
<td class="td-num">{{ fix(v.current,0) }}</td>
<td class="td-num">{{ fix(v.torque,2) }}</td>
</tr>
</tbody>
</table>
</div>
<div class="kpi-row">
<div v-for="(v, i) in tension_vfd" :key="'vfd'+i" class="kpi">
<div class="kpi-label">三辊 VFD-{{ i+1 }} 速度</div>
<div class="kpi-value">{{ fix(v.speed,1) }}<span class="kpi-unit">m/min</span></div>
</div>
<div class="sub-card">
<div class="sub-header">平整 + 涂油 + 收卷</div>
<div class="sub-body">
<div class="kpi-grid two">
<div class="kpi"><div class="kpi-label">平整辊缝</div><div class="kpi-value">{{ fix(leveler.gap,2) }}<span class="kpi-unit">mm</span></div></div>
<div class="kpi"><div class="kpi-label">轧制力</div><div class="kpi-value">{{ fix(leveler.force,0) }}<span class="kpi-unit">kN</span></div></div>
<div class="kpi"><div class="kpi-label">延伸率</div><div class="kpi-value">{{ fix(leveler.elongation,2) }}<span class="kpi-unit">%</span></div></div>
<div class="kpi"><div class="kpi-label">收卷张力</div><div class="kpi-value">{{ fix(recoiler.tension,1) }}<span class="kpi-unit">kN</span></div></div>
<div class="kpi"><div class="kpi-label">收卷直径</div><div class="kpi-value">{{ fix(recoiler.diameter,0) }}<span class="kpi-unit">mm</span></div></div>
<div class="kpi"><div class="kpi-label">收卷速度</div><div class="kpi-value">{{ fix(recoiler.speed,1) }}<span class="kpi-unit">m/min</span></div></div>
</div>
</div>
<div v-for="(v, i) in tension_vfd" :key="'vfdc'+i" class="kpi">
<div class="kpi-label">三辊 VFD-{{ i+1 }} 电流</div>
<div class="kpi-value">{{ fix(v.current,0) }}<span class="kpi-unit">A</span></div>
</div>
<div v-for="(v, i) in tension_vfd" :key="'vfdq'+i" class="kpi">
<div class="kpi-label">三辊 VFD-{{ i+1 }} 扭矩</div>
<div class="kpi-value">{{ fix(v.torque,2) }}<span class="kpi-unit">kN·m</span></div>
</div>
<div class="kpi"><div class="kpi-label">平整辊缝</div><div class="kpi-value">{{ fix(leveler.gap,2) }}<span class="kpi-unit">mm</span></div></div>
<div class="kpi"><div class="kpi-label">平整轧制力</div><div class="kpi-value">{{ fix(leveler.force,0) }}<span class="kpi-unit">kN</span></div></div>
<div class="kpi"><div class="kpi-label">平整延伸率</div><div class="kpi-value">{{ fix(leveler.elongation,2) }}<span class="kpi-unit">%</span></div></div>
<div class="kpi"><div class="kpi-label">收卷张力</div><div class="kpi-value">{{ fix(recoiler.tension,1) }}<span class="kpi-unit">kN</span></div></div>
<div class="kpi"><div class="kpi-label">收卷直径</div><div class="kpi-value">{{ fix(recoiler.diameter,0) }}<span class="kpi-unit">mm</span></div></div>
<div class="kpi"><div class="kpi-label">收卷速度</div><div class="kpi-value">{{ fix(recoiler.speed,1) }}<span class="kpi-unit">m/min</span></div></div>
</div>
</div>
</section>
<!-- 跟踪表 -->
<section class="sec">
<div class="sec-title-bar">物料跟踪表 <span class="hd-cnt">{{ equipments.length }} 台设备</span></div>
<div class="sec-title-bar"><span class="sec-pill" style="background:#5a6a78;">物料跟踪表</span> {{ equipments.length }} 台设备</div>
<div class="pane">
<table class="data-table compact tracking-table">
<thead>
<tr>
<th style="width:32px;">#</th>
<th style="width:72px;"></th>
<th>设备</th>
<th style="width:64px;">状态</th>
<th>当前钢卷</th>
<th style="width:80px;">辊缝 mm</th>
<th style="width:78px;">速度</th>
<th style="width:80px;">张力/</th>
</tr>
</thead>
<tbody>
<tr v-for="(eq, i) in equipments" :key="eq.k"
:class="{ 'row-active': eq.k === currentEquipment.k, 'row-passed': i < currentEquipment.idx, 'row-pending': i > currentEquipment.idx }">
<td class="td-num">{{ i + 1 }}</td>
<td>
<span class="sec-tag" :style="{ color: sectionColor(eq.section), borderColor: sectionColor(eq.section) }">
{{ eq.section }}
</span>
</td>
<td>{{ eq.label }}</td>
<td>
<span v-if="eq.k === currentEquipment.k" class="badge badge-yellow">加工中</span>
<span v-else-if="i < currentEquipment.idx" class="badge badge-blue">已过</span>
<span v-else class="badge badge-gray">待入</span>
</td>
<td class="td-num">{{ rowOf(eq, i).coil }}</td>
<td class="td-num">{{ rowOf(eq, i).gap }}</td>
<td class="td-num">{{ rowOf(eq, i).speed }}</td>
<td class="td-num">{{ rowOf(eq, i).aux }}</td>
</tr>
</tbody>
</table>
<div class="tbl-scroll">
<table class="data-table compact tracking-table">
<thead>
<tr>
<th style="width:32px;">#</th>
<th style="width:72px;"></th>
<th>设备</th>
<th style="width:64px;">状态</th>
<th>当前钢卷</th>
<th style="width:80px;">辊缝 mm</th>
<th style="width:78px;"></th>
<th style="width:80px;">张力/温度</th>
</tr>
</thead>
<tbody>
<tr v-for="(eq, i) in equipments" :key="eq.k"
:class="{ 'row-active': eq.k === currentEquipment.k, 'row-passed': i < currentEquipment.idx, 'row-pending': i > currentEquipment.idx }">
<td class="td-num">{{ i + 1 }}</td>
<td>
<span class="sec-tag" :style="{ color: sectionColor(eq.section), borderColor: sectionColor(eq.section) }">{{ eq.section }}</span>
</td>
<td>{{ eq.label }}</td>
<td>
<span v-if="eq.k === currentEquipment.k" class="badge badge-yellow">加工中</span>
<span v-else-if="i < currentEquipment.idx" class="badge badge-blue">已过</span>
<span v-else class="badge badge-gray">待入</span>
</td>
<td class="td-num">{{ rowOf(eq, i).coil }}</td>
<td class="td-num">{{ rowOf(eq, i).gap }}</td>
<td class="td-num">{{ rowOf(eq, i).speed }}</td>
<td class="td-num">{{ rowOf(eq, i).aux }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
@@ -837,52 +809,59 @@ export default {
.line-wrap { padding: 0; }
.line-body { padding: 6px 10px 10px; background: #0a1218; }
.line-svg { width: 100%; height: 312px; display: block; }
.line-svg { width: 100%; height: 310px; display: block; }
.sec {
background: $bg-card; border: 1px solid $border; border-radius: 6px;
overflow: hidden;
overflow: hidden; min-width: 0;
}
.sec-title-bar {
display: flex; align-items: center; gap: 8px;
padding: 7px 12px; font-size: 13px; color: #c8d4e0; font-weight: 600;
padding: 7px 12px; font-size: 12px; color: $text-muted; font-weight: 500;
background: #161d24; border-bottom: 1px solid $border;
border-left: 3px solid transparent;
}
.pane { padding: 10px 12px; }
.pane-grid {
display: grid; gap: 10px;
grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
}
.pane-grid.two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.entry-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); }
.tank-grid {
display: grid; gap: 8px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
.sec-pill {
display: inline-block; padding: 2px 10px;
font-size: 11.5px; font-weight: 700; color: #0a1218;
border-radius: 3px; letter-spacing: 1px;
}
.pane { padding: 10px 12px; min-width: 0; }
.sub-card { background: #0f161c; border: 1px solid $border; border-radius: 4px; display: flex; flex-direction: column; }
.sub-header {
padding: 6px 10px; font-size: 12px; color: #c8d4e0;
background: #161d24; border-bottom: 1px solid $border;
display: flex; align-items: center; gap: 8px;
.kpi-row {
display: grid; gap: 6px 8px;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.sub-header.acid { color: #ffaa44; }
.sub-header.rinse { color: #3aa0c8; }
.sub-body { padding: 8px 10px; flex: 1; }
.kpi-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px 10px; }
.kpi-grid.two { grid-template-columns: repeat(2, 1fr); }
.kpi { display: flex; flex-direction: column; gap: 2px; }
.kpi-label { color: #8b9aab; font-size: 10.5px; }
.kpi-row.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.kpi-row.tight {
margin-top: 8px; padding-top: 8px;
border-top: 1px dashed $border;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}
.kpi { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kpi-label { color: #8b9aab; font-size: 10.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kpi-value {
color: #00c8ff; font-family: monospace; font-size: 14px; font-weight: 600;
color: #00c8ff; font-family: monospace; font-size: 13.5px; font-weight: 600;
background: #0a1218; border: 1px solid #2a3540; border-radius: 3px;
padding: 3px 8px; text-align: right;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kpi-unit { color: #6b7c8d; font-size: 10px; font-weight: 400; margin-left: 4px; }
.producing-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
padding: 6px 4px 8px; font-size: 12px;
.tank-row {
display: grid; gap: 8px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
margin-bottom: 4px;
}
.tank-card { background: #0f161c; border: 1px solid $border; border-radius: 4px; padding: 6px 8px; min-width: 0; }
.tank-title { font-size: 11.5px; font-weight: 600; margin-bottom: 5px; }
.tbl-scroll { width: 100%; overflow-x: auto; margin-bottom: 8px; }
.tbl-scroll:last-child { margin-bottom: 0; }
.producing-row {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
padding: 4px 4px 8px; font-size: 12px;
border-bottom: 1px dashed $border; margin-bottom: 6px;
.kv-label { color: $text-muted; font-size: 11px; margin-left: 4px; }
.kv-value { color: $sms-highlight; font-weight: 600; }