lty/qy-lty-admin/components/songs/export-batch-dialog.tsx
2026-03-17 13:17:02 +08:00

172 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react"
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Download } from "lucide-react"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
import { Label } from "@/components/ui/label"
import { exportBatchCards } from "@/lib/api/card"
import { useToast } from "@/components/ui/use-toast"
import { isAuthenticated } from "@/lib/api/auth"
interface ExportBatchDialogProps {
batchId: number
}
export function ExportBatchDialog({ batchId }: ExportBatchDialogProps) {
const [open, setOpen] = useState(false)
const [isExporting, setIsExporting] = useState(false)
const [format, setFormat] = useState<'xlsx' | 'csv'>('xlsx')
const { toast } = useToast()
const handleExport = async () => {
try {
// 检查登录状态
if (!isAuthenticated()) {
toast({
title: "未登录",
description: "请先登录后再进行操作",
variant: "destructive",
})
return
}
setIsExporting(true)
const data = await exportBatchCards(batchId, format)
// 创建下载链接
const link = document.createElement('a')
const fileExtension = format
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
const fileName = `batch-${batchId}-${timestamp}.${fileExtension}`
if (format === 'xlsx') {
// 处理二进制数据 (Excel)
const blob = new Blob([data as Blob], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
const url = URL.createObjectURL(blob)
link.href = url
link.download = fileName
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(url)
document.body.removeChild(link)
} else {
// 处理文本数据 (CSV)
const blob = new Blob([data as string], { type: 'text/csv;charset=utf-8;' })
const url = URL.createObjectURL(blob)
link.href = url
link.download = fileName
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(url)
document.body.removeChild(link)
}
toast({
title: "导出成功",
description: `批次 ${batchId} 已成功导出为 ${format.toUpperCase()} 格式`,
})
setOpen(false)
} catch (error) {
console.error("导出失败:", error)
// 处理不同类型的错误
let errorMessage = "无法导出批次,请稍后重试"
if (error instanceof Error) {
errorMessage = error.message
} else if (typeof error === 'object' && error !== null && 'response' in error) {
// Axios 错误
const axiosError = error as any
if (axiosError.response?.status === 401) {
errorMessage = "认证失败,请重新登录"
} else if (axiosError.response?.data?.message) {
errorMessage = axiosError.response.data.message
} else if (axiosError.response?.statusText) {
errorMessage = `请求失败: ${axiosError.response.statusText}`
}
}
toast({
title: "导出失败",
description: errorMessage,
variant: "destructive",
})
} finally {
setIsExporting(false)
}
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button
variant="ghost"
size="sm"
className="h-8 hover:bg-blue-50 hover:text-blue-600"
>
<Download className="h-4 w-4 mr-1" />
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription>
{batchId}
</DialogDescription>
</DialogHeader>
<div className="py-4">
<RadioGroup
value={format}
onValueChange={(value) => setFormat(value as 'xlsx' | 'csv')}
className="flex flex-col space-y-3"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="xlsx" id="xlsx" />
<Label htmlFor="xlsx" className="font-medium">Excel (XLSX)</Label>
<span className="text-xs text-gray-500 ml-1">- </span>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="csv" id="csv" />
<Label htmlFor="csv" className="font-medium">CSV</Label>
<span className="text-xs text-gray-500 ml-1">- </span>
</div>
</RadioGroup>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>
</Button>
<Button
onClick={handleExport}
className="bg-gradient-to-r from-blue-500 to-blue-600"
disabled={isExporting}
>
{isExporting ? (
<>
<div className="h-4 w-4 mr-2 animate-spin rounded-full border-2 border-current border-t-transparent" />
...
</>
) : (
<>
<Download className="h-4 w-4 mr-2" />
{format.toUpperCase()}
</>
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}