207 lines
No EOL
10 KiB
JavaScript
207 lines
No EOL
10 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) {
|
|
// 处理多选 MODEL_PROVIDER (复选框)
|
|
const providers = Array.isArray(data.DEFAULT_MODEL_PROVIDERS)
|
|
? data.DEFAULT_MODEL_PROVIDERS
|
|
: (typeof data.MODEL_PROVIDER === 'string' ? data.MODEL_PROVIDER.split(',') : []);
|
|
|
|
const checkboxes = modelProviderEl.querySelectorAll('input[type="checkbox"]');
|
|
checkboxes.forEach(checkbox => {
|
|
checkbox.checked = providers.includes(checkbox.value);
|
|
});
|
|
|
|
// 如果没有任何选中的,默认选中第一个(保持兼容性)
|
|
const anyChecked = Array.from(checkboxes).some(cb => cb.checked);
|
|
if (!anyChecked && checkboxes.length > 0) {
|
|
checkboxes[0].checked = true;
|
|
}
|
|
|
|
// 为复选框添加事件监听,防止取消勾选最后一个
|
|
checkboxes.forEach(checkbox => {
|
|
// 移除旧的监听器(如果有的话,虽然这里大概率没有)
|
|
const newCheckbox = checkbox.cloneNode(true);
|
|
checkbox.parentNode.replaceChild(newCheckbox, checkbox);
|
|
|
|
newCheckbox.addEventListener('change', (e) => {
|
|
const checkedCount = modelProviderEl.querySelectorAll('input[type="checkbox"]:checked').length;
|
|
if (checkedCount === 0) {
|
|
newCheckbox.checked = true;
|
|
showToast(t('common.warning'), t('config.modelProviderRequired'), 'warning');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
if (systemPromptEl) systemPromptEl.value = data.systemPrompt || '';
|
|
|
|
// 高级配置参数
|
|
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');
|
|
const providerFallbackChainEl = document.getElementById('providerFallbackChain');
|
|
|
|
if (systemPromptFilePathEl) systemPromptFilePathEl.value = data.SYSTEM_PROMPT_FILE_PATH || 'configs/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;
|
|
|
|
// 加载 Fallback 链配置
|
|
if (providerFallbackChainEl) {
|
|
if (data.providerFallbackChain && typeof data.providerFallbackChain === 'object') {
|
|
providerFallbackChainEl.value = JSON.stringify(data.providerFallbackChain, null, 2);
|
|
} else {
|
|
providerFallbackChainEl.value = '';
|
|
}
|
|
}
|
|
|
|
// 加载代理配置
|
|
const proxyUrlEl = document.getElementById('proxyUrl');
|
|
if (proxyUrlEl) proxyUrlEl.value = data.PROXY_URL || '';
|
|
|
|
// 加载启用代理的提供商
|
|
const proxyProviderCheckboxes = document.querySelectorAll('input[name="proxyProvider"]');
|
|
const enabledProviders = data.PROXY_ENABLED_PROVIDERS || [];
|
|
proxyProviderCheckboxes.forEach(checkbox => {
|
|
checkbox.checked = enabledProviders.includes(checkbox.value);
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Failed to load configuration:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存配置
|
|
*/
|
|
async function saveConfiguration() {
|
|
const modelProviderEl = document.getElementById('modelProvider');
|
|
let selectedProviders = [];
|
|
if (modelProviderEl) {
|
|
// 从复选框中获取选中的提供商
|
|
selectedProviders = Array.from(modelProviderEl.querySelectorAll('input[type="checkbox"]:checked'))
|
|
.map(cb => cb.value);
|
|
}
|
|
|
|
// 校验:必须至少勾选一个
|
|
if (selectedProviders.length === 0) {
|
|
showToast(t('common.error'), t('config.modelProviderRequired'), 'error');
|
|
return;
|
|
}
|
|
|
|
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: selectedProviders.length > 0 ? selectedProviders.join(',') : 'gemini-cli-oauth',
|
|
systemPrompt: document.getElementById('systemPrompt')?.value || '',
|
|
};
|
|
|
|
// 获取后台登录密码(如果有输入)
|
|
const adminPassword = document.getElementById('adminPassword')?.value || '';
|
|
|
|
// 保存高级配置参数
|
|
config.SYSTEM_PROMPT_FILE_PATH = document.getElementById('systemPromptFilePath')?.value || 'configs/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);
|
|
|
|
// 保存 Fallback 链配置
|
|
const fallbackChainValue = document.getElementById('providerFallbackChain')?.value?.trim() || '';
|
|
if (fallbackChainValue) {
|
|
try {
|
|
config.providerFallbackChain = JSON.parse(fallbackChainValue);
|
|
} catch (e) {
|
|
showToast(t('common.error'), t('config.advanced.fallbackChainInvalid') || 'Fallback 链配置格式无效,请输入有效的 JSON', 'error');
|
|
return;
|
|
}
|
|
} else {
|
|
config.providerFallbackChain = {};
|
|
}
|
|
|
|
// 保存代理配置
|
|
config.PROXY_URL = document.getElementById('proxyUrl')?.value?.trim() || null;
|
|
|
|
// 获取启用代理的提供商列表
|
|
const proxyProviderCheckboxes = document.querySelectorAll('input[name="proxyProvider"]:checked');
|
|
config.PROXY_ENABLED_PROVIDERS = Array.from(proxyProviderCheckboxes).map(cb => cb.value);
|
|
|
|
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
|
|
}; |