0914-2-version

This commit is contained in:
superlishunqin 2025-09-14 02:00:19 +08:00
parent 77b57a9876
commit 441b478391
5 changed files with 209 additions and 179 deletions

View File

@ -6,6 +6,68 @@ from app.utils.database import safe_add_and_commit
from datetime import datetime, timedelta
from sqlalchemy import and_, or_, desc
# 这个文件包含需要在student.py中添加的缺勤次数计算函数
def calculate_absent_count_for_record(record):
"""为单个考勤记录计算真实的缺勤次数"""
import json
from app.models import DailyAttendanceDetail
# 获取该记录的每日明细
daily_details = DailyAttendanceDetail.query.filter_by(
weekly_record_id=record.record_id
).all()
absent_count = 0
for detail in daily_details:
# 处理完全缺勤的情况
if detail.status == '缺勤' and (not detail.remarks or not detail.remarks.startswith('{')):
# 完全缺勤的天数,早上+下午都缺勤
absent_count += 2 # 早上缺勤1次 + 下午缺勤1次
continue
if detail.remarks and detail.remarks.startswith('{'):
try:
remarks_data = json.loads(detail.remarks)
details_info = remarks_data.get('details', {})
# 统计缺勤次数
# 检查早上缺勤morning_in AND morning_out 都missing
morning_data = details_info.get('morning', {})
morning_in_time = morning_data.get('in')
morning_out_time = morning_data.get('out')
morning_in_status = morning_data.get('status', 'missing')
if ((not morning_in_time or morning_in_status == 'missing') and
(not morning_out_time)):
absent_count += 1
# 检查下午缺勤afternoon_in AND afternoon_out 都missing
afternoon_data = details_info.get('afternoon', {})
afternoon_in_time = afternoon_data.get('in')
afternoon_out_time = afternoon_data.get('out')
afternoon_in_status = afternoon_data.get('status', 'missing')
if ((not afternoon_in_time or afternoon_in_status == 'missing') and
(not afternoon_out_time)):
absent_count += 1
except (json.JSONDecodeError, KeyError, AttributeError):
continue
return absent_count
def add_absent_count_to_records(records):
"""为考勤记录列表添加缺勤次数计算属性"""
total_absent_count = 0
for record in records:
absent_count = calculate_absent_count_for_record(record)
record.absent_count = absent_count
total_absent_count += absent_count
return total_absent_count
student_bp = Blueprint('student', __name__)
@ -35,9 +97,9 @@ def dashboard():
db.func.sum(WeeklyAttendance.actual_work_hours)
).filter_by(student_number=current_user.student_number).scalar() or 0
total_absent_days = db.session.query(
db.func.sum(WeeklyAttendance.absent_days)
).filter_by(student_number=current_user.student_number).scalar() or 0
# 获取所有考勤记录并计算真实缺勤次数
all_records = WeeklyAttendance.query.filter_by(student_number=current_user.student_number).all()
total_absent_count = add_absent_count_to_records(all_records)
# 获取未审批的请假记录
pending_leaves = LeaveRecord.query.filter_by(
@ -50,7 +112,7 @@ def dashboard():
recent_attendance=recent_attendance,
total_records=total_records,
total_work_hours=float(total_work_hours),
total_absent_days=int(total_absent_days),
total_absent_count=int(total_absent_count),
pending_leaves=pending_leaves)
@ -147,7 +209,9 @@ def attendance():
total_actual_hours = sum(record.actual_work_hours for record, _ in all_records)
total_class_hours = sum(record.class_work_hours for record, _ in all_records)
total_absent_days = sum(record.absent_days for record, _ in all_records)
# 为记录添加缺勤次数计算
record_list = [record for record, _ in all_records]
total_absent_count = add_absent_count_to_records(record_list)
total_overtime_hours = sum(record.overtime_hours for record, _ in all_records)
total_late_count = sum(late_count for _, late_count in all_records)
@ -164,7 +228,7 @@ def attendance():
'total_weeks': len(all_records),
'total_actual_hours': total_actual_hours,
'total_class_hours': total_class_hours,
'total_absent_days': total_absent_days,
'total_absent_count': total_absent_count,
'total_overtime_hours': total_overtime_hours,
'total_late_count': total_late_count,
'total_leave_days': total_leave_days,
@ -200,6 +264,61 @@ def attendance_details(record_id):
weekly_record_id=record_id
).order_by(DailyAttendanceDetail.attendance_date).all()
# 🔥 新增:计算真实的缺勤次数和迟到次数
def calculate_real_counts(daily_details_list):
"""计算真实的缺勤次数和迟到次数"""
late_count = 0
absent_count = 0
for detail in daily_details_list:
# 🔥 处理完全缺勤的情况
if detail.status == '缺勤' and (not detail.remarks or not detail.remarks.startswith('{')):
# 完全缺勤的天数,早上+下午都缺勤
absent_count += 2 # 早上缺勤1次 + 下午缺勤1次
continue
if detail.remarks and detail.remarks.startswith('{'):
try:
remarks_data = json.loads(detail.remarks)
details_info = remarks_data.get('details', {})
# 统计迟到次数
for period in ['morning', 'afternoon', 'evening']:
period_data = details_info.get(period, {})
if period_data.get('status') == 'late':
late_count += 1
# 统计缺勤次数
# 检查早上缺勤morning_in AND morning_out 都missing
morning_data = details_info.get('morning', {})
morning_in_time = morning_data.get('in')
morning_out_time = morning_data.get('out')
morning_in_status = morning_data.get('status', 'missing')
if ((not morning_in_time or morning_in_status == 'missing') and
(not morning_out_time)):
absent_count += 1
# 检查下午缺勤afternoon_in AND afternoon_out 都missing
afternoon_data = details_info.get('afternoon', {})
afternoon_in_time = afternoon_data.get('in')
afternoon_out_time = afternoon_data.get('out')
afternoon_in_status = afternoon_data.get('status', 'missing')
if ((not afternoon_in_time or afternoon_in_status == 'missing') and
(not afternoon_out_time)):
absent_count += 1
except (json.JSONDecodeError, KeyError, AttributeError):
continue
return late_count, absent_count
# 🔥 计算真实的次数并添加到record对象中
real_late_count, real_absent_count = calculate_real_counts(daily_details)
record.late_count = real_late_count
record.absent_count = real_absent_count
# 处理每日详情,计算工作时长和解析详细信息
processed_daily_details = []
for detail in daily_details:
@ -264,8 +383,9 @@ def attendance_details(record_id):
desc(WeeklyAttendance.week_start_date)
).limit(5).all()
# 🔥 修改:传递 weekly_record 而不是 record以匹配模板
return render_template('student/attendance_details.html',
record=record,
weekly_record=record, # 🔥 关键修改
student=student,
daily_details=processed_daily_details,
total_days=total_days,
@ -275,7 +395,6 @@ def attendance_details(record_id):
avg_daily_hours=avg_daily_hours,
recent_records=recent_records)
@student_bp.route('/statistics')
@login_required
def statistics():
@ -313,12 +432,15 @@ def statistics():
# 获取考勤记录,按周排序
attendance_records = attendance_query.order_by(desc(WeeklyAttendance.week_start_date)).all()
# 计算真实缺勤次数
add_absent_count_to_records(attendance_records)
# 计算统计数据
total_stats = {
'total_work_hours': sum(record.actual_work_hours for record in attendance_records),
'total_class_hours': sum(record.class_work_hours for record in attendance_records),
'total_overtime_hours': sum(record.overtime_hours for record in attendance_records),
'total_absent_days': sum(record.absent_days for record in attendance_records),
'total_absent_count': sum(getattr(record, 'absent_count', 0) for record in attendance_records),
'attendance_weeks': len(attendance_records)
}
@ -400,11 +522,15 @@ def statistics():
if all_records:
# 计算入学以来的总统计
enrollment_weeks = (datetime.now().date() - student.enrollment_date).days // 7
# 🔥 修复:先计算缺勤次数,再定义字典
add_absent_count_to_records(all_records)
all_time_stats = {
'total_work_hours': sum(record.actual_work_hours for record in all_records),
'total_class_hours': sum(record.class_work_hours for record in all_records),
'total_overtime_hours': sum(record.overtime_hours for record in all_records),
'total_absent_days': sum(record.absent_days for record in all_records),
'total_absent_count': sum(getattr(record, 'absent_count', 0) for record in all_records),
'attendance_weeks': len(all_records),
'enrollment_weeks': enrollment_weeks,
'attendance_rate': round(len(all_records) / max(enrollment_weeks, 1) * 100,

View File

@ -108,10 +108,10 @@
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-danger text-uppercase mb-1">
旷工天
缺勤次
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{{ total_stats.total_absent_days }}天
{{ total_stats.total_absent_count }}次
</div>
</div>
<div class="col-auto">
@ -204,7 +204,7 @@
<th>实际工作时长</th>
<th>班内工作时长</th>
<th>迟到次数</th>
<th>旷工天</th>
<th>缺勤次</th>
<th>加班时长</th>
<th>记录时间</th>
<th>操作</th>
@ -236,7 +236,7 @@
</td>
<td>
{% if record.absent_days > 0 %}
<span class="badge bg-danger">{{ record.absent_days }}天</span>
<span class="badge bg-danger">{{ record.absent_count if record.absent_count is defined else 0 }}次</span>
{% else %}
<span class="badge bg-success">0天</span>
{% endif %}

View File

@ -6,18 +6,9 @@
<div class="container-fluid mt-4">
<!-- 页面标题 -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2 class="fw-bold text-primary mb-0">
<i class="fas fa-calendar-check me-2"></i>我的考勤详情
</h2>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ url_for('student.dashboard') }}">首页</a></li>
<li class="breadcrumb-item"><a href="{{ url_for('student.attendance') }}">考勤记录</a></li>
<li class="breadcrumb-item active">考勤详情</li>
</ol>
</nav>
</div>
<h1 class="h3 mb-0">
<i class="fas fa-calendar-check me-2"></i>考勤详情
</h1>
<div>
<a href="{{ url_for('student.attendance') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left me-2"></i>返回列表
@ -37,8 +28,8 @@
<div class="card-body">
<div class="row">
<div class="col-6">
<p><strong>学号:</strong> {{ record.student_number }}</p>
<p><strong>姓名:</strong> {{ record.name }}</p>
<p><strong>学号:</strong> {{ weekly_record.student_number }}</p>
<p><strong>姓名:</strong> {{ weekly_record.name }}</p>
{% if student %}
<p><strong>年级:</strong> {{ student.grade }}</p>
<p><strong>学院:</strong> {{ student.college or '未设置' }}</p>
@ -71,12 +62,12 @@
<div class="card-body">
<div class="row">
<div class="col-6">
<p><strong>开始日期:</strong> {{ record.week_start_date.strftime('%Y年%m月%d日') }}</p>
<p><strong>结束日期:</strong> {{ record.week_end_date.strftime('%Y年%m月%d日') }}</p>
<p><strong>开始日期:</strong> {{ weekly_record.week_start_date.strftime('%Y年%m月%d日') }}</p>
<p><strong>结束日期:</strong> {{ weekly_record.week_end_date.strftime('%Y年%m月%d日') }}</p>
</div>
<div class="col-6">
<p><strong>创建时间:</strong> {{ record.created_at.strftime('%Y-%m-%d %H:%M') }}</p>
<p><strong>更新时间:</strong> {{ record.updated_at.strftime('%Y-%m-%d %H:%M') }}</p>
<p><strong>创建时间:</strong> {{ weekly_record.created_at.strftime('%Y-%m-%d %H:%M') }}</p>
<p><strong>更新时间:</strong> {{ weekly_record.updated_at.strftime('%Y-%m-%d %H:%M') }}</p>
</div>
</div>
</div>
@ -95,7 +86,7 @@
实际出勤时长
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{{ "%.1f"|format(record.actual_work_hours) }}小时
{{ "%.1f"|format(weekly_record.actual_work_hours) }}小时
</div>
</div>
<div class="col-auto">
@ -115,7 +106,7 @@
班内工作时长
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{{ "%.1f"|format(record.class_work_hours) }}小时
{{ "%.1f"|format(weekly_record.class_work_hours) }}小时
</div>
</div>
<div class="col-auto">
@ -131,11 +122,13 @@
<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">
{{ record.absent_days }}天
{# 🔥 修改:使用 weekly_record.absent_count单位改为“次” #}
{{ weekly_record.absent_count if weekly_record.absent_count is defined else 0 }}次
</div>
</div>
<div class="col-auto">
@ -155,7 +148,7 @@
加班时长
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{{ "%.1f"|format(record.overtime_hours) }}小时
{{ "%.1f"|format(weekly_record.overtime_hours) }}小时
</div>
</div>
<div class="col-auto">
@ -172,7 +165,7 @@
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">
<i class="fas fa-list me-2"></i>每日考勤明细
<small class="text-muted">(点击详情按钮查看详细时段信息)</small>
<small class="text-muted">(点击日期查看详细时段信息)</small>
</h6>
</div>
<div class="card-body">
@ -194,10 +187,7 @@
<tbody>
{% for detail in daily_details %}
<tr class="{% if '迟到' in detail.status %}table-warning{% elif detail.status == '缺勤' %}table-danger{% endif %}">
<td>
<strong>{{ detail.attendance_date.strftime('%m-%d') }}</strong>
<small class="d-block text-muted">{{ detail.attendance_date.strftime('%Y') }}</small>
</td>
<td>{{ detail.attendance_date.strftime('%m-%d') }}</td>
<td>
{% set weekday = detail.attendance_date.weekday() %}
{% if weekday == 0 %}周一
@ -208,10 +198,6 @@
{% elif weekday == 5 %}周六
{% else %}周日
{% endif %}
{% if weekday >= 5 %}
<small class="badge bg-info">休息日</small>
{% endif %}
</td>
<td>
{% if detail.status == '正常' %}
@ -232,14 +218,14 @@
</td>
<td>
{% if detail.check_in_time %}
<span class="badge bg-primary">{{ detail.check_in_time.strftime('%H:%M') }}</span>
{{ detail.check_in_time.strftime('%H:%M') }}
{% else %}
<span class="text-muted">未打卡</span>
{% endif %}
</td>
<td>
{% if detail.check_out_time %}
<span class="badge bg-success">{{ detail.check_out_time.strftime('%H:%M') }}</span>
{{ detail.check_out_time.strftime('%H:%M') }}
{% else %}
<span class="text-muted">未打卡</span>
{% endif %}
@ -273,8 +259,8 @@
</table>
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-calendar-times fa-4x text-muted mb-3"></i>
<div class="text-center py-3">
<i class="fas fa-calendar-times fa-3x text-muted mb-3"></i>
<h5 class="text-muted">暂无每日考勤明细</h5>
<p class="text-muted">该考勤周期内没有详细的打卡记录</p>
</div>
@ -282,7 +268,7 @@
</div>
</div>
<!-- 统计分析和历史对比 -->
<!-- 统计分析和历史对比的其他部分... -->
<div class="row mb-4">
<div class="col-md-6">
<div class="card shadow">
@ -307,8 +293,9 @@
</div>
<div class="col-3">
<div class="border-end">
<h6 class="text-danger">{{ absent_days }}</h6>
<small class="text-muted">缺勤天数</small>
{# 🔥 修改:标题改为“缺勤次数”,数据源改为 weekly_record.absent_count #}
<h6 class="text-danger">{{ weekly_record.absent_count if weekly_record.absent_count is defined else 0 }}</h6>
<small class="text-muted">缺勤次数</small>
</div>
</div>
<div class="col-3">
@ -316,23 +303,6 @@
<small class="text-muted">日均时长</small>
</div>
</div>
<!-- 出勤率计算 -->
<hr>
<div class="row text-center">
<div class="col-4">
<h6 class="text-primary">{{ "%.1f"|format((present_days / max(total_days, 1) * 100)) }}%</h6>
<small class="text-muted">出勤率</small>
</div>
<div class="col-4">
<h6 class="text-success">{{ "%.1f"|format((record.class_work_hours / max(record.actual_work_hours, 1) * 100)) }}%</h6>
<small class="text-muted">班内工作率</small>
</div>
<div class="col-4">
<h6 class="text-info">{{ total_days }}</h6>
<small class="text-muted">考勤天数</small>
</div>
</div>
</div>
</div>
</div>
@ -345,19 +315,19 @@
</h6>
</div>
<div class="card-body">
{% if recent_records %}
{% if historical_records %}
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>周期</th>
<th>出勤时长</th>
<th>旷工天数</th>
<th>对比</th>
{# 🔥 修改:表头改为“缺勤次数” #}
<th>缺勤次数</th>
</tr>
</thead>
<tbody>
{% for record_item in recent_records %}
{% for record_item in historical_records %}
<tr>
<td>
<small>{{ record_item.week_start_date.strftime('%m-%d') }}</small>
@ -366,20 +336,12 @@
<span class="badge bg-primary">{{ "%.1f"|format(record_item.actual_work_hours) }}h</span>
</td>
<td>
{% if record_item.absent_days > 0 %}
<span class="badge bg-warning">{{ record_item.absent_days }}</span>
{# 🔥 修改:使用 record_item.absent_count单位改为“次” #}
{% set absent_count = record_item.absent_count if record_item.absent_count is defined else 0 %}
{% if absent_count > 0 %}
<span class="badge bg-warning">{{ absent_count }}次</span>
{% else %}
<span class="badge bg-success">0</span>
{% endif %}
</td>
<td>
{% set diff = record.actual_work_hours - record_item.actual_work_hours %}
{% if diff > 0 %}
<small class="text-success">+{{ "%.1f"|format(diff) }}h</small>
{% elif diff < 0 %}
<small class="text-danger">{{ "%.1f"|format(diff) }}h</small>
{% else %}
<small class="text-muted">-</small>
<span class="badge bg-success">0次</span>
{% endif %}
</td>
</tr>
@ -394,27 +356,11 @@
</div>
</div>
</div>
<!-- 操作建议 -->
{% if late_days > 0 or absent_days > 0 %}
<div class="alert alert-warning" role="alert">
<h6 class="alert-heading"><i class="fas fa-exclamation-triangle me-2"></i>考勤提醒</h6>
<p class="mb-0">
{% if late_days > 0 %}
本周有 <strong>{{ late_days }}</strong> 天迟到,
{% endif %}
{% if absent_days > 0 %}
<strong>{{ absent_days }}</strong> 天缺勤,
{% endif %}
请注意调整作息时间,保持良好的考勤记录。
</p>
</div>
{% endif %}
</div>
<!-- 详细时段信息模态框 -->
<div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-dialog modal-lg modal-dialog-centered"> <!-- 添加 modal-dialog-centered -->
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="detailModalLabel">
@ -472,54 +418,22 @@
border-radius: 0.35rem;
padding: 1rem;
margin-bottom: 1rem;
background-color: #f8f9fc;
}
.period-header {
font-weight: 600;
color: #5a5c69;
margin-bottom: 0.75rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid #e3e6f0;
margin-bottom: 0.5rem;
}
.badge.bg-orange {
background-color: #fd7e14 !important;
}
.time-info {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
.badge.bg-orange {
background-color: #fd7e14 !important;
color: white;
}
.time-info > div {
flex: 1;
min-width: 120px;
}
/* 高亮迟到和缺勤行 */
.table-warning {
--bs-table-accent-bg: rgba(255, 193, 7, 0.1);
}
.table-danger {
--bs-table-accent-bg: rgba(220, 53, 69, 0.1);
}
@media (max-width: 768px) {
.time-info {
flex-direction: column;
align-items: flex-start;
}
.time-info > div {
width: 100%;
margin-bottom: 0.5rem;
}
}
</style>
{% endblock %}
@ -529,7 +443,7 @@
function showDetailModal(detailId, date, remarksJson) {
document.getElementById('modalDate').textContent = date;
console.log('调用showDetailModal', detailId, date, remarksJson);
console.log('调用showDetailModal', detailId, date, remarksJson); // 调试信息
let detailsData = null;
@ -537,7 +451,7 @@ function showDetailModal(detailId, date, remarksJson) {
if (remarksJson && remarksJson.startsWith('{')) {
const parsed = JSON.parse(remarksJson);
detailsData = parsed.details;
console.log('解析的详细数据:', detailsData);
console.log('解析的详细数据:', detailsData); // 调试信息
}
} catch (e) {
console.error('解析详细信息失败:', e);
@ -545,15 +459,15 @@ function showDetailModal(detailId, date, remarksJson) {
if (!detailsData) {
document.getElementById('detailContent').innerHTML =
'<div class="alert alert-info"><i class="fas fa-info-circle me-2"></i>暂无详细时段信息</div>';
'<p class="text-muted">暂无详细时段信息</p><p class="text-muted">原始数据: ' + remarksJson + '</p>';
} else {
let html = '';
// 显示各个时段的详情
const periods = [
{ key: 'morning', name: '早上时段', time: '09:45-11:30', icon: 'fa-sun' },
{ key: 'afternoon', name: '下午时段', time: '13:30-18:30', icon: 'fa-cloud-sun' },
{ key: 'evening', name: '晚上时段', time: '19:00-23:30', icon: 'fa-moon' }
{ key: 'morning', name: '早上时段', time: '09:45-11:30' },
{ key: 'afternoon', name: '下午时段', time: '13:30-18:30' },
{ key: 'evening', name: '晚上时段', time: '19:00-23:30' }
];
periods.forEach(period => {
@ -562,8 +476,7 @@ function showDetailModal(detailId, date, remarksJson) {
html += `
<div class="period-card">
<div class="period-header">
<i class="fas ${period.icon} me-2"></i>${period.name}
<small class="text-muted">(${period.time})</small>
<i class="fas fa-clock me-2"></i>${period.name} (${period.time})
</div>
<div class="time-info">
<div>
@ -571,14 +484,14 @@ function showDetailModal(detailId, date, remarksJson) {
<span class="badge ${getStatusClass(data.status, 'in')}">
${data.in || '未打卡'}
</span>
${data.late_minutes ? `<small class="text-warning d-block">(迟到${data.late_minutes}分钟)</small>` : ''}
${data.late_minutes ? `<small class="text-warning">(迟到${data.late_minutes}分钟)</small>` : ''}
</div>
<div>
<strong>签退:</strong>
<span class="badge ${getStatusClass(data.status, 'out')}">
${data.out || '未打卡'}
</span>
${data.early_minutes ? `<small class="text-warning d-block">(早退${data.early_minutes}分钟)</small>` : ''}
${data.early_minutes ? `<small class="text-warning">(早退${data.early_minutes}分钟)</small>` : ''}
</div>
<div>
<strong>工时:</strong>
@ -595,7 +508,7 @@ function showDetailModal(detailId, date, remarksJson) {
html += `
<div class="period-card">
<div class="period-header">
<i class="fas fa-business-time me-2"></i>周末加班
<i class="fas fa-moon me-2"></i>周末加班
</div>
<div class="time-info">
<div>
@ -616,7 +529,7 @@ function showDetailModal(detailId, date, remarksJson) {
}
if (html === '') {
html = '<div class="alert alert-warning"><i class="fas fa-exclamation-triangle me-2"></i>该日期没有详细的时段打卡信息</div>';
html = '<p class="text-muted">该日期没有详细的时段打卡信息</p>';
}
document.getElementById('detailContent').innerHTML = html;
@ -640,12 +553,7 @@ function calculatePeriodHours(startTime, endTime) {
try {
const start = new Date(`2000-01-01 ${startTime}:00`);
const end = new Date(`2000-01-01 ${endTime}:00`);
let diff = (end - start) / (1000 * 60 * 60);
// 处理跨天情况
if (diff < 0) {
diff += 24;
}
const diff = (end - start) / (1000 * 60 * 60);
if (diff > 0) {
return `<span class="badge bg-primary">${diff.toFixed(1)}h</span>`;
@ -657,17 +565,13 @@ function calculatePeriodHours(startTime, endTime) {
return '<span class="text-muted">-</span>';
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
console.log('学生考勤详情页面已加载');
// 显示考勤统计
console.log('考勤统计:', {
正常天数: {{ present_days }},
迟到天数: {{ late_days }},
缺勤天数: {{ absent_days }},
日均时长: {{ "%.1f"|format(avg_daily_hours) }}
});
});
// 测试函数
function testModal() {
console.log('测试模态框');
document.getElementById('modalDate').textContent = '测试日期';
document.getElementById('detailContent').innerHTML = '<p>测试内容</p>';
const modal = new bootstrap.Modal(document.getElementById('detailModal'));
modal.show();
}
</script>
{% endblock %}

View File

@ -58,8 +58,8 @@
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">{{ total_absent_days }}</h4>
<p class="card-text">旷工天</p>
<h4 class="card-title">{{ total_absent_count }}</h4>
<p class="card-text">缺勤次</p>
</div>
<div class="align-self-center">
<i class="fas fa-exclamation-triangle fa-2x opacity-75"></i>
@ -108,7 +108,7 @@
<th>周次</th>
<th>实际工作时长</th>
<th>班内工作时长</th>
<th>旷工天</th>
<th>缺勤次</th>
<th>加班时长</th>
</tr>
</thead>
@ -128,7 +128,7 @@
</td>
<td>
{% if record.absent_days > 0 %}
<span class="badge bg-danger">{{ record.absent_days }}天</span>
<span class="badge bg-danger">{{ record.absent_count if record.absent_count is defined else 0 }}次</span>
{% else %}
<span class="badge bg-success">0天</span>
{% endif %}

View File

@ -119,8 +119,8 @@
</div>
<div class="col-md-2">
<div class="text-center">
<h4 class="text-danger">{{ all_time_stats.total_absent_days }}</h4>
<small class="text-muted">旷工天</small>
<h4 class="text-danger">{{ all_time_stats.total_absent_count }}</h4>
<small class="text-muted">缺勤次</small>
</div>
</div>
<div class="col-md-2">
@ -267,7 +267,7 @@
<th>实际工作时长</th>
<th>班内工作时长</th>
<th>加班时长</th>
<th>旷工天</th>
<th>缺勤次</th>
<th>考勤状态</th>
<th>操作</th>
</tr>
@ -298,7 +298,7 @@
</td>
<td>
{% if record.absent_days > 0 %}
<span class="badge bg-danger">{{ record.absent_days }}天</span>
<span class="badge bg-danger">{{ record.absent_count if record.absent_count is defined else 0 }}次</span>
{% else %}
<span class="badge bg-success">0天</span>
{% endif %}