feat(dashboard): add boss dashboard H5 and APIs

Implement the mobile dashboard frontend, admin overview APIs, report archive export, and local dev proxy so the boss dashboard can run against real backend data while preserving MSW demos.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
danaisuiyuan
2026-05-11 13:07:40 +08:00
parent 693c66c258
commit 403ffe0fde
40 changed files with 6767 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
import { Button, DotLoading, ErrorBlock } from 'antd-mobile'
import { KpiCard } from '../../../components/kpi/KpiCard'
import { MiniTrendChart } from '../../../components/charts/MiniTrendChart'
import { formatMoney } from '../../../utils/format'
import { useDashboardOverview } from '../api'
import { RankList } from '../components/RankList'
import { RiskAlertSection } from '../components/RiskAlertSection'
import { TodaySnapshotSection } from '../components/TodaySnapshotSection'
export function BossDashboardPage() {
const { data, isLoading, isError, refetch } = useDashboardOverview()
if (isLoading) {
return (
<section className="loading-page">
<DotLoading color="primary" />
<p>...</p>
</section>
)
}
if (isError || !data) {
return (
<section className="error-page">
<ErrorBlock status="default" title="驾驶舱加载失败" description="后端接口暂不可用,请确认服务、登录态或接口权限后重试。" />
<Button color="primary" onClick={() => void refetch()}>
</Button>
</section>
)
}
const coreKpis = data.kpis.slice(0, 4)
const moreKpis = data.kpis.slice(4)
return (
<section className="dashboard-page">
<header className="dashboard-hero">
<div className="hero-topline">
<span></span>
<button type="button"></button>
</div>
<p className="eyebrow"> {data.businessDate}</p>
<h1></h1>
<p className="hero-summary">{data.summary}</p>
<div className="hero-metric">
<span></span>
<strong>{formatMoney(data.kpis[0]?.value)}</strong>
<small>{data.generatedAt}</small>
</div>
</header>
<section className="kpi-grid" aria-label="核心经营指标">
{coreKpis.map((metric) => (
<KpiCard key={metric.key} metric={metric} />
))}
</section>
<section className="section-block compact-section">
<div className="section-title-row">
<div>
<p className="section-kicker">More</p>
<h2></h2>
</div>
</div>
<div className="kpi-grid kpi-grid--compact">
{moreKpis.map((metric) => (
<KpiCard key={metric.key} metric={metric} />
))}
</div>
</section>
<TodaySnapshotSection snapshots={data.snapshots} />
<section className="section-block">
<div className="section-title-row">
<div>
<p className="section-kicker">Trend</p>
<h2> 7 </h2>
</div>
</div>
<MiniTrendChart data={data.trends} />
</section>
<section className="section-block compact-section">
<div className="section-title-row">
<div>
<p className="section-kicker">Fund</p>
<h2></h2>
</div>
</div>
<div className="kpi-grid kpi-grid--compact">
{data.fundPool.map((metric) => (
<KpiCard key={metric.key} metric={metric} />
))}
</div>
</section>
<RankList title="高价值用户" items={data.userRanks} />
<RankList title="团队贡献排行" items={data.teamRanks} />
<RankList title="高货值未成交商品" items={data.productRanks} />
<RiskAlertSection risks={data.risks} />
</section>
)
}