#49スコア 4.5/5物流・倉庫

AI に出荷梱包を作らせてみた — 3つの画面が同じ2段スキャンを手組みしたので、ScanGate を起こした(やってみた #49)

ルート: /shipping
デスクトップ表示
モバイル表示

375px のビューポートで撮影。縦長のページはフレーム内をスクロールします。

解説記事

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 採用・scanStage machine を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 ごとに ScanInputkey で 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 はもちろん、DeltaEditableDataTableRevealSectionCheckbox(最終検品チェックリスト)・Progresstone(前回 #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 が組み上げた実コード

ファイル名をクリックでソースを展開できます。