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 %}
 |