修复了ui的bug
This commit is contained in:
15
.idea/workspace.xml
generated
15
.idea/workspace.xml
generated
@@ -6,10 +6,6 @@
|
|||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="6b18b44a-df57-4212-a857-9e291ebe5dd2" name="更改" comment="">
|
<list default="true" id="6b18b44a-df57-4212-a857-9e291ebe5dd2" name="更改" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/docutranslate/agents/markdown_agent.py" beforeDir="false" afterPath="$PROJECT_DIR$/docutranslate/agents/markdown_agent.py" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/docutranslate/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/docutranslate/app.py" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -76,7 +72,7 @@
|
|||||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager": "true",
|
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager": "true",
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
"git-widget-placeholder": "main",
|
"git-widget-placeholder": "main",
|
||||||
"last_opened_file_path": "C:/Users/jxgm/Desktop/FileTranslate/docutranslate/agents",
|
"last_opened_file_path": "C:/Users/jxgm/Desktop/FileTranslate/dist/DocuTranslate",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
@@ -88,8 +84,8 @@
|
|||||||
}</component>
|
}</component>
|
||||||
<component name="RecentsManager">
|
<component name="RecentsManager">
|
||||||
<key name="CopyFile.RECENT_KEYS">
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\docutranslate\agents" />
|
|
||||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist\DocuTranslate" />
|
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist\DocuTranslate" />
|
||||||
|
<recent name="C:\Users\jxgm\Desktop\FileTranslate\docutranslate\agents" />
|
||||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist" />
|
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist" />
|
||||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist\app" />
|
<recent name="C:\Users\jxgm\Desktop\FileTranslate\dist\app" />
|
||||||
<recent name="C:\Users\jxgm\Desktop\FileTranslate\tests\files" />
|
<recent name="C:\Users\jxgm\Desktop\FileTranslate\tests\files" />
|
||||||
@@ -624,6 +620,7 @@
|
|||||||
<workItem from="1747299661166" duration="4649000" />
|
<workItem from="1747299661166" duration="4649000" />
|
||||||
<workItem from="1747311432043" duration="2883000" />
|
<workItem from="1747311432043" duration="2883000" />
|
||||||
<workItem from="1747380029603" duration="10381000" />
|
<workItem from="1747380029603" duration="10381000" />
|
||||||
|
<workItem from="1747403732304" duration="980000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
@@ -631,7 +628,7 @@
|
|||||||
<option name="version" value="3" />
|
<option name="version" value="3" />
|
||||||
</component>
|
</component>
|
||||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$app_test__1_.coverage" NAME="app_test (1) 覆盖结果" MODIFIED="1747399020079" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
<SUITE FILE_PATH="coverage/filetranslate$app_test__1_.coverage" NAME="app_test (1) 覆盖结果" MODIFIED="1747404483499" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$test.coverage" NAME="test 覆盖结果" MODIFIED="1747301959211" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
<SUITE FILE_PATH="coverage/filetranslate$test.coverage" NAME="test 覆盖结果" MODIFIED="1747301959211" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$convert.coverage" NAME="convert 覆盖结果" MODIFIED="1746963490689" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/utils" />
|
<SUITE FILE_PATH="coverage/filetranslate$convert.coverage" NAME="convert 覆盖结果" MODIFIED="1746963490689" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/utils" />
|
||||||
<SUITE FILE_PATH="coverage/PDFtranslate$PDFtranslater__1_.coverage" NAME="PDFtranslater (1) 覆盖结果" MODIFIED="1746633258205" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/pdftranslate_packages" />
|
<SUITE FILE_PATH="coverage/PDFtranslate$PDFtranslater__1_.coverage" NAME="PDFtranslater (1) 覆盖结果" MODIFIED="1746633258205" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/pdftranslate_packages" />
|
||||||
@@ -642,9 +639,9 @@
|
|||||||
<SUITE FILE_PATH="coverage/filetranslate$test3.coverage" NAME="test3 覆盖结果" MODIFIED="1746884110572" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
<SUITE FILE_PATH="coverage/filetranslate$test3.coverage" NAME="test3 覆盖结果" MODIFIED="1746884110572" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$app__1_.coverage" NAME="app (1) 覆盖结果" MODIFIED="1747136094477" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
<SUITE FILE_PATH="coverage/filetranslate$app__1_.coverage" NAME="app (1) 覆盖结果" MODIFIED="1747136094477" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$markdown_splitter.coverage" NAME="markdown_splitter 覆盖结果" MODIFIED="1746805063874" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/utils" />
|
<SUITE FILE_PATH="coverage/filetranslate$markdown_splitter.coverage" NAME="markdown_splitter 覆盖结果" MODIFIED="1746805063874" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/utils" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$agent.coverage" NAME="agent 覆盖结果" MODIFIED="1746805293987" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/Agents" />
|
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$PDFtranslater__2_.coverage" NAME="PDFtranslater (2) 覆盖结果" MODIFIED="1746679546680" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/filetranslate_packages" />
|
|
||||||
<SUITE FILE_PATH="coverage/PDFtranslate$test.coverage" NAME="test 覆盖结果" MODIFIED="1746629433597" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
<SUITE FILE_PATH="coverage/PDFtranslate$test.coverage" NAME="test 覆盖结果" MODIFIED="1746629433597" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||||
|
<SUITE FILE_PATH="coverage/filetranslate$PDFtranslater__2_.coverage" NAME="PDFtranslater (2) 覆盖结果" MODIFIED="1746679546680" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/filetranslate_packages" />
|
||||||
|
<SUITE FILE_PATH="coverage/filetranslate$agent.coverage" NAME="agent 覆盖结果" MODIFIED="1746805293987" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/Agents" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$agent_utils.coverage" NAME="agent_utils 覆盖结果" MODIFIED="1746708534311" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/utils" />
|
<SUITE FILE_PATH="coverage/filetranslate$agent_utils.coverage" NAME="agent_utils 覆盖结果" MODIFIED="1746708534311" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/docutranslate/utils" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$.coverage" NAME="切分测试 覆盖结果" MODIFIED="1747187128847" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
<SUITE FILE_PATH="coverage/filetranslate$.coverage" NAME="切分测试 覆盖结果" MODIFIED="1747187128847" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||||
<SUITE FILE_PATH="coverage/filetranslate$test1.coverage" NAME="test1 覆盖结果" MODIFIED="1746936018440" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
<SUITE FILE_PATH="coverage/filetranslate$test1.coverage" NAME="test1 覆盖结果" MODIFIED="1746936018440" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/tests" />
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ from docutranslate.logger import translater_logger
|
|||||||
|
|
||||||
# --- HTML模板 (JS part needs modification) ---
|
# --- HTML模板 (JS part needs modification) ---
|
||||||
# language=HTML
|
# language=HTML
|
||||||
HTML_TEMPLATE = """
|
HTML_TEMPLATE = """<!DOCTYPE html>
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
@@ -138,21 +137,42 @@ HTML_TEMPLATE = """
|
|||||||
}
|
}
|
||||||
|
|
||||||
#fileDropArea.drag-over {
|
#fileDropArea.drag-over {
|
||||||
border-color: #007bff; /* Pico primary color */
|
border-color: var(--pico-primary-focus); /* Pico primary color */
|
||||||
background-color: rgba(0, 123, 255, 0.05);
|
background-color: var(--pico-primary-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
#fileDropArea p {
|
#fileDropArea.file-selected {
|
||||||
|
border-color: var(--pico-form-element-valid-border-color, #2e7d32); /* Pico success color */
|
||||||
|
background-color: var(--pico-form-element-valid-background-color, #e8f5e9); /* Light green */
|
||||||
|
}
|
||||||
|
|
||||||
|
#fileDropArea p { /* General style for <p> inside drop area */
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
color: #555;
|
color: #555;
|
||||||
} \
|
}
|
||||||
\
|
/* #fileDropPrompt will be hidden/shown by JS using .hidden class */
|
||||||
|
|
||||||
|
|
||||||
#fileNameDisplay {
|
#fileNameDisplay {
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#fileNameDisplay.has-file {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--pico-form-element-valid-border-color, #1a531d); /* Darker green or success color */
|
||||||
|
}
|
||||||
|
|
||||||
|
#fileDropArea.input-error {
|
||||||
|
border-color: var(--pico-form-element-invalid-border-color, #d32f2f) !important;
|
||||||
|
}
|
||||||
|
#fileNameDisplay.input-error-text {
|
||||||
|
color: var(--pico-form-element-invalid-border-color, #d32f2f) !important;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.form-grid {
|
.form-grid {
|
||||||
@@ -173,7 +193,7 @@ HTML_TEMPLATE = """
|
|||||||
<label for="file">文档选择</label>
|
<label for="file">文档选择</label>
|
||||||
<div id="fileDropArea">
|
<div id="fileDropArea">
|
||||||
<input type="file" id="file" name="file" required style="display: none;">
|
<input type="file" id="file" name="file" required style="display: none;">
|
||||||
<p>点击此处选择文件,或将文件拖拽到这里</p>
|
<p id="fileDropPrompt">点击此处选择文件,或将文件拖拽到这里</p>
|
||||||
<div id="fileNameDisplay">未选择文件</div>
|
<div id="fileNameDisplay">未选择文件</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -299,6 +319,7 @@ HTML_TEMPLATE = """
|
|||||||
const fileInput = document.getElementById('file');
|
const fileInput = document.getElementById('file');
|
||||||
const fileDropArea = document.getElementById('fileDropArea');
|
const fileDropArea = document.getElementById('fileDropArea');
|
||||||
const fileNameDisplay = document.getElementById('fileNameDisplay');
|
const fileNameDisplay = document.getElementById('fileNameDisplay');
|
||||||
|
const fileDropPrompt = document.getElementById('fileDropPrompt'); // <-- 获取提示文字元素
|
||||||
|
|
||||||
|
|
||||||
let logPollIntervalId = null;
|
let logPollIntervalId = null;
|
||||||
@@ -374,8 +395,18 @@ HTML_TEMPLATE = """
|
|||||||
fileInput.addEventListener('change', () => {
|
fileInput.addEventListener('change', () => {
|
||||||
if (fileInput.files.length > 0) {
|
if (fileInput.files.length > 0) {
|
||||||
fileNameDisplay.textContent = `已选择: ${fileInput.files[0].name}`;
|
fileNameDisplay.textContent = `已选择: ${fileInput.files[0].name}`;
|
||||||
|
fileDropArea.classList.add('file-selected');
|
||||||
|
fileNameDisplay.classList.add('has-file');
|
||||||
|
fileDropPrompt.classList.add('hidden'); // <-- 隐藏提示文字
|
||||||
|
fileDropArea.classList.remove('input-error');
|
||||||
|
fileNameDisplay.classList.remove('input-error-text');
|
||||||
|
statusMsg.textContent = '';
|
||||||
|
statusMsg.className = '';
|
||||||
} else {
|
} else {
|
||||||
fileNameDisplay.textContent = '未选择文件';
|
fileNameDisplay.textContent = '未选择文件';
|
||||||
|
fileDropArea.classList.remove('file-selected');
|
||||||
|
fileNameDisplay.classList.remove('has-file');
|
||||||
|
fileDropPrompt.classList.remove('hidden'); // <-- 显示提示文字
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -390,7 +421,9 @@ HTML_TEMPLATE = """
|
|||||||
|
|
||||||
['dragenter', 'dragover'].forEach(eventName => {
|
['dragenter', 'dragover'].forEach(eventName => {
|
||||||
fileDropArea.addEventListener(eventName, () => {
|
fileDropArea.addEventListener(eventName, () => {
|
||||||
|
if (!fileDropArea.classList.contains('file-selected')) {
|
||||||
fileDropArea.classList.add('drag-over');
|
fileDropArea.classList.add('drag-over');
|
||||||
|
}
|
||||||
}, false);
|
}, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -405,14 +438,12 @@ HTML_TEMPLATE = """
|
|||||||
const files = dt.files;
|
const files = dt.files;
|
||||||
|
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
fileInput.files = files; // Assign dropped files to the input
|
fileInput.files = files;
|
||||||
fileNameDisplay.textContent = `已选择: ${files[0].name}`;
|
|
||||||
// Manually trigger change event for any listeners on fileInput
|
|
||||||
const event = new Event('change', {bubbles: true});
|
const event = new Event('change', {bubbles: true});
|
||||||
fileInput.dispatchEvent(event);
|
fileInput.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
}, false); \
|
}, false);
|
||||||
\
|
|
||||||
// --- End Drag and Drop ---
|
// --- End Drag and Drop ---
|
||||||
|
|
||||||
|
|
||||||
@@ -455,8 +486,8 @@ HTML_TEMPLATE = """
|
|||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
submitButton.removeAttribute('aria-busy');
|
submitButton.removeAttribute('aria-busy');
|
||||||
submitButton.textContent = '开始翻译';
|
submitButton.textContent = '开始翻译';
|
||||||
submitButton.classList.remove('secondary', 'contrast'); // PicoCSS: remove secondary/contrast
|
submitButton.classList.remove('secondary', 'contrast');
|
||||||
submitButton.classList.add('primary'); // PicoCSS: add primary
|
submitButton.classList.add('primary');
|
||||||
isTranslating = false;
|
isTranslating = false;
|
||||||
|
|
||||||
if (status.download_ready && !status.error_flag) {
|
if (status.download_ready && !status.error_flag) {
|
||||||
@@ -546,9 +577,9 @@ HTML_TEMPLATE = """
|
|||||||
} else { // Task is still processing
|
} else { // Task is still processing
|
||||||
submitButton.textContent = '取消翻译';
|
submitButton.textContent = '取消翻译';
|
||||||
submitButton.classList.remove('primary');
|
submitButton.classList.remove('primary');
|
||||||
submitButton.classList.add('secondary'); // PicoCSS: use secondary for cancel
|
submitButton.classList.add('secondary');
|
||||||
isTranslating = true;
|
isTranslating = true;
|
||||||
submitButton.disabled = false; // Enable button to allow cancellation
|
submitButton.disabled = false;
|
||||||
submitButton.removeAttribute('aria-busy');
|
submitButton.removeAttribute('aria-busy');
|
||||||
downloadBtns.style.display = 'none';
|
downloadBtns.style.display = 'none';
|
||||||
}
|
}
|
||||||
@@ -563,8 +594,8 @@ HTML_TEMPLATE = """
|
|||||||
stopPolling();
|
stopPolling();
|
||||||
lastLogCount = 0;
|
lastLogCount = 0;
|
||||||
logArea.innerHTML = '';
|
logArea.innerHTML = '';
|
||||||
pollLogs(); // Initial poll
|
pollLogs();
|
||||||
pollStatus(); // Initial poll
|
pollStatus();
|
||||||
logPollIntervalId = setInterval(pollLogs, 2000);
|
logPollIntervalId = setInterval(pollLogs, 2000);
|
||||||
statusPollIntervalId = setInterval(pollStatus, 1500);
|
statusPollIntervalId = setInterval(pollStatus, 1500);
|
||||||
}
|
}
|
||||||
@@ -579,7 +610,7 @@ HTML_TEMPLATE = """
|
|||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
platformSelect.value = getFromStorage('translator_last_platform', 'custom');
|
platformSelect.value = getFromStorage('translator_last_platform', 'custom');
|
||||||
updatePlatformUI(); // This will also load API key and model for the platform
|
updatePlatformUI();
|
||||||
toLangSelect.value = getFromStorage('translator_to_lang', '中文');
|
toLangSelect.value = getFromStorage('translator_to_lang', '中文');
|
||||||
formulaCheckbox.checked = getFromStorage('translator_formula_ocr') === 'true';
|
formulaCheckbox.checked = getFromStorage('translator_formula_ocr') === 'true';
|
||||||
codeCheckbox.checked = getFromStorage('translator_code_ocr') === 'true';
|
codeCheckbox.checked = getFromStorage('translator_code_ocr') === 'true';
|
||||||
@@ -598,11 +629,10 @@ HTML_TEMPLATE = """
|
|||||||
|
|
||||||
if (response.ok && result.cancelled) {
|
if (response.ok && result.cancelled) {
|
||||||
statusMsg.textContent = result.message || '取消请求已发送。';
|
statusMsg.textContent = result.message || '取消请求已发送。';
|
||||||
statusMsg.className = ''; // Neutral message
|
statusMsg.className = '';
|
||||||
} else {
|
} else {
|
||||||
statusMsg.textContent = result.message || '取消失败。';
|
statusMsg.textContent = result.message || '取消失败。';
|
||||||
statusMsg.className = 'error-message';
|
statusMsg.className = 'error-message';
|
||||||
// Re-enable button as "Cancel Translation" if cancellation failed but task might still be running
|
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
submitButton.textContent = '取消翻译';
|
submitButton.textContent = '取消翻译';
|
||||||
submitButton.removeAttribute('aria-busy');
|
submitButton.removeAttribute('aria-busy');
|
||||||
@@ -612,10 +642,9 @@ HTML_TEMPLATE = """
|
|||||||
statusMsg.textContent = '取消请求发送失败。';
|
statusMsg.textContent = '取消请求发送失败。';
|
||||||
statusMsg.className = 'error-message';
|
statusMsg.className = 'error-message';
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
submitButton.textContent = '取消翻译'; // Or '开始翻译' if we assume it stopped
|
submitButton.textContent = '取消翻译';
|
||||||
submitButton.removeAttribute('aria-busy');
|
submitButton.removeAttribute('aria-busy');
|
||||||
}
|
}
|
||||||
// Polling will handle the final state update for the button and status.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
form.addEventListener('submit', async function (event) {
|
form.addEventListener('submit', async function (event) {
|
||||||
@@ -626,18 +655,30 @@ HTML_TEMPLATE = """
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate file input
|
|
||||||
if (fileInput.files.length === 0) {
|
if (fileInput.files.length === 0) {
|
||||||
statusMsg.textContent = '请选择一个文件进行翻译。';
|
statusMsg.textContent = '请选择一个文件进行翻译。';
|
||||||
statusMsg.className = 'error-message';
|
statusMsg.className = 'error-message';
|
||||||
fileNameDisplay.textContent = '请选择文件!';
|
fileNameDisplay.textContent = '请选择文件!';
|
||||||
fileDropArea.classList.add('error-message'); // Optional: add error style to drop area
|
fileNameDisplay.classList.add('input-error-text');
|
||||||
setTimeout(() => fileDropArea.classList.remove('error-message'), 2000);
|
fileDropArea.classList.add('input-error');
|
||||||
|
fileDropPrompt.classList.remove('hidden'); // 确保错误时提示文字可见
|
||||||
|
setTimeout(() => {
|
||||||
|
fileDropArea.classList.remove('input-error');
|
||||||
|
fileNameDisplay.classList.remove('input-error-text');
|
||||||
|
if (fileNameDisplay.textContent === '请选择文件!') {
|
||||||
|
fileNameDisplay.textContent = '未选择文件';
|
||||||
|
}
|
||||||
|
// 如果没有文件被选中,提示文字应该保持可见
|
||||||
|
if (fileInput.files.length === 0) {
|
||||||
|
fileDropPrompt.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 3000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stopPolling(); // Stop any existing polling
|
stopPolling();
|
||||||
submitButton.disabled = true;
|
submitButton.disabled = true;
|
||||||
submitButton.setAttribute('aria-busy', 'true');
|
submitButton.setAttribute('aria-busy', 'true');
|
||||||
submitButton.textContent = '初始化...';
|
submitButton.textContent = '初始化...';
|
||||||
@@ -654,12 +695,12 @@ HTML_TEMPLATE = """
|
|||||||
if (response.ok && result.task_started) {
|
if (response.ok && result.task_started) {
|
||||||
statusMsg.textContent = result.message || '任务已开始,正在处理...';
|
statusMsg.textContent = result.message || '任务已开始,正在处理...';
|
||||||
statusMsg.className = '';
|
statusMsg.className = '';
|
||||||
submitButton.textContent = '取消翻译'; // Change button text
|
submitButton.textContent = '取消翻译';
|
||||||
submitButton.classList.remove('primary');
|
submitButton.classList.remove('primary');
|
||||||
submitButton.classList.add('secondary'); // Change button style
|
submitButton.classList.add('secondary');
|
||||||
isTranslating = true; // Set translation flag
|
isTranslating = true;
|
||||||
submitButton.removeAttribute('aria-busy'); // No longer busy submitting, now in "cancellable" state
|
submitButton.removeAttribute('aria-busy');
|
||||||
startPolling(); // Start polling for status and logs
|
startPolling();
|
||||||
} else {
|
} else {
|
||||||
statusMsg.textContent = result.message || `请求失败 (${response.status})`;
|
statusMsg.textContent = result.message || `请求失败 (${response.status})`;
|
||||||
statusMsg.className = 'error-message';
|
statusMsg.className = 'error-message';
|
||||||
@@ -680,8 +721,7 @@ HTML_TEMPLATE = """
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html> \
|
</html>"""
|
||||||
"""
|
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
@@ -734,16 +774,25 @@ class QueueAndHistoryHandler(logging.Handler):
|
|||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
async def startup_event():
|
async def startup_event():
|
||||||
app.state.main_event_loop = asyncio.get_running_loop()
|
app.state.main_event_loop = asyncio.get_running_loop()
|
||||||
if translater_logger.hasHandlers():
|
|
||||||
translater_logger.handlers.clear()
|
# Clear ALL existing handlers (not just checking if any exist)
|
||||||
|
for handler in translater_logger.handlers[:]:
|
||||||
|
translater_logger.removeHandler(handler)
|
||||||
|
|
||||||
|
# Configure the new handler
|
||||||
queue_handler = QueueAndHistoryHandler(log_queue, log_history, MAX_LOG_HISTORY)
|
queue_handler = QueueAndHistoryHandler(log_queue, log_history, MAX_LOG_HISTORY)
|
||||||
queue_handler.setLevel(logging.INFO)
|
queue_handler.setLevel(logging.INFO)
|
||||||
queue_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
|
queue_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
|
||||||
translater_logger.addHandler(queue_handler)
|
|
||||||
translater_logger.propagate = False # 非常重要,阻止日志向上传播到root logger
|
|
||||||
translater_logger.setLevel(logging.INFO) # 确保 translater_logger 本身的级别是 INFO
|
|
||||||
|
|
||||||
translater_logger.info("应用启动完成,日志队列/历史处理器已清除并重新配置。")
|
# Add the handler and configure the logger
|
||||||
|
translater_logger.addHandler(queue_handler)
|
||||||
|
translater_logger.propagate = False
|
||||||
|
translater_logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Clear the log history for a fresh start
|
||||||
|
log_history.clear()
|
||||||
|
|
||||||
|
translater_logger.info("应用启动完成,日志队列/历史处理器已正确配置。")
|
||||||
|
|
||||||
# --- Background Task Logic ---
|
# --- Background Task Logic ---
|
||||||
async def _perform_translation(params: Dict[str, Any], file_contents: bytes, original_filename: str):
|
async def _perform_translation(params: Dict[str, Any], file_contents: bytes, original_filename: str):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "docutranslate"
|
name = "docutranslate"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
description = "文件翻译工具"
|
description = "文件翻译工具"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|||||||
Reference in New Issue
Block a user