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

@@ -33,6 +33,7 @@ const zh: Record<string, string> = {
'nav.dashboard': '概览',
'nav.dashboard.matches': '赛事概览',
'nav.dashboard.players': '玩家概览',
'nav.invites': '邀请管理',
'nav.users': '玩家管理',
'nav.agents': '代理管理',
'nav.agents_players': '代理&玩家',
@@ -46,7 +47,61 @@ const zh: Record<string, string> = {
'nav.audit': '操作日志',
'nav.smoke_tests': '自动化测试',
'nav.media': '媒体库',
'nav.payment_methods': '收款方式',
'nav.deposit_orders': '充值审核',
'nav.deposit_manage': '充值管理',
'nav.players': '直属玩家',
'deposit.payment_methods_title': '收款方式管理',
'deposit.deposit_orders_title': '充值审核',
'deposit.all_status': '所有状态',
'deposit.all_types': '所有类型',
'deposit.status_pending': '待审核',
'deposit.status_approved': '已通过',
'deposit.status_rejected': '已拒绝',
'deposit.search_player_ph': '搜索玩家...',
'deposit.order_no': '订单号',
'deposit.player': '玩家',
'deposit.amount': '金额',
'deposit.screenshot': '截图',
'deposit.approved_amount': '批准金额',
'deposit.reviewer': '审核人',
'deposit.time': '时间',
'deposit.approve': '批准',
'deposit.reject': '拒绝',
'deposit.approve_title': '批准充值',
'deposit.reject_title': '拒绝充值',
'deposit.submitted_amount': '申报金额',
'deposit.approved_amount_label': '批准金额(可调整)',
'deposit.remark_label': '备注(可选)',
'deposit.confirm_approve': '确认批准',
'deposit.confirm_reject': '确认拒绝',
'deposit.reject_reason_label': '拒绝原因 *',
'deposit.reject_reason_ph': '请输入拒绝原因...',
'deposit.reason_required': '请输入拒绝原因',
'deposit.prev': '上一页',
'deposit.next': '下一页',
'deposit.add_method': '+ 添加',
'deposit.display_name': '展示名称',
'deposit.details': '详情',
'deposit.sort': '排序',
'deposit.active': '启用',
'deposit.show_player': '前台展示',
'deposit.edit_method': '编辑收款方式',
'deposit.create_method': '新建收款方式',
'deposit.bank_name': '银行名称',
'deposit.account_holder': '账户持有人',
'deposit.account_number': '银行账号',
'deposit.usdt_address': 'USDT 地址',
'deposit.qr_code': '二维码',
'deposit.sort_order': '排序序号',
'deposit.show_on_player': '展示给玩家',
'deposit.save': '保存',
'deposit.confirm_deactivate': '确认停用此收款方式?',
'deposit.lang_zh': '中文',
'deposit.lang_en': 'English',
'deposit.lang_ms': 'Bahasa',
'deposit.multilingual_hint': '为不同语言设置显示名称,留空则使用默认值',
'nav.subAgents': '二级代理',
'nav.myBets': '注单查询',
'nav.open_menu': '打开菜单',
@@ -90,6 +145,10 @@ const zh: Record<string, string> = {
'common.used': '已用',
'common.platform_direct': '平台直属',
'common.updated_at': '更新于',
'common.enable': '启用',
'common.disable': '停用',
'common.show_player': '前台展示',
'common.hide_player': '前台隐藏',
'dash.title': '概览',
'dash.desc': '平台整体运行概况',
@@ -233,6 +292,7 @@ const en: Record<string, string> = {
'nav.dashboard': 'Overview',
'nav.dashboard.matches': 'Match overview',
'nav.dashboard.players': 'Player overview',
'nav.invites': 'Invitations',
'nav.users': 'Players',
'nav.agents': 'Agents',
'nav.agents_players': 'Agents & Players',
@@ -246,9 +306,63 @@ const en: Record<string, string> = {
'nav.audit': 'Audit Log',
'nav.smoke_tests': 'Smoke tests',
'nav.media': 'Media Library',
'nav.payment_methods': 'Payment Methods',
'nav.deposit_orders': 'Deposit Review',
'nav.deposit_manage': 'Deposit Mgmt',
'nav.players': 'My Players',
'nav.subAgents': 'Tier-2 agents',
'nav.myBets': 'Bet Search',
'deposit.payment_methods_title': 'Payment Methods',
'deposit.deposit_orders_title': 'Deposit Review',
'deposit.all_status': 'All Status',
'deposit.all_types': 'All Types',
'deposit.status_pending': 'Pending',
'deposit.status_approved': 'Approved',
'deposit.status_rejected': 'Rejected',
'deposit.search_player_ph': 'Search player...',
'deposit.order_no': 'Order No',
'deposit.player': 'Player',
'deposit.amount': 'Amount',
'deposit.screenshot': 'Screenshot',
'deposit.approved_amount': 'Approved Amt',
'deposit.reviewer': 'Reviewer',
'deposit.time': 'Time',
'deposit.approve': 'Approve',
'deposit.reject': 'Reject',
'deposit.approve_title': 'Approve Deposit',
'deposit.reject_title': 'Reject Deposit',
'deposit.submitted_amount': 'Submitted Amount',
'deposit.approved_amount_label': 'Approved Amount (adjust if needed)',
'deposit.remark_label': 'Remark (optional)',
'deposit.confirm_approve': 'Confirm Approve',
'deposit.confirm_reject': 'Confirm Reject',
'deposit.reject_reason_label': 'Reject Reason *',
'deposit.reject_reason_ph': 'Enter the reason for rejection...',
'deposit.reason_required': 'Please enter a reject reason',
'deposit.prev': 'Prev',
'deposit.next': 'Next',
'deposit.add_method': '+ Add',
'deposit.display_name': 'Display Name',
'deposit.details': 'Details',
'deposit.sort': 'Sort',
'deposit.active': 'Active',
'deposit.show_player': 'Show Player',
'deposit.edit_method': 'Edit Payment Method',
'deposit.create_method': 'Create Payment Method',
'deposit.bank_name': 'Bank Name',
'deposit.account_holder': 'Account Holder',
'deposit.account_number': 'Account Number',
'deposit.usdt_address': 'USDT Address',
'deposit.qr_code': 'QR Code',
'deposit.sort_order': 'Sort Order',
'deposit.show_on_player': 'Show on Player',
'deposit.save': 'Save',
'deposit.confirm_deactivate': 'Confirm deactivate this payment method?',
'deposit.lang_zh': 'Chinese',
'deposit.lang_en': 'English',
'deposit.lang_ms': 'Malay',
'deposit.multilingual_hint': 'Set display names for each language. Leave blank to use default.',
'nav.open_menu': 'Open menu',
'nav.close_menu': 'Close menu',
'breadcrumb.settlement': 'Settlement',
@@ -290,6 +404,10 @@ const en: Record<string, string> = {
'common.used': 'Used',
'common.platform_direct': 'Platform direct',
'common.updated_at': 'Updated',
'common.enable': 'Enable',
'common.disable': 'Disable',
'common.show_player': 'Show player',
'common.hide_player': 'Hide player',
'dash.title': 'Overview',
'dash.desc': 'Platform overview',
@@ -433,6 +551,7 @@ const ms: Record<string, string> = {
'nav.dashboard': 'Gambaran',
'nav.dashboard.matches': 'Gambaran perlawanan',
'nav.dashboard.players': 'Gambaran pemain',
'nav.invites': 'Jemputan',
'nav.users': 'Pemain',
'nav.agents': 'Ejen',
'nav.agents_players': 'Ejen & Pemain',
@@ -446,9 +565,63 @@ const ms: Record<string, string> = {
'nav.audit': 'Log audit',
'nav.smoke_tests': 'Ujian asap',
'nav.media': 'Perpustakaan Media',
'nav.payment_methods': 'Kaedah Pembayaran',
'nav.deposit_orders': 'Semakan Deposit',
'nav.deposit_manage': 'Urus Deposit',
'nav.players': 'Pemain saya',
'nav.subAgents': 'Ejen peringkat 2',
'nav.myBets': 'Carian pertaruhan',
'deposit.payment_methods_title': 'Kaedah Pembayaran',
'deposit.deposit_orders_title': 'Semakan Deposit',
'deposit.all_status': 'Semua Status',
'deposit.all_types': 'Semua Jenis',
'deposit.status_pending': 'Menunggu',
'deposit.status_approved': 'Diluluskan',
'deposit.status_rejected': 'Ditolak',
'deposit.search_player_ph': 'Cari pemain...',
'deposit.order_no': 'No. Pesanan',
'deposit.player': 'Pemain',
'deposit.amount': 'Jumlah',
'deposit.screenshot': 'Tangkapan skrin',
'deposit.approved_amount': 'Jml Diluluskan',
'deposit.reviewer': 'Pengulas',
'deposit.time': 'Masa',
'deposit.approve': 'Luluskan',
'deposit.reject': 'Tolak',
'deposit.approve_title': 'Luluskan Deposit',
'deposit.reject_title': 'Tolak Deposit',
'deposit.submitted_amount': 'Jumlah Dihantar',
'deposit.approved_amount_label': 'Jumlah Diluluskan (laraskan jika perlu)',
'deposit.remark_label': 'Catatan (pilihan)',
'deposit.confirm_approve': 'Sahkan Luluskan',
'deposit.confirm_reject': 'Sahkan Tolak',
'deposit.reject_reason_label': 'Sebab Penolakan *',
'deposit.reject_reason_ph': 'Masukkan sebab penolakan...',
'deposit.reason_required': 'Sila masukkan sebab penolakan',
'deposit.prev': 'Sebelum',
'deposit.next': 'Seterus',
'deposit.add_method': '+ Tambah',
'deposit.display_name': 'Nama Paparan',
'deposit.details': 'Butiran',
'deposit.sort': 'Isih',
'deposit.active': 'Aktif',
'deposit.show_player': 'Papar Pemain',
'deposit.edit_method': 'Edit Kaedah Pembayaran',
'deposit.create_method': 'Cipta Kaedah Pembayaran',
'deposit.bank_name': 'Nama Bank',
'deposit.account_holder': 'Pemegang Akaun',
'deposit.account_number': 'Nombor Akaun',
'deposit.usdt_address': 'Alamat USDT',
'deposit.qr_code': 'Kod QR',
'deposit.sort_order': 'Susunan Isih',
'deposit.show_on_player': 'Papar kepada Pemain',
'deposit.save': 'Simpan',
'deposit.confirm_deactivate': 'Sahkan nyahaktifkan kaedah pembayaran ini?',
'deposit.lang_zh': 'Cina',
'deposit.lang_en': 'Inggeris',
'deposit.lang_ms': 'Melayu',
'deposit.multilingual_hint': 'Tetapkan nama paparan untuk setiap bahasa. Kosongkan untuk guna nilai lalai.',
'nav.open_menu': 'Buka menu',
'nav.close_menu': 'Tutup menu',
'breadcrumb.settlement': 'Penyelesaian',
@@ -490,6 +663,10 @@ const ms: Record<string, string> = {
'common.used': 'Digunakan',
'common.platform_direct': 'Terus platform',
'common.updated_at': 'Dikemas kini',
'common.enable': 'Aktifkan',
'common.disable': 'Nyahaktif',
'common.show_player': 'Papar pemain',
'common.hide_player': 'Sembunyikan pemain',
'dash.title': 'Gambaran',
'dash.desc': 'Gambaran keseluruhan platform',

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.',

View File

@@ -27,6 +27,7 @@ export const adminPagesZh: Record<string, string> = {
'user.filter.agent_ph': '全部',
'user.col.username': '用户名',
'user.col.agent': '所属代理',
'user.col.invite_code': '邀请码',
'user.col.balance': '可用 / 冻结',
'user.col.bets': '注单',
'user.col.stake_payout': '投注 / 派彩',
@@ -141,7 +142,7 @@ export const adminPagesZh: Record<string, string> = {
'agent.field.player_liability': '玩家负债',
'agent.field.sub_agent_exposure': '下级代理敞口',
'agent.hint.credit_limit': '代理可向直属玩家上分的总额度上限',
'agent.hint.cashback_example': '例如 0.01 表示 1%',
'agent.hint.cashback_example': '例如填写 1 表示 1%',
'agent.field.max_single_deposit': '单笔上分限额',
'agent.field.max_daily_deposit': '日上分限额',
'agent.hint.deposit_limit_empty': '0 表示不限;下级代理不能超过上级设置',
@@ -181,9 +182,10 @@ export const adminPagesZh: Record<string, string> = {
'finance.tx.cashback': '返水',
'finance.tx.resettle': '重结算调整',
'user.action.view_wallet_ledger': '查看资金流水',
'user.action.ledger_short': '流水',
'user.wallet_ledger_dialog_title': '{name} 的资金流水',
'agent.hierarchy.settings_title': '代理层级设置',
'agent.hierarchy.settings_hint': '0 表示不限制代理层级;达到上限的代理将无法创建下级。下级默认授信比例用于创建下级代理时的预填额度。',
'agent.hierarchy.settings_hint': '0 表示不限制代理层级;达到上限的代理将无法创建下级。',
'agent.hierarchy.max_level': '最大代理层级',
'agent.hierarchy.default_sub_credit_ratio': '下级默认授信比例',
'agent.hierarchy.default_sub_credit_ratio_hint': '创建下级代理时,授信额度默认预填为上级可用授信 × 此比例',
@@ -203,7 +205,12 @@ export const adminPagesZh: Record<string, string> = {
'finance.col.balance_change': '余额变动',
'finance.col.balance_before': '变动前余额',
'finance.col.balance_after': '变动后余额',
'finance.tx.deposit': '上分',
'finance.col.tx_type': '类型',
'finance.col.deposit_method': '充值方式',
'finance.deposit_method.manual_admin': '管理员人工充值',
'finance.deposit_method.manual_agent': '代理人工充值',
'finance.deposit_method.manual': '人工充值',
'finance.tx.deposit': '充值',
'finance.tx.withdraw': '下分',
'finance.tx.request_id': '请求 ID',
'finance.remark.agent_deposit': '代理上分',
@@ -387,10 +394,17 @@ export const adminPagesZh: Record<string, string> = {
'cashback.rule_period': '选择开始/结束日期,统计该周期内、按注单结算时间落在区间内的有效投注。',
'cashback.rule_eligible': '计入:已结算且结果为「赢」或「输」的注单(单关按本金,串关按整单本金计一次)。不计入:未结算、已取消、作废、走水,以及返水比例为 0 的注单;已返水过的注单不会重复计入。',
'cashback.rule_formula': '单笔返水 = 投注本金 × 适用返水比例;同一玩家多笔注单汇总后生成一条返水明细。',
'cashback.rule_rate': '返水比例优先级:玩家专属规则 > 代理线规则 > 全局规则 > 所属代理默认返水率(在代理/玩家管理中配置,如 0.01 表示 1%。',
'cashback.rule_rate': '返水比例优先级:玩家专属规则 > 代理线规则 > 全局规则 > 默认返水率(代理邀请用代理返水;管理员邀请用「管理员邀请返水」;无邀请码用「平台直属默认返水」;可在玩家管理中单独覆盖)。以百分比填写,如 1 表示 1%。',
'cashback.rule_flow': '操作流程:生成预览(同周期仅保留一条待发放)→ 核对明细 → 确认发放;不需要的可作废。已发放周期不可重复预览。',
'cashback.rule_platform': '发放方式:返水由平台直接打入玩家现金余额,不从代理信用或余额中扣除。',
'cashback.rule_note_zero': '预览为 0 时,请检查:周期内是否有已结算输赢注单、代理/玩家是否配置了大于 0 的返水率。',
'cashback.rule_note_zero': '预览为 0 时,请检查:周期内是否有已结算输赢注单、返水比例是否大于 0含全局设置中的平台直属默认比例与玩家/代理单独设置)。',
'cashback.use_custom_rate': '单独设置返水比例',
'cashback.use_default_rate': '使用默认比例 {rate}',
'cashback.settings_title': '返水设置',
'cashback.platform_direct_default_rate': '平台直属默认返水比例',
'cashback.platform_direct_default_hint': '无邀请码自助注册的玩家在未单独设置时使用此比例。',
'cashback.admin_invite_default_rate': '管理员邀请返水比例',
'cashback.admin_invite_default_hint': '玩家通过管理员邀请码注册时使用;默认与平台直属相同,可单独调整。代理邀请玩家使用管理员在代理管理中为该代理设置的返水比例。',
'user.field.player_id': '玩家 ID',
'user.field.bet_count': '注单数',
@@ -609,6 +623,57 @@ export const adminPagesZh: Record<string, string> = {
'agent_portal.initial_deposit_hint': '可选。开户时从您的授信中给玩家上分,不能超过可用授信',
'agent_portal.search_player_ph': '用户名或 ID',
'agent_portal.no_players': '暂无直属玩家,点击右上角创建',
'invite.title': '邀请码与注册链接',
'invite.menu_btn': '邀请',
'invite.dialog_title': '邀请管理',
'invite.tab_generate': '生成邀请',
'invite.tab_history': '邀请历史',
'invite.hint': '点击生成邀请码与注册链接;玩家填邀请码注册,不填则为平台直属玩家',
'invite.generate_btn': '生成邀请码/链接',
'invite.regenerate_btn': '重新生成',
'invite.generate_ok': '邀请码已生成',
'invite.generate_failed': '生成失败,请重试',
'invite.not_generated': '尚未生成邀请码',
'invite.code': '邀请码',
'invite.cashback_rate': '返水比例',
'invite.cashback_rate_hint': '该邀请码注册的玩家将使用此返水比例;默认读取全局「管理员邀请返水比例」。',
'invite.link': '注册链接',
'invite.copy_code': '复制邀请码',
'invite.copy_code_short': '复制码',
'invite.copy_link_short': '复制链接',
'invite.copy_link': '复制注册链接',
'invite.copy_code_ok': '邀请码已复制',
'invite.copy_link_ok': '注册链接已复制',
'invite.copy_failed': '复制失败,请手动复制',
'invite.unavailable': '邀请码暂不可用',
'invite.history_title': '邀请历史',
'invite.view_history': '查看历史',
'invite.history_hint': '管理员可查看全部邀请码;代理仅可查看自己及下级代理的邀请码',
'invite.page_desc': '查看全部邀请码历史与状态,生成或作废邀请码',
'invite.history_load_failed': '加载邀请历史失败',
'invite.filter_status': '状态',
'invite.filter_sponsor': '邀请人',
'invite.filter_code': '邀请码',
'invite.filter_code_ph': '输入邀请码',
'invite.col_status': '状态',
'invite.col_sponsor': '邀请人',
'invite.col_registrant': '注册人',
'invite.not_registered': '未注册',
'invite.col_cashback_rate': '返水比例',
'invite.col_created': '创建时间',
'invite.col_revoked': '作废时间',
'invite.status.ACTIVE': '有效',
'invite.status.USED': '已使用',
'invite.status.REVOKED': '已作废',
'invite.revoke_btn': '作废',
'invite.revoke_title': '作废邀请码',
'invite.revoke_confirm': '确定作废邀请码 {code}?作废后该码将无法用于注册。',
'invite.revoke_ok': '邀请码已作废',
'invite.revoke_failed': '作废失败,请重试',
'invite.delete_title': '删除邀请记录',
'invite.delete_confirm': '确定删除邀请码 {code} 的历史记录?删除后不可恢复。',
'invite.delete_ok': '邀请记录已删除',
'invite.delete_failed': '删除失败,请重试',
'agent_portal.search_sub_agent_ph': '用户名或 ID',
'agent_portal.no_sub_agents': '暂无二级代理,点击右上角创建',
'agent_portal.no_sub_agents_level': '暂无{level}级代理,点击右上角创建',
@@ -901,6 +966,7 @@ export const adminPagesEn: Record<string, string> = {
'user.filter.agent_ph': 'All',
'user.col.username': 'Username',
'user.col.agent': 'Agent',
'user.col.invite_code': 'Invite code',
'user.col.balance': 'Available / Frozen',
'user.col.bets': 'Bets',
'user.col.stake_payout': 'Stake / Payout',
@@ -1015,7 +1081,7 @@ export const adminPagesEn: Record<string, string> = {
'agent.field.player_liability': 'Player liability',
'agent.field.sub_agent_exposure': 'Sub-agent exposure',
'agent.hint.credit_limit': 'Max total top-up capacity for direct players',
'agent.hint.cashback_example': 'e.g. 0.01 = 1%',
'agent.hint.cashback_example': 'e.g. enter 1 for 1%',
'agent.field.max_single_deposit': 'Max single top-up',
'agent.field.max_daily_deposit': 'Max daily top-up',
'agent.hint.deposit_limit_empty': '0 = unlimited; sub-agents cannot exceed parent limits',
@@ -1055,9 +1121,10 @@ export const adminPagesEn: Record<string, string> = {
'finance.tx.cashback': 'Cashback',
'finance.tx.resettle': 'Resettlement',
'user.action.view_wallet_ledger': 'View wallet ledger',
'user.action.ledger_short': '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.settings_hint': '0 means unlimited levels. Agents at the cap cannot create sub-agents.',
'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',
@@ -1077,6 +1144,11 @@ export const adminPagesEn: Record<string, string> = {
'finance.col.balance_change': 'Balance change',
'finance.col.balance_before': 'Balance before',
'finance.col.balance_after': 'Balance after',
'finance.col.tx_type': 'Type',
'finance.col.deposit_method': 'Deposit method',
'finance.deposit_method.manual_admin': 'Admin manual deposit',
'finance.deposit_method.manual_agent': 'Agent manual deposit',
'finance.deposit_method.manual': 'Manual deposit',
'finance.tx.deposit': 'Deposit',
'finance.tx.withdraw': 'Withdraw',
'finance.tx.request_id': 'Request ID',
@@ -1261,10 +1333,17 @@ export const adminPagesEn: Record<string, string> = {
'cashback.rule_period': 'Pick a date range. Bets are included by settlement time within that period.',
'cashback.rule_eligible': 'Included: settled bets with result WON or LOST (singles by stake; parlays counted once by parlay stake). Excluded: pending, cancelled, void, push, zero-rate bets, and bets already paid cashback.',
'cashback.rule_formula': 'Per bet: stake × applicable cashback rate. Amounts are summed per player into one line item.',
'cashback.rule_rate': 'Rate priority: player rule > agent rule > global rule > agent default rate (set under Agents/Players, e.g. 0.01 = 1%).',
'cashback.rule_rate': 'Rate priority: player rule > agent rule > global rule > default rate (agent-line players use their agent default; platform-direct players use the rate under Global settings; override per player in player management). Enter as percent, e.g. 1 = 1%.',
'cashback.rule_flow': 'Flow: preview (one pending batch per period) → review → confirm payout; void if not needed. Paid periods cannot be previewed again.',
'cashback.rule_platform': 'Payout: cashback is credited to player cash balance by the platform; it is not deducted from agent credit or balance.',
'cashback.rule_note_zero': 'If preview is 0, check for settled WON/LOST bets in the period and a cashback rate above 0.',
'cashback.rule_note_zero': 'If preview is 0, check for settled WON/LOST bets in the period and a cashback rate above 0 (including platform-direct default in Global settings and per-player/agent overrides).',
'cashback.use_custom_rate': 'Custom cashback rate',
'cashback.use_default_rate': 'Use default rate {rate}',
'cashback.settings_title': 'Cashback settings',
'cashback.platform_direct_default_rate': 'Platform-direct default cashback rate',
'cashback.admin_invite_default_rate': 'Admin invite cashback rate',
'cashback.admin_invite_default_hint': 'Used when players register with an admin invite code; defaults to platform-direct rate. Agent invites use the rate set for that agent under Agent management.',
'cashback.platform_direct_default_hint': 'Used for self-registration without an invite code unless overridden per player.',
'user.field.player_id': 'Player ID',
'user.field.bet_count': 'Bet count',
@@ -1484,6 +1563,57 @@ export const adminPagesEn: Record<string, string> = {
'agent_portal.initial_deposit_hint': 'Optional. Initial top-up from your credit at account creation',
'agent_portal.search_player_ph': 'Username or ID',
'agent_portal.no_players': 'No direct players yet. Use the button above to create one.',
'invite.title': 'Invitation code & register link',
'invite.menu_btn': 'Invite',
'invite.dialog_title': 'Invitations',
'invite.tab_generate': 'Generate',
'invite.tab_history': 'History',
'invite.hint': 'Generate an invite code and register link. Players may enter the code to register; blank registers as platform-direct.',
'invite.generate_btn': 'Generate code / link',
'invite.regenerate_btn': 'Regenerate',
'invite.generate_ok': 'Invitation code generated',
'invite.generate_failed': 'Failed to generate — please retry',
'invite.not_generated': 'No invitation code yet',
'invite.code': 'Code',
'invite.cashback_rate': 'Cashback rate',
'invite.cashback_rate_hint': 'Players registering with this code use this rate. Defaults to the global admin-invite cashback rate.',
'invite.link': 'Register link',
'invite.copy_code': 'Copy code',
'invite.copy_code_short': 'Copy',
'invite.copy_link': 'Copy register link',
'invite.copy_link_short': 'Copy link',
'invite.copy_code_ok': 'Invitation code copied',
'invite.copy_link_ok': 'Register link copied',
'invite.copy_failed': 'Copy failed — please copy manually',
'invite.unavailable': 'Invitation code unavailable',
'invite.history_title': 'Invitation history',
'invite.view_history': 'View history',
'invite.history_hint': 'Admins see all codes; agents see their own and sub-agents codes.',
'invite.page_desc': 'View all invitation codes, status, and registration counts.',
'invite.history_load_failed': 'Failed to load invitation history',
'invite.filter_status': 'Status',
'invite.filter_sponsor': 'Sponsor',
'invite.filter_code': 'Code',
'invite.filter_code_ph': 'Enter code',
'invite.col_status': 'Status',
'invite.col_sponsor': 'Sponsor',
'invite.col_registrant': 'Registrant',
'invite.not_registered': 'Not registered',
'invite.col_cashback_rate': 'Cashback',
'invite.col_created': 'Created',
'invite.col_revoked': 'Revoked',
'invite.status.ACTIVE': 'Active',
'invite.status.USED': 'Used',
'invite.status.REVOKED': 'Revoked',
'invite.revoke_btn': 'Revoke',
'invite.revoke_title': 'Revoke invitation code',
'invite.revoke_confirm': 'Revoke code {code}? It will no longer work for registration.',
'invite.revoke_ok': 'Invitation code revoked',
'invite.revoke_failed': 'Failed to revoke — please retry',
'invite.delete_title': 'Delete invitation record',
'invite.delete_confirm': 'Delete history for code {code}? This cannot be undone.',
'invite.delete_ok': 'Invitation record deleted',
'invite.delete_failed': 'Failed to delete — please retry',
'agent_portal.search_sub_agent_ph': 'Username or ID',
'agent_portal.no_sub_agents': 'No tier-2 agents yet. Use the button above to create one.',
'agent_portal.no_sub_agents_level': 'No L{level} agents yet. Use the button above to create one.',