feat(linkage): 鞍座改为预备生产位 + 在线改人工触发 + 计划删除

- 上卷鞍座=预备生产位(不生产);投入生产后离开鞍座、进入生产中并转入物料跟踪,鞍座随即空出
- 在线状态改为人工触发:移动到入口端才变在线,引擎不再自动上线(ensure_online 置空)
- 单卷在产:投入生产时若已有在产卷则拒绝
- 物料跟踪显示在产卷实时进度(客户端外推带头长度/进度条)
- 入口跟踪鞍座卡片改为预备生产展示(去掉进度)
- 计划管理新增删除按钮 + DELETE /plan/{id}(生产中不可删)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-29 15:20:16 +08:00
parent 1a6deea4bb
commit 62c484411e
6 changed files with 103 additions and 94 deletions

View File

@@ -5,9 +5,9 @@
<div class="card">
<div class="card-header">
入口跟踪
<span class="ch-badge">{{ saddle ? '生产' + statusLabel(saddle.status) : '鞍座空闲' }}</span>
<span class="ch-badge">{{ saddle ? '上卷鞍座:预备生产' : '上卷鞍座空闲' }}</span>
<span style="margin-left:auto;display:flex;gap:8px;align-items:center;">
<button v-if="saddle && saddle.status !== 'producing'" class="btn btn-primary" @click="commit(saddle)">投入生产</button>
<button v-if="saddle" class="btn btn-primary" @click="commit(saddle)">投入生产</button>
<button class="btn btn-outline" @click="refreshAll">刷新</button>
</span>
</div>
@@ -38,28 +38,24 @@
</div>
</div>
<!-- 下方单个上卷鞍座唯一进入生产的工位 -->
<!-- 下方单个上卷鞍座预备生产位投入生产后离开鞍座进入物料跟踪 -->
<div :class="['pos-cell', 'saddle-cell', { filled: !!saddle }]">
<div class="pos-title saddle-title">上卷鞍座<span class="st-tag">生产</span></div>
<div class="pos-title saddle-title">上卷鞍座<span class="st-tag">预备生产位</span></div>
<div v-if="saddle" class="saddle-body">
<div class="sb-info">
<span><i>冷卷号</i>{{ saddle.cold_coil_no || saddle.plan_no }}</span>
<span><i>热卷号</i>{{ saddle.hot_coil_no || '—' }}</span>
<span><i>钢种</i>{{ saddle.steel_grade || '—' }}</span>
<span><i>规格</i>{{ fmt(saddle.product_thickness, 2) }}×{{ fmt(saddle.product_width, 0) }}</span>
<span><i>来料重[t]</i>{{ fmt(saddle.incoming_weight, 3) }}</span>
<span><i>轧制模式</i>{{ saddle.rolling_mode || '—' }}</span>
<span><i>状态</i><b :class="badgeOf(saddle.status)" style="padding:0 6px;border-radius:2px;">{{ statusLabel(saddle.status) }}</b></span>
</div>
<div class="sb-run">
<div class="sb-metric"><span class="m-v">{{ fmt(saddle.run_speed, 0) }}</span><span class="m-u">m/min</span></div>
<div class="sb-metric"><span class="m-v">{{ fmt(saddle.run_length_m, 0) }}</span><span class="m-u">/ {{ TARGET }} m</span></div>
<div class="sb-prog">
<div class="prog-bar-wrap" style="height:9px;"><div class="prog-bar-fill" :style="{ width: progPct(saddle) + '%', background: progColor(saddle) }"></div></div>
<span class="sb-pct">{{ progPct(saddle).toFixed(1) }}%</span>
</div>
<div class="sb-stage">
<span class="badge badge-yellow">预备生产</span>
<span class="sb-hint">点击右上投入生产 进入生产中并转入物料跟踪</span>
</div>
</div>
<div v-else class="pos-empty">空闲 移动计划上卷鞍座开始生产</div>
<div v-else class="pos-empty">空闲 把在线计划移动到上卷鞍座预备生产</div>
</div>
</div>
</div>
@@ -203,8 +199,8 @@ export default {
async commit(p) {
try {
await commitProducing(p.id)
this.$message.success('已投入生产')
this.fetchSaddle()
this.$message.success('已投入生产,转入物料跟踪')
this.refreshAll()
} catch (e) {
this.$message.error(e?.response?.data?.detail || '操作失败')
}
@@ -252,12 +248,9 @@ export default {
span { font-size: 12px; color: $text-primary; font-family: $font-mono; font-weight: 600; display: flex; gap: 6px;
i { color: $text-muted; font-style: normal; font-family: $font-main; font-weight: 400; min-width: 56px; } }
}
.sb-run { display: flex; align-items: center; gap: 16px; border-left: 1px solid $border; padding-left: 16px; }
.sb-metric { display: flex; flex-direction: column; line-height: 1.1;
.m-v { font-size: 22px; font-family: $font-mono; font-weight: 700; color: $sms-teal; }
.m-u { font-size: 10px; color: $text-muted; } }
.sb-prog { flex: 1; display: flex; flex-direction: column; gap: 5px;
.sb-pct { font-size: 11px; font-family: $font-mono; font-weight: 700; color: $sms-teal; text-align: right; } }
.sb-stage { display: flex; flex-direction: column; align-items: center; gap: 8px; justify-content: center;
border-left: 1px solid $border; padding-left: 16px;
.sb-hint { font-size: 11px; color: $text-muted; text-align: center; } }
.action-link { color: $accent-green; cursor: pointer; font-size: 12px; &:hover { text-decoration: underline; } }