Fix attendance filter: align with badge via status_code (not late/early/OT thresholds)
The previous filter used 'late_minutes == 0 AND early_minutes == 0 AND ot_minutes == 0' for '正常', which incorrectly included records whose import-time late_minutes was 0 but post-enrich status_code was 'abnormal' (e.g. act_in=18:00 vs exp_in=11:00) or 'missing' (act_in='-'). Switch filter to status_code conditions so the result set matches the badge rendered from status_code. Also accept the Chinese basic-status labels (正常/異常/缺勤/公假/請假) as filter values, and return only those 5 from /api/attendance/status_texts so the dropdown vocabulary stays in sync. Frontend attendance list: simplify getStatusBadge to drop now-unused late/early/ot props; align row highlight with the basic-status grouping.
This commit is contained in:
+30
-31
@@ -1099,9 +1099,14 @@ async def attendance_status_texts(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Return distinct status_text values for filter dropdown."""
|
||||
rows = db.query(AttendanceRecord.status_text).distinct().all()
|
||||
return [r[0] for r in rows if r[0]]
|
||||
"""Return BASIC status categories for filter dropdown.
|
||||
|
||||
The frontend renders only 5 basic statuses (正常/異常/缺勤/公假/請假),
|
||||
so the dropdown should offer those exact values rather than every
|
||||
raw status_text variant (e.g. '異常-遲到39分'). Keeping it server-driven
|
||||
so client and server agree on the filter vocabulary.
|
||||
"""
|
||||
return ['正常', '異常', '缺勤', '公假', '請假']
|
||||
|
||||
@app.get("/api/attendance/stats")
|
||||
async def attendance_stats(
|
||||
@@ -1263,41 +1268,35 @@ async def attendance_records(
|
||||
if status:
|
||||
q = q.filter(AttendanceRecord.status_code == status)
|
||||
if status_text:
|
||||
# Map status_text filter to actual conditions
|
||||
if status_text == 'abnormal':
|
||||
q = q.filter(
|
||||
(AttendanceRecord.late_minutes > 30) |
|
||||
(AttendanceRecord.early_minutes > 30) |
|
||||
(AttendanceRecord.ot_minutes > 30)
|
||||
)
|
||||
# Map status_text filter to status_code conditions so the result set
|
||||
# stays aligned with the badge rendered from (post-enrich) status_code.
|
||||
# Previously used late/early/OT thresholds which mismatched because
|
||||
# the import path can leave late_minutes=0 while status_code='abnormal'
|
||||
# (e.g. act_in=18:00 vs exp_in=11:00), and missing records also have
|
||||
# all three == 0 despite status_code='missing'.
|
||||
# Accept both English status_code values AND the Chinese basic-status
|
||||
# labels returned by /api/attendance/status_texts dropdown.
|
||||
abnormal_codes = ('abnormal', 'late', 'early', 'ot',
|
||||
'late_early', 'late_ot', 'early_ot')
|
||||
if status_text in ('abnormal', '異常'):
|
||||
q = q.filter(AttendanceRecord.status_code.in_(abnormal_codes))
|
||||
elif status_text == 'late':
|
||||
q = q.filter(
|
||||
(AttendanceRecord.late_minutes > 0) &
|
||||
(AttendanceRecord.late_minutes <= 30)
|
||||
)
|
||||
q = q.filter(AttendanceRecord.status_code.in_(('late', 'late_early', 'late_ot')))
|
||||
elif status_text == 'early':
|
||||
q = q.filter(
|
||||
(AttendanceRecord.early_minutes > 0) &
|
||||
(AttendanceRecord.early_minutes <= 30)
|
||||
)
|
||||
q = q.filter(AttendanceRecord.status_code.in_(('early', 'late_early', 'early_ot')))
|
||||
elif status_text == 'ot':
|
||||
q = q.filter(
|
||||
(AttendanceRecord.ot_minutes > 0) &
|
||||
(AttendanceRecord.ot_minutes <= 30)
|
||||
)
|
||||
elif status_text == 'missing':
|
||||
q = q.filter(AttendanceRecord.status_code.in_(('ot', 'late_ot', 'early_ot')))
|
||||
elif status_text in ('missing', '缺勤'):
|
||||
q = q.filter(AttendanceRecord.status_code == 'missing')
|
||||
elif status_text in ('holiday', 'al', 'sl', 'cl', 'mixed_leave'):
|
||||
elif status_text in ('holiday', '公假'):
|
||||
q = q.filter(AttendanceRecord.status_code == 'holiday')
|
||||
elif status_text in ('al', 'sl', 'cl', 'mixed_leave'):
|
||||
q = q.filter(AttendanceRecord.status_code == status_text)
|
||||
elif status_text == 'leave':
|
||||
elif status_text in ('leave', '請假'):
|
||||
# Any leave type — group filter
|
||||
q = q.filter(AttendanceRecord.status_code.in_(['al', 'sl', 'cl', 'mixed_leave']))
|
||||
elif status_text == 'normal':
|
||||
q = q.filter(
|
||||
(AttendanceRecord.late_minutes == 0) &
|
||||
(AttendanceRecord.early_minutes == 0) &
|
||||
(AttendanceRecord.ot_minutes == 0)
|
||||
)
|
||||
elif status_text in ('normal', '正常'):
|
||||
q = q.filter(AttendanceRecord.status_code == 'normal')
|
||||
else:
|
||||
# Fallback to text search
|
||||
q = q.filter(AttendanceRecord.status_text.like(f"%{status_text}%"))
|
||||
|
||||
Reference in New Issue
Block a user