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

@@ -19,6 +19,7 @@ const adminMenus = computed(() => [
{ path: '/matches', label: t('nav.matches'), matchPrefix: true },
{ path: '/users', label: t('nav.agents_players') },
{ path: '/finance-logs', label: t('nav.finance_logs') },
{ path: '/deposit', label: t('nav.deposit_manage'), matchPrefix: true },
{ path: '/cashback', label: t('nav.cashback') },
{ path: '/bets', label: t('nav.bets') },
{ path: '/contents', label: t('nav.contents') },
@@ -49,10 +50,15 @@ function isDashboardSectionPath(path: string) {
return path === '/' || path === '/dashboard/players';
}
function isDepositSectionPath(path: string) {
return path === '/deposit' || path === '/deposit-orders' || path === '/payment-methods';
}
const currentLabel = computed(() => {
const hit = menus.value.find((m) => {
if ('matchPrefix' in m && m.matchPrefix) {
if (m.path === '/') return isDashboardSectionPath(route.path);
if (m.path === '/deposit') return isDepositSectionPath(route.path);
return isMatchesSectionPath(route.path);
}
return route.path === m.path;
@@ -147,7 +153,9 @@ watch(() => route.path, () => {
m.matchPrefix &&
(m.path === '/'
? isDashboardSectionPath(route.path)
: isMatchesSectionPath(route.path))),
: m.path === '/deposit'
? isDepositSectionPath(route.path)
: isMatchesSectionPath(route.path))),
}"
@click="onNavClick"
>
@@ -224,8 +232,8 @@ watch(() => route.path, () => {
flex-shrink: 0;
position: fixed;
top: 0; left: 0; bottom: 0;
background: rgba(6, 6, 6, 0.98);
border-right: 1px solid #1c1c1c;
background: #0a0a0a;
border-right: 1px solid rgba(255, 255, 255, 0.06);
display: flex;
flex-direction: column;
z-index: 100;
@@ -264,25 +272,22 @@ watch(() => route.path, () => {
.nav-item {
display: flex;
align-items: center;
padding: 9px 10px;
padding: 8px 10px;
border-radius: 6px;
color: #aaa;
color: #737373;
font-size: 13px;
font-weight: 500;
transition: all 0.15s;
border-left: 2px solid transparent;
letter-spacing: 0.02em;
font-weight: 450;
transition: color 0.15s, background 0.15s;
letter-spacing: 0;
}
.nav-item:hover {
background: rgba(255, 255, 255, 0.05);
color: #fff;
background: rgba(255, 255, 255, 0.04);
color: #d4d4d4;
}
.nav-item.active {
background: linear-gradient(90deg, rgba(36, 143, 84, 0.22), rgba(36, 143, 84, 0.04));
color: var(--green-text);
font-weight: 700;
border-left-color: var(--green-bright);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
background: rgba(255, 255, 255, 0.06);
color: #f5f5f5;
font-weight: 500;
}
.sidebar-foot {
@@ -322,9 +327,8 @@ watch(() => route.path, () => {
box-sizing: border-box;
display: flex; align-items: center; justify-content: space-between;
padding: 0 28px;
background: rgba(6, 6, 6, 0.98);
border-bottom: 1px solid #1a1a1a;
backdrop-filter: blur(12px);
background: #0a0a0a;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.topbar-left {
@@ -361,10 +365,10 @@ watch(() => route.path, () => {
}
.topbar-title {
display: flex; align-items: center; gap: 12px;
font-size: 15px; font-weight: 700;
color: #e8e8e8;
letter-spacing: 0.04em;
display: flex; align-items: center; gap: 10px;
font-size: 14px; font-weight: 500;
color: #f5f5f5;
letter-spacing: 0;
min-width: 0;
}
.topbar-page-label {
@@ -382,26 +386,24 @@ watch(() => route.path, () => {
min-width: 0;
}
.crumb-link {
color: var(--green-text);
color: #737373;
transition: color 0.15s;
}
.crumb-link:hover {
color: #d4fde5;
color: #f5f5f5;
}
.crumb-current {
color: #e8e8e8;
color: #f5f5f5;
}
.crumb-sep {
color: #444;
color: #525252;
font-weight: 400;
user-select: none;
}
.topbar-accent {
width: 3px; height: 16px;
background: linear-gradient(180deg, var(--green-glow), var(--green-deep));
border-radius: 2px;
width: 1px; height: 14px;
background: rgba(255, 255, 255, 0.12);
flex-shrink: 0;
box-shadow: 0 0 8px rgba(47, 181, 106, 0.45);
}
.topbar-page-actions {
@@ -424,12 +426,11 @@ watch(() => route.path, () => {
display: flex; align-items: center; gap: 8px;
}
.avatar {
width: 30px; height: 30px; border-radius: 50%;
background: var(--primary-grad);
border: 1px solid var(--green-border);
box-shadow: var(--primary-shadow);
width: 28px; height: 28px; border-radius: 50%;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.1);
display: flex; align-items: center; justify-content: center;
font-size: 12px; font-weight: 800; color: #fff;
font-size: 11px; font-weight: 500; color: #d4d4d4;
flex-shrink: 0;
}
.user-info {
@@ -445,14 +446,14 @@ watch(() => route.path, () => {
}
.portal-tag {
padding: 3px 8px;
border: 1px solid var(--green-border);
padding: 2px 7px;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 4px;
font-size: 11px;
color: var(--green-text);
background: var(--green-surface);
font-weight: 600;
letter-spacing: 0.04em;
color: #737373;
background: transparent;
font-weight: 500;
letter-spacing: 0;
}
.btn-logout {