33 lines
1.4 KiB
JavaScript
33 lines
1.4 KiB
JavaScript
import { formatNumber, formatPercent } from "../utils/format.js";
|
|
import { MiniStat } from "./MiniStat.jsx";
|
|
import { Panel } from "./Panel.jsx";
|
|
|
|
export function FunnelPanel({ funnel, loading = false, sideMetrics }) {
|
|
return (
|
|
<Panel title="付费转化漏斗">
|
|
<div className={["funnel-layout", loading ? "skeleton-panel" : ""].filter(Boolean).join(" ")} aria-busy={loading || undefined}>
|
|
<div className="funnel-stack">
|
|
{loading
|
|
? Array.from({ length: 3 }).map((_, index) => <span className={`skeleton-block skeleton-funnel-stage skeleton-funnel-stage--${index + 1}`} key={index} />)
|
|
: funnel.map((item, index) => (
|
|
<div className="funnel-stage-row" key={item.name}>
|
|
<div className={`funnel-stage funnel-stage--${index + 1}`}>
|
|
<span>{item.name}</span>
|
|
<strong>{formatNumber(item.value)}</strong>
|
|
</div>
|
|
<b>{formatPercent(item.rate)}</b>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="side-metrics">
|
|
{loading
|
|
? Array.from({ length: 3 }).map((_, index) => <span className="skeleton-block skeleton-mini-stat" key={index} />)
|
|
: sideMetrics.map((item) => (
|
|
<MiniStat key={item.label} item={item} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
</Panel>
|
|
);
|
|
}
|