feat: multi-tier agent hierarchy, wallet ledger, and player UX polish

Add configurable agent max level and default sub-agent credit ratio, per-agent block direct player login on suspend, admin/agent wallet transaction views, and match detail my-bets section with refreshed player card styling.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-10 16:15:34 +08:00
parent 641c92a5f5
commit ef6b15f119
39 changed files with 2398 additions and 410 deletions

View File

@@ -0,0 +1,20 @@
const ZH_LEVEL_NUMERALS: Record<number, string> = {
1: '一',
2: '二',
3: '三',
4: '四',
5: '五',
6: '六',
7: '七',
8: '八',
9: '九',
10: '十',
};
/** 中文界面用「一、二、三…」,其他语言用阿拉伯数字 */
export function formatAgentLevelNumeral(level: number, locale: string): string {
if (locale.startsWith('zh') && ZH_LEVEL_NUMERALS[level]) {
return ZH_LEVEL_NUMERALS[level];
}
return String(level);
}

View File

@@ -47,6 +47,8 @@ export async function hydrateStaffSession(): Promise<boolean> {
locale: raw.locale,
role: raw.role,
agentLevel: typeof raw.agentLevel === 'number' ? raw.agentLevel : null,
maxAgentLevel: typeof raw.maxAgentLevel === 'number' ? raw.maxAgentLevel : null,
canManageSubAgents: raw.canManageSubAgents === true,
});
return true;
} catch (e: unknown) {

View File

@@ -0,0 +1,23 @@
export const TX_KEY_MAP: Record<string, string> = {
MANUAL_DEPOSIT: 'finance.tx.deposit',
MANUAL_WITHDRAW: 'finance.tx.withdraw',
MANUAL_ADJUST: 'finance.tx.adjust',
BET_FREEZE: 'finance.tx.bet_freeze',
BET_DEDUCT: 'finance.tx.bet_deduct',
BET_SETTLE_WIN: 'finance.tx.bet_win',
BET_SETTLE_LOSE: 'finance.tx.bet_lose',
BET_SETTLE_PUSH: 'finance.tx.bet_push',
BET_WIN: 'finance.tx.bet_win',
BET_REFUND: 'finance.tx.bet_refund',
BET_VOID: 'finance.tx.bet_void',
BET_VOID_REFUND: 'finance.tx.bet_void',
CASHBACK: 'finance.tx.cashback',
CASHBACK_DEPOSIT: 'finance.tx.cashback',
RESETTLE_REVERSE: 'finance.tx.resettle',
DEPOSIT: 'finance.tx.deposit',
WITHDRAW: 'finance.tx.withdraw',
};
export function walletTxTypeKey(type: string): string {
return TX_KEY_MAP[type.toUpperCase()] ?? '';
}