fix: defer attendance settlement until lesson end

This commit is contained in:
2026-07-15 09:39:21 +08:00
parent b1f35f9d1a
commit fcde6caaaa
6 changed files with 213 additions and 3 deletions

View File

@@ -40,11 +40,13 @@ import { usePermission } from '../../hooks/usePermission';
import { message } from '../../ui/app-message';
import {
canPullAttendance,
filterLessonAttendanceRecords,
getAttendanceExperience,
getPunchDisplayInfo,
getSchedulePhase,
summarizeLessonCheckins,
type AttendanceSummary,
type LessonAttendanceFilter,
type SchedulePhase,
} from './attendance-workspace';
import './attendance.css';
@@ -261,6 +263,8 @@ const TeacherAttendanceWorkspace: React.FC = () => {
const [lessonRecords, setLessonRecords] = useState<AttendanceRecordItem[]>([]);
const [recordLoading, setRecordLoading] = useState(false);
const [drawerOpen, setDrawerOpen] = useState(false);
const [studentKeyword, setStudentKeyword] = useState('');
const [checkinFilter, setCheckinFilter] = useState<LessonAttendanceFilter>('all');
const loadWorkspace = useCallback(async () => {
setLoading(true);
@@ -284,6 +288,8 @@ const TeacherAttendanceWorkspace: React.FC = () => {
const openAttendance = useCallback(async (schedule: TodaySchedule) => {
setStudentKeyword('');
setCheckinFilter('all');
setSelectedSchedule(schedule);
setDrawerOpen(true);
setRecordLoading(true);
@@ -334,6 +340,10 @@ const TeacherAttendanceWorkspace: React.FC = () => {
(item) => getSchedulePhase(item.startTime, item.endTime, now) !== 'ended',
);
const isAttendanceCompleted = lessonSession?.status === 'completed';
const filteredLessonRecords = useMemo(
() => filterLessonAttendanceRecords(lessonRecords, studentKeyword, checkinFilter),
[lessonRecords, studentKeyword, checkinFilter],
);
return (
<div className="attendance-page teacher-attendance">
@@ -407,12 +417,39 @@ const TeacherAttendanceWorkspace: React.FC = () => {
/>
)}
<LessonCheckinSummaryStrip records={lessonRecords} />
<div className="lesson-record-filters">
<Input.Search
allowClear
value={studentKeyword}
placeholder="搜索学生姓名"
onChange={(event) => setStudentKeyword(event.target.value)}
className="lesson-record-search"
/>
<Select<LessonAttendanceFilter>
value={checkinFilter}
onChange={setCheckinFilter}
options={[
{ value: 'all', label: '全部学生' },
{ value: 'checked_in', label: '已打卡' },
{ value: 'not_checked_in', label: '未打卡' },
]}
className="lesson-record-filter-select"
/>
<span className="lesson-record-filter-count">
{filteredLessonRecords.length} / {lessonRecords.length}
</span>
</div>
<Table<AttendanceRecordItem>
rowKey="id"
loading={recordLoading}
dataSource={lessonRecords}
dataSource={filteredLessonRecords}
pagination={false}
locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="本节课尚未开始点名" /> }}
locale={{
emptyText: <Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description={lessonRecords.length === 0 ? '本节课尚未开始点名' : '没有符合条件的学生'}
/>,
}}
columns={[
{
title: '学生', dataIndex: ['student', 'name'],