前端区分任务是否提交
This commit is contained in:
@@ -481,7 +481,7 @@
|
|||||||
<!-- Bootstrap JS -->
|
<!-- Bootstrap JS -->
|
||||||
<script src="/static/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
<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 tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||||
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
||||||
@@ -548,21 +548,8 @@
|
|||||||
|
|
||||||
// --- Utility Functions ---
|
// --- Utility Functions ---
|
||||||
const generateTaskId = () => Math.random().toString(36).substring(2, 10);
|
const generateTaskId = () => Math.random().toString(36).substring(2, 10);
|
||||||
const saveToStorage = (key, value) => {
|
const saveToStorage = (key, value) => { try { localStorage.setItem(key, value); } catch (e) { console.warn("Save to storage failed:", e); } };
|
||||||
try {
|
const getFromStorage = (key, defaultValue = '') => { try { return localStorage.getItem(key) || defaultValue; } catch (e) { console.warn("Read from storage failed:", e); return defaultValue; } };
|
||||||
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) {
|
function fileToBase64(file) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -680,6 +667,7 @@
|
|||||||
file: null,
|
file: null,
|
||||||
htmlUrl: null,
|
htmlUrl: null,
|
||||||
fileNameStem: null,
|
fileNameStem: null,
|
||||||
|
isSubmitted: false // MODIFICATION 1: Add isSubmitted flag
|
||||||
},
|
},
|
||||||
intervals: {
|
intervals: {
|
||||||
log: null,
|
log: null,
|
||||||
@@ -709,7 +697,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addEventListenersToCard(taskId) {
|
function addEventListenersToCard(taskId) {
|
||||||
const {elements, state} = tasks[taskId];
|
const { elements, state } = tasks[taskId];
|
||||||
|
|
||||||
elements.removeBtn.addEventListener('click', () => removeTask(taskId));
|
elements.removeBtn.addEventListener('click', () => removeTask(taskId));
|
||||||
|
|
||||||
@@ -746,7 +734,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleFileSelect(taskId) {
|
function handleFileSelect(taskId) {
|
||||||
const {elements, state} = tasks[taskId];
|
const { elements, state } = tasks[taskId];
|
||||||
const file = elements.fileInput.files[0];
|
const file = elements.fileInput.files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
state.file = file;
|
state.file = file;
|
||||||
@@ -761,7 +749,7 @@
|
|||||||
|
|
||||||
// --- Core Translation Logic ---
|
// --- Core Translation Logic ---
|
||||||
async function startTranslation(taskId) {
|
async function startTranslation(taskId) {
|
||||||
const {elements, state} = tasks[taskId];
|
const { elements, state } = tasks[taskId];
|
||||||
|
|
||||||
// --- Validation ---
|
// --- Validation ---
|
||||||
if (!state.file) {
|
if (!state.file) {
|
||||||
@@ -803,6 +791,8 @@
|
|||||||
try {
|
try {
|
||||||
const fileContentBase64 = await fileToBase64(state.file);
|
const fileContentBase64 = await fileToBase64(state.file);
|
||||||
|
|
||||||
|
state.isSubmitted = true; // MODIFICATION 2: Mark task as submitted before sending request
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
task_id: taskId,
|
task_id: taskId,
|
||||||
base_url: baseUrlInput.value,
|
base_url: baseUrlInput.value,
|
||||||
@@ -824,7 +814,7 @@
|
|||||||
|
|
||||||
const response = await fetch('/service/translate', {
|
const response = await fetch('/service/translate', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
});
|
});
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
@@ -852,12 +842,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function cancelTranslation(taskId) {
|
async function cancelTranslation(taskId) {
|
||||||
const {elements} = tasks[taskId];
|
const { elements } = tasks[taskId];
|
||||||
elements.startBtn.disabled = true;
|
elements.startBtn.disabled = true;
|
||||||
elements.startBtn.innerHTML = `<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 正在取消...`;
|
elements.startBtn.innerHTML = `<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 正在取消...`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/service/cancel/${taskId}`, {method: 'POST'});
|
const response = await fetch(`/service/cancel/${taskId}`, { method: 'POST' });
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok && result.cancelled) {
|
if (response.ok && result.cancelled) {
|
||||||
@@ -877,7 +867,7 @@
|
|||||||
// --- Polling ---
|
// --- Polling ---
|
||||||
function startPolling(taskId) {
|
function startPolling(taskId) {
|
||||||
stopPolling(taskId);
|
stopPolling(taskId);
|
||||||
const {intervals} = tasks[taskId];
|
const { intervals } = tasks[taskId];
|
||||||
intervals.log = setInterval(() => pollLogs(taskId), 2000);
|
intervals.log = setInterval(() => pollLogs(taskId), 2000);
|
||||||
intervals.status = setInterval(() => pollStatus(taskId), 1500);
|
intervals.status = setInterval(() => pollStatus(taskId), 1500);
|
||||||
pollLogs(taskId);
|
pollLogs(taskId);
|
||||||
@@ -885,7 +875,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stopPolling(taskId) {
|
function stopPolling(taskId) {
|
||||||
const {intervals} = tasks[taskId];
|
const { intervals } = tasks[taskId];
|
||||||
if (intervals.log) clearInterval(intervals.log);
|
if (intervals.log) clearInterval(intervals.log);
|
||||||
if (intervals.status) clearInterval(intervals.status);
|
if (intervals.status) clearInterval(intervals.status);
|
||||||
intervals.log = null;
|
intervals.log = null;
|
||||||
@@ -893,7 +883,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function pollLogs(taskId) {
|
async function pollLogs(taskId) {
|
||||||
const {elements} = tasks[taskId];
|
const { elements } = tasks[taskId];
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/service/logs/${taskId}`);
|
const response = await fetch(`/service/logs/${taskId}`);
|
||||||
if (!response.ok) return;
|
if (!response.ok) return;
|
||||||
@@ -908,12 +898,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function pollStatus(taskId, isRestore = false) {
|
async function pollStatus(taskId, isRestore = false) {
|
||||||
const {elements, state} = tasks[taskId];
|
const { elements, state } = tasks[taskId];
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/service/status/${taskId}`);
|
const response = await fetch(`/service/status/${taskId}`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// If 404 on restore, it means the task is old and gone from server. Remove it.
|
// MODIFICATION 3: Only remove task if it was already submitted
|
||||||
if (response.status === 404 && isRestore) {
|
// An unsubmitted task will have `state.isSubmitted = false`, and will not be removed.
|
||||||
|
if (response.status === 404 && isRestore && state.isSubmitted) {
|
||||||
removeTask(taskId);
|
removeTask(taskId);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -967,7 +958,7 @@
|
|||||||
|
|
||||||
// --- Download and Preview ---
|
// --- Download and Preview ---
|
||||||
function setupPreview(taskId) {
|
function setupPreview(taskId) {
|
||||||
const {state} = tasks[taskId];
|
const { state } = tasks[taskId];
|
||||||
if (!state.htmlUrl) return;
|
if (!state.htmlUrl) return;
|
||||||
|
|
||||||
// Clear previous content
|
// Clear previous content
|
||||||
@@ -1021,14 +1012,12 @@
|
|||||||
try {
|
try {
|
||||||
translatedPreviewFrame.contentWindow.focus();
|
translatedPreviewFrame.contentWindow.focus();
|
||||||
translatedPreviewFrame.contentWindow.print();
|
translatedPreviewFrame.contentWindow.print();
|
||||||
} catch (e) {
|
} catch(e) { alert('打印失败,请使用浏览器打印功能。'); }
|
||||||
alert('打印失败,请使用浏览器打印功能。');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadPdf(taskId) {
|
function downloadPdf(taskId) {
|
||||||
const {elements, state} = tasks[taskId];
|
const { elements, state } = tasks[taskId];
|
||||||
if (!state.htmlUrl) return;
|
if (!state.htmlUrl) return;
|
||||||
|
|
||||||
elements.pdfBtn.disabled = true;
|
elements.pdfBtn.disabled = true;
|
||||||
@@ -1157,9 +1146,7 @@
|
|||||||
platformSelect.addEventListener('change', updatePlatformUI);
|
platformSelect.addEventListener('change', updatePlatformUI);
|
||||||
apikeyInput.addEventListener('input', e => saveToStorage(`translator_platform_${platformSelect.value}_apikey`, e.target.value));
|
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));
|
modelInput.addEventListener('input', e => saveToStorage(`translator_platform_${platformSelect.value}_model_id`, e.target.value));
|
||||||
baseUrlInput.addEventListener('input', e => {
|
baseUrlInput.addEventListener('input', e => { if (platformSelect.value === 'custom') saveToStorage('translator_platform_custom_base_url', e.target.value); });
|
||||||
if (platformSelect.value === 'custom') saveToStorage('translator_platform_custom_base_url', e.target.value);
|
|
||||||
});
|
|
||||||
convertEnginSelect.addEventListener('change', updateConvertEnginUI);
|
convertEnginSelect.addEventListener('change', updateConvertEnginUI);
|
||||||
mineruTokenInput.addEventListener('input', e => saveToStorage('translator_mineru_token', e.target.value));
|
mineruTokenInput.addEventListener('input', e => saveToStorage('translator_mineru_token', e.target.value));
|
||||||
toLangSelect.addEventListener('change', e => saveToStorage('translator_to_lang', e.target.value));
|
toLangSelect.addEventListener('change', e => saveToStorage('translator_to_lang', e.target.value));
|
||||||
@@ -1232,6 +1219,6 @@
|
|||||||
|
|
||||||
// --- Start the application ---
|
// --- Start the application ---
|
||||||
document.addEventListener('DOMContentLoaded', init);
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user