AI に出荷梱包を作らせてみた — 3つの画面が同じ2段スキャンを手組みしたので、ScanGate を起こした(やってみた #49)
/shipping375px のビューポートで撮影。縦長のページはフレーム内をスクロールします。
解説記事
AI に出荷梱包を作らせてみた — 3つの画面が同じ2段スキャンを手組みしたので、ScanGate を起こした(やってみた #49)
やってみたシリーズ: 自作のデザインシステム
@gunjo/ui(群青)を、文脈ゼロの cold な AI に実 UI で作らせる連載。物流/倉庫(WMS)3枚目——出荷検品 / 梱包(出荷照合 × カートン→商品の2段スキャン × カートン管理/重量 × 最終検品 × 配送ラベル)。
#47 ピッキング(取り出す)・#48 入庫(格納する)に続く出荷側。ピッキング済みを箱詰め前に照合し、カートン(箱)をスキャンして開き → 商品をスキャンして詰める——カートン→商品の2段スキャン。出荷の作法。
結果 — 4.5/5(tsc/build 緑・全 primitive 採用)
tsc/build 緑・console 0・375px ハンディプライマリ・カートンスキャン→開封→商品スキャンで梱包+1・カートン未開封で商品スキャンは「先にカートンを」プロンプト・過剰梱包阻止・重量/配送業者ゲート・出荷確定で read-only サマリ。
※ 今回 cold AI の最終レポートはセッション制限で返らなかったが、退避した画面コードを検証して主要シグナルを確認した(tsc/build 緑・全 primitive 採用・
scanStagemachine を26箇所で手組み)。
今回の本題 — 3画面が同じ2段スキャンを手組みした → ScanGate を起こす
物流の3画面すべてが、同じ2段スキャンゲートを scanStage ステートマシンで手組みしていた。しかも順序がバラバラなのに同じ形:
#47 ピッキング: location → item(棚を確認してから商品)
#48 入庫 : item → location(商品を読んで推奨棚へ・逆順)
#49 出荷梱包 : carton → item(箱を開いてから商品を詰める)
順序が3通り違っても、本質は同じ——「scan して確定(context)→ 次の stage が context を読んで scan してカウント」。毎回 scanStage/activeCartonId を手で書き、stage ごとに ScanInput を key で remount し、auto-focus を配線していた。3回ルール発火で ScanGate(#227)(PR #232)を出荷:
<ScanGate
stages={[
{ id: "carton", label: "① カートンをスキャン", onScan: (code) => {
const c = openCarton(code)
return c ? { ok: true, message: `${code} を開きました`, advance: "next", value: c }
: { ok: false, message: "見つかりません", advance: "stay" }
}},
{ id: "item", label: "② 商品をスキャン", onScan: (code, ctx) => {
const line = pack(code, ctx.values.carton) // 前 stage の確定 context を読む
return line ? { ok: true, message: `${line.name} を梱包`, advance: "stay" }
: { ok: false, message: "受注に無い商品", advance: "stay" }
}},
]}
/>
- 各 stage の
onScan(code, ctx)が{ ok, message, advance, value }を返す。advance("next"/"stay"/"reset"/stage id)が machine を駆動、valueは stage id で記憶され次の stage がctx.values[stageId]で読む。 - stage 間で自動 advance+自動 focus(スキャンガンのループ)。最終 stage の
"next"は先頭に wrap+context クリア=1サイクル完了。 - 番号付き step indicator(done/active/todo)+ imperative
refハンドル(reset/goTo/getValues)で「カートンを閉じる」「次のロケーションへ」ボタン。 - 読み上げ・debounce・feed は
ScanInputから継承。
ブラウザ実証: カートン CTN-001 スキャン→ carton→item に advance+context 保存→商品スキャンで「デスクライト LED を CTN-001 に梱包(1/3)」(context のカートンを参照)→ stay で連続梱包→「閉じる」ボタンの ref.reset() で stage 1+context クリア。
複利も全部効いた
ScanGate の土台 ScanInput はもちろん、Delta・EditableDataTable・RevealSection・Checkbox(最終検品チェックリスト)・Progress の tone(前回 #48 で追加)・CardTitle as——全部発掘・採用。前々回・前回の投資が出荷画面でも返ってきた。
学び — 「順序が違っても同じ形」は、合成 primitive のサイン
location→item / item→location / carton→item = 順序は違うが同じ2段ゲート
→ 抽象は「stage 配列+per-stage resolver+確定 context+auto-advance」
3画面が表面上は違う作法(ピッキング/入庫/出荷)なのに、同じ合成構造を手組みしていた。これこそ「上位協調 primitive」が隠れているサイン——個別の glue が3回、形を変えて再発したら、それは抽象を1つ作るべき合図。ScanInput(単発スキャン)を3画面で作り切った上に、その段階合成を ScanGate として括り出した。primitive は2層になった。
次回予告(やってみた #50)
- 在庫ロケーション管理 / 棚卸移動(容量 Meter#230 を2回目確認へ)。方針: 1業界3〜5枚・可能な限り違う内容・業界特有UI最優先。
試す
まだ alpha。3画面が同じ2段スキャンを手組みしたので、段階合成を ScanGate として括り出した回。
<!-- 公開前: 相互URL差込/スクショ確定/EN(dev.to)ミラー -->
使用した @gunjo/ui コンポーネント
この画面のソースが直接 import している部品です。
cold AI が組み上げた実コード
ファイル名をクリックでソースを展開できます。