feat: replace watermarks with corner tags, improve parlay layout and admin polish

- MatchDetailView: replace StatusWatermark with top-right solid status tags, remove match-hero background image
- ParlayPanel: replace StatusWatermark with corner tags, improve toggle button style and layout spacing, fix overflow clipping
- Admin: wallet ledger dialog, agent manager, and player page refinements

🤖 Generated with [Qoder][https://qoder.com]
This commit is contained in:
2026-06-10 16:24:01 +08:00
parent ef6b15f119
commit a8ee28fcce
7 changed files with 159 additions and 58 deletions

View File

@@ -1452,26 +1452,26 @@ function creditTypeLabel(type: string) {
</template>
</el-table-column>
<el-table-column prop="userId" label="ID" width="64" />
<el-table-column prop="username" :label="t('user.col.username')" width="100" show-overflow-tooltip />
<el-table-column :label="t('common.status')" width="72">
<el-table-column prop="userId" label="ID" min-width="64" />
<el-table-column prop="username" :label="t('user.col.username')" min-width="100" show-overflow-tooltip />
<el-table-column :label="t('common.status')" min-width="72">
<template #default="{ row }">
<el-tag :type="statusTagType(row.status)" size="small">{{ statusLabel(row.status) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="level" :label="t('agent.col.level')" width="52" align="center">
<el-table-column prop="level" :label="t('agent.col.level')" min-width="52" align="center">
<template #default="{ row }">L{{ row.level }}</template>
</el-table-column>
<el-table-column :label="t('agent.col.credit')" width="132" align="right">
<el-table-column :label="t('agent.col.credit')" min-width="148" align="right">
<template #default="{ row }">
<el-tooltip :content="creditLineFull(row)" placement="top">
<span class="amount-compact">{{ creditLine(row) }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="directPlayerCount" :label="t('agent.col.direct_players')" width="72" align="center" />
<el-table-column prop="childAgentCount" :label="t('agent.col.sub_agents')" width="72" align="center" />
<el-table-column :label="t('agent.col.cashback')" width="80" align="right">
<el-table-column prop="directPlayerCount" :label="t('agent.col.direct_players')" min-width="72" align="center" />
<el-table-column prop="childAgentCount" :label="t('agent.col.sub_agents')" min-width="72" align="center" />
<el-table-column :label="t('agent.col.cashback')" min-width="80" align="right">
<template #default="{ row }">{{ row.cashbackRate }}</template>
</el-table-column>
<el-table-column :label="t('common.actions')" width="400" fixed="right" align="center">
@@ -1595,24 +1595,24 @@ function creditTypeLabel(type: string) {
</div>
</template>
</el-table-column>
<el-table-column prop="userId" label="ID" width="64" />
<el-table-column prop="username" :label="t('user.col.username')" width="100" show-overflow-tooltip />
<el-table-column :label="t('agent.col.parent_chain')" width="120" show-overflow-tooltip>
<el-table-column prop="userId" label="ID" min-width="64" />
<el-table-column prop="username" :label="t('user.col.username')" min-width="100" show-overflow-tooltip />
<el-table-column :label="t('agent.col.parent_chain')" min-width="120" show-overflow-tooltip>
<template #default="{ row }">{{ parentChainLabel(row) }}</template>
</el-table-column>
<el-table-column :label="t('common.status')" width="72">
<el-table-column :label="t('common.status')" min-width="72">
<template #default="{ row }">
<el-tag :type="statusTagType(subAgentAccountStatus(row))" size="small">{{ statusLabel(subAgentAccountStatus(row)) }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('agent.col.credit')" width="132" align="right">
<el-table-column :label="t('agent.col.credit')" min-width="148" align="right">
<template #default="{ row }">
<el-tooltip :content="creditLineFull(row)" placement="top">
<span class="amount-compact">{{ creditLine(row) }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="directPlayerCount" :label="t('agent.col.direct_players')" width="72" align="center" />
<el-table-column prop="directPlayerCount" :label="t('agent.col.direct_players')" min-width="72" align="center" />
<el-table-column :label="t('common.actions')" width="400" fixed="right" align="center">
<template #default="{ row }">
<div class="action-btns" @click.stop>
@@ -2248,7 +2248,9 @@ function creditTypeLabel(type: string) {
.expandable-table :deep(.row-expandable) {
cursor: pointer;
}
.compact-agent-table :deep(.el-table__header .el-table__cell),
.compact-agent-table :deep(.el-table__header .el-table__cell) {
padding: 4px 8px;
}
.compact-agent-table :deep(.el-table__body .el-table__cell) {
padding: 6px 8px;
}

View File

@@ -42,11 +42,13 @@ import {
snapshotFromAgentRow,
type AgentCreditAdjustContext,
} from '../../utils/agent-credit-context';
import { formatAgentLevelNumeral } from '../../utils/agent-level-label';
const { t, localeTag } = useAdminLocale();
const auth = useAuthStore();
const profile = ref<{
level?: number;
creditLimit?: string;
usedCredit?: string;
availableCredit?: string;
@@ -57,6 +59,41 @@ const canManageSubAgents = computed(
() => profile.value.canManageSubAgents === true || auth.canManageSubAgents.value,
);
const myAgentLevel = computed(() => profile.value.level ?? auth.user.value?.agentLevel ?? 1);
const childAgentLevel = computed(() => myAgentLevel.value + 1);
function lvlLabel(level: number) {
return formatAgentLevelNumeral(level, localeTag.value);
}
const childAgentTierName = computed(() =>
t('agent.level_name', { level: lvlLabel(childAgentLevel.value) }),
);
const subAgentsTabLabel = computed(() =>
`${childAgentTierName.value} (${subAgents.value.length})`,
);
const createSubBtnLabel = computed(() => {
if (childAgentLevel.value === 2) return t('agent.create_sub_btn');
return t('agent.create_level_agent_btn', { level: lvlLabel(childAgentLevel.value) });
});
const createSubDialogTitle = computed(() => {
if (childAgentLevel.value === 2) return t('agent_portal.create_sub_agent_dialog');
return t('agent.dialog.create_level_agent', { level: lvlLabel(childAgentLevel.value) });
});
const noSubAgentsHint = computed(() => {
if (childAgentLevel.value === 2) return t('agent_portal.no_sub_agents');
return t('agent_portal.no_sub_agents_level', { level: lvlLabel(childAgentLevel.value) });
});
const subAgentPlayersReadonlyHint = computed(() => {
if (childAgentLevel.value === 2) return t('agent_portal.sub_agent_players_readonly');
return t('agent_portal.sub_agent_players_readonly_level', { level: lvlLabel(childAgentLevel.value) });
});
/* ─── Top-level tab: players | subAgents ─── */
const activeTab = ref('players');
@@ -654,7 +691,7 @@ function statusTagType(s: string) {
</el-tab-pane>
<!-- Tab: 下级代理 (仅一级代理可见) -->
<el-tab-pane v-if="canManageSubAgents" :label="`${t('nav.subAgents')} (${subAgents.length})`" name="subAgents">
<el-tab-pane v-if="canManageSubAgents" :label="subAgentsTabLabel" name="subAgents">
<div class="inner-toolbar">
<el-form inline size="small" style="flex: 1">
<el-form-item :label="t('common.search')">
@@ -662,7 +699,7 @@ function statusTagType(s: string) {
</el-form-item>
</el-form>
<el-button type="primary" size="small" @click="openCreateSub">
+ {{ t('agent_portal.create_tier2_btn') }}
{{ createSubBtnLabel }}
</el-button>
</div>
@@ -677,7 +714,7 @@ function statusTagType(s: string) {
@expand-change="onSubAgentExpand"
@row-click="onSubAgentRowClick"
>
<template #empty><div class="empty-hint">{{ t('agent_portal.no_sub_agents') || '暂无下级代理' }}</div></template>
<template #empty><div class="empty-hint">{{ noSubAgentsHint }}</div></template>
<el-table-column type="expand">
<template #default="{ row }">
@@ -687,7 +724,7 @@ function statusTagType(s: string) {
</div>
<template v-else>
<div class="expand-section-title">{{ t('nav.players') }} ({{ getSubAgentPlayers(row.userId).length }})</div>
<p class="expand-readonly-hint">{{ t('agent_portal.sub_agent_players_readonly') }}</p>
<p class="expand-readonly-hint">{{ subAgentPlayersReadonlyHint }}</p>
<el-table :data="getSubAgentPlayers(row.userId)" stripe size="small" class="inner-table nested-table">
<template #empty><div class="empty-hint">暂无数据</div></template>
<el-table-column prop="id" :label="t('common.col_id')" width="60" />
@@ -869,7 +906,7 @@ function statusTagType(s: string) {
</el-dialog>
<!-- Create Sub-Agent -->
<el-dialog v-model="createSubVisible" :title="t('agent_portal.create_tier2_btn')" width="480px" destroy-on-close>
<el-dialog v-model="createSubVisible" :title="createSubDialogTitle" width="480px" destroy-on-close>
<el-form label-width="100px">
<el-form-item :label="t('user.col.username')" required>
<el-input v-model="createSubForm.username" :placeholder="t('agent_portal.agent_username_ph')" />