254 lines
12 KiB
HTML
254 lines
12 KiB
HTML
{% extends 'base.html' %}
|
|
|
|
{% block title %}系统日志管理{% endblock %}
|
|
|
|
{% block head %}
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/log-list.css') }}">
|
|
<link href="https://fonts.googleapis.com/css2?family=Dancing+Script&family=Montserrat:wght@300;400;500&display=swap" rel="stylesheet">
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="content-container">
|
|
<div class="content-header">
|
|
<h1><i class="fas fa-history sparkle"></i> 系统日志管理</h1>
|
|
<div class="actions">
|
|
<button id="btnExport" class="btn btn-blossom">
|
|
<i class="fas fa-file-export"></i> 导出日志
|
|
</button>
|
|
<button id="btnClear" class="btn btn-danger-soft">
|
|
<i class="fas fa-trash"></i> 清除日志
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="filter-panel">
|
|
<div class="filter-panel-header">
|
|
<span class="filter-title">日志筛选</span>
|
|
<div class="snowflake-divider">
|
|
<span>❄</span><span>❄</span><span>❄</span>
|
|
</div>
|
|
</div>
|
|
<form method="get" action="{{ url_for('log.log_list') }}">
|
|
<div class="filter-row">
|
|
<div class="filter-item">
|
|
<label for="user_id">用户</label>
|
|
<select name="user_id" id="user_id" class="elegant-select">
|
|
<option value="">全部用户</option>
|
|
{% for user in users %}
|
|
<option value="{{ user.id }}" {% if filters.user_id == user.id %}selected{% endif %}>
|
|
{{ user.username }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="filter-item">
|
|
<label for="action">操作类型</label>
|
|
<select name="action" id="action" class="elegant-select">
|
|
<option value="">全部操作</option>
|
|
{% for action_type, count in action_types %}
|
|
<option value="{{ action_type }}" {% if filters.action == action_type %}selected{% endif %}>
|
|
{{ action_type }} ({{ count }})
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="filter-item">
|
|
<label for="target_type">目标类型</label>
|
|
<select name="target_type" id="target_type" class="elegant-select">
|
|
<option value="">全部类型</option>
|
|
{% for target_type, count in target_types %}
|
|
<option value="{{ target_type }}" {% if filters.target_type == target_type %}selected{% endif %}>
|
|
{{ target_type }} ({{ count }})
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="filter-item">
|
|
<label for="date_range">时间范围</label>
|
|
<select name="date_range" id="date_range" class="elegant-select">
|
|
<option value="1" {% if filters.date_range == '1' %}selected{% endif %}>最近1天</option>
|
|
<option value="7" {% if filters.date_range == '7' %}selected{% endif %}>最近7天</option>
|
|
<option value="30" {% if filters.date_range == '30' %}selected{% endif %}>最近30天</option>
|
|
<option value="custom" {% if filters.date_range == 'custom' %}selected{% endif %}>自定义</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="filter-row date-range-inputs" {% if filters.date_range != 'custom' %}style="display:none"{% endif %}>
|
|
<div class="filter-item">
|
|
<label for="start_date">开始日期</label>
|
|
<input type="date" name="start_date" id="start_date" value="{{ filters.start_date }}" class="elegant-input">
|
|
</div>
|
|
<div class="filter-item">
|
|
<label for="end_date">结束日期</label>
|
|
<input type="date" name="end_date" id="end_date" value="{{ filters.end_date }}" class="elegant-input">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="filter-actions">
|
|
<button type="submit" class="btn btn-primary-soft">应用筛选</button>
|
|
<a href="{{ url_for('log.log_list') }}" class="btn btn-secondary-soft">重置</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card glass-card">
|
|
<div class="card-body">
|
|
<div class="table-container">
|
|
<table class="table elegant-table">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>用户</th>
|
|
<th>操作</th>
|
|
<th>目标类型</th>
|
|
<th>目标ID</th>
|
|
<th>IP地址</th>
|
|
<th>描述</th>
|
|
<th>时间</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for log in pagination.items %}
|
|
<tr class="fade-in-row">
|
|
<td>{{ log.id }}</td>
|
|
<td>
|
|
{% if log.user %}
|
|
<span class="user-badge">{{ log.user.username }}</span>
|
|
{% else %}
|
|
<span class="text-muted">未登录</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ log.action }}</td>
|
|
<td>{{ log.target_type }}</td>
|
|
<td>{{ log.target_id }}</td>
|
|
<td>{{ log.ip_address }}</td>
|
|
<td>{{ log.description }}</td>
|
|
<td>{{ log.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="8" class="text-center empty-message">
|
|
<div class="empty-container">
|
|
<i class="fas fa-search"></i>
|
|
<p>没有找到符合条件的日志记录</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 分页部分 -->
|
|
<div class="pagination-wrapper">
|
|
<div class="pagination-container">
|
|
{% if pagination.has_prev %}
|
|
<a href="{{ url_for('log.log_list', page=pagination.prev_num, user_id=filters.user_id, action=filters.action, target_type=filters.target_type, date_range=filters.date_range, start_date=filters.start_date, end_date=filters.end_date) }}" class="btn btn-sm btn-outline-primary page-btn"><i class="fas fa-chevron-left"></i> 上一页</a>
|
|
{% endif %}
|
|
|
|
<span class="page-info">
|
|
第 {{ pagination.page }} 页,共 {{ pagination.pages }} 页,总计 {{ pagination.total }} 条记录
|
|
</span>
|
|
|
|
{% if pagination.has_next %}
|
|
<a href="{{ url_for('log.log_list', page=pagination.next_num, user_id=filters.user_id, action=filters.action, target_type=filters.target_type, date_range=filters.date_range, start_date=filters.start_date, end_date=filters.end_date) }}" class="btn btn-sm btn-outline-primary page-btn">下一页 <i class="fas fa-chevron-right"></i></a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 导出日志模态框 -->
|
|
<div class="modal fade" id="exportLogModal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-elegant" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-file-export"></i> 导出日志</h5>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p class="modal-message">请选择导出格式:</p>
|
|
<div class="form-group">
|
|
<select id="exportFormat" class="form-control elegant-select">
|
|
<option value="csv">CSV 格式</option>
|
|
<option value="excel">Excel 格式</option>
|
|
</select>
|
|
</div>
|
|
<div class="alert alert-info elegant-alert">
|
|
<i class="fas fa-info-circle"></i> 将导出当前筛选条件下的所有日志记录。
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary-soft" data-dismiss="modal">取消</button>
|
|
<button type="button" id="confirmExport" class="btn btn-primary-soft">确认导出</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 清除日志确认框 -->
|
|
<div class="modal fade" id="clearLogModal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-elegant" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="fas fa-trash-alt"></i> 清除日志确认</h5>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p class="modal-message">请选择要清除的日志范围:</p>
|
|
<div class="form-group">
|
|
<select id="clearDays" class="form-control elegant-select">
|
|
<option value="0">清除全部日志</option>
|
|
<option value="30">清除30天前的日志</option>
|
|
<option value="90">清除90天前的日志</option>
|
|
<option value="180">清除半年前的日志</option>
|
|
<option value="365">清除一年前的日志</option>
|
|
</select>
|
|
</div>
|
|
<div class="alert alert-warning elegant-alert">
|
|
<i class="fas fa-exclamation-triangle"></i> 警告:此操作不可恢复!
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary-soft" data-dismiss="modal">取消</button>
|
|
<button type="button" id="confirmClear" class="btn btn-danger-soft">确认清除</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script src="{{ url_for('static', filename='js/log-list.js') }}"></script>
|
|
<script>
|
|
// 添加雪花动画效果
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// 为表格行添加渐入效果
|
|
const rows = document.querySelectorAll('.fade-in-row');
|
|
rows.forEach((row, index) => {
|
|
row.style.animationDelay = `${index * 0.05}s`;
|
|
});
|
|
|
|
// 为按钮添加悬停效果
|
|
const buttons = document.querySelectorAll('.btn');
|
|
buttons.forEach(btn => {
|
|
btn.addEventListener('mouseover', function() {
|
|
this.classList.add('btn-glow');
|
|
});
|
|
btn.addEventListener('mouseout', function() {
|
|
this.classList.remove('btn-glow');
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|