2026-05-26 02:39:46 +08:00

163 lines
5.7 KiB
JavaScript

import { DataState } from "@/shared/ui/DataState.jsx";
import { DataTable } from "@/shared/ui/DataTable.jsx";
import {
AdminFilterResetButton,
AdminFilterSelect,
AdminListBody,
AdminListPage,
AdminListToolbar,
} from "@/shared/ui/AdminListLayout.jsx";
import { formatMillis } from "@/shared/utils/time.js";
import { useUserLeaderboardPage } from "@/features/user-leaderboard/hooks/useUserLeaderboardPage.js";
import styles from "@/features/user-leaderboard/user-leaderboard.module.css";
const boardTypeOptions = [
["sent", "用户送礼榜"],
["received", "收礼榜"],
["room", "房间礼物值榜"],
];
const periodOptions = [
["today", "今天"],
["week", "一周"],
["month", "一月"],
];
const columns = [
{
key: "rank",
label: "排名",
width: "minmax(96px, 0.45fr)",
render: (item) => <span className={styles.rank}>#{item.rank}</span>,
},
{
key: "subject",
label: "对象",
width: "minmax(280px, 1.25fr)",
render: (item, _index, context) => <LeaderboardSubject item={item} type={context.boardType} />,
},
{
key: "giftValue",
label: "礼物值",
width: "minmax(150px, 0.75fr)",
render: (item) => formatNumber(item.giftValue),
},
{
key: "giftCount",
label: "礼物数量",
width: "minmax(130px, 0.65fr)",
render: (item) => formatNumber(item.giftCount),
},
{
key: "transactionCount",
label: "交易数",
width: "minmax(120px, 0.6fr)",
render: (item) => formatNumber(item.transactionCount),
},
{
key: "lastGiftAtMs",
label: "最后送礼时间",
width: "minmax(180px, 0.85fr)",
render: (item) => `${formatMillis(item.lastGiftAtMs, "UTC")} UTC`,
},
];
export function UserLeaderboardPage() {
const page = useUserLeaderboardPage();
const items = page.data.items || [];
const total = page.data.total || 0;
return (
<AdminListPage>
<AdminListToolbar
filters={
<>
<AdminFilterSelect
label="榜单"
options={boardTypeOptions}
value={page.boardType}
onChange={page.changeBoardType}
/>
<AdminFilterSelect
label="时间维度"
options={periodOptions}
value={page.period}
onChange={page.changePeriod}
/>
<AdminFilterResetButton
disabled={page.boardType === "sent" && page.period === "today"}
onClick={page.resetFilters}
/>
</>
}
/>
<div className={styles.summary}>
<div>
<span className={styles.summaryLabel}>UTC 时间范围</span>
<span className={styles.summaryValue}>
{formatMillis(page.data.startAtMs, "UTC")} - {formatMillis(page.data.endAtMs, "UTC")}
</span>
</div>
{page.data.myRank ? (
<div>
<span className={styles.summaryLabel}>当前用户排名</span>
<span className={styles.summaryValue}>
#{page.data.myRank.rank} · {formatNumber(page.data.myRank.giftValue)}
</span>
</div>
) : null}
</div>
<DataState error={page.error} loading={page.loading} onRetry={page.reload}>
<AdminListBody>
<DataTable
columns={columns}
context={{ boardType: page.boardType }}
items={items}
minWidth="960px"
pagination={
total > 0
? {
page: page.page,
pageSize: page.data.pageSize || 50,
total,
onPageChange: page.setPage,
}
: undefined
}
rowKey={(item) => `${page.boardType}-${item.userId || item.roomId || item.rank}`}
/>
</AdminListBody>
</DataState>
</AdminListPage>
);
}
function LeaderboardSubject({ item, type }) {
if (type === "room") {
const room = item.room || {};
return (
<div className={styles.identity}>
<span className={styles.name}>{room.title || item.roomId || "-"}</span>
<span className={styles.meta}>
{room.roomShortId ? `短号 ${room.roomShortId}` : item.roomId || "-"}
{room.ownerUserId ? ` · 房主 ${room.ownerUserId}` : ""}
</span>
</div>
);
}
const user = item.user || {};
return (
<div className={styles.identity}>
<span className={styles.name}>{user.username || user.displayUserId || item.userId || "-"}</span>
<span className={styles.meta}>
{user.displayUserId ? `短号 ${user.displayUserId}` : ""}
{item.userId ? `${user.displayUserId ? " · " : ""}ID ${item.userId}` : ""}
</span>
</div>
);
}
function formatNumber(value) {
return Number(value || 0).toLocaleString("zh-CN");
}