// 全局变量存储 JWT 令牌
let authToken = localStorage.getItem('auth_token');
$(document).ready(function() {
// 检查认证状态
if (!authToken) {
window.location.href = '/login';
return;
}
// 设置 AJAX 默认配置
$.ajaxSetup({
beforeSend: function(xhr, settings) {
// 不为登录请求添加认证头
if (settings.url === '/api/auth/login') {
return;
}
if (authToken) {
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
}
},
error: function(xhr, status, error) {
// 如果收到 401,重定向到登录页
if (xhr.status === 401) {
localStorage.removeItem('auth_token');
window.location.href = '/login';
return;
}
handleAjaxError(xhr, status, error);
}
});
// 初始化工具提示
$('[data-bs-toggle="tooltip"]').tooltip();
// 加载初始数据
loadProjects();
loadAPIKeys();
loadLogs();
checkHealth();
loadHealthDetails();
loadStatsDetails();
// 设置定期健康检查
setInterval(checkHealth, 30000);
// 项目管理
$('#addProjectForm').on('submit', function(e) {
e.preventDefault();
const projectData = {
name: $('#projectName').val(),
jenkinsJob: $('#jenkinsJob').val(),
giteaRepo: $('#giteaRepo').val()
};
$.ajax({
url: '/api/projects/',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(projectData),
success: function() {
$('#addProjectModal').modal('hide');
$('#addProjectForm')[0].reset();
loadProjects();
showSuccess('项目添加成功');
},
error: handleAjaxError
});
});
// API 密钥管理
$('#generateKeyForm').on('submit', function(e) {
e.preventDefault();
$.ajax({
url: '/api/keys',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({ description: $('#keyDescription').val() }),
success: function(response) {
$('#generateKeyModal').modal('hide');
$('#generateKeyForm')[0].reset();
loadAPIKeys();
showSuccess('API 密钥生成成功');
// 显示新生成的密钥
showApiKeyModal(response.key);
},
error: handleAjaxError
});
});
// 日志查询
$('#logQueryForm').on('submit', function(e) {
e.preventDefault();
loadLogs({
startTime: $('#startTime').val(),
endTime: $('#endTime').val(),
level: $('#logLevel').val(),
query: $('#logQuery').val()
});
});
// 标签页切换
$('.nav-link').on('click', function() {
$('.nav-link').removeClass('active');
$(this).addClass('active');
});
});
function loadProjects() {
$.get('/api/projects/')
.done(function(data) {
const tbody = $('#projectsTable tbody');
tbody.empty();
data.projects.forEach(function(project) {
tbody.append(`
| ${escapeHtml(project.name)} |
${escapeHtml(project.jenkinsJob)} |
${escapeHtml(project.giteaRepo)} |
|
`);
});
})
.fail(handleAjaxError);
}
function loadAPIKeys() {
$.get('/api/keys')
.done(function(data) {
const tbody = $('#apiKeysTable tbody');
tbody.empty();
data.keys.forEach(function(key) {
tbody.append(`
| ${escapeHtml(key.description || '无描述')} |
${escapeHtml(key.key)} |
${new Date(key.created_at).toLocaleString('zh-CN')} |
|
`);
});
})
.fail(handleAjaxError);
}
function loadLogs(query = {}) {
$.get('/api/logs', query)
.done(function(data) {
const logContainer = $('#logEntries');
logContainer.empty();
if (data.logs && data.logs.length > 0) {
data.logs.forEach(function(log) {
const levelClass = {
'error': 'error',
'warn': 'warn',
'info': 'info',
'debug': 'debug'
}[log.level] || '';
logContainer.append(`
${new Date(log.timestamp).toLocaleString('zh-CN')}
[${escapeHtml(log.level.toUpperCase())}] ${escapeHtml(log.message)}
`);
});
} else {
logContainer.append('暂无日志记录
');
}
})
.fail(handleAjaxError);
}
function checkHealth() {
$.get('/health')
.done(function(data) {
const indicator = $('.health-indicator');
indicator.removeClass('healthy unhealthy')
.addClass(data.status === 'healthy' ? 'healthy' : 'unhealthy');
$('#healthStatus').text(data.status === 'healthy' ? '健康' : '异常');
})
.fail(function() {
const indicator = $('.health-indicator');
indicator.removeClass('healthy').addClass('unhealthy');
$('#healthStatus').text('异常');
});
}
function loadHealthDetails() {
$.get('/health')
.done(function(data) {
const healthDetails = $('#healthDetails');
healthDetails.html(`
状态:
${data.status === 'healthy' ? '健康' : '异常'}
版本: ${data.version || '未知'}
启动时间: ${data.uptime || '未知'}
内存使用: ${data.memory || '未知'}
`);
})
.fail(function() {
$('#healthDetails').html('无法获取健康状态
');
});
}
function loadStatsDetails() {
$.get('/api/stats')
.done(function(data) {
const statsDetails = $('#statsDetails');
statsDetails.html(`
总项目数: ${data.total_projects || 0}
API 密钥数: ${data.total_api_keys || 0}
今日触发次数: ${data.today_triggers || 0}
成功触发次数: ${data.successful_triggers || 0}
`);
})
.fail(function() {
$('#statsDetails').html('无法获取统计信息
');
});
}
function deleteProject(id) {
if (!confirm('确定要删除这个项目吗?')) return;
$.ajax({
url: `/api/projects/${id}`,
method: 'DELETE',
success: function() {
loadProjects();
showSuccess('项目删除成功');
},
error: handleAjaxError
});
}
function revokeKey(id) {
if (!confirm('确定要撤销这个 API 密钥吗?')) return;
$.ajax({
url: `/api/keys/${id}`,
method: 'DELETE',
success: function() {
loadAPIKeys();
showSuccess('API 密钥撤销成功');
},
error: handleAjaxError
});
}
function showApiKeyModal(key) {
// 创建模态框显示新生成的密钥
const modal = $(`
`);
$('body').append(modal);
modal.modal('show');
modal.on('hidden.bs.modal', function() {
modal.remove();
});
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(function() {
showSuccess('已复制到剪贴板');
}, function() {
showError('复制失败');
});
}
function handleAjaxError(jqXHR, textStatus, errorThrown) {
const message = jqXHR.responseJSON?.detail || errorThrown || '发生错误';
showError(`错误: ${message}`);
}
function showSuccess(message) {
// 创建成功提示
const alert = $(`
${message}
`);
$('.main-content').prepend(alert);
// 3秒后自动消失
setTimeout(function() {
alert.alert('close');
}, 3000);
}
function showError(message) {
// 创建错误提示
const alert = $(`
${message}
`);
$('.main-content').prepend(alert);
// 5秒后自动消失
setTimeout(function() {
alert.alert('close');
}, 5000);
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}