163 lines
5.7 KiB
JavaScript
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");
|
|
}
|