106 lines
2.7 KiB
TypeScript
106 lines
2.7 KiB
TypeScript
'use client'
|
|
|
|
import { useRef } from 'react'
|
|
import { useVirtualizer } from '@tanstack/react-virtual'
|
|
|
|
import { Level } from '@/types'
|
|
import { GRID_TEMPLATE, LevelRow } from './level-row'
|
|
|
|
interface LevelTableProps {
|
|
levels: Level[]
|
|
onEdit: (level: Level) => void
|
|
onDelete: (id: string) => void
|
|
}
|
|
|
|
const HEADER_COLUMNS = [
|
|
'序号',
|
|
'图片',
|
|
'答案',
|
|
'谐音梗',
|
|
'提示',
|
|
'创建时间',
|
|
'操作',
|
|
]
|
|
|
|
export function LevelTable({ levels, onEdit, onDelete }: LevelTableProps) {
|
|
const scrollRef = useRef<HTMLDivElement>(null)
|
|
|
|
const items = levels
|
|
|
|
const rowVirtualizer = useVirtualizer({
|
|
count: items.length,
|
|
getScrollElement: () => scrollRef.current,
|
|
estimateSize: () => 64,
|
|
overscan: 10,
|
|
})
|
|
|
|
if (items.length === 0) {
|
|
return (
|
|
<div className="text-center py-12 text-gray-500">
|
|
<p>暂无关卡数据</p>
|
|
<p className="text-sm mt-2">
|
|
点击上方“添加关卡”按钮创建第一个关卡
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
<div className="rounded-md border overflow-hidden bg-background">
|
|
{/* 表头 */}
|
|
<div
|
|
className="grid items-center gap-3 px-3 py-2 bg-muted/40 text-xs font-medium text-muted-foreground border-b"
|
|
style={{ gridTemplateColumns: GRID_TEMPLATE }}
|
|
>
|
|
{HEADER_COLUMNS.map((h, i) => (
|
|
<span key={i}>{h}</span>
|
|
))}
|
|
</div>
|
|
|
|
{/* 虚拟滚动 */}
|
|
<div
|
|
ref={scrollRef}
|
|
className="overflow-auto"
|
|
style={{ height: 'calc(100vh - 260px)' }}
|
|
>
|
|
<div
|
|
style={{
|
|
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
position: 'relative',
|
|
width: '100%',
|
|
}}
|
|
>
|
|
{rowVirtualizer.getVirtualItems().map((v) => {
|
|
const level = items[v.index]
|
|
return (
|
|
<div
|
|
key={level.id}
|
|
style={{
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
transform: `translateY(${v.start}px)`,
|
|
}}
|
|
>
|
|
<LevelRow
|
|
level={level}
|
|
index={v.index}
|
|
onEdit={onEdit}
|
|
onDelete={onDelete}
|
|
/>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="px-2 text-xs text-muted-foreground">
|
|
共 {items.length} 条 · 在编辑 / 创建弹窗中指定位置可调整顺序
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|