feat: 支持批量上传关卡
This commit is contained in:
156
components/levels/delete-confirm-dialog.tsx
Normal file
156
components/levels/delete-confirm-dialog.tsx
Normal file
@@ -0,0 +1,156 @@
|
||||
'use client'
|
||||
|
||||
import Image from 'next/image'
|
||||
import { AlertTriangle, Trash2 } from 'lucide-react'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { Spinner } from '@/components/ui/spinner'
|
||||
import { Level } from '@/types'
|
||||
|
||||
interface DeleteConfirmDialogProps {
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
level: Level | null
|
||||
/** 列表里的行号(0-based),用于展示 #序号 */
|
||||
index?: number
|
||||
isLoading?: boolean
|
||||
onConfirm: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* 关卡删除二次确认弹窗。
|
||||
* 展示关卡预览(双图 + 答案)让用户确认删除对象,而不是盲点。
|
||||
* - 确认按钮 autoFocus:Enter 直接确认,Esc 由 Radix Dialog 默认关闭
|
||||
* - 删除中禁用所有交互并显示 Spinner
|
||||
*/
|
||||
export function DeleteConfirmDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
level,
|
||||
index,
|
||||
isLoading = false,
|
||||
onConfirm,
|
||||
}: DeleteConfirmDialogProps) {
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={(next) => {
|
||||
// 删除进行中不允许关闭,避免中途点取消造成状态不一致
|
||||
if (isLoading && !next) return
|
||||
onOpenChange(next)
|
||||
}}
|
||||
>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader className="items-center text-center sm:items-center sm:text-center">
|
||||
{/* 红色警告图标 + 软光晕,视觉焦点 */}
|
||||
<div className="relative mx-auto mb-2 flex h-14 w-14 items-center justify-center">
|
||||
<div className="absolute inset-0 rounded-full bg-red-500/10" />
|
||||
<div className="absolute inset-1.5 rounded-full bg-red-500/15" />
|
||||
<AlertTriangle
|
||||
className="relative h-7 w-7 text-red-600"
|
||||
strokeWidth={2.25}
|
||||
/>
|
||||
</div>
|
||||
<DialogTitle className="text-base">确认删除此关卡?</DialogTitle>
|
||||
<DialogDescription>
|
||||
删除后将立即从小程序端下线,且
|
||||
<span className="font-medium text-red-600"> 无法恢复</span>
|
||||
。请确认无误。
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{/* 关卡预览卡片 */}
|
||||
{level && (
|
||||
<div className="rounded-md border border-dashed bg-muted/40 p-3">
|
||||
<div className="mb-2 flex items-center justify-between text-xs text-muted-foreground">
|
||||
<span>待删除关卡</span>
|
||||
{typeof index === 'number' && index >= 0 && (
|
||||
<span className="rounded bg-background px-1.5 py-0.5 font-mono text-[11px] tabular-nums">
|
||||
#{index + 1}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex flex-shrink-0 gap-1.5">
|
||||
<div className="relative h-14 w-14 overflow-hidden rounded-md bg-background ring-1 ring-border">
|
||||
{level.image1Url ? (
|
||||
<Image
|
||||
src={level.image1Url}
|
||||
alt="图片1"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="56px"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="relative h-14 w-14 overflow-hidden rounded-md bg-background ring-1 ring-border">
|
||||
{level.image2Url ? (
|
||||
<Image
|
||||
src={level.image2Url}
|
||||
alt="图片2"
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="56px"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-base font-semibold leading-tight">
|
||||
{level.answer}
|
||||
</div>
|
||||
{level.punchline ? (
|
||||
<div className="mt-1 truncate text-xs text-orange-600">
|
||||
{level.punchline}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-1 text-xs text-muted-foreground">
|
||||
(无谐音梗)
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<DialogFooter className="gap-2 sm:gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => onOpenChange(false)}
|
||||
disabled={isLoading}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
onClick={onConfirm}
|
||||
disabled={isLoading}
|
||||
autoFocus
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
删除中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
确认删除
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user