ai_v/templates/logs.html
24024 d4b28a731a feat(admin): 添加系统通知管理及前端通知显示功能
- 新增 SystemNotification 模型,实现系统通知的数据存储
- 管理后台新增通知相关接口,支持通知的增删改查
- 用户端新增接口,获取最新激活通知并支持标记已读
- 在前端首页添加全局通知弹窗,实现通知自动轮询及已读同步
- 生成历史记录中兼容支持图片缩略图及新旧图片格式
- 优化后台图片同步逻辑,新增缩略图生成与存储
- 支持上传参考图的拖拽、粘贴、多文件上传及排序功能
- 增加购买积分页面入口及菜单项,调整菜单结构
- 日志系统由 Redis 列表迁移为有序集合,保留 30 天日志
- 优化日志页面样式,提升可读性及滚动体验
- 调整部分模板布局为自定义滚动条容器,增强视觉一致性
2026-01-12 23:29:29 +08:00

117 lines
6.0 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 %}系统日志 - AI 视界{% endblock %}
{% block content %}
<div class="w-full h-full overflow-y-auto p-8 lg:p-12 custom-scrollbar">
<div class="max-w-7xl mx-auto space-y-8">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="w-12 h-12 bg-slate-900 text-white rounded-2xl flex items-center justify-center shadow-lg">
<i data-lucide="terminal" class="w-7 h-7"></i>
</div>
<div>
<h1 class="text-3xl font-black text-slate-900 tracking-tight">系统审计日志</h1>
<p class="text-slate-400 text-sm">实时监控系统运行状态与安全事件</p>
</div>
</div>
<div class="flex items-center gap-4">
<!-- 筛选工具栏 -->
<div class="flex items-center bg-white border border-slate-200 rounded-xl px-4 py-2 shadow-sm">
<i data-lucide="search" class="w-4 h-4 text-slate-400 mr-2"></i>
<input type="text" id="logSearch" placeholder="搜索消息或手机号..."
class="outline-none text-sm w-48 text-slate-600" oninput="loadLogs()">
</div>
<select id="logLevel" class="bg-white border border-slate-200 rounded-xl px-4 py-2 text-sm text-slate-600 outline-none shadow-sm" onchange="loadLogs()">
<option value="">全部级别</option>
<option value="INFO">INFO</option>
<option value="WARNING">WARNING</option>
<option value="ERROR">ERROR</option>
</select>
<button onclick="loadLogs()" class="bg-white border border-slate-200 p-3 rounded-xl hover:bg-slate-50 transition-all shadow-sm">
<i data-lucide="refresh-cw" class="w-5 h-5 text-slate-600"></i>
</button>
<a href="/" class="btn-primary px-6 py-3 rounded-xl text-sm font-bold shadow-lg">返回工作台</a>
</div>
</div>
<div class="bg-white rounded-[2.5rem] shadow-xl border border-slate-100 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-slate-50 border-b border-slate-100 sticky top-0 z-10 shadow-sm">
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest bg-slate-50">时间</th>
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest bg-slate-50">级别</th>
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest bg-slate-50">事件消息</th>
<th class="px-8 py-5 text-[10px] font-black text-slate-400 uppercase tracking-widest bg-slate-50">关键参数</th>
</tr>
</thead>
<tbody id="logTableBody" class="text-sm font-medium">
<!-- 动态加载 -->
<tr>
<td colspan="4" class="px-8 py-20 text-center text-slate-400 italic">正在连接日志服务器...</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
async function loadLogs() {
const search = document.getElementById('logSearch')?.value || '';
const level = document.getElementById('logLevel')?.value || '';
const url = `/api/auth/logs?search=${encodeURIComponent(search)}&level=${level}`;
try {
const r = await fetch(url);
const d = await r.json();
const body = document.getElementById('logTableBody');
if (d.error) {
body.innerHTML = `<tr><td colspan="4" class="px-8 py-20 text-center text-rose-500 font-bold">${d.error}</td></tr>`;
return;
}
if (d.logs.length === 0) {
body.innerHTML = `<tr><td colspan="4" class="px-8 py-20 text-center text-slate-400 italic">没有找到符合条件的日志</td></tr>`;
return;
}
body.innerHTML = d.logs.map(log => `
<tr class="border-b border-slate-50 hover:bg-slate-50/50 transition-colors">
<td class="px-8 py-5 text-slate-400 font-mono text-xs">${log.time}</td>
<td class="px-8 py-5">
<span class="px-2.5 py-1 rounded-lg text-[10px] font-black uppercase ${
log.level === 'INFO' ? 'bg-indigo-50 text-indigo-600' :
log.level === 'WARNING' ? 'bg-amber-50 text-amber-600' : 'bg-rose-50 text-rose-600'
}">${log.level}</span>
</td>
<td class="px-8 py-5 text-slate-700 font-bold break-all whitespace-pre-wrap min-w-[300px]">${log.message}</td>
<td class="px-8 py-5 text-slate-400 font-mono text-[10px] min-w-[200px]">
${Object.entries(log.extra).map(([k, v]) => {
const val = typeof v === 'object' ? JSON.stringify(v) : v;
return `<span class="inline-block bg-slate-100 rounded px-1.5 py-0.5 mr-1 mb-1 break-all">${k}: ${val}</span>`;
}).join('')}
</td>
</tr>
`).join('');
} catch (e) {
console.error(e);
}
}
// 初始化加载
loadLogs();
// 自动刷新逻辑如果搜索框为空则每5秒刷新一次
setInterval(() => {
const search = document.getElementById('logSearch')?.value || '';
if (!search) loadLogs();
}, 5000);
</script>
{% endblock %}