Files
verify/frontend/src/pages/developer/agents/[id].vue
T
2026-04-27 17:22:56 +08:00

371 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { computed, onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { toast } from 'vue-sonner'
import { BasicPage } from '@/components/global-layout'
import api from '@/services/api'
const router = useRouter()
const route = useRoute()
const { t } = useI18n()
interface Agent {
id: number
username: string
email: string
avatar: string
status: string
parent_agent_id: number | null
parent_agent_name: string
commission: number
can_create_agent: boolean
balance: number
}
const loading = ref(true)
const saving = ref(false)
const agents = ref<Agent[]>([])
const agentId = computed(() => route.params.id as string)
const form = ref({
username: '',
email: '',
password: '',
parent_agent_id: '',
commission: 0,
can_create_agent: false,
balance: 0,
})
async function fetchAgent() {
loading.value = true
try {
const data = await api.get<Agent>(`/dev/agents/${agentId.value}`)
if (data) {
form.value.username = data.username || ''
form.value.email = data.email || ''
form.value.password = ''
form.value.parent_agent_id = data.parent_agent_id ? String(data.parent_agent_id) : 'none'
form.value.commission = data.commission || 0
form.value.can_create_agent = data.can_create_agent === true
form.value.balance = data.balance || 0
}
}
catch (error) {
console.error('获取代理信息失败:', error)
toast.error(t('developer.agents.edit.fetchFailed'))
router.push('/developer/agents')
}
finally {
loading.value = false
}
}
async function fetchAgents() {
try {
const data = await api.get<{ agents?: Agent[], total: number }>('/dev/agents')
agents.value = (data?.agents || []).filter(a => String(a.id) !== agentId.value)
}
catch (error) {
console.error('获取代理列表失败:', error)
}
}
const selectedParentAgent = computed(() => {
if (form.value.parent_agent_id && form.value.parent_agent_id !== 'none') {
return agents.value.find(a => String(a.id) === form.value.parent_agent_id)
}
return null
})
async function handleSave() {
if (!form.value.username) {
toast.error(t('developer.agents.create.usernameRequired'))
return
}
if (form.value.password && form.value.password.length < 6) {
toast.error(t('developer.agents.create.passwordMinLength'))
return
}
saving.value = true
try {
const payload: any = {
commission: form.value.commission,
can_create_agent: form.value.can_create_agent,
balance: form.value.balance,
}
if (form.value.email) {
payload.email = form.value.email
}
if (form.value.password) {
payload.password = form.value.password
}
if (form.value.parent_agent_id && form.value.parent_agent_id !== 'none') {
payload.parent_agent_id = parseInt(form.value.parent_agent_id)
} else {
payload.parent_agent_id = null
}
await api.put(`/dev/agents/${agentId.value}`, payload)
toast.success(t('developer.agents.edit.saveSuccess'))
router.push('/developer/agents')
}
catch (error: any) {
console.error('保存代理失败:', error)
toast.error(error.message || t('developer.agents.edit.saveFailed'))
}
finally {
saving.value = false
}
}
onMounted(() => {
fetchAgent()
fetchAgents()
})
</script>
<template>
<BasicPage
:title="t('developer.agents.edit.title')"
:description="t('developer.agents.edit.description')"
:breadcrumbs="[
{ title: t('developer.agents.title'), href: '/developer/agents' },
{ title: t('developer.agents.edit.title') },
]"
sticky
>
<div v-if="loading" class="flex items-center justify-center py-12">
<Icon icon="lucide:loader-2" class="h-8 w-8 animate-spin text-muted-foreground" />
</div>
<div v-else class="space-y-6">
<div class="grid gap-6 lg:grid-cols-3">
<div class="lg:col-span-2 space-y-6">
<UiCard>
<UiCardHeader>
<UiCardTitle class="flex items-center gap-2">
<Icon icon="lucide:user" class="size-5" />
{{ t('developer.agents.create.basicInfo') }}
</UiCardTitle>
<UiCardDescription>{{ t('developer.agents.create.basicInfoDesc') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-6">
<div class="space-y-2">
<UiLabel for="username">
{{ t('developer.agents.form.username') }}
</UiLabel>
<UiInput
id="username"
v-model="form.username"
disabled
class="bg-muted"
/>
<p class="text-xs text-muted-foreground">
{{ t('developer.agents.edit.usernameHint') }}
</p>
</div>
<div class="space-y-2">
<UiLabel for="email">
{{ t('developer.agents.form.email') }}
</UiLabel>
<UiInput
id="email"
v-model="form.email"
type="email"
:placeholder="t('developer.agents.form.emailPlaceholder')"
/>
</div>
<div class="space-y-2">
<UiLabel for="password">
{{ t('developer.agents.form.password') }}
</UiLabel>
<UiInput
id="password"
v-model="form.password"
type="password"
:placeholder="t('developer.agents.edit.passwordPlaceholder')"
/>
<p class="text-xs text-muted-foreground">
{{ t('developer.agents.edit.passwordHint') }}
</p>
</div>
</UiCardContent>
</UiCard>
<UiCard>
<UiCardHeader>
<UiCardTitle class="flex items-center gap-2">
<Icon icon="lucide:settings-2" class="size-5" />
{{ t('developer.agents.create.agentConfig') }}
</UiCardTitle>
<UiCardDescription>{{ t('developer.agents.create.agentConfigDesc') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-6">
<div class="space-y-2">
<UiLabel for="parent_agent">
{{ t('developer.agents.form.parentAgent') }}
</UiLabel>
<UiSelect v-model="form.parent_agent_id">
<UiSelectTrigger>
<UiSelectValue :placeholder="t('developer.agents.form.selectParentAgent')" />
</UiSelectTrigger>
<UiSelectContent>
<UiSelectItem value="none">
{{ t('developer.agents.form.noParent') }}
</UiSelectItem>
<UiSelectItem
v-for="agent in agents"
:key="agent.id"
:value="String(agent.id)"
>
{{ agent.username }}
</UiSelectItem>
</UiSelectContent>
</UiSelect>
<p class="text-xs text-muted-foreground">
{{ t('developer.agents.create.parentAgentHint') }}
</p>
</div>
<div class="space-y-2">
<UiLabel for="commission">
{{ t('developer.agents.form.commission') }}
</UiLabel>
<div class="flex items-center gap-4">
<UiNumberField
v-model="form.commission"
:min="0"
:max="1"
:step="0.01"
class="flex-1 max-w-[200px]"
>
<UiNumberFieldContent>
<UiNumberFieldDecrement />
<UiNumberFieldInput />
<UiNumberFieldIncrement />
</UiNumberFieldContent>
</UiNumberField>
<span class="text-sm text-muted-foreground">%</span>
</div>
<p class="text-xs text-muted-foreground">
{{ t('developer.agents.form.commissionPlaceholder') }}
</p>
</div>
<div class="space-y-2">
<UiLabel for="balance">
{{ t('developer.agents.form.balance') }}
</UiLabel>
<div class="flex items-center gap-4">
<UiNumberField
v-model="form.balance"
:min="0"
:step="0.01"
class="flex-1 max-w-[200px]"
>
<UiNumberFieldContent>
<UiNumberFieldDecrement />
<UiNumberFieldInput />
<UiNumberFieldIncrement />
</UiNumberFieldContent>
</UiNumberField>
<span class="text-sm text-muted-foreground">¥</span>
</div>
<p class="text-xs text-muted-foreground">
{{ t('developer.agents.form.balancePlaceholder') }}
</p>
</div>
<div class="flex items-center justify-between">
<div class="space-y-0.5">
<UiLabel>{{ t('developer.agents.form.canCreateAgent') }}</UiLabel>
<p class="text-xs text-muted-foreground">
{{ t('developer.agents.create.canCreateAgentHint') }}
</p>
</div>
<!-- 注意UiSwitch 必须使用 v-model不能使用 v-model:checked -->
<UiSwitch v-model="form.can_create_agent" />
</div>
</UiCardContent>
</UiCard>
</div>
<div class="space-y-6">
<UiCard>
<UiCardHeader>
<UiCardTitle class="flex items-center gap-2">
<Icon icon="lucide:receipt" class="size-5" />
{{ t('developer.agents.create.preview') }}
</UiCardTitle>
</UiCardHeader>
<UiCardContent class="space-y-4">
<div class="space-y-3">
<div class="flex justify-between text-sm">
<span class="text-muted-foreground">{{ t('developer.agents.form.username') }}</span>
<span>{{ form.username || '-' }}</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-muted-foreground">{{ t('developer.agents.form.canCreateAgent') }}</span>
<span>{{ form.can_create_agent ? t('common.yes') : t('common.no') }}</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-muted-foreground">{{ t('developer.agents.form.email') }}</span>
<span>{{ form.email || '-' }}</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-muted-foreground">{{ t('developer.agents.form.parentAgent') }}</span>
<span>{{ selectedParentAgent?.username || '-' }}</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-muted-foreground">{{ t('developer.agents.form.commission') }}</span>
<span>{{ (form.commission * 100).toFixed(0) }}%</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-muted-foreground">{{ t('developer.agents.form.balance') }}</span>
<span>¥{{ form.balance.toFixed(2) }}</span>
</div>
</div>
</UiCardContent>
</UiCard>
<UiCard>
<UiCardContent class="pt-6">
<div class="flex flex-col gap-3">
<UiButton
class="w-full"
size="lg"
:disabled="saving"
@click="handleSave"
>
<Icon v-if="saving" icon="lucide:loader-2" class="mr-2 h-4 w-4 animate-spin" />
<Icon v-else icon="lucide:save" class="mr-2 h-4 w-4" />
{{ t('developer.agents.edit.save') }}
</UiButton>
<UiButton
variant="outline"
class="w-full"
@click="router.back()"
>
{{ t('developer.agents.create.cancel') }}
</UiButton>
</div>
</UiCardContent>
</UiCard>
</div>
</div>
</div>
</BasicPage>
</template>