201 lines
7.2 KiB
JavaScript
201 lines
7.2 KiB
JavaScript
import ReplayOutlined from "@mui/icons-material/ReplayOutlined";
|
|
import { RoomTurnoverRewardConfigDrawer } from "@/features/room-turnover-reward/components/RoomTurnoverRewardConfigDrawer.jsx";
|
|
import { RoomTurnoverRewardConfigSummary } from "@/features/room-turnover-reward/components/RoomTurnoverRewardConfigSummary.jsx";
|
|
import { useRoomTurnoverRewardPage } from "@/features/room-turnover-reward/hooks/useRoomTurnoverRewardPage.js";
|
|
import styles from "@/features/room-turnover-reward/room-turnover-reward.module.css";
|
|
import { AdminActionIconButton, AdminListBody, AdminListPage } from "@/shared/ui/AdminListLayout.jsx";
|
|
import { DataState } from "@/shared/ui/DataState.jsx";
|
|
import { DataTable } from "@/shared/ui/DataTable.jsx";
|
|
import { createOptionsColumnFilter, createTextColumnFilter } from "@/shared/ui/tableFilters.js";
|
|
import { TimeText } from "@/shared/ui/TimeText.jsx";
|
|
|
|
const settlementStatusOptions = [
|
|
["pending", "待发放"],
|
|
["granted", "已发放"],
|
|
["failed", "发放失败"],
|
|
];
|
|
|
|
const columnsBase = [
|
|
{
|
|
key: "room",
|
|
label: "房间",
|
|
width: "minmax(220px, 0.9fr)",
|
|
render: (item) => (
|
|
<div className={styles.stack}>
|
|
<span className={styles.name}>{item.roomId || "-"}</span>
|
|
<span className={styles.meta}>房主 {item.ownerUserId || "-"}</span>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
key: "period",
|
|
label: "周期",
|
|
width: "minmax(260px, 1.1fr)",
|
|
render: (item) => (
|
|
<div className={styles.stack}>
|
|
<TimeText value={item.periodStartMs} />
|
|
<span className={styles.meta}>
|
|
至 <TimeText value={item.periodEndMs} />
|
|
</span>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
key: "coinSpent",
|
|
label: "房间流水",
|
|
width: "minmax(160px, 0.7fr)",
|
|
render: (item) => `${formatNumber(item.coinSpent)} 金币`,
|
|
},
|
|
{
|
|
key: "tier",
|
|
label: "命中档位",
|
|
width: "minmax(180px, 0.75fr)",
|
|
render: (item) => (
|
|
<div className={styles.stack}>
|
|
<span>{item.tierCode || `档位 #${item.tierId || "-"}`}</span>
|
|
<span className={styles.meta}>阈值 {formatNumber(item.thresholdCoinSpent)}</span>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
key: "reward",
|
|
label: "奖励金币",
|
|
width: "minmax(140px, 0.65fr)",
|
|
render: (item) => formatNumber(item.rewardCoinAmount),
|
|
},
|
|
{
|
|
key: "status",
|
|
label: "状态",
|
|
width: "minmax(130px, 0.6fr)",
|
|
render: (item) => settlementStatusBadge(item.status),
|
|
},
|
|
{
|
|
key: "failure",
|
|
label: "失败原因",
|
|
width: "minmax(220px, 0.9fr)",
|
|
render: (item) => item.failureReason || "-",
|
|
},
|
|
{
|
|
key: "record",
|
|
label: "记录",
|
|
width: "minmax(280px, 1fr)",
|
|
render: (item) => (
|
|
<div className={styles.stack}>
|
|
<span>{item.settlementId}</span>
|
|
<span className={styles.meta}>{item.walletTransactionId || item.walletCommandId || "-"}</span>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
key: "actions",
|
|
label: "操作",
|
|
width: "112px",
|
|
fixed: "right",
|
|
resizable: false,
|
|
render: (item, _index, context = {}) =>
|
|
item.status === "failed" && context.abilities?.canRetry ? (
|
|
<AdminActionIconButton
|
|
disabled={context.retryingSettlementId === item.settlementId}
|
|
label="重试"
|
|
tooltip="重试发放"
|
|
onClick={() => context.retrySettlement?.(item)}
|
|
>
|
|
<ReplayOutlined fontSize="small" />
|
|
</AdminActionIconButton>
|
|
) : (
|
|
"-"
|
|
),
|
|
},
|
|
];
|
|
|
|
export function RoomTurnoverRewardPage() {
|
|
const page = useRoomTurnoverRewardPage();
|
|
const total = page.settlements.total || 0;
|
|
const columns = columnsBase.map((column) => {
|
|
if (column.key === "room") {
|
|
return {
|
|
...column,
|
|
filter: createTextColumnFilter({
|
|
placeholder: "搜索房间 ID",
|
|
value: page.query,
|
|
onChange: page.changeQuery,
|
|
}),
|
|
};
|
|
}
|
|
if (column.key === "status") {
|
|
return {
|
|
...column,
|
|
filter: createOptionsColumnFilter({
|
|
options: [["", "全部状态"], ...settlementStatusOptions],
|
|
placeholder: "搜索状态",
|
|
value: page.status,
|
|
onChange: page.changeStatus,
|
|
}),
|
|
};
|
|
}
|
|
return column;
|
|
});
|
|
|
|
return (
|
|
<AdminListPage>
|
|
<RoomTurnoverRewardConfigSummary
|
|
canUpdate={page.abilities.canUpdate}
|
|
config={page.config}
|
|
configLoading={page.configLoading}
|
|
onEdit={page.openConfigDrawer}
|
|
onRefresh={page.reloadConfig}
|
|
/>
|
|
<DataState error={page.settlementsError} loading={page.settlementsLoading} onRetry={page.reloadSettlements}>
|
|
<AdminListBody>
|
|
<DataTable
|
|
columns={columns}
|
|
context={{
|
|
abilities: page.abilities,
|
|
retryingSettlementId: page.retryingSettlementId,
|
|
retrySettlement: page.retrySettlement,
|
|
}}
|
|
items={page.settlements.items || []}
|
|
minWidth="1480px"
|
|
pagination={
|
|
total > 0
|
|
? {
|
|
page: page.page,
|
|
pageSize: page.settlements.pageSize || 50,
|
|
total,
|
|
onPageChange: page.setPage,
|
|
}
|
|
: undefined
|
|
}
|
|
rowKey={(item) => item.settlementId}
|
|
/>
|
|
</AdminListBody>
|
|
</DataState>
|
|
<RoomTurnoverRewardConfigDrawer
|
|
abilities={page.abilities}
|
|
configLoading={page.configLoading}
|
|
configSaving={page.configSaving}
|
|
form={page.form}
|
|
open={page.configDrawerOpen}
|
|
setForm={page.setForm}
|
|
onClose={page.closeConfigDrawer}
|
|
onSubmit={page.submitConfig}
|
|
/>
|
|
</AdminListPage>
|
|
);
|
|
}
|
|
|
|
function settlementStatusBadge(status) {
|
|
const label = settlementStatusOptions.find(([value]) => value === status)?.[1] || status || "-";
|
|
const className =
|
|
status === "granted"
|
|
? styles.statusActive
|
|
: status === "failed"
|
|
? styles.statusFailed
|
|
: styles.statusInactive;
|
|
return <span className={[styles.statusBadge, className].join(" ")}>{label}</span>;
|
|
}
|
|
|
|
function formatNumber(value) {
|
|
return new Intl.NumberFormat("zh-CN").format(Number(value || 0));
|
|
}
|