add global config support

This commit is contained in:
wjqserver 2025-06-30 15:31:14 +08:00
parent cd1e1a42f3
commit 34d553a890
23 changed files with 1682 additions and 343 deletions

153
frontend/js/global.js Normal file
View file

@ -0,0 +1,153 @@
// js/global.js - 全局配置页面的逻辑
import { theme, activateNav } from './common.js';
import { api } from './api.js';
import { notification } from './notifications.js';
import { initCaddyStatus } from './caddy.js';
import { createCustomSelect } from './ui.js';
const DOMElements = {
globalForm: document.getElementById('global-caddy-form'),
themeToggleInput: document.getElementById('theme-toggle-input'),
logoutBtn: document.getElementById('logout-btn'),
toastContainer: document.getElementById('toast-container'),
dialogContainer: document.getElementById('dialog-container'),
enableDnsChallengeCheckbox: document.getElementById('enable_dns_challenge'),
globalTlsConfigGroup: document.getElementById('global-tls-config-group'),
enableEchCheckbox: document.getElementById('enable_ech'),
echConfigGroup: document.getElementById('ech-config-group'),
};
const submitButton = DOMElements.globalForm.querySelector('button[type="submit"]');
// 从表单收集数据, 构建成后端需要的JSON结构
function getGlobalConfigFromForm() {
const formData = new FormData(DOMElements.globalForm);
const enableEch = DOMElements.enableEchCheckbox.checked;
return {
debug: DOMElements.globalForm.querySelector('[name="debug"]').checked,
ports_config: {
admin_port: formData.get('admin_port'),
http_port: parseInt(formData.get('http_port'), 10) || 80,
https_port: parseInt(formData.get('https_port'), 10) || 443,
},
metrics: DOMElements.globalForm.querySelector('[name="metrics"]').checked,
log_config: {
level: DOMElements.globalForm.querySelector('input[name="log_level"]').value,
rotate_size: formData.get('log_rotate_size'),
rotate_keep: formData.get('log_rotate_keep'),
rotate_keep_for_time: formData.get('log_rotate_keep_for_time'),
},
tls_config: {
enable_dns_challenge: DOMElements.enableDnsChallengeCheckbox.checked,
provider: DOMElements.globalForm.querySelector('input[name="tls_provider"]').value,
token: formData.get('tls_token'),
echouter_sni: enableEch ? formData.get('tls_ech_sni') : "",
email: formData.get('tls_email'),
},
tls_snippet_config: {},
};
}
// 用从API获取的数据填充表单
function fillGlobalConfigForm(config) {
if (!config) return;
DOMElements.globalForm.querySelector('[name="debug"]').checked = config.debug || false;
DOMElements.globalForm.querySelector('[name="metrics"]').checked = config.metrics || false;
const ports = config.ports_config || {};
DOMElements.globalForm.querySelector('[name="admin_port"]').value = ports.admin_port || ':2019';
DOMElements.globalForm.querySelector('[name="http_port"]').value = ports.http_port || 80;
DOMElements.globalForm.querySelector('[name="https_port"]').value = ports.https_port || 443;
const log = config.log_config || {};
const logLevelSelect = document.getElementById('select-log-level');
const logLevel = log.level || 'INFO';
if (logLevelSelect && logLevelSelect.querySelector('.select-selected')) {
logLevelSelect.querySelector('.select-selected').textContent = logLevel;
const hiddenInput = logLevelSelect.querySelector('input[name="log_level"]');
if (hiddenInput) hiddenInput.value = logLevel;
}
DOMElements.globalForm.querySelector('[name="log_rotate_size"]').value = log.rotate_size || '10MB';
DOMElements.globalForm.querySelector('[name="log_rotate_keep"]').value = log.rotate_keep || '10';
DOMElements.globalForm.querySelector('[name="log_rotate_keep_for_time"]').value = log.rotate_keep_for_time || '24h';
const tls = config.tls_config || {};
DOMElements.enableDnsChallengeCheckbox.checked = tls.enable_dns_challenge || false;
DOMElements.globalTlsConfigGroup.classList.toggle('hidden', !DOMElements.enableDnsChallengeCheckbox.checked);
const tlsProviderSelect = document.getElementById('select-tls-provider');
const provider = tls.provider || '';
if (tlsProviderSelect && provider && tlsProviderSelect.querySelector('.select-selected')) {
tlsProviderSelect.querySelector('.select-selected').textContent = provider;
const hiddenProviderInput = tlsProviderSelect.querySelector('input[name="tls_provider"]');
if (hiddenProviderInput) hiddenProviderInput.value = provider;
}
DOMElements.globalForm.querySelector('[name="tls_token"]').value = tls.token || '';
DOMElements.globalForm.querySelector('[name="tls_email"]').value = tls.email || '';
const echOuterSni = tls.echouter_sni || '';
DOMElements.enableEchCheckbox.checked = !!echOuterSni;
DOMElements.echConfigGroup.classList.toggle('hidden', !DOMElements.enableEchCheckbox.checked);
DOMElements.globalForm.querySelector('[name="tls_ech_sni"]').value = echOuterSni;
}
async function handleSaveGlobalConfig(e) {
e.preventDefault();
const configData = getGlobalConfigFromForm();
submitButton.disabled = true;
submitButton.querySelector('span').textContent = "保存中...";
try {
// 修正: 更新API端点路径
const result = await api.put('/global/config', configData);
notification.toast(result.message || '全局配置已成功保存Caddy正在重载...', 'success');
} catch (error) {
notification.toast(`保存失败: ${error.message}`, 'error');
} finally {
submitButton.disabled = false;
submitButton.querySelector('span').textContent = "保存并重载";
}
}
async function handleLogout() {
if (await notification.confirm('您确定要退出登录吗?')) {
notification.toast('正在退出...', 'info');
setTimeout(() => { window.location.href = '/v0/api/auth/logout'; }, 500);
}
}
function init() {
theme.init(DOMElements.themeToggleInput);
notification.init(DOMElements.toastContainer, DOMElements.dialogContainer);
activateNav('global');
initCaddyStatus();
// 修正: 更新API端点路径
api.get('/global/log/levels')
.then(levels => createCustomSelect('select-log-level', Object.keys(levels)))
.catch(err => notification.toast(`加载日志级别失败: ${err.message}`, 'error'));
// 修正: 更新API端点路径
api.get('/global/tls/providers')
.then(providers => createCustomSelect('select-tls-provider', Object.keys(providers)))
.catch(err => notification.toast(`加载TLS提供商失败: ${err.message}`, 'error'));
// 修正: 更新API端点路径
api.get('/global/config')
.then(config => fillGlobalConfigForm(config))
.catch(err => notification.toast(`加载全局配置失败: ${err.message}`, 'error'));
DOMElements.globalForm.addEventListener('submit', handleSaveGlobalConfig);
DOMElements.logoutBtn.addEventListener('click', handleLogout);
DOMElements.enableDnsChallengeCheckbox.addEventListener('change', (e) => {
DOMElements.globalTlsConfigGroup.classList.toggle('hidden', !e.target.checked);
});
DOMElements.enableEchCheckbox.addEventListener('change', (e) => {
DOMElements.echConfigGroup.classList.toggle('hidden', !e.target.checked);
});
}
init();