PHP考勤脚本函数仅返回最后一条日期记录的问题求助
问题分析与解决方案
我仔细看了你的代码,导致只能返回最后一条考勤记录的核心问题有两个:
1. SQL查询的致命问题
你的原查询使用了GROUP BY t.teacher_name,这会强制将每个教师的多条考勤记录合并成一条(数据库会返回分组后的第一条/最后一条记录,取决于引擎),而且你定义了$month和$year变量但完全没用到,导致查询会拉取所有月份的考勤数据,最终每个教师只能拿到一条随机的考勤记录。
修正后的SQL查询
function get_month_attendance(){ global $db, $mybb; $month = date('m'); $year = date('Y'); // 用4位年份更稳妥,避免两位数年份的混淆问题 // 修改SQL:去掉GROUP BY,加入月份/年份筛选,只拉取当前月的考勤 $query = $db->query(" SELECT t.*, a.* FROM ".TABLE_PREFIX."teachers t LEFT JOIN ".TABLE_PREFIX."teacher_attendance a ON(a.tid=t.tid) AND a.month = '{$month}' -- 假设考勤表有month字段,根据你的实际表结构调整 AND a.year = '{$year}' -- 假设考勤表有year字段,若用日期字段则用MONTH(a.date)=... WHERE t.teacher_approve != '0' ORDER BY t.tid ASC, a.day ASC ");
2. PHP数据处理逻辑错误
原代码在while循环中每次只处理单条考勤记录,然后直接生成整行的日期单元格,这意味着每个教师的行只能基于当前循环到的那条考勤记录来渲染,其他日期自然都是默认的'A'。
我们需要先把所有教师的考勤数据按tid分组,存储每个教师每天的考勤信息,再逐个生成行:
重构后的get_month_attendance函数
function get_month_attendance(){ global $db, $mybb; $month = date('m'); $year = date('Y'); // 修正后的SQL查询 $query = $db->query(" SELECT t.*, a.* FROM ".TABLE_PREFIX."teachers t LEFT JOIN ".TABLE_PREFIX."teacher_attendance a ON(a.tid=t.tid) AND a.month = '{$month}' AND a.year = '{$year}' WHERE t.teacher_approve != '0' ORDER BY t.tid ASC, a.day ASC "); // 先按tid分组存储教师和对应的全月考勤 $teachers = []; while($row = $db->fetch_array($query)) { $tid = $row['tid']; if (!isset($teachers[$tid])) { // 初始化教师基础信息 $teachers[$tid] = [ 'tid' => $tid, 'teacher_name' => $row['teacher_name'], 'teacher_gender' => $row['teacher_gender'], 'attendances' => [] // 存储该教师每天的考勤记录 ]; } // 如果这条是有效的考勤记录(aid存在),按日期存储 if (!empty($row['aid'])) { $teachers[$tid]['attendances'][$row['day']] = $row; } } $month_attendance = ''; foreach($teachers as $t) { // 处理性别前缀 if ($t['teacher_gender'] == "Male") { $name_prefix = 'Sir '; } elseif ($t['teacher_gender'] == "Female") { $name_prefix = 'Miss '; } else { $name_prefix = ''; // 兼容其他性别情况 } $bg_color = alt_trow(); $month_attendance .= '<tr> <td class="'.$bg_color.'"> <a href="teachers.php?action=view_profile&tid='.$t['tid'].'">'.$name_prefix.$t['teacher_name'].'</a> </td>'; // 循环生成1-31天的考勤单元格 for($day = 1; $day <= 31; $day++) { $day_str = str_pad($day, 2, '0', STR_PAD_LEFT); // 转成01/02这样的格式,和数据库存储匹配 // 获取当前教师当天的考勤记录,没有则传null $attendance_data = isset($t['attendances'][$day_str]) ? $t['attendances'][$day_str] : null; $month_attendance .= get_day_attendance($attendance_data, $day_str); } $month_attendance .= '</tr>'; } if (!$month_attendance) { $month_attendance = '<tr><td colspan="32" align="center">No Teacher(s).</td></tr>'; } return $month_attendance; }
3. 修正get_day_attendance函数的小问题
原函数里$attendance_bit变量未初始化就使用,而且需要处理没有考勤记录的情况(传null时直接显示默认的'A'):
function get_day_attendance($a, $day){ $att_text = 'A'; $att_color = '#FF7777'; // 只有当存在考勤记录时才处理 if ($a !== null) { if ($a['day'] == $day) { if ($a['aid']) // 考勤已记录 { if (!empty($a['enter_time'])) // 教师在场 { $enter_time = 'Entered on: '.date("H:i A", $a['enter_time']); $exit_time = ''; if (!empty($a['exit_time'])) // 教师已离开 { $exit_time = '<br />Exited on: '.date("H:i A", $a['exit_time']); } $att_text = '<div class="tooltip">P<span class="tooltiptext" style="text-align: left; width: 200px;">'.$enter_time.$exit_time.'</span></div>'; $att_color = '#00FF54'; } else { if ($a['leave'] == "1") // 教师请假 { $att_text = '<div class="tooltip">L<span class="tooltiptext" style="text-align: left; width: 200px;">Reason: '.$a['leave_reason'].'</span></div>'; $att_color = '#F9FF00'; } } } } } // 直接返回单元格,不需要未定义的$attendance_bit变量 return '<td style="background: '.$att_color.';" width="2.5%" align="center">'.$att_text.'</td>'; }
关键说明
- 如果你考勤表中没有单独的
month和year字段,而是用attendance_date这样的日期字段,把SQL里的筛选条件改成:AND MONTH(a.attendance_date) = '{$month}' AND YEAR(a.attendance_date) = '{$year}' - 重构后的数据处理逻辑会先把每个教师的所有考勤记录收集起来,再逐个日期匹配渲染,这样就能正确展示全月的考勤状态了
内容的提问来源于stack exchange,提问作者Imran Omer
相关产品推荐
相关产品推荐

