Initial commit

This commit is contained in:
zaemon.li
2025-08-23 02:47:26 +08:00
parent 0360d8ade0
commit f7de9beef8
38 changed files with 669 additions and 0 deletions

133
static/app.js Normal file
View File

@@ -0,0 +1,133 @@
document.addEventListener('DOMContentLoaded', () => {
const searchButton = document.getElementById('searchButton');
const wordInput = document.getElementById('wordInput');
const resultsDiv = document.getElementById('results');
const sourceLangSelect = document.getElementById('sourceLang');
const targetLangSelect = document.getElementById('targetLang');
// 全局配置变量,增加 available_pairs
let appConfig = {
max_input_chars: 50,
available_pairs: {}
};
// --- 新增一个映射用于在UI上显示完整的语言名称 ---
const langNameMap = {
"en": "英语 (English)", "zh": "中文 (Chinese)", "es": "西班牙语 (Spanish)",
"fr": "法语 (French)", "de": "德语 (German)", "ru": "俄语 (Russian)",
"ja": "日语 (Japanese)", "ar": "阿拉伯语 (Arabic)", "pt": "葡萄牙语 (Portuguese)",
};
// --- 映射结束 ---
// --- 新增:更新目标语言下拉菜单的函数 ---
function updateTargetLangOptions() {
const selectedSource = sourceLangSelect.value;
const availableTargets = appConfig.available_pairs[selectedSource] || [];
// 清空当前选项
targetLangSelect.innerHTML = '';
if (availableTargets.length === 0) {
// 如果没有可用的目标语言,可以禁用或显示提示
const option = document.createElement('option');
option.textContent = "无可用目标";
targetLangSelect.appendChild(option);
targetLangSelect.disabled = true;
} else {
// 重新填充选项
availableTargets.forEach(langCode => {
const option = document.createElement('option');
option.value = langCode;
option.textContent = langNameMap[langCode] || langCode;
targetLangSelect.appendChild(option);
});
targetLangSelect.disabled = false;
}
}
// --- 函数结束 ---
(async function fetchConfig() {
try {
const response = await fetch('/api/config');
if (response.ok) {
const configData = await response.json();
appConfig = configData;
console.log("Successfully loaded config from server:", appConfig);
// --- 新增:配置加载成功后,立即更新一次目标语言菜单 ---
updateTargetLangOptions();
}
} catch (error) {
console.error("Could not fetch config from server, using default values.", error);
}
})();
// --- 新增:为源语言选择框添加 onchange 事件监听器 ---
sourceLangSelect.addEventListener('change', updateTargetLangOptions);
const performSearch = async () => {
// ... performSearch 函数本身的代码完全不用变 ...
const word = wordInput.value.trim();
const sourceLang = sourceLangSelect.value;
const targetLang = targetLangSelect.value;
if (!word || !sourceLang || !targetLang || targetLangSelect.disabled) return;
const maxChars = appConfig.max_input_chars;
if (word.length > maxChars) {
resultsDiv.innerHTML = `<p style="color: red;">输入内容过长,最多允许输入 ${maxChars} 个字符。</p>`;
return;
}
resultsDiv.innerHTML = '<p>正在查询...</p>';
try {
const apiUrl = `/api/lookup?word=${encodeURIComponent(word)}&source=${sourceLang}&target=${targetLang}`;
const response = await fetch(apiUrl);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`服务器错误: ${response.status} - ${errorText}`);
}
const data = await response.json();
console.log("Received data from backend:", data);
renderResults(data);
} catch (error) {
resultsDiv.innerHTML = `<p style="color: red;">查询失败: ${error.message}</p>`;
}
};
// ... 其他事件监听和 renderResults 函数保持不变 ...
searchButton.addEventListener('click', performSearch);
wordInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
performSearch();
}
});
function renderResults(data) {
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
let html = `<h2>${wordInput.value}</h2>`;
html += `<div class="phonetics">`;
if (data.p) {
html += `<span>${data.p}</span>`;
}
html += `</div>`;
if (data.defs && Array.isArray(data.defs) && data.defs.length > 0) {
data.defs.forEach(def => {
html += `<div class="entry">`;
html += `<div class="part-of-speech">${def.pos}</div>`;
html += `<div class="definition-block">`;
html += `<p>• ${def.m}</p>`;
if (def.ex) {
html += `<div class="example"><p>e.g., ${def.ex}</p></div>`;
}
html += `</div>`;
html += `</div>`;
});
} else {
html += `<p>未找到该词的释义。</p>`
}
resultsDiv.innerHTML = html;
}
});

68
static/index.html Normal file
View File

@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Dictionary</title>
<style>
/* CSS样式保持不变 */
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #333; }
h1 { color: #1a73e8; }
#search-controls { display: flex; gap: 10px; margin-bottom: 20px; align-items: center; }
#lang-selectors { display: flex; gap: 5px; }
#lang-selectors select { padding: 8px; font-size: 14px; border: 1px solid #ccc; border-radius: 8px; }
#search-container { display: flex; flex-grow: 1; gap: 10px; }
#wordInput { flex-grow: 1; padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 8px; }
#searchButton { padding: 10px 20px; font-size: 16px; background-color: #1a73e8; color: white; border: none; border-radius: 8px; cursor: pointer; }
#searchButton:hover { background-color: #185abc; }
#results { margin-top: 30px; }
.entry { border-left: 3px solid #1a73e8; padding: 15px; margin-top: 20px; background-color: #f8f9fa; border-radius: 0 8px 8px 0; }
.phonetics { font-size: 1.1em; color: #5f6368; }
.phonetics span { margin-right: 20px; }
.part-of-speech { font-weight: bold; font-size: 1.2em; margin-top: 10px; }
.definition-block { margin-top: 15px; }
.definition-block small { color: #5f6368; }
.example { margin-top: 10px; font-style: italic; color: #3c4043; }
.example small { color: #70757a; }
</style>
</head>
<body>
<h1>AI 词典</h1>
<div id="search-controls">
<div id="lang-selectors">
<select id="sourceLang">
<option value="en">英语 (English)</option>
<option value="zh">中文 (Chinese)</option>
<option value="es">西班牙语 (Spanish)</option>
<option value="fr">法语 (French)</option>
<option value="de">德语 (German)</option>
<option value="ru">俄语 (Russian)</option>
<option value="ja">日语 (Japanese)</option>
<option value="ar">阿拉伯语 (Arabic)</option>
<option value="pt">葡萄牙语 (Portuguese)</option>
</select>
<span></span>
<select id="targetLang">
<option value="zh">中文 (Chinese)</option>
<option value="en">英语 (English)</option>
<option value="es">西班牙语 (Spanish)</option>
<option value="fr">法语 (French)</option>
<option value="de">德语 (German)</option>
<option value="ru">俄语 (Russian)</option>
<option value="ja">日语 (Japanese)</option>
<option value="ar">阿拉伯语 (Arabic)</option>
<option value="pt">葡萄牙语 (Portuguese)</option>
</select>
</div>
<div id="search-container">
<input type="text" id="wordInput" placeholder="输入要查询的单词...">
<button id="searchButton">查询</button>
</div>
</div>
<div id="results"></div>
<script src="app.js"></script>
</body>
</html>