feat: 授权管理改为设置卡类价格,代理管理增加消费列

This commit is contained in:
2026-05-07 00:28:52 +08:00
parent 7646bd2c88
commit e7e7631fa5
9 changed files with 74 additions and 56 deletions
+16 -30
View File
@@ -36,8 +36,7 @@ const cardTypes = ref<CardType[]>([])
const form = ref({
agent_id: '',
application_id: '',
discount: 1.0,
card_types: [] as Array<{ card_type_id: number, can_generate: boolean }>,
card_types: [] as Array<{ card_type_id: number, can_generate: boolean, price: number }>,
})
async function fetchAgents() {
@@ -72,6 +71,7 @@ async function fetchCardTypes(applicationId: string) {
form.value.card_types = cardTypes.value.map(ct => ({
card_type_id: ct.id,
can_generate: false,
price: ct.price,
}))
}
catch (error) {
@@ -139,7 +139,6 @@ async function handleSave() {
await api.post('/dev/agent-apps/authorize', {
agent_id: Number(form.value.agent_id),
application_id: Number(form.value.application_id),
discount: form.value.discount,
card_types: form.value.card_types,
})
toast.success('授权成功')
@@ -218,26 +217,6 @@ onMounted(() => {
</UiSelectContent>
</UiSelect>
</div>
<div class="space-y-2">
<UiLabel>折扣</UiLabel>
<div class="flex items-center gap-4">
<UiInput
v-model.number="form.discount"
type="number"
step="0.01"
min="0.01"
max="1"
class="flex-1"
/>
<span class="text-sm text-muted-foreground w-20">
{{ (form.discount * 10).toFixed(1) }}
</span>
</div>
<p class="text-xs text-muted-foreground">
代理购买卡密的折扣范围0.01-1
</p>
</div>
</UiCardContent>
</UiCard>
@@ -247,7 +226,7 @@ onMounted(() => {
<Key class="size-5" />
卡密权限
</UiCardTitle>
<UiCardDescription>配置代理可生成的卡密类型</UiCardDescription>
<UiCardDescription>配置代理可生成的卡密类型及价格</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-4">
<div class="flex gap-2">
@@ -268,7 +247,8 @@ onMounted(() => {
<UiTableHead class="w-12" />
<UiTableHead>卡类名称</UiTableHead>
<UiTableHead>计费类型</UiTableHead>
<UiTableHead></UiTableHead>
<UiTableHead></UiTableHead>
<UiTableHead>授权价格</UiTableHead>
</UiTableRow>
</UiTableHeader>
<UiTableBody>
@@ -297,6 +277,16 @@ onMounted(() => {
<UiTableCell>
¥{{ cardTypes[index]?.price || 0 }}
</UiTableCell>
<UiTableCell @click.stop>
<UiInput
v-model.number="ct.price"
type="number"
step="0.01"
min="0"
class="w-24 h-8"
@click.stop
/>
</UiTableCell>
</UiTableRow>
</UiTableBody>
</UiTable>
@@ -323,13 +313,9 @@ onMounted(() => {
<span class="text-muted-foreground">应用</span>
<span>{{ selectedApplication?.name || '-' }}</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-muted-foreground">折扣</span>
<span>{{ (form.discount * 10).toFixed(1) }}</span>
</div>
<div v-if="cardTypes.length > 0" class="flex justify-between text-sm">
<span class="text-muted-foreground">卡密权限</span>
<span class="text-primary">{{ enabledCardTypesCount }}/{{ cardTypes.length }}</span>
<span>{{ enabledCardTypesCount }}/{{ cardTypes.length }}</span>
</div>
</div>
</UiCardContent>
@@ -2,6 +2,16 @@ import { z } from 'zod'
export const agentAppStatusSchema = z.enum(['active', 'inactive'])
export const cardTypeSchema = z.object({
id: z.number().optional(),
card_type_id: z.number(),
name: z.string().optional(),
billing_type: z.string().optional(),
can_generate: z.boolean(),
price: z.number().optional(),
origin_price: z.number().optional(),
})
export const agentAppSchema = z.object({
id: z.number(),
agent_id: z.number(),
@@ -12,13 +22,9 @@ export const agentAppSchema = z.object({
status: agentAppStatusSchema,
discount: z.number(),
balance: z.number(),
card_types: z.array(z.object({
id: z.number().optional(),
card_type_id: z.number(),
name: z.string().optional(),
can_generate: z.boolean(),
})).optional(),
card_types: z.array(cardTypeSchema).optional(),
created_at: z.string(),
})
export type CardTypeAuth = z.infer<typeof cardTypeSchema>
export type AgentApp = z.infer<typeof agentAppSchema>
+15 -11
View File
@@ -80,6 +80,15 @@ async function handleRemove() {
}
}
function getBillingTypeText(type: string) {
const map: Record<string, string> = {
subscription: '订阅',
time: '计时',
point: '点卡',
}
return map[type] || type
}
onMounted(() => {
fetchData()
})
@@ -119,10 +128,10 @@ onMounted(() => {
<UiCardTitle class="text-sm font-medium">
已启用
</UiCardTitle>
<CheckCircle class="size-4 text-green-500" />
<CheckCircle class="size-4 text-muted-foreground" />
</UiCardHeader>
<UiCardContent>
<div class="text-2xl font-bold text-green-600">
<div class="text-2xl font-bold">
{{ activeCount }}
</div>
</UiCardContent>
@@ -133,10 +142,10 @@ onMounted(() => {
<UiCardTitle class="text-sm font-medium">
已禁用
</UiCardTitle>
<XCircle class="size-4 text-orange-500" />
<XCircle class="size-4 text-muted-foreground" />
</UiCardHeader>
<UiCardContent>
<div class="text-2xl font-bold text-orange-600">
<div class="text-2xl font-bold">
{{ inactiveCount }}
</div>
</UiCardContent>
@@ -147,10 +156,10 @@ onMounted(() => {
<UiCardTitle class="text-sm font-medium">
代理余额总计
</UiCardTitle>
<Wallet class="size-4 text-blue-500" />
<Wallet class="size-4 text-muted-foreground" />
</UiCardHeader>
<UiCardContent>
<div class="text-2xl font-bold text-blue-600">
<div class="text-2xl font-bold">
¥{{ totalBalance.toFixed(2) }}
</div>
</UiCardContent>
@@ -201,7 +210,6 @@ onMounted(() => {
<UiTableHead>代理</UiTableHead>
<UiTableHead>应用</UiTableHead>
<UiTableHead>卡密权限</UiTableHead>
<UiTableHead>折扣</UiTableHead>
<UiTableHead>余额</UiTableHead>
<UiTableHead>状态</UiTableHead>
<UiTableHead>授权时间</UiTableHead>
@@ -236,16 +244,12 @@ onMounted(() => {
</div>
<span v-else class="text-muted-foreground text-sm">-</span>
</UiTableCell>
<UiTableCell>
{{ (item.discount * 10).toFixed(1) }}
</UiTableCell>
<UiTableCell>
<span class="font-medium">¥{{ (item.balance || 0).toFixed(2) }}</span>
</UiTableCell>
<UiTableCell>
<UiBadge
:variant="item.status === 'active' ? 'default' : 'secondary'"
:class="item.status === 'active' ? 'bg-green-500/10 text-green-600 hover:bg-green-500/20' : 'bg-orange-500/10 text-orange-600 hover:bg-orange-500/20'"
>
{{ item.status === 'active' ? '已启用' : '已禁用' }}
</UiBadge>
@@ -97,6 +97,14 @@ export function getColumns(actions: {
return `¥${balance.toFixed(2)}`
},
},
{
accessorKey: 'total_consumption',
header: () => t('admin.agents.columns.totalConsumption'),
cell: ({ row }) => {
const consumption = row.getValue('total_consumption') as number
return `¥${consumption.toFixed(2)}`
},
},
{
accessorKey: 'created_at',
header: () => t('admin.agents.columns.createdAt'),
@@ -57,6 +57,7 @@ const columnLabels: Record<string, string> = {
cards_count: 'admin.agents.columns.cardsCount',
child_agents_count: 'admin.agents.columns.childAgentsCount',
balance: 'admin.agents.columns.balance',
total_consumption: 'admin.agents.columns.totalConsumption',
created_at: 'admin.agents.columns.createdAt',
last_login_at: 'admin.agents.columns.lastLoginAt',
}
@@ -10,6 +10,7 @@ export interface Agent {
created_at: string
last_login_at: string
balance: number
total_consumption: number
can_create_agent: boolean
cards_count: number
child_agents_count: number
+1
View File
@@ -1201,6 +1201,7 @@
"childAgentsCount": "下级代理",
"canCreateAgent": "创建代理权限",
"balance": "余额",
"totalConsumption": "消费",
"createdAt": "注册时间",
"lastLoginAt": "最后登录"
},