feat(admin,api,player): 代理层级管理、额度上下分与玩家钱包详情
新增代理管理器与二级代理体系,完善信用额度/上下分上下文与冻结策略;代理端玩家与子代理管理增强;玩家端新增钱包详情页与交易筛选优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -26,12 +26,14 @@ const zh: Record<string, string> = {
|
||||
'login.quick_label': '快速登录(调试)',
|
||||
'login.quick_admin': '管理员',
|
||||
'login.quick_agent': '一级代理',
|
||||
'login.quick_agent2': '二级代理',
|
||||
'login.captcha_ph': '验证码',
|
||||
'login.captcha_refresh': '点击刷新',
|
||||
|
||||
'nav.dashboard': '概览',
|
||||
'nav.users': '玩家管理',
|
||||
'nav.agents': '代理管理',
|
||||
'nav.agents_players': '代理&玩家',
|
||||
'nav.matches': '赛事管理',
|
||||
'nav.outrights': '优胜冠军',
|
||||
'nav.bets': '注单管理',
|
||||
@@ -49,6 +51,8 @@ const zh: Record<string, string> = {
|
||||
'breadcrumb.outright_edit': '编辑优胜冠军',
|
||||
'role.admin': '系统管理员',
|
||||
'role.agent': '代理账号',
|
||||
'role.tier1_agent': '一级代理',
|
||||
'role.tier2_agent': '二级代理',
|
||||
'logout': '退出',
|
||||
'lang': '语言',
|
||||
'portal.admin': '平台后台',
|
||||
@@ -135,11 +139,21 @@ const zh: Record<string, string> = {
|
||||
'page.audit.desc': '记录所有管理员操作行为',
|
||||
'page.settlement.title': '赛事结算',
|
||||
'page.agent_dash.title': '代理概览',
|
||||
'page.agent_dash.desc': '实时数据总览',
|
||||
'page.agent_dash.desc': '下线经营概况与分布',
|
||||
'agent_dash.load_error_hint': '无法加载概览数据,请检查网络或重新登录后再试。',
|
||||
'agent_dash.board_hint': '一屏查看下线经营趋势与分布',
|
||||
'agent_dash.kpi_players': '直属玩家 / 下级代理',
|
||||
'agent_dash.kpi_pending_sub': '{bets} 单待结算',
|
||||
'agent_dash.pie_credit': '授信占用',
|
||||
'agent_dash.pie_players': '直属玩家',
|
||||
'agent_dash.credit_available': '可用额度',
|
||||
'agent_dash.credit_used': '已用额度',
|
||||
'agent_dash.liability_direct': '玩家余额占用',
|
||||
'agent_dash.liability_child': '下级代理占用',
|
||||
'page.agent_players.title': '直属玩家',
|
||||
'page.agent_players.desc': '管理你名下的直属玩家',
|
||||
'page.agent_sub.title': '下级代理',
|
||||
'page.agent_sub.desc': '仅一级代理可见',
|
||||
'page.agent_sub.desc': '管理二级代理账号与授信分配',
|
||||
'page.agent_bets.title': '注单查询',
|
||||
'page.agent_bets.desc': '下级玩家的全部投注记录',
|
||||
|
||||
@@ -190,12 +204,14 @@ const en: Record<string, string> = {
|
||||
'login.quick_label': 'Quick sign-in (debug)',
|
||||
'login.quick_admin': 'Admin',
|
||||
'login.quick_agent': 'Tier-1 agent',
|
||||
'login.quick_agent2': 'Tier-2 agent',
|
||||
'login.captcha_ph': 'Captcha',
|
||||
'login.captcha_refresh': 'Click to refresh',
|
||||
|
||||
'nav.dashboard': 'Overview',
|
||||
'nav.users': 'Players',
|
||||
'nav.agents': 'Agents',
|
||||
'nav.agents_players': 'Agents & Players',
|
||||
'nav.matches': 'Matches',
|
||||
'nav.outrights': 'Outrights',
|
||||
'nav.bets': 'Bets',
|
||||
@@ -213,6 +229,8 @@ const en: Record<string, string> = {
|
||||
'breadcrumb.outright_edit': 'Edit outright',
|
||||
'role.admin': 'Administrator',
|
||||
'role.agent': 'Agent',
|
||||
'role.tier1_agent': 'Tier-1 Agent',
|
||||
'role.tier2_agent': 'Tier-2 Agent',
|
||||
'logout': 'Logout',
|
||||
'lang': 'Language',
|
||||
'portal.admin': 'Platform Admin',
|
||||
@@ -299,11 +317,21 @@ const en: Record<string, string> = {
|
||||
'page.audit.desc': 'Administrator action history',
|
||||
'page.settlement.title': 'Settlement',
|
||||
'page.agent_dash.title': 'Agent overview',
|
||||
'page.agent_dash.desc': 'Live summary',
|
||||
'page.agent_dash.desc': 'Downline performance at a glance',
|
||||
'agent_dash.load_error_hint': 'Could not load overview. Check your network or sign in again.',
|
||||
'agent_dash.board_hint': 'Trends and distribution for your downline',
|
||||
'agent_dash.kpi_players': 'Direct players / Sub-agents',
|
||||
'agent_dash.kpi_pending_sub': '{bets} pending bets',
|
||||
'agent_dash.pie_credit': 'Credit usage',
|
||||
'agent_dash.pie_players': 'Direct players',
|
||||
'agent_dash.credit_available': 'Available',
|
||||
'agent_dash.credit_used': 'Used',
|
||||
'agent_dash.liability_direct': 'Player balance',
|
||||
'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.desc': 'Tier-1 agents only',
|
||||
'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',
|
||||
|
||||
@@ -354,12 +382,14 @@ const ms: Record<string, string> = {
|
||||
'login.quick_label': 'Log masuk pantas (debug)',
|
||||
'login.quick_admin': 'Admin',
|
||||
'login.quick_agent': 'Ejen peringkat 1',
|
||||
'login.quick_agent2': 'Ejen peringkat 2',
|
||||
'login.captcha_ph': 'Captcha',
|
||||
'login.captcha_refresh': 'Klik untuk muat semula',
|
||||
|
||||
'nav.dashboard': 'Gambaran',
|
||||
'nav.users': 'Pemain',
|
||||
'nav.agents': 'Ejen',
|
||||
'nav.agents_players': 'Ejen & Pemain',
|
||||
'nav.matches': 'Perlawanan',
|
||||
'nav.outrights': 'Juara',
|
||||
'nav.bets': 'Pertaruhan',
|
||||
@@ -377,6 +407,8 @@ const ms: Record<string, string> = {
|
||||
'breadcrumb.outright_edit': 'Edit juara',
|
||||
'role.admin': 'Pentadbir',
|
||||
'role.agent': 'Ejen',
|
||||
'role.tier1_agent': 'Ejen Peringkat 1',
|
||||
'role.tier2_agent': 'Ejen Peringkat 2',
|
||||
'logout': 'Log keluar',
|
||||
'lang': 'Bahasa',
|
||||
'portal.admin': 'Admin Platform',
|
||||
@@ -463,11 +495,21 @@ const ms: Record<string, string> = {
|
||||
'page.audit.desc': 'Sejarah tindakan pentadbir',
|
||||
'page.settlement.title': 'Penyelesaian',
|
||||
'page.agent_dash.title': 'Gambaran ejen',
|
||||
'page.agent_dash.desc': 'Ringkasan langsung',
|
||||
'page.agent_dash.desc': 'Prestasi downline sepintas lalu',
|
||||
'agent_dash.load_error_hint': 'Gagal memuatkan gambaran. Semak rangkaian atau log masuk semula.',
|
||||
'agent_dash.board_hint': 'Trend dan taburan downline anda',
|
||||
'agent_dash.kpi_players': 'Pemain terus / Ejen bawahan',
|
||||
'agent_dash.kpi_pending_sub': '{bets} pertaruhan belum selesai',
|
||||
'agent_dash.pie_credit': 'Penggunaan kredit',
|
||||
'agent_dash.pie_players': 'Pemain terus',
|
||||
'agent_dash.credit_available': 'Tersedia',
|
||||
'agent_dash.credit_used': 'Digunakan',
|
||||
'agent_dash.liability_direct': 'Baki pemain',
|
||||
'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.desc': 'Ejen peringkat 1 sahaja',
|
||||
'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',
|
||||
|
||||
|
||||
@@ -94,13 +94,17 @@ 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.hint.account_type': 'Ejen guna had kredit; pemain boleh di bawah ejen',
|
||||
|
||||
'agent.create_btn': '+ Ejen peringkat 1 baharu',
|
||||
'agent.create_sub': 'Cipta sub-ejen',
|
||||
'agent.hint.creating_under_agent': 'Cipta akaun di bawah ejen ini',
|
||||
'agent.filter.username_ph': 'Nama pengguna',
|
||||
'agent.col.level': 'Peringkat',
|
||||
'agent.col.credit': 'Had / Digunakan / Tersedia',
|
||||
'agent.col.direct_players': 'Pemain terus',
|
||||
'agent.col.sub_agents': 'Sub-ejen',
|
||||
'agent.col.cashback': 'Kadar rebat',
|
||||
'agent.col.phone': 'Telefon',
|
||||
'agent.col.created': 'Dicipta',
|
||||
@@ -359,9 +363,9 @@ export const adminPagesMs: Record<string, string> = {
|
||||
'err.password_min': 'Kata laluan sekurang-kurangnya 8 aksara',
|
||||
'err.password_mismatch': 'Kata laluan tidak sepadan',
|
||||
'err.credit_negative': 'Had kredit tidak boleh negatif',
|
||||
'err.insufficient_credit': 'Kredit tersedia tidak mencukupi. Kurangkan jumlah atau minta penambahan had.',
|
||||
'err.kickoff_required': 'Sila isi masa mula',
|
||||
'err.team_country_required': 'Pilih pasukan tuan rumah dan pelawat',
|
||||
'err.team_country_required': 'Pilih pasukan tuan rumah dan pelawat',
|
||||
'err.teams_required': 'Isi nama pasukan tuan rumah dan pelawat (ZH atau EN)',
|
||||
'err.teams_same': 'Pasukan tuan rumah dan pelawat mesti berbeza',
|
||||
'err.league_required': 'Sila isi nama liga',
|
||||
@@ -433,6 +437,18 @@ export const adminPagesMs: Record<string, string> = {
|
||||
'agent_portal.withdraw_btn_label': 'Keluarkan',
|
||||
'agent_portal.transfer_title_deposit': 'Tambah baki {name}',
|
||||
'agent_portal.transfer_title_withdraw': 'Keluarkan dari {name}',
|
||||
'agent_portal.create_player_dialog': 'Pemain baharu',
|
||||
'agent_portal.edit_player_dialog': 'Edit pemain langsung',
|
||||
'agent_portal.credit_available_hint': 'Kredit tersedia: {amount} (tambah baki ditolak dari had)',
|
||||
'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.',
|
||||
'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.create_sub_agent_dialog': 'Ejen peringkat 2 baharu',
|
||||
'agent_portal.sub_agent_credit_hint': 'Kredit awal diperuntukkan dari had tersedia anda',
|
||||
'agent_portal.adjust_credit_dialog': 'Laraskan kredit {name}',
|
||||
'agent_portal.credit_adjust_hint': 'Positif untuk tambah, negatif untuk kurangkan',
|
||||
'msg.agent_sub_created': 'Sub-ejen dicipta',
|
||||
'msg.withdraw_ok': 'Pengeluaran berjaya',
|
||||
|
||||
|
||||
@@ -94,13 +94,17 @@ export const adminPagesZh: Record<string, string> = {
|
||||
'user.field.account_type': '账号类型',
|
||||
'user.type.player': '玩家',
|
||||
'user.type.tier1_agent': '一级代理',
|
||||
'user.type.sub_agent': '二级代理',
|
||||
'user.hint.account_type': '代理使用授信额度;玩家可挂靠代理并上分',
|
||||
|
||||
'agent.create_btn': '+ 新建一级代理',
|
||||
'agent.create_sub': '创建二级代理',
|
||||
'agent.hint.creating_under_agent': '在此代理下创建账号',
|
||||
'agent.filter.username_ph': '用户名',
|
||||
'agent.col.level': '层级',
|
||||
'agent.col.credit': '授信 / 已用 / 可用',
|
||||
'agent.col.direct_players': '直属玩家',
|
||||
'agent.col.sub_agents': '下级代理',
|
||||
'agent.col.cashback': '返水率',
|
||||
'agent.col.phone': '手机',
|
||||
'agent.col.created': '创建时间',
|
||||
@@ -118,6 +122,9 @@ export const adminPagesZh: Record<string, string> = {
|
||||
'agent.field.sub_agent_exposure': '下级代理敞口',
|
||||
'agent.hint.credit_limit': '代理可向直属玩家上分的总额度上限',
|
||||
'agent.hint.cashback_example': '例如 0.01 表示 1%',
|
||||
'agent.field.max_single_deposit': '单笔上分限额',
|
||||
'agent.field.max_daily_deposit': '日上分限额',
|
||||
'agent.hint.deposit_limit_empty': '0 表示不限;下级代理不能超过上级设置',
|
||||
'agent.hint.credit_adjust': '正数为增加授信,负数为减少',
|
||||
'agent.hint.credit_remark': '选填,写入额度流水',
|
||||
'agent.section.credit_log': '最近额度变动',
|
||||
@@ -131,6 +138,18 @@ 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.msg.cascade_freeze_done': '已停用代理并冻结其直属玩家',
|
||||
'agent.msg.freeze_done': '已{action}',
|
||||
|
||||
'match.create_btn': '+ 新增赛事',
|
||||
'match.create_fixture_btn': '+ 新增单场',
|
||||
@@ -361,6 +380,7 @@ export const adminPagesZh: Record<string, string> = {
|
||||
'err.password_min': '密码至少 8 位',
|
||||
'err.password_mismatch': '两次密码不一致',
|
||||
'err.credit_negative': '授信额度不能为负',
|
||||
'err.insufficient_credit': '可用授信不足,请减少上分金额或联系上级调额',
|
||||
'err.kickoff_required': '请填写开赛时间',
|
||||
'err.team_country_required': '请选择主客队',
|
||||
'err.teams_required': '请填写主客队名称(中文、英文或马来文至少一项)',
|
||||
@@ -466,6 +486,36 @@ export const adminPagesZh: Record<string, string> = {
|
||||
'agent_portal.withdraw_btn_label': '下分',
|
||||
'agent_portal.transfer_title_deposit': '给 {name} 上分',
|
||||
'agent_portal.transfer_title_withdraw': '从 {name} 下分',
|
||||
'transfer.context.player_section': '玩家余额',
|
||||
'transfer.context.agent_section': '授信代理 · {name}(L{level})',
|
||||
'transfer.context.withdrawable': '可下分金额',
|
||||
'transfer.context.deposit_cap': '本次最多可上分',
|
||||
'transfer.context.daily_used': '今日已上分',
|
||||
'transfer.context.unlimited': '不限',
|
||||
'transfer.context.no_agent': '平台直属玩家,上分不受代理授信约束',
|
||||
'transfer.context.admin_credit_only': '管理员上分仅受上级可用授信约束,不受单笔/日限',
|
||||
'transfer.context.withdraw_exceed': '下分金额不能超过玩家可用余额',
|
||||
'credit.context.target_section': '目标代理授信',
|
||||
'credit.context.parent_section': '上级代理 · {name}',
|
||||
'credit.context.max_increase': '最多可增加授信',
|
||||
'credit.context.no_parent': '一级代理由平台直管,增信不受上级约束',
|
||||
'credit.context.after_adjust': '调整后授信额度',
|
||||
'credit.context.direct_liability': '直属玩家占用',
|
||||
'credit.context.child_exposure': '下级代理占用',
|
||||
'credit.context.acting_agent': '当前代理',
|
||||
'agent_portal.create_player_dialog': '新建直属玩家',
|
||||
'agent_portal.edit_player_dialog': '编辑直属玩家',
|
||||
'agent_portal.credit_available_hint': '当前可用授信:{amount}(上分将从授信中扣除)',
|
||||
'agent_portal.sub_agent_players_readonly': '以下为该二级代理直属玩家,仅可查看;开户、上分等操作由二级代理自行处理。',
|
||||
'agent_portal.initial_deposit_hint': '可选。开户时从您的授信中给玩家上分,不能超过可用授信',
|
||||
'agent_portal.search_player_ph': '用户名或 ID',
|
||||
'agent_portal.no_players': '暂无直属玩家,点击右上角创建',
|
||||
'agent_portal.search_sub_agent_ph': '用户名或 ID',
|
||||
'agent_portal.no_sub_agents': '暂无二级代理,点击右上角创建',
|
||||
'agent_portal.create_sub_agent_dialog': '新建二级代理',
|
||||
'agent_portal.sub_agent_credit_hint': '初始授信从您的可用额度中划拨,不能超过可用授信',
|
||||
'agent_portal.adjust_credit_dialog': '调整 {name} 授信',
|
||||
'agent_portal.credit_adjust_hint': '正数为增加授信,负数为减少授信',
|
||||
'msg.agent_sub_created': '下级代理已创建',
|
||||
'msg.withdraw_ok': '下分成功',
|
||||
|
||||
@@ -728,13 +778,17 @@ 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.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': 'Create sub-agent',
|
||||
'agent.hint.creating_under_agent': 'Create account under this agent',
|
||||
'agent.filter.username_ph': 'Username',
|
||||
'agent.col.level': 'Level',
|
||||
'agent.col.credit': 'Limit / Used / Available',
|
||||
'agent.col.direct_players': 'Direct players',
|
||||
'agent.col.sub_agents': 'Sub-agents',
|
||||
'agent.col.cashback': 'Cashback rate',
|
||||
'agent.col.phone': 'Phone',
|
||||
'agent.col.created': 'Created',
|
||||
@@ -752,6 +806,9 @@ export const adminPagesEn: Record<string, string> = {
|
||||
'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.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',
|
||||
'agent.hint.credit_adjust': 'Positive increases, negative decreases',
|
||||
'agent.hint.credit_remark': 'Optional, written to credit ledger',
|
||||
'agent.section.credit_log': 'Recent credit changes',
|
||||
@@ -765,6 +822,18 @@ 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.msg.cascade_freeze_done': 'Agent suspended and direct players frozen',
|
||||
'agent.msg.freeze_done': '{action} completed',
|
||||
|
||||
'match.create_btn': '+ New tournament',
|
||||
'match.create_fixture_btn': '+ Add fixture',
|
||||
@@ -995,6 +1064,7 @@ export const adminPagesEn: Record<string, string> = {
|
||||
'err.password_min': 'Password must be at least 8 characters',
|
||||
'err.password_mismatch': 'Passwords do not match',
|
||||
'err.credit_negative': 'Credit limit cannot be negative',
|
||||
'err.insufficient_credit': 'Insufficient available credit. Reduce the amount or request a limit increase.',
|
||||
'err.kickoff_required': 'Kickoff time is required',
|
||||
'err.team_country_required': 'Select home and away teams',
|
||||
'err.teams_required': 'Enter home and away team names (ZH or EN)',
|
||||
@@ -1101,6 +1171,36 @@ export const adminPagesEn: Record<string, string> = {
|
||||
'agent_portal.withdraw_btn_label': 'Withdraw',
|
||||
'agent_portal.transfer_title_deposit': 'Top up {name}',
|
||||
'agent_portal.transfer_title_withdraw': 'Withdraw from {name}',
|
||||
'transfer.context.player_section': 'Player balance',
|
||||
'transfer.context.agent_section': 'Credit agent · {name} (L{level})',
|
||||
'transfer.context.withdrawable': 'Withdrawable',
|
||||
'transfer.context.deposit_cap': 'Max top-up this time',
|
||||
'transfer.context.daily_used': 'Topped up today',
|
||||
'transfer.context.unlimited': 'No limit',
|
||||
'transfer.context.no_agent': 'Platform-direct player — not limited by agent credit',
|
||||
'transfer.context.admin_credit_only': 'Admin top-up is capped by parent available credit only (not single/daily limits)',
|
||||
'transfer.context.withdraw_exceed': 'Withdrawal cannot exceed player available balance',
|
||||
'credit.context.target_section': 'Target agent credit',
|
||||
'credit.context.parent_section': 'Parent agent · {name}',
|
||||
'credit.context.max_increase': 'Max increase',
|
||||
'credit.context.no_parent': 'Tier-1 agents are platform-managed; increases are not capped by a parent',
|
||||
'credit.context.after_adjust': 'Credit limit after adjustment',
|
||||
'credit.context.direct_liability': 'Direct player exposure',
|
||||
'credit.context.child_exposure': 'Sub-agent exposure',
|
||||
'credit.context.acting_agent': 'Current agent',
|
||||
'agent_portal.create_player_dialog': 'New direct player',
|
||||
'agent_portal.edit_player_dialog': 'Edit direct player',
|
||||
'agent_portal.credit_available_hint': 'Available credit: {amount} (top-ups deduct from your limit)',
|
||||
'agent_portal.sub_agent_players_readonly': 'Players under this sub-agent are read-only here. Account opening and top-ups are handled by the sub-agent.',
|
||||
'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.',
|
||||
'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.create_sub_agent_dialog': 'New tier-2 agent',
|
||||
'agent_portal.sub_agent_credit_hint': 'Initial credit is allocated from your available limit',
|
||||
'agent_portal.adjust_credit_dialog': 'Adjust credit for {name}',
|
||||
'agent_portal.credit_adjust_hint': 'Positive to increase, negative to decrease',
|
||||
'msg.agent_sub_created': 'Sub-agent created',
|
||||
'msg.withdraw_ok': 'Withdrawal successful',
|
||||
|
||||
|
||||
@@ -14,3 +14,17 @@ export function resolveFormError(e: unknown, t: (key: string) => string): string
|
||||
if (e instanceof Error && e.message.startsWith('err.')) return t(e.message);
|
||||
return t('msg.form_invalid');
|
||||
}
|
||||
|
||||
/** 从 API 错误响应提取可读文案(Nest 全局过滤器返回 `error` 字段) */
|
||||
export function resolveApiError(
|
||||
err: unknown,
|
||||
t: (key: string) => string,
|
||||
fallbackKey = 'msg.save_failed',
|
||||
): string {
|
||||
const data = (err as { response?: { data?: { error?: string | string[]; message?: string | string[] } } })
|
||||
?.response?.data;
|
||||
const raw = data?.error ?? data?.message;
|
||||
if (Array.isArray(raw)) return raw.join(';');
|
||||
if (typeof raw === 'string' && raw.trim()) return raw;
|
||||
return t(fallbackKey);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user