feat(admin): 从已有玩家升级代理、修复 i18n 与过期 .js 冲突
- 新建一级代理改为选择已有玩家;新建用户可选一级代理 - 操作日志/注单等扁平 key 翻译;清理 src 内误生成 .js,Vite 优先解析 .ts Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,11 +11,13 @@ import {
|
||||
emptyAgentEditForm,
|
||||
editFormFromAgentDetail,
|
||||
buildCreateAgentPayload,
|
||||
applyPromotableUserToForm,
|
||||
type AgentRow,
|
||||
type AgentDetail,
|
||||
type AgentCreateForm,
|
||||
type AgentEditForm,
|
||||
} from './agent-form';
|
||||
type PromotableUserOption,
|
||||
} from './agent-form.ts';
|
||||
import {
|
||||
formatAmount,
|
||||
formatAmountFull,
|
||||
@@ -45,6 +47,9 @@ const editLoading = ref(false);
|
||||
const creditLoading = ref(false);
|
||||
|
||||
const createForm = ref<AgentCreateForm>(emptyAgentCreateForm());
|
||||
const promotableUsers = ref<PromotableUserOption[]>([]);
|
||||
const promotableLoading = ref(false);
|
||||
const promotableKeyword = ref('');
|
||||
const editForm = ref<AgentEditForm>(emptyAgentEditForm());
|
||||
const detail = ref<AgentDetail | null>(null);
|
||||
const editingId = ref('');
|
||||
@@ -76,9 +81,38 @@ function onSizeChange(size: number) {
|
||||
load();
|
||||
}
|
||||
|
||||
async function loadPromotableUsers() {
|
||||
promotableLoading.value = true;
|
||||
try {
|
||||
const { data } = await api.get('/admin/users/promotable-for-agent', {
|
||||
params: { keyword: promotableKeyword.value.trim() || undefined },
|
||||
});
|
||||
promotableUsers.value = data.data as PromotableUserOption[];
|
||||
} finally {
|
||||
promotableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
createForm.value = emptyAgentCreateForm();
|
||||
promotableKeyword.value = '';
|
||||
createVisible.value = true;
|
||||
loadPromotableUsers();
|
||||
}
|
||||
|
||||
function onPromotableSearch(q: string) {
|
||||
promotableKeyword.value = q;
|
||||
void loadPromotableUsers();
|
||||
}
|
||||
|
||||
function onPromotableUserChange(userId: string) {
|
||||
const user = promotableUsers.value.find((u) => u.id === userId);
|
||||
if (user) applyPromotableUserToForm(createForm.value, user);
|
||||
}
|
||||
|
||||
function formatPromotableLabel(u: PromotableUserOption) {
|
||||
const parent = u.parentUsername ? ` · ${u.parentUsername}` : '';
|
||||
return `${u.username} (#${u.id})${parent}`;
|
||||
}
|
||||
|
||||
async function openDetail(userId: string) {
|
||||
@@ -270,14 +304,25 @@ function creditTypeLabel(type: string) {
|
||||
|
||||
<el-dialog v-model="createVisible" :title="t('agent.dialog.create')" width="520px" destroy-on-close>
|
||||
<el-form label-width="100px">
|
||||
<el-form-item :label="t('user.col.username')" required>
|
||||
<el-input v-model="createForm.username" :placeholder="t('user.ph.username_unique')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('user.field.password')" required>
|
||||
<el-input v-model="createForm.password" type="text" autocomplete="off" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('user.field.confirm_password')" required>
|
||||
<el-input v-model="createForm.confirmPassword" type="text" autocomplete="off" />
|
||||
<el-form-item :label="t('agent.field.select_user')" required>
|
||||
<el-select
|
||||
v-model="createForm.userId"
|
||||
filterable
|
||||
remote
|
||||
:remote-method="onPromotableSearch"
|
||||
:loading="promotableLoading"
|
||||
:placeholder="t('agent.ph.select_user')"
|
||||
style="width: 100%"
|
||||
@change="onPromotableUserChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in promotableUsers"
|
||||
:key="u.id"
|
||||
:label="formatPromotableLabel(u)"
|
||||
:value="u.id"
|
||||
/>
|
||||
</el-select>
|
||||
<div class="field-hint">{{ t('agent.hint.select_user') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('agent.field.credit_limit')" required>
|
||||
<el-input-number
|
||||
|
||||
Reference in New Issue
Block a user