feat: 支持批量上传关卡

This commit is contained in:
richarjiang
2026-05-01 08:44:56 +08:00
parent f3f27def2b
commit 66a9ee2950
27 changed files with 5262 additions and 515 deletions

View File

@@ -6,16 +6,19 @@ import { Button } from '@/components/ui/button'
import { Header } from '@/components/layout/header'
import { LevelTable } from '@/components/levels/level-table'
import { LevelDialog } from '@/components/levels/level-dialog'
import { BatchImportDialog } from '@/components/levels/batch-import-dialog'
import { DeleteConfirmDialog } from '@/components/levels/delete-confirm-dialog'
import { Spinner } from '@/components/ui/spinner'
import { Level, LevelFormData } from '@/types'
import { Plus } from 'lucide-react'
import { Plus, Upload } from 'lucide-react'
import { apiFetch } from '@/lib/api'
export default function LevelsPage() {
const queryClient = useQueryClient()
const [isDialogOpen, setIsDialogOpen] = useState(false)
const [isBatchOpen, setIsBatchOpen] = useState(false)
const [editingLevel, setEditingLevel] = useState<Level | null>(null)
const [deleteConfirmId, setDeleteConfirmId] = useState<string | null>(null)
const [deletingLevel, setDeletingLevel] = useState<Level | null>(null)
// Fetch levels
const { data: levels, isLoading, error } = useQuery<Level[]>({
@@ -79,7 +82,7 @@ export default function LevelsPage() {
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['levels'] })
setDeleteConfirmId(null)
setDeletingLevel(null)
},
})
@@ -94,13 +97,8 @@ export default function LevelsPage() {
}
const handleDelete = (id: string) => {
if (deleteConfirmId === id) {
deleteMutation.mutate(id)
} else {
setDeleteConfirmId(id)
// Reset after 3 seconds
setTimeout(() => setDeleteConfirmId(null), 3000)
}
const target = (levels || []).find((l) => l.id === id)
if (target) setDeletingLevel(target)
}
const handleSubmit = async (data: LevelFormData) => {
@@ -147,17 +145,22 @@ export default function LevelsPage() {
{levels?.length || 0}
</p>
</div>
<Button onClick={handleOpenCreate}>
<Plus className="h-4 w-4 mr-2" />
</Button>
<div className="flex items-center gap-2">
<Button variant="outline" onClick={() => setIsBatchOpen(true)}>
<Upload className="h-4 w-4 mr-2" />
</Button>
<Button onClick={handleOpenCreate}>
<Plus className="h-4 w-4 mr-2" />
</Button>
</div>
</div>
<LevelTable
levels={levels || []}
onEdit={handleOpenEdit}
onDelete={handleDelete}
deleteConfirmId={deleteConfirmId}
/>
</div>
</div>
@@ -166,8 +169,39 @@ export default function LevelsPage() {
open={isDialogOpen}
onOpenChange={setIsDialogOpen}
level={editingLevel}
totalCount={levels?.length || 0}
currentIndex={
editingLevel
? (levels || []).findIndex((l) => l.id === editingLevel.id)
: null
}
onSubmit={handleSubmit}
/>
<BatchImportDialog
open={isBatchOpen}
onOpenChange={setIsBatchOpen}
onSuccess={() =>
queryClient.invalidateQueries({ queryKey: ['levels'] })
}
/>
<DeleteConfirmDialog
open={!!deletingLevel}
onOpenChange={(next) => {
if (!next) setDeletingLevel(null)
}}
level={deletingLevel}
index={
deletingLevel
? (levels || []).findIndex((l) => l.id === deletingLevel.id)
: undefined
}
isLoading={deleteMutation.isPending}
onConfirm={() => {
if (deletingLevel) deleteMutation.mutate(deletingLevel.id)
}}
/>
</div>
)
}