RAG/static/config/script.js

1690 lines
65 KiB
JavaScript
Raw Permalink Normal View History

2026-01-18 15:46:45 +08:00
// 配置管理系统 JavaScript
// 全局变量
let currentConfig = null;
let configList = [];
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
2026-01-22 13:04:29 +08:00
// 添加删除确认模态框的HTML
const deleteConfirmModalHTML = `
<div class="modal" id="deleteConfirmModal">
<div class="modal-content">
<div class="modal-header">
<h3>删除配置</h3>
<button class="close-btn" id="deleteConfirmCloseBtn">&times;</button>
</div>
<div class="modal-body">
<p>确定要删除这个配置吗此操作不可恢复</p>
<div class="modal-footer">
<button type="button" class="btn secondary" id="cancelDeleteBtn">取消</button>
<button type="button" class="btn danger" id="confirmDeleteBtn">删除</button>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', deleteConfirmModalHTML);
2026-01-18 15:46:45 +08:00
// 绑定事件监听器
bindEventListeners();
// 加载配置列表
loadConfigs();
});
// 绑定事件监听器
function bindEventListeners() {
2026-01-22 13:04:29 +08:00
// 配置类型选择
const configTypeSelect = document.getElementById('configTypeSelect');
// 选中下拉框选项后直接显示配置详情界面
configTypeSelect.addEventListener('change', function() {
if (this.value) {
handleAddConfigDirectly();
}
});
2026-01-18 15:46:45 +08:00
// 关闭添加配置模态框
document.getElementById('addConfigCloseBtn').addEventListener('click', hideAddConfigModal);
// 取消添加配置
document.getElementById('cancelAddBtn').addEventListener('click', hideAddConfigModal);
// 提交添加配置表单
document.getElementById('addConfigForm').addEventListener('submit', handleAddConfig);
// 保存配置按钮
document.getElementById('saveBtn').addEventListener('click', saveConfig);
// 删除配置按钮
document.getElementById('deleteBtn').addEventListener('click', showDeleteConfirm);
// 关闭删除确认模态框
document.getElementById('deleteConfirmCloseBtn').addEventListener('click', hideDeleteConfirmModal);
// 取消删除
document.getElementById('cancelDeleteBtn').addEventListener('click', hideDeleteConfirmModal);
// 确认删除
document.getElementById('confirmDeleteBtn').addEventListener('click', confirmDeleteConfig);
// 点击模态框外部关闭模态框
window.addEventListener('click', function(event) {
if (event.target.classList.contains('modal')) {
event.target.classList.remove('show');
}
});
}
// 加载配置列表
async function loadConfigs() {
try {
const response = await fetch('/folder-configs');
if (!response.ok) {
throw new Error('Failed to load configurations');
}
const data = await response.json();
configList = data.configurations;
// 渲染配置列表
renderConfigList();
// 如果没有选择任何配置,显示欢迎界面
if (!currentConfig) {
showWelcomeScreen();
} else {
// 重新加载当前配置
loadConfigDetails(currentConfig.id);
}
} catch (error) {
console.error('Error loading configurations:', error);
alert('加载配置失败: ' + error.message);
}
}
// 渲染配置列表
function renderConfigList() {
const configListElement = document.getElementById('configList');
configListElement.innerHTML = '';
if (configList.length === 0) {
configListElement.innerHTML = '<div style="text-align: center; padding: 20px; color: #666;">暂无配置</div>';
return;
}
configList.forEach(config => {
const configItem = document.createElement('div');
configItem.className = 'config-item';
configItem.dataset.id = config.id;
2026-01-22 13:04:29 +08:00
configItem.dataset.type = config.type;
2026-01-18 15:46:45 +08:00
if (currentConfig && config.id === currentConfig.id) {
configItem.classList.add('active');
}
2026-01-22 13:04:29 +08:00
// 生成配置描述信息
let configInfo = '';
if (config.type === 'database') {
const dbConfig = config.config;
if (dbConfig.database && dbConfig.table_name) {
configInfo = `${dbConfig.database}.${dbConfig.table_name}`;
} else if (dbConfig.database) {
configInfo = dbConfig.database;
}
2026-01-25 21:59:25 +08:00
} else if (config.type === 'folder') {
2026-01-22 13:04:29 +08:00
const folderConfig = config.config;
2026-01-25 21:59:25 +08:00
if (folderConfig.host && folderConfig.folder_path) {
configInfo = `${folderConfig.host}:${folderConfig.folder_path}`;
} else if (folderConfig.folder_path) {
2026-01-22 13:04:29 +08:00
configInfo = folderConfig.folder_path;
2026-01-25 21:59:25 +08:00
} else if (folderConfig.host) {
configInfo = folderConfig.host;
2026-01-22 13:04:29 +08:00
}
}
// 使用配置ID作为标题
const configName = config.id;
// 生成HTML结构
2026-01-18 15:46:45 +08:00
configItem.innerHTML = `
2026-01-22 13:04:29 +08:00
<div class="config-item-content">
<div class="config-item-details">
<div class="config-item-title">${configName}</div>
<div class="config-item-info">${configInfo}</div>
<div class="config-item-meta">
<div class="config-item-time">${new Date(config.update_at).toLocaleString()}</div>
</div>
</div>
</div>
2026-01-18 15:46:45 +08:00
`;
configItem.addEventListener('click', () => loadConfigDetails(config.id));
configListElement.appendChild(configItem);
});
}
// 加载配置详情
async function loadConfigDetails(configId) {
try {
// 查找配置
2026-01-22 13:04:29 +08:00
let config = configList.find(c => c.id === configId);
// 如果配置不存在,可能是刚创建的,尝试从服务器重新获取配置列表
if (!config) {
await loadConfigs();
config = configList.find(c => c.id === configId);
}
// 如果仍然找不到配置,说明真的有问题,直接报错
2026-01-18 15:46:45 +08:00
if (!config) {
throw new Error('配置不存在');
}
currentConfig = config;
// 更新配置列表选中状态
renderConfigList();
// 显示配置详情界面
showConfigScreen();
2026-01-22 13:04:29 +08:00
// 更新配置标题使用配置ID即文件名
2026-01-27 11:20:01 +08:00
if (config.id === null) {
document.getElementById('configTitle').textContent = '新增数据源';
} else {
document.getElementById('configTitle').textContent = config.id;
}
2026-01-18 15:46:45 +08:00
// 生成配置表单
generateConfigForm(config.config);
} catch (error) {
console.error('Error loading config details:', error);
alert('加载配置详情失败: ' + error.message);
}
}
// 生成配置表单
function generateConfigForm(config) {
const formElement = document.getElementById('configForm');
formElement.innerHTML = '';
// 基本信息部分
const basicSection = document.createElement('div');
basicSection.innerHTML = `
<h3 class="section-title">基本信息</h3>
2026-01-22 13:04:29 +08:00
<!-- 配置名称自动生成隐藏输入框 -->
<input type="text" id="formName" value="${config.name || ''}" style="display: none;">
2026-01-18 15:46:45 +08:00
<div class="form-group">
<label for="formType">配置类型</label>
<select id="formType" disabled>
<option value="database" ${config.type === 'database' ? 'selected' : ''}>数据库 (database)</option>
2026-01-25 21:59:25 +08:00
<option value="folder" ${config.type === 'folder' ? 'selected' : ''}>文件夹 (folder)</option>
<option value="git" ${config.type === 'git' ? 'selected' : ''}>Git代码库 (git)</option>
2026-01-18 15:46:45 +08:00
</select>
</div>
`;
formElement.appendChild(basicSection);
// 根据配置类型生成相应的表单字段
2026-01-25 21:59:25 +08:00
if (config.type === 'folder') {
2026-01-18 15:46:45 +08:00
const folderSection = document.createElement('div');
folderSection.innerHTML = `
<h3 class="section-title">文件夹配置</h3>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formFolderPath">文件夹路径 <span class="required">*</span></label>
2026-01-18 15:46:45 +08:00
<input type="text" id="formFolderPath" value="${config.folder_path || ''}" required>
</div>
<div class="form-group checkbox">
<input type="checkbox" id="formRecursive" ${config.recursive ? 'checked' : ''}>
<label for="formRecursive">递归扫描子文件夹</label>
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formIgnorePatterns">忽略的文件模式 (用逗号分隔示例*.log, *.tmp, node_modules/)</label>
2026-01-18 15:46:45 +08:00
<input type="text" id="formIgnorePatterns" value="${config.ignore_patterns ? config.ignore_patterns.join(', ') : ''}">
2026-01-22 13:04:29 +08:00
<div style="margin-top: 5px; font-size: 0.85em; color: #666;">
示例*.log, *.tmp, node_modules/
</div>
2026-01-18 15:46:45 +08:00
</div>
`;
formElement.appendChild(folderSection);
2026-01-22 13:04:29 +08:00
2026-01-18 15:46:45 +08:00
}
2026-01-25 21:59:25 +08:00
// 为folder添加SSH连接配置
if (config.type === 'folder') {
2026-01-22 13:04:29 +08:00
const sshSection = document.createElement('div');
sshSection.innerHTML = `
<h3 class="section-title">SSH连接配置</h3>
2026-01-18 15:46:45 +08:00
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formHost">主机地址 <span class="required">*</span></label>
2026-01-18 15:46:45 +08:00
<input type="text" id="formHost" value="${config.host || ''}" required>
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formPort">端口 <span class="required">*</span></label>
2026-01-18 15:46:45 +08:00
<input type="number" id="formPort" value="${config.port || 22}" min="1" max="65535" required>
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formUsername">用户名 <span class="required">*</span></label>
2026-01-18 15:46:45 +08:00
<input type="text" id="formUsername" value="${config.username || ''}" required>
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formPassword">密码 <span class="required">*</span></label>
<input type="password" id="formPassword" value="${config.password || ''}" required>
2026-01-18 15:46:45 +08:00
</div>
2026-01-26 15:09:12 +08:00
<div class="form-actions">
<button type="button" id="testSshConnectionBtn" class="btn secondary" style="margin-top: 10px;">🔌 测试SSH连接</button>
</div>
2026-01-18 15:46:45 +08:00
`;
2026-01-22 13:04:29 +08:00
formElement.appendChild(sshSection);
2026-01-26 15:09:12 +08:00
// 绑定事件
bindFolderEvents();
2026-01-18 15:46:45 +08:00
}
// Git代码库配置
if (config.type === 'git') {
const gitSection = document.createElement('div');
gitSection.innerHTML = `
<h3 class="section-title">Git代码库配置</h3>
<div class="form-group">
<label for="formGitUrl">Git仓库地址 <span class="required">*</span></label>
<input type="text" id="formGitUrl" value="${config.git_url || ''}" required>
</div>
<div class="form-group">
<label for="formBranch">分支名称</label>
<input type="text" id="formBranch" value="${config.branch || 'main'}">
</div>
<div class="form-group">
<label for="formProtocol">协议类型</label>
<select id="formProtocol">
<option value="https" ${config.protocol === 'https' ? 'selected' : ''}>HTTPS</option>
<option value="ssh" ${config.protocol === 'ssh' ? 'selected' : ''}>SSH</option>
</select>
</div>
<div class="form-group" id="httpsTokenGroup">
<label for="formHttpsToken">HTTPS令牌</label>
<input type="password" id="formHttpsToken" value="${config.https_token || ''}">
</div>
<div class="form-group" id="sshKeyGroup" style="display: none;">
<label for="formSshKey">SSH私钥</label>
<textarea id="formSshKey" rows="10" value="${config.ssh_key || ''}">${config.ssh_key || ''}</textarea>
</div>
<div class="form-group">
<label for="formPollInterval">轮询间隔</label>
<input type="number" id="formPollInterval" value="${config.poll_interval || 300}" min="60" max="3600">
</div>
<div class="form-actions">
<button type="button" id="testGitConnectionBtn" class="btn secondary" style="margin-top: 10px;">🔌 测试Git连接</button>
</div>
`;
formElement.appendChild(gitSection);
// 绑定事件
bindGitEvents();
}
2026-01-18 15:46:45 +08:00
if (config.type === 'database') {
2026-01-22 13:04:29 +08:00
// 数据库连接配置(放在前面,方便先测试连接)
const connectionSection = document.createElement('div');
connectionSection.innerHTML = `
<h3 class="section-title">数据库连接配置</h3>
<div class="form-group">
<label for="formDbType">数据库类型 <span class="required">*</span></label>
<select id="formDbType" required>
<option value="mysql" ${config.db_type === 'mysql' ? 'selected' : config.db_type === undefined ? 'selected' : ''}>MySQL</option>
<option value="dameng" ${config.db_type === 'dameng' ? 'selected' : ''}>达梦数据库</option>
</select>
</div>
2026-01-18 15:46:45 +08:00
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formMysqlHost">主机地址 <span class="required">*</span></label>
<input type="text" id="formMysqlHost" value="${config.mysql_host || ''}" required>
2026-01-18 15:46:45 +08:00
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formMysqlPort">端口 <span class="required">*</span></label>
<input type="number" id="formMysqlPort" value="${config.mysql_port || 3306}" min="1" max="65535" required>
2026-01-18 15:46:45 +08:00
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formMysqlUser">用户名 <span class="required">*</span></label>
<input type="text" id="formMysqlUser" value="${config.mysql_user || ''}" required>
2026-01-18 15:46:45 +08:00
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formMysqlPassword">密码 <span class="required">*</span></label>
<input type="password" id="formMysqlPassword" value="${config.mysql_password || ''}" required>
2026-01-18 15:46:45 +08:00
</div>
2026-01-22 13:04:29 +08:00
2026-01-18 15:46:45 +08:00
<div class="form-group">
2026-01-22 13:04:29 +08:00
<button type="button" id="testConnectionBtn" class="btn primary" style="margin-right: 10px;">🔌 测试连接</button>
<button type="button" id="getDatabasesBtn" class="btn primary">📋 获取数据库列表</button>
2026-01-18 15:46:45 +08:00
</div>
`;
2026-01-22 13:04:29 +08:00
formElement.appendChild(connectionSection);
2026-01-18 15:46:45 +08:00
2026-01-22 13:04:29 +08:00
const databaseSection = document.createElement('div');
databaseSection.innerHTML = `
<h3 class="section-title">数据库配置</h3>
2026-01-18 15:46:45 +08:00
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formDatabase">数据库名称 <span class="required">*</span></label>
<select id="formDatabase" required>
<option value="">-- 选择数据库 --</option>
</select>
2026-01-18 15:46:45 +08:00
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<button type="button" id="getTablesBtn" class="btn primary">📋 获取表列表</button>
2026-01-18 15:46:45 +08:00
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formTableName">表名 <span class="required">*</span></label>
<select id="formTableName" required>
<option value="">-- 选择表 --</option>
</select>
</div>
<div class="form-group">
<button type="button" id="getTableStructureBtn" class="btn primary">📋 获取表结构</button>
</div>
<div class="form-group">
<label for="formIdColumn">ID列 <span class="required">*</span></label>
<select id="formIdColumn" required>
<option value="">-- 选择ID列 --</option>
</select>
</div>
<div class="form-group">
<label>内容列可多选 <span class="required">*</span></label>
<div id="formContentColumn" class="checkbox-group"></div>
</div>
<div class="form-group">
<label for="formTitleColumn">标题列可选</label>
<select id="formTitleColumn">
<option value="">-- 选择标题列可选--</option>
</select>
2026-01-18 15:46:45 +08:00
</div>
<div class="form-group">
2026-01-22 13:04:29 +08:00
<label for="formUpdatedAtColumn">更新时间列可选</label>
<select id="formUpdatedAtColumn">
<option value="">-- 选择更新时间列可选--</option>
</select>
2026-01-18 15:46:45 +08:00
</div>
`;
2026-01-22 13:04:29 +08:00
formElement.appendChild(databaseSection);
// 设置初始值
const formDatabase = document.getElementById('formDatabase');
const formTableName = document.getElementById('formTableName');
if (config.database) {
// 添加已保存的数据库名称作为选项
const dbOption = document.createElement('option');
dbOption.value = config.database;
dbOption.textContent = config.database;
dbOption.selected = true;
formDatabase.appendChild(dbOption);
}
if (config.table_name) {
// 添加已保存的表名作为选项
const tableOption = document.createElement('option');
tableOption.value = config.table_name;
tableOption.textContent = config.table_name;
tableOption.selected = true;
formTableName.appendChild(tableOption);
}
// 如果有完整的数据库配置,尝试获取实际的数据表结构
if (config.database && config.table_name) {
// 尝试从后端获取实际的数据表结构
fetchTableStructure(config).then(columns => {
if (columns && columns.length > 0) {
// 更新列选择器,显示所有列
updateColumnSelectors(columns);
// 确保所有选择器都有正确的值
if (config.id_column) {
document.getElementById('formIdColumn').value = config.id_column;
}
if (config.title_column) {
document.getElementById('formTitleColumn').value = config.title_column;
}
// 处理内容列的选中状态(复选框组)
const contentColumns = config.content_column ? config.content_column.split(',') : [];
if (contentColumns.length > 0) {
const contentGroup = document.getElementById('formContentColumn');
const checkboxes = contentGroup.querySelectorAll('input[name="contentColumn"]');
checkboxes.forEach(checkbox => {
if (contentColumns.includes(checkbox.value)) {
checkbox.checked = true;
}
});
}
}
}).catch(error => {
console.error('获取表结构失败:', error);
// 如果获取失败,继续使用原有的模拟列列表
const mockColumns = [];
// 添加ID列
mockColumns.push({ name: config.id_column || '', type: '', key: 'PRI' });
// 添加内容列
const contentColumns = config.content_column ? config.content_column.split(',') : [];
contentColumns.forEach(colName => {
if (colName !== config.id_column) {
mockColumns.push({ name: colName, type: '', key: '' });
}
});
// 添加标题列
if (config.title_column && config.title_column !== config.id_column && !contentColumns.includes(config.title_column)) {
mockColumns.push({ name: config.title_column, type: '', key: '' });
}
// 更新列选择器
updateColumnSelectors(mockColumns);
});
}
// 确保所有选择器都有正确的值
if (config.id_column) {
document.getElementById('formIdColumn').value = config.id_column;
}
if (config.title_column) {
document.getElementById('formTitleColumn').value = config.title_column;
}
// 处理内容列的选中状态(复选框组)
const contentColumns = config.content_column ? config.content_column.split(',') : [];
if (contentColumns.length > 0) {
const contentGroup = document.getElementById('formContentColumn');
const checkboxes = contentGroup.querySelectorAll('input[name="contentColumn"]');
checkboxes.forEach(checkbox => {
if (contentColumns.includes(checkbox.value)) {
checkbox.checked = true;
}
});
}
// 绑定事件
bindDatabaseEvents();
// 绑定认证方式选择的事件
}
}
// 数据库事件绑定函数
function bindDatabaseEvents() {
// 测试数据库连接
document.getElementById('testConnectionBtn')?.addEventListener('click', async () => {
try {
const host = document.getElementById('formMysqlHost').value;
const port = parseInt(document.getElementById('formMysqlPort').value);
const username = document.getElementById('formMysqlUser').value;
const password = document.getElementById('formMysqlPassword').value;
const dbType = document.getElementById('formDbType').value;
2026-01-22 13:04:29 +08:00
if (!host || !username) {
alert('请填写主机地址和用户名');
return;
}
// SSH隧道配置
const useSshTunnel = document.getElementById('useSshTunnel')?.checked || false;
let sshConfig = {};
if (useSshTunnel) {
const sshHost = document.getElementById('formSshHost').value;
const sshPort = parseInt(document.getElementById('formSshPort').value || 22);
const sshUsername = document.getElementById('formSshUsername').value;
const sshPassword = document.getElementById('formSshPassword').value;
const sshKeyPath = document.getElementById('formSshKeyPathDisplay').value;
const sshKeyContent = document.getElementById('sshPrivateKeyContent')?.value || '';
if (!sshHost || !sshUsername) {
alert('请填写SSH主机地址和用户名');
return;
}
sshConfig = {
use_ssh_tunnel: true,
ssh_host: sshHost,
ssh_port: sshPort,
ssh_username: sshUsername,
ssh_password: sshPassword,
ssh_key_path: sshKeyPath,
ssh_key_content: sshKeyContent
};
}
// 禁用按钮
const btn = document.getElementById('testConnectionBtn');
const originalText = btn.textContent;
btn.textContent = '🔌 测试中...';
btn.disabled = true;
// 发送请求
const response = await fetch('/database/databases', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
host,
port,
username,
password,
db_type: dbType,
2026-01-22 13:04:29 +08:00
...sshConfig
})
});
if (response.ok) {
alert('数据库连接成功!');
} else {
const errorData = await response.json();
throw new Error(errorData.detail || '连接失败');
}
} catch (error) {
alert('数据库连接失败: ' + error.message);
} finally {
// 恢复按钮
const btn = document.getElementById('testConnectionBtn');
btn.textContent = '🔌 测试连接';
btn.disabled = false;
}
});
// 获取数据库列表
document.getElementById('getDatabasesBtn')?.addEventListener('click', async () => {
try {
const host = document.getElementById('formMysqlHost').value;
const port = parseInt(document.getElementById('formMysqlPort').value);
const username = document.getElementById('formMysqlUser').value;
const password = document.getElementById('formMysqlPassword').value;
const dbType = document.getElementById('formDbType').value;
2026-01-22 13:04:29 +08:00
if (!host || !username) {
alert('请填写主机地址和用户名');
return;
}
// SSH隧道配置
const useSshTunnel = document.getElementById('useSshTunnel')?.checked || false;
let sshConfig = {};
if (useSshTunnel) {
const sshHost = document.getElementById('formSshHost').value;
const sshPort = parseInt(document.getElementById('formSshPort').value || 22);
const sshUsername = document.getElementById('formSshUsername').value;
const sshPassword = document.getElementById('formSshPassword').value;
const sshKeyPath = document.getElementById('formSshKeyPathDisplay').value;
const sshKeyContent = document.getElementById('sshPrivateKeyContent')?.value || '';
if (!sshHost || !sshUsername) {
alert('请填写SSH主机地址和用户名');
return;
}
sshConfig = {
use_ssh_tunnel: true,
ssh_host: sshHost,
ssh_port: sshPort,
ssh_username: sshUsername,
ssh_password: sshPassword,
ssh_key_path: sshKeyPath,
ssh_key_content: sshKeyContent
};
}
// 禁用按钮
const btn = document.getElementById('getDatabasesBtn');
const originalText = btn.textContent;
btn.textContent = '📋 获取中...';
btn.disabled = true;
// 发送请求
const response = await fetch('/database/databases', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
host,
port,
username,
password,
db_type: dbType,
2026-01-22 13:04:29 +08:00
...sshConfig
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || '获取失败');
}
const data = await response.json();
const databases = data.databases;
// 更新下拉列表
const select = document.getElementById('formDatabase');
select.innerHTML = '<option value="">-- 选择数据库 --</option>';
databases.forEach(db => {
const option = document.createElement('option');
option.value = db;
option.textContent = db;
select.appendChild(option);
});
alert(`成功获取 ${databases.length} 个数据库`);
} catch (error) {
alert('获取数据库列表失败: ' + error.message);
} finally {
// 恢复按钮
const btn = document.getElementById('getDatabasesBtn');
btn.textContent = '📋 获取数据库列表';
btn.disabled = false;
}
});
// 获取表列表
document.getElementById('getTablesBtn')?.addEventListener('click', async () => {
try {
const host = document.getElementById('formMysqlHost').value;
const port = parseInt(document.getElementById('formMysqlPort').value);
const username = document.getElementById('formMysqlUser').value;
const password = document.getElementById('formMysqlPassword').value;
const database = document.getElementById('formDatabase').value;
const dbType = document.getElementById('formDbType').value;
2026-01-22 13:04:29 +08:00
if (!host || !username || !database) {
alert('请填写完整的数据库连接信息并选择数据库');
return;
}
// SSH隧道配置
const useSshTunnel = document.getElementById('useSshTunnel')?.checked || false;
let sshConfig = {};
if (useSshTunnel) {
const sshHost = document.getElementById('formSshHost').value;
const sshPort = parseInt(document.getElementById('formSshPort').value || 22);
const sshUsername = document.getElementById('formSshUsername').value;
const sshPassword = document.getElementById('formSshPassword').value;
const sshKeyPath = document.getElementById('formSshKeyPathDisplay').value;
const sshKeyContent = document.getElementById('sshPrivateKeyContent')?.value || '';
if (!sshHost || !sshUsername) {
alert('请填写SSH主机地址和用户名');
return;
}
sshConfig = {
use_ssh_tunnel: true,
ssh_host: sshHost,
ssh_port: sshPort,
ssh_username: sshUsername,
ssh_password: sshPassword,
ssh_key_path: sshKeyPath,
ssh_key_content: sshKeyContent
};
}
// 禁用按钮
const btn = document.getElementById('getTablesBtn');
const originalText = btn.textContent;
btn.textContent = '📋 获取中...';
btn.disabled = true;
// 发送请求
const response = await fetch('/database/tables', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
host,
port,
username,
password,
database,
db_type: dbType,
2026-01-22 13:04:29 +08:00
...sshConfig
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || '获取失败');
}
const data = await response.json();
const tables = data.tables;
// 更新下拉列表
const select = document.getElementById('formTableName');
select.innerHTML = '<option value="">-- 选择表 --</option>';
tables.forEach(table => {
const option = document.createElement('option');
option.value = table;
option.textContent = table;
select.appendChild(option);
});
alert(`成功获取 ${tables.length} 个表`);
} catch (error) {
alert('获取表列表失败: ' + error.message);
} finally {
// 恢复按钮
const btn = document.getElementById('getTablesBtn');
btn.textContent = '📋 获取表列表';
btn.disabled = false;
}
});
// 获取表结构
document.getElementById('getTableStructureBtn')?.addEventListener('click', async () => {
try {
const host = document.getElementById('formMysqlHost').value;
const port = parseInt(document.getElementById('formMysqlPort').value);
const username = document.getElementById('formMysqlUser').value;
const password = document.getElementById('formMysqlPassword').value;
const database = document.getElementById('formDatabase').value;
const table_name = document.getElementById('formTableName').value;
const dbType = document.getElementById('formDbType').value;
2026-01-22 13:04:29 +08:00
if (!host || !username || !database || !table_name) {
alert('请填写完整的数据库连接信息并选择数据库和表');
return;
}
// SSH隧道配置
const useSshTunnel = document.getElementById('useSshTunnel')?.checked || false;
let sshConfig = {};
if (useSshTunnel) {
const sshHost = document.getElementById('formSshHost').value;
const sshPort = parseInt(document.getElementById('formSshPort').value || 22);
const sshUsername = document.getElementById('formSshUsername').value;
const sshPassword = document.getElementById('formSshPassword').value;
const sshKeyPath = document.getElementById('formSshKeyPathDisplay').value;
const sshKeyContent = document.getElementById('sshPrivateKeyContent')?.value || '';
if (!sshHost || !sshUsername) {
alert('请填写SSH主机地址和用户名');
return;
}
sshConfig = {
use_ssh_tunnel: true,
ssh_host: sshHost,
ssh_port: sshPort,
ssh_username: sshUsername,
ssh_password: sshPassword,
ssh_key_path: sshKeyPath,
ssh_key_content: sshKeyContent
};
}
// 禁用按钮
const btn = document.getElementById('getTableStructureBtn');
const originalText = btn.textContent;
btn.textContent = '📋 获取中...';
btn.disabled = true;
// 发送请求
const response = await fetch('/database/table-structure', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
host,
port,
username,
password,
database,
table_name,
db_type: dbType,
2026-01-22 13:04:29 +08:00
...sshConfig
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || '获取失败');
}
const data = await response.json();
const columns = data.columns;
// 更新所有列选择器
updateColumnSelectors(columns);
alert(`成功获取表结构,共 ${columns.length}`);
} catch (error) {
alert('获取表结构失败: ' + error.message);
} finally {
// 恢复按钮
const btn = document.getElementById('getTableStructureBtn');
btn.textContent = '📋 获取表结构';
btn.disabled = false;
}
});
// 自动填充已有的列信息
const fillExistingColumns = () => {
const database = document.getElementById('formDatabase').value;
const table_name = document.getElementById('formTableName').value;
if (database && table_name && currentConfig) {
// 如果有当前配置,尝试获取表结构
document.getElementById('getTableStructureBtn')?.click();
}
};
// 监听数据库和表选择变化
document.getElementById('formDatabase')?.addEventListener('change', async () => {
// 清除表选择
document.getElementById('formTableName').innerHTML = '<option value="">-- 选择表 --</option>';
// 清除列选择
clearColumnSelectors();
});
document.getElementById('formTableName')?.addEventListener('change', fillExistingColumns);
}
// 更新列选择器
function updateColumnSelectors(columns) {
// ID列选择器
const idSelect = document.getElementById('formIdColumn');
idSelect.innerHTML = '<option value="">-- 选择ID列 --</option>';
// 内容列选择器(改为复选框组)
const contentGroup = document.getElementById('formContentColumn');
contentGroup.innerHTML = '';
// 标题列选择器
const titleSelect = document.getElementById('formTitleColumn');
titleSelect.innerHTML = '<option value="">-- 选择标题列(可选)--</option>';
// 更新时间列选择器
const updatedAtSelect = document.getElementById('formUpdatedAtColumn');
updatedAtSelect.innerHTML = '<option value="">-- 选择更新时间列(可选)--</option>';
// 文件列选择器 - 只在元素存在时操作database类型配置中已删除
const fileSelect = document.getElementById('formFileColumn');
// 填充选项
columns.forEach(col => {
const colName = col.name;
const colType = col.type;
// 添加到ID列选择器优先选择主键
const idOption = document.createElement('option');
idOption.value = colName;
idOption.textContent = colName + (col.key === 'PRI' ? ' (主键)' : '');
idSelect.appendChild(idOption);
// 如果是主键,默认选中
if (col.key === 'PRI') {
idSelect.value = colName;
}
// 添加到内容列选择器(复选框组)
const checkboxItem = document.createElement('label');
// 类型为空时不显示类型信息
const displayText = colType ? `${colName} (${colType})` : colName;
checkboxItem.innerHTML = `
<input type="checkbox" name="contentColumn" value="${colName}">
<span>${displayText}</span>
`;
contentGroup.appendChild(checkboxItem);
// 添加到文件列选择器 - 只在元素存在时操作database类型配置中已删除
if (fileSelect) {
const fileOption = document.createElement('option');
fileOption.value = colName;
fileOption.textContent = colType ? `${colName} (${colType})` : colName;
fileSelect.appendChild(fileOption);
}
// 添加到标题列选择器
const titleOption = document.createElement('option');
titleOption.value = colName;
titleOption.textContent = colType ? `${colName} (${colType})` : colName;
titleSelect.appendChild(titleOption);
// 添加到更新时间列选择器
const updatedAtOption = document.createElement('option');
updatedAtOption.value = colName;
updatedAtOption.textContent = colType ? `${colName} (${colType})` : colName;
updatedAtSelect.appendChild(updatedAtOption);
});
// 如果有当前配置,保持选中状态
if (currentConfig) {
const config = currentConfig.config;
if (config.id_column) {
idSelect.value = config.id_column;
}
// 处理内容列的选中状态(复选框组)
const contentColumns = config.content_column ? config.content_column.split(',') : [];
if (contentColumns.length > 0) {
const checkboxes = contentGroup.querySelectorAll('input[name="contentColumn"]');
checkboxes.forEach(checkbox => {
if (contentColumns.includes(checkbox.value)) {
checkbox.checked = true;
}
});
}
if (config.title_column) {
titleSelect.value = config.title_column;
}
if (config.updated_at_column) {
updatedAtSelect.value = config.updated_at_column;
}
}
}
// 清除列选择器
function clearColumnSelectors() {
document.getElementById('formIdColumn').innerHTML = '<option value="">-- 选择ID列 --</option>';
document.getElementById('formContentColumn').innerHTML = '';
// 文件列选择器 - 只在元素存在时操作database类型配置中已删除
const fileSelect = document.getElementById('formFileColumn');
if (fileSelect) {
fileSelect.innerHTML = '<option value="">-- 选择文件列(可选)--</option>';
}
document.getElementById('formTitleColumn').innerHTML = '<option value="">-- 选择标题列(可选)--</option>';
document.getElementById('formUpdatedAtColumn').innerHTML = '<option value="">-- 选择更新时间列(可选)--</option>';
}
// 获取数据表结构
async function fetchTableStructure(config) {
try {
// 确保有必要的连接信息
if (!config.mysql_host || !config.mysql_user) {
throw new Error('缺少数据库连接信息');
}
// 发送请求获取表结构
const response = await fetch('/database/table-structure', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
host: config.mysql_host,
port: config.mysql_port || 3306,
username: config.mysql_user,
password: config.mysql_password || '',
database: config.database,
table_name: config.table_name,
db_type: config.db_type || 'mysql'
2026-01-22 13:04:29 +08:00
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || '获取表结构失败');
}
const data = await response.json();
return data.columns;
} catch (error) {
console.error('获取表结构失败:', error);
throw error;
2026-01-18 15:46:45 +08:00
}
}
// 显示欢迎界面
function showWelcomeScreen() {
document.getElementById('welcomeScreen').style.display = 'flex';
document.getElementById('configScreen').style.display = 'none';
currentConfig = null;
}
// 显示配置详情界面
function showConfigScreen() {
document.getElementById('welcomeScreen').style.display = 'none';
document.getElementById('configScreen').style.display = 'flex';
}
// 显示添加配置模态框
function showAddConfigModal() {
document.getElementById('addConfigModal').classList.add('show');
// 添加配置类型选择的事件监听器
const configTypeSelect = document.getElementById('configType');
const dbTypeGroup = document.getElementById('dbTypeGroup');
configTypeSelect.addEventListener('change', function() {
if (this.value === 'database') {
dbTypeGroup.style.display = 'block';
} else {
dbTypeGroup.style.display = 'none';
}
});
// 触发一次change事件确保初始状态正确
configTypeSelect.dispatchEvent(new Event('change'));
2026-01-18 15:46:45 +08:00
}
// 隐藏添加配置模态框
function hideAddConfigModal() {
document.getElementById('addConfigModal').classList.remove('show');
document.getElementById('addConfigForm').reset();
}
2026-01-22 13:04:29 +08:00
// 直接创建配置(根据下拉框选择的类型)
async function handleAddConfigDirectly() {
// 获取选择的配置类型
const configTypeSelect = document.getElementById('configTypeSelect');
const configType = configTypeSelect.value;
// 检查是否选择了类型
if (!configType) {
alert('请选择配置类型');
return;
}
// 根据配置类型创建一个临时的配置对象
let tempConfig;
if (configType === 'database') {
tempConfig = {
type: configType,
mysql_host: '',
mysql_port: 3306,
mysql_password: '',
database: '',
table_name: '',
id_column: '',
content_column: '',
db_type: 'mysql'
2026-01-22 13:04:29 +08:00
};
2026-01-25 21:59:25 +08:00
} else if (configType === 'folder') {
2026-01-22 13:04:29 +08:00
tempConfig = {
type: configType,
folder_path: '',
recursive: true,
ignore_patterns: [],
host: '',
port: 22,
username: '',
password: ''
};
} else if (configType === 'git') {
tempConfig = {
type: configType,
git_url: '',
branch: 'main',
protocol: 'https',
https_token: '',
ssh_key: '',
poll_interval: 300
};
2026-01-22 13:04:29 +08:00
} else {
alert('不支持的配置类型');
return;
}
// 直接设置当前配置,不立即发送到后端
currentConfig = {
id: null, // 临时ID保存时由后端生成
config: tempConfig
};
// 渲染配置表单
generateConfigForm(tempConfig);
// 切换到配置详情界面
showConfigScreen();
2026-01-27 11:20:01 +08:00
// 更新配置标题为"新增数据源"
document.getElementById('configTitle').textContent = '新增数据源';
2026-01-22 13:04:29 +08:00
// 重置类型选择
configTypeSelect.value = '';
// 提示用户需要填写配置信息
alert('请填写配置信息,然后点击保存按钮创建配置');
}
// 处理添加配置(旧的模态框方式,保留以便兼容)
2026-01-18 15:46:45 +08:00
async function handleAddConfig(event) {
event.preventDefault();
// 获取表单数据
const formData = new FormData(event.target);
2026-01-22 13:04:29 +08:00
const configType = formData.get('type');
const configName = formData.get('name');
const dbType = formData.get('dbType') || 'mysql';
2026-01-22 13:04:29 +08:00
// 根据配置类型创建不同的配置对象
let configData;
if (configType === 'database') {
configData = {
name: configName,
type: configType,
mysql_host: '',
mysql_port: 3306,
mysql_password: '',
database: '',
table_name: '',
id_column: '',
content_column: '',
db_type: dbType
2026-01-22 13:04:29 +08:00
};
2026-01-25 21:59:25 +08:00
} else if (configType === 'folder') {
2026-01-22 13:04:29 +08:00
configData = {
name: configName,
type: configType,
folder_path: '',
recursive: true,
ignore_patterns: [],
host: '',
port: 22,
username: '',
password: ''
};
} else {
alert('不支持的配置类型');
return;
}
2026-01-18 15:46:45 +08:00
try {
// 创建新配置
2026-01-22 13:04:29 +08:00
const response = await fetch('/folder-configs', {
2026-01-18 15:46:45 +08:00
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(configData)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || 'Failed to create config');
}
const newConfig = await response.json();
// 隐藏模态框
hideAddConfigModal();
2026-01-22 13:04:29 +08:00
// 刷新配置列表并等待完成
await loadConfigs();
2026-01-18 15:46:45 +08:00
// 加载新配置详情
loadConfigDetails(newConfig.id);
} catch (error) {
console.error('Error creating config:', error);
alert('创建配置失败: ' + error.message);
}
}
// 保存配置
async function saveConfig() {
if (!currentConfig) {
alert('没有选中的配置');
return;
}
try {
// 收集表单数据
const formData = collectFormData();
2026-01-22 13:04:29 +08:00
console.log(formData);
2026-01-18 15:46:45 +08:00
2026-01-22 13:04:29 +08:00
// 检查必要的信息是否都填写了
let missingFields = [];
2026-01-18 15:46:45 +08:00
2026-01-22 13:04:29 +08:00
// 检查基本信息
if (!formData.type) missingFields.push('配置类型');
// 自动生成配置名称(如果为空)
if (!formData.name) {
let generatedName = '';
if (formData.type === 'database') {
// 数据库配置database_数据库名_表名
generatedName = `database_${formData.database || 'unknown'}_${formData.table_name || 'unknown'}`;
2026-01-25 21:59:25 +08:00
} else if (formData.type === 'folder') {
// 文件夹folder_主机_文件夹路径替换特殊字符
2026-01-22 13:04:29 +08:00
const folderName = formData.folder_path ? formData.folder_path.replace(/[\\/:*?"<>|]/g, '_') : 'unknown';
2026-01-25 21:59:25 +08:00
generatedName = `folder_${formData.host || 'unknown'}_${folderName}`;
} else if (formData.type === 'git') {
// Git配置git_仓库地址替换特殊字符
const repoName = formData.git_url ? formData.git_url.replace(/[\\/:*?"<>|]/g, '_') : 'unknown';
generatedName = `git_${repoName}_${formData.branch || 'main'}`;
2026-01-22 13:04:29 +08:00
} else {
2026-01-25 21:59:25 +08:00
// 不支持的配置类型
alert('不支持的配置类型');
return;
2026-01-22 13:04:29 +08:00
}
formData.name = generatedName;
2026-01-22 13:04:29 +08:00
}
// 根据不同类型检查特定字段
if (formData.type === 'database') {
if (!formData.mysql_host) missingFields.push('数据库主机');
if (!formData.mysql_port) missingFields.push('数据库端口');
if (!formData.mysql_user) missingFields.push('数据库用户名');
if (!formData.mysql_password) missingFields.push('数据库密码');
if (!formData.database) missingFields.push('数据库名称');
if (!formData.table_name) missingFields.push('表名');
if (!formData.id_column) missingFields.push('ID列');
if (!formData.content_column || formData.content_column.trim() === '') {
missingFields.push('内容列');
}
2026-01-25 21:59:25 +08:00
} else if (formData.type === 'folder') {
2026-01-22 13:04:29 +08:00
if (!formData.folder_path) missingFields.push('文件夹路径');
if (!formData.host) missingFields.push('主机地址');
if (!formData.port) missingFields.push('端口');
if (!formData.username) missingFields.push('用户名');
if (!formData.password) missingFields.push('密码');
} else if (formData.type === 'git') {
if (!formData.git_url) missingFields.push('Git仓库地址');
if (!formData.branch) missingFields.push('分支名称');
if (!formData.protocol) missingFields.push('协议类型');
2026-01-22 13:04:29 +08:00
}
// 如果有缺失的字段,提示用户
if (missingFields.length > 0) {
alert('请填写以下必要信息:\n' + missingFields.join('\n'));
return;
}
// 更新当前配置 - 直接使用新的表单数据作为完整配置,这样可以删除不再需要的旧字段
currentConfig.config = formData;
// 根据当前配置ID决定使用POST还是PUT方法
let response;
if (currentConfig.id === null) {
// 新配置使用POST方法创建
response = await fetch('/folder-configs', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(currentConfig.config)
});
} else {
// 现有配置使用PUT方法更新
response = await fetch(`/folder-configs/${currentConfig.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(currentConfig.config)
});
}
2026-01-18 15:46:45 +08:00
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || 'Failed to save config');
}
2026-01-22 13:04:29 +08:00
// 获取保存/更新后的配置
const updatedConfig = await response.json();
2026-01-25 21:59:25 +08:00
// 检查是否是新配置POST
const isNewConfig = currentConfig.id === null;
2026-01-22 13:04:29 +08:00
// 更新当前配置的ID
currentConfig.id = updatedConfig.id;
2026-01-18 15:46:45 +08:00
// 刷新配置列表
2026-01-22 13:04:29 +08:00
await loadConfigs();
// 使用新的ID重新加载配置详情
loadConfigDetails(updatedConfig.id);
2026-01-18 15:46:45 +08:00
2026-01-22 13:04:29 +08:00
// 根据配置类型执行不同的同步操作
try {
// 数据源名称是配置的ID而不是config中的name字段
const sourceName = updatedConfig.id;
2026-01-25 21:59:25 +08:00
if (isNewConfig) {
2026-01-22 13:04:29 +08:00
// 新配置POST保存成功后立刻启动数据源的同步操作
alert('配置保存成功,正在启动同步...');
// 启动同步
const syncResponse = await fetch('/sync', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
full_sync: true,
source_name: sourceName
})
});
if (syncResponse.ok) {
const syncResult = await syncResponse.json();
alert('同步已启动:' + syncResult.message);
} else {
throw new Error('同步启动失败');
}
} else {
// 现有配置PUT保存成功后先删除chromadb中已有的知识然后立刻启动数据源的同步操作
alert('配置更新成功,正在清理旧数据并启动同步...');
// 1. 删除旧数据
const deleteResponse = await fetch(`/documents/source/${encodeURIComponent(sourceName)}`, {
method: 'DELETE'
});
if (!deleteResponse.ok) {
throw new Error('删除旧数据失败');
}
// 2. 启动同步
const syncResponse = await fetch('/sync', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
full_sync: true,
source_name: sourceName
})
});
if (syncResponse.ok) {
const syncResult = await syncResponse.json();
alert('数据清理完成,同步已启动:' + syncResult.message);
} else {
throw new Error('同步启动失败');
}
}
} catch (error) {
console.error('同步操作失败:', error);
alert('配置保存成功,但同步操作失败:' + error.message);
}
// 重新渲染配置列表
renderConfigList();
2026-01-18 15:46:45 +08:00
} catch (error) {
console.error('Error saving config:', error);
alert('保存配置失败: ' + error.message);
}
}
// 收集表单数据
function collectFormData() {
const formData = {};
// 基本信息
formData.name = document.getElementById('formName').value;
formData.type = document.getElementById('formType').value;
// 文件夹配置
2026-01-25 21:59:25 +08:00
if (formData.type === 'folder') {
2026-01-18 15:46:45 +08:00
formData.folder_path = document.getElementById('formFolderPath').value;
formData.recursive = document.getElementById('formRecursive').checked;
const ignorePatterns = document.getElementById('formIgnorePatterns').value;
formData.ignore_patterns = ignorePatterns ? ignorePatterns.split(',').map(p => p.trim()) : [];
2026-01-25 21:59:25 +08:00
// 文件夹的SSH配置
2026-01-18 15:46:45 +08:00
formData.host = document.getElementById('formHost').value;
formData.port = parseInt(document.getElementById('formPort').value);
formData.username = document.getElementById('formUsername').value;
formData.password = document.getElementById('formPassword').value;
}
// 数据库配置
if (formData.type === 'database') {
formData.database = document.getElementById('formDatabase').value;
formData.table_name = document.getElementById('formTableName').value;
formData.id_column = document.getElementById('formIdColumn').value;
2026-01-22 13:04:29 +08:00
// 收集多选的内容列
const contentGroup = document.getElementById('formContentColumn');
const checkedBoxes = Array.from(contentGroup.querySelectorAll('input[name="contentColumn"]:checked'));
formData.content_column = checkedBoxes.map(checkbox => checkbox.value).join(','); // 转换为逗号分隔的字符串
2026-01-18 15:46:45 +08:00
formData.title_column = document.getElementById('formTitleColumn').value;
2026-01-22 13:04:29 +08:00
formData.updated_at_column = document.getElementById('formUpdatedAtColumn').value;
2026-01-18 15:46:45 +08:00
// 数据库连接配置
formData.mysql_host = document.getElementById('formMysqlHost').value;
formData.mysql_port = parseInt(document.getElementById('formMysqlPort').value);
formData.mysql_user = document.getElementById('formMysqlUser').value;
formData.mysql_password = document.getElementById('formMysqlPassword').value;
formData.db_type = document.getElementById('formDbType').value;
2026-01-22 13:04:29 +08:00
2026-01-25 21:59:25 +08:00
2026-01-22 13:04:29 +08:00
2026-01-18 15:46:45 +08:00
}
// Git配置
if (formData.type === 'git') {
formData.git_url = document.getElementById('formGitUrl').value;
formData.branch = document.getElementById('formBranch').value;
formData.protocol = document.getElementById('formProtocol').value;
formData.https_token = document.getElementById('formHttpsToken').value;
formData.ssh_key = document.getElementById('formSshKey').value;
formData.poll_interval = parseInt(document.getElementById('formPollInterval').value);
}
2026-01-18 15:46:45 +08:00
return formData;
}
// 显示删除确认
function showDeleteConfirm() {
if (!currentConfig) {
alert('没有选中的配置');
return;
}
document.getElementById('deleteConfirmModal').classList.add('show');
}
// 隐藏删除确认模态框
function hideDeleteConfirmModal() {
document.getElementById('deleteConfirmModal').classList.remove('show');
}
// 确认删除配置
async function confirmDeleteConfig() {
if (!currentConfig) {
alert('没有选中的配置');
return;
}
try {
const response = await fetch(`/folder-configs/${currentConfig.id}`, {
method: 'DELETE'
});
if (!response.ok) {
throw new Error('Failed to delete config');
}
// 隐藏模态框
hideDeleteConfirmModal();
// 刷新配置列表
loadConfigs();
// 显示欢迎界面
showWelcomeScreen();
alert('配置删除成功');
} catch (error) {
console.error('Error deleting config:', error);
alert('删除配置失败: ' + error.message);
}
}
// Git事件绑定函数
function bindGitEvents() {
// 协议切换逻辑
const protocolSelect = document.getElementById('formProtocol');
const httpsTokenGroup = document.getElementById('httpsTokenGroup');
const sshKeyGroup = document.getElementById('sshKeyGroup');
protocolSelect.addEventListener('change', function() {
const protocol = this.value;
if (protocol === 'https') {
httpsTokenGroup.style.display = 'block';
sshKeyGroup.style.display = 'none';
} else if (protocol === 'ssh') {
httpsTokenGroup.style.display = 'none';
sshKeyGroup.style.display = 'block';
}
});
// 触发一次change事件确保初始状态正确
protocolSelect.dispatchEvent(new Event('change'));
// 测试Git连接
document.getElementById('testGitConnectionBtn')?.addEventListener('click', async () => {
try {
const gitUrl = document.getElementById('formGitUrl').value;
const branch = document.getElementById('formBranch').value;
const protocol = document.getElementById('formProtocol').value;
const httpsToken = document.getElementById('formHttpsToken').value;
const sshKey = document.getElementById('formSshKey').value;
if (!gitUrl) {
alert('请填写Git仓库地址');
return;
}
// 禁用按钮
const btn = document.getElementById('testGitConnectionBtn');
const originalText = btn.textContent;
btn.textContent = '🔌 测试中...';
btn.disabled = true;
// 发送请求
const response = await fetch('/git/test-connection', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
git_url: gitUrl,
branch: branch,
protocol: protocol,
https_token: httpsToken,
ssh_key: sshKey
})
});
if (response.ok) {
const result = await response.json();
alert('Git连接测试成功');
} else {
const errorData = await response.json();
throw new Error(errorData.detail || '连接失败');
}
} catch (error) {
alert('Git连接测试失败: ' + error.message);
} finally {
// 恢复按钮
const btn = document.getElementById('testGitConnectionBtn');
btn.textContent = '🔌 测试Git连接';
btn.disabled = false;
}
});
}
2026-01-26 15:09:12 +08:00
// 为文件夹配置添加事件绑定
function bindFolderEvents() {
// 测试SSH连接
const testBtn = document.getElementById('testSshConnectionBtn');
if (testBtn) {
testBtn.onclick = async () => {
try {
const host = document.getElementById('formHost').value;
const port = parseInt(document.getElementById('formPort').value);
const username = document.getElementById('formUsername').value;
const password = document.getElementById('formPassword').value;
if (!host || !username) {
alert('请填写主机地址和用户名');
return;
}
// 禁用按钮
const btn = document.getElementById('testSshConnectionBtn');
const originalText = btn.textContent;
btn.textContent = '🔌 测试中...';
btn.disabled = true;
// 发送请求
const response = await fetch('/folder/test-connection', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
host,
port,
username,
password
})
});
if (response.ok) {
alert('SSH连接成功');
} else {
const errorData = await response.json();
throw new Error(errorData.detail || '连接失败');
}
} catch (error) {
alert('SSH连接失败: ' + error.message);
} finally {
// 恢复按钮
const btn = document.getElementById('testSshConnectionBtn');
btn.textContent = '🔌 测试SSH连接';
btn.disabled = false;
}
};
}
}
2026-01-18 15:46:45 +08:00
// 添加CSS样式确保模态框显示
const style = document.createElement('style');
style.textContent = `
.modal {
display: none;
}
.modal.show {
display: block;
}
`;
document.head.appendChild(style);
2026-01-26 15:09:12 +08:00
// 绑定事件
bindDatabaseEvents();
2026-01-22 13:04:29 +08:00