添加图标
This commit is contained in:
@@ -3,8 +3,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>DocuTranslate - 交互式文档翻译</title>
|
||||
|
||||
<title>DocuTranslate - 交互式文档翻译</title>
|
||||
<link rel="icon" href="/static/favicon.ico" type="image/x-icon">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="/static/bootstrap.css" rel="stylesheet" crossorigin="anonymous">
|
||||
<!-- Bootstrap Icons -->
|
||||
@@ -60,17 +61,21 @@
|
||||
transition: all 0.2s ease-in-out;
|
||||
background-color: var(--bs-body-bg);
|
||||
}
|
||||
|
||||
.file-drop-area.drag-over {
|
||||
border-color: var(--bs-primary);
|
||||
background-color: var(--bs-secondary-bg);
|
||||
}
|
||||
|
||||
.file-drop-area.file-selected {
|
||||
border-style: solid;
|
||||
border-color: var(--bs-success);
|
||||
}
|
||||
|
||||
.file-drop-area.input-error {
|
||||
border-color: var(--bs-danger);
|
||||
}
|
||||
|
||||
.file-name-display.input-error-text {
|
||||
color: var(--bs-danger);
|
||||
font-weight: bold;
|
||||
@@ -85,6 +90,7 @@
|
||||
#previewModal .modal-dialog {
|
||||
max-width: 95vw;
|
||||
}
|
||||
|
||||
#previewModal .modal-body {
|
||||
height: 80vh;
|
||||
}
|
||||
@@ -95,6 +101,7 @@
|
||||
border: 1px solid var(--bs-border-color);
|
||||
border-radius: .375rem;
|
||||
}
|
||||
|
||||
.preview-pane iframe, .preview-pane pre {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -119,7 +126,7 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container-fluid main-container">
|
||||
<div class="container-fluid main-container">
|
||||
<div class="row gx-4">
|
||||
<!-- Left: Settings Panel -->
|
||||
<div class="col-lg-4">
|
||||
@@ -135,7 +142,8 @@
|
||||
<!-- Parsing Engine Settings -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
|
||||
<strong><i class="bi bi-file-earmark-binary me-2"></i>解析配置</strong>
|
||||
</button>
|
||||
</h2>
|
||||
@@ -151,9 +159,11 @@
|
||||
<div class="mb-3" id="mineruTokenGroup">
|
||||
<label for="mineru_token" class="form-label">
|
||||
Mineru Token
|
||||
<a href="https://mineru.net/apiManage/token" target="_blank" class="ms-1" title="获取Mineru Token"><i class="bi bi-box-arrow-up-right"></i></a>
|
||||
<a href="https://mineru.net/apiManage/token" target="_blank" class="ms-1"
|
||||
title="获取Mineru Token"><i class="bi bi-box-arrow-up-right"></i></a>
|
||||
</label>
|
||||
<input type="password" class="form-control" id="mineru_token" name="mineru_token" placeholder="使用Mineru引擎时需要">
|
||||
<input type="password" class="form-control" id="mineru_token"
|
||||
name="mineru_token" placeholder="使用Mineru引擎时需要">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -162,7 +172,8 @@
|
||||
<!-- AI Settings -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<strong><i class="bi bi-robot me-2"></i>翻译模型</strong>
|
||||
</button>
|
||||
</h2>
|
||||
@@ -175,7 +186,9 @@
|
||||
<option value="https://api.openai.com/v1">OpenAI</option>
|
||||
<option value="https://open.bigmodel.cn/api/paas/v4">智谱AI</option>
|
||||
<option value="https://api.deepseek.com/v1">DeepSeek</option>
|
||||
<option value="https://dashscope.aliyuncs.com/compatible-mode/v1">阿里云百炼</option>
|
||||
<option value="https://dashscope.aliyuncs.com/compatible-mode/v1">
|
||||
阿里云百炼
|
||||
</option>
|
||||
<option value="https://www.dmxapi.cn/v1">DMXAPI</option>
|
||||
<option value="https://openrouter.ai/api/v1">OpenRouter</option>
|
||||
<option value="https://ark.cn-beijing.volces.com/api/v3">火山引擎</option>
|
||||
@@ -189,13 +202,16 @@
|
||||
<div class="mb-3">
|
||||
<label for="apikey" class="form-label">
|
||||
API Key
|
||||
<a href="#" target="_blank" class="ms-1" id="api_href" title="获取API Key"><i class="bi bi-box-arrow-up-right"></i></a>
|
||||
<a href="#" target="_blank" class="ms-1" id="api_href"
|
||||
title="获取API Key"><i class="bi bi-box-arrow-up-right"></i></a>
|
||||
</label>
|
||||
<input type="password" class="form-control" id="apikey" name="apikey" required placeholder="请输入您的API Key">
|
||||
<input type="password" class="form-control" id="apikey" name="apikey" required
|
||||
placeholder="请输入您的API Key">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="model_id" class="form-label">模型 ID</label>
|
||||
<input type="text" class="form-control" id="model_id" name="model_id" required placeholder="例如: gpt-4o, glm-4">
|
||||
<input type="text" class="form-control" id="model_id" name="model_id" required
|
||||
placeholder="例如: gpt-4o, glm-4">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -204,7 +220,9 @@
|
||||
<!-- Translation Settings -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingThree">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseThree" aria-expanded="false"
|
||||
aria-controls="collapseThree">
|
||||
<strong><i class="bi bi-translate me-2"></i>翻译配置</strong>
|
||||
</button>
|
||||
</h2>
|
||||
@@ -221,19 +239,26 @@
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="custom_prompt_translate" class="form-label">自定义Prompt</label>
|
||||
<textarea class="form-control" id="custom_prompt_translate" name="custom_prompt_translate" rows="3" placeholder="可选,如“人名保持原文不翻译”"></textarea>
|
||||
<textarea class="form-control" id="custom_prompt_translate"
|
||||
name="custom_prompt_translate" rows="3"
|
||||
placeholder="可选,如“人名保持原文不翻译”"></textarea>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="formula_ocr" name="formula_ocr" checked>
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="formula_ocr"
|
||||
name="formula_ocr" checked>
|
||||
<label class="form-check-label" for="formula_ocr">公式识别</label>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="code_ocr" name="code_ocr" checked>
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="code_ocr"
|
||||
name="code_ocr" checked>
|
||||
<label class="form-check-label" for="code_ocr">代码识别</label>
|
||||
</div>
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="refine_markdown" name="refine_markdown">
|
||||
<label class="form-check-label" for="refine_markdown">Markdown修复<span class="d-inline-block" tabindex="0" data-bs-toggle="tooltip" title="使用ai对解析后的文本先修复再翻译,现不推荐开启">
|
||||
<input class="form-check-input" type="checkbox" role="switch"
|
||||
id="refine_markdown" name="refine_markdown">
|
||||
<label class="form-check-label" for="refine_markdown">Markdown修复<span
|
||||
class="d-inline-block" tabindex="0" data-bs-toggle="tooltip"
|
||||
title="使用ai对解析后的文本先修复再翻译,现不推荐开启">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</span></label>
|
||||
|
||||
@@ -245,32 +270,49 @@
|
||||
<!-- Other Settings -->
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingFour">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFour" aria-expanded="false" aria-controls="collapseFour">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseFour" aria-expanded="false"
|
||||
aria-controls="collapseFour">
|
||||
<strong><i class="bi bi-sliders me-2"></i>高级参数</strong>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseFour" class="accordion-collapse collapse" aria-labelledby="headingFour">
|
||||
<div class="accordion-body">
|
||||
<div class="mb-3">
|
||||
<label for="chunk-size-slider" class="form-label d-flex justify-content-between">
|
||||
<label for="chunk-size-slider"
|
||||
class="form-label d-flex justify-content-between">
|
||||
<span>分块大小: <span id="chunk-size-display"></span></span>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1 slider-reset-btn" id="chunk-size-reset">重置</button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-secondary py-0 px-1 slider-reset-btn"
|
||||
id="chunk-size-reset">重置
|
||||
</button>
|
||||
</label>
|
||||
<input type="range" class="form-range" min="1000" max="6000" step="100" id="chunk-size-slider" name="chunk_size">
|
||||
<input type="range" class="form-range" min="1000" max="6000" step="100"
|
||||
id="chunk-size-slider" name="chunk_size">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="concurrent-slider" class="form-label d-flex justify-content-between">
|
||||
<label for="concurrent-slider"
|
||||
class="form-label d-flex justify-content-between">
|
||||
<span>并发数: <span id="concurrent-display"></span></span>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1 slider-reset-btn" id="concurrent-reset">重置</button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-secondary py-0 px-1 slider-reset-btn"
|
||||
id="concurrent-reset">重置
|
||||
</button>
|
||||
</label>
|
||||
<input type="range" class="form-range" min="1" max="60" step="1" id="concurrent-slider" name="concurrent">
|
||||
<input type="range" class="form-range" min="1" max="60" step="1"
|
||||
id="concurrent-slider" name="concurrent">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="temperature-slider" class="form-label d-flex justify-content-between">
|
||||
<label for="temperature-slider"
|
||||
class="form-label d-flex justify-content-between">
|
||||
<span>Temperature: <span id="temperature-display"></span></span>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary py-0 px-1 slider-reset-btn" id="temperature-reset">重置</button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-secondary py-0 px-1 slider-reset-btn"
|
||||
id="temperature-reset">重置
|
||||
</button>
|
||||
</label>
|
||||
<input type="range" class="form-range" min="0" max="2" step="0.1" id="temperature-slider" name="temperature">
|
||||
<input type="range" class="form-range" min="0" max="2" step="0.1"
|
||||
id="temperature-slider" name="temperature">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -297,7 +339,8 @@
|
||||
<div class="task-area" id="task-area-container">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4 class="mb-0"><i class="bi bi-list-task me-2"></i>任务列表</h4>
|
||||
<button class="btn btn-primary" id="addNewTaskBtn"><i class="bi bi-plus-circle-fill me-2"></i>新建任务</button>
|
||||
<button class="btn btn-primary" id="addNewTaskBtn"><i class="bi bi-plus-circle-fill me-2"></i>新建任务
|
||||
</button>
|
||||
</div>
|
||||
<div id="task-container">
|
||||
<!-- Task cards will be injected here -->
|
||||
@@ -309,10 +352,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Task Card Template -->
|
||||
<template id="taskCardTemplate">
|
||||
<!-- Task Card Template -->
|
||||
<template id="taskCardTemplate">
|
||||
<div class="card mb-3 task-card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span class="fw-bold">任务 ID: <code class="task-id-display"></code></span>
|
||||
@@ -336,7 +379,8 @@
|
||||
<span class="status-message small text-muted">等待上传文件...</span>
|
||||
</div>
|
||||
<div class="progress mt-1" role="progressbar" style="height: 5px; display: none;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 100%"></div>
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
style="width: 100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -345,32 +389,40 @@
|
||||
<div class="card-footer d-flex justify-content-between align-items-center">
|
||||
<div class="download-buttons" style="display: none;">
|
||||
<button class="btn btn-sm btn-success preview-html-btn"><i class="bi bi-eye-fill me-1"></i>预览</button>
|
||||
<button class="btn btn-sm btn-info download-pdf-btn"><i class="bi bi-file-earmark-pdf-fill me-1"></i>下载 PDF</button>
|
||||
<button class="btn btn-sm btn-info download-pdf-btn"><i class="bi bi-file-earmark-pdf-fill me-1"></i>下载
|
||||
PDF
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<button type="button" class="btn btn-sm btn-secondary dropdown-toggle" data-bs-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<i class="bi bi-download me-1"></i>下载其他格式
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item download-html-link" href="#"><i class="bi bi-filetype-html me-2"></i>HTML</a></li>
|
||||
<li><a class="dropdown-item download-markdown-link" href="#"><i class="bi bi-markdown-fill me-2"></i>Markdown(嵌图)</a></li>
|
||||
<li><a class="dropdown-item download-markdown-zip-link" href="#"><i class="bi bi-file-zip-fill me-2"></i>Markdown压缩包</a></li>
|
||||
<li><a class="dropdown-item download-html-link" href="#"><i
|
||||
class="bi bi-filetype-html me-2"></i>HTML</a></li>
|
||||
<li><a class="dropdown-item download-markdown-link" href="#"><i
|
||||
class="bi bi-markdown-fill me-2"></i>Markdown(嵌图)</a></li>
|
||||
<li><a class="dropdown-item download-markdown-zip-link" href="#"><i
|
||||
class="bi bi-file-zip-fill me-2"></i>Markdown压缩包</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary start-translate-btn ms-auto"><i class="bi bi-play-fill me-1"></i>开始翻译</button>
|
||||
<button class="btn btn-primary start-translate-btn ms-auto"><i class="bi bi-play-fill me-1"></i>开始翻译
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- Preview Modal -->
|
||||
<div class="modal fade" id="previewModal" tabindex="-1" aria-labelledby="previewModalTitle" aria-hidden="true">
|
||||
<!-- Preview Modal -->
|
||||
<div class="modal fade" id="previewModal" tabindex="-1" aria-labelledby="previewModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-fullscreen-xl-down">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="previewModalTitle">双语预览</h5>
|
||||
<div class="btn-group me-auto ms-4" role="group">
|
||||
<button type="button" class="btn btn-sm btn-primary" id="setBilingualViewBtn">双语</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" id="setTranslatedOnlyViewBtn">仅译文</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" id="setTranslatedOnlyViewBtn">仅译文
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
@@ -390,31 +442,46 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-primary" id="printFromPreview"><i class="bi bi-printer-fill me-2"></i>打印/保存为PDF</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" id="printFromPreview"><i
|
||||
class="bi bi-printer-fill me-2"></i>打印/保存为PDF
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hidden iframe for direct PDF printing -->
|
||||
<iframe id="printFrame" style="display: none;"></iframe>
|
||||
<!-- Hidden iframe for direct PDF printing -->
|
||||
<iframe id="printFrame" style="display: none;"></iframe>
|
||||
|
||||
<!-- Theme Switcher -->
|
||||
<div class="dropdown theme-switch">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="theme-switcher" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<!-- Theme Switcher -->
|
||||
<div class="dropdown theme-switch">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="theme-switcher" data-bs-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<i class="bi bi-circle-half"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="theme-switcher">
|
||||
<li><button class="dropdown-item" type="button" data-bs-theme-value="light"><i class="bi bi-sun-fill me-2"></i> Light</button></li>
|
||||
<li><button class="dropdown-item" type="button" data-bs-theme-value="dark"><i class="bi bi-moon-stars-fill me-2"></i> Dark</button></li>
|
||||
<li><button class="dropdown-item active" type="button" data-bs-theme-value="auto"><i class="bi bi-circle-half me-2"></i> Auto</button></li>
|
||||
<li>
|
||||
<button class="dropdown-item" type="button" data-bs-theme-value="light"><i class="bi bi-sun-fill me-2"></i>
|
||||
Light
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="dropdown-item" type="button" data-bs-theme-value="dark"><i
|
||||
class="bi bi-moon-stars-fill me-2"></i> Dark
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="dropdown-item active" type="button" data-bs-theme-value="auto"><i
|
||||
class="bi bi-circle-half me-2"></i> Auto
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="/static/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="/static/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
|
||||
<script type="module">
|
||||
<script type="module">
|
||||
|
||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
||||
@@ -481,8 +548,21 @@
|
||||
|
||||
// --- Utility Functions ---
|
||||
const generateTaskId = () => Math.random().toString(36).substring(2, 10);
|
||||
const saveToStorage = (key, value) => { try { localStorage.setItem(key, value); } catch (e) { console.warn("Save to storage failed:", e); } };
|
||||
const getFromStorage = (key, defaultValue = '') => { try { return localStorage.getItem(key) || defaultValue; } catch (e) { console.warn("Read from storage failed:", e); return defaultValue; } };
|
||||
const saveToStorage = (key, value) => {
|
||||
try {
|
||||
localStorage.setItem(key, value);
|
||||
} catch (e) {
|
||||
console.warn("Save to storage failed:", e);
|
||||
}
|
||||
};
|
||||
const getFromStorage = (key, defaultValue = '') => {
|
||||
try {
|
||||
return localStorage.getItem(key) || defaultValue;
|
||||
} catch (e) {
|
||||
console.warn("Read from storage failed:", e);
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
function fileToBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -629,7 +709,7 @@
|
||||
}
|
||||
|
||||
function addEventListenersToCard(taskId) {
|
||||
const { elements, state } = tasks[taskId];
|
||||
const {elements, state} = tasks[taskId];
|
||||
|
||||
elements.removeBtn.addEventListener('click', () => removeTask(taskId));
|
||||
|
||||
@@ -666,7 +746,7 @@
|
||||
}
|
||||
|
||||
function handleFileSelect(taskId) {
|
||||
const { elements, state } = tasks[taskId];
|
||||
const {elements, state} = tasks[taskId];
|
||||
const file = elements.fileInput.files[0];
|
||||
if (file) {
|
||||
state.file = file;
|
||||
@@ -681,7 +761,7 @@
|
||||
|
||||
// --- Core Translation Logic ---
|
||||
async function startTranslation(taskId) {
|
||||
const { elements, state } = tasks[taskId];
|
||||
const {elements, state} = tasks[taskId];
|
||||
|
||||
// --- Validation ---
|
||||
if (!state.file) {
|
||||
@@ -744,7 +824,7 @@
|
||||
|
||||
const response = await fetch('/service/translate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
const result = await response.json();
|
||||
@@ -772,12 +852,12 @@
|
||||
}
|
||||
|
||||
async function cancelTranslation(taskId) {
|
||||
const { elements } = tasks[taskId];
|
||||
const {elements} = tasks[taskId];
|
||||
elements.startBtn.disabled = true;
|
||||
elements.startBtn.innerHTML = `<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 正在取消...`;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/service/cancel/${taskId}`, { method: 'POST' });
|
||||
const response = await fetch(`/service/cancel/${taskId}`, {method: 'POST'});
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok && result.cancelled) {
|
||||
@@ -797,7 +877,7 @@
|
||||
// --- Polling ---
|
||||
function startPolling(taskId) {
|
||||
stopPolling(taskId);
|
||||
const { intervals } = tasks[taskId];
|
||||
const {intervals} = tasks[taskId];
|
||||
intervals.log = setInterval(() => pollLogs(taskId), 2000);
|
||||
intervals.status = setInterval(() => pollStatus(taskId), 1500);
|
||||
pollLogs(taskId);
|
||||
@@ -805,7 +885,7 @@
|
||||
}
|
||||
|
||||
function stopPolling(taskId) {
|
||||
const { intervals } = tasks[taskId];
|
||||
const {intervals} = tasks[taskId];
|
||||
if (intervals.log) clearInterval(intervals.log);
|
||||
if (intervals.status) clearInterval(intervals.status);
|
||||
intervals.log = null;
|
||||
@@ -813,7 +893,7 @@
|
||||
}
|
||||
|
||||
async function pollLogs(taskId) {
|
||||
const { elements } = tasks[taskId];
|
||||
const {elements} = tasks[taskId];
|
||||
try {
|
||||
const response = await fetch(`/service/logs/${taskId}`);
|
||||
if (!response.ok) return;
|
||||
@@ -828,7 +908,7 @@
|
||||
}
|
||||
|
||||
async function pollStatus(taskId, isRestore = false) {
|
||||
const { elements, state } = tasks[taskId];
|
||||
const {elements, state} = tasks[taskId];
|
||||
try {
|
||||
const response = await fetch(`/service/status/${taskId}`);
|
||||
if (!response.ok) {
|
||||
@@ -887,7 +967,7 @@
|
||||
|
||||
// --- Download and Preview ---
|
||||
function setupPreview(taskId) {
|
||||
const { state } = tasks[taskId];
|
||||
const {state} = tasks[taskId];
|
||||
if (!state.htmlUrl) return;
|
||||
|
||||
// Clear previous content
|
||||
@@ -941,12 +1021,14 @@
|
||||
try {
|
||||
translatedPreviewFrame.contentWindow.focus();
|
||||
translatedPreviewFrame.contentWindow.print();
|
||||
} catch(e) { alert('打印失败,请使用浏览器打印功能。'); }
|
||||
} catch (e) {
|
||||
alert('打印失败,请使用浏览器打印功能。');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function downloadPdf(taskId) {
|
||||
const { elements, state } = tasks[taskId];
|
||||
const {elements, state} = tasks[taskId];
|
||||
if (!state.htmlUrl) return;
|
||||
|
||||
elements.pdfBtn.disabled = true;
|
||||
@@ -1075,7 +1157,9 @@
|
||||
platformSelect.addEventListener('change', updatePlatformUI);
|
||||
apikeyInput.addEventListener('input', e => saveToStorage(`translator_platform_${platformSelect.value}_apikey`, e.target.value));
|
||||
modelInput.addEventListener('input', e => saveToStorage(`translator_platform_${platformSelect.value}_model_id`, e.target.value));
|
||||
baseUrlInput.addEventListener('input', e => { if (platformSelect.value === 'custom') saveToStorage('translator_platform_custom_base_url', e.target.value); });
|
||||
baseUrlInput.addEventListener('input', e => {
|
||||
if (platformSelect.value === 'custom') saveToStorage('translator_platform_custom_base_url', e.target.value);
|
||||
});
|
||||
convertEnginSelect.addEventListener('change', updateConvertEnginUI);
|
||||
mineruTokenInput.addEventListener('input', e => saveToStorage('translator_mineru_token', e.target.value));
|
||||
toLangSelect.addEventListener('change', e => saveToStorage('translator_to_lang', e.target.value));
|
||||
@@ -1148,6 +1232,6 @@
|
||||
|
||||
// --- Start the application ---
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user