feat: 手动充值、邀请码注册与后台管理增强

新增玩家手动充值全流程(收款方式配置、充值下单/审核、钱包上分),
支持邀请码注册、邀请历史与专属返水率;完善后台代理/玩家管理与响应式操作栏,
并补充前台注册、充值页及多语言错误码。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-11 12:20:11 +08:00
parent 618fb49511
commit 10485ecfaf
98 changed files with 7908 additions and 856 deletions

View File

@@ -27,6 +27,7 @@ export const adminPagesMs: Record<string, string> = {
'user.filter.agent_ph': 'Semua',
'user.col.username': 'Nama pengguna',
'user.col.agent': 'Ejen',
'user.col.invite_code': 'Kod jemputan',
'user.col.balance': 'Tersedia / Dibekukan',
'user.col.bets': 'Pertaruhan',
'user.col.stake_payout': 'Stake / Bayaran',
@@ -141,7 +142,7 @@ export const adminPagesMs: Record<string, string> = {
'agent.field.player_liability': 'Liabiliti pemain',
'agent.field.sub_agent_exposure': 'Pendedahan sub-ejen',
'agent.hint.credit_limit': 'Had maksimum tambah baki untuk pemain terus',
'agent.hint.cashback_example': 'cth. 0.01 = 1%',
'agent.hint.cashback_example': 'cth. 1 bermaksud 1%',
'agent.hint.credit_adjust': 'Positif menambah, negatif mengurangkan',
'agent.hint.credit_remark': 'Pilihan, ditulis ke lejar kredit',
'agent.section.credit_log': 'Perubahan kredit terkini',
@@ -178,6 +179,7 @@ export const adminPagesMs: Record<string, string> = {
'finance.tx.cashback': 'Rebat',
'finance.tx.resettle': 'Penyelesaian semula',
'user.action.view_wallet_ledger': 'Lihat lejar dompet',
'user.action.ledger_short': 'Lejar',
'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.',
@@ -199,6 +201,11 @@ export const adminPagesMs: Record<string, string> = {
'finance.col.balance_change': 'Perubahan baki',
'finance.col.balance_before': 'Baki sebelum',
'finance.col.balance_after': 'Baki selepas',
'finance.col.tx_type': 'Jenis',
'finance.col.deposit_method': 'Kaedah deposit',
'finance.deposit_method.manual_admin': 'Deposit manual admin',
'finance.deposit_method.manual_agent': 'Deposit manual ejen',
'finance.deposit_method.manual': 'Deposit manual',
'finance.tx.deposit': 'Deposit',
'finance.tx.withdraw': 'Pengeluaran',
'finance.tx.request_id': 'ID permintaan',
@@ -372,10 +379,17 @@ export const adminPagesMs: Record<string, string> = {
'cashback.rule_period': 'Pilih julat tarikh. Taruhan dikira mengikut masa penyelesaian dalam tempoh tersebut.',
'cashback.rule_eligible': 'Termasuk: taruhan selesai WON/LOST (tunggal ikut stake; parlay sekali ikut stake parlay). Tidak termasuk: belum selesai, dibatalkan, batal, push, kadar 0, dan taruhan yang sudah dibayar rebat.',
'cashback.rule_formula': 'Setiap taruhan: stake × kadar rebat. Jumlah diagregat mengikut pemain.',
'cashback.rule_rate': 'Keutamaan kadar: pemain > ejen > global > kadar lalai ejen (cth. 0.01 = 1%).',
'cashback.rule_rate': 'Keutamaan kadar: pemain > ejen > global > kadar lalai (pemain bawah ejen guna kadar ejen; pemain terus platform guna kadar dalam Tetapan global; boleh ganti setiap pemain). Isi peratus, cth. 1 = 1%.',
'cashback.rule_flow': 'Aliran: pratonton (satu menunggu setiap tempoh) → semak → sahkan bayaran; batalkan jika tidak perlu. Tempoh dibayar tidak boleh pratonton semula.',
'cashback.rule_platform': 'Bayaran: rebat dikreditkan ke baki tunai pemain oleh platform; tidak ditolak daripada kredit atau baki ejen.',
'cashback.rule_note_zero': 'Jika 0, semak taruhan WON/LOST dalam tempoh dan kadar rebat > 0.',
'cashback.rule_note_zero': 'Jika 0, semak taruhan WON/LOST dalam tempoh dan kadar rebat > 0 (termasuk lalai terus platform dalam Tetapan global dan tetapan pemain/ejen).',
'cashback.use_custom_rate': 'Tetapkan kadar rebat khusus',
'cashback.use_default_rate': 'Guna kadar lalai {rate}',
'cashback.settings_title': 'Tetapan rebat',
'cashback.platform_direct_default_rate': 'Kadar rebat lalai terus platform',
'cashback.platform_direct_default_hint': 'Pemain daftar sendiri tanpa kod jemputan guna kadar ini melainkan ditetapkan secara individu.',
'cashback.admin_invite_default_rate': 'Kadar rebat jemputan admin',
'cashback.admin_invite_default_hint': 'Pemain daftar dengan kod jemputan admin; lalai sama dengan terus platform. Jemputan ejen guna kadar ejen yang ditetapkan admin.',
'user.field.player_id': 'ID pemain',
'user.field.bet_count': 'Bilangan pertaruhan',
@@ -544,6 +558,57 @@ export const adminPagesMs: Record<string, string> = {
'agent_portal.initial_deposit_hint': 'Pilihan. Tambah baki awal dari kredit anda semasa pendaftaran',
'agent_portal.search_player_ph': 'Nama pengguna atau ID',
'agent_portal.no_players': 'Tiada pemain langsung. Klik butang di atas untuk cipta.',
'invite.title': 'Kod jemputan & pautan daftar',
'invite.menu_btn': 'Jemputan',
'invite.dialog_title': 'Pengurusan jemputan',
'invite.tab_generate': 'Jana jemputan',
'invite.tab_history': 'Sejarah',
'invite.hint': 'Klik untuk jana kod jemputan dan pautan daftar. Pemain boleh masukkan kod; kosongkan untuk terus platform.',
'invite.generate_btn': 'Jana kod / pautan',
'invite.regenerate_btn': 'Jana semula',
'invite.generate_ok': 'Kod jemputan dijana',
'invite.generate_failed': 'Gagal jana — sila cuba lagi',
'invite.not_generated': 'Belum jana kod jemputan',
'invite.code': 'Kod jemputan',
'invite.cashback_rate': 'Kadar rebat',
'invite.cashback_rate_hint': 'Pemain yang daftar dengan kod ini guna kadar ini. Lalai dari kadar jemputan admin global.',
'invite.link': 'Pautan daftar',
'invite.copy_code': 'Salin kod',
'invite.copy_code_short': 'Salin',
'invite.copy_link_short': 'Salin pautan',
'invite.copy_link': 'Salin pautan daftar',
'invite.copy_code_ok': 'Kod jemputan disalin',
'invite.copy_link_ok': 'Pautan daftar disalin',
'invite.copy_failed': 'Salinan gagal — sila salin secara manual',
'invite.unavailable': 'Kod jemputan tidak tersedia',
'invite.history_title': 'Sejarah jemputan',
'invite.view_history': 'Lihat sejarah',
'invite.history_hint': 'Admin lihat semua kod; ejen lihat kod sendiri dan ejen bawahan.',
'invite.page_desc': 'Lihat sejarah kod jemputan, status dan bilangan pendaftaran.',
'invite.history_load_failed': 'Gagal memuatkan sejarah jemputan',
'invite.filter_status': 'Status',
'invite.filter_sponsor': 'Penjemput',
'invite.filter_code': 'Kod',
'invite.filter_code_ph': 'Masukkan kod',
'invite.col_status': 'Status',
'invite.col_sponsor': 'Penjemput',
'invite.col_registrant': 'Pendaftar',
'invite.not_registered': 'Belum daftar',
'invite.col_cashback_rate': 'Rebat',
'invite.col_created': 'Dicipta',
'invite.col_revoked': 'Dibatalkan',
'invite.status.ACTIVE': 'Aktif',
'invite.status.USED': 'Digunakan',
'invite.status.REVOKED': 'Dibatalkan',
'invite.revoke_btn': 'Batalkan',
'invite.revoke_title': 'Batalkan kod jemputan',
'invite.revoke_confirm': 'Batalkan kod {code}? Kod tidak boleh digunakan untuk pendaftaran.',
'invite.revoke_ok': 'Kod jemputan dibatalkan',
'invite.revoke_failed': 'Gagal batalkan — sila cuba lagi',
'invite.delete_title': 'Padam rekod jemputan',
'invite.delete_confirm': 'Padam sejarah kod {code}? Tindakan ini tidak boleh dibatalkan.',
'invite.delete_ok': 'Rekod jemputan dipadam',
'invite.delete_failed': 'Gagal padam — sila cuba lagi',
'agent_portal.search_sub_agent_ph': 'Nama pengguna atau ID',
'agent_portal.no_sub_agents': 'Tiada ejen peringkat 2. Klik butang di atas untuk cipta.',
'agent_portal.no_sub_agents_level': 'Tiada ejen peringkat {level}. Klik butang di atas untuk cipta.',