diff --git a/databi/src/api.js b/databi/src/api.js index e5e7b53..54c3728 100644 --- a/databi/src/api.js +++ b/databi/src/api.js @@ -50,10 +50,10 @@ export async function fetchPlatformGrantUsers({ appCode, countryId, endMs, page, }); } -export async function fetchPlatformGrantRecords({ appCode, countryId, endMs, page, pageSize, regionId, startMs, statDay, statTz, userId }) { +export async function fetchPlatformGrantRecords({ appCode, countryId, endMs, page, pageSize, regionId, source, startMs, statDay, statTz, userId }) { return fetchDatabiData("/v1/statistics/platform-grants/records", { appCode, - query: platformGrantQuery({ appCode, countryId, endMs, page, pageSize, regionId, startMs, statDay, statTz, userId }) + query: platformGrantQuery({ appCode, countryId, endMs, page, pageSize, regionId, source, startMs, statDay, statTz, userId }) }); } @@ -81,7 +81,7 @@ export async function fetchSelfGameStatisticsOverview({ appCode, countryId, endM return fetchDatabiData("/v1/statistics/self-games/overview", { appCode, query }); } -function platformGrantQuery({ appCode, countryId, endMs, page, pageSize, regionId, startMs, statDay, statTz, userId }) { +function platformGrantQuery({ appCode, countryId, endMs, page, pageSize, regionId, source, startMs, statDay, statTz, userId }) { const query = { app_code: normalizeAppCode(appCode) || "lalu" }; if (statTz) { query.stat_tz = statTz; @@ -104,6 +104,9 @@ function platformGrantQuery({ appCode, countryId, endMs, page, pageSize, regionI if (userId) { query.user_id = String(userId); } + if (source && source !== "all") { + query.source = String(source); + } if (page) { query.page = String(page); } diff --git a/databi/src/components/ReportOverview.jsx b/databi/src/components/ReportOverview.jsx index 52cf13b..8ba5e07 100644 --- a/databi/src/components/ReportOverview.jsx +++ b/databi/src/components/ReportOverview.jsx @@ -15,6 +15,16 @@ const reportTabs = [ { key: "robot", label: "机器人送礼" } ]; +const platformGrantRecordSourceOptions = [ + { label: "全部来源", value: "all" }, + { label: "任务奖励", value: "WalletTaskRewardCredited" }, + { label: "房间流水奖励", value: "WalletRoomTurnoverRewardCredited" }, + { label: "邀请活动奖励", value: "WalletInviteActivityRewardCredited" }, + { label: "代理开通奖励", value: "WalletAgencyOpeningRewardCredited" }, + { label: "资源发放", value: "WalletBalanceChanged" }, + { label: "平台发放", value: "WalletPlatformGrantCoinCredited" } +]; + const countryColumns = [ { align: "left", key: "date_label", label: "日期", render: (row) => , sortable: false, stickyLeft: true }, { align: "left", key: "country", label: "国家", render: (row) => , sortable: false }, @@ -577,15 +587,24 @@ function PlatformGrantUsersModal({ modal, onClose, onOpenRecords }) { {loading ? : null} {!loading && error ? {error} : null} {!loading && !error && !items.length ? 当前无数据 : null} - {!loading && !error ? items.map((item) => ( - - - - - {formatOptionalCoin(item.total_coin)} - {formatOptionalCoin(item.record_count)} - {formatDateTime(item.last_granted_at_ms)} - - )) : null} + + {formatOptionalCoin(item.total_coin)} + {formatOptionalCoin(item.record_count)} + {formatDateTime(item.last_granted_at_ms)} + + ); + }) : null} @@ -611,6 +630,7 @@ function PlatformGrantUsersModal({ modal, onClose, onOpenRecords }) { function PlatformGrantRecordsModal({ modal, onClose }) { const pageSize = 20; const [page, setPage] = useState(1); + const [source, setSource] = useState("all"); const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); @@ -618,7 +638,7 @@ function PlatformGrantRecordsModal({ modal, onClose }) { let active = true; setLoading(true); setError(""); - fetchPlatformGrantRecords({ ...modal.query, page, pageSize }) + fetchPlatformGrantRecords({ ...modal.query, page, pageSize, source }) .then((nextData) => { if (active) { setData(nextData || {}); @@ -638,12 +658,26 @@ function PlatformGrantRecordsModal({ modal, onClose }) { return () => { active = false; }; - }, [modal.query, page]); + }, [modal.query, page, source]); const items = Array.isArray(data?.items) ? data.items : []; const total = Number(data?.total || 0); + const selectSource = (event) => { + setSource(event.target.value); + setPage(1); + }; return ( +
+ +
@@ -960,6 +994,8 @@ function platformGrantSourceLabel(value) { return "邀请活动奖励"; case "WalletAgencyOpeningRewardCredited": return "代理开通奖励"; + case "WalletBalanceChanged": + return "资源发放"; case "WalletPlatformGrantCoinCredited": return "平台发放"; default: diff --git a/databi/src/components/ReportOverview.test.jsx b/databi/src/components/ReportOverview.test.jsx index 87dcb84..86c4ae1 100644 --- a/databi/src/components/ReportOverview.test.jsx +++ b/databi/src/components/ReportOverview.test.jsx @@ -98,10 +98,12 @@ test("drills platform grant coin from total to country users and user records", pageSize: 20, total: 1 }); + const taskRecord = { amount: 33, event_id: "grant:task:7001", event_type: "WalletTaskRewardCredited", occurred_at_ms: Date.UTC(2026, 5, 5, 10, 20, 30), user_id: "7001" }; + const resourceRecord = { amount: 22, event_id: "grant:resource:7001", event_type: "WalletBalanceChanged", occurred_at_ms: Date.UTC(2026, 5, 5, 9, 20, 30), user_id: "7001" }; vi.mocked(fetchPlatformGrantRecords).mockResolvedValue({ items: [ - { amount: 33, event_id: "grant:task:7001", event_type: "WalletTaskRewardCredited", occurred_at_ms: Date.UTC(2026, 5, 5, 10, 20, 30), user_id: "7001" }, - { amount: 22, event_id: "grant:lucky:7001", event_type: "WalletLuckyGiftRewardCredited", occurred_at_ms: Date.UTC(2026, 5, 5, 9, 20, 30), user_id: "7001" } + taskRecord, + resourceRecord ], page: 1, pageSize: 20, @@ -160,6 +162,14 @@ test("drills platform grant coin from total to country users and user records", regionId: 10, userId: "7001" }))); - expect(await screen.findByText("任务奖励")).toBeInTheDocument(); - expect(screen.getByText("幸运礼物返奖")).toBeInTheDocument(); + expect(await screen.findByRole("cell", { name: "任务奖励" })).toBeInTheDocument(); + expect(screen.getByRole("cell", { name: "资源发放" })).toBeInTheDocument(); + + await user.selectOptions(screen.getByLabelText("来源筛选"), "WalletTaskRewardCredited"); + await waitFor(() => expect(fetchPlatformGrantRecords).toHaveBeenLastCalledWith(expect.objectContaining({ + page: 1, + pageSize: 20, + source: "WalletTaskRewardCredited", + userId: "7001" + }))); }); diff --git a/databi/src/styles/report.css b/databi/src/styles/report.css index b7937dc..29a5c92 100644 --- a/databi/src/styles/report.css +++ b/databi/src/styles/report.css @@ -820,6 +820,39 @@ overflow: auto; } +.report-modal-toolbar { + align-items: center; + display: flex; + justify-content: flex-end; +} + +.report-source-filter { + align-items: center; + color: #65748a; + display: inline-flex; + font-size: 13px; + font-weight: 760; + gap: 10px; +} + +.report-source-filter select { + appearance: none; + background: #ffffff; + border: 1px solid #c7d7e7; + border-radius: 8px; + color: #253047; + cursor: pointer; + font: inherit; + min-width: 150px; + padding: 7px 12px; +} + +.report-source-filter select:focus { + border-color: #1688d9; + box-shadow: 0 0 0 3px rgba(22, 136, 217, 0.12); + outline: none; +} + .report-modal-table-wrap { min-width: 0; overflow: auto; @@ -865,6 +898,20 @@ background: #f7fbff; } +.report-modal-table tbody tr.report-clickable-row { + cursor: pointer; +} + +.report-modal-table tbody tr.report-clickable-row:hover td { + background: #eef7ff; +} + +.report-modal-table tbody tr.report-clickable-row:focus-visible td { + background: #e9f5ff; + outline: 2px solid #1688d9; + outline-offset: -2px; +} + .report-user-cell { display: inline-flex; max-width: 260px;