feat(admin): 从已有玩家升级代理、修复 i18n 与过期 .js 冲突

- 新建一级代理改为选择已有玩家;新建用户可选一级代理

- 操作日志/注单等扁平 key 翻译;清理 src 内误生成 .js,Vite 优先解析 .ts

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-03 15:42:15 +08:00
parent cbfa18d1d3
commit 3b739982a1
27 changed files with 625 additions and 165 deletions

View File

@@ -14,7 +14,7 @@ import { useAdminLocale } from '../composables/useAdminLocale';
const { t, localeTag } = useAdminLocale();
const { statusOptions, typeOptions } = useBetFilterOptions();
import type { BetListRow, BetDetail } from './bet-form';
import type { BetListRow, BetDetail } from './bet-form.ts';
const bets = ref<BetListRow[]>([]);
const total = ref(0);
@@ -104,14 +104,14 @@ async function openDetail(row: BetListRow) {
</script>
<template>
<div class="admin-list-page">
<div class="admin-list-page bets-page">
<div class="page-header">
<h2 class="page-title">{{ t('page.bets.title') }}</h2>
<span class="page-desc">{{ t('page.bets.desc') }}</span>
</div>
<el-card class="filter-card" shadow="never">
<el-form inline>
<el-form inline class="bets-filter-form">
<el-form-item :label="t('common.keyword')">
<el-input
v-model="keyword"
@@ -168,53 +168,53 @@ async function openDetail(row: BetListRow) {
<el-card class="data-card" shadow="never">
<div class="table-wrap">
<el-table :data="bets" stripe>
<el-table-column prop="id" :label="t('bet.col.serial')" width="56" align="center" />
<el-table-column prop="betNo" :label="t('bet.col.bet_no')" width="168" show-overflow-tooltip>
<el-table :data="bets" stripe class="bets-table">
<el-table-column prop="id" :label="t('bet.col.serial')" width="64" align="center" />
<el-table-column prop="betNo" :label="t('bet.col.bet_no')" min-width="200" show-overflow-tooltip>
<template #default="{ row }">
<span class="bet-no">{{ row.betNo }}</span>
</template>
</el-table-column>
<el-table-column prop="username" :label="t('bet.col.player')" width="100" show-overflow-tooltip />
<el-table-column :label="t('bet.col.agent')" width="100" show-overflow-tooltip>
<el-table-column prop="username" :label="t('bet.col.player')" min-width="100" show-overflow-tooltip />
<el-table-column :label="t('bet.col.agent')" min-width="108" show-overflow-tooltip>
<template #default="{ row }">{{ parentLabel(row) }}</template>
</el-table-column>
<el-table-column :label="t('common.type')" width="72" align="center">
<el-table-column :label="t('common.type')" min-width="92" align="center">
<template #default="{ row }">
<el-tag type="info" size="small" effect="plain">{{ betTypeLabel(row.betType) }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('bet.col.selection')" width="52" align="center">
<el-table-column :label="t('bet.col.selection_count')" width="88" align="center">
<template #default="{ row }">{{ row.selectionCount }}</template>
</el-table-column>
<el-table-column :label="t('bet.col.stake')" width="96" align="right">
<el-table-column :label="t('bet.col.stake')" min-width="100" align="right">
<template #default="{ row }">
<el-tooltip :content="formatAmountFull(row.stake)" placement="top">
<span>{{ formatAmount(row.stake) }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="t('bet.col.odds')" width="72" align="right">
<el-table-column :label="t('bet.col.odds')" width="80" align="right">
<template #default="{ row }">{{ row.totalOdds ?? '—' }}</template>
</el-table-column>
<el-table-column :label="t('bet.col.payout')" width="96" align="right">
<el-table-column :label="t('bet.col.payout')" min-width="100" align="right">
<template #default="{ row }">
<el-tooltip :content="formatAmountFull(row.actualReturn)" placement="top">
<span>{{ formatAmount(row.actualReturn) }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="t('common.status')" width="88" align="center">
<el-table-column :label="t('common.status')" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="betStatusTagType(row.status)" size="small">
{{ betStatusLabel(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('bet.col.placed_at')" width="160">
<el-table-column :label="t('bet.col.placed_at')" min-width="168">
<template #default="{ row }">{{ formatTime(row.placedAt) }}</template>
</el-table-column>
<el-table-column :label="t('common.actions')" width="88" fixed="right" align="center">
<el-table-column :label="t('common.actions')" width="100" fixed="right" align="center">
<template #default="{ row }">
<el-button type="primary" link size="small" @click="openDetail(row)">{{ t('common.detail') }}</el-button>
</template>
@@ -302,7 +302,30 @@ async function openDetail(row: BetListRow) {
.page-desc { font-size: 13px; color: #666; }
.filter-card { margin-bottom: 16px; border-radius: 12px; }
.data-card { border-radius: 12px; }
.bet-no { font-size: 12px; color: #ccc; font-family: ui-monospace, monospace; }
.bets-filter-form {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 4px 8px;
}
.bets-filter-form :deep(.el-form-item) {
margin-right: 12px;
margin-bottom: 8px;
}
.bets-filter-form :deep(.el-form-item__label) {
padding-bottom: 0;
}
.bets-table {
min-width: 1180px;
}
.bet-no {
font-size: 12px;
color: #ccc;
font-family: ui-monospace, monospace;
white-space: nowrap;
}
.pager { display: flex; justify-content: flex-end; margin-top: 16px; }
.detail-desc { margin-bottom: 16px; }
.selections-title {