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): 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[] { 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 = { 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, }, ] }