Files
SignatureSystem/templates/logs.html
2026-07-20 13:16:17 +08:00

123 lines
5.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}自动签名系统 - 日志{% endblock %}
{% block content %}
<div style="display:flex;flex-direction:column;height:100%;">
<div class="log-toolbar">
<span style="font-size:13px;font-weight:600;color:#1a237e;"><i class="bi bi-terminal"></i> 系统日志</span>
<select class="form-select" id="logSourceFilter">
<option value="all">全部来源</option>
<option value="前端操作">前端操作</option>
<option value="外部API">外部API</option>
</select>
<select class="form-select" id="logLevelFilter">
<option value="all">全部级别</option>
<option value="INFO">INFO</option>
<option value="WARN">WARN</option>
<option value="ERROR">ERROR</option>
</select>
<input type="text" class="form-control" id="logKeyword" placeholder="关键字搜索" style="width:200px;">
<div class="form-check form-check-inline ms-2">
<input class="form-check-input" type="checkbox" id="autoScroll" checked>
<label class="form-check-label" for="autoScroll" style="font-size:12px;">自动滚动</label>
</div>
<button class="btn btn-outline-secondary btn-sm" id="btnClearLog"><i class="bi bi-trash"></i> 清空</button>
<button class="btn btn-outline-danger btn-sm" id="btnLocateError"><i class="bi bi-exclamation-triangle"></i> 定位异常</button>
<span class="ms-auto" style="font-size:12px;color:#757575;" id="logCount">0 条</span>
</div>
<div class="log-content" id="logContent"></div>
</div>
{% endblock %}
{% block extra_js %}
<script>
(function() {
const logContent = document.getElementById('logContent');
const logSourceFilter = document.getElementById('logSourceFilter');
const logLevelFilter = document.getElementById('logLevelFilter');
const logKeyword = document.getElementById('logKeyword');
const autoScroll = document.getElementById('autoScroll');
const logCountEl = document.getElementById('logCount');
let allLogs = [];
let logId = 0;
function addLogEntry(level, source, message) {
logId++;
const entry = { id: logId, level, source, message, time: new Date() };
allLogs.push(entry);
renderEntry(entry);
logCountEl.textContent = allLogs.length + ' 条';
}
function renderEntry(entry) {
if (!matchFilter(entry)) return;
const div = document.createElement('div');
div.className = `log-entry level-${entry.level}`;
div.dataset.id = entry.id;
div.dataset.level = entry.level;
div.dataset.source = entry.source;
const sourceClass = entry.source === '外部API' ? 'log-source-api' : 'log-source-frontend';
const timeStr = entry.time.toLocaleTimeString('zh-CN', { hour12: false });
div.innerHTML = `<span class="log-timestamp">[${timeStr}]</span> <span class="${sourceClass}">[${entry.source}]</span> <span style="font-weight:600;">[${entry.level}]</span> ${escapeHtml(entry.message)}`;
logContent.appendChild(div);
if (autoScroll.checked) {
logContent.scrollTop = logContent.scrollHeight;
}
}
function matchFilter(entry) {
const src = logSourceFilter.value;
const lvl = logLevelFilter.value;
const kw = logKeyword.value.trim().toLowerCase();
if (src !== 'all' && entry.source !== src) return false;
if (lvl !== 'all' && entry.level !== lvl) return false;
if (kw && !entry.message.toLowerCase().includes(kw)) return false;
return true;
}
function rerenderAll() {
logContent.innerHTML = '';
allLogs.forEach(entry => renderEntry(entry));
}
logSourceFilter.addEventListener('change', rerenderAll);
logLevelFilter.addEventListener('change', rerenderAll);
logKeyword.addEventListener('input', rerenderAll);
document.getElementById('btnClearLog').addEventListener('click', function() {
allLogs = [];
logContent.innerHTML = '';
logCountEl.textContent = '0 条';
});
document.getElementById('btnLocateError').addEventListener('click', function() {
const errorEntries = logContent.querySelectorAll('.level-ERROR');
if (errorEntries.length > 0) {
errorEntries.forEach(e => e.classList.remove('highlight-error'));
const last = errorEntries[errorEntries.length - 1];
last.scrollIntoView({ behavior: 'smooth', block: 'center' });
last.classList.add('highlight-error');
} else {
alert('没有发现异常日志');
}
});
const evtSource = new EventSource('/api/logs/stream');
evtSource.onmessage = function(event) {
try {
const data = JSON.parse(event.data);
addLogEntry(data.level || 'INFO', data.source || '系统', data.message || '');
} catch (e) {
addLogEntry('INFO', '系统', event.data);
}
};
evtSource.onerror = function() {
addLogEntry('WARN', '系统', '日志流连接断开5秒后重连...');
};
addLogEntry('INFO', '系统', '日志页面已加载,正在监听系统日志...');
})();
</script>
{% endblock %}