From c3536166b7bfa0e02fc0a5e70cf6ebd237982428 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 9 May 2026 04:30:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9B=E5=BB=BA=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E7=9A=84=E6=8E=88=E6=9D=83=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在左侧导航添加授权管理链接(代理管理后) - 创建独立的授权管理页面,参考版本管理页面样式 - 添加统计卡片显示授权应用总数、活跃授权、授权卡类 - 创建添加/编辑授权页面 - 从代理编辑页面移除授权管理部分 - 添加路由配置 --- .../src/components/admin-sidebar/index.vue | 7 +- frontend/src/pages/admin/agent-apps/[id].vue | 301 ++++++++++++++++++ .../admin/agent-apps/components/columns.ts | 117 +++++++ .../agent-apps/components/data-table.vue | 61 ++++ .../src/pages/admin/agent-apps/create.vue | 243 ++++++++++++++ .../src/pages/admin/agent-apps/data/schema.ts | 13 + frontend/src/pages/admin/agent-apps/index.vue | 190 +++++++++++ frontend/src/pages/admin/agents/[id].vue | 301 +----------------- frontend/src/router/routes.ts | 18 ++ 9 files changed, 950 insertions(+), 301 deletions(-) create mode 100644 frontend/src/pages/admin/agent-apps/[id].vue 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 create mode 100644 frontend/src/pages/admin/agent-apps/create.vue create mode 100644 frontend/src/pages/admin/agent-apps/data/schema.ts create mode 100644 frontend/src/pages/admin/agent-apps/index.vue diff --git a/frontend/src/components/admin-sidebar/index.vue b/frontend/src/components/admin-sidebar/index.vue index 4b5a529..85d980c 100644 --- a/frontend/src/components/admin-sidebar/index.vue +++ b/frontend/src/components/admin-sidebar/index.vue @@ -1,5 +1,5 @@ + + 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..9d382ba --- /dev/null +++ b/frontend/src/pages/admin/agent-apps/components/columns.ts @@ -0,0 +1,117 @@ +import type { ColumnDef } from '@tanstack/vue-table' +import type { Composer } from 'vue-i18n' + +import { Badge } from '@/components/ui/badge' +import { Button } from '@/components/ui/button' +import { Check, Pencil, Trash2, X } from 'lucide-vue-next' +import { h } from 'vue' + +import type { AgentApp } from '../data/schema' + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { MoreHorizontal } from 'lucide-vue-next' + +export function getColumns(actions: { + onEdit: (row: AgentApp) => void + onDelete: (row: AgentApp) => void + onToggleStatus: (row: AgentApp) => void +}, t: Composer['t']): ColumnDef[] { + return [ + { + accessorKey: 'agent_name', + header: () => h('span', {}, '代理'), + cell: ({ row }) => { + const agentName = row.getValue('agent_name') as string + return h('div', { class: 'flex items-center gap-2' }, [ + h('span', { class: 'font-medium' }, agentName || '-'), + ]) + }, + }, + { + accessorKey: 'app_name', + header: () => h('span', {}, '应用'), + cell: ({ row }) => { + const appName = row.getValue('app_name') as string + return h('span', { class: 'font-medium' }, appName || '-') + }, + }, + { + accessorKey: 'card_types', + header: () => h('span', {}, '卡密类型'), + cell: ({ row }) => { + const cardTypes = row.getValue('card_types') as AgentApp['card_types'] + const total = cardTypes?.length || 0 + const authorized = cardTypes?.filter(c => c.can_generate).length || 0 + return h('div', { class: 'flex items-center gap-2' }, [ + h('span', { class: 'text-sm' }, `${authorized} / ${total}`), + ]) + }, + }, + { + accessorKey: 'balance', + header: () => h('span', {}, '余额'), + cell: ({ row }) => { + const balance = row.getValue('balance') as number + return h('span', { class: 'text-sm font-medium' }, `¥${(balance || 0).toFixed(2)}`) + }, + }, + { + accessorKey: 'status', + header: () => h('span', {}, '状态'), + cell: ({ row }) => { + const status = row.getValue('status') as string + const isActive = status === 'active' + return h(Badge, { variant: isActive ? 'default' : 'secondary' }, () => + isActive ? '已启用' : '已禁用' + ) + }, + }, + { + id: 'actions', + header: () => h('span', { class: 'sr-only' }, '操作'), + cell: ({ row }) => { + const app = row.original + const isActive = app.status === 'active' + + 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.onEdit(app) }, () => [ + h(Pencil, { class: 'mr-2 h-4 w-4' }), + '编辑', + ]), + h(DropdownMenuItem, { onClick: () => actions.onToggleStatus(app) }, () => [ + h(Check, { class: 'mr-2 h-4 w-4' }), + isActive ? '禁用' : '启用', + ]), + h(DropdownMenuSeparator), + h(DropdownMenuItem, { class: 'text-destructive', onClick: () => actions.onDelete(app) }, () => [ + h(Trash2, { class: 'mr-2 h-4 w-4' }), + '删除', + ]), + ], + ), + ], + }, + ) + }, + }, + ] +} 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..b0dcc51 --- /dev/null +++ b/frontend/src/pages/admin/agent-apps/components/data-table.vue @@ -0,0 +1,61 @@ + + + diff --git a/frontend/src/pages/admin/agent-apps/create.vue b/frontend/src/pages/admin/agent-apps/create.vue new file mode 100644 index 0000000..ef442db --- /dev/null +++ b/frontend/src/pages/admin/agent-apps/create.vue @@ -0,0 +1,243 @@ + + + diff --git a/frontend/src/pages/admin/agent-apps/data/schema.ts b/frontend/src/pages/admin/agent-apps/data/schema.ts new file mode 100644 index 0000000..a05fa6d --- /dev/null +++ b/frontend/src/pages/admin/agent-apps/data/schema.ts @@ -0,0 +1,13 @@ +export interface AgentApp { + id: number + agent_id: number + agent_name?: string + application_id: number + app_name: string + status: string + discount: number + balance: number + card_types: { card_type_id: number, can_generate: boolean, name?: string }[] + created_at?: string + updated_at?: string +} diff --git a/frontend/src/pages/admin/agent-apps/index.vue b/frontend/src/pages/admin/agent-apps/index.vue new file mode 100644 index 0000000..d623cfb --- /dev/null +++ b/frontend/src/pages/admin/agent-apps/index.vue @@ -0,0 +1,190 @@ + + + diff --git a/frontend/src/pages/admin/agents/[id].vue b/frontend/src/pages/admin/agents/[id].vue index 33f9251..3023d14 100644 --- a/frontend/src/pages/admin/agents/[id].vue +++ b/frontend/src/pages/admin/agents/[id].vue @@ -1,5 +1,5 @@ @@ -386,98 +247,6 @@ onMounted(() => { - - - -
- - - 授权应用 - - 管理该代理可生成卡密的应用和卡类权限 -
- - - 添加授权 - -
- -
- -
-
- -

暂无授权应用

-

点击上方按钮为代理添加应用授权

-
-
- - - - - - - - - - - - - -
应用卡密类型余额状态操作
-
-
-
@@ -540,73 +309,5 @@ onMounted(() => {
- - - - - 添加授权 - 为该代理添加应用和卡类权限 - -
-
- 选择应用 - - - - - - - {{ app.name }} - - - -
- -
- 卡类权限 -
- - - - - - - - - - - - - - - - - -
卡类类型售价可生成
{{ ct.name }}{{ ct.billing_type }} - - - -
-
-
-
- - 取消 - - - 确认授权 - - -
-
diff --git a/frontend/src/router/routes.ts b/frontend/src/router/routes.ts index 637536f..04435eb 100644 --- a/frontend/src/router/routes.ts +++ b/frontend/src/router/routes.ts @@ -185,6 +185,24 @@ const routes: RouteRecordRaw[] = [ component: () => import('@/pages/admin/agents/[id].vue'), meta: { title: '编辑代理 - 管理后台' }, }, + { + path: 'agent-apps', + name: 'AdminAgentApps', + component: () => import('@/pages/admin/agent-apps/index.vue'), + meta: { title: '授权管理 - 管理后台' }, + }, + { + path: 'agent-apps/create', + name: 'AdminAgentAppCreate', + component: () => import('@/pages/admin/agent-apps/create.vue'), + meta: { title: '添加授权 - 管理后台' }, + }, + { + path: 'agent-apps/:id', + name: 'AdminAgentAppEdit', + component: () => import('@/pages/admin/agent-apps/[id].vue'), + meta: { title: '编辑授权 - 管理后台' }, + }, { path: 'finance', name: 'AdminFinance',