2026-06-29 14:26:00 +08:00

160 lines
5.6 KiB
JavaScript

import { DataState } from "@/shared/ui/DataState.jsx";
import { DataTable } from "@/shared/ui/DataTable.jsx";
import { AdminListBody, AdminListPage } from "@/shared/ui/AdminListLayout.jsx";
import { AdminUserIdentity } from "@/shared/ui/AdminUserIdentity.jsx";
import { createOptionsColumnFilter, createUserIdentityColumnFilter } from "@/shared/ui/tableFilters.js";
import { formatMillis } from "@/shared/utils/time.js";
import { RegistrationRewardConfigDrawer } from "@/features/registration-reward/components/RegistrationRewardConfigDrawer.jsx";
import { RegistrationRewardConfigSummary } from "@/features/registration-reward/components/RegistrationRewardConfigSummary.jsx";
import { useRegistrationRewardPage } from "@/features/registration-reward/hooks/useRegistrationRewardPage.js";
import styles from "@/features/registration-reward/registration-reward.module.css";
const claimStatusOptions = [
["pending", "发放中"],
["granted", "已发放"],
["failed", "发放失败"],
];
const columnsBase = [
{
key: "user",
label: "用户信息",
width: "minmax(260px, 1.2fr)",
render: (claim) => <ClaimUser claim={claim} />,
},
{
key: "reward",
label: "奖励",
width: "minmax(180px, 0.85fr)",
render: (claim) => <RewardSummary claim={claim} />,
},
{
key: "status",
label: "状态",
width: "minmax(120px, 0.55fr)",
render: (claim) => claimStatusLabel(claim.status),
},
{
key: "claimedAt",
label: "领取时间",
width: "minmax(180px, 0.85fr)",
render: (claim) => formatMillis(claim.claimedAtMs || claim.createdAtMs),
},
{
key: "claimId",
label: "领取记录",
width: "minmax(240px, 1fr)",
render: (claim) => claim.claimId || "-",
},
{
key: "failure",
label: "失败原因",
width: "minmax(180px, 0.85fr)",
render: (claim) => claim.failureReason || "-",
},
];
export function RegistrationRewardPage() {
const page = useRegistrationRewardPage();
const total = page.claims.total || 0;
const columns = columnsBase.map((column) => {
if (column.key === "user") {
return {
...column,
filter: createUserIdentityColumnFilter({
value: page.userFilter,
onChange: page.changeUserFilter,
}),
};
}
if (column.key === "status") {
return {
...column,
filter: createOptionsColumnFilter({
options: [["", "全部状态"], ...claimStatusOptions],
placeholder: "搜索状态",
value: page.status,
onChange: page.changeStatus,
}),
};
}
return column;
});
return (
<AdminListPage>
<RegistrationRewardConfigSummary
canUpdate={page.abilities.canUpdate}
config={page.config}
configLoading={page.configLoading}
resourceGroups={page.resourceGroups}
timeRange={page.timeRange}
todayClaimedCount={page.claims.todayClaimedCount || 0}
onEdit={page.openConfigDrawer}
onRefresh={page.reloadConfig}
onTimeRangeChange={page.changeTimeRange}
/>
<DataState error={page.claimsError} loading={page.claimsLoading} onRetry={page.reloadClaims}>
<AdminListBody>
<DataTable
columns={columns}
items={page.claims.items || []}
minWidth="1240px"
pagination={
total > 0
? {
page: page.page,
pageSize: page.claims.pageSize || 50,
total,
onPageChange: page.setPage,
}
: undefined
}
rowKey={(claim) => claim.claimId}
/>
</AdminListBody>
</DataState>
<RegistrationRewardConfigDrawer
abilities={page.abilities}
configLoading={page.configLoading}
configSaving={page.configSaving}
form={page.form}
open={page.configDrawerOpen}
resourceGroups={page.resourceGroups}
setForm={page.setForm}
onClose={page.closeConfigDrawer}
onSubmit={page.submitConfig}
/>
</AdminListPage>
);
}
function ClaimUser({ claim }) {
const user = claim.user || {};
return <AdminUserIdentity openInAppUserDetail user={{ ...user, userId: user.userId || claim.userId }} />;
}
function RewardSummary({ claim }) {
if (claim.rewardType === "resource_group") {
return (
<div className={styles.stack}>
<span>资源组</span>
<span className={styles.meta}>#{claim.resourceGroupId || "-"}</span>
</div>
);
}
return (
<div className={styles.stack}>
<span>{formatNumber(claim.coinAmount)} 金币</span>
</div>
);
}
function claimStatusLabel(status) {
return claimStatusOptions.find(([value]) => value === status)?.[1] || status || "-";
}
function formatNumber(value) {
return new Intl.NumberFormat("zh-CN").format(Number(value || 0));
}