import { useState, type CSSProperties } from 'react'; import { getTranslation, type Locale } from '../i18n/utils'; import { Icon } from '../icons'; import { cssVars } from './css'; /* ===================================================================== * 数字生活生态全景图 — 首页 3 受众 × 业务页 5 赛道的「桥」 * 依据:business-architecture.md §4 产品×受众矩阵(2026-08 已拍板) * 同一组 8 个产品,两种视角:按赛道(连接/成长/交易/理解/成全)/ 按受众(消费者/企业/未来) * ===================================================================== */ // 已确认的产品×受众矩阵。顺序与 i18n business.tracks[].products[] 严格一致。 // C=消费者 B=企业 F=未来(平台层) type Aud = { c: boolean; b: boolean; f: boolean }; const MATRIX: Aud[][] = [ // 内容社交:青核 / 音酷 / 蜜恋 [{ c: true, b: false, f: false }, { c: true, b: false, f: false }, { c: true, b: false, f: false }], // 职场服务:职来 / 看见高山 [{ c: true, b: true, f: false }, { c: true, b: true, f: false }], // 数字支付:妥哒 [{ c: true, b: true, f: false }], // 人工智能:阿布AI [{ c: true, b: false, f: true }], // 生活服务:听愿 [{ c: true, b: false, f: true }], ]; type Lens = 'track' | 'audience'; type Sel = | { kind: 'center' } | { kind: 'track'; i: number } | { kind: 'aud'; key: 'c' | 'b' | 'f' }; // 5 赛道节点角度(五边形:从顶点顺时针每 72°) const TRACK_ANGLES = [-90, -18, 54, 126, 198]; // 3 受众节点角度(顶 / 左下 / 右下) const AUD_ANGLES = [-90, 150, 30]; function polar(angleDeg: number, r: number) { const a = (angleDeg * Math.PI) / 180; return { x: 50 + r * Math.cos(a), y: 50 + r * Math.sin(a) }; } export default function EcosystemMap({ locale }: { locale: Locale }) { const t = getTranslation(locale); const tracks = t.business.tracks; const isEn = locale === 'en'; const tr = (zh: string, hk: string, en: string) => (isEn ? en : locale === 'hk' ? hk : zh); const [lens, setLens] = useState('track'); const [sel, setSel] = useState({ kind: 'track', i: 0 }); const audienceMeta: { key: 'c' | 'b' | 'f'; name: string; icon: string; def: string; angle: number }[] = [ { key: 'c', name: tr('消费者', '消費者', 'Consumers'), icon: 'users', def: tr('个体的数字生活', '個體的數位生活', "Individuals' digital life"), angle: AUD_ANGLES[0] }, { key: 'b', name: tr('企业', '企業', 'Enterprises'), icon: 'briefcase', def: tr('组织的效率与增长', '組織的效率與增長', 'Organizational efficiency & growth'), angle: AUD_ANGLES[1] }, { key: 'f', name: tr('未来', '未來', 'Future'), icon: 'rocket', def: tr('前沿与平台层', '前沿與平台層', 'Frontier & platform layer'), angle: AUD_ANGLES[2] }, ]; const actionLabel = (i: number) => tr(['连接', '成长', '交易', '理解', '成全'][i], ['連接', '成長', '交易', '理解', '成全'][i], ['Connect', 'Grow', 'Transact', 'Understand', 'Fulfill'][i]); const totalProducts = tracks.reduce((n, tk) => n + tk.products.length, 0); // 切换视角时回到该视角的默认选中 const switchLens = (next: Lens) => { setLens(next); setSel(next === 'track' ? { kind: 'track', i: 0 } : { kind: 'aud', key: 'c' }); }; // —— 右侧详情面板的产品列表 —— type PItem = { name: string; desc: string; icon?: string; aud: Aud }; let panelTitle: string; let panelEyebrow: string; let panelNote: string; let products: PItem[]; if (sel.kind === 'center') { panelEyebrow = tr('数字生活生态', '數位生活生態', 'Digital Life Ecosystem'); panelTitle = tr('巴适伙伴', '巴適夥伴', 'BaskBuddy'); panelNote = tr( `以"温暖科技"连接人、机会、价值与智能——${tracks.length} 大赛道 · ${totalProducts} 个自研产品,共建数字生活生态。`, `以「溫暖科技」連接人、機會、價值與智能——${tracks.length} 大賽道 · ${totalProducts} 個自研產品,共建數位生活生態。`, `Connecting people, opportunities, value & intelligence with "warm tech" — ${tracks.length} tracks · ${totalProducts} self-built products.`, ); products = tracks.flatMap((tk, ti) => tk.products.map((p, pi) => ({ name: p.name, desc: p.desc, icon: p.icon, aud: MATRIX[ti][pi] })), ); } else if (sel.kind === 'track') { const ti = sel.i; const tk = tracks[ti]; panelEyebrow = tr('赛道', '賽道', 'Track'); panelTitle = `${tk.name} · ${actionLabel(ti)}`; panelNote = tr( ['人与人的连接', '人与机会的连接', '人与价值的连接', '人与智能的连接', '人与心愿的连接'][ti], ['人與人的連接', '人與機會的連接', '人與價值的連接', '人與智能的連接', '人與心願的連接'][ti], ['People ↔ people', 'People ↔ opportunities', 'People ↔ value', 'People ↔ intelligence', 'People ↔ wishes'][ti], ); products = tk.products.map((p, pi) => ({ name: p.name, desc: p.desc, icon: p.icon, aud: MATRIX[ti][pi] })); } else { const key = sel.key; const am = audienceMeta.find((a) => a.key === key)!; panelEyebrow = tr('受众', '受眾', 'Audience'); panelTitle = am.name; panelNote = am.def; products = tracks.flatMap((tk, ti) => tk.products.flatMap((p, pi) => MATRIX[ti][pi][key] ? [{ name: p.name, desc: p.desc, icon: p.icon, aud: MATRIX[ti][pi] }] : [], ), ); } const audDot = (a: Aud) => ( ); return (
{/* —— 视角切换 —— */}
{(['track', 'audience'] as Lens[]).map((l) => ( ))}
{/* —— 全景图舞台 —— */}
{/* 连接线 */} {/* 中心枢纽 */} {/* 赛道节点 */} {lens === 'track' && tracks.map((tk, i) => { const p = polar(TRACK_ANGLES[i], 36); const on = sel.kind === 'track' && sel.i === i; return ( ); })} {/* 受众节点 */} {lens === 'audience' && audienceMeta.map((am) => { const p = polar(am.angle, 36); const on = sel.kind === 'aud' && sel.key === am.key; const count = tracks.reduce( (n, tk, ti) => n + tk.products.filter((_, pi) => MATRIX[ti][pi][am.key]).length, 0, ); return ( ); })}
{/* —— 详情面板 —— */}
{/* 受众图例(桥接说明) */}

{tr( '同一组产品,两种视角:按"赛道"看我们造什么,按"受众"看我们为谁。', '同一組產品,兩種視角:按「賽道」看我們造什麼,按「受眾」看我們為誰。', 'Same products, two lenses: "By track" shows what we build; "By audience" shows who we serve.', )}

); }