157 lines
4.3 KiB
TypeScript
157 lines
4.3 KiB
TypeScript
'use client'
|
|
|
|
import { ColumnDef } from '@tanstack/react-table'
|
|
import { Level } from '@/types'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Pencil, Trash2 } from 'lucide-react'
|
|
import Image from 'next/image'
|
|
|
|
interface ColumnCallbacks {
|
|
onEdit: (level: Level) => void
|
|
onDelete: (id: string) => void
|
|
deleteConfirmId: string | null
|
|
}
|
|
|
|
export function createColumns({
|
|
onEdit,
|
|
onDelete,
|
|
deleteConfirmId,
|
|
}: ColumnCallbacks): ColumnDef<Level>[] {
|
|
return [
|
|
{
|
|
accessorKey: 'sortOrder',
|
|
header: '序号',
|
|
cell: ({ row }) => (
|
|
<span className="text-muted-foreground">{row.original.sortOrder + 1}</span>
|
|
),
|
|
size: 60,
|
|
},
|
|
{
|
|
id: 'images',
|
|
header: '图片',
|
|
cell: ({ row }) => {
|
|
const { image1Url, image2Url } = row.original
|
|
return (
|
|
<div className="flex gap-1.5">
|
|
<div className="relative w-12 h-12 rounded overflow-hidden bg-gray-100 flex-shrink-0">
|
|
{image1Url ? (
|
|
<Image
|
|
src={image1Url}
|
|
alt="图片1"
|
|
fill
|
|
className="object-cover"
|
|
sizes="48px"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full flex items-center justify-center text-gray-400 text-[10px]">
|
|
无
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="relative w-12 h-12 rounded overflow-hidden bg-gray-100 flex-shrink-0">
|
|
{image2Url ? (
|
|
<Image
|
|
src={image2Url}
|
|
alt="图片2"
|
|
fill
|
|
className="object-cover"
|
|
sizes="48px"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full flex items-center justify-center text-gray-400 text-[10px]">
|
|
无
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
},
|
|
size: 120,
|
|
},
|
|
{
|
|
accessorKey: 'answer',
|
|
header: '答案',
|
|
cell: ({ row }) => (
|
|
<span className="font-medium">{row.original.answer}</span>
|
|
),
|
|
},
|
|
{
|
|
accessorKey: 'punchline',
|
|
header: '谐音梗',
|
|
cell: ({ row }) => {
|
|
const punchline = row.original.punchline
|
|
return punchline ? (
|
|
<span className="text-orange-600">{punchline}</span>
|
|
) : (
|
|
<span className="text-muted-foreground">—</span>
|
|
)
|
|
},
|
|
},
|
|
{
|
|
id: 'hints',
|
|
header: '提示',
|
|
cell: ({ row }) => {
|
|
const { hint1, hint2, hint3 } = row.original
|
|
const hints = [hint1, hint2, hint3].filter(Boolean)
|
|
return hints.length > 0 ? (
|
|
<span className="text-sm text-muted-foreground truncate max-w-[200px] block">
|
|
{hints.join('、')}
|
|
</span>
|
|
) : (
|
|
<span className="text-muted-foreground">—</span>
|
|
)
|
|
},
|
|
},
|
|
{
|
|
accessorKey: 'createdAt',
|
|
header: '创建时间',
|
|
cell: ({ row }) => {
|
|
const date = new Date(row.original.createdAt)
|
|
return (
|
|
<span className="text-sm text-muted-foreground whitespace-nowrap">
|
|
{date.toLocaleDateString('zh-CN', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
})}
|
|
</span>
|
|
)
|
|
},
|
|
size: 120,
|
|
},
|
|
{
|
|
id: 'actions',
|
|
header: '操作',
|
|
cell: ({ row }) => {
|
|
const level = row.original
|
|
const isConfirming = deleteConfirmId === level.id
|
|
return (
|
|
<div className="flex items-center gap-2">
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
className="h-8 w-8"
|
|
onClick={() => onEdit(level)}
|
|
>
|
|
<Pencil className="h-3.5 w-3.5" />
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
className={`h-8 w-8 ${
|
|
isConfirming
|
|
? 'bg-red-600 text-white hover:bg-red-700 border-red-600'
|
|
: 'text-red-600 hover:text-red-700 hover:bg-red-50'
|
|
}`}
|
|
onClick={() => onDelete(level.id)}
|
|
>
|
|
<Trash2 className="h-3.5 w-3.5" />
|
|
</Button>
|
|
</div>
|
|
)
|
|
},
|
|
size: 100,
|
|
},
|
|
]
|
|
}
|