You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel考勤系统:如何获取指定日期未提交考勤的班级与Section

Laravel考勤系统:获取指定日期未提交考勤的班级与Section

问题背景

在Laravel中开发考勤系统,需要区分指定日期下已提交考勤和未提交考勤的班级与Section。相关表结构如下:

  • students表:存储学生数据,包含clas_name(班级)与section_name(Section)字段;
  • attendence_dates表:记录已提交考勤的班级信息,标记当日班级是否上课(working)、考勤是否最终提交(final),表迁移代码:
public function up()
{
    Schema::create('attendence_dates', function (Blueprint $table) {                  
        $table->bigIncrements('id');
        $table->date('date')->default(date("Y-m-d"));
        $table->string('clas_name', 20)->nullable();
        $table->string('section_name',20)->nullable();
        $table->boolean('working')->default(false);
        $table->boolean('final')->default(false);
        $table->string('remarks', 100)->nullable();
        $table->unsignedBigInteger('updated_by')->nullable(); 
        $table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();
    });
}
  • attendences表:存储学生具体考勤状态(P为出勤,A为缺勤),表迁移代码:
public function up()
{
    Schema::create('attendences', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->integer('att_month')->default('0')->nullable();
        $table->date('att_date')->useCurrent();            
        $table->string('clas_name', 20)->nullable();
        $table->string('section_name',20)->nullable();                           
        $table->unsignedBigInteger('student_id')->nullable();
        $table->unsignedBigInteger('acc_id')->nullable();
        $table->enum('status', ['P', 'A'])->default('P');                
        $table->foreign('student_id')->references('id')->on('students')
                ->onDelete('SET NULL')
                ->onUpdate('CASCADE');
        $table->foreign('acc_id')->references('acc_id')->on('students')
                ->onDelete('SET NULL')
                ->onUpdate('CASCADE');                                         
        $table->timestamps();
    });
}
  • class表:存储班级基础信息,表迁移代码:
public function up()
{
    Schema::create('class', function (Blueprint $table) {
        $table->Increments('id');
        $table->string('name', 50);
        $table->string('full_name', 50);
        $table->boolean('status')->default(1);
        $table->timestamps();        
    });
}
  • sections表:存储Section基础信息,表迁移代码:
public function up()
{
    Schema::create('sections', function (Blueprint $table) {
        $table->integer('id',true,true);
        $table->string('name', 50);
        $table->string('short_name', 50); 
        $table->boolean('status')->default(1);
        $table->timestamps();
    });
}

当前实现与问题

已通过以下代码获取所有有学生的班级与Section:

$classAll = DB::table('students')
    ->select('clas_name', 'section_name')
    ->groupBy('clas_name','section_name')
    ->orderBy('clas_name','ASC')
    ->orderBy('section_name','ASC')
    ->get();

通过以下代码获取指定日期已提交考勤的班级与Section:

// 获取已提交考勤的班级数据
$posted = DB::table('attendence_dates')
        ->select('clas_name', 'section_name')
        ->where('date', $date)
        ->groupBy('clas_name','section_name')
        ->orderBy('clas_name','ASC')
        ->orderBy('section_name','ASC')
        ->get(); 

尝试获取未提交考勤的班级与Section时:

  • 使用$pending = $classAll->diff($posted);报错:Object of class stdClass could not be converted to string,因为diff默认会把对象转为字符串比较,无法正确识别两个对象是否代表同一班级+Section;
  • 使用$pending = $classAll->diffKeys($posted);无报错但结果错误,因为diffKeys只比较集合的键(即数组索引),而非实际的班级和Section值。

补充说明

选择从students表获取班级与Section,而非class和sections表,是因为class表可能存在无学生的空班级,且部分班级的Section数量不一致,直接从students表读取更符合实际业务场景。

解决方案

方法一:数据库查询(推荐,效率更高)

直接通过SQL查询获取未提交的班级与Section,避免在内存中处理集合:

$pending = DB::table('students')
    ->select('clas_name', 'section_name')
    ->groupBy('clas_name', 'section_name')
    ->whereNotExists(function ($query) use ($date) {
        $query->select(DB::raw(1))
              ->from('attendence_dates')
              ->whereColumn('attendence_dates.clas_name', 'students.clas_name')
              ->whereColumn('attendence_dates.section_name', 'students.section_name')
              ->where('attendence_dates.date', $date);
    })
    ->orderBy('clas_name', 'ASC')
    ->orderBy('section_name', 'ASC')
    ->get();

这个查询利用whereNotExists,找出所有在students表中存在,但在指定日期的attendence_dates表中没有记录的班级+Section组合。

方法二:Laravel Collection处理

如果需要在内存中处理集合,可以使用diffUsing方法自定义比较逻辑,判断两个对象的clas_name和section_name是否都相同:

$pending = $classAll->diffUsing($posted, function ($a, $b) {
    // 先比较班级名称,再比较Section名称
    $classCompare = strcmp($a->clas_name, $b->clas_name);
    if ($classCompare !== 0) {
        return $classCompare;
    }
    return strcmp($a->section_name, $b->section_name);
});

diffUsing允许你自定义两个元素的比较规则,返回0表示两个元素相等,非0则表示不等,这样就能正确筛选出未提交的班级与Section。


内容的提问来源于stack exchange,提问作者Vehlad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:44:57