配送ルートRouteStopsBeta
配送や輸送の停止地点を、現在地、完了、遅延、不在などの状態付きタイムラインで表示します。
プレビュー
- 佐藤 一郎完了2個
東京都渋谷区神南 1-2-3
予定 09:30実績 09:282分早着 - 鈴木 商店完了5個
東京都渋谷区宇田川町 4-5
予定 09:50実績 09:588分遅れ - 3高橋 花子配送中現在地1個
東京都渋谷区道玄坂 2-6-7
予定 10:15実績 10:216分遅れ - 田中 工業不在3個
東京都渋谷区桜丘町 8-9
予定 10:40 - 山田 太郎遅延1個
東京都目黒区上目黒 1-1
予定 11:0018分遅れ - 6伊藤 ストア未配4個
東京都目黒区中目黒 3-2
予定 11:25
状態とバリエーション
当日配送
予定/実績時刻と遅延を同じ停止地点に表示します。
- 佐藤 一郎完了2個
東京都渋谷区神南 1-2-3
予定 09:30実績 09:282分早着 - 鈴木 商店完了5個
東京都渋谷区宇田川町 4-5
予定 09:50実績 09:588分遅れ - 3高橋 花子配送中現在地1個
東京都渋谷区道玄坂 2-6-7
予定 10:15実績 10:216分遅れ - 田中 工業不在3個
東京都渋谷区桜丘町 8-9
予定 10:40 - 山田 太郎遅延1個
東京都目黒区上目黒 1-1
予定 11:0018分遅れ - 6伊藤 ストア未配4個
東京都目黒区中目黒 3-2
予定 11:25
複数日の輸送追跡
dateLabel を使うと HH:MM ではなく日付またぎの追跡にできます。
- 輸出通関完了
上海港 (CNSHA)
2026/05/12 許可
- 船積完了
本船 EVER BLUE / V.0PA21
2026/05/15
- 3海上輸送進行中現在地
上海 → 東京
2026/05/16 - 05/29(航行中)
- 4着港未着手
東京港 (JPTYO)
ETA 2026/05/30
- 5国内配送・納品未着手
江東区 物流センター
予定 2026/06/05
時刻なし
状態の順序だけを見せたい一覧では hideTimes を使います。
- 佐藤 一郎完了2個
東京都渋谷区神南 1-2-3
- 鈴木 商店完了5個
東京都渋谷区宇田川町 4-5
- 3高橋 花子配送中現在地1個
東京都渋谷区道玄坂 2-6-7
- 田中 工業不在3個
東京都渋谷区桜丘町 8-9
- 山田 太郎遅延1個
東京都目黒区上目黒 1-1
- 6伊藤 ストア未配4個
東京都目黒区中目黒 3-2
プロパティ
表は横にスクロールできます
| プロパティ | 型 | 初期値 | 説明 |
|---|---|---|---|
| stops | RouteStopItem[] | - | 停止地点の順序付き配列です。id/title/status/time/meta/actions を含みます。 |
| RouteStopItem.status | "pending" | "current" | "completed" | "failed" | "delayed" | - | マーカー、バッジ、current の aria-current を決めます。 |
| plannedTime / actualTime | "HH:MM" | - | 当日配送向けの予定/実績時刻です。両方ある場合は遅延を計算します。 |
| delayMinutes | number | - | 明示的な遅延分です。正は遅れ、負は早着です。 |
| dateLabel | ReactNode | - | 複数日・複数週の輸送追跡で使う自由形式の日付行です。 |
| actions | ReactNode | - | 停止地点ごとの状態更新などの操作です。 |
| statusLabels / currentLabel | localized labels | - | 状態バッジと現在地ラベルを上書きします。既定は中立語彙(未着手 / 進行中 / 完了 / 失敗 / 遅延)で、ドメインごとに上書きします(配送=未配 / 配送中 / 不在 など)。(#282) |
| timeLabels / delayLabels / formatDelay | localized labels | - | 予定/実績/遅延の表示をローカライズします。 |
| hideTimes | boolean | false | 時刻や遅延行を隠します。 |
使い方
import * as React from "react";
import { Button, RouteStops, type RouteStopItem } from "@gunjo/ui";
const baseStops: RouteStopItem[] = [
{ id: "1", title: "佐藤 一郎", description: "東京都渋谷区神南 1-2-3", status: "completed", plannedTime: "09:30", actualTime: "09:28", meta: "2個" },
{ id: "2", title: "鈴木 商店", description: "東京都渋谷区宇田川町 4-5", status: "completed", plannedTime: "09:50", actualTime: "09:58", meta: "5個" },
{ id: "3", title: "高橋 花子", description: "東京都渋谷区道玄坂 2-6-7", status: "current", plannedTime: "10:15", actualTime: "10:21", meta: "1個" },
{ id: "4", title: "田中 工業", description: "東京都渋谷区桜丘町 8-9", status: "failed", plannedTime: "10:40", meta: "3個" },
{ id: "5", title: "山田 太郎", description: "東京都目黒区上目黒 1-1", status: "delayed", plannedTime: "11:00", delayMinutes: 18, meta: "1個" },
{ id: "6", title: "伊藤 ストア", description: "東京都目黒区中目黒 3-2", status: "pending", plannedTime: "11:25", meta: "4個" },
];
export function DeliveryRoute() {
const [currentOutcome, setCurrentOutcome] = React.useState<"active" | "completed" | "failed">("active");
const stops = baseStops.map((stop) => {
if (stop.id === "3") {
return {
...stop,
status: currentOutcome === "completed" ? "completed" as const : currentOutcome === "failed" ? "failed" as const : "current" as const,
actions: currentOutcome === "active" ? (
<>
<Button type="button" size="sm" variant="outline" onClick={() => setCurrentOutcome("completed")}>
完了
</Button>
<Button type="button" size="sm" variant="ghost" onClick={() => setCurrentOutcome("failed")}>
不在
</Button>
</>
) : undefined,
};
}
if (currentOutcome !== "active" && stop.id === "4") return { ...stop, status: "current" as const };
return stop;
});
return (
<div className="flex w-full max-w-md flex-col rounded-lg border bg-card p-4">
<RouteStops stops={stops} currentLabel="現在地" timeLabels={{ planned: "予定", actual: "実績" }} />
</div>
);
}