/* === Product Pool page === */ /* global React, LineChart, useToast, Icons */ const { useState: usePoolState, useMemo: usePoolMemo } = React; const fmtPct = (v) => v == null ? '-' : (v * 100).toFixed(2) + '%'; const fmtNum = (v, decimals = 2) => v == null ? '-' : v.toFixed(decimals); function PageProductPool({ onNav, openDrawer, compareIds, addToCompare }) { const { products, CATEGORIES, FEATURED, managers } = window.IRDATA; const [catId, setCatId] = usePoolState("agg"); const [mgrFilter, setMgrFilter] = usePoolState("all"); const [selected, setSelected] = usePoolState(new Set()); const [featFilter, setFeatFilter] = usePoolState(null); const toast = useToast(); const filtered = usePoolMemo(() => products.filter((p) => p.catId === catId && ( mgrFilter === "all" || p.managerId === mgrFilter) && ( !featFilter || (p.featured || []).includes(featFilter)) ), [catId, mgrFilter, featFilter, products]); const catCounts = CATEGORIES.map((c) => ({ ...c, count: products.filter((p) => p.catId === c.id).length, delta: c.id === "agg" ? 2 : c.id === "mod" ? 1 : c.id === "low" ? -1 : 0 })); // Average metrics scoped to selected category const scoped = products.filter((p) => p.catId === catId); const avg = (arr, key) => arr.length ? arr.reduce((a, b) => a + b[key], 0) / arr.length : 0; const metrics = { annualReturn: avg(scoped, "annualReturn"), maxDrawdown: avg(scoped, "maxDrawdown"), vol: avg(scoped, "vol"), sharpe: avg(scoped, "sharpe") }; const toggleSel = (id) => { const s = new Set(selected); s.has(id) ? s.delete(id) : s.add(id); setSelected(s); }; const doImport = () => { if (selected.size === 0) {toast.push("请先勾选产品", "warn");return;} const arr = [...selected]; arr.forEach((id) => addToCompare(id)); toast.push(`已导入 ${arr.length} 只产品至产品对比`); setSelected(new Set()); }; const currentCat = CATEGORIES.find((c) => c.id === catId); return ( {/* Pool overview header (slim) */}
产品池
共 {products.length} 只在管产品 · 覆盖 {managers.length} 家管理人
{/* Merged "产品筛选" card (left, two modules) + 产品指标 card (right) */}
{/* Merged categories + featured */}
产品筛选
{(featFilter || catId !== "agg") && }
{/* Sub-module: 产品分类 */}
产品分类
{catCounts.map((c) =>
setCatId(c.id)}>
{c.name}
{c.count}
0 ? "delta-up" : c.delta < 0 ? "delta-down" : "delta-flat")}> {c.delta > 0 ? "▲" : c.delta < 0 ? "▼" : "—"} {Math.abs(c.delta)}
)}
{/* Divider */}
{/* Sub-module: 特色产品 */}
特色产品 系列产品矩阵
{featFilter && }
{FEATURED.map((f) =>
setFeatFilter(featFilter === f.id ? null : f.id)} style={{ "--accent": f.color, "--accent-soft": f.soft, borderColor: featFilter === f.id ? f.color : "", boxShadow: featFilter === f.id ? `0 0 0 1px ${f.color}` : "" }}>
特色系列
{f.name}
{f.count}
0 ? "delta-up" : f.delta < 0 ? "delta-down" : "delta-flat"}> {f.delta > 0 ? "▲" : f.delta < 0 ? "▼" : "—"} {Math.abs(f.delta)}
)}
{/* Metrics */}
产品指标
openDrawer({ kind: "info", payload: { title: "平均年化收益", sub: currentCat.name, kvs: scoped.map((p) => ({ k: p.name, v: {fmtPct(p.annualReturn)} })), body: "该分类下所有产品自管理起算的年化收益均值。" } })}>
平均年化收益
{fmtPct(metrics.annualReturn)}
基于 {scoped.length} 只产品
openDrawer({ kind: "info", payload: { title: "平均最大回撤", sub: currentCat.name, kvs: scoped.map((p) => ({ k: p.name, v: {fmtPct(p.maxDrawdown)} })) } })}>
平均最大回撤
{fmtPct(metrics.maxDrawdown)}
同类均值参考
openDrawer({ kind: "info", payload: { title: "平均年化波动率", sub: currentCat.name, kvs: scoped.map((p) => ({ k: p.name, v: {fmtPct(p.vol)} })) } })}>
平均波动率
{fmtPct(metrics.vol)}
年化标准差
openDrawer({ kind: "info", payload: { title: "平均夏普比率", sub: currentCat.name, kvs: scoped.map((p) => ({ k: p.name, v: {fmtNum(p.sharpe)} })) } })}>
平均夏普比率
{fmtNum(metrics.sharpe)}
无风险利率 2.5%
{/* Product list */}
分类: {CATEGORIES.map((c) => setCatId(c.id)}> {c.name} {products.filter((p) => p.catId === c.id).length} )} 管理人:
已选 {selected.size} 只
{filtered.map((p) => { const cat = CATEGORIES.find((c) => c.id === p.catId) || { name: "未分类", color: "#999", soft: "#eee" }; const isSel = selected.has(p.id); const inCmp = compareIds.includes(p.id); return ( ); })} {filtered.length === 0 && }
产品 分类 管理人 年化收益 最大回撤 夏普 操作
toggleSel(p.id)} />
{p.name} {p.code} · 评级 {p.rating}
{cat.name} {p.manager} = 0 ? "var(--red)" : "var(--green)" }}> {fmtPct(p.annualReturn)} {fmtPct(p.maxDrawdown)} {fmtNum(p.sharpe)} {!inCmp && } {inCmp && 已在对比}
{Icons.empty}
当前筛选下无产品
); } Object.assign(window, { PageProductPool });