索引に戻る

仕掛在庫とリードタイムの価値流れ図

フロー
生成可能
仕掛在庫とリードタイムの価値流れ図

作品として見る

持ち帰る

コピーして貼るか、ファイルに保存して渡す。ネットにつながらない環境には「全部入り」を 1 つ渡せば足りる。

全部入り

value-stream-map-everything.md

このパネルの中身を、URL の先にあるファイルの中身まで含めて 1 つにまとめた Markdown

依頼文

2.3 KB
「仕掛在庫とリードタイムの価値流れ図」でHTML資料を作ってください。この型は実行できるので、版面を組み直す必要はありません — 必要なのは中身です。

## この型がすること
工程別サイクルタイム・段取・稼働条件と工程間在庫を並べ、顧客需要から算出するタクトに対して、付加価値時間と在庫換算の待ちを分けて読む。

## 渡す必要があるもの
- 一勤務あたりの顧客需要と正味稼働時間を同じ時間単位で示す。タクトは稼働時間÷需要で導出する。
- 3〜8工程のサイクル・段取時間、稼働率、担当人数と、隣接工程間の仕掛在庫を順序どおりに指定する。

## 入力の形
- `title` — string — 処理時間と滞留の違いを伝える見出し
- `subtitle` — string? — 対象製品・期間・生産条件
- `timeUnit` — string — 時間値の共通単位
- `demandPerShift` — number — 一勤務あたりの顧客需要量
- `netAvailableTime` — number — 一勤務あたりの正味稼働時間
- `operations` — array (id, label, cycleTime, changeoverTime, uptimePercent, operators) — 3〜8工程
- `buffers` — array (id, afterOperationId, label, inventoryUnits) — 各隣接工程間の仕掛在庫。待ち時間は在庫÷需要×正味稼働時間

入力の機械可読な検証は schema.ts が持ちます。足りない入力は推測せず質問してください。

## 向かない場合
- 工程順・分岐だけを簡潔に示す場合はprocess-flowを使う。仕掛在庫やタクトはこの契約には含まれない。
- 工程の前後関係や開始・終了境界だけを概観する場合はSIPOCを使う。ここでは在庫・時間の定量値を要する。

## 作り方
入力を JSON にまとめ、次を実行します。

```bash
node scripts/render.mjs value-stream-map <入力.json> --theme ink -o out.html
```

出力は 1 ファイルで完結し、外部から何も読み込みません。

## 原本
- https://design-vault.pages.dev/designs/value-stream-map/source/template.tsx
- https://design-vault.pages.dev/designs/value-stream-map/source/schema.ts
- https://design-vault.pages.dev/designs/value-stream-map/source/sample-data.json
- https://design-vault.pages.dev/designs/value-stream-map/sample.html

ファイル

テンプレート・入力スキーマ・サンプルデータ・メタ情報。この文書はこの 4 つから生成されています。 生成された文書

template.tsx

9.9 KB

/designs/value-stream-map/source/template.tsx

中身を見る
import type { Props } from "./schema";

const CSS = String.raw`
.asset{font-family:var(--font-sans);color:var(--color-on-surface);background:var(--color-surface);max-width:var(--container-slide);margin:auto;padding:2.25rem 2.5rem;line-height:1.5}.asset *{box-sizing:border-box}.asset h1{font-size:var(--text-h1);line-height:1.3;margin:0}.asset .subtitle{color:var(--color-secondary);margin:.6rem 0 1.25rem}.asset .eyebrow{font:600 var(--text-label) var(--font-mono);letter-spacing:.1em;color:var(--color-tertiary)}.asset .plot{display:block;width:100%;height:auto}.asset .plot text{font-family:var(--font-sans);font-size:12px;fill:var(--color-secondary)}.asset .plot .ink{fill:var(--color-on-surface)}.asset .summary{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.75rem;margin:1rem 0 1.5rem}.asset .metric{padding:.8rem;background:var(--color-surface-subtle);border-top:3px solid var(--color-tertiary);min-width:0}.asset .metric dt{font-size:var(--text-label);color:var(--color-secondary)}.asset .metric dd{margin:.25rem 0 0;font:700 var(--text-h3) var(--font-mono);overflow-wrap:anywhere}.asset .ledger{border-collapse:collapse;width:100%;font-variant-numeric:tabular-nums}.asset .ledger th,.asset .ledger td{text-align:left;vertical-align:top;padding:.65rem .75rem;border-bottom:1px solid var(--color-outline);overflow-wrap:anywhere}.asset .ledger th{color:var(--color-secondary)}.asset .ledger .mono{font-family:var(--font-mono)}.asset details{margin-top:1rem}.asset summary{cursor:pointer;min-height:2.75rem;padding:.5rem 0;color:var(--color-secondary)}.asset .note{border-left:3px solid var(--color-outline);padding:.75rem 1rem;color:var(--color-secondary)}
@media(max-width:760px){.asset{padding:1.5rem 1rem}.asset h1{font-size:var(--text-h2)}.asset .summary{grid-template-columns:1fr 1fr}.asset .ledger,.asset .ledger tbody,.asset .ledger tr,.asset .ledger td{display:block}.asset .ledger thead{display:none}.asset .ledger tr{padding:.65rem 0;border-bottom:1px solid var(--color-outline)}.asset .ledger td{display:grid;grid-template-columns:9rem minmax(0,1fr);gap:.75rem;border:0;padding:.2rem 0}.asset .ledger td:before{content:attr(data-label);font-size:var(--text-label);color:var(--color-secondary)}.asset-value-stream-map .plot{display:none}}
`;

type Operation = Props["operations"][number];
type Buffer = Props["buffers"][number];
const fmt = (value: number) => Number.isInteger(value) ? value.toLocaleString("ja-JP") : value.toLocaleString("ja-JP", { maximumFractionDigits: 3 });
const waitFor = (buffer: Buffer, data: Props) => buffer.inventoryUnits / data.demandPerShift * data.netAvailableTime;
const shorten = (value: string, size = 20) => [...value].length > size ? [...value].slice(0, size - 1).join("") + "…" : value;

export default function Template(d: Props) {
  const takt = d.netAvailableTime / d.demandPerShift;
  const valueAdded = d.operations.reduce((sum, operation) => sum + operation.cycleTime, 0);
  const waiting = d.buffers.reduce((sum, buffer) => sum + waitFor(buffer, d), 0);
  const leadTime = valueAdded + waiting;
  const bottleneck = [...d.operations].sort((a, b) => b.cycleTime - a.cycleTime)[0];
  const xAt = (index: number) => 42 + index * 150;
  const bufferAfter = (operation: Operation) => d.buffers.find(buffer => buffer.afterOperationId === operation.id)!;
  const waitWidth = leadTime ? waiting / leadTime * 920 : 0;
  return <section className="asset asset-value-stream-map">
    <style>{CSS}</style>
    <header>
      <p className="eyebrow">VALUE STREAM MAP / LEAD TIME AND FLOW</p>
      <h1>{d.title}</h1>
      {d.subtitle && <p className="subtitle">{d.subtitle}</p>}
    </header>
    <svg className="plot" data-layout-still="true" width="1280" height="720" viewBox="0 0 1280 720" role="img" aria-labelledby="vsm-title vsm-desc" fontFamily="sans-serif" fontSize="12" fill="var(--color-secondary)">
      <title id="vsm-title">{d.title}</title>
      <desc id="vsm-desc">顧客需要 {fmt(d.demandPerShift)} 個/勤務、タクト {fmt(takt)} {d.timeUnit}。工程処理時間 {fmt(valueAdded)} {d.timeUnit}、在庫換算の待ち {fmt(waiting)} {d.timeUnit}、総リードタイム {fmt(leadTime)} {d.timeUnit}。</desc>
      <rect x="0" y="0" width="1280" height="720" fill="var(--color-surface)" />
      <text x="54" y="35" fontSize="13" fontWeight="700" letterSpacing="2" fill="var(--color-tertiary)">VALUE STREAM MAP</text>
      <text x="54" y="70" fontSize="21" fontWeight="700" fill="var(--color-on-surface)">{d.title}</text>
      <text x="54" y="108">顧客需要 {fmt(d.demandPerShift)} 個 / 勤務  正味稼働 {fmt(d.netAvailableTime)} {d.timeUnit} / 勤務  タクト {fmt(takt)} {d.timeUnit} / 個</text>
      <text x="42" y="155" fontWeight="700" fill="var(--color-on-surface)">工程間在庫 → 需要と稼働時間から待ちを換算</text>
      {d.buffers.map((buffer, index) => {
        const x = xAt(index) + 136;
        return <g key={buffer.id} data-vsm-record={buffer.id}>
          <polygon points={`${x},180 ${x - 13},204 ${x + 13},204`} fill="var(--color-secondary)" />
          <text x={x} y="220" textAnchor="middle" fontSize="10">{fmt(buffer.inventoryUnits)}個</text>
          <text x={x} y="237" textAnchor="middle" fontSize="10">待ち {fmt(waitFor(buffer, d))}{d.timeUnit}</text>
        </g>;
      })}
      {d.operations.map((operation, index) => {
        const x = xAt(index);
        const y = 266;
        const queue = index < d.operations.length - 1 ? bufferAfter(operation) : undefined;
        return <g key={operation.id} data-vsm-record={operation.id}>
          <rect x={x} y={y} width="122" height="151" fill="var(--color-surface)" stroke={operation.id === bottleneck.id ? "var(--color-tertiary)" : "var(--color-outline)"} strokeWidth={operation.id === bottleneck.id ? 2.5 : 1.2} />
          <rect x={x} y={y} width="122" height="7" fill={operation.id === bottleneck.id ? "var(--color-tertiary)" : "var(--color-outline)"} />
          <text x={x + 8} y={y + 31} fontSize="13" fontWeight="700" fill="var(--color-on-surface)">P{String(index + 1).padStart(2, "0")}</text>
          <text x={x + 8} y={y + 72} fontSize="9" fill={operation.cycleTime > takt ? "var(--color-tertiary)" : "var(--color-secondary)"}>C/T {fmt(operation.cycleTime)}</text>
          <text x={x + 8} y={y + 91} fontSize="9">Takt {fmt(takt)}</text>
          <text x={x + 8} y={y + 110} fontSize="9">段取 {fmt(operation.changeoverTime)}</text>
          <text x={x + 8} y={y + 130} fontSize="9">稼働 {fmt(operation.uptimePercent)}%/{operation.operators}人</text>
          {queue && <g>
            <line x1={x + 122} y1="430" x2={x + 145} y2="430" stroke="var(--color-tertiary)" strokeWidth="2" />
            <path d={`M ${x + 138} 425 L ${x + 145} 430 L ${x + 138} 435`} fill="none" stroke="var(--color-tertiary)" strokeWidth="2" />
          </g>}
        </g>;
      })}
      <line x1="54" y1="462" x2="1225" y2="462" stroke="var(--color-outline)" />
      <text x="54" y="491" fontWeight="700" fill="var(--color-on-surface)">総リードタイム内訳</text>
      <text x="54" y="528">待ち / 在庫換算</text>
      <rect x="245" y="510" width={waitWidth} height="24" fill="var(--color-secondary)" />
      <rect x={245 + waitWidth} y="510" width={920 - waitWidth} height="24" fill="var(--color-tertiary)" />
      <text x="245" y="557">待ち {fmt(waiting)} {d.timeUnit}</text>
      <text x="720" y="557">処理 {fmt(valueAdded)} {d.timeUnit}</text>
      <text x="54" y="596" fontWeight="700" fill="var(--color-on-surface)">総リードタイム {fmt(leadTime)} {d.timeUnit} | 付加価値時間 {leadTime ? fmt(valueAdded / leadTime * 100) : 0}% | 最長処理 {shorten(bottleneck.label)}</text>
      <text x="54" y="635">段取時間・稼働率・担当人数は工程条件。仕掛在庫の待ち換算は需要一定を前提とする。</text>
      <text x="54" y="675">工程順、個別実績、境界条件は下の台帳を参照。</text>
    </svg>
    <dl className="summary">
      <div className="metric"><dt>タクトタイム</dt><dd>{fmt(takt)} {d.timeUnit} / 個</dd></div>
      <div className="metric"><dt>付加価値処理</dt><dd>{fmt(valueAdded)} {d.timeUnit}</dd></div>
      <div className="metric"><dt>在庫換算の待ち</dt><dd>{fmt(waiting)} {d.timeUnit}</dd></div>
      <div className="metric"><dt>総リードタイム</dt><dd>{fmt(leadTime)} {d.timeUnit}</dd></div>
    </dl>
    <p className="note">タクトは正味稼働時間÷顧客需要です。バッファの待ちは在庫量を一定需要で時間換算します。需要変動・故障・工程間の相互依存はこの現在状態図に含みません。</p>
    <details open>
      <summary>工程・工程間在庫のデータを確認({d.operations.length + d.buffers.length}件)</summary>
      <table className="ledger"><thead><tr><th>順序 / 項目</th><th>処理・在庫</th><th>段取・待ち</th><th>稼働条件</th></tr></thead>
        <tbody>
          {d.operations.map((operation, index) => <tr key={operation.id} data-vsm-record={operation.id}>
            <td data-label="順序 / 項目">工程 {index + 1} / {operation.label}</td><td data-label="処理・在庫" className="mono">C/T {fmt(operation.cycleTime)} {d.timeUnit}</td><td data-label="段取・待ち" className="mono">段取 {fmt(operation.changeoverTime)} {d.timeUnit}</td><td data-label="稼働条件">稼働 {fmt(operation.uptimePercent)}% ・ {operation.operators}人{operation.cycleTime > takt ? " ・ タクト超過" : ""}</td>
          </tr>)}
          {d.buffers.map((buffer, index) => <tr key={buffer.id} data-vsm-record={buffer.id}>
            <td data-label="順序 / 項目">工程{index + 1}後 / {buffer.label}</td><td data-label="処理・在庫" className="mono">{fmt(buffer.inventoryUnits)}個</td><td data-label="段取・待ち" className="mono">待ち {fmt(waitFor(buffer, d))} {d.timeUnit}</td><td data-label="稼働条件">需要 {fmt(d.demandPerShift)}個 / 勤務</td>
          </tr>)}
        </tbody>
      </table>
    </details>
  </section>;
}

schema.ts

2.5 KB

/designs/value-stream-map/source/schema.ts

中身を見る
import { z } from "zod";

const text = z.string().trim().min(1).max(160);
const label = z.string().trim().min(1).max(30);
const id = z.string().trim().min(1).max(24);
const finite = z.number().finite();

const operation = z.object({
  id: id.describe("工程の一意なID"),
  label: label.describe("工程名"),
  cycleTime: finite.positive().describe("一単位あたりの処理時間。timeUnitと同じ単位"),
  changeoverTime: finite.nonnegative().describe("品種切替え時間。timeUnitと同じ単位"),
  uptimePercent: finite.min(0).max(100).describe("稼働可能時間の割合"),
  operators: z.number().int().min(1).max(50).describe("工程の標準担当人数"),
}).strict();
const buffer = z.object({
  id: id.describe("工程間バッファの一意なID"),
  afterOperationId: id.describe("仕掛在庫の直前にある工程ID"),
  label: label.describe("仕掛・待ち行列の名前"),
  inventoryUnits: finite.nonnegative().describe("次工程の前に滞留する在庫個数"),
}).strict();
const unique = (values: string[]) => new Set(values).size === values.length;

export const schema = z.object({
  title: text.describe("処理時間と滞留の違いを伝える見出し"),
  subtitle: text.optional().describe("対象製品・期間・生産条件"),
  timeUnit: z.string().trim().min(1).max(12).describe("時間値の共通単位"),
  demandPerShift: finite.positive().describe("一勤務あたりの顧客需要量"),
  netAvailableTime: finite.positive().describe("一勤務あたりの正味稼働時間。timeUnitと同じ単位"),
  operations: z.array(operation).min(3).max(8).describe("価値付加処理の順序と工程別データ"),
  buffers: z.array(buffer).min(2).max(7).describe("隣接工程間の仕掛在庫"),
}).strict().superRefine((data, ctx) => {
  if (data.buffers.length !== data.operations.length - 1) {
    ctx.addIssue({ code: "custom", path: ["buffers"], message: "隣接する各工程間にバッファを一つずつ設定" });
  }
  data.buffers.forEach((item, index) => {
    if (data.operations[index]?.id !== item.afterOperationId) {
      ctx.addIssue({ code: "custom", path: ["buffers", index, "afterOperationId"], message: "バッファは対応する直前工程の直後に並ぶ" });
    }
  });
  if (!unique([...data.operations.map(item => item.id), ...data.buffers.map(item => item.id)])) {
    ctx.addIssue({ code: "custom", path: ["operations"], message: "工程とバッファのIDはすべて一意" });
  }
});

export type Props = z.infer<typeof schema>;

meta.yaml

3.0 KB

/designs/value-stream-map/source/meta.yaml

中身を見る
id: value-stream-map
name:
  ja: 仕掛在庫とリードタイムの価値流れ図
  en: Value Stream Map with WIP and Lead Time
purpose:
  ja: 工程別サイクルタイム・段取・稼働条件と工程間在庫を並べ、顧客需要から算出するタクトに対して、付加価値時間と在庫換算の待ちを分けて読む。
  en: Map process cycle, changeover and uptime alongside inter-process inventory, then separate value-added time from demand-based waiting against takt.
status: published
still: ./still.png
category: operations
catalogOrder: 840
jobs:
  - prioritize-diagnose
  - plan-sequence
useCases:
  - process
  - prioritization
layoutKinds:
  - flow
tags:
  - value-stream-map
  - lean-operations
  - takt-time
  - work-in-process
  - offline
  - responsive
whenToUse:
  - ja: 顧客需要に必要なタクトと工程別処理能力を比べ、在庫が積み上がる箇所や待ち時間の大きい区間を見つける。
    en: Use to compare process capacity with demand-based takt and locate inventory buildup or long waits.
  - ja: リードタイム全体のうち実際の処理時間が占める割合を示し、改善対象を選ぶ。
    en: Use to separate processing time from total lead time when choosing where to improve.
avoidWhen:
  - ja: 工程順・分岐だけを簡潔に示す場合はprocess-flowを使う。仕掛在庫やタクトはこの契約には含まれない。
    en: Use process-flow for simple step order and branching without WIP and takt analysis.
  - ja: 工程の前後関係や開始・終了境界だけを概観する場合はSIPOCを使う。ここでは在庫・時間の定量値を要する。
    en: Use SIPOC for a high-level boundary overview; this layout requires quantified inventory and time values.
requiredInputs:
  - ja: 一勤務あたりの顧客需要と正味稼働時間を同じ時間単位で示す。タクトは稼働時間÷需要で導出する。
    en: Provide customer demand and net available time per shift in the same time unit; takt is derived as available time divided by demand.
  - ja: 3〜8工程のサイクル・段取時間、稼働率、担当人数と、隣接工程間の仕掛在庫を順序どおりに指定する。
    en: Supply cycle and changeover time, uptime, and operators for three to eight ordered processes, plus WIP for every adjacent process pair.
relatedLayouts:
  - process-flow
  - sipoc-overview
  - critical-path-gantt
dataSchema:
  title: string — 処理時間と滞留の違いを伝える見出し
  subtitle: string? — 対象製品・期間・生産条件
  timeUnit: string — 時間値の共通単位
  demandPerShift: number — 一勤務あたりの顧客需要量
  netAvailableTime: number — 一勤務あたりの正味稼働時間
  operations: array (id, label, cycleTime, changeoverTime, uptimePercent, operators) — 3〜8工程
  buffers: array (id, afterOperationId, label, inventoryUnits) — 各隣接工程間の仕掛在庫。待ち時間は在庫÷需要×正味稼働時間
sources: []

sample-data.json

1.2 KB

/designs/value-stream-map/source/sample-data.json

中身を見る
{
  "title": "滞留在庫が処理時間より長いリードタイムを生む",
  "subtitle": "架空サンプル|電子部品の受注組立ライン・1勤務あたりの顧客需要",
  "timeUnit": "時間",
  "demandPerShift": 300,
  "netAvailableTime": 7.5,
  "operations": [
    { "id": "p-receive", "label": "部品と受注仕様を照合", "cycleTime": 0.018, "changeoverTime": 0.04, "uptimePercent": 96, "operators": 1 },
    { "id": "p-prepare", "label": "基板と部材を準備", "cycleTime": 0.025, "changeoverTime": 0.08, "uptimePercent": 94, "operators": 2 },
    { "id": "p-assemble", "label": "基板へ部品を実装", "cycleTime": 0.04, "changeoverTime": 0.12, "uptimePercent": 91, "operators": 3 },
    { "id": "p-inspect", "label": "通電と外観を検査", "cycleTime": 0.02, "changeoverTime": 0.03, "uptimePercent": 98, "operators": 1 }
  ],
  "buffers": [
    { "id": "b01", "afterOperationId": "p-receive", "label": "部材確認後の仕掛", "inventoryUnits": 48 },
    { "id": "b02", "afterOperationId": "p-prepare", "label": "実装待ち基板", "inventoryUnits": 30 },
    { "id": "b03", "afterOperationId": "p-assemble", "label": "検査待ち完成品", "inventoryUnits": 60 }
  ]
}