feat: 优化代理管理页面和代理后台页面
- 添加云端数据权限列到代理管理页面 - 重构代理后台用户管理、卡密管理、财务管理页面使用DataTable组件 - 添加统计卡片到代理后台各页面 - 修复agent-apps相关类型错误 - 添加代理后台页面i18n国际化支持 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import type { Composer } from 'vue-i18n'
|
||||
|
||||
import { ArrowDownLeft, ArrowUpRight, RotateCcw } from 'lucide-vue-next'
|
||||
import { h } from 'vue'
|
||||
|
||||
import type { Transaction } from '../data/schema'
|
||||
|
||||
import Badge from '@/components/ui/badge/Badge.vue'
|
||||
|
||||
export function getColumns(t: Composer['t']): ColumnDef<Transaction>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'type',
|
||||
header: () => t('agent.finance.columns.type'),
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue('type') as string
|
||||
const typeMap: Record<string, { label: string, variant: 'default' | 'secondary' | 'destructive', icon: any }> = {
|
||||
recharge: { label: t('agent.finance.types.recharge'), variant: 'default', icon: ArrowDownLeft },
|
||||
consume: { label: t('agent.finance.types.consume'), variant: 'secondary', icon: ArrowUpRight },
|
||||
refund: { label: t('agent.finance.types.refund'), variant: 'default', icon: RotateCcw },
|
||||
}
|
||||
const config = typeMap[type] || { label: type, variant: 'secondary', icon: ArrowUpRight }
|
||||
const iconClass = type === 'recharge' ? 'text-green-500' : type === 'refund' ? 'text-blue-500' : 'text-red-500'
|
||||
const bgClass = type === 'recharge' ? 'bg-green-500/10' : type === 'refund' ? 'bg-blue-500/10' : 'bg-red-500/10'
|
||||
|
||||
return h('div', { class: 'flex items-center gap-2' }, [
|
||||
h('div', { class: `size-8 rounded-lg flex items-center justify-center ${bgClass}` }, [
|
||||
h(config.icon, { class: `size-4 ${iconClass}` }),
|
||||
]),
|
||||
h('span', config.label),
|
||||
])
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: () => t('agent.finance.columns.description'),
|
||||
cell: ({ row }) => {
|
||||
const description = row.getValue('description') as string
|
||||
const type = row.getValue('type') as string
|
||||
return h('span', { class: 'text-muted-foreground' }, description || t(`agent.finance.types.${type}`) || '-')
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'amount',
|
||||
header: () => t('agent.finance.columns.amount'),
|
||||
cell: ({ row }) => {
|
||||
const type = row.getValue('type') as string
|
||||
const amount = row.getValue('amount') as number
|
||||
const prefix = type === 'recharge' || type === 'refund' ? '+' : '-'
|
||||
const textClass = type === 'recharge' || type === 'refund' ? 'text-green-500' : 'text-red-500'
|
||||
return h('span', { class: `font-semibold ${textClass}` }, `${prefix}¥${(amount || 0).toFixed(2)}`)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'balance',
|
||||
header: () => t('agent.finance.columns.balance'),
|
||||
cell: ({ row }) => {
|
||||
const balance = row.getValue('balance') as number
|
||||
return h('span', { class: 'text-muted-foreground' }, `¥${(balance || 0).toFixed(2)}`)
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: () => t('agent.finance.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 h('span', { class: 'text-muted-foreground whitespace-nowrap' }, date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}))
|
||||
}
|
||||
catch {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user