import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useMutation, useQuery } from '@tanstack/react-query' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { useToast } from '@/components/ui/toast' import { useUploadStore } from '@/store/uploadStore' import { apiClient } from '@/services/api' import type { ExportRequest, ExportOptions } from '@/types/api' type ExportFormat = 'txt' | 'json' | 'excel' | 'markdown' | 'pdf' export default function ExportPage() { const { t } = useTranslation() const navigate = useNavigate() const { toast } = useToast() const { batchId } = useUploadStore() const [format, setFormat] = useState('txt') const [selectedRuleId, setSelectedRuleId] = useState() const [options, setOptions] = useState({ confidence_threshold: 0.5, include_metadata: true, filename_pattern: '{filename}_ocr', css_template: 'default', }) // Fetch export rules const { data: exportRules } = useQuery({ queryKey: ['exportRules'], queryFn: () => apiClient.getExportRules(), enabled: true, }) // Fetch CSS templates const { data: cssTemplates } = useQuery({ queryKey: ['cssTemplates'], queryFn: () => apiClient.getCSSTemplates(), enabled: format === 'pdf', }) // Export mutation const exportMutation = useMutation({ mutationFn: async (data: ExportRequest) => { const blob = await apiClient.exportResults(data) return { blob, format: data.format } }, onSuccess: ({ blob, format: exportFormat }) => { // Create download link const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url // Determine file extension const extensions: Record = { txt: 'txt', json: 'json', excel: 'xlsx', markdown: 'md', pdf: 'pdf', } a.download = `batch_${batchId}_export.${extensions[exportFormat]}` document.body.appendChild(a) a.click() window.URL.revokeObjectURL(url) document.body.removeChild(a) toast({ title: t('export.exportSuccess'), description: `已成功匯出為 ${exportFormat.toUpperCase()} 格式`, variant: 'success', }) }, onError: (error: any) => { toast({ title: t('export.exportError'), description: error.response?.data?.detail || t('errors.networkError'), variant: 'destructive', }) }, }) const handleExport = () => { if (!batchId) { toast({ title: t('errors.validationError'), description: '請先上傳並處理檔案', variant: 'destructive', }) return } const exportRequest: ExportRequest = { batch_id: batchId, format, rule_id: selectedRuleId, options, } exportMutation.mutate(exportRequest) } const handleFormatChange = (newFormat: ExportFormat) => { setFormat(newFormat) // Reset CSS template if switching away from PDF if (newFormat !== 'pdf') { setOptions((prev) => ({ ...prev, css_template: undefined })) } else { setOptions((prev) => ({ ...prev, css_template: 'default' })) } } const handleRuleChange = (ruleId: number | undefined) => { setSelectedRuleId(ruleId) if (ruleId && exportRules) { const rule = exportRules.find((r) => r.id === ruleId) if (rule && rule.config_json) { // Apply rule configuration setOptions((prev) => ({ ...prev, ...rule.config_json, css_template: rule.css_template || prev.css_template, })) } } } // Show helpful message when no batch is selected if (!batchId) { return (
{t('export.title')}

{t('export.noBatchMessage', { defaultValue: '尚未選擇任何批次。請先上傳並完成處理檔案。' })}

) } return (

{t('export.title')}

批次 ID: {batchId}

{/* Format Selection */} {t('export.format')}
{(['txt', 'json', 'excel', 'markdown', 'pdf'] as ExportFormat[]).map((fmt) => ( ))}
{/* Export Rules */} {exportRules && exportRules.length > 0 && ( {t('export.rules.title')}
)} {/* Export Options */} {t('export.options.title')} {/* Confidence Threshold */}
setOptions((prev) => ({ ...prev, confidence_threshold: Number(e.target.value), })) } className="w-full" />
0 0.5 1.0
{/* Include Metadata */}
setOptions((prev) => ({ ...prev, include_metadata: e.target.checked, })) } className="w-4 h-4 border border-gray-200 rounded" />
{/* Filename Pattern */}
setOptions((prev) => ({ ...prev, filename_pattern: e.target.value, })) } className="w-full px-3 py-2 border border-gray-200 rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary" placeholder="{filename}_ocr" />

可用變數: {'{filename}'}, {'{batch_id}'}, {'{date}'}

{/* CSS Template (PDF only) */} {format === 'pdf' && cssTemplates && cssTemplates.length > 0 && (
)}
{/* Export Button */}
) }