// 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 (
{/* 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 前月
{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) =>
{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%を適用。
;
// ── Time savings tile ─────────────────────────────────────────
const TimeSavings = () =>
作業時間削減
10–20
時間 / 月
22 シート手集計の自動化で、デモ副社長の作業時間が削減。
{[
{ l: 'Excel手集計', v: '0h' },
{ l: 'コピペ', v: '0h' },
{ l: '転記ミス', v: '0件' }].
map((s, i) =>
)}
;
return (
{/* Header */}
2026年5月 · 全校舎ビュー
KPI レポート
22 シート Excel の手集計から解放。自動更新 · エクスポート可能。
{/* Quick stats */}
{/* Rescue hero */}
{/* Charts */}
{/* Funnel + time-savings */}
);
}
window.KPI = KPI;