feat(admin,api,player): 代理层级管理、额度上下分与玩家钱包详情
新增代理管理器与二级代理体系,完善信用额度/上下分上下文与冻结策略;代理端玩家与子代理管理增强;玩家端新增钱包详情页与交易筛选优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { useAdminLocale } from '../composables/useAdminLocale';
|
||||
@@ -25,6 +25,8 @@ import {
|
||||
shouldCompactAmount as shouldCompact,
|
||||
} from '../utils/format-amount';
|
||||
import AdminTableEmpty from '../components/AdminTableEmpty.vue';
|
||||
import WalletTransferContext from '../components/WalletTransferContext.vue';
|
||||
import { useAdminPlayerTransfer } from '../composables/useAdminPlayerTransfer';
|
||||
|
||||
const users = ref<PlayerRow[]>([]);
|
||||
const total = ref(0);
|
||||
@@ -39,17 +41,30 @@ const agentOptions = ref<{ id: string; username: string }[]>([]);
|
||||
const createVisible = ref(false);
|
||||
const editVisible = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
const depositVisible = ref(false);
|
||||
const createLoading = ref(false);
|
||||
const editLoading = ref(false);
|
||||
const depositLoading = ref(false);
|
||||
|
||||
const createForm = ref<PlayerCreateForm>(emptyPlayerCreateForm());
|
||||
const editForm = ref<PlayerEditForm>(emptyPlayerEditForm());
|
||||
const detail = ref<PlayerDetail | null>(null);
|
||||
const editingId = ref('');
|
||||
|
||||
const depositForm = ref({ userId: '', amount: 100, remark: '' });
|
||||
const {
|
||||
transferVisible,
|
||||
transferLoading,
|
||||
transferType,
|
||||
transferTarget,
|
||||
transferAmount,
|
||||
transferRemark,
|
||||
transferContext,
|
||||
transferContextLoading,
|
||||
transferAmountRange,
|
||||
transferAmountDisabled,
|
||||
transferTitle,
|
||||
openTransfer,
|
||||
submitTransfer,
|
||||
} = useAdminPlayerTransfer(() => load());
|
||||
|
||||
const playerSettings = ref({ allowPasswordChange: true, allowUsernameChange: false });
|
||||
const bettingLimits = ref({
|
||||
minStake: 1,
|
||||
@@ -219,11 +234,6 @@ async function openEdit(id: string) {
|
||||
editVisible.value = true;
|
||||
}
|
||||
|
||||
function openDeposit(row: PlayerRow) {
|
||||
depositForm.value = { userId: row.id, amount: 100, remark: t('user.deposit_remark_default') };
|
||||
depositVisible.value = true;
|
||||
}
|
||||
|
||||
async function submitCreate() {
|
||||
let payload: ReturnType<typeof buildCreatePlayerPayload>;
|
||||
try {
|
||||
@@ -311,30 +321,6 @@ async function submitEdit() {
|
||||
}
|
||||
}
|
||||
|
||||
async function submitDeposit() {
|
||||
if (depositForm.value.amount <= 0) {
|
||||
ElMessage.warning(t('msg.amount_gt_zero'));
|
||||
return;
|
||||
}
|
||||
depositLoading.value = true;
|
||||
try {
|
||||
await api.post('/admin/wallet/deposit', {
|
||||
userId: depositForm.value.userId,
|
||||
amount: depositForm.value.amount,
|
||||
remark: depositForm.value.remark,
|
||||
requestId: `dep-${depositForm.value.userId}-${Date.now()}`,
|
||||
});
|
||||
ElMessage.success(t('msg.topup_ok'));
|
||||
depositVisible.value = false;
|
||||
load();
|
||||
} catch (e: unknown) {
|
||||
const err = e as { response?: { data?: { error?: string } } };
|
||||
ElMessage.error(err.response?.data?.error ?? t('msg.topup_failed'));
|
||||
} finally {
|
||||
depositLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(v: string) {
|
||||
if (!v) return '—';
|
||||
return new Date(v).toLocaleString(localeTag.value);
|
||||
@@ -554,11 +540,12 @@ function statusLabel(s: string) {
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('common.actions')" width="300" fixed="right" align="center">
|
||||
<el-table-column :label="t('common.actions')" width="340" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button size="small" link type="primary" @click="openDetail(row.id)">{{ t('common.detail') }}</el-button>
|
||||
<el-button size="small" link type="primary" @click="openEdit(row.id)">{{ t('common.edit') }}</el-button>
|
||||
<el-button size="small" link type="primary" @click="openDeposit(row)">{{ t('common.topup') }}</el-button>
|
||||
<el-button size="small" link type="success" @click="openTransfer('deposit', row)">{{ t('common.topup') }}</el-button>
|
||||
<el-button size="small" link type="warning" @click="openTransfer('withdraw', row)">{{ t('agent_portal.withdraw_btn_label') }}</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 'ACTIVE'"
|
||||
size="small"
|
||||
@@ -760,21 +747,41 @@ function statusLabel(s: string) {
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="depositVisible" :title="t('user.dialog.deposit')" width="400px" destroy-on-close>
|
||||
<el-form label-width="80px">
|
||||
<el-form-item :label="t('user.field.player_id')">
|
||||
<el-input :model-value="depositForm.userId" disabled />
|
||||
<el-dialog v-model="transferVisible" :title="transferTitle()" width="520px" destroy-on-close>
|
||||
<WalletTransferContext
|
||||
:context="transferContext"
|
||||
:mode="transferType"
|
||||
:loading="transferContextLoading"
|
||||
/>
|
||||
<el-form label-width="88px">
|
||||
<el-form-item :label="t('common.col_id')">
|
||||
<span>{{ transferTarget?.id }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('user.field.amount')">
|
||||
<el-input-number v-model="depositForm.amount" :min="0.01" :step="10" style="width: 100%" />
|
||||
<el-input-number
|
||||
v-model="transferAmount"
|
||||
:min="transferAmountRange.min"
|
||||
:max="transferAmountRange.max"
|
||||
:disabled="transferAmountDisabled"
|
||||
:step="10"
|
||||
:precision="2"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('user.field.remark')">
|
||||
<el-input v-model="depositForm.remark" />
|
||||
<el-input v-model="transferRemark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="depositVisible = false">{{ t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="depositLoading" @click="submitDeposit">{{ t('user.btn.confirm_deposit') }}</el-button>
|
||||
<el-button @click="transferVisible = false">{{ t('common.cancel') }}</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="transferLoading"
|
||||
:disabled="transferAmountDisabled"
|
||||
@click="submitTransfer"
|
||||
>
|
||||
{{ t('common.confirm') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user