feat: unify Direct Track PDF rendering and simplify export options
Backend changes: - Apply background image + invisible text layer to all Direct Track PDFs - Add CHART to regions_to_avoid for text extraction - Improve visual fidelity for native PDFs and Office documents Frontend changes: - Remove JSON, UnifiedDocument, Markdown download buttons - Simplify to 2-column layout with only Layout PDF and Reflow PDF - Remove translation JSON download and Layout PDF option - Keep only Reflow PDF for translated document downloads - Clean up unused imports (FileJson, Database, FileOutput) Archives two OpenSpec proposals: - unify-direct-track-pdf-rendering - simplify-frontend-export-options 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,6 @@ import {
|
||||
AlertCircle,
|
||||
Clock,
|
||||
Layers,
|
||||
FileJson,
|
||||
Loader2,
|
||||
ArrowLeft,
|
||||
RefreshCw,
|
||||
@@ -22,12 +21,10 @@ import {
|
||||
Table2,
|
||||
Image,
|
||||
BarChart3,
|
||||
Database,
|
||||
Languages,
|
||||
Globe,
|
||||
CheckCircle,
|
||||
Trash2,
|
||||
FileOutput
|
||||
Trash2
|
||||
} from 'lucide-react'
|
||||
import type { ProcessingTrack, TranslationStatus, TranslationListItem } from '@/types/apiV2'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
@@ -224,60 +221,6 @@ export default function TaskDetailPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownloadMarkdown = async () => {
|
||||
if (!taskId) return
|
||||
try {
|
||||
await apiClientV2.downloadMarkdown(taskId)
|
||||
toast({
|
||||
title: t('export.exportSuccess'),
|
||||
description: 'Markdown 已下載',
|
||||
variant: 'success',
|
||||
})
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: t('export.exportError'),
|
||||
description: error.response?.data?.detail || t('errors.networkError'),
|
||||
variant: 'destructive',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownloadJSON = async () => {
|
||||
if (!taskId) return
|
||||
try {
|
||||
await apiClientV2.downloadJSON(taskId)
|
||||
toast({
|
||||
title: t('export.exportSuccess'),
|
||||
description: 'JSON 已下載',
|
||||
variant: 'success',
|
||||
})
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: t('export.exportError'),
|
||||
description: error.response?.data?.detail || t('errors.networkError'),
|
||||
variant: 'destructive',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownloadUnified = async () => {
|
||||
if (!taskId) return
|
||||
try {
|
||||
await apiClientV2.downloadUnified(taskId)
|
||||
toast({
|
||||
title: t('export.exportSuccess'),
|
||||
description: 'UnifiedDocument JSON 已下載',
|
||||
variant: 'success',
|
||||
})
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: t('export.exportError'),
|
||||
description: error.response?.data?.detail || t('errors.networkError'),
|
||||
variant: 'destructive',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleStartTranslation = async () => {
|
||||
if (!taskId || isTranslating) return
|
||||
|
||||
@@ -319,24 +262,6 @@ export default function TaskDetailPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownloadTranslation = async (lang: string) => {
|
||||
if (!taskId) return
|
||||
try {
|
||||
await apiClientV2.downloadTranslation(taskId, lang)
|
||||
toast({
|
||||
title: '下載成功',
|
||||
description: `翻譯結果 (${lang}) 已下載`,
|
||||
variant: 'success',
|
||||
})
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: '下載失敗',
|
||||
description: error.response?.data?.detail || t('errors.networkError'),
|
||||
variant: 'destructive',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteTranslation = async (lang: string) => {
|
||||
if (!taskId) return
|
||||
try {
|
||||
@@ -542,19 +467,7 @@ export default function TaskDetailPage() {
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-3">
|
||||
<Button onClick={handleDownloadJSON} variant="outline" className="gap-2 h-20 flex-col">
|
||||
<FileJson className="w-8 h-8" />
|
||||
<span>JSON</span>
|
||||
</Button>
|
||||
<Button onClick={handleDownloadUnified} variant="outline" className="gap-2 h-20 flex-col">
|
||||
<Database className="w-8 h-8" />
|
||||
<span>統一格式</span>
|
||||
</Button>
|
||||
<Button onClick={handleDownloadMarkdown} variant="outline" className="gap-2 h-20 flex-col">
|
||||
<FileText className="w-8 h-8" />
|
||||
<span>Markdown</span>
|
||||
</Button>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<Button onClick={handleDownloadLayoutPDF} className="gap-2 h-20 flex-col">
|
||||
<Download className="w-8 h-8" />
|
||||
<span>版面 PDF</span>
|
||||
@@ -650,28 +563,12 @@ export default function TaskDetailPage() {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleDownloadTranslation(item.target_lang)}
|
||||
onClick={() => handleDownloadTranslatedPdf(item.target_lang, 'reflow')}
|
||||
className="gap-1"
|
||||
>
|
||||
<Download className="w-3 h-3" />
|
||||
JSON
|
||||
流式 PDF
|
||||
</Button>
|
||||
<Select
|
||||
onValueChange={(format: 'layout' | 'reflow') =>
|
||||
handleDownloadTranslatedPdf(item.target_lang, format)
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-[100px] h-8">
|
||||
<div className="flex items-center gap-1">
|
||||
<FileOutput className="w-3 h-3" />
|
||||
<span className="text-xs">PDF</span>
|
||||
</div>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="layout">版面 PDF</SelectItem>
|
||||
<SelectItem value="reflow">流式 PDF</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user