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:
@@ -47,7 +47,7 @@ const zh: Record<string, string> = {
|
||||
'nav.smoke_tests': '自动化测试',
|
||||
'nav.media': '媒体库',
|
||||
'nav.players': '直属玩家',
|
||||
'nav.subAgents': '下级代理',
|
||||
'nav.subAgents': '二级代理',
|
||||
'nav.myBets': '注单查询',
|
||||
'nav.open_menu': '打开菜单',
|
||||
'nav.close_menu': '关闭菜单',
|
||||
@@ -174,7 +174,7 @@ const zh: Record<string, string> = {
|
||||
'agent_dash.liability_child': '下级代理占用',
|
||||
'page.agent_players.title': '直属玩家',
|
||||
'page.agent_players.desc': '管理你名下的直属玩家',
|
||||
'page.agent_sub.title': '下级代理',
|
||||
'page.agent_sub.title': '二级代理',
|
||||
'page.agent_sub.desc': '管理二级代理账号与授信分配',
|
||||
'page.agent_bets.title': '注单查询',
|
||||
'page.agent_bets.desc': '下级玩家的全部投注记录',
|
||||
@@ -247,7 +247,7 @@ const en: Record<string, string> = {
|
||||
'nav.smoke_tests': 'Smoke tests',
|
||||
'nav.media': 'Media Library',
|
||||
'nav.players': 'My Players',
|
||||
'nav.subAgents': 'Sub-Agents',
|
||||
'nav.subAgents': 'Tier-2 agents',
|
||||
'nav.myBets': 'Bet Search',
|
||||
'nav.open_menu': 'Open menu',
|
||||
'nav.close_menu': 'Close menu',
|
||||
@@ -374,7 +374,7 @@ const en: Record<string, string> = {
|
||||
'agent_dash.liability_child': 'Sub-agent exposure',
|
||||
'page.agent_players.title': 'My players',
|
||||
'page.agent_players.desc': 'Players under your account',
|
||||
'page.agent_sub.title': 'Sub-agents',
|
||||
'page.agent_sub.title': 'Tier-2 agents',
|
||||
'page.agent_sub.desc': 'Manage tier-2 agents and credit allocation',
|
||||
'page.agent_bets.title': 'Bet search',
|
||||
'page.agent_bets.desc': 'All bets from downstream players',
|
||||
@@ -447,7 +447,7 @@ const ms: Record<string, string> = {
|
||||
'nav.smoke_tests': 'Ujian asap',
|
||||
'nav.media': 'Perpustakaan Media',
|
||||
'nav.players': 'Pemain saya',
|
||||
'nav.subAgents': 'Sub-ejen',
|
||||
'nav.subAgents': 'Ejen peringkat 2',
|
||||
'nav.myBets': 'Carian pertaruhan',
|
||||
'nav.open_menu': 'Buka menu',
|
||||
'nav.close_menu': 'Tutup menu',
|
||||
@@ -574,7 +574,7 @@ const ms: Record<string, string> = {
|
||||
'agent_dash.liability_child': 'Pendedahan ejen bawahan',
|
||||
'page.agent_players.title': 'Pemain saya',
|
||||
'page.agent_players.desc': 'Pemain di bawah akaun anda',
|
||||
'page.agent_sub.title': 'Sub-ejen',
|
||||
'page.agent_sub.title': 'Ejen peringkat 2',
|
||||
'page.agent_sub.desc': 'Urus ejen peringkat 2 dan peruntukan kredit',
|
||||
'page.agent_bets.title': 'Carian pertaruhan',
|
||||
'page.agent_bets.desc': 'Semua pertaruhan pemain hiliran',
|
||||
|
||||
@@ -100,13 +100,21 @@ export const adminPagesMs: Record<string, string> = {
|
||||
'user.field.account_type': 'Jenis akaun',
|
||||
'user.type.player': 'Pemain',
|
||||
'user.type.tier1_agent': 'Ejen peringkat 1',
|
||||
'user.type.sub_agent': 'Sub-ejen',
|
||||
'user.type.sub_agent': 'Ejen peringkat 2',
|
||||
'user.hint.account_type': 'Ejen guna had kredit; pemain boleh di bawah ejen',
|
||||
|
||||
'agent.create_btn': '+ Ejen peringkat 1 baharu',
|
||||
'agent.create_sub_btn': '+ Ejen peringkat 2 baharu',
|
||||
'agent.create_sub': 'Cipta sub-ejen',
|
||||
'agent.hint.sub_agent_parent': 'Ejen peringkat 2 mesti di bawah ejen peringkat 1',
|
||||
'agent.create_sub': 'Cipta ejen peringkat 2',
|
||||
'agent.create_child_btn': '+ Sub-ejen baharu',
|
||||
'agent.dialog.create_child_agent': 'Sub-ejen baharu',
|
||||
'agent.create_level_agent': 'Cipta ejen peringkat {level}',
|
||||
'agent.create_level_agent_btn': '+ Ejen peringkat {level} baharu',
|
||||
'agent.level_name': 'Ejen peringkat {level}',
|
||||
'agent.level_tab': 'Ejen peringkat {level}',
|
||||
'agent.dialog.create_level_agent': 'Ejen peringkat {level} baharu',
|
||||
'agent.hint.select_parent_for_level': 'Pilih ejen peringkat {level} sebagai induk',
|
||||
'agent.err.parent_level_mismatch': 'Peringkat induk tidak sah untuk cipta ejen peringkat {level}',
|
||||
'agent.hint.creating_under_agent': 'Cipta akaun di bawah ejen ini',
|
||||
'agent.filter.username_ph': 'Nama pengguna',
|
||||
'agent_mgr.tab.players': 'Pemain',
|
||||
@@ -150,6 +158,37 @@ export const adminPagesMs: Record<string, string> = {
|
||||
'agent.credit_tx.view_all': 'Lihat semua lejar kredit',
|
||||
'finance.tab.credit': 'Lejar kredit',
|
||||
'finance.tab.transfer': 'Lejar pemindahan',
|
||||
'finance.tab.wallet': 'Lejar dompet',
|
||||
'finance.filter.type_category': 'Jenis transaksi',
|
||||
'finance.filter.type_category_all': 'Semua',
|
||||
'finance.filter.type_category_deposit': 'Pemindahan',
|
||||
'finance.filter.type_category_bet': 'Pertaruhan',
|
||||
'finance.filter.type_category_cashback': 'Rebat',
|
||||
'finance.col.frozen_before': 'Beku sebelum',
|
||||
'finance.col.frozen_after': 'Beku selepas',
|
||||
'finance.col.reference': 'Pertaruhan berkaitan',
|
||||
'finance.tx.adjust': 'Pelarasan baki',
|
||||
'finance.tx.bet_freeze': 'Beku pertaruhan',
|
||||
'finance.tx.bet_deduct': 'Potong pertaruhan',
|
||||
'finance.tx.bet_win': 'Bayaran pertaruhan',
|
||||
'finance.tx.bet_lose': 'Penyelesaian pertaruhan',
|
||||
'finance.tx.bet_push': 'Refund seri',
|
||||
'finance.tx.bet_refund': 'Refund pertaruhan',
|
||||
'finance.tx.bet_void': 'Pertaruhan batal',
|
||||
'finance.tx.cashback': 'Rebat',
|
||||
'finance.tx.resettle': 'Penyelesaian semula',
|
||||
'user.action.view_wallet_ledger': 'Lihat lejar dompet',
|
||||
'user.wallet_ledger_dialog_title': 'Lejar dompet — {name}',
|
||||
'agent.hierarchy.settings_title': 'Hierarki ejen',
|
||||
'agent.hierarchy.settings_hint': '0 bermaksud tanpa had. Ejen di had atas tidak boleh cipta sub-ejen.',
|
||||
'agent.hierarchy.max_level': 'Tahap ejen maksimum',
|
||||
'agent.hierarchy.default_sub_credit_ratio': 'Nisbah kredit sub-ejen lalai',
|
||||
'agent.hierarchy.create_credit_default_hint': 'Lalai {ratio}% ({amount}), tidak melebihi kredit induk; boleh diselaraskan',
|
||||
'agent.hierarchy.create_credit_quick_hint': 'Kredit induk tersedia {amount} — klik nisbah untuk isi',
|
||||
'agent.hierarchy.create_level_hint': 'Akan dicipta sebagai ejen peringkat {n}',
|
||||
'agent.field.parent_agent': 'Ejen induk',
|
||||
'agent.col.parent_chain': 'Rantaian induk',
|
||||
'role.agent_level': 'Ejen peringkat {n}',
|
||||
'finance.filter.date_range': 'Julat tarikh',
|
||||
'finance.filter.player_ph': 'Nama pengguna pemain',
|
||||
'finance.filter.parent_agent_ph': 'Nama/ID ejen induk',
|
||||
|
||||
@@ -106,13 +106,21 @@ export const adminPagesZh: Record<string, string> = {
|
||||
'agent.create_btn': '+ 新建一级代理',
|
||||
'agent.create_sub_btn': '+ 新建二级代理',
|
||||
'agent.create_sub': '创建二级代理',
|
||||
'agent.hint.sub_agent_parent': '二级代理必须挂靠在一级代理名下',
|
||||
'agent.create_child_btn': '+ 新建下级代理',
|
||||
'agent.dialog.create_child_agent': '新建下级代理',
|
||||
'agent.create_level_agent': '创建{level}级代理',
|
||||
'agent.create_level_agent_btn': '+ 新建{level}级代理',
|
||||
'agent.level_name': '{level}级代理',
|
||||
'agent.level_tab': '{level}级代理',
|
||||
'agent.dialog.create_level_agent': '新建{level}级代理',
|
||||
'agent.hint.select_parent_for_level': '请选择 {level} 级代理作为上级',
|
||||
'agent.err.parent_level_mismatch': '上级代理层级不正确,无法创建 {level} 级代理',
|
||||
'agent.hint.creating_under_agent': '在此代理下创建账号',
|
||||
'agent.filter.username_ph': '用户名',
|
||||
'agent_mgr.tab.players': '玩家',
|
||||
'agent_mgr.tab.agents': '代理',
|
||||
'agent.col.level': '层级',
|
||||
'agent.col.credit': '授信 / 已用 / 可用',
|
||||
'agent.col.credit': '授信/已用/可用',
|
||||
'agent.col.direct_players': '直属玩家',
|
||||
'agent.direct_players_title': '直属玩家 · {name}',
|
||||
'agent.platform_row_name': '平台',
|
||||
@@ -153,6 +161,38 @@ export const adminPagesZh: Record<string, string> = {
|
||||
'agent.credit_tx.view_all': '查看全部额度流水',
|
||||
'finance.tab.credit': '额度流水',
|
||||
'finance.tab.transfer': '上下分流水',
|
||||
'finance.tab.wallet': '钱包流水',
|
||||
'finance.filter.type_category': '流水类型',
|
||||
'finance.filter.type_category_all': '全部',
|
||||
'finance.filter.type_category_deposit': '上下分',
|
||||
'finance.filter.type_category_bet': '投注',
|
||||
'finance.filter.type_category_cashback': '返水',
|
||||
'finance.col.frozen_before': '变动前冻结',
|
||||
'finance.col.frozen_after': '变动后冻结',
|
||||
'finance.col.reference': '关联注单',
|
||||
'finance.tx.adjust': '余额调整',
|
||||
'finance.tx.bet_freeze': '投注冻结',
|
||||
'finance.tx.bet_deduct': '投注扣款',
|
||||
'finance.tx.bet_win': '投注派彩',
|
||||
'finance.tx.bet_lose': '投注结算',
|
||||
'finance.tx.bet_push': '走水返还',
|
||||
'finance.tx.bet_refund': '投注退款',
|
||||
'finance.tx.bet_void': '注单作废',
|
||||
'finance.tx.cashback': '返水',
|
||||
'finance.tx.resettle': '重结算调整',
|
||||
'user.action.view_wallet_ledger': '查看资金流水',
|
||||
'user.wallet_ledger_dialog_title': '{name} 的资金流水',
|
||||
'agent.hierarchy.settings_title': '代理层级设置',
|
||||
'agent.hierarchy.settings_hint': '0 表示不限制代理层级;达到上限的代理将无法创建下级。下级默认授信比例用于创建下级代理时的预填额度。',
|
||||
'agent.hierarchy.max_level': '最大代理层级',
|
||||
'agent.hierarchy.default_sub_credit_ratio': '下级默认授信比例',
|
||||
'agent.hierarchy.default_sub_credit_ratio_hint': '创建下级代理时,授信额度默认预填为上级可用授信 × 此比例',
|
||||
'agent.hierarchy.create_credit_default_hint': '默认 {ratio}%({amount}),不超过上级可用授信,可手动调整',
|
||||
'agent.hierarchy.create_credit_quick_hint': '上级可用授信 {amount},点击比例快速填入',
|
||||
'agent.hierarchy.create_level_hint': '将创建为 {n} 级代理',
|
||||
'agent.field.parent_agent': '上级代理',
|
||||
'agent.col.parent_chain': '上级链路',
|
||||
'role.agent_level': '{n}级代理',
|
||||
'finance.filter.date_range': '时间范围',
|
||||
'finance.filter.player_ph': '玩家用户名',
|
||||
'finance.filter.parent_agent_ph': '上级代理用户名或 ID',
|
||||
@@ -176,17 +216,15 @@ export const adminPagesZh: Record<string, string> = {
|
||||
'agent.field.select_user': '选择用户',
|
||||
'agent.ph.select_user': '搜索玩家用户名',
|
||||
'agent.hint.select_user': '从已有玩家账号中选择,将其设为一级代理(不新建登录账号)',
|
||||
'agent.suspend.settings_title': '代理停用策略',
|
||||
'agent.suspend.settings_hint': 'MVP 默认仅停用代理操作权限,不自动冻结或禁止其直属玩家登录。',
|
||||
'agent.suspend.freeze_direct_players': '停用时允许级联冻结直属玩家',
|
||||
'agent.suspend.block_player_login': '上级代理停用时禁止直属玩家登录',
|
||||
'agent.suspend.cascade_disabled_hint': '未开启级联冻结,仅停用该代理操作权限,直属玩家不受影响。',
|
||||
'agent.freeze.confirm_freeze_title': '确认停用代理',
|
||||
'agent.freeze.confirm_freeze_body': '确定停用代理「{name}」?停用后该代理无法登录代理端。',
|
||||
'agent.freeze.confirm_unfreeze_body': '确定恢复代理「{name}」为正常状态?',
|
||||
'agent.freeze.cascade_hint': '是否同时冻结该代理名下所有直属玩家账号?',
|
||||
'agent.freeze.cascade_label': '级联冻结直属玩家',
|
||||
'agent.freeze.opt_freeze_direct_players': '同时冻结直属玩家',
|
||||
'agent.freeze.opt_block_player_login': '禁止直属玩家登录',
|
||||
'agent.unfreeze.confirm_title': '确认恢复代理',
|
||||
'agent.unfreeze.opt_unfreeze_direct_players': '同时解冻直属玩家',
|
||||
'agent.msg.cascade_freeze_done': '已停用代理并冻结其直属玩家',
|
||||
'agent.msg.cascade_unfreeze_done': '已恢复代理并解冻其直属玩家',
|
||||
'agent.msg.freeze_done': '已{action}',
|
||||
|
||||
'match.create_btn': '+ 新增联赛',
|
||||
@@ -931,13 +969,21 @@ export const adminPagesEn: Record<string, string> = {
|
||||
'user.field.account_type': 'Account type',
|
||||
'user.type.player': 'Player',
|
||||
'user.type.tier1_agent': 'Tier-1 agent',
|
||||
'user.type.sub_agent': 'Sub-agent',
|
||||
'user.type.sub_agent': 'Tier-2 agent',
|
||||
'user.hint.account_type': 'Agents use credit limits; players can belong to an agent and receive top-ups',
|
||||
|
||||
'agent.create_btn': '+ New tier-1 agent',
|
||||
'agent.create_sub_btn': '+ New tier-2 agent',
|
||||
'agent.create_sub': 'Create sub-agent',
|
||||
'agent.hint.sub_agent_parent': 'Tier-2 agents must belong to a tier-1 agent',
|
||||
'agent.create_sub': 'Create tier-2 agent',
|
||||
'agent.create_child_btn': '+ New sub-agent',
|
||||
'agent.dialog.create_child_agent': 'New sub-agent',
|
||||
'agent.create_level_agent': 'Create L{level} agent',
|
||||
'agent.create_level_agent_btn': '+ New L{level} agent',
|
||||
'agent.level_name': 'Tier-{level} agent',
|
||||
'agent.level_tab': 'L{level} agents',
|
||||
'agent.dialog.create_level_agent': 'New L{level} agent',
|
||||
'agent.hint.select_parent_for_level': 'Select a level-{level} agent as parent',
|
||||
'agent.err.parent_level_mismatch': 'Invalid parent level for creating a level-{level} agent',
|
||||
'agent.hint.creating_under_agent': 'Create account under this agent',
|
||||
'agent.filter.username_ph': 'Username',
|
||||
'agent_mgr.tab.players': 'Players',
|
||||
@@ -984,6 +1030,38 @@ export const adminPagesEn: Record<string, string> = {
|
||||
'agent.credit_tx.view_all': 'View all credit ledger',
|
||||
'finance.tab.credit': 'Credit ledger',
|
||||
'finance.tab.transfer': 'Transfer ledger',
|
||||
'finance.tab.wallet': 'Wallet ledger',
|
||||
'finance.filter.type_category': 'Transaction type',
|
||||
'finance.filter.type_category_all': 'All',
|
||||
'finance.filter.type_category_deposit': 'Transfers',
|
||||
'finance.filter.type_category_bet': 'Bets',
|
||||
'finance.filter.type_category_cashback': 'Cashback',
|
||||
'finance.col.frozen_before': 'Frozen before',
|
||||
'finance.col.frozen_after': 'Frozen after',
|
||||
'finance.col.reference': 'Related bet',
|
||||
'finance.tx.adjust': 'Balance adjustment',
|
||||
'finance.tx.bet_freeze': 'Bet freeze',
|
||||
'finance.tx.bet_deduct': 'Bet deduct',
|
||||
'finance.tx.bet_win': 'Bet payout',
|
||||
'finance.tx.bet_lose': 'Bet settlement',
|
||||
'finance.tx.bet_push': 'Push refund',
|
||||
'finance.tx.bet_refund': 'Bet refund',
|
||||
'finance.tx.bet_void': 'Bet void',
|
||||
'finance.tx.cashback': 'Cashback',
|
||||
'finance.tx.resettle': 'Resettlement',
|
||||
'user.action.view_wallet_ledger': 'View wallet ledger',
|
||||
'user.wallet_ledger_dialog_title': 'Wallet ledger — {name}',
|
||||
'agent.hierarchy.settings_title': 'Agent hierarchy',
|
||||
'agent.hierarchy.settings_hint': '0 means unlimited levels. Agents at the cap cannot create sub-agents. The default credit ratio pre-fills sub-agent credit limits.',
|
||||
'agent.hierarchy.max_level': 'Max agent level',
|
||||
'agent.hierarchy.default_sub_credit_ratio': 'Default sub-agent credit ratio',
|
||||
'agent.hierarchy.default_sub_credit_ratio_hint': 'When creating a sub-agent, pre-fill credit as parent available × this ratio',
|
||||
'agent.hierarchy.create_credit_default_hint': 'Default {ratio}% ({amount}), capped by parent available credit; adjustable',
|
||||
'agent.hierarchy.create_credit_quick_hint': 'Parent available {amount} — click a ratio to fill',
|
||||
'agent.hierarchy.create_level_hint': 'Will be created as level {n} agent',
|
||||
'agent.field.parent_agent': 'Parent agent',
|
||||
'agent.col.parent_chain': 'Parent chain',
|
||||
'role.agent_level': 'Level {n} agent',
|
||||
'finance.filter.date_range': 'Date range',
|
||||
'finance.filter.player_ph': 'Player username',
|
||||
'finance.filter.parent_agent_ph': 'Parent agent username or ID',
|
||||
@@ -1007,17 +1085,15 @@ export const adminPagesEn: Record<string, string> = {
|
||||
'agent.field.select_user': 'Select user',
|
||||
'agent.ph.select_user': 'Search player username',
|
||||
'agent.hint.select_user': 'Pick an existing player account to promote to tier-1 agent (no new login)',
|
||||
'agent.suspend.settings_title': 'Agent suspension policy',
|
||||
'agent.suspend.settings_hint': 'MVP default: suspend agent operations only; do not auto-freeze or block direct players.',
|
||||
'agent.suspend.freeze_direct_players': 'Allow cascade freeze of direct players on suspend',
|
||||
'agent.suspend.block_player_login': 'Block direct player login when parent agent is suspended',
|
||||
'agent.suspend.cascade_disabled_hint': 'Cascade freeze is off; only the agent is suspended, direct players are unaffected.',
|
||||
'agent.freeze.confirm_freeze_title': 'Confirm suspend agent',
|
||||
'agent.freeze.confirm_freeze_body': 'Suspend agent "{name}"? They will not be able to sign in to the agent portal.',
|
||||
'agent.freeze.confirm_unfreeze_body': 'Restore agent "{name}" to active status?',
|
||||
'agent.freeze.cascade_hint': 'Also freeze all direct player accounts under this agent?',
|
||||
'agent.freeze.cascade_label': 'Cascade freeze direct players',
|
||||
'agent.freeze.opt_freeze_direct_players': 'Also freeze direct players',
|
||||
'agent.freeze.opt_block_player_login': 'Block direct player login',
|
||||
'agent.unfreeze.confirm_title': 'Confirm restore agent',
|
||||
'agent.unfreeze.opt_unfreeze_direct_players': 'Also unfreeze direct players',
|
||||
'agent.msg.cascade_freeze_done': 'Agent suspended and direct players frozen',
|
||||
'agent.msg.cascade_unfreeze_done': 'Agent restored and direct players unfrozen',
|
||||
'agent.msg.freeze_done': '{action} completed',
|
||||
|
||||
'match.create_btn': '+ New league',
|
||||
|
||||
Reference in New Issue
Block a user