/** * PDF翻译助手前端脚本 */ // 当前翻译ID let currentTranslationId = null; let currentTaskId = null; // 上传表单处理 document.getElementById('uploadForm').addEventListener('submit', async function(e) { e.preventDefault(); const fileInput = document.getElementById('pdfFile'); const file = fileInput.files[0]; if (!file) { alert('请选择PDF文件'); return; } if (!file.name.toLowerCase().endsWith('.pdf')) { alert('只支持PDF文件'); return; } // 显示进度区域 document.getElementById('progressSection').style.display = 'block'; document.getElementById('resultSection').style.display = 'none'; document.getElementById('cacheNotice').style.display = 'none'; // 显示加载状态 const submitBtn = document.getElementById('submitBtn'); const btnText = document.getElementById('btnText'); const btnSpinner = document.getElementById('btnSpinner'); submitBtn.disabled = true; btnText.textContent = '上传中...'; btnSpinner.style.display = 'inline-block'; // 构建表单数据 const formData = new FormData(); formData.append('file', file); const instruction = document.getElementById('instruction')?.value; if (instruction) { formData.append('instruction', instruction); } try { // 上传文件 const response = await fetch('/api/upload', { method: 'POST', body: formData }); const result = await response.json(); if (!response.ok) { throw new Error(result.error || '上传失败'); } currentTranslationId = result.translation_id; currentTaskId = result.task_id; // 如果使用缓存,直接显示结果 if (result.from_cache) { document.getElementById('cacheNotice').style.display = 'block'; showResult(currentTranslationId); } else { // 开始轮询进度 pollProgress(currentTaskId, currentTranslationId); } } catch (error) { alert('上传失败: ' + error.message); resetUploadButton(); } }); // 轮询翻译进度 async function pollProgress(taskId, translationId) { const progressBar = document.getElementById('progressBar'); const progressMessage = document.getElementById('progressMessage'); const poll = async () => { try { // 同时检查任务状态和翻译状态 const taskResponse = await fetch(`/api/task/${taskId}`); const taskResult = await taskResponse.json(); const transResponse = await fetch(`/api/status/${translationId}`); const transResult = await transResponse.json(); // 更新进度 if (taskResult.progress) { progressBar.style.width = taskResult.progress + '%'; progressBar.textContent = taskResult.progress + '%'; } if (taskResult.message) { progressMessage.textContent = taskResult.message; } // 检查是否完成 if (taskResult.status === 'completed' || transResult.status === 'completed') { progressBar.style.width = '100%'; progressBar.textContent = '100%'; progressMessage.textContent = '翻译完成!'; // 显示结果 setTimeout(() => showResult(translationId), 500); return; } if (taskResult.status === 'failed') { progressMessage.textContent = '翻译失败: ' + (taskResult.error || '未知错误'); resetUploadButton(); return; } // 继续轮询 setTimeout(poll, 2000); } catch (error) { console.error('轮询失败:', error); setTimeout(poll, 3000); } }; poll(); } // 显示翻译结果 async function showResult(translationId) { const resultSection = document.getElementById('resultSection'); const resultContent = document.getElementById('resultContent'); try { const response = await fetch(`/api/result/${translationId}`); const result = await response.json(); if (!response.ok) { throw new Error(result.error || '获取结果失败'); } // 渲染Markdown内容 resultContent.innerHTML = renderMarkdown(result.content); resultSection.style.display = 'block'; resetUploadButton(); } catch (error) { alert('获取结果失败: ' + error.message); resetUploadButton(); } } // 重置上传按钮 function resetUploadButton() { const submitBtn = document.getElementById('submitBtn'); const btnText = document.getElementById('btnText'); const btnSpinner = document.getElementById('btnSpinner'); submitBtn.disabled = false; btnText.textContent = '开始翻译'; btnSpinner.style.display = 'none'; } // 下载结果 document.getElementById('downloadBtn')?.addEventListener('click', function() { if (currentTranslationId) { window.location.href = `/api/download/${currentTranslationId}`; } }); // 对比查看 document.getElementById('viewCompare')?.addEventListener('click', async function() { if (!currentTranslationId) return; try { const response = await fetch(`/api/compare/${currentTranslationId}`); const result = await response.json(); // 显示对比视图 showCompareView(result); } catch (error) { alert('获取对比失败: ' + error.message); } }); // 显示对比视图 function showCompareView(data) { const resultContent = document.getElementById('resultContent'); resultContent.innerHTML = `
原文
${escapeHtml(data.original)}
译文
${renderMarkdown(data.translated)}
`; } // 重新翻译 document.getElementById('retranslateBtn')?.addEventListener('click', async function() { if (!currentTranslationId) return; const instruction = document.getElementById('retranslateInstruction').value; if (!instruction.trim()) { alert('请输入翻译要求'); return; } try { const response = await fetch(`/api/retranslate/${currentTranslationId}`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({instruction: instruction}) }); const result = await response.json(); if (!response.ok) { throw new Error(result.error || '重译请求失败'); } // 开始新的翻译任务 currentTranslationId = result.translation_id; document.getElementById('progressSection').style.display = 'block'; document.getElementById('resultSection').style.display = 'none'; pollProgress(null, currentTranslationId); } catch (error) { alert('重译失败: ' + error.message); } }); // 简单Markdown渲染 function renderMarkdown(text) { // 标题 text = text.replace(/^## (.*)$/gm, '

$1

'); text = text.replace(/^# (.*)$/gm, '

$1

'); // 分隔线 text = text.replace(/^---$/gm, '
'); // 引用 text = text.replace(/^> (.*)$/gm, '
$1
'); // 段落 text = text.replace(/\n\n/g, '

'); text = '

' + text + '

'; return text; } // HTML转义 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 检查用户登录状态 async function checkUserStatus() { try { const response = await fetch('/api/user/info'); const result = await response.json(); if (result.user) { console.log('用户已登录:', result.user.username); } } catch (error) { console.error('检查用户状态失败:', error); } } // 页面加载时检查状态 document.addEventListener('DOMContentLoaded', checkUserStatus);