351 lines
11 KiB
JavaScript
351 lines
11 KiB
JavaScript
// 操作日志页面JavaScript
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 初始化
|
||
initializeLogManagement();
|
||
});
|
||
|
||
// 初始化日志管理功能
|
||
function initializeLogManagement() {
|
||
// 添加事件监听器
|
||
setupEventListeners();
|
||
|
||
// 初始化工具提示
|
||
initializeTooltips();
|
||
|
||
// 初始化表格
|
||
initializeTable();
|
||
}
|
||
|
||
// 设置事件监听器
|
||
function setupEventListeners() {
|
||
// 搜索表单提交
|
||
const searchForm = document.querySelector('form[method="GET"]');
|
||
if (searchForm) {
|
||
searchForm.addEventListener('submit', function(e) {
|
||
// 可以在这里添加搜索前的验证
|
||
});
|
||
}
|
||
|
||
// 用户类型筛选变更
|
||
const userTypeSelect = document.getElementById('user_type');
|
||
if (userTypeSelect) {
|
||
userTypeSelect.addEventListener('change', function() {
|
||
// 自动提交表单
|
||
this.form.submit();
|
||
});
|
||
}
|
||
|
||
// 操作类型输入框
|
||
const actionInput = document.getElementById('action');
|
||
if (actionInput) {
|
||
// 添加防抖搜索
|
||
let searchTimer;
|
||
actionInput.addEventListener('input', function() {
|
||
clearTimeout(searchTimer);
|
||
searchTimer = setTimeout(() => {
|
||
// 可以实现实时搜索
|
||
}, 500);
|
||
});
|
||
}
|
||
}
|
||
|
||
// 初始化工具提示
|
||
function initializeTooltips() {
|
||
// 为用户代理字段添加工具提示
|
||
const userAgentElements = document.querySelectorAll('.user-agent');
|
||
userAgentElements.forEach(element => {
|
||
if (element.title) {
|
||
// 使用Bootstrap的tooltip
|
||
new bootstrap.Tooltip(element);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 初始化表格
|
||
function initializeTable() {
|
||
// 添加表格行点击事件
|
||
const tableRows = document.querySelectorAll('.table tbody tr');
|
||
tableRows.forEach(row => {
|
||
row.addEventListener('click', function(e) {
|
||
// 如果点击的是按钮,不触发行点击事件
|
||
if (e.target.tagName === 'BUTTON' || e.target.closest('button')) {
|
||
return;
|
||
}
|
||
|
||
// 高亮选中行
|
||
tableRows.forEach(r => r.classList.remove('table-active'));
|
||
this.classList.add('table-active');
|
||
});
|
||
});
|
||
}
|
||
|
||
// 查看日志详情
|
||
function viewLogDetail(logId) {
|
||
// 发送AJAX请求获取日志详情
|
||
fetch(`/admin/logs/${logId}/detail`)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
showLogDetailModal(data.log);
|
||
} else {
|
||
showError('获取日志详情失败: ' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
showError('网络错误,请重试');
|
||
});
|
||
}
|
||
|
||
// 显示日志详情模态框
|
||
function showLogDetailModal(log) {
|
||
const modalHtml = `
|
||
<div class="modal fade" id="logDetailModal" tabindex="-1">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title">操作日志详情</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="log-detail">
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="log-info-item">
|
||
<span class="log-info-label">日志ID:</span>
|
||
<span class="log-info-value">#${log.id}</span>
|
||
</div>
|
||
<div class="log-info-item">
|
||
<span class="log-info-label">操作者:</span>
|
||
<span class="log-info-value">
|
||
<span class="badge bg-${log.user_type === 2 ? 'warning' : 'info'}">
|
||
${log.user_type === 2 ? '管理员' : '用户'}
|
||
</span>
|
||
#${log.user_id || '未知'}
|
||
</span>
|
||
</div>
|
||
<div class="log-info-item">
|
||
<span class="log-info-label">操作类型:</span>
|
||
<span class="log-info-value operation-action">${log.action}</span>
|
||
</div>
|
||
<div class="log-info-item">
|
||
<span class="log-info-label">操作对象:</span>
|
||
<span class="log-info-value">
|
||
${log.resource_type || '无'}
|
||
${log.resource_id ? `#${log.resource_id}` : ''}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="log-info-item">
|
||
<span class="log-info-label">IP地址:</span>
|
||
<span class="log-info-value"><code>${log.ip_address || '未知'}</code></span>
|
||
</div>
|
||
<div class="log-info-item">
|
||
<span class="log-info-label">操作时间:</span>
|
||
<span class="log-info-value">${formatDateTime(log.created_at)}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
${log.user_agent ? `
|
||
<div class="mt-3">
|
||
<h6>用户代理信息:</h6>
|
||
<div class="user-agent-detail">
|
||
<code>${log.user_agent}</code>
|
||
</div>
|
||
</div>
|
||
` : ''}
|
||
|
||
${log.request_data ? `
|
||
<div class="mt-3">
|
||
<h6>请求数据:</h6>
|
||
<pre class="request-data"><code>${JSON.stringify(log.request_data, null, 2)}</code></pre>
|
||
</div>
|
||
` : ''}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
// 移除现有的模态框
|
||
const existingModal = document.getElementById('logDetailModal');
|
||
if (existingModal) {
|
||
existingModal.remove();
|
||
}
|
||
|
||
// 添加新的模态框
|
||
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
||
|
||
// 显示模态框
|
||
const modal = new bootstrap.Modal(document.getElementById('logDetailModal'));
|
||
modal.show();
|
||
}
|
||
|
||
// 导出日志
|
||
function exportLogs() {
|
||
// 获取当前筛选条件
|
||
const userType = document.getElementById('user_type').value;
|
||
const action = document.getElementById('action').value;
|
||
|
||
// 构建导出URL
|
||
const params = new URLSearchParams();
|
||
if (userType) params.append('user_type', userType);
|
||
if (action) params.append('action', action);
|
||
|
||
const exportUrl = `/admin/logs/export?${params.toString()}`;
|
||
|
||
// 下载文件
|
||
window.location.href = exportUrl;
|
||
}
|
||
|
||
// 清理日志
|
||
function clearLogs() {
|
||
if (!confirm('确定要清理历史日志吗?此操作不可逆!')) {
|
||
return;
|
||
}
|
||
|
||
const daysToKeep = prompt('请输入要保留的天数(例如:30):', '30');
|
||
if (!daysToKeep || isNaN(daysToKeep) || daysToKeep <= 0) {
|
||
showError('请输入有效的天数');
|
||
return;
|
||
}
|
||
|
||
// 显示加载状态
|
||
showLoading();
|
||
|
||
// 发送AJAX请求
|
||
fetch('/admin/logs/clear', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
days_to_keep: parseInt(daysToKeep)
|
||
})
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
hideLoading();
|
||
if (data.success) {
|
||
showSuccess(data.message);
|
||
// 刷新页面
|
||
setTimeout(() => {
|
||
location.reload();
|
||
}, 1000);
|
||
} else {
|
||
showError(data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
hideLoading();
|
||
console.error('Error:', error);
|
||
showError('网络错误,请重试');
|
||
});
|
||
}
|
||
|
||
// 搜索日志
|
||
function searchLogs() {
|
||
const searchForm = document.querySelector('form[method="GET"]');
|
||
if (searchForm) {
|
||
searchForm.submit();
|
||
}
|
||
}
|
||
|
||
// 重置搜索
|
||
function resetSearch() {
|
||
window.location.href = '/admin/logs';
|
||
}
|
||
|
||
// 格式化日期时间
|
||
function formatDateTime(dateTimeString) {
|
||
if (!dateTimeString) return '未知';
|
||
|
||
const date = new Date(dateTimeString);
|
||
return date.toLocaleString('zh-CN');
|
||
}
|
||
|
||
// 显示成功消息
|
||
function showSuccess(message) {
|
||
showAlert(message, 'success');
|
||
}
|
||
|
||
// 显示错误消息
|
||
function showError(message) {
|
||
showAlert(message, 'danger');
|
||
}
|
||
|
||
// 显示提示消息
|
||
function showAlert(message, type) {
|
||
const alertDiv = document.createElement('div');
|
||
alertDiv.className = `alert alert-${type} alert-dismissible fade show`;
|
||
alertDiv.innerHTML = `
|
||
${message}
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
`;
|
||
|
||
// 插入到页面顶部
|
||
const container = document.querySelector('.admin-content');
|
||
container.insertBefore(alertDiv, container.firstChild);
|
||
|
||
// 3秒后自动关闭
|
||
setTimeout(() => {
|
||
alertDiv.remove();
|
||
}, 3000);
|
||
}
|
||
|
||
// 显示加载状态
|
||
function showLoading() {
|
||
const loadingDiv = document.createElement('div');
|
||
loadingDiv.id = 'loading-overlay';
|
||
loadingDiv.innerHTML = `
|
||
<div class="loading-spinner">
|
||
<i class="bi bi-hourglass-split"></i>
|
||
<div>处理中...</div>
|
||
</div>
|
||
`;
|
||
loadingDiv.style.cssText = `
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0,0,0,0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 9999;
|
||
color: white;
|
||
`;
|
||
|
||
document.body.appendChild(loadingDiv);
|
||
}
|
||
|
||
// 隐藏加载状态
|
||
function hideLoading() {
|
||
const loadingDiv = document.getElementById('loading-overlay');
|
||
if (loadingDiv) {
|
||
loadingDiv.remove();
|
||
}
|
||
}
|
||
|
||
// 表格排序功能
|
||
function sortTable(column) {
|
||
// 实现表格排序功能
|
||
console.log('Sort by:', column);
|
||
}
|
||
|
||
// 批量操作功能(可选)
|
||
function bulkOperation() {
|
||
// 实现批量操作功能
|
||
const selectedLogs = document.querySelectorAll('input[type="checkbox"]:checked');
|
||
if (selectedLogs.length === 0) {
|
||
showError('请选择要操作的日志');
|
||
return;
|
||
}
|
||
|
||
// 实现批量操作逻辑
|
||
}
|