Initial commit: 网络验证平台
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
import type { ColumnDef, Row } from '@tanstack/vue-table'
|
||||
import type { Composer } from 'vue-i18n'
|
||||
|
||||
import { Ban, Check, MoreHorizontal, Pencil, Trash2, X } from 'lucide-vue-next'
|
||||
import { h } from 'vue'
|
||||
|
||||
import type { Agent } from '../data/schema'
|
||||
|
||||
import Badge from '@/components/ui/badge/Badge.vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
|
||||
function getIndentStyle(row: Row<Agent>): string {
|
||||
const depth = row.depth
|
||||
if (depth === 0) return ''
|
||||
return `padding-left: ${depth * 24}px;`
|
||||
}
|
||||
|
||||
export function getColumns(actions: {
|
||||
onToggleStatus: (row: Agent) => void
|
||||
onEdit: (row: Agent) => void
|
||||
onDelete: (row: Agent) => void
|
||||
}, t: Composer['t']): ColumnDef<Agent>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'username',
|
||||
header: () => t('developer.agents.columns.username'),
|
||||
cell: ({ row }) => {
|
||||
const agent = row.original
|
||||
const indentStyle = getIndentStyle(row)
|
||||
return h('div', { class: 'flex items-center space-x-3', style: indentStyle }, [
|
||||
h(Avatar, { class: 'h-8 w-8' }, () => [
|
||||
h(AvatarImage, { src: agent.avatar, alt: agent.username }),
|
||||
h(AvatarFallback, {}, () => agent.username?.charAt(0).toUpperCase() || 'U'),
|
||||
]),
|
||||
h('div', { class: 'flex flex-col' }, [
|
||||
h('span', { class: 'font-medium' }, agent.username),
|
||||
agent.email ? h('span', { class: 'text-xs text-muted-foreground' }, agent.email) : null,
|
||||
]),
|
||||
])
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: () => t('developer.agents.columns.status'),
|
||||
cell: ({ row }) => {
|
||||
const status = row.getValue('status') as string
|
||||
const statusMap: Record<string, { text: string, variant: any }> = {
|
||||
active: { text: t('developer.agents.status.active'), variant: 'default' },
|
||||
inactive: { text: t('developer.agents.status.inactive'), variant: 'secondary' },
|
||||
banned: { text: t('developer.agents.status.banned'), variant: 'destructive' },
|
||||
}
|
||||
const { text, variant } = statusMap[status] || { text: status, variant: 'default' }
|
||||
return h(Badge, { variant }, () => text)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'can_create_agent',
|
||||
header: () => t('developer.agents.columns.canCreateAgent'),
|
||||
cell: ({ row }) => {
|
||||
const canCreate = row.getValue('can_create_agent') as boolean
|
||||
return h('div', { class: 'flex items-center justify-center' }, [
|
||||
canCreate
|
||||
? h(Check, { class: 'h-4 w-4 text-green-500' })
|
||||
: h(X, { class: 'h-4 w-4 text-red-500' }),
|
||||
])
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'cards_count',
|
||||
header: () => t('developer.agents.columns.cardsCount'),
|
||||
cell: ({ row }) => {
|
||||
const count = row.getValue('cards_count') as number
|
||||
return h(Badge, { variant: 'outline' }, () => String(count))
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'child_agents_count',
|
||||
header: () => t('developer.agents.columns.childAgentsCount'),
|
||||
cell: ({ row }) => {
|
||||
const count = row.getValue('child_agents_count') as number
|
||||
return h(Badge, { variant: 'secondary' }, () => String(count))
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'balance',
|
||||
header: () => t('developer.agents.columns.balance'),
|
||||
cell: ({ row }) => {
|
||||
const balance = row.getValue('balance') as number
|
||||
return `¥${balance.toFixed(2)}`
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'commission',
|
||||
header: () => t('developer.agents.columns.commission'),
|
||||
cell: ({ row }) => {
|
||||
const commission = row.getValue('commission') as number
|
||||
return `${(commission * 100).toFixed(0)}%`
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: () => t('developer.agents.columns.createdAt'),
|
||||
cell: ({ row }) => {
|
||||
const createdAt = row.getValue('created_at') as string
|
||||
if (!createdAt) return '-'
|
||||
try {
|
||||
const date = new Date(createdAt)
|
||||
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 '-'
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'last_login_at',
|
||||
header: () => t('developer.agents.columns.lastLoginAt'),
|
||||
cell: ({ row }) => {
|
||||
const lastLoginAt = row.getValue('last_login_at') as string
|
||||
if (!lastLoginAt) return '-'
|
||||
try {
|
||||
const date = new Date(lastLoginAt)
|
||||
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' }, t('common.actions')),
|
||||
cell: ({ row }) => {
|
||||
const agent = row.original
|
||||
const isBanned = agent.status === 'banned'
|
||||
|
||||
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' }, t('common.openMenu')),
|
||||
])),
|
||||
h(
|
||||
DropdownMenuContent,
|
||||
{ align: 'end' },
|
||||
() => [
|
||||
h(DropdownMenuItem, { onClick: () => actions.onEdit(agent) }, () => [
|
||||
h(Pencil, { class: 'mr-2 h-4 w-4' }),
|
||||
t('common.edit'),
|
||||
]),
|
||||
h(DropdownMenuItem, { onClick: () => actions.onToggleStatus(agent) }, () => [
|
||||
h(Ban, { class: 'mr-2 h-4 w-4' }),
|
||||
isBanned ? t('developer.agents.enable') : t('developer.agents.disable'),
|
||||
]),
|
||||
h(DropdownMenuSeparator),
|
||||
h(DropdownMenuItem, { class: 'text-destructive', onClick: () => actions.onDelete(agent) }, () => [
|
||||
h(Trash2, { class: 'mr-2 h-4 w-4' }),
|
||||
t('common.delete'),
|
||||
]),
|
||||
],
|
||||
),
|
||||
],
|
||||
},
|
||||
)
|
||||
},
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user