From 64569e305e4aa2ceba238f4907e033b275517c07 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 7 May 2026 02:31:15 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8E=88=E6=9D=83?= =?UTF-8?q?=E8=AF=A6=E6=83=85API=E8=BF=94=E5=9B=9E=E6=A0=BC=E5=BC=8F,?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=8E=88=E6=9D=83=E7=AE=A1=E7=90=86=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E8=A1=A8=E6=A0=BC=E5=92=8C=E6=89=B9=E9=87=8F=E6=93=8D?= =?UTF-8?q?=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/router/admin/agent_apps.go | 16 +- .../admin/agent-apps/components/columns.ts | 144 ++++++++++ .../agent-apps/components/data-table.vue | 78 ++++++ frontend/src/pages/admin/agent-apps/index.vue | 252 ++++++++---------- 4 files changed, 338 insertions(+), 152 deletions(-) create mode 100644 frontend/src/pages/admin/agent-apps/components/columns.ts create mode 100644 frontend/src/pages/admin/agent-apps/components/data-table.vue diff --git a/backend/internal/router/admin/agent_apps.go b/backend/internal/router/admin/agent_apps.go index 11a81ba..ef6593e 100644 --- a/backend/internal/router/admin/agent_apps.go +++ b/backend/internal/router/admin/agent_apps.go @@ -568,9 +568,11 @@ func handleGetAgentAppDetail(c *gin.Context) { } type CardTypeResponse struct { - ID uint `json:"id"` + CardTypeID uint `json:"card_type_id"` Name string `json:"name"` + BillingType string `json:"billing_type"` Price float64 `json:"price"` + OriginPrice float64 `json:"origin_price"` CanGenerate bool `json:"can_generate"` } @@ -583,6 +585,7 @@ func handleGetAgentAppDetail(c *gin.Context) { AppName string `json:"app_name"` Discount float64 `json:"discount"` Status string `json:"status"` + Balance float64 `json:"balance"` CardTypes []CardTypeResponse `json:"card_types"` CreatedAt string `json:"created_at"` } @@ -590,9 +593,11 @@ func handleGetAgentAppDetail(c *gin.Context) { var cardTypes []CardTypeResponse for _, ct := range agentApp.CardTypes { cardTypes = append(cardTypes, CardTypeResponse{ - ID: ct.CardTypeID, + CardTypeID: ct.CardTypeID, Name: ct.CardType.Name, - Price: ct.CardType.Price, + BillingType: ct.CardType.RechargeType, + Price: ct.Price, + OriginPrice: ct.CardType.Price, CanGenerate: ct.CanGenerate, }) } @@ -605,6 +610,7 @@ func handleGetAgentAppDetail(c *gin.Context) { AppName: application.Name, Discount: agentApp.Discount, Status: agentApp.Status, + Balance: agent.Balance, CardTypes: cardTypes, CreatedAt: agentApp.CreatedAt.Format("2006-01-02 15:04:05"), } @@ -613,7 +619,9 @@ func handleGetAgentAppDetail(c *gin.Context) { result.AgentEmail = *agent.Email } - response.Success(c, result) + response.Success(c, gin.H{ + "agent_app": result, + }) } func handleUpdateAgentApp(c *gin.Context) { diff --git a/frontend/src/pages/admin/agent-apps/components/columns.ts b/frontend/src/pages/admin/agent-apps/components/columns.ts new file mode 100644 index 0000000..faac45d --- /dev/null +++ b/frontend/src/pages/admin/agent-apps/components/columns.ts @@ -0,0 +1,144 @@ +import type { ColumnDef } from '@tanstack/vue-table' + +import { Eye, MoreHorizontal, Pencil, Trash2 } from 'lucide-vue-next' +import { h } from 'vue' + +import type { AgentApp } from '@/pages/admin/agent-apps/data/schema' + +import Badge from '@/components/ui/badge/Badge.vue' +import Button from '@/components/ui/button/Button.vue' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' + +export function getColumns(actions: { + onView: (row: AgentApp) => void + onEdit: (row: AgentApp) => void + onDelete: (row: AgentApp) => void +}): ColumnDef[] { + return [ + { + accessorKey: 'agent_name', + header: '代理', + cell: ({ row }) => { + const name = row.getValue('agent_name') as string + const email = row.original.agent_email + return h('div', { class: 'flex items-center space-x-3' }, [ + h('div', { class: 'h-8 w-8 rounded bg-primary/10 flex items-center justify-center flex-shrink-0' }, [ + h('span', { class: 'text-primary font-bold text-sm' }, name ? name.charAt(0).toUpperCase() : '?'), + ]), + h('div', {}, [ + h('p', { class: 'font-medium' }, name || '-'), + email ? h('p', { class: 'text-xs text-muted-foreground' }, email) : null, + ]), + ]) + }, + }, + { + accessorKey: 'app_name', + header: '应用', + cell: ({ row }) => { + const appName = row.getValue('app_name') as string + return appName ? h(Badge, { variant: 'secondary' }, () => appName) : '-' + }, + }, + { + accessorKey: 'card_types', + header: '卡密权限', + cell: ({ row }) => { + const cardTypes = row.original.card_types || [] + if (cardTypes.length === 0) + return h('span', { class: 'text-muted-foreground text-sm' }, '-') + const authorized = cardTypes.filter(ct => ct.can_generate).length + return h('span', { class: 'text-sm' }, `${authorized}/${cardTypes.length}`) + }, + }, + { + accessorKey: 'balance', + header: '余额', + cell: ({ row }) => { + const balance = row.getValue('balance') as number + return h('span', { class: 'font-medium' }, `¥${(balance || 0).toFixed(2)}`) + }, + }, + { + accessorKey: 'status', + header: '状态', + cell: ({ row }) => { + const status = row.getValue('status') as string + const isActive = status === 'active' + return h(Badge, { variant: isActive ? 'default' : 'secondary' }, () => isActive ? '已启用' : '已禁用') + }, + }, + { + accessorKey: 'created_at', + header: '授权时间', + cell: ({ row }) => { + const createdAt = row.getValue('created_at') + if (!createdAt) + return '-' + try { + const date = new Date(createdAt as string) + if (Number.isNaN(date.getTime())) + return '-' + return date.toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + }) + } + catch { + return '-' + } + }, + }, + { + id: 'actions', + header: () => h('span', { class: 'sr-only' }, '操作'), + cell: ({ row }) => { + const item = row.original + return h( + DropdownMenu, + {}, + { + default: () => [ + h(DropdownMenuTrigger, { asChild: true }, () => + h(Button, { variant: 'ghost', class: 'h-8 w-8 p-0' }, () => [ + h(MoreHorizontal, { class: 'h-4 w-4' }), + h('span', { class: 'sr-only' }, '打开菜单'), + ]), + ), + h( + DropdownMenuContent, + { align: 'end' }, + () => [ + h(DropdownMenuItem, { onClick: () => actions.onView(item) }, () => [ + h(Eye, { class: 'mr-2 h-4 w-4' }), + '查看授权', + ]), + h(DropdownMenuItem, { onClick: () => actions.onEdit(item) }, () => [ + h(Pencil, { class: 'mr-2 h-4 w-4' }), + '编辑授权', + ]), + h(DropdownMenuSeparator), + h(DropdownMenuItem, { class: 'text-destructive', onClick: () => actions.onDelete(item) }, () => [ + h(Trash2, { class: 'mr-2 h-4 w-4' }), + '移除授权', + ]), + ], + ), + ], + }, + ) + }, + enableSorting: false, + enableHiding: false, + }, + ] +} diff --git a/frontend/src/pages/admin/agent-apps/components/data-table.vue b/frontend/src/pages/admin/agent-apps/components/data-table.vue new file mode 100644 index 0000000..96b8021 --- /dev/null +++ b/frontend/src/pages/admin/agent-apps/components/data-table.vue @@ -0,0 +1,78 @@ + + + diff --git a/frontend/src/pages/admin/agent-apps/index.vue b/frontend/src/pages/admin/agent-apps/index.vue index 86ccedf..d1b851c 100644 --- a/frontend/src/pages/admin/agent-apps/index.vue +++ b/frontend/src/pages/admin/agent-apps/index.vue @@ -1,45 +1,49 @@