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>
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
import { CapsuleTabs, Tag } from 'antd-mobile'
|
||
import { useState } from 'react'
|
||
import { formatMoney, formatNumber } from '../../../utils/format'
|
||
import type { SnapshotSlot, TodaySnapshot } from '../types'
|
||
|
||
type TodaySnapshotSectionProps = {
|
||
snapshots: TodaySnapshot[]
|
||
}
|
||
|
||
const statusMap = {
|
||
pending: { color: 'default', label: '待生成' },
|
||
success: { color: 'success', label: '已生成' },
|
||
failed: { color: 'danger', label: '生成失败' },
|
||
temporary: { color: 'warning', label: '临时数据' },
|
||
} as const
|
||
|
||
export function TodaySnapshotSection({ snapshots }: TodaySnapshotSectionProps) {
|
||
const [activeSlot, setActiveSlot] = useState<SnapshotSlot>('1015')
|
||
const activeSnapshot = snapshots.find((snapshot) => snapshot.slot === activeSlot) ?? snapshots[0]
|
||
const status = statusMap[activeSnapshot.status]
|
||
|
||
return (
|
||
<section className="section-block snapshot-section">
|
||
<div className="section-title-row">
|
||
<div>
|
||
<p className="section-kicker">今日节点</p>
|
||
<h2>抢购 / 寄卖快报</h2>
|
||
</div>
|
||
<Tag color={status.color}>{status.label}</Tag>
|
||
</div>
|
||
|
||
<CapsuleTabs activeKey={activeSlot} onChange={(key) => setActiveSlot(key as SnapshotSlot)}>
|
||
{snapshots.map((snapshot) => (
|
||
<CapsuleTabs.Tab title={snapshot.title.replace(' ', '')} key={snapshot.slot} />
|
||
))}
|
||
</CapsuleTabs>
|
||
|
||
<div className="snapshot-card">
|
||
<p className="snapshot-message">{activeSnapshot.message}</p>
|
||
{activeSnapshot.generatedAt && <p className="snapshot-time">生成时间:{activeSnapshot.generatedAt}</p>}
|
||
<div className="snapshot-grid">
|
||
<span>
|
||
采购用户<strong>{formatNumber(activeSnapshot.purchaseUsers)}人</strong>
|
||
</span>
|
||
<span>
|
||
订单数<strong>{formatNumber(activeSnapshot.orderCount)}单</strong>
|
||
</span>
|
||
<span>
|
||
成交额<strong>{formatMoney(activeSnapshot.dealAmount)}</strong>
|
||
</span>
|
||
<span>
|
||
支付额<strong>{formatMoney(activeSnapshot.paidAmount)}</strong>
|
||
</span>
|
||
<span>
|
||
新增商品<strong>{formatNumber(activeSnapshot.newMerchandiseCount)}件</strong>
|
||
</span>
|
||
<span>
|
||
奖金变化<strong>{formatMoney(Number(activeSnapshot.selfBonusChange) + Number(activeSnapshot.shareBonusChange))}</strong>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|