Initial commit: 网络验证平台

This commit is contained in:
Admin
2026-04-27 17:22:56 +08:00
commit afe67d704e
780 changed files with 88960 additions and 0 deletions
+175
View File
@@ -0,0 +1,175 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { toast } from 'vue-sonner'
import api from '@/services/api'
const route = useRoute()
const router = useRouter()
const loading = ref(false)
const apps = ref<any[]>([])
const cardTypes = ref<any[]>([])
const form = ref({
app_id: route.query.app_id || '',
card_type_id: route.query.card_type_id || '',
quantity: 1,
})
const selectedApp = computed(() => {
return apps.value.find(a => a.id === Number(form.value.app_id))
})
const availableCardTypes = computed(() => {
return cardTypes.value.filter(ct => ct.app_id === Number(form.value.app_id))
})
const totalPrice = computed(() => {
const ct = cardTypes.value.find(c => c.id === Number(form.value.card_type_id))
return ct ? ct.price * form.value.quantity : 0
})
onMounted(async () => {
try {
const data = await api.get('/agent/apps')
apps.value = data || []
if (apps.value.length > 0) {
const typesData = await api.get('/agent/card-types')
cardTypes.value = typesData || []
}
}
catch (error) {
console.error('获取数据失败:', error)
}
})
async function handleGenerate() {
if (!form.value.app_id) {
toast.error('请选择应用')
return
}
if (!form.value.card_type_id) {
toast.error('请选择卡类')
return
}
if (form.value.quantity < 1 || form.value.quantity > 100) {
toast.error('生成数量需要在 1-100 之间')
return
}
loading.value = true
try {
const data = await api.post<{ codes: string[], cards: any[] }>('/agent/cards/generate', {
app_id: Number(form.value.app_id),
card_type_id: Number(form.value.card_type_id),
quantity: form.value.quantity,
})
toast.success(`成功生成 ${data.codes.length} 张卡密`)
const codesText = data.codes.join('\n')
await navigator.clipboard.writeText(codesText)
toast.success('卡密已复制到剪贴板')
router.push('/agent/cards')
}
catch (error: any) {
console.error('生成卡密失败:', error)
toast.error(error.message || '生成失败')
}
finally {
loading.value = false
}
}
</script>
<template>
<div class="space-y-6">
<div>
<h1 class="text-2xl font-bold">
生成卡密
</h1>
<p class="text-muted-foreground">
为授权应用生成卡密
</p>
</div>
<UiCard class="max-w-xl">
<UiCardHeader>
<UiCardTitle>生成设置</UiCardTitle>
<UiCardDescription>
选择应用和卡类设置生成数量
</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-6">
<div class="space-y-2">
<UiLabel>选择应用</UiLabel>
<UiSelect v-model="form.app_id">
<UiSelectTrigger>
<UiSelectValue placeholder="请选择应用" />
</UiSelectTrigger>
<UiSelectContent>
<UiSelectItem v-for="app in apps" :key="app.id" :value="String(app.id)">
{{ app.name }}
</UiSelectItem>
</UiSelectContent>
</UiSelect>
</div>
<div v-if="form.app_id" class="space-y-2">
<UiLabel>选择卡类</UiLabel>
<UiSelect v-model="form.card_type_id">
<UiSelectTrigger>
<UiSelectValue placeholder="请选择卡类" />
</UiSelectTrigger>
<UiSelectContent>
<UiSelectItem v-for="ct in availableCardTypes" :key="ct.id" :value="String(ct.id)">
{{ ct.name }} - {{ ct.duration_days }} - ¥{{ ct.price }}
</UiSelectItem>
</UiSelectContent>
</UiSelect>
</div>
<div class="space-y-2">
<UiLabel>生成数量</UiLabel>
<UiInput
v-model.number="form.quantity"
type="number"
:min="1"
:max="100"
placeholder="请输入生成数量"
/>
<p class="text-xs text-muted-foreground">
单次最多生成 100 张卡密
</p>
</div>
<div v-if="totalPrice > 0" class="p-4 rounded-lg bg-muted/50">
<div class="flex items-center justify-between">
<span class="text-muted-foreground">预计费用</span>
<span class="text-xl font-bold">¥{{ totalPrice.toFixed(2) }}</span>
</div>
</div>
<div class="flex gap-3">
<UiButton variant="outline" as-child>
<router-link to="/agent/cards">
取消
</router-link>
</UiButton>
<UiButton
:disabled="loading || !form.app_id || !form.card_type_id"
@click="handleGenerate"
>
<Icon v-if="loading" icon="lucide:loader-2" class="mr-2 h-4 w-4 animate-spin" />
{{ loading ? '生成中...' : '生成卡密' }}
</UiButton>
</div>
</UiCardContent>
</UiCard>
</div>
</template>