384 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
{% extends 'layout/base.html' %}
 | 
						||
 | 
						||
{% block title %}管理员控制台 - SmartDSP考勤管理系统{% endblock %}
 | 
						||
 | 
						||
{% block content %}
 | 
						||
<div class="container-fluid mt-4">
 | 
						||
    <!-- 页面标题 -->
 | 
						||
    <div class="d-flex justify-content-between align-items-center mb-4">
 | 
						||
        <h1 class="h3 mb-0">
 | 
						||
            <i class="fas fa-tachometer-alt me-2"></i>管理员控制台
 | 
						||
        </h1>
 | 
						||
        <div class="text-muted" id="current-time">
 | 
						||
            <i class="fas fa-clock me-1"></i>
 | 
						||
            加载中...
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
 | 
						||
    <!-- 统计卡片 -->
 | 
						||
    <div class="row mb-4">
 | 
						||
        <div class="col-xl-3 col-md-6 mb-4">
 | 
						||
            <div class="card border-left-primary shadow h-100 py-2">
 | 
						||
                <div class="card-body">
 | 
						||
                    <div class="row no-gutters align-items-center">
 | 
						||
                        <div class="col mr-2">
 | 
						||
                            <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
 | 
						||
                                学生总数
 | 
						||
                            </div>
 | 
						||
                            <div class="h5 mb-0 font-weight-bold text-gray-800">
 | 
						||
                                {{ total_students or 0 }}
 | 
						||
                            </div>
 | 
						||
                        </div>
 | 
						||
                        <div class="col-auto">
 | 
						||
                            <i class="fas fa-users fa-2x text-gray-300"></i>
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
 | 
						||
        <div class="col-xl-3 col-md-6 mb-4">
 | 
						||
            <div class="card border-left-success shadow h-100 py-2">
 | 
						||
                <div class="card-body">
 | 
						||
                    <div class="row no-gutters align-items-center">
 | 
						||
                        <div class="col mr-2">
 | 
						||
                            <div class="text-xs font-weight-bold text-success text-uppercase mb-1">
 | 
						||
                                考勤记录总数
 | 
						||
                            </div>
 | 
						||
                            <div class="h5 mb-0 font-weight-bold text-gray-800">
 | 
						||
                                {{ total_attendance_records or 0 }}
 | 
						||
                            </div>
 | 
						||
                        </div>
 | 
						||
                        <div class="col-auto">
 | 
						||
                            <i class="fas fa-calendar-check fa-2x text-gray-300"></i>
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
 | 
						||
        <div class="col-xl-3 col-md-6 mb-4">
 | 
						||
            <div class="card border-left-warning shadow h-100 py-2">
 | 
						||
                <div class="card-body">
 | 
						||
                    <div class="row no-gutters align-items-center">
 | 
						||
                        <div class="col mr-2">
 | 
						||
                            <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
 | 
						||
                                待审批请假
 | 
						||
                            </div>
 | 
						||
                            <div class="h5 mb-0 font-weight-bold text-gray-800">
 | 
						||
                                {{ pending_leaves or 0 }}
 | 
						||
                            </div>
 | 
						||
                        </div>
 | 
						||
                        <div class="col-auto">
 | 
						||
                            <i class="fas fa-clock fa-2x text-gray-300"></i>
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
 | 
						||
        <div class="col-xl-3 col-md-6 mb-4">
 | 
						||
            <div class="card border-left-info shadow h-100 py-2">
 | 
						||
                <div class="card-body">
 | 
						||
                    <div class="row no-gutters align-items-center">
 | 
						||
                        <div class="col mr-2">
 | 
						||
                            <div class="text-xs font-weight-bold text-info text-uppercase mb-1">
 | 
						||
                                本周新记录
 | 
						||
                            </div>
 | 
						||
                            <div class="h5 mb-0 font-weight-bold text-gray-800">
 | 
						||
                                {{ recent_records or 0 }}
 | 
						||
                            </div>
 | 
						||
                        </div>
 | 
						||
                        <div class="col-auto">
 | 
						||
                            <i class="fas fa-calendar-week fa-2x text-gray-300"></i>
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
 | 
						||
    <!-- 内容区域 -->
 | 
						||
    <div class="row">
 | 
						||
        <!-- 学院统计 -->
 | 
						||
        <div class="col-xl-6 col-lg-6">
 | 
						||
            <div class="card shadow mb-4">
 | 
						||
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
 | 
						||
                    <h6 class="m-0 font-weight-bold text-primary">
 | 
						||
                        <i class="fas fa-university me-2"></i>学院分布
 | 
						||
                    </h6>
 | 
						||
                </div>
 | 
						||
                <div class="card-body">
 | 
						||
                    {% if college_stats %}
 | 
						||
                        <div class="table-responsive">
 | 
						||
                            <table class="table table-sm">
 | 
						||
                                <thead>
 | 
						||
                                    <tr>
 | 
						||
                                        <th>学院</th>
 | 
						||
                                        <th class="text-end">学生数</th>
 | 
						||
                                    </tr>
 | 
						||
                                </thead>
 | 
						||
                                <tbody>
 | 
						||
                                    {% for college, count in college_stats %}
 | 
						||
                                    <tr>
 | 
						||
                                        <td>{{ college or '未知学院' }}</td>
 | 
						||
                                        <td class="text-end">
 | 
						||
                                            <span class="badge bg-primary">{{ count }}</span>
 | 
						||
                                        </td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% endfor %}
 | 
						||
                                </tbody>
 | 
						||
                            </table>
 | 
						||
                        </div>
 | 
						||
                    {% else %}
 | 
						||
                        <div class="text-center text-muted py-4">
 | 
						||
                            <i class="fas fa-chart-bar fa-3x mb-3"></i>
 | 
						||
                            <p>暂无数据</p>
 | 
						||
                        </div>
 | 
						||
                    {% endif %}
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
 | 
						||
        <!-- 导师统计 -->
 | 
						||
        <div class="col-xl-6 col-lg-6">
 | 
						||
            <div class="card shadow mb-4">
 | 
						||
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
 | 
						||
                    <h6 class="m-0 font-weight-bold text-primary">
 | 
						||
                        <i class="fas fa-user-tie me-2"></i>导师排行(TOP 10)
 | 
						||
                    </h6>
 | 
						||
                </div>
 | 
						||
                <div class="card-body">
 | 
						||
                    {% if supervisor_stats %}
 | 
						||
                        <div class="table-responsive">
 | 
						||
                            <table class="table table-sm">
 | 
						||
                                <thead>
 | 
						||
                                    <tr>
 | 
						||
                                        <th>导师</th>
 | 
						||
                                        <th class="text-end">学生数</th>
 | 
						||
                                    </tr>
 | 
						||
                                </thead>
 | 
						||
                                <tbody>
 | 
						||
                                    {% for supervisor, count in supervisor_stats %}
 | 
						||
                                    <tr>
 | 
						||
                                        <td>{{ supervisor or '未知导师' }}</td>
 | 
						||
                                        <td class="text-end">
 | 
						||
                                            <span class="badge bg-success">{{ count }}</span>
 | 
						||
                                        </td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% endfor %}
 | 
						||
                                </tbody>
 | 
						||
                            </table>
 | 
						||
                        </div>
 | 
						||
                    {% else %}
 | 
						||
                        <div class="text-center text-muted py-4">
 | 
						||
                            <i class="fas fa-chart-bar fa-3x mb-3"></i>
 | 
						||
                            <p>暂无数据</p>
 | 
						||
                        </div>
 | 
						||
                    {% endif %}
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
 | 
						||
    <!-- 最近请假申请 -->
 | 
						||
    {% if recent_leaves %}
 | 
						||
    <div class="row">
 | 
						||
        <div class="col-12">
 | 
						||
            <div class="card shadow mb-4">
 | 
						||
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
 | 
						||
                    <h6 class="m-0 font-weight-bold text-primary">
 | 
						||
                        <i class="fas fa-file-alt me-2"></i>最近请假申请
 | 
						||
                    </h6>
 | 
						||
                    <a href="{{ url_for('admin.pending_leaves') }}" class="btn btn-primary btn-sm">
 | 
						||
                        <i class="fas fa-eye me-1"></i>查看全部
 | 
						||
                    </a>
 | 
						||
                </div>
 | 
						||
                <div class="card-body">
 | 
						||
                    <div class="table-responsive">
 | 
						||
                        <table class="table table-hover">
 | 
						||
                            <thead>
 | 
						||
                                <tr>
 | 
						||
                                    <th>学号</th>
 | 
						||
                                    <th>请假日期</th>
 | 
						||
                                    <th>请假原因</th>
 | 
						||
                                    <th>申请时间</th>
 | 
						||
                                    <th class="text-center">操作</th>
 | 
						||
                                </tr>
 | 
						||
                            </thead>
 | 
						||
                            <tbody>
 | 
						||
                                {% for leave in recent_leaves %}
 | 
						||
                                <tr>
 | 
						||
                                    <td>{{ leave.student_number }}</td>
 | 
						||
                                    <td>
 | 
						||
                                        {{ leave.leave_start_date.strftime('%Y-%m-%d') }}
 | 
						||
                                        {% if leave.leave_start_date != leave.leave_end_date %}
 | 
						||
                                            至 {{ leave.leave_end_date.strftime('%Y-%m-%d') }}
 | 
						||
                                        {% endif %}
 | 
						||
                                    </td>
 | 
						||
                                    <td>
 | 
						||
                                        <span class="text-truncate" style="max-width: 200px; display: inline-block;"
 | 
						||
                                              title="{{ leave.leave_reason }}">
 | 
						||
                                            {{ leave.leave_reason[:50] }}{% if leave.leave_reason|length > 50 %}...{% endif %}
 | 
						||
                                        </span>
 | 
						||
                                    </td>
 | 
						||
                                    <td>{{ leave.created_at.strftime('%m-%d %H:%M') }}</td>
 | 
						||
                                    <td class="text-center">
 | 
						||
                                        <div class="btn-group btn-group-sm">
 | 
						||
                                            <button class="btn btn-success btn-sm"
 | 
						||
                                                    onclick="approveLeave({{ leave.leave_id }})">
 | 
						||
                                                <i class="fas fa-check"></i>
 | 
						||
                                            </button>
 | 
						||
                                            <button class="btn btn-danger btn-sm"
 | 
						||
                                                    onclick="rejectLeave({{ leave.leave_id }})">
 | 
						||
                                                <i class="fas fa-times"></i>
 | 
						||
                                            </button>
 | 
						||
                                        </div>
 | 
						||
                                    </td>
 | 
						||
                                </tr>
 | 
						||
                                {% endfor %}
 | 
						||
                            </tbody>
 | 
						||
                        </table>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
    {% endif %}
 | 
						||
 | 
						||
    <!-- 快捷操作 -->
 | 
						||
    <div class="row">
 | 
						||
        <div class="col-12">
 | 
						||
            <div class="card shadow mb-4">
 | 
						||
                <div class="card-header py-3">
 | 
						||
                    <h6 class="m-0 font-weight-bold text-primary">
 | 
						||
                        <i class="fas fa-bolt me-2"></i>快捷操作
 | 
						||
                    </h6>
 | 
						||
                </div>
 | 
						||
                <div class="card-body">
 | 
						||
                    <div class="row">
 | 
						||
                        <div class="col-md-3 mb-3">
 | 
						||
                            <a href="{{ url_for('admin.student_list') }}" class="btn btn-outline-primary btn-block h-100">
 | 
						||
                                <i class="fas fa-users fa-2x mb-2"></i><br>
 | 
						||
                                <span>学生管理</span>
 | 
						||
                            </a>
 | 
						||
                        </div>
 | 
						||
                        <div class="col-md-3 mb-3">
 | 
						||
                            <a href="{{ url_for('admin.attendance_management') }}" class="btn btn-outline-success btn-block h-100">
 | 
						||
                                <i class="fas fa-calendar-check fa-2x mb-2"></i><br>
 | 
						||
                                <span>考勤管理</span>
 | 
						||
                            </a>
 | 
						||
                        </div>
 | 
						||
                        <div class="col-md-3 mb-3">
 | 
						||
                            <a href="{{ url_for('admin.upload_attendance') }}" class="btn btn-outline-info btn-block h-100">
 | 
						||
                                <i class="fas fa-upload fa-2x mb-2"></i><br>
 | 
						||
                                <span>上传数据</span>
 | 
						||
                            </a>
 | 
						||
                        </div>
 | 
						||
                        <div class="col-md-3 mb-3">
 | 
						||
                            <a href="{{ url_for('admin.statistics') }}" class="btn btn-outline-warning btn-block h-100">
 | 
						||
                                <i class="fas fa-chart-bar fa-2x mb-2"></i><br>
 | 
						||
                                <span>统计报表</span>
 | 
						||
                            </a>
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
</div>
 | 
						||
{% endblock %}
 | 
						||
 | 
						||
{% block extra_css %}
 | 
						||
<style>
 | 
						||
.border-left-primary {
 | 
						||
    border-left: 0.25rem solid #4e73df !important;
 | 
						||
}
 | 
						||
.border-left-success {
 | 
						||
    border-left: 0.25rem solid #1cc88a !important;
 | 
						||
}
 | 
						||
.border-left-warning {
 | 
						||
    border-left: 0.25rem solid #f6c23e !important;
 | 
						||
}
 | 
						||
.border-left-info {
 | 
						||
    border-left: 0.25rem solid #36b9cc !important;
 | 
						||
}
 | 
						||
 | 
						||
.text-xs {
 | 
						||
    font-size: .7rem;
 | 
						||
}
 | 
						||
 | 
						||
.btn-block {
 | 
						||
    display: block;
 | 
						||
    width: 100%;
 | 
						||
    text-align: center;
 | 
						||
    padding: 1rem;
 | 
						||
}
 | 
						||
 | 
						||
.text-gray-800 {
 | 
						||
    color: #5a5c69 !important;
 | 
						||
}
 | 
						||
 | 
						||
.text-gray-300 {
 | 
						||
    color: #dddfeb !important;
 | 
						||
}
 | 
						||
</style>
 | 
						||
{% endblock %}
 | 
						||
 | 
						||
{% block extra_js %}
 | 
						||
<script>
 | 
						||
// 显示当前时间
 | 
						||
function updateCurrentTime() {
 | 
						||
    const now = new Date();
 | 
						||
    const timeString = `${now.getFullYear()}年${(now.getMonth()+1).toString().padStart(2,'0')}月${now.getDate().toString().padStart(2,'0')}日 ${now.getHours().toString().padStart(2,'0')}:${now.getMinutes().toString().padStart(2,'0')}`;
 | 
						||
    document.getElementById('current-time').innerHTML = `<i class="fas fa-clock me-1"></i>${timeString}`;
 | 
						||
}
 | 
						||
 | 
						||
function approveLeave(leaveId) {
 | 
						||
    if (confirm('确认批准这个请假申请吗?')) {
 | 
						||
        fetch(`/admin/leave/${leaveId}/approve`, {
 | 
						||
            method: 'POST',
 | 
						||
            headers: {
 | 
						||
                'Content-Type': 'application/json',
 | 
						||
            }
 | 
						||
        }).then(response => {
 | 
						||
            if (response.ok) {
 | 
						||
                location.reload();
 | 
						||
            } else {
 | 
						||
                alert('操作失败,请稍后重试');
 | 
						||
            }
 | 
						||
        }).catch(error => {
 | 
						||
            console.error('Error:', error);
 | 
						||
            alert('操作失败,请稍后重试');
 | 
						||
        });
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
function rejectLeave(leaveId) {
 | 
						||
    if (confirm('确认拒绝这个请假申请吗?')) {
 | 
						||
        fetch(`/admin/leave/${leaveId}/reject`, {
 | 
						||
            method: 'POST',
 | 
						||
            headers: {
 | 
						||
                'Content-Type': 'application/json',
 | 
						||
            }
 | 
						||
        }).then(response => {
 | 
						||
            if (response.ok) {
 | 
						||
                location.reload();
 | 
						||
            } else {
 | 
						||
                alert('操作失败,请稍后重试');
 | 
						||
            }
 | 
						||
        }).catch(error => {
 | 
						||
            console.error('Error:', error);
 | 
						||
            alert('操作失败,请稍后重试');
 | 
						||
        });
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
// 页面加载时更新时间,然后每分钟更新一次
 | 
						||
document.addEventListener('DOMContentLoaded', function() {
 | 
						||
    updateCurrentTime();
 | 
						||
    setInterval(updateCurrentTime, 60000); // 每分钟更新一次
 | 
						||
});
 | 
						||
</script>
 | 
						||
{% endblock %}
 |