Files
pad_scanner/docs/multi-code-boxing-ui-preview.html
Misaka_Company f964c76382 feat: refactor multi-code boxing UI with compact v2 layout
Merge box number and paichan info into a single header bar,
compress list rows to 40px with left color bars, fix bottom
operation area (scan/submit/finish) above status bar, and
shrink notification bars and status bar for more list space.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-18 13:58:50 +08:00

1190 lines
34 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans SC', sans-serif;
background: #f0f2f5;
color: #333;
padding: 20px;
}
h1 {
text-align: center;
font-size: 22px;
margin-bottom: 6px;
color: #1a1a1a;
}
.subtitle {
text-align: center;
font-size: 14px;
color: #888;
margin-bottom: 30px;
}
/* === 场景选择 Tab === */
.scenario-tabs {
display: flex;
gap: 8px;
margin-bottom: 24px;
flex-wrap: wrap;
justify-content: center;
}
.scenario-tab {
padding: 8px 18px;
border: 2px solid #ddd;
border-radius: 20px;
background: #fff;
cursor: pointer;
font-size: 14px;
font-weight: 600;
transition: all 0.2s;
color: #555;
}
.scenario-tab:hover { border-color: #1976d2; color: #1976d2; }
.scenario-tab.active { background: #1976d2; color: #fff; border-color: #1976d2; }
/* === 手机框架 === */
.phone-container {
display: flex;
justify-content: center;
gap: 32px;
flex-wrap: wrap;
}
.phone-wrapper {
text-align: center;
}
.phone-label {
font-size: 14px;
font-weight: 600;
color: #555;
margin-bottom: 10px;
}
.phone-frame {
width: 380px;
background: #fff;
border-radius: 24px;
box-shadow: 0 4px 24px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.05);
overflow: hidden;
}
/* === AppBar === */
.app-bar {
display: flex;
align-items: center;
padding: 14px 12px;
background: #f5f5f5;
border-bottom: 1px solid #e0e0e0;
}
.app-bar-title {
font-size: 18px;
font-weight: 700;
color: #1a1a1a;
}
.mode-badge {
margin-left: 12px;
padding: 6px 10px;
border-radius: 8px;
background: #e65100;
color: #fff;
font-size: 13px;
font-weight: 800;
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
flex: 1;
justify-content: center;
}
.mode-badge .icon { font-size: 14px; }
.mode-badge .shortcut {
font-size: 11px;
font-weight: 700;
opacity: 0.88;
margin-left: 4px;
}
/* === Alert Bars === */
.alert-bar {
width: 100%;
padding: 8px 16px;
font-size: 13px;
display: flex;
align-items: center;
gap: 8px;
}
.alert-sync {
background: #fff3e0;
color: #e65100;
}
.alert-sync .spinner {
width: 16px; height: 16px;
border: 2px solid #fb8c00;
border-top-color: transparent;
border-radius: 50%;
animation: spin 0.8s linear infinite;
flex-shrink: 0;
}
@keyframes spin { to { transform: rotate(360deg); } }
.alert-warning {
background: #fff8e1;
color: #ff8f00;
}
.alert-blue {
background: #e3f2fd;
color: #0d47a1;
}
.alert-amber {
background: #fff8e1;
color: #ff8f00;
}
/* === Body Content === */
.body-content {
padding: 12px;
}
/* --- Box No Panel --- */
.box-no-panel {
margin-bottom: 12px;
}
.box-no-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
}
.box-no-label {
font-size: 22px;
font-weight: 700;
}
.box-no-input {
width: 96px;
height: 44px;
text-align: center;
font-size: 24px;
font-weight: 700;
border: 2px solid #9e9e9e;
border-radius: 6px;
outline: none;
color: #333;
}
.box-no-input:focus { border-color: #1976d2; }
.box-no-divider {
height: 1px;
background: #e0e0e0;
}
/* --- Info Row --- */
.info-row {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.info-row-text {
flex: 1;
font-size: 13px;
font-weight: 600;
color: #333;
}
.info-row-btn {
padding: 4px 8px;
font-size: 13px;
color: #1976d2;
background: none;
border: none;
cursor: pointer;
}
.info-row-btn.disabled {
color: #bdbdbd;
cursor: default;
}
/* --- Packed List --- */
.packed-header {
font-size: 13px;
font-weight: 700;
margin-bottom: 6px;
}
.packed-empty {
font-size: 13px;
color: #9e9e9e;
}
.packed-item {
margin-bottom: 6px;
padding: 6px 8px;
border: 1px solid #e0e0e0;
border-radius: 6px;
background: #fafafa;
}
.packed-item.editing {
background: #fff3e0;
border-color: #fb8c00;
}
.packed-item-row {
display: flex;
align-items: center;
}
.packed-item-info {
flex: 1;
font-size: 13px;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.packed-item-qty {
font-size: 13px;
color: #555;
margin-right: 4px;
}
.packed-item-edit-input {
width: 56px;
height: 32px;
text-align: center;
border: 1px solid #bbb;
border-radius: 4px;
font-size: 13px;
outline: none;
margin-right: 4px;
}
.icon-btn {
width: 32px;
height: 32px;
border: none;
background: none;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 50%;
font-size: 16px;
color: #666;
}
.icon-btn:hover { background: #e0e0e0; }
.icon-btn.check { color: #4caf50; }
.icon-btn.close { color: #f44336; }
.icon-btn.edit { color: #ff9800; }
.icon-btn.delete { color: #e53935; }
.delete-confirm {
display: flex;
align-items: center;
padding-top: 4px;
font-size: 13px;
}
.delete-confirm span { flex: 1; }
.delete-confirm-btn {
border: none;
background: none;
font-size: 14px;
cursor: pointer;
padding: 4px 8px;
}
.delete-confirm-btn.yes { color: #e53935; }
.delete-confirm-btn.no { color: #666; }
/* --- Divider --- */
.divider {
height: 1px;
background: #e0e0e0;
margin: 12px 0;
}
/* --- Scan Area --- */
.scan-area {
width: 100%;
padding: 14px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.scan-area.waiting {
background: #f5f5f5;
color: #9e9e9e;
font-size: 14px;
}
.scan-area.scanned {
background: #fff;
border: 2px solid #4caf50;
justify-content: flex-start;
padding: 10px;
}
.scan-area .check-icon {
color: #4caf50;
font-size: 18px;
}
.scan-area .scanned-text {
font-size: 14px;
font-weight: 700;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.scan-area .scanner-icon {
font-size: 20px;
color: #9e9e9e;
}
/* --- Submit Area --- */
.submit-area {
display: flex;
align-items: flex-end;
gap: 8px;
}
.submit-qty-col {
flex: 1;
}
.submit-label {
font-size: 13px;
color: #999;
margin-bottom: 4px;
}
.submit-label.active { color: #666; }
.submit-qty-input {
width: 100%;
height: 40px;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 0 10px;
font-size: 16px;
outline: none;
}
.submit-qty-input:focus { border-color: #1976d2; }
.submit-qty-input.error { border-color: #f44336; }
.submit-qty-input:disabled { background: #f5f5f5; color: #bbb; }
.submit-btn {
height: 40px;
padding: 0 16px;
border: none;
border-radius: 6px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
.submit-btn.active {
background: #1976d2;
color: #fff;
}
.submit-btn.disabled {
background: #e0e0e0;
color: #9e9e9e;
cursor: default;
}
/* --- Finish Button --- */
.finish-btn-area {
padding: 4px 12px;
}
.finish-btn {
width: 100%;
height: 40px;
border: 1px solid #ccc;
border-radius: 6px;
background: #fff;
font-size: 15px;
font-weight: 600;
cursor: pointer;
color: #333;
transition: all 0.2s;
}
.finish-btn:hover { background: #f5f5f5; border-color: #999; }
.finish-btn.disabled {
color: #bbb;
border-color: #e0e0e0;
cursor: default;
}
/* --- Status Bar --- */
.status-bar {
width: 100%;
padding: 12px 16px;
background: #f0f0f0;
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
.status-dot.blue { background: #1976d2; }
.status-dot.orange { background: #ff9800; }
.status-dot.green { background: #4caf50; }
.status-dot.red { background: #f44336; }
.status-dot.yellow { background: #fbc02d; }
.status-dot.amber { background: #ff8f00; }
.status-text {
font-size: 14px;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* === 说明卡片 === */
.notes-section {
max-width: 820px;
margin: 40px auto 0;
padding: 0 20px;
}
.notes-card {
background: #fff;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
margin-bottom: 20px;
}
.notes-card h3 {
font-size: 16px;
margin-bottom: 12px;
color: #1a1a1a;
border-bottom: 2px solid #1976d2;
padding-bottom: 6px;
display: inline-block;
}
.notes-card p, .notes-card li {
font-size: 14px;
line-height: 1.8;
color: #555;
}
.notes-card ul {
padding-left: 20px;
}
.notes-card code {
background: #f5f5f5;
padding: 2px 6px;
border-radius: 4px;
font-size: 13px;
color: #d32f2f;
}
.flow-diagram {
background: #fafafa;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 16px;
font-family: 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
white-space: pre;
overflow-x: auto;
color: #333;
}
.color-legend {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin-top: 8px;
}
.color-legend-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
}
.color-legend-dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
</style>
</head>
<body>
<h1>装箱编号 — 多码凑箱模式 UI 展示</h1>
<p class="subtitle">基于 boxing_page.dart 实际代码还原 | 源文件lib/pages/boxing_page.dart (2312行)</p>
<!-- 场景选择 -->
<div class="scenario-tabs">
<div class="scenario-tab active" onclick="showScenario('s1', this)">初始状态</div>
<div class="scenario-tab" onclick="showScenario('s2', this)">已扫码识别</div>
<div class="scenario-tab" onclick="showScenario('s3', this)">已装入多项</div>
<div class="scenario-tab" onclick="showScenario('s4', this)">编辑/删除已装入项</div>
<div class="scenario-tab" onclick="showScenario('s5', this)">排产号切换</div>
<div class="scenario-tab" onclick="showScenario('s6', this)">自动同步转运</div>
</div>
<!-- 场景容器 -->
<div class="phone-container">
<!-- ========== 场景1初始状态 ========== -->
<div class="phone-wrapper" id="s1">
<div class="phone-label">场景1初始等待扫码</div>
<div class="phone-frame">
<!-- AppBar -->
<div class="app-bar">
<span class="app-bar-title">装箱编号</span>
<div class="mode-badge">
<span class="icon"></span>
多码凑箱
<span class="shortcut">P2</span>
</div>
</div>
<!-- Body -->
<div class="body-content">
<!-- Box No Panel -->
<div class="box-no-panel">
<div class="box-no-row">
<span class="box-no-label">当前箱号</span>
<input class="box-no-input" value="1" />
</div>
<div class="box-no-divider"></div>
</div>
<!-- Packed List -->
<div class="packed-header">已装入本箱0项</div>
<div class="packed-empty">(空)</div>
<div class="divider"></div>
<!-- Scan Area (waiting) -->
<div class="scan-area waiting">
<span class="scanner-icon">📷</span>
请扫描执行卡二维码
</div>
<div style="height: 10px"></div>
<!-- Submit Area -->
<div class="submit-area">
<div class="submit-qty-col">
<div class="submit-label">数量</div>
<input class="submit-qty-input" disabled placeholder="" />
</div>
<button class="submit-btn disabled">确认</button>
</div>
</div>
<!-- Finish Button -->
<div class="finish-btn-area">
<button class="finish-btn disabled">完成本箱</button>
</div>
<!-- Status Bar -->
<div class="status-bar">
<div class="status-dot blue"></div>
<span class="status-text">等待扫码</span>
</div>
</div>
</div>
<!-- ========== 场景2已扫码识别 ========== -->
<div class="phone-wrapper" id="s2" style="display:none;">
<div class="phone-label">场景2已扫码显示信息待确认</div>
<div class="phone-frame">
<div class="app-bar">
<span class="app-bar-title">装箱编号</span>
<div class="mode-badge">
<span class="icon"></span>
多码凑箱
<span class="shortcut">P2</span>
</div>
</div>
<div class="body-content">
<!-- Box No Panel -->
<div class="box-no-panel">
<div class="box-no-row">
<span class="box-no-label">当前箱号</span>
<input class="box-no-input" value="1" />
</div>
<div class="box-no-divider"></div>
</div>
<!-- Info Row -->
<div class="info-row">
<span class="info-row-text">W00009 已有0箱 最大箱号0</span>
<button class="info-row-btn disabled">详情 →</button>
</div>
<!-- Packed List -->
<div class="packed-header">已装入本箱0项</div>
<div class="packed-empty">(空)</div>
<div class="divider"></div>
<!-- Scan Area (scanned) -->
<div class="scan-area scanned">
<span class="check-icon"></span>
<span class="scanned-text">26BW0011 WO-2026-001 80件</span>
</div>
<div style="height: 10px"></div>
<!-- Submit Area -->
<div class="submit-area">
<div class="submit-qty-col">
<div class="submit-label active">数量</div>
<input class="submit-qty-input" value="80" />
</div>
<button class="submit-btn active">确认</button>
</div>
</div>
<div class="finish-btn-area">
<button class="finish-btn disabled">完成本箱</button>
</div>
<div class="status-bar">
<div class="status-dot blue"></div>
<span class="status-text">数量已填入,请确认或修改</span>
</div>
</div>
</div>
<!-- ========== 场景3已装入多项 ========== -->
<div class="phone-wrapper" id="s3" style="display:none;">
<div class="phone-label">场景3已装入3项等待继续扫码</div>
<div class="phone-frame">
<div class="app-bar">
<span class="app-bar-title">装箱编号</span>
<div class="mode-badge">
<span class="icon"></span>
多码凑箱
<span class="shortcut">P2</span>
</div>
</div>
<div class="body-content">
<!-- Box No Panel -->
<div class="box-no-panel">
<div class="box-no-row">
<span class="box-no-label">当前箱号</span>
<input class="box-no-input" value="1" />
</div>
<div class="box-no-divider"></div>
</div>
<!-- Info Row -->
<div class="info-row">
<span class="info-row-text">W00009 已有1箱 最大箱号1</span>
<button class="info-row-btn">详情 →</button>
</div>
<!-- Packed List (3 items) -->
<div class="packed-header">已装入本箱3项</div>
<div class="packed-item">
<div class="packed-item-row">
<span class="packed-item-info">26BW0011 WO-2026-001</span>
<span class="packed-item-qty">80/80</span>
<button class="icon-btn edit" title="修改">✏️</button>
<button class="icon-btn delete" title="删除">🗑</button>
</div>
</div>
<div class="packed-item">
<div class="packed-item-row">
<span class="packed-item-info">26BW0012 WO-2026-002</span>
<span class="packed-item-qty">60/60</span>
<button class="icon-btn edit" title="修改">✏️</button>
<button class="icon-btn delete" title="删除">🗑</button>
</div>
</div>
<div class="packed-item">
<div class="packed-item-row">
<span class="packed-item-info">26BW0013 WO-2026-003</span>
<span class="packed-item-qty">40/40</span>
<button class="icon-btn edit" title="修改">✏️</button>
<button class="icon-btn delete" title="删除">🗑</button>
</div>
</div>
<div class="divider"></div>
<!-- Scan Area (waiting for next) -->
<div class="scan-area waiting">
<span class="scanner-icon">📷</span>
请扫描执行卡二维码
</div>
<div style="height: 10px"></div>
<!-- Submit Area (disabled, waiting) -->
<div class="submit-area">
<div class="submit-qty-col">
<div class="submit-label">数量</div>
<input class="submit-qty-input" disabled />
</div>
<button class="submit-btn disabled">确认</button>
</div>
</div>
<div class="finish-btn-area">
<button class="finish-btn">完成本箱</button>
</div>
<div class="status-bar">
<div class="status-dot green"></div>
<span class="status-text">装箱成功,请继续扫码</span>
</div>
</div>
</div>
<!-- ========== 场景4编辑/删除 ========== -->
<div class="phone-wrapper" id="s4" style="display:none;">
<div class="phone-label">场景4编辑数量 &amp; 删除确认</div>
<div class="phone-frame">
<div class="app-bar">
<span class="app-bar-title">装箱编号</span>
<div class="mode-badge">
<span class="icon"></span>
多码凑箱
<span class="shortcut">P2</span>
</div>
</div>
<div class="body-content">
<!-- Box No Panel -->
<div class="box-no-panel">
<div class="box-no-row">
<span class="box-no-label">当前箱号</span>
<input class="box-no-input" value="1" />
</div>
<div class="box-no-divider"></div>
</div>
<!-- Info Row -->
<div class="info-row">
<span class="info-row-text">W00009 已有1箱 最大箱号1</span>
<button class="info-row-btn">详情 →</button>
</div>
<!-- Packed List -->
<div class="packed-header">已装入本箱3项</div>
<!-- Item being edited -->
<div class="packed-item editing">
<div class="packed-item-row">
<span class="packed-item-info">26BW0011 WO-2026-001</span>
<input class="packed-item-edit-input" value="75" />
<button class="icon-btn check" title="保存"></button>
<button class="icon-btn close" title="取消"></button>
</div>
</div>
<!-- Normal item -->
<div class="packed-item">
<div class="packed-item-row">
<span class="packed-item-info">26BW0012 WO-2026-002</span>
<span class="packed-item-qty">60/60</span>
<button class="icon-btn edit" title="修改">✏️</button>
<button class="icon-btn delete" title="删除">🗑</button>
</div>
</div>
<!-- Item with delete confirmation -->
<div class="packed-item">
<div class="packed-item-row">
<span class="packed-item-info">26BW0013 WO-2026-003</span>
<span class="packed-item-qty">40/40</span>
<button class="icon-btn edit" title="修改">✏️</button>
<button class="icon-btn delete" title="删除">🗑</button>
</div>
<div class="delete-confirm">
<span>确认删除此条记录?</span>
<button class="delete-confirm-btn yes"></button>
<button class="delete-confirm-btn no"></button>
</div>
</div>
<div class="divider"></div>
<!-- Scan Area (waiting) -->
<div class="scan-area waiting">
<span class="scanner-icon">📷</span>
请扫描执行卡二维码
</div>
<div style="height: 10px"></div>
<div class="submit-area">
<div class="submit-qty-col">
<div class="submit-label">数量</div>
<input class="submit-qty-input" disabled />
</div>
<button class="submit-btn disabled">确认</button>
</div>
</div>
<div class="finish-btn-area">
<button class="finish-btn">完成本箱</button>
</div>
<div class="status-bar">
<div class="status-dot blue"></div>
<span class="status-text">请继续扫码或完成本箱</span>
</div>
</div>
</div>
<!-- ========== 场景5排产号切换 ========== -->
<div class="phone-wrapper" id="s5" style="display:none;">
<div class="phone-label">场景5排产号切换时蓝色提示条</div>
<div class="phone-frame">
<div class="app-bar">
<span class="app-bar-title">装箱编号</span>
<div class="mode-badge">
<span class="icon"></span>
多码凑箱
<span class="shortcut">P2</span>
</div>
</div>
<!-- Blue notice bar -->
<div class="alert-bar alert-blue">
排产号已切换W00010
</div>
<div class="body-content">
<!-- Box No Panel - box no auto reset to max+1 -->
<div class="box-no-panel">
<div class="box-no-row">
<span class="box-no-label">当前箱号</span>
<input class="box-no-input" value="2" />
</div>
<div class="box-no-divider"></div>
</div>
<!-- Info Row -->
<div class="info-row">
<span class="info-row-text">W00010 已有0箱 最大箱号1</span>
<button class="info-row-btn">详情 →</button>
</div>
<!-- Packed List (cleared) -->
<div class="packed-header">已装入本箱0项</div>
<div class="packed-empty">(空)</div>
<div class="divider"></div>
<!-- Scan Area (new scanned code) -->
<div class="scan-area scanned">
<span class="check-icon"></span>
<span class="scanned-text">26BW0020 WO-2026-010 100件</span>
</div>
<div style="height: 10px"></div>
<div class="submit-area">
<div class="submit-qty-col">
<div class="submit-label active">数量</div>
<input class="submit-qty-input" value="100" />
</div>
<button class="submit-btn active">确认</button>
</div>
</div>
<div class="finish-btn-area">
<button class="finish-btn disabled">完成本箱</button>
</div>
<div class="status-bar">
<div class="status-dot blue"></div>
<span class="status-text">排产号已切换,箱号已重置</span>
</div>
</div>
</div>
<!-- ========== 场景6自动同步转运 ========== -->
<div class="phone-wrapper" id="s6" style="display:none;">
<div class="phone-label">场景6从转运同步自动装箱处理中</div>
<div class="phone-frame">
<div class="app-bar">
<span class="app-bar-title">装箱编号</span>
<div class="mode-badge">
<span class="icon"></span>
多码凑箱
<span class="shortcut">P2</span>
</div>
</div>
<!-- Sync in progress bar -->
<div class="alert-bar alert-sync">
<div class="spinner"></div>
正在同步转运数据...
</div>
<!-- Warning bar -->
<div class="alert-bar alert-warning">
总排号 26BW0099 未找到排产号信息,已忽略
</div>
<div class="body-content">
<!-- Box No Panel -->
<div class="box-no-panel">
<div class="box-no-row">
<span class="box-no-label">当前箱号</span>
<input class="box-no-input" value="3" />
</div>
<div class="box-no-divider"></div>
</div>
<!-- Info Row -->
<div class="info-row">
<span class="info-row-text">W00009 已有2箱 最大箱号2</span>
<button class="info-row-btn">详情 →</button>
</div>
<!-- Packed List (2 items already packed during sync) -->
<div class="packed-header">已装入本箱2项</div>
<div class="packed-item">
<div class="packed-item-row">
<span class="packed-item-info">26BW0015 WO-2026-005</span>
<span class="packed-item-qty">30/30</span>
<button class="icon-btn edit" title="修改">✏️</button>
<button class="icon-btn delete" title="删除">🗑</button>
</div>
</div>
<div class="packed-item">
<div class="packed-item-row">
<span class="packed-item-info">26BW0016 WO-2026-006</span>
<span class="packed-item-qty">50/50</span>
<button class="icon-btn edit" title="修改">✏️</button>
<button class="icon-btn delete" title="删除">🗑</button>
</div>
</div>
<div class="divider"></div>
<!-- Scan Area (waiting) -->
<div class="scan-area waiting">
<span class="scanner-icon">📷</span>
请扫描执行卡二维码
</div>
<div style="height: 10px"></div>
<div class="submit-area">
<div class="submit-qty-col">
<div class="submit-label">数量</div>
<input class="submit-qty-input" disabled />
</div>
<button class="submit-btn disabled">确认</button>
</div>
</div>
<div class="finish-btn-area">
<button class="finish-btn">完成本箱</button>
</div>
<div class="status-bar">
<div class="status-dot orange"></div>
<span class="status-text">正在同步转运数据...</span>
</div>
</div>
</div>
</div>
<!-- 说明文档 -->
<div class="notes-section">
<div class="notes-card">
<h3>状态栏颜色含义</h3>
<div class="color-legend">
<div class="color-legend-item"><div class="color-legend-dot" style="background:#1976d2"></div>蓝色 — 空闲/等待扫码</div>
<div class="color-legend-item"><div class="color-legend-dot" style="background:#ff9800"></div>橙色 — 提交中/同步中</div>
<div class="color-legend-item"><div class="color-legend-dot" style="background:#4caf50"></div>绿色 — 操作成功</div>
<div class="color-legend-item"><div class="color-legend-dot" style="background:#f44336"></div>红色 — 错误(无效码/提交失败)</div>
<div class="color-legend-item"><div class="color-legend-dot" style="background:#fbc02d"></div>黄色 — 网络异常</div>
<div class="color-legend-item"><div class="color-legend-dot" style="background:#ff8f00"></div>琥珀 — 警告(重复箱号)</div>
</div>
</div>
<div class="notes-card">
<h3>多码凑箱模式 UI 结构</h3>
<div class="flow-diagram">┌──────────────────────────────────────────┐
│ AppBar: "装箱编号" + [多码凑箱] 模式按钮 (P2) │
├──────────────────────────────────────────┤
│ [提示条区域] │
│ - 橙色同步条:正在同步转运数据... │
│ - 黄色警告条:自动装箱失败的警告信息 │
│ - 蓝色通知条:排产号已切换 │
│ - 琥珀警告条:箱号已存在 │
├──────────────────────────────────────────┤
│ 当前箱号: [ N ] ← 顶部大号输入框 │
│ ─────────────────────────────────────── │
│ W00009 已有3箱 最大箱号3 [详情 →] │
│ │
│ 已装入本箱N项
│ ┌──────────────────────────────────────┐ │
│ │ 26BW0011 WO-001 80/80 ✏️ 🗑 │ │
│ │ 26BW0012 WO-002 60/60 ✏️ 🗑 │ │
│ │ 26BW0013 WO-003 40/40 ✏️ 🗑 │ │
│ └──────────────────────────────────────┘ │
│ ─────────────────────────────────────── │
│ [✓ 26BW0014 WO-004 50件] ← 扫码显示区 │
│ │
│ 数量 │
│ [ 50 ] [确认] │
├──────────────────────────────────────────┤
│ [ 完成本箱 ] ← 全宽按钮 │
├──────────────────────────────────────────┤
│ ● 等待扫码 / 请继续扫码或完成本箱 │
└──────────────────────────────────────────┘</div>
</div>
<div class="notes-card">
<h3>核心业务流程</h3>
<div class="flow-diagram">多码凑箱流程_buildManyToOneBody:
1. 扫码 → 解析总排号 → 调用 fetchBoxInfo API
2. 判断排产号上下文decideMultiCodePaichanContext
├─ firstScan → 自动填入箱号 (maxBoxNo+1)
├─ samePaichan → 保持当前箱号
└─ switchedPaichan → 清空已装入列表,重置箱号 (maxBoxNo+1)
3. 自动填充剩余数量 → 等待用户确认
├─ 修改箱号 → 清除编辑/删除状态
└─ 修改数量 → 实时校验是否超额
4. 点击 [确认] → saveBoxRecord API
├─ 成功 → 添加到 _manyToOnePackedItems
│ phase 回到 waiting
│ 状态: "装箱成功,请继续扫码"
└─ 失败 → 显示错误状态
5. 继续扫码 / 完成本箱
├─ 继续扫码 → 回到步骤1
└─ 完成本箱 → 清空已装入列表
箱号 +1回到初始状态</div>
</div>
<div class="notes-card">
<h3>与单码装箱模式的差异</h3>
<ul>
<li><strong>UI 布局不同:</strong>多码凑箱使用独立的 <code>_buildManyToOneBody</code>,将箱号提升到顶部大号输入;单码装箱使用 <code>_buildScanArea</code> + <code>_buildInfoArea</code> + <code>_buildInputArea</code> 传统布局。</li>
<li><strong>箱号管理:</strong>多码模式下不检测重复箱号(<code>_boxNoIsDuplicate</code> 对 multiCode 直接返回 false允许多个总排号装入同一箱。</li>
<li><strong>底部按钮:</strong>多码模式显示"完成本箱"按钮OutlinedButton无已分配列表编辑功能单码模式显示"返回"按钮和已分配箱的编辑/删除。</li>
<li><strong>提交成功后行为:</strong>多码模式将结果存入 <code>_manyToOnePackedItems</code> 列表phase 回到 waiting继续扫码单码模式保持在 scanned 阶段,箱号 +1。</li>
<li><strong>排产号切换感知:</strong>多码模式通过 <code>decideMultiCodePaichanContext</code> 检测排产号变化,切换时清空已装入列表并弹出蓝色通知。</li>
</ul>
</div>
<div class="notes-card">
<h3>关键代码引用</h3>
<ul>
<li><strong>模式枚举:</strong><code>BoxingMode.multiCode</code> — boxing_page.dart:18</li>
<li><strong>多码体布局:</strong><code>_buildManyToOneBody()</code> — boxing_page.dart:1656</li>
<li><strong>箱号面板:</strong><code>_buildManyToOneBoxNoPanel()</code> — boxing_page.dart:1679</li>
<li><strong>已装入列表:</strong><code>_buildManyToOnePackedList()</code> — boxing_page.dart:1756</li>
<li><strong>扫码区:</strong><code>_buildManyToOneScanArea()</code> — boxing_page.dart:1898</li>
<li><strong>提交区:</strong><code>_buildManyToOneSubmitArea()</code> — boxing_page.dart:1944</li>
<li><strong>排产号上下文:</strong><code>decideMultiCodePaichanContext()</code> — boxing_context.dart:12</li>
<li><strong>自动填充逻辑:</strong><code>_applyAutoFill()</code> — boxing_page.dart:400</li>
<li><strong>提交成功回调:</strong><code>_onSubmitSuccess()</code> — boxing_page.dart:637</li>
<li><strong>完成本箱:</strong><code>_finishManyToOneBox()</code> — boxing_page.dart:821</li>
<li><strong>状态栏组件:</strong><code>StatusBar</code> — widgets/status_bar.dart:14</li>
</ul>
</div>
<div class="notes-card">
<h3>提示条Alert Bars触发条件</h3>
<ul>
<li><strong style="color:#e65100">橙色同步条</strong>:从转运页自动跳转时,<code>_isAutoProcessing = true</code> 时显示</li>
<li><strong style="color:#ff8f00">黄色警告条</strong>:自动处理中部分总排号失败时,累积在 <code>_autoWarnings</code> 中显示</li>
<li><strong style="color:#0d47a1">蓝色通知条</strong>:排产号切换时,<code>_paichanSwitchNotice</code> 非空时显示</li>
<li><strong style="color:#ff8f00">琥珀重复条</strong>:箱号与已有记录冲突时显示(多码模式下不会触发)</li>
</ul>
</div>
</div>
<script>
function showScenario(id, tab) {
document.querySelectorAll('.phone-wrapper').forEach(el => el.style.display = 'none');
document.querySelectorAll('.scenario-tab').forEach(el => el.classList.remove('active'));
document.getElementById(id).style.display = '';
tab.classList.add('active');
}
</script>
</body>
</html>