diff --git a/src/i18n/locales/en/settlementCenter.json b/src/i18n/locales/en/settlementCenter.json index f16a5da..ad4b53f 100644 --- a/src/i18n/locales/en/settlementCenter.json +++ b/src/i18n/locales/en/settlementCenter.json @@ -270,6 +270,13 @@ "recordReceiptFrom": "Record receipt ({{payer}} → {{payee}})", "recordPayoutTo": "Record payout ({{payer}} → {{payee}})", "rebateAllocationsHint": "How rebate is allocated across agent tiers.", + "rebateAllocParticipant": "Participant", + "rebateAllocRate": "Share", + "rebateAllocAmount": "Allocated", + "rebateAllocTotal": "Total", + "rebateAllocTicket": "Ticket", + "showRawRebateAllocations": "Show per-ticket detail ({{count}})", + "hideRawRebateAllocations": "Hide per-ticket detail", "payment": "Payment", "flowHint": { "playerPayAgent": "Player should settle with the direct agent", diff --git a/src/i18n/locales/ne/settlementCenter.json b/src/i18n/locales/ne/settlementCenter.json index fbe82d8..be24b81 100644 --- a/src/i18n/locales/ne/settlementCenter.json +++ b/src/i18n/locales/ne/settlementCenter.json @@ -272,6 +272,13 @@ "recordReceiptFrom": "रसिद दर्ता ({{payer}} → {{payee}})", "recordPayoutTo": "भुक्तानी दर्ता ({{payer}} → {{payee}})", "rebateAllocationsHint": "एजेन्ट तहहरूमा रिबेट कसरी बाँडिन्छ।", + "rebateAllocParticipant": "सहभागी", + "rebateAllocRate": "शेयर", + "rebateAllocAmount": "बाँडफाँड रकम", + "rebateAllocTotal": "कुल", + "rebateAllocTicket": "टिकट", + "showRawRebateAllocations": "टिकट अनुसार विवरण देखाउनुहोस् ({{count}})", + "hideRawRebateAllocations": "टिकट विवरण लुकाउनुहोस्", "payment": "भुक्तानी", "flowHint": { "playerPayAgent": "खेलाडीले प्रत्यक्ष एजेन्टसँग सेटल गर्नुपर्छ", diff --git a/src/i18n/locales/zh/settlementCenter.json b/src/i18n/locales/zh/settlementCenter.json index 86adf94..720d9ac 100644 --- a/src/i18n/locales/zh/settlementCenter.json +++ b/src/i18n/locales/zh/settlementCenter.json @@ -255,6 +255,13 @@ "recordReceiptFrom": "登记收款({{payer}} 付给 {{payee}})", "recordPayoutTo": "登记付款({{payer}} 付给 {{payee}})", "rebateAllocationsHint": "各层级代理对回水的承担明细。", + "rebateAllocParticipant": "参与方", + "rebateAllocRate": "占成", + "rebateAllocAmount": "分摊金额", + "rebateAllocTotal": "合计", + "rebateAllocTicket": "注单", + "showRawRebateAllocations": "展开按注单明细 ({{count}})", + "hideRawRebateAllocations": "收起按注单明细", "payment": "收付", "flowHint": { "playerPayAgent": "玩家应向直属代理结算", diff --git a/src/modules/settlement/agent-bill-detail.tsx b/src/modules/settlement/agent-bill-detail.tsx index d63d884..d0340b8 100644 --- a/src/modules/settlement/agent-bill-detail.tsx +++ b/src/modules/settlement/agent-bill-detail.tsx @@ -199,30 +199,40 @@ export function AgentBillDetail({ button: null, onClick: null, }; - const rebateAllocationSummary = Object.values( - rebateAllocations.reduce>( - (acc, row) => { - const label = row.participant_label ?? `${row.participant_type}#${row.participant_id}`; - const key = `${row.participant_type}:${row.participant_id}:${row.allocation_rule}`; - const current = acc[key]; - if (current) { - current.amount += row.allocated_amount; - current.rows += 1; - return acc; - } + const rebateAllocationSummary = (() => { + const groups: Record = {}; + rebateAllocations.forEach((row) => { + const label = row.participant_label ?? (row.participant_type === 'platform' ? 'Platform' : `${row.participant_type}#${row.participant_id}`); + const key = `${row.participant_type}:${row.participant_id}`; + const current = groups[key]; + if (current) { + current.amount += row.allocated_amount; + current.rows += 1; + return; + } + groups[key] = { + key, + label, + shareRate: row.actual_share_rate, + amount: row.allocated_amount, + rows: 1, + rule: row.allocation_rule, + }; + }); + return Object.values(groups).sort((a, b) => b.amount - a.amount || a.label.localeCompare(b.label, 'zh-CN')); + })(); - acc[key] = { - key, - label: `${label} · ${row.allocation_rule}`, - amount: row.allocated_amount, - rows: 1, - }; + const rebateTotalAmount = rebateAllocationSummary.reduce((s, r) => s + r.amount, 0); - return acc; - }, - {}, - ), - ).sort((a, b) => b.amount - a.amount || a.label.localeCompare(b.label, "zh-CN")); + const rebateDetailByTicket = (() => { + const groups: Record = {}; + rebateAllocations.forEach((row) => { + const rid = row.rebate_record_id; + if (!groups[rid]) groups[rid] = { rebateRecordId: rid, rows: [] }; + groups[rid].rows.push(row); + }); + return Object.values(groups); + })(); const showActionError = (err: unknown, fallback: string): void => { toast.error(err instanceof LotteryApiBizError ? err.message : fallback); @@ -428,62 +438,111 @@ export function AgentBillDetail({ ) : null} {rebateAllocations.length > 0 ? ( -
-

- {t("settlementBills.rebateAllocations", { defaultValue: "回水分摊" })} -

-

- {t("settlementCenter:billDisplay.rebateAllocationsHint", { - defaultValue: "各层级代理对回水的承担明细。", - })} -

-
-
    - {rebateAllocationSummary.map((row) => ( -
  • - - {row.label} - - {t("common:count", { defaultValue: "{{count}} 条", count: row.rows })} - - - - {formatDashboardMoneyMinor(row.amount, currencyCode)} - -
  • - ))} -
- - - - {rebateDetailsOpen ? ( -
    - {rebateAllocations.map((row) => ( -
  • - - {row.participant_label ?? `${row.participant_type}#${row.participant_id}`} ·{" "} - {row.allocation_rule} - - - {formatDashboardMoneyMinor(row.allocated_amount, currencyCode)} - -
  • - ))} -
- ) : null} +
+
+

+ {t("settlementBills.rebateAllocations", { defaultValue: "回水分摊" })} +

+ + {t("settlementCenter:billDisplay.rebateAllocationsHint", { + defaultValue: "各层级承担明细", + })} +
+ + {/* 汇总表格 */} +
+ + + + + + + + + + {rebateAllocationSummary.map((row) => { + const pct = rebateTotalAmount > 0 + ? Math.round((row.amount / rebateTotalAmount) * 100) + : 0; + return ( + + + + + + ); + })} + {rebateAllocationSummary.length > 1 ? ( + + + + + ) : null} + +
+ {t("settlementCenter:billDisplay.rebateAllocParticipant", { defaultValue: "参与方" })} + + {t("settlementCenter:billDisplay.rebateAllocRate", { defaultValue: "占成" })} + + {t("settlementCenter:billDisplay.rebateAllocAmount", { defaultValue: "分摊金额" })} +
{row.label} + {row.shareRate > 0 ? `${row.shareRate}%` : "—"} + + {formatDashboardMoneyMinor(row.amount, currencyCode)} + ({pct}%) +
+ {t("settlementCenter:billDisplay.rebateAllocTotal", { defaultValue: "合计" })} + + + {formatDashboardMoneyMinor(rebateTotalAmount, currencyCode)} +
+
+ + {/* 按注单分组展开 */} + {rebateDetailByTicket.length > 1 ? ( + <> + + + {rebateDetailsOpen ? ( +
+ {rebateDetailByTicket.map((group, idx) => ( +
+

+ {t("settlementCenter:billDisplay.rebateAllocTicket", { defaultValue: "注单" })} #{idx + 1} +

+ {group.rows.map((row) => ( +
+ + {row.participant_label ?? (row.participant_type === 'platform' ? 'Platform' : `#${row.participant_id}`)} + {row.actual_share_rate > 0 ? ( + ({row.actual_share_rate}%) + ) : null} + + + {formatDashboardMoneyMinor(row.allocated_amount, currencyCode)} + +
+ ))} +
+ ))} +
+ ) : null} + + ) : null}
) : null}