From 441b4783913b0c7d17db78260c3c97b54abe2c01 Mon Sep 17 00:00:00 2001 From: superlishunqin <852326703@qq.com> Date: Sun, 14 Sep 2025 02:00:19 +0800 Subject: [PATCH] 0914-2-version --- app/routes/student.py | 146 +++++++++++- app/templates/student/attendance.html | 8 +- app/templates/student/attendance_details.html | 218 +++++------------- app/templates/student/dashboard.html | 8 +- app/templates/student/statistics.html | 8 +- 5 files changed, 209 insertions(+), 179 deletions(-) diff --git a/app/routes/student.py b/app/routes/student.py index 7e45b04..597590a 100644 --- a/app/routes/student.py +++ b/app/routes/student.py @@ -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, diff --git a/app/templates/student/attendance.html b/app/templates/student/attendance.html index 77a4c19..69867ca 100644 --- a/app/templates/student/attendance.html +++ b/app/templates/student/attendance.html @@ -108,10 +108,10 @@
- 旷工天数 + 缺勤次数
- {{ total_stats.total_absent_days }}天 + {{ total_stats.total_absent_count }}次
@@ -204,7 +204,7 @@ 实际工作时长 班内工作时长 迟到次数 - 旷工天数 + 缺勤次数 加班时长 记录时间 操作 @@ -236,7 +236,7 @@ {% if record.absent_days > 0 %} - {{ record.absent_days }}天 + {{ record.absent_count if record.absent_count is defined else 0 }}次 {% else %} 0天 {% endif %} diff --git a/app/templates/student/attendance_details.html b/app/templates/student/attendance_details.html index 3cc1456..de23726 100644 --- a/app/templates/student/attendance_details.html +++ b/app/templates/student/attendance_details.html @@ -6,18 +6,9 @@
-
-

- 我的考勤详情 -

- -
+

+ 考勤详情 +

返回列表 @@ -37,8 +28,8 @@
-

学号: {{ record.student_number }}

-

姓名: {{ record.name }}

+

学号: {{ weekly_record.student_number }}

+

姓名: {{ weekly_record.name }}

{% if student %}

年级: {{ student.grade }}

学院: {{ student.college or '未设置' }}

@@ -71,12 +62,12 @@
-

开始日期: {{ record.week_start_date.strftime('%Y年%m月%d日') }}

-

结束日期: {{ record.week_end_date.strftime('%Y年%m月%d日') }}

+

开始日期: {{ weekly_record.week_start_date.strftime('%Y年%m月%d日') }}

+

结束日期: {{ weekly_record.week_end_date.strftime('%Y年%m月%d日') }}

-

创建时间: {{ record.created_at.strftime('%Y-%m-%d %H:%M') }}

-

更新时间: {{ record.updated_at.strftime('%Y-%m-%d %H:%M') }}

+

创建时间: {{ weekly_record.created_at.strftime('%Y-%m-%d %H:%M') }}

+

更新时间: {{ weekly_record.updated_at.strftime('%Y-%m-%d %H:%M') }}

@@ -95,7 +86,7 @@ 实际出勤时长
- {{ "%.1f"|format(record.actual_work_hours) }}小时 + {{ "%.1f"|format(weekly_record.actual_work_hours) }}小时
@@ -115,7 +106,7 @@ 班内工作时长
- {{ "%.1f"|format(record.class_work_hours) }}小时 + {{ "%.1f"|format(weekly_record.class_work_hours) }}小时
@@ -131,11 +122,13 @@
+ {# 🔥 修改:标题改为“缺勤次数” #}
- 旷工天数 + 缺勤次数
- {{ record.absent_days }}天 + {# 🔥 修改:使用 weekly_record.absent_count,单位改为“次” #} + {{ weekly_record.absent_count if weekly_record.absent_count is defined else 0 }}次
@@ -155,7 +148,7 @@ 加班时长
- {{ "%.1f"|format(record.overtime_hours) }}小时 + {{ "%.1f"|format(weekly_record.overtime_hours) }}小时
@@ -172,7 +165,7 @@
每日考勤明细 - (点击详情按钮查看详细时段信息) + (点击日期查看详细时段信息)
@@ -194,10 +187,7 @@ {% for detail in daily_details %} - - {{ detail.attendance_date.strftime('%m-%d') }} - {{ detail.attendance_date.strftime('%Y') }} - + {{ detail.attendance_date.strftime('%m-%d') }} {% set weekday = detail.attendance_date.weekday() %} {% if weekday == 0 %}周一 @@ -208,10 +198,6 @@ {% elif weekday == 5 %}周六 {% else %}周日 {% endif %} - - {% if weekday >= 5 %} - 休息日 - {% endif %} {% if detail.status == '正常' %} @@ -232,14 +218,14 @@ {% if detail.check_in_time %} - {{ detail.check_in_time.strftime('%H:%M') }} + {{ detail.check_in_time.strftime('%H:%M') }} {% else %} 未打卡 {% endif %} {% if detail.check_out_time %} - {{ detail.check_out_time.strftime('%H:%M') }} + {{ detail.check_out_time.strftime('%H:%M') }} {% else %} 未打卡 {% endif %} @@ -273,8 +259,8 @@
{% else %} -
- +
+
暂无每日考勤明细

该考勤周期内没有详细的打卡记录

@@ -282,7 +268,7 @@
- +
@@ -307,8 +293,9 @@
-
{{ absent_days }}
- 缺勤天数 + {# 🔥 修改:标题改为“缺勤次数”,数据源改为 weekly_record.absent_count #} +
{{ weekly_record.absent_count if weekly_record.absent_count is defined else 0 }}
+ 缺勤次数
@@ -316,23 +303,6 @@ 日均时长
- - -
-
-
-
{{ "%.1f"|format((present_days / max(total_days, 1) * 100)) }}%
- 出勤率 -
-
-
{{ "%.1f"|format((record.class_work_hours / max(record.actual_work_hours, 1) * 100)) }}%
- 班内工作率 -
-
-
{{ total_days }}
- 考勤天数 -
-
@@ -345,19 +315,19 @@
- {% if recent_records %} + {% if historical_records %}
- - + {# 🔥 修改:表头改为“缺勤次数” #} + - {% for record_item in recent_records %} + {% for record_item in historical_records %} - @@ -394,27 +356,11 @@ - - - {% if late_days > 0 or absent_days > 0 %} - - {% endif %} - + @@ -128,7 +128,7 @@ - + @@ -298,7 +298,7 @@
周期 出勤时长旷工天数对比缺勤次数
{{ record_item.week_start_date.strftime('%m-%d') }} @@ -366,20 +336,12 @@ {{ "%.1f"|format(record_item.actual_work_hours) }}h - {% if record_item.absent_days > 0 %} - {{ record_item.absent_days }} + {# 🔥 修改:使用 record_item.absent_count,单位改为“次” #} + {% set absent_count = record_item.absent_count if record_item.absent_count is defined else 0 %} + {% if absent_count > 0 %} + {{ absent_count }}次 {% else %} - 0 - {% endif %} - - {% set diff = record.actual_work_hours - record_item.actual_work_hours %} - {% if diff > 0 %} - +{{ "%.1f"|format(diff) }}h - {% elif diff < 0 %} - {{ "%.1f"|format(diff) }}h - {% else %} - - + 0次 {% endif %}
周次 实际工作时长 班内工作时长旷工天数缺勤次数 加班时长
{% if record.absent_days > 0 %} - {{ record.absent_days }}天 + {{ record.absent_count if record.absent_count is defined else 0 }}次 {% else %} 0天 {% endif %} diff --git a/app/templates/student/statistics.html b/app/templates/student/statistics.html index b0aee22..ab1a19a 100644 --- a/app/templates/student/statistics.html +++ b/app/templates/student/statistics.html @@ -119,8 +119,8 @@
-

{{ all_time_stats.total_absent_days }}

- 旷工天数 +

{{ all_time_stats.total_absent_count }}

+ 缺勤次数
@@ -267,7 +267,7 @@
实际工作时长 班内工作时长 加班时长旷工天数缺勤次数 考勤状态 操作
{% if record.absent_days > 0 %} - {{ record.absent_days }}天 + {{ record.absent_count if record.absent_count is defined else 0 }}次 {% else %} 0天 {% endif %}