实现中英文双语支持,包括: 1. 添加i18n.js核心模块处理语言切换和翻译 2. 创建语言切换器组件 3. 更新所有UI文本使用翻译键 4. 添加I18N_GUIDE.md文档说明使用方法 5. 修改样式适配语言切换器 6. 添加adm-zip依赖支持配置文件打包下载 7. 更新登录页面支持多语言 8. 重构toast消息显示支持多语言标题
263 lines
No EOL
14 KiB
JavaScript
263 lines
No EOL
14 KiB
JavaScript
// 配置管理模块
|
|
|
|
import { showToast, formatUptime } from './utils.js';
|
|
import { handleProviderChange, handleGeminiCredsTypeChange, handleKiroCredsTypeChange } from './event-handlers.js';
|
|
import { loadProviders } from './provider-manager.js';
|
|
import { t } from './i18n.js';
|
|
|
|
/**
|
|
* 加载配置
|
|
*/
|
|
async function loadConfiguration() {
|
|
try {
|
|
const data = await window.apiClient.get('/config');
|
|
|
|
// 基础配置
|
|
const apiKeyEl = document.getElementById('apiKey');
|
|
const hostEl = document.getElementById('host');
|
|
const portEl = document.getElementById('port');
|
|
const modelProviderEl = document.getElementById('modelProvider');
|
|
const systemPromptEl = document.getElementById('systemPrompt');
|
|
|
|
if (apiKeyEl) apiKeyEl.value = data.REQUIRED_API_KEY || '';
|
|
if (hostEl) hostEl.value = data.HOST || '127.0.0.1';
|
|
if (portEl) portEl.value = data.SERVER_PORT || 3000;
|
|
if (modelProviderEl) modelProviderEl.value = data.MODEL_PROVIDER || 'gemini-cli-oauth';
|
|
if (systemPromptEl) systemPromptEl.value = data.systemPrompt || '';
|
|
|
|
// Gemini CLI OAuth
|
|
const projectIdEl = document.getElementById('projectId');
|
|
const geminiOauthCredsBase64El = document.getElementById('geminiOauthCredsBase64');
|
|
const geminiOauthCredsFilePathEl = document.getElementById('geminiOauthCredsFilePath');
|
|
|
|
if (projectIdEl) projectIdEl.value = data.PROJECT_ID || '';
|
|
if (geminiOauthCredsBase64El) geminiOauthCredsBase64El.value = data.GEMINI_OAUTH_CREDS_BASE64 || '';
|
|
if (geminiOauthCredsFilePathEl) geminiOauthCredsFilePathEl.value = data.GEMINI_OAUTH_CREDS_FILE_PATH || '';
|
|
const geminiBaseUrlEl = document.getElementById('geminiBaseUrl');
|
|
if (geminiBaseUrlEl) geminiBaseUrlEl.value = data.GEMINI_BASE_URL || '';
|
|
const antigravityBaseUrlDailyEl = document.getElementById('antigravityBaseUrlDaily');
|
|
if (antigravityBaseUrlDailyEl) antigravityBaseUrlDailyEl.value = data.ANTIGRAVITY_BASE_URL_DAILY || '';
|
|
const antigravityBaseUrlAutopushEl = document.getElementById('antigravityBaseUrlAutopush');
|
|
if (antigravityBaseUrlAutopushEl) antigravityBaseUrlAutopushEl.value = data.ANTIGRAVITY_BASE_URL_AUTOPUSH || '';
|
|
|
|
// OpenAI Custom
|
|
const openaiApiKeyEl = document.getElementById('openaiApiKey');
|
|
const openaiBaseUrlEl = document.getElementById('openaiBaseUrl');
|
|
|
|
if (openaiApiKeyEl) openaiApiKeyEl.value = data.OPENAI_API_KEY || '';
|
|
if (openaiBaseUrlEl) openaiBaseUrlEl.value = data.OPENAI_BASE_URL || 'https://api.openai.com/v1';
|
|
|
|
// Claude Custom
|
|
const claudeApiKeyEl = document.getElementById('claudeApiKey');
|
|
const claudeBaseUrlEl = document.getElementById('claudeBaseUrl');
|
|
|
|
if (claudeApiKeyEl) claudeApiKeyEl.value = data.CLAUDE_API_KEY || '';
|
|
if (claudeBaseUrlEl) claudeBaseUrlEl.value = data.CLAUDE_BASE_URL || 'https://api.anthropic.com';
|
|
|
|
// Claude Kiro OAuth
|
|
const kiroOauthCredsBase64El = document.getElementById('kiroOauthCredsBase64');
|
|
const kiroOauthCredsFilePathEl = document.getElementById('kiroOauthCredsFilePath');
|
|
|
|
if (kiroOauthCredsBase64El) kiroOauthCredsBase64El.value = data.KIRO_OAUTH_CREDS_BASE64 || '';
|
|
if (kiroOauthCredsFilePathEl) kiroOauthCredsFilePathEl.value = data.KIRO_OAUTH_CREDS_FILE_PATH || '';
|
|
const kiroBaseUrlEl = document.getElementById('kiroBaseUrl');
|
|
if (kiroBaseUrlEl) kiroBaseUrlEl.value = data.KIRO_BASE_URL || '';
|
|
const kiroRefreshUrlEl = document.getElementById('kiroRefreshUrl');
|
|
if (kiroRefreshUrlEl) kiroRefreshUrlEl.value = data.KIRO_REFRESH_URL || '';
|
|
const kiroRefreshIdcUrlEl = document.getElementById('kiroRefreshIdcUrl');
|
|
if (kiroRefreshIdcUrlEl) kiroRefreshIdcUrlEl.value = data.KIRO_REFRESH_IDC_URL || '';
|
|
|
|
// Qwen OAuth
|
|
const qwenOauthCredsFilePathEl = document.getElementById('qwenOauthCredsFilePath');
|
|
if (qwenOauthCredsFilePathEl) qwenOauthCredsFilePathEl.value = data.QWEN_OAUTH_CREDS_FILE_PATH || '';
|
|
const qwenBaseUrlEl = document.getElementById('qwenBaseUrl');
|
|
if (qwenBaseUrlEl) qwenBaseUrlEl.value = data.QWEN_BASE_URL || '';
|
|
const qwenOauthBaseUrlEl = document.getElementById('qwenOauthBaseUrl');
|
|
if (qwenOauthBaseUrlEl) qwenOauthBaseUrlEl.value = data.QWEN_OAUTH_BASE_URL || '';
|
|
|
|
// OpenAI Responses
|
|
const openaiResponsesApiKeyEl = document.getElementById('openaiResponsesApiKey');
|
|
const openaiResponsesBaseUrlEl = document.getElementById('openaiResponsesBaseUrl');
|
|
|
|
if (openaiResponsesApiKeyEl) openaiResponsesApiKeyEl.value = data.OPENAI_API_KEY || '';
|
|
if (openaiResponsesBaseUrlEl) openaiResponsesBaseUrlEl.value = data.OPENAI_BASE_URL || 'https://api.openai.com/v1';
|
|
|
|
// 高级配置参数
|
|
const systemPromptFilePathEl = document.getElementById('systemPromptFilePath');
|
|
const systemPromptModeEl = document.getElementById('systemPromptMode');
|
|
const promptLogBaseNameEl = document.getElementById('promptLogBaseName');
|
|
const promptLogModeEl = document.getElementById('promptLogMode');
|
|
const requestMaxRetriesEl = document.getElementById('requestMaxRetries');
|
|
const requestBaseDelayEl = document.getElementById('requestBaseDelay');
|
|
const cronNearMinutesEl = document.getElementById('cronNearMinutes');
|
|
const cronRefreshTokenEl = document.getElementById('cronRefreshToken');
|
|
const providerPoolsFilePathEl = document.getElementById('providerPoolsFilePath');
|
|
const maxErrorCountEl = document.getElementById('maxErrorCount');
|
|
|
|
if (systemPromptFilePathEl) systemPromptFilePathEl.value = data.SYSTEM_PROMPT_FILE_PATH || 'input_system_prompt.txt';
|
|
if (systemPromptModeEl) systemPromptModeEl.value = data.SYSTEM_PROMPT_MODE || 'append';
|
|
if (promptLogBaseNameEl) promptLogBaseNameEl.value = data.PROMPT_LOG_BASE_NAME || 'prompt_log';
|
|
if (promptLogModeEl) promptLogModeEl.value = data.PROMPT_LOG_MODE || 'none';
|
|
if (requestMaxRetriesEl) requestMaxRetriesEl.value = data.REQUEST_MAX_RETRIES || 3;
|
|
if (requestBaseDelayEl) requestBaseDelayEl.value = data.REQUEST_BASE_DELAY || 1000;
|
|
if (cronNearMinutesEl) cronNearMinutesEl.value = data.CRON_NEAR_MINUTES || 1;
|
|
if (cronRefreshTokenEl) cronRefreshTokenEl.checked = data.CRON_REFRESH_TOKEN || false;
|
|
if (providerPoolsFilePathEl) providerPoolsFilePathEl.value = data.PROVIDER_POOLS_FILE_PATH;
|
|
if (maxErrorCountEl) maxErrorCountEl.value = data.MAX_ERROR_COUNT || 3;
|
|
|
|
// 触发提供商配置显示
|
|
handleProviderChange();
|
|
|
|
// 根据Gemini凭据类型设置显示
|
|
const geminiCredsType = data.GEMINI_OAUTH_CREDS_BASE64 ? 'base64' : 'file';
|
|
const geminiRadio = document.querySelector(`input[name="geminiCredsType"][value="${geminiCredsType}"]`);
|
|
if (geminiRadio) {
|
|
geminiRadio.checked = true;
|
|
handleGeminiCredsTypeChange({ target: geminiRadio });
|
|
}
|
|
|
|
// 根据Kiro凭据类型设置显示
|
|
const kiroCredsType = data.KIRO_OAUTH_CREDS_BASE64 ? 'base64' : 'file';
|
|
const kiroRadio = document.querySelector(`input[name="kiroCredsType"][value="${kiroCredsType}"]`);
|
|
if (kiroRadio) {
|
|
kiroRadio.checked = true;
|
|
handleKiroCredsTypeChange({ target: kiroRadio });
|
|
}
|
|
|
|
// 检查并设置提供商池菜单显示状态
|
|
// const providerPoolsFilePath = data.PROVIDER_POOLS_FILE_PATH;
|
|
// const providersMenuItem = document.querySelector('.nav-item[data-section="providers"]');
|
|
// if (providerPoolsFilePath && providerPoolsFilePath.trim() !== '') {
|
|
// if (providersMenuItem) providersMenuItem.style.display = 'flex';
|
|
// } else {
|
|
// if (providersMenuItem) providersMenuItem.style.display = 'none';
|
|
// }
|
|
|
|
} catch (error) {
|
|
console.error('Failed to load configuration:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存配置
|
|
*/
|
|
async function saveConfiguration() {
|
|
const config = {
|
|
REQUIRED_API_KEY: document.getElementById('apiKey')?.value || '',
|
|
HOST: document.getElementById('host')?.value || '127.0.0.1',
|
|
SERVER_PORT: parseInt(document.getElementById('port')?.value || 3000),
|
|
MODEL_PROVIDER: document.getElementById('modelProvider')?.value || 'gemini-cli-oauth',
|
|
systemPrompt: document.getElementById('systemPrompt')?.value || '',
|
|
};
|
|
|
|
// 获取后台登录密码(如果有输入)
|
|
const adminPassword = document.getElementById('adminPassword')?.value || '';
|
|
|
|
// 根据不同提供商保存不同的配置
|
|
const provider = document.getElementById('modelProvider')?.value;
|
|
|
|
switch (provider) {
|
|
case 'gemini-cli-oauth':
|
|
config.PROJECT_ID = document.getElementById('projectId')?.value || '';
|
|
const geminiCredsType = document.querySelector('input[name="geminiCredsType"]:checked')?.value;
|
|
if (geminiCredsType === 'base64') {
|
|
config.GEMINI_OAUTH_CREDS_BASE64 = document.getElementById('geminiOauthCredsBase64')?.value || '';
|
|
config.GEMINI_OAUTH_CREDS_FILE_PATH = null;
|
|
} else {
|
|
config.GEMINI_OAUTH_CREDS_BASE64 = null;
|
|
config.GEMINI_OAUTH_CREDS_FILE_PATH = document.getElementById('geminiOauthCredsFilePath')?.value || '';
|
|
}
|
|
config.GEMINI_BASE_URL = document.getElementById('geminiBaseUrl')?.value || null;
|
|
break;
|
|
|
|
case 'gemini-antigravity':
|
|
config.ANTIGRAVITY_BASE_URL_DAILY = document.getElementById('antigravityBaseUrlDaily')?.value || null;
|
|
config.ANTIGRAVITY_BASE_URL_AUTOPUSH = document.getElementById('antigravityBaseUrlAutopush')?.value || null;
|
|
config.ANTIGRAVITY_OAUTH_CREDS_FILE_PATH = document.getElementById('antigravityOauthCredsFilePath')?.value || '';
|
|
break;
|
|
|
|
case 'openai-custom':
|
|
config.OPENAI_API_KEY = document.getElementById('openaiApiKey')?.value || '';
|
|
config.OPENAI_BASE_URL = document.getElementById('openaiBaseUrl')?.value || '';
|
|
break;
|
|
|
|
case 'claude-custom':
|
|
config.CLAUDE_API_KEY = document.getElementById('claudeApiKey')?.value || '';
|
|
config.CLAUDE_BASE_URL = document.getElementById('claudeBaseUrl')?.value || '';
|
|
break;
|
|
|
|
case 'claude-kiro-oauth':
|
|
const kiroCredsType = document.querySelector('input[name="kiroCredsType"]:checked')?.value;
|
|
if (kiroCredsType === 'base64') {
|
|
config.KIRO_OAUTH_CREDS_BASE64 = document.getElementById('kiroOauthCredsBase64')?.value || '';
|
|
config.KIRO_OAUTH_CREDS_FILE_PATH = null;
|
|
} else {
|
|
config.KIRO_OAUTH_CREDS_BASE64 = null;
|
|
config.KIRO_OAUTH_CREDS_FILE_PATH = document.getElementById('kiroOauthCredsFilePath')?.value || '';
|
|
}
|
|
config.KIRO_BASE_URL = document.getElementById('kiroBaseUrl')?.value || null;
|
|
config.KIRO_REFRESH_URL = document.getElementById('kiroRefreshUrl')?.value || null;
|
|
config.KIRO_REFRESH_IDC_URL = document.getElementById('kiroRefreshIdcUrl')?.value || null;
|
|
break;
|
|
|
|
case 'openai-qwen-oauth':
|
|
config.QWEN_OAUTH_CREDS_FILE_PATH = document.getElementById('qwenOauthCredsFilePath')?.value || '';
|
|
config.QWEN_BASE_URL = document.getElementById('qwenBaseUrl')?.value || null;
|
|
config.QWEN_OAUTH_BASE_URL = document.getElementById('qwenOauthBaseUrl')?.value || null;
|
|
break;
|
|
|
|
case 'openaiResponses-custom':
|
|
config.OPENAI_API_KEY = document.getElementById('openaiResponsesApiKey')?.value || '';
|
|
config.OPENAI_BASE_URL = document.getElementById('openaiResponsesBaseUrl')?.value || '';
|
|
break;
|
|
}
|
|
|
|
// 保存高级配置参数
|
|
config.SYSTEM_PROMPT_FILE_PATH = document.getElementById('systemPromptFilePath')?.value || 'input_system_prompt.txt';
|
|
config.SYSTEM_PROMPT_MODE = document.getElementById('systemPromptMode')?.value || 'append';
|
|
config.PROMPT_LOG_BASE_NAME = document.getElementById('promptLogBaseName')?.value || '';
|
|
config.PROMPT_LOG_MODE = document.getElementById('promptLogMode')?.value || '';
|
|
config.REQUEST_MAX_RETRIES = parseInt(document.getElementById('requestMaxRetries')?.value || 3);
|
|
config.REQUEST_BASE_DELAY = parseInt(document.getElementById('requestBaseDelay')?.value || 1000);
|
|
config.CRON_NEAR_MINUTES = parseInt(document.getElementById('cronNearMinutes')?.value || 1);
|
|
config.CRON_REFRESH_TOKEN = document.getElementById('cronRefreshToken')?.checked || false;
|
|
config.PROVIDER_POOLS_FILE_PATH = document.getElementById('providerPoolsFilePath')?.value || '';
|
|
config.MAX_ERROR_COUNT = parseInt(document.getElementById('maxErrorCount')?.value || 3);
|
|
|
|
try {
|
|
await window.apiClient.post('/config', config);
|
|
|
|
// 如果输入了新密码,单独保存密码
|
|
if (adminPassword) {
|
|
try {
|
|
await window.apiClient.post('/admin-password', { password: adminPassword });
|
|
// 清空密码输入框
|
|
const adminPasswordEl = document.getElementById('adminPassword');
|
|
if (adminPasswordEl) adminPasswordEl.value = '';
|
|
showToast(t('common.success'), t('common.passwordUpdated'), 'success');
|
|
} catch (pwdError) {
|
|
console.error('Failed to save admin password:', pwdError);
|
|
showToast(t('common.error'), t('common.error') + ': ' + pwdError.message, 'error');
|
|
}
|
|
}
|
|
|
|
await window.apiClient.post('/reload-config');
|
|
showToast(t('common.success'), t('common.configSaved'), 'success');
|
|
|
|
// 检查当前是否在提供商池管理页面,如果是则刷新数据
|
|
const providersSection = document.getElementById('providers');
|
|
if (providersSection && providersSection.classList.contains('active')) {
|
|
// 当前在提供商池页面,刷新数据
|
|
await loadProviders();
|
|
showToast(t('common.success'), t('common.providerPoolRefreshed'), 'success');
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to save configuration:', error);
|
|
showToast(t('common.error'), t('common.error') + ': ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
export {
|
|
loadConfiguration,
|
|
saveConfiguration
|
|
}; |