2105 lines
68 KiB
HTML
2105 lines
68 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>单码装箱模式 - UI 状态全览</title>
|
||
<style>
|
||
:root {
|
||
--blue: #1565C0;
|
||
--green: #2E7D32;
|
||
--red: #C62828;
|
||
--amber: #F57F1F;
|
||
--orange: #E65100;
|
||
--yellow: #F9A825;
|
||
--grey50: #FAFAFA;
|
||
--grey100: #F5F5F5;
|
||
--grey200: #EEEEEE;
|
||
--grey300: #E0E0E0;
|
||
--grey400: #BDBDBD;
|
||
--grey500: #9E9E9E;
|
||
--grey600: #757575;
|
||
--grey700: #616161;
|
||
--grey800: #424242;
|
||
--radius: 8px;
|
||
--device-w: 360px;
|
||
}
|
||
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||
background: #ECEFF1;
|
||
color: #212121;
|
||
padding: 24px;
|
||
}
|
||
|
||
h1 {
|
||
text-align: center;
|
||
font-size: 24px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.subtitle {
|
||
text-align: center;
|
||
font-size: 13px;
|
||
color: var(--grey600);
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.subtitle code {
|
||
background: #CFD8DC;
|
||
padding: 1px 5px;
|
||
border-radius: 3px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* ── Section headers ── */
|
||
.section {
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
padding-bottom: 8px;
|
||
border-bottom: 2px solid var(--blue);
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.section-desc {
|
||
font-size: 13px;
|
||
color: var(--grey600);
|
||
margin-bottom: 16px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
/* ── Phone mockup ── */
|
||
.phone-row {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 24px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.phone-card {
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||
overflow: hidden;
|
||
width: var(--device-w);
|
||
}
|
||
|
||
.phone-label {
|
||
background: #37474F;
|
||
color: #fff;
|
||
padding: 8px 12px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.phone-label .tag {
|
||
background: rgba(255,255,255,0.2);
|
||
padding: 1px 6px;
|
||
border-radius: 3px;
|
||
font-size: 10px;
|
||
}
|
||
|
||
.phone-screen {
|
||
width: 100%;
|
||
border-top: 1px solid var(--grey200);
|
||
}
|
||
|
||
/* ── App chrome ── */
|
||
.app-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 12px 12px 12px 16px;
|
||
background: #fff;
|
||
border-bottom: 1px solid var(--grey200);
|
||
}
|
||
|
||
.app-bar h2 {
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.mode-pill {
|
||
background: var(--blue);
|
||
color: #fff;
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
padding: 3px 9px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.mode-pill .pill-icon {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.mode-pill .pill-key {
|
||
background: rgba(255,255,255,0.22);
|
||
padding: 0 4px;
|
||
border-radius: 4px;
|
||
font-size: 10px;
|
||
}
|
||
|
||
/* ── Banners ── */
|
||
.banner {
|
||
padding: 6px 12px;
|
||
font-size: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.banner.orange {
|
||
background: #FFF3E0;
|
||
color: #E65100;
|
||
}
|
||
|
||
.banner.amber {
|
||
background: #FFF8E1;
|
||
color: #E65100;
|
||
}
|
||
|
||
.banner.blue {
|
||
background: #E3F2FD;
|
||
color: #1565C0;
|
||
}
|
||
|
||
.banner.red {
|
||
background: #FFEBEE;
|
||
color: #C62828;
|
||
}
|
||
|
||
.spinner {
|
||
width: 12px; height: 12px;
|
||
border: 1.5px solid #E65100;
|
||
border-top-color: transparent;
|
||
border-radius: 50%;
|
||
animation: spin 0.8s linear infinite;
|
||
display: inline-block;
|
||
}
|
||
|
||
@keyframes spin { to { transform: rotate(360deg); } }
|
||
|
||
/* ── Scan area ── */
|
||
.scan-area {
|
||
margin: 12px 12px 0;
|
||
padding: 14px 16px;
|
||
border-radius: var(--radius);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.scan-area.waiting {
|
||
background: var(--grey100);
|
||
color: var(--grey500);
|
||
justify-content: center;
|
||
}
|
||
|
||
.scan-area.scanned {
|
||
background: #fff;
|
||
border: 2px solid var(--green);
|
||
color: #212121;
|
||
}
|
||
|
||
.scan-area .scan-label {
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
flex: 1;
|
||
}
|
||
|
||
.scan-area .scan-tag {
|
||
font-size: 12px;
|
||
color: var(--green);
|
||
}
|
||
|
||
/* ── Info area ── */
|
||
.info-area {
|
||
margin: 0 12px;
|
||
padding-top: 10px;
|
||
}
|
||
|
||
.info-main {
|
||
display: flex;
|
||
gap: 8px;
|
||
align-items: center;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.info-main .paichan {
|
||
flex: 5;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.info-main .work-order {
|
||
flex: 4;
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
text-align: center;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.info-main .qty {
|
||
flex: 3;
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
text-align: right;
|
||
}
|
||
|
||
.info-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.info-meta .meta-left {
|
||
display: flex;
|
||
gap: 16px;
|
||
color: var(--grey700);
|
||
}
|
||
|
||
.info-meta .meta-left .meta-label {
|
||
color: var(--grey600);
|
||
}
|
||
|
||
.info-meta .meta-left .meta-value {
|
||
font-weight: 600;
|
||
}
|
||
|
||
.info-meta .meta-left .max-qty {
|
||
color: var(--amber);
|
||
}
|
||
|
||
.detail-link {
|
||
font-size: 13px;
|
||
color: var(--blue);
|
||
background: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
padding: 0;
|
||
}
|
||
|
||
.detail-link.disabled {
|
||
color: var(--grey400);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.info-placeholder {
|
||
color: var(--grey400);
|
||
}
|
||
|
||
/* ── Divider ── */
|
||
.section-divider {
|
||
border: none;
|
||
border-top: 1px solid var(--grey300);
|
||
margin: 12px 0;
|
||
}
|
||
|
||
/* ── Assigned boxes ── */
|
||
.assigned-section {
|
||
margin: 0 12px;
|
||
}
|
||
|
||
.assigned-label {
|
||
font-size: 13px;
|
||
color: var(--grey600);
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.assigned-row {
|
||
margin-bottom: 6px;
|
||
padding: 6px 8px;
|
||
border-radius: 6px;
|
||
background: var(--grey50);
|
||
border: 1px solid var(--grey300);
|
||
}
|
||
|
||
.assigned-row.editing {
|
||
background: #FFF3E0;
|
||
border-color: var(--amber);
|
||
}
|
||
|
||
.assigned-row .ar-top {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.assigned-row .ar-box-no {
|
||
flex: 1;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.assigned-row .ar-qty {
|
||
font-size: 13px;
|
||
}
|
||
|
||
.assigned-row .ar-actions {
|
||
display: flex;
|
||
gap: 0;
|
||
}
|
||
|
||
.assigned-row .ar-actions .ar-btn {
|
||
width: 28px; height: 28px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
background: none; border: none; cursor: pointer;
|
||
font-size: 16px; padding: 0;
|
||
}
|
||
|
||
.assigned-row .ar-actions .ar-btn:disabled {
|
||
opacity: 0.4;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.delete-confirm {
|
||
margin-top: 4px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.delete-confirm .btn-yes {
|
||
background: none; border: none;
|
||
color: var(--red); cursor: pointer;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.delete-confirm .btn-no {
|
||
background: none; border: none;
|
||
color: var(--grey600); cursor: pointer;
|
||
}
|
||
|
||
/* ── Input area ── */
|
||
.input-area {
|
||
margin: 0 12px 12px;
|
||
display: flex;
|
||
gap: 8px;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.input-group {
|
||
flex: 1;
|
||
}
|
||
|
||
.input-group label {
|
||
display: block;
|
||
font-size: 13px;
|
||
color: var(--grey600);
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.input-group input {
|
||
width: 100%;
|
||
height: 40px;
|
||
padding: 0 10px;
|
||
border: 1px solid var(--grey400);
|
||
border-radius: 0;
|
||
font-size: 16px;
|
||
outline: none;
|
||
}
|
||
|
||
.input-group input:focus {
|
||
border-color: var(--blue);
|
||
box-shadow: 0 0 0 1px var(--blue);
|
||
}
|
||
|
||
.input-group input.disabled {
|
||
background: var(--grey100);
|
||
color: var(--grey400);
|
||
border-color: var(--grey300);
|
||
}
|
||
|
||
.input-group input.warn-amber {
|
||
border-color: var(--amber);
|
||
}
|
||
|
||
.input-group input.warn-red {
|
||
border-color: var(--red);
|
||
}
|
||
|
||
.btn-confirm {
|
||
height: 40px;
|
||
padding: 0 16px;
|
||
background: var(--blue);
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 4px;
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.btn-confirm:disabled {
|
||
background: var(--grey300);
|
||
color: var(--grey600);
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.btn-confirm.saving {
|
||
background: var(--blue);
|
||
}
|
||
|
||
/* ── Action buttons ── */
|
||
.action-bar {
|
||
display: flex;
|
||
gap: 12px;
|
||
padding: 4px 12px;
|
||
}
|
||
|
||
.btn-back {
|
||
flex: 1;
|
||
height: 40px;
|
||
background: #fff;
|
||
border: 1px solid var(--grey400);
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.btn-cancel {
|
||
flex: 1;
|
||
height: 40px;
|
||
background: var(--blue);
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* ── Status bar ── */
|
||
.status-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
padding: 6px 12px;
|
||
background: var(--grey200);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.status-dot {
|
||
width: 7px; height: 7px;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.status-dot.blue { background: var(--blue); }
|
||
.status-dot.green { background: var(--green); }
|
||
.status-dot.red { background: var(--red); }
|
||
.status-dot.orange { background: var(--orange); }
|
||
.status-dot.yellow { background: var(--yellow); }
|
||
.status-dot.amber { background: var(--amber); }
|
||
|
||
/* ── State explanation ── */
|
||
.state-note {
|
||
background: #fff;
|
||
border-left: 3px solid var(--blue);
|
||
padding: 10px 14px;
|
||
margin: 12px 0 20px;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
color: var(--grey700);
|
||
}
|
||
|
||
.state-note strong {
|
||
color: #212121;
|
||
}
|
||
|
||
.state-note code {
|
||
background: var(--grey100);
|
||
padding: 0 4px;
|
||
border-radius: 2px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* ── Logic table ── */
|
||
.logic-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 12px;
|
||
margin: 12px 0 20px;
|
||
background: #fff;
|
||
}
|
||
|
||
.logic-table th {
|
||
background: var(--grey100);
|
||
text-align: left;
|
||
padding: 8px 10px;
|
||
border: 1px solid var(--grey300);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.logic-table td {
|
||
padding: 6px 10px;
|
||
border: 1px solid var(--grey300);
|
||
vertical-align: top;
|
||
}
|
||
|
||
/* ── Diagram ── */
|
||
.flow-diagram {
|
||
background: #fff;
|
||
border: 1px solid var(--grey300);
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin: 12px 0 20px;
|
||
font-size: 13px;
|
||
line-height: 2;
|
||
}
|
||
|
||
.flow-node {
|
||
display: inline-block;
|
||
padding: 4px 10px;
|
||
border-radius: 4px;
|
||
font-weight: 600;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.flow-node.idle { background: #E3F2FD; color: var(--blue); }
|
||
.flow-node.scanned { background: #E8F5E9; color: var(--green); }
|
||
.flow-node.submit { background: #FFF3E0; color: var(--orange); }
|
||
.flow-node.error { background: #FFEBEE; color: var(--red); }
|
||
.flow-node.success { background: #E8F5E9; color: var(--green); }
|
||
|
||
.arrow { color: var(--grey500); margin: 0 4px; }
|
||
|
||
/* ── Legend ── */
|
||
.legend {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 12px;
|
||
margin: 8px 0 16px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.legend-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.legend-dot {
|
||
width: 10px; height: 10px;
|
||
border-radius: 50%;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>单码装箱模式 — UI 状态全览</h1>
|
||
<p class="subtitle">
|
||
源码:<code>lib/pages/boxing_page.dart</code>(<em>_BoxingPageState</em>)<br>
|
||
覆盖 <strong>BoxingMode.singleCode</strong> 下所有 UI 状态、状态机流转与交互细节
|
||
</p>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 0. 颜色图例 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">0. 状态栏颜色图例</div>
|
||
<div class="legend">
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--blue)"></div> 蓝色 — 等待/空闲</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--green)"></div> 绿色 — 成功</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--red)"></div> 红色 — 错误(无效码/数量超限/提交失败)</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--orange)"></div> 橙色 — 进行中(提交中/同步数据)</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--amber)"></div> 琥珀 — 警告(箱号重复/提交重复)</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--yellow)"></div> 黄色 — 网络异常</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 1. 状态机 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">1. 状态机(_Phase 枚举)</div>
|
||
|
||
<div class="flow-diagram">
|
||
<span class="flow-node idle">waiting<br>等待扫码</span>
|
||
<span class="arrow">→ 扫码成功 →</span>
|
||
<span class="flow-node scanned">scanned<br>已扫码,已自动填充</span>
|
||
<span class="arrow">→ 用户点击确认 →</span>
|
||
<span class="flow-node submit">submitting<br>正在提交…</span>
|
||
<span class="arrow">→</span><br><br>
|
||
成功,尚有剩余 →
|
||
<span class="flow-node success">回到 scanned(箱号+1,数量=剩余)</span>
|
||
<span class="arrow"> / </span>
|
||
<span class="flow-node success">回到 waiting(全部装箱完毕)</span><br>
|
||
失败 →
|
||
<span class="flow-node error">停留在 scanned,显示错误覆盖</span>
|
||
</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>_Phase</th>
|
||
<th>触发条件</th>
|
||
<th>主要 UI 效果</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>waiting</code></td>
|
||
<td>初始化 / 重置 / 全部装箱完毕</td>
|
||
<td>扫码区灰色占位;信息区灰色 "--";输入区禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>scanned</code></td>
|
||
<td>扫码成功且 API 返回有效数据</td>
|
||
<td>扫码区绿色边框+总排号;信息区展示数据;输入区可编辑,自动填充箱号/数量</td>
|
||
</tr>
|
||
<tr>
|
||
<td><em>没有 submitted</em></td>
|
||
<td>—</td>
|
||
<td>单码模式中,提交成功后直接进入新的 scanned 或 resetting waiting,不经 submitted 阶段</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 2. UI 状态可视化 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">2. UI 状态可视化</div>
|
||
<p class="section-desc">每个手机模型展示一个具体状态。底部状态栏颜色参考上方图例。</p>
|
||
|
||
<!-- ── 2.1 等待扫码 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.1 等待扫码 (waiting) <span class="tag">初始状态</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area waiting">
|
||
📷 请扫描执行卡二维码
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan info-placeholder">--</span>
|
||
<span class="work-order info-placeholder">--</span>
|
||
<span class="qty info-placeholder">--</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="info-placeholder">--</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="info-placeholder">--</span></span>
|
||
</div>
|
||
<button class="detail-link disabled">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input class="disabled" disabled value="">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input class="disabled" disabled value="">
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot blue"></div>
|
||
等待扫码
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.2 已扫码-正常可装箱 ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.2 已扫码-正常 (scanned, can submit) <span class="tag">最常见状态</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">2箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">5</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="6">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="150" style="border-color:var(--blue);box-shadow:0 0 0 1px var(--blue);">
|
||
</div>
|
||
<button class="btn-confirm">确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot blue"></div>
|
||
数量已填入,请确认或修改
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── 2.3 已扫码+已分配列表 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.3 已扫码+已分配 (with assigned boxes)</div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">3箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">7</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="assigned-section">
|
||
<div class="assigned-label">已分配</div>
|
||
<div class="assigned-row">
|
||
<div class="ar-top">
|
||
<span class="ar-box-no">3号箱</span>
|
||
<span class="ar-qty">数量 50</span>
|
||
<div class="ar-actions">
|
||
<button class="ar-btn" title="修改">✏️</button>
|
||
<button class="ar-btn" title="删除">🗑️</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="assigned-row">
|
||
<div class="ar-top">
|
||
<span class="ar-box-no">7号箱</span>
|
||
<span class="ar-qty">数量 100</span>
|
||
<div class="ar-actions">
|
||
<button class="ar-btn" title="修改">✏️</button>
|
||
<button class="ar-btn" title="删除">🗑️</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="8">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="50" style="border-color:var(--blue);box-shadow:0 0 0 1px var(--blue);">
|
||
</div>
|
||
<button class="btn-confirm">确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot blue"></div>
|
||
数量已填入,请确认或修改
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.4 已分配行 - 编辑状态 ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.4 已分配行 - 编辑中 (editing assigned) <span class="tag">行内编辑</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">3箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">7</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="assigned-section">
|
||
<div class="assigned-label">已分配</div>
|
||
<div class="assigned-row">
|
||
<div class="ar-top">
|
||
<span class="ar-box-no">3号箱</span>
|
||
<span class="ar-qty">数量 50</span>
|
||
<div class="ar-actions">
|
||
<button class="ar-btn" title="修改">✏️</button>
|
||
<button class="ar-btn" title="删除">🗑️</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="assigned-row editing">
|
||
<div class="ar-top">
|
||
<span class="ar-box-no">7号箱</span>
|
||
<input style="width:56px;height:32px;font-size:13px;text-align:center;padding:0 4px;border:1px solid var(--amber);border-radius:4px;" value="80">
|
||
<div class="ar-actions">
|
||
<button class="ar-btn" title="保存" style="color:var(--green);">✅</button>
|
||
<button class="ar-btn" title="取消" style="color:var(--grey600);">❌</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="8">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="50">
|
||
</div>
|
||
<button class="btn-confirm">保存</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
<button class="btn-cancel" style="flex:1;background:#fff;color:#212121;border:1px solid var(--grey400);">取消</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot blue"></div>
|
||
数量已填入,请确认或修改
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── 2.5 已分配行 - 删除待确认 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.5 已分配行 - 删除确认 (delete confirm) <span class="tag">行内确认</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">2箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">5</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="assigned-section">
|
||
<div class="assigned-label">已分配</div>
|
||
<div class="assigned-row">
|
||
<div class="ar-top">
|
||
<span class="ar-box-no">3号箱</span>
|
||
<span class="ar-qty">数量 50</span>
|
||
<div class="ar-actions">
|
||
<button class="ar-btn" title="修改">✏️</button>
|
||
<button class="ar-btn" title="删除">🗑️</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="assigned-row">
|
||
<div class="ar-top">
|
||
<span class="ar-box-no">5号箱</span>
|
||
<span class="ar-qty">数量 100</span>
|
||
<div class="ar-actions">
|
||
<button class="ar-btn" title="修改">✏️</button>
|
||
<button class="ar-btn" title="删除">🗑️</button>
|
||
</div>
|
||
</div>
|
||
<div class="delete-confirm">
|
||
<span>确认删除此条记录?</span>
|
||
<button class="btn-yes">是</button>
|
||
<button class="btn-no">否</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="6">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="50">
|
||
</div>
|
||
<button class="btn-confirm">确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot blue"></div>
|
||
数量已填入,请确认或修改
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.6 提交中 ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.6 正在提交 (submitting) <span class="tag">按钮 loading</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">2箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">5</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="6">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="50">
|
||
</div>
|
||
<button class="btn-confirm saving" disabled>
|
||
<span class="spinner"></span>
|
||
</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot orange"></div>
|
||
正在提交…
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── 2.7 箱号重复 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.7 箱号重复 (duplicate box no) <span class="tag">琥珀色警告</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<!-- 重复箱号 banner -->
|
||
<div class="banner amber">
|
||
⚠️ 箱号 5 已存在,请重新输入
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">2箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">5</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input class="warn-amber" value="5">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="50">
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot amber"></div>
|
||
箱号 5 已存在,请重新输入
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.8 数量超限 ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.8 数量超限 (quantity too high) <span class="tag">红色警告</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">2箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">5</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="6">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input class="warn-red" value="200">
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot red"></div>
|
||
超出可装数量上限
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── 2.9 已全部装箱完毕 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.9 已全部装箱完毕 (fully packed on scan) <span class="tag">红色覆盖</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180002</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-B202</span>
|
||
<span class="work-order">WO-2026-0901</span>
|
||
<span class="qty">100件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">3箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">3</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="4">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="">
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot red"></div>
|
||
该总排号已全部装箱完毕
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.10 无效码 ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.10 无效码 (invalid code) <span class="tag">红色覆盖 2s</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="banner red">
|
||
❌ 无效码,请重新扫描
|
||
</div>
|
||
<div class="scan-area waiting">
|
||
📷 请扫描执行卡二维码
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan info-placeholder">--</span>
|
||
<span class="work-order info-placeholder">--</span>
|
||
<span class="qty info-placeholder">--</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="info-placeholder">--</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="info-placeholder">--</span></span>
|
||
</div>
|
||
<button class="detail-link disabled">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input class="disabled" disabled>
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input class="disabled" disabled>
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot red"></div>
|
||
无效码,请重新扫描
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── 2.11 网络异常 / 查询失败 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.11 网络异常 (network error) <span class="tag">黄色覆盖 2s</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="banner" style="background:#FFFDE7;color:#F9A825;">
|
||
⚠️ 网络异常,请检查网络连接
|
||
</div>
|
||
<div class="scan-area waiting">
|
||
📷 请扫描执行卡二维码
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan info-placeholder">--</span>
|
||
<span class="work-order info-placeholder">--</span>
|
||
<span class="qty info-placeholder">--</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="info-placeholder">--</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="info-placeholder">--</span></span>
|
||
</div>
|
||
<button class="detail-link disabled">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input class="disabled" disabled>
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input class="disabled" disabled>
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot yellow"></div>
|
||
网络异常,请检查网络连接
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.12 提交失败 ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.12 提交失败 (submit failure) <span class="tag">红色覆盖 2s</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="banner red">
|
||
❌ 服务器响应异常,请稍后重试
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">2箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">5</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="6">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="50">
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot red"></div>
|
||
服务器响应异常,请稍后重试
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── 2.13 提交重复箱号 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.13 提交重复 (duplicate on submit) <span class="tag">琥珀覆盖 2s</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="banner amber">
|
||
⚠️ 该总排号在箱号 5 已存在,请重新输入
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180001</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-A101</span>
|
||
<span class="work-order">WO-2026-0882</span>
|
||
<span class="qty">200件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">2箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">7</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="5">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="50">
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot amber"></div>
|
||
该总排号在箱号 5 已存在,请重新输入
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.14 未配置 API ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.14 未配置 API (no API configured) <span class="tag">红色覆盖 2s</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="banner red">
|
||
❌ 未配置 API 地址,请前往设置
|
||
</div>
|
||
<div class="scan-area waiting">
|
||
📷 请扫描执行卡二维码
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan info-placeholder">--</span>
|
||
<span class="work-order info-placeholder">--</span>
|
||
<span class="qty info-placeholder">--</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="info-placeholder">--</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="info-placeholder">--</span></span>
|
||
</div>
|
||
<button class="detail-link disabled">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input class="disabled" disabled>
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input class="disabled" disabled>
|
||
</div>
|
||
<button class="btn-confirm" disabled>确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot red"></div>
|
||
未配置 API 地址,请前往设置
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ── 2.15 同步转运数据 ── -->
|
||
<div class="phone-row">
|
||
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.15 同步转运数据中 (auto processing) <span class="tag">橙色横幅</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="banner orange">
|
||
<span class="spinner"></span> 正在同步转运数据...
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180003</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-C303</span>
|
||
<span class="work-order">WO-2026-0920</span>
|
||
<span class="qty">300件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">0箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value">0</span></span>
|
||
</div>
|
||
<button class="detail-link disabled">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="1">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="300">
|
||
</div>
|
||
<button class="btn-confirm">确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot orange"></div>
|
||
正在同步转运数据...
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2.16 自动装箱警告 ── -->
|
||
<div class="phone-card">
|
||
<div class="phone-label">2.16 自动装箱警告 (auto warnings) <span class="tag">琥珀横幅</span></div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱编号</h2>
|
||
<div class="mode-pill">
|
||
<span class="pill-icon">⇄</span> 单码装箱 <span class="pill-key">P2</span>
|
||
</div>
|
||
</div>
|
||
<div class="banner amber">
|
||
⚠️ 总排号 ZP-INVALID 未找到排产号信息,已忽略
|
||
</div>
|
||
<div class="scan-area scanned">
|
||
✅ <span class="scan-label">ZP202605180004</span> <span class="scan-tag">已识别</span>
|
||
</div>
|
||
<div class="info-area">
|
||
<div class="info-main">
|
||
<span class="paichan">PC-2605-D404</span>
|
||
<span class="work-order">WO-2026-0931</span>
|
||
<span class="qty">150件</span>
|
||
</div>
|
||
<div class="info-meta">
|
||
<div class="meta-left">
|
||
<span><span class="meta-label">已有箱数:</span><span class="meta-value">1箱</span></span>
|
||
<span><span class="meta-label">最大箱号:</span><span class="meta-value max-qty">3</span></span>
|
||
</div>
|
||
<button class="detail-link">详情 →</button>
|
||
</div>
|
||
</div>
|
||
<hr class="section-divider">
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<label>箱号</label>
|
||
<input value="4">
|
||
</div>
|
||
<div class="input-group">
|
||
<label>数量</label>
|
||
<input value="100" style="border-color:var(--blue);box-shadow:0 0 0 1px var(--blue);">
|
||
</div>
|
||
<button class="btn-confirm">确认</button>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="btn-back">返回</button>
|
||
</div>
|
||
<div class="status-bar">
|
||
<div class="status-dot blue"></div>
|
||
数量已填入,请确认或修改
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 3. _canSubmit 判定条件 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">3. 提交按钮启用条件(_canSubmit)</div>
|
||
|
||
<div class="state-note">
|
||
确认按钮的 enabled 状态由 <code>_canSubmit</code> 决定。当以下<strong>所有条件</strong>同时满足时,按钮启用:
|
||
</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>#</th>
|
||
<th>条件</th>
|
||
<th>代码表达式</th>
|
||
<th>不满足时效果</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>1</td>
|
||
<td>未处于提交中</td>
|
||
<td><code>!_isSubmitting</code></td>
|
||
<td>按钮显示 loading 转圈</td>
|
||
</tr>
|
||
<tr>
|
||
<td>2</td>
|
||
<td>阶段为 scanned</td>
|
||
<td><code>_phase == _Phase.scanned</code></td>
|
||
<td>按钮灰色禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>3</td>
|
||
<td>已有总排号</td>
|
||
<td><code>_zongpaiNo != null</code></td>
|
||
<td>按钮灰色禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>4</td>
|
||
<td>箱号有效</td>
|
||
<td><code>boxNo != null && boxNo > 0</code></td>
|
||
<td>按钮灰色禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>5</td>
|
||
<td>数量有效</td>
|
||
<td><code>qty != null && qty > 0</code></td>
|
||
<td>按钮灰色禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>6</td>
|
||
<td>数量未超限</td>
|
||
<td><code>!_quantityTooHigh</code>(qty ≤ remaining)</td>
|
||
<td>数量输入红色边框;状态栏红色 "超出可装数量上限"</td>
|
||
</tr>
|
||
<tr>
|
||
<td>7</td>
|
||
<td>箱号不重复</td>
|
||
<td><code>!_isDuplicateBoxNo</code></td>
|
||
<td>箱号输入琥珀边框;琥珀横幅;状态栏琥珀色 "箱号 X 已存在"</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 4. _showStatusOverride 状态覆盖机制 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">4. 状态栏覆盖机制(_showStatusOverride)</div>
|
||
|
||
<div class="state-note">
|
||
方法签名:<code>void _showStatusOverride(String text, StatusDotColor dot, Duration duration)</code><br><br>
|
||
大多数反馈状态通过此方法展示。调用后立即替换底部状态栏的 <strong>文字</strong>和<strong>圆点颜色</strong>,并在 <code>duration</code> 到期后自动恢复为基础状态(由 <code>_updateBaseStatus()</code> 计算)。
|
||
</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>场景</th>
|
||
<th>文字</th>
|
||
<th>颜色</th>
|
||
<th>持续时间</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>无效码</td>
|
||
<td>无效码,请重新扫描</td>
|
||
<td>红色</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>网络异常</td>
|
||
<td>网络异常,请检查网络连接</td>
|
||
<td>黄色</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>查询失败</td>
|
||
<td>查询失败(或具体消息)</td>
|
||
<td>红色</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>提交重复</td>
|
||
<td>该总排号在箱号 X 已存在,请重新输入</td>
|
||
<td>琥珀</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>提交失败</td>
|
||
<td>提交失败(或具体消息)</td>
|
||
<td>红色</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>未配置 API</td>
|
||
<td>未配置 API 地址,请前往设置</td>
|
||
<td>红色</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>装箱成功-继续</td>
|
||
<td>请继续完成剩余数量装箱</td>
|
||
<td>绿色</td>
|
||
<td>1.5s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>装箱成功-全部</td>
|
||
<td>装箱成功</td>
|
||
<td>绿色</td>
|
||
<td>1.5s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>全部装箱完毕</td>
|
||
<td>该总排号已全部装箱完毕</td>
|
||
<td>红色</td>
|
||
<td>常驻(_statusOverride)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>删除成功</td>
|
||
<td>删除成功</td>
|
||
<td>绿色</td>
|
||
<td>1.5s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>修改成功</td>
|
||
<td>修改成功</td>
|
||
<td>绿色</td>
|
||
<td>1.5s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>保存编辑-数量无效</td>
|
||
<td>请输入有效数量</td>
|
||
<td>红色</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>保存编辑-数量超限</td>
|
||
<td>超出可装数量上限</td>
|
||
<td>红色</td>
|
||
<td>2s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>同步转运数据</td>
|
||
<td>正在同步转运数据...</td>
|
||
<td>橙色</td>
|
||
<td>常驻(直到处理结束)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 5. 自动填充逻辑 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">5. 自动填充逻辑(_applyAutoFill)</div>
|
||
|
||
<div class="state-note">
|
||
扫码成功并获取 API 数据后自动触发。核心逻辑:<strong>填充箱号 = lastBoxNo+1 或 maxBoxNo+1</strong>;<strong>填充数量 = 剩余可装数量</strong>;数量输入框自动全选并聚焦。
|
||
</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>情况</th>
|
||
<th>箱号填充</th>
|
||
<th>数量填充</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>首次扫码(无历史箱号)</td>
|
||
<td><code>maxBoxNo + 1</code>(通常为 1)</td>
|
||
<td><code>erpQuantity - packedQuantity</code>(全部剩余)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>上次装箱后有继续</td>
|
||
<td><code>lastBoxNo + 1</code></td>
|
||
<td>剩余可装数量</td>
|
||
</tr>
|
||
<tr>
|
||
<td>已全部装箱完毕</td>
|
||
<td>清空</td>
|
||
<td>清空</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 6. 已分配行操作 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">6. 已分配行操作详解</div>
|
||
|
||
<div class="state-note">
|
||
每个 <code>CurrentZongpaiBoxData</code> 渲染为一行 <code>_buildAssignedBoxRow</code>。操作按钮在 <strong>view/edit 模式</strong> 和 <strong>delete 确认模式</strong> 间切换。
|
||
</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>操作</th>
|
||
<th>入口</th>
|
||
<th>交互过程</th>
|
||
<th>成功后效果</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><strong>修改</strong></td>
|
||
<td>点击 ✏️</td>
|
||
<td>行变橙色背景;数量文字→文本输入;显示 ✅保存 / ❌取消 按钮</td>
|
||
<td>调用 <code>updateBoxRecord</code>;状态栏绿 "修改成功" 1.5s;自动刷新输入区</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>删除</strong></td>
|
||
<td>点击 🗑️</td>
|
||
<td>行下方出现红色确认条 "确认删除此条记录?" [是] [否]</td>
|
||
<td>调用 <code>deleteBoxRecord</code>;状态栏绿 "删除成功" 1.5s;行移除此数据</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>取消编辑</strong></td>
|
||
<td>点击 ❌ 或 "否"</td>
|
||
<td>恢复 view 模式,不做 API 调用</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 7. 模式切换 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">7. 模式切换(_cycleMode)</div>
|
||
|
||
<div class="state-note">
|
||
触发方式:<strong>点击 Pill</strong> 或 <strong>按下 P2 物理按键</strong>(Android KeyCode R1 / LogicalKey gameButtonRight1 / LogicalKey select)。<br>
|
||
切换时调用 <code>_resetState()</code> 清空所有状态,包括阶段、总排号、箱号输入等。
|
||
</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>方向</th>
|
||
<th>Pill 背景色</th>
|
||
<th>标签</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>单码 → 多码</td>
|
||
<td>橙色 <code>Colors.orange.shade700</code></td>
|
||
<td>多码凑箱</td>
|
||
</tr>
|
||
<tr>
|
||
<td>多码 → 单码</td>
|
||
<td>蓝色 <code>Colors.blue.shade700</code></td>
|
||
<td>单码装箱</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 8. 装箱详情页 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">8. 装箱详情页(BoxingDetailPage)</div>
|
||
|
||
<div class="state-note">
|
||
源码:<code>lib/pages/boxing_detail_page.dart</code><br>
|
||
通过点击主页面 "详情 →" 进入。传入 <code>paichanNo</code> 和 <code>existingBoxes</code>,按箱号分组展示每个箱内的总排号明细(总排号、工单号、数量/总量)。
|
||
</div>
|
||
|
||
<div class="phone-row">
|
||
<div class="phone-card">
|
||
<div class="phone-label">装箱详情(导航页)</div>
|
||
<div class="phone-screen">
|
||
<div class="app-bar">
|
||
<h2>装箱详情 PC-2605-A101</h2>
|
||
</div>
|
||
<div style="padding:12px;">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;">
|
||
<span style="font-size:14px;font-weight:700;">箱号 3</span>
|
||
<span style="font-size:14px;font-weight:600;color:var(--blue);">共 50 件</span>
|
||
</div>
|
||
<div style="border:1px solid var(--grey300);border-radius:6px;padding:8px;">
|
||
<div style="display:flex;gap:8px;font-size:14px;margin:2px 0;">
|
||
<span style="flex:3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">ZP202605180001</span>
|
||
<span style="flex:2;color:var(--grey600);">WO-2026-0882</span>
|
||
<span>50/--</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin:12px 0 4px;">
|
||
<span style="font-size:14px;font-weight:700;">箱号 7</span>
|
||
<span style="font-size:14px;font-weight:600;color:var(--blue);">共 100 件</span>
|
||
</div>
|
||
<div style="border:1px solid var(--grey300);border-radius:6px;padding:8px;">
|
||
<div style="display:flex;gap:8px;font-size:14px;margin:2px 0;">
|
||
<span style="flex:3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">ZP202605180001</span>
|
||
<span style="flex:2;color:var(--grey600);">WO-2026-0882</span>
|
||
<span>100/--</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="padding:12px 16px;background:var(--grey200);font-size:14px;">
|
||
共 2 箱
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 9. 关键状态字段速查表 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">9. 关键状态字段速查表</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>_mode</code></td>
|
||
<td>BoxingMode</td>
|
||
<td>singleCode / multiCode</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_phase</code></td>
|
||
<td>_Phase (enum)</td>
|
||
<td>waiting / scanned(单码无 submitted)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_zongpaiNo</code></td>
|
||
<td>String?</td>
|
||
<td>当前总排号,null = 未扫码</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_paichanNo</code></td>
|
||
<td>String?</td>
|
||
<td>来自 API 的排产号</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_workOrderNo</code></td>
|
||
<td>String?</td>
|
||
<td>来自 API 的工单号</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_erpQuantity</code></td>
|
||
<td>int?</td>
|
||
<td>来自 API 的 ERP 总数量</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_currentZongpaiBoxes</code></td>
|
||
<td>List<CurrentZongpaiBoxData></td>
|
||
<td>当前总排号已分配的箱号列表("已分配" 区数据源)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_existingBoxes</code></td>
|
||
<td>List<BoxDetailData></td>
|
||
<td>该排产号所有已有箱号(详情页数据源)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_maxBoxNo</code></td>
|
||
<td>int</td>
|
||
<td>已有最大箱号,用于填充下一个箱号</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_lastBoxNo</code></td>
|
||
<td>int?</td>
|
||
<td>上次提交的箱号(用于 continue 时 boxNo+1)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_editingBox</code></td>
|
||
<td>CurrentZongpaiBoxData?</td>
|
||
<td>当前正在编辑的已分配行(null = 非编辑状态)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_isSubmitting</code></td>
|
||
<td>bool</td>
|
||
<td>正在提交 API 请求(禁用按钮、显示 loading 转圈)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_isDuplicateBoxNo</code></td>
|
||
<td>bool</td>
|
||
<td>当前箱号是否和已有箱号重复</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_editingAssignedItemId</code></td>
|
||
<td>int?</td>
|
||
<td>正在编辑的已分配行 ID</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_deletingAssignedItemId</code></td>
|
||
<td>int?</td>
|
||
<td>待删除的已分配行 ID(显示确认条)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_statusOverrideText</code></td>
|
||
<td>String?</td>
|
||
<td>覆盖状态栏文字(null = 使用基础状态文字)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_statusOverrideDot</code></td>
|
||
<td>StatusDotColor?</td>
|
||
<td>覆盖状态栏圆点颜色</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>_isAutoProcessing</code></td>
|
||
<td>bool</td>
|
||
<td>是否正在自动同步/装箱转运数据</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<!-- 10. 数据来源 -->
|
||
<!-- ═══════════════════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">10. API 数据依赖</div>
|
||
|
||
<div class="state-note">
|
||
所有核心信息来自 <code>BoxInfoResult</code>(方法:fetchBoxInfo),装箱操作依赖 saveBoxRecord / updateBoxRecord / deleteBoxRecord。
|
||
</div>
|
||
|
||
<table class="logic-table">
|
||
<thead>
|
||
<tr>
|
||
<th>API</th>
|
||
<th>触发时机</th>
|
||
<th>返回关键字段</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>fetchBoxInfo(zongpaiNo)</code></td>
|
||
<td>扫码时</td>
|
||
<td>paichanNo, workOrderNo, quantity, currentZongpaiBoxes, existingBoxes, maxBoxNo</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>saveBoxRecord(zongpaiNo, boxNo, quantity)</code></td>
|
||
<td>首次添加装箱记录</td>
|
||
<td>success, isDuplicate, boxItemId</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>updateBoxRecord(boxItemId, boxNo, quantity)</code></td>
|
||
<td>修改已分配行 / 保存编辑</td>
|
||
<td>success, isDuplicate</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>deleteBoxRecord(boxItemId)</code></td>
|
||
<td>删除已分配行确认</td>
|
||
<td>success</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div style="text-align:center;padding:24px;font-size:12px;color:var(--grey500);">
|
||
生成时间:2026-05-18 · 源码:<code>lib/pages/boxing_page.dart</code>(2545行)<br>
|
||
相关模块:<code>lib/pages/boxing_detail_page.dart</code> · <code>lib/widgets/status_bar.dart</code> · <code>lib/services/boxing_context.dart</code>
|
||
</div>
|
||
|
||
</body>
|
||
</html>
|