CHM_attendance/app/templates/admin/student_detail.html
2025-06-12 10:41:08 +08:00

474 lines
21 KiB
HTML

{% extends 'layout/base.html' %}
{% block title %}学生详情 - {{ student.name }} - SmartDSP考勤管理系统{% endblock %}
{% block content %}
<div class="container-fluid mt-4">
<!-- 返回按钮 -->
<div class="mb-3">
<a href="{{ url_for('admin.student_list') }}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i>返回学生列表
</a>
</div>
<!-- 学生基本信息 -->
<div class="row">
<div class="col-md-8">
<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 me-2"></i>基本信息
</h6>
<div class="btn-group">
<a href="{{ url_for('admin.edit_student', student_number=student.student_number) }}"
class="btn btn-primary btn-sm">
<i class="fas fa-edit me-1"></i>编辑
</a>
<button class="btn btn-danger btn-sm" onclick="deleteStudent('{{ student.student_number }}')">
<i class="fas fa-trash me-1"></i>删除
</button>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<table class="table table-borderless table-sm">
<tr>
<td class="fw-bold text-muted" style="width: 30%;">学号:</td>
<td>{{ student.student_number }}</td>
</tr>
<tr>
<td class="fw-bold text-muted">姓名:</td>
<td><strong>{{ student.name }}</strong></td>
</tr>
<tr>
<td class="fw-bold text-muted">性别:</td>
<td>
{% if student.gender == '男' %}
<i class="fas fa-mars text-primary me-1"></i>{{ student.gender }}
{% else %}
<i class="fas fa-venus text-danger me-1"></i>{{ student.gender }}
{% endif %}
</td>
</tr>
<tr>
<td class="fw-bold text-muted">年级:</td>
<td>{{ student.grade }}级</td>
</tr>
<tr>
<td class="fw-bold text-muted">手机号:</td>
<td>
{% if student.phone %}
<i class="fas fa-phone me-1"></i>{{ student.phone }}
{% else %}
<span class="text-muted">未填写</span>
{% endif %}
</td>
</tr>
</table>
</div>
<div class="col-md-6">
<table class="table table-borderless table-sm">
<tr>
<td class="fw-bold text-muted" style="width: 30%;">学院:</td>
<td>
{% if student.college %}
<i class="fas fa-university me-1"></i>{{ student.college }}
{% else %}
<span class="text-muted">未填写</span>
{% endif %}
</td>
</tr>
<tr>
<td class="fw-bold text-muted">专业:</td>
<td>
{% if student.major %}
<i class="fas fa-graduation-cap me-1"></i>{{ student.major }}
{% else %}
<span class="text-muted">未填写</span>
{% endif %}
</td>
</tr>
<tr>
<td class="fw-bold text-muted">导师:</td>
<td>
{% if student.supervisor %}
<i class="fas fa-user-tie me-1"></i>{{ student.supervisor }}
{% else %}
<span class="text-muted">未分配</span>
{% endif %}
</td>
</tr>
<tr>
<td class="fw-bold text-muted">学位类型:</td>
<td>
{% if student.degree_type %}
<span class="badge bg-info">{{ student.degree_type }}</span>
{% else %}
<span class="text-muted">未填写</span>
{% endif %}
</td>
</tr>
<tr>
<td class="fw-bold text-muted">状态:</td>
<td>
{% if student.status == '在读' %}
<span class="badge bg-success">
<i class="fas fa-check me-1"></i>在读
</span>
{% else %}
<span class="badge bg-secondary">
<i class="fas fa-graduation-cap me-1"></i>毕业
</span>
{% endif %}
</td>
</tr>
</table>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<div class="fw-bold text-muted mb-2">
<i class="fas fa-calendar-alt me-1"></i>入学日期:
</div>
<div class="ms-3">
{% if student.enrollment_date %}
<span class="badge bg-light text-dark">
{{ student.enrollment_date.strftime('%Y年%m月%d日') }}
</span>
{% else %}
<span class="text-muted">未填写</span>
{% endif %}
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<div class="fw-bold text-muted mb-2">
<i class="fas fa-clock me-1"></i>注册时间:
</div>
<div class="ms-3">
<span class="badge bg-light text-dark">
{{ student.created_at.strftime('%Y年%m月%d日 %H:%M') }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<!-- 考勤统计 -->
<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-chart-bar me-2"></i>考勤统计
</h6>
</div>
<div class="card-body text-center">
<div class="row">
<div class="col-6 border-end">
<div class="h4 mb-0 text-primary">{{ "%.1f"|format(total_work_hours) }}</div>
<div class="text-muted small">总工作时长(小时)</div>
</div>
<div class="col-6">
<div class="h4 mb-0 text-warning">{{ total_absent_days }}</div>
<div class="text-muted small">旷工天数</div>
</div>
</div>
<hr class="my-3">
<div class="row">
<div class="col-12">
<div class="h5 mb-0 text-info">{{ attendance_records|length }}</div>
<div class="text-muted small">考勤记录数</div>
</div>
</div>
</div>
</div>
<!-- 账户信息 -->
<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-key me-2"></i>账户信息
</h6>
</div>
<div class="card-body">
{% if student.user %}
<div class="mb-3">
<span class="fw-bold">账户状态:</span>
{% if student.user.is_active %}
<span class="badge bg-success">
<i class="fas fa-check me-1"></i>正常
</span>
{% else %}
<span class="badge bg-danger">
<i class="fas fa-ban me-1"></i>已禁用
</span>
{% endif %}
</div>
<div class="mb-3">
<span class="fw-bold">最后登录:</span>
<br>
{% if student.user.last_login %}
<small class="text-muted">
{{ student.user.last_login.strftime('%Y-%m-%d %H:%M') }}
</small>
{% else %}
<small class="text-muted">从未登录</small>
{% endif %}
</div>
<div class="d-grid gap-2">
<button class="btn btn-outline-warning btn-sm" onclick="resetPassword()">
<i class="fas fa-key me-1"></i>重置密码
</button>
<button class="btn btn-outline-secondary btn-sm" onclick="toggleAccountStatus()">
{% if student.user.is_active %}
<i class="fas fa-ban me-1"></i>禁用账户
{% else %}
<i class="fas fa-check me-1"></i>启用账户
{% endif %}
</button>
</div>
{% else %}
<div class="text-center text-muted">
<i class="fas fa-exclamation-triangle fa-2x mb-2"></i>
<p>该学生暂无账户信息</p>
</div>
{% endif %}
</div>
</div>
<!-- 快速操作 -->
<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="d-grid gap-2">
<a href="{{ url_for('admin.attendance_management') }}?student_search={{ student.student_number }}"
class="btn btn-outline-info btn-sm">
<i class="fas fa-calendar-check me-1"></i>查看考勤详情
</a>
<button class="btn btn-outline-primary btn-sm" onclick="exportStudentData()">
<i class="fas fa-download me-1"></i>导出数据
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 最近考勤记录 -->
<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-calendar-check me-2"></i>最近考勤记录
</h6>
<a href="{{ url_for('admin.attendance_management') }}?student_search={{ student.student_number }}"
class="btn btn-primary btn-sm">
<i class="fas fa-eye me-1"></i>查看全部
</a>
</div>
<div class="card-body">
{% if attendance_records %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>周期</th>
<th>实际工作时长</th>
<th>班内工作时长</th>
<th>旷工天数</th>
<th>加班时长</th>
<th>创建时间</th>
</tr>
</thead>
<tbody>
{% for record in attendance_records %}
<tr>
<td>
<div class="fw-bold">
{{ record.week_start_date.strftime('%m-%d') }}
{{ record.week_end_date.strftime('%m-%d') }}
</div>
<small class="text-muted">
{{ record.week_start_date.strftime('%Y年') }}
</small>
</td>
<td>
<span class="badge bg-primary">
{{ "%.1f"|format(record.actual_work_hours or 0) }}h
</span>
</td>
<td>
<span class="badge bg-info">
{{ "%.1f"|format(record.class_work_hours or 0) }}h
</span>
</td>
<td>
{% if record.absent_days > 0 %}
<span class="badge bg-warning">{{ record.absent_days }}天</span>
{% else %}
<span class="text-success">
<i class="fas fa-check"></i> 0天
</span>
{% endif %}
</td>
<td>
{% if record.overtime_hours > 0 %}
<span class="badge bg-success">
{{ "%.1f"|format(record.overtime_hours) }}h
</span>
{% else %}
<span class="text-muted">0h</span>
{% endif %}
</td>
<td>
<small class="text-muted">
{{ record.created_at.strftime('%m-%d %H:%M') }}
</small>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-calendar-times fa-3x text-muted mb-3"></i>
<p class="text-muted">暂无考勤记录</p>
<a href="{{ url_for('admin.upload_attendance') }}" class="btn btn-outline-primary">
<i class="fas fa-upload me-1"></i>上传考勤数据
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// 删除学生
function deleteStudent(studentNumber) {
if (confirm('确认删除这个学生吗?此操作不可恢复!\n\n学生的所有考勤记录也将被删除。')) {
fetch(`/admin/students/${studentNumber}/delete`, {
method: 'POST'
})
.then(response => response.json())
.then(result => {
if (result.success) {
alert(result.message);
window.location.href = '/admin/students';
} else {
alert(result.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('删除失败,请稍后重试');
});
}
}
// 重置密码
function resetPassword() {
if (confirm('确认重置该学生的密码为默认密码(123456)吗?')) {
fetch(`/admin/students/{{ student.student_number }}/reset_password`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(result => {
if (result.success) {
alert('密码重置成功');
} else {
alert(result.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('操作失败,请稍后重试');
});
}
}
// 切换账户状态
function toggleAccountStatus() {
{% if student.user %}
const isActive = {{ 'true' if student.user.is_active else 'false' }};
const action = isActive ? '禁用' : '启用';
if (confirm(`确认${action}该学生的账户吗?`)) {
fetch(`/admin/students/{{ student.student_number }}/toggle_status`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(result => {
if (result.success) {
alert(result.message);
location.reload(); // 重新加载页面以更新按钮状态
} else {
alert(result.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('操作失败,请稍后重试');
});
}
{% else %}
alert('该学生暂无账户信息');
{% endif %}
}
// 导出学生数据(可选功能)
function exportStudentData() {
// 这里可以实现导出学生考勤数据的功能
alert('导出功能正在开发中...');
}
</script>
{% endblock %}
{% block extra_css %}
<style>
.border-end {
border-right: 1px solid #dee2e6 !important;
}
.table-borderless td {
border: none !important;
padding: 0.5rem 0.75rem;
}
.card-header {
background-color: #f8f9fc;
border-bottom: 1px solid #e3e6f0;
}
.badge {
font-size: 0.75em;
}
.btn-group .btn {
margin-left: 0;
}
</style>
{% endblock %}