// kpi.jsx — 画面4: KPI ダッシュボード (22シートExcel置換) function KPI({ chartKind = 'line' /* line | bar | area */ }) { // ── Channel funnel (horizontal bars) ────────────────────────── const Funnel = () => { const maxFlow = Math.max(...CHANNEL_FUNNEL.map((c) => c.flow)); const stages = [ { k: 'flow', label: '流入' }, { k: 'visit', label: '見学' }, { k: 'brief', label: '説明会' }, { k: 'applied', label: '申込' }, { k: 'enrolled', label: '入学' }]; return (

流入チャネル別ファネル

過去30日
{/* Header row */}
チャネル
流入 → 入学
{stages.slice(1).map((s) =>
{s.label}
)}
{CHANNEL_FUNNEL.map((ch) => { const ratio = ch.enrolled / ch.flow; const sa = (k) => Math.max(8, ch[k] / maxFlow * 100); return (
{ch.name}
0.18 ? '#7A9F7E' : ratio < 0.12 ? '#C9536A' : '#5D3848' }}>{(ratio * 100).toFixed(1)}% 入学率
{/* Stacked funnel: 5 nested bars right-shifted, descending width */}
{stages.map((s, i) =>
{ch[s.k]}
)}
{stages.slice(1).map((s) => { const prev = stages[stages.findIndex((x) => x.k === s.k) - 1].k; const conv = ch[s.k] / ch[prev]; return (
0.6 ? 'text-okgreen' : conv < 0.4 ? 'text-alert' : 'text-ink2'}`}> {(conv * 100).toFixed(0)}%
); })}
); })}
紹介 が最高転換 (47.6%入学率) — 紹介報酬制度の Phase 2 着手で更に伸長見込 合計流入 427名
); }; // ── Sales chart (line / bar / area) ─────────────────────────── const SalesChart = () => { const w = 640,h = 240,pad = { l: 36, r: 16, t: 16, b: 28 }; const cw = w - pad.l - pad.r,ch = h - pad.t - pad.b; const months = MONTHLY_SALES; const schools = [ { id: 'umeda', name: '梅田福島', color: '#B5728C' }, { id: 'kyobashi', name: '京橋', color: '#D89AAA' }, { id: 'shinsai', name: '心斎橋', color: '#C9A98C' }, { id: 'namba', name: '難波', color: '#9A8EAA' }, { id: 'kobe', name: '神戸', color: '#7A9F7E' }, { id: 'shinjuku', name: '新宿', color: '#D6A172' }]; const max = 2200; const xAt = (i) => pad.l + i / (months.length - 1) * cw; const yAt = (v) => pad.t + ch - v / max * ch; const total = months.reduce((sum, m) => sum + schools.reduce((s, sc) => s + m[sc.id], 0), 0); const totalLast = schools.reduce((s, sc) => s + months[months.length - 1][sc.id], 0); const totalPrev = schools.reduce((s, sc) => s + months[months.length - 2][sc.id], 0); const growthPct = ((totalLast - totalPrev) / totalPrev * 100).toFixed(1); return (

校舎別売上推移

過去6ヶ月(万円)
¥{(totalLast * 10).toLocaleString()}
5月 +{growthPct}% vs 前月
{/* grid */} {[0, 500, 1000, 1500, 2000].map((v) => {v} )} {/* x labels */} {months.map((m, i) => {m.month.slice(5)} )} {chartKind === 'bar' && (() => { const bw = cw / months.length / (schools.length + 1); return months.map((m, i) => {schools.map((sc, j) => { const x = xAt(i) - schools.length * bw / 2 + j * bw; const y = yAt(m[sc.id]); return ; })} ); })()} {chartKind !== 'bar' && schools.map((sc) => { const pts = months.map((m, i) => `${xAt(i)},${yAt(m[sc.id])}`).join(' '); if (chartKind === 'area') { const areaPath = `M ${xAt(0)},${yAt(0)} L ${pts.split(' ').join(' L ')} L ${xAt(months.length - 1)},${yAt(0)} Z`; return ( {months.map((m, i) => )} ); } return ( {months.map((m, i) => )} ); })} {/* highlight latest umeda */} 梅田 2,080
{schools.map((sc) =>
{sc.name} {months[months.length - 1][sc.id]}
)}
); }; // ── Course mix (donut) ──────────────────────────────────────── const Donut = () => { const total = COURSE_MIX.reduce((s, c) => s + c.students, 0); const r = 64,sw = 22,cx = 90,cy = 90; const circumference = 2 * Math.PI * r; let offset = 0; return (

コース別構成

在籍 {total}名
{COURSE_MIX.map((c, i) => { const dash = c.share * circumference; const seg = ; offset += dash; return seg; })} {total} 在籍合計
{COURSE_MIX.map((c) =>
{c.name} {(c.share * 100).toFixed(0)}% {c.students}名
)}
平均単価 ¥327,800 · LTV ¥4.2億 / 年
); }; // ── Rescue simulation hero ──────────────────────────────────── const RescueHero = () =>
取りこぼし救済シミュレーション
3 日未連絡アラートの稼働で、月平均
3 件 救済 +¥855,000 / 月
過去90日で「説明会後3日以上未連絡」かつ離脱したケース:月平均9名。うち平均単価¥285,000を母数に、過去類似ケースの再アプローチ成功率33%を適用。
年換算
+¥10.26M
; // ── Time savings tile ───────────────────────────────────────── const TimeSavings = () =>
作業時間削減
10–20 時間 / 月
22 シート手集計の自動化で、デモ副社長の作業時間が削減。
{[ { l: 'Excel手集計', v: '0h' }, { l: 'コピペ', v: '0h' }, { l: '転記ミス', v: '0件' }]. map((s, i) =>
{s.v}
{s.l}
)}
; return (
{/* Header */}
2026年5月 · 全校舎ビュー

KPI レポート

22 シート Excel の手集計から解放。自動更新 · エクスポート可能

{/* Quick stats */}
{/* Rescue hero */}
{/* Charts */}
{/* Funnel + time-savings */}
); } window.KPI = KPI;