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

Laravel中如何验证课程选择的重复与Hari、Jam冲突问题

问题描述

我有如下数据(附图片)
课程数据表格
请问如何验证用户是否选择了相同的Kode,或者所选Kode存在Hari(星期)或Jam(时间)冲突的情况。

我的Controller代码

public function store(Request $request)
{
    $validate   =   Validator::make($request->all(), [
                        'kode_matkul'   =>  'required',
                    ]);

    if($validate->fails()) {
        return response()->json(['errors' => $validate->errors()]);
    }
}

我的View Blade代码

<tbody>
  @foreach ($mapel as $row)
    <tr>
      <td class="text-center">{{ $row->course }}</td>
      <td>{{ $row->course_name }}</td>
      <td class="text-center">{{ $row->sks }}</td>
      <td class="text-center">{{ $row->kelompok }}</td>
      <td>{{ $row->name }}</td>
      <td class="text-center">{{ $row->hari }}</td>
      <td class="text-center">{{ date('H:i', strtotime($row->start_time)) . ' - ' . date('H:i', strtotime($row->end_time)) }}</td>
      <td class="text-center">{{ $row->ruangan }}</td>
      <td class="text-center">
        <input class="form-check-input" type="checkbox" name="kode_matkul[]" id="kode_matkul" value="{{ $row->course }}">
      </td>
    </tr>
  @endforeach
</tbody>

解决方案

1. 验证重复选择的Kode

直接在Laravel验证规则里添加distinct,自动检查提交的数组是否有重复值:

$validate = Validator::make($request->all(), [
    'kode_matkul' => 'required|array|distinct',
]);

如果用户选了相同的Kode,验证会直接返回错误提示。

2. 验证星期与时间冲突

需要先获取选中课程的完整数据,再逐一对比课程的星期和时间区间是否重叠。

步骤1:查询选中课程的详情

假设你的课程模型是Course,通过选中的kode_matkul批量查询对应课程:

$selectedCourses = Course::whereIn('course', $request->kode_matkul)->get();

步骤2:检查时间重叠逻辑

遍历选中的课程,两两对比星期和时间区间:

$hasConflict = false;
$conflictMessage = '';

// 遍历每一门课程,和后续课程逐一对比
foreach ($selectedCourses as $index => $course) {
    for ($i = $index + 1; $i < $selectedCourses->count(); $i++) {
        $otherCourse = $selectedCourses[$i];
        
        // 先判断是否是同一个星期
        if ($course->hari === $otherCourse->hari) {
            // 转换时间为DateTime对象,方便区间比较
            $courseStart = new DateTime($course->start_time);
            $courseEnd = new DateTime($course->end_time);
            $otherStart = new DateTime($otherCourse->start_time);
            $otherEnd = new DateTime($otherCourse->end_time);
            
            // 时间重叠判定:A的开始时间在B的区间内,或B的开始时间在A的区间内
            if (($courseStart >= $otherStart && $courseStart < $otherEnd) || ($otherStart >= $courseStart && $otherStart < $courseEnd)) {
                $hasConflict = true;
                $conflictMessage = "课程 {$course->course} ({$course->course_name}) 与 {$otherCourse->course} ({$otherCourse->course_name}) 在星期{$course->hari}时间重叠";
                break 2; // 直接跳出两层循环
            }
        }
    }
}

// 存在冲突则返回错误
if ($hasConflict) {
    return response()->json(['errors' => ['kode_matkul' => [$conflictMessage]]]);
}

整合后的完整Controller代码

public function store(Request $request)
{
    $validate = Validator::make($request->all(), [
        'kode_matkul' => 'required|array|distinct',
    ]);

    if ($validate->fails()) {
        return response()->json(['errors' => $validate->errors()]);
    }

    // 获取选中课程的完整数据
    $selectedCourses = Course::whereIn('course', $request->kode_matkul)->get();

    // 检查时间冲突
    $hasConflict = false;
    $conflictMessage = '';

    foreach ($selectedCourses as $index => $course) {
        for ($i = $index + 1; $i < $selectedCourses->count(); $i++) {
            $otherCourse = $selectedCourses[$i];
            
            if ($course->hari === $otherCourse->hari) {
                $courseStart = new DateTime($course->start_time);
                $courseEnd = new DateTime($course->end_time);
                $otherStart = new DateTime($otherCourse->start_time);
                $otherEnd = new DateTime($otherCourse->end_time);
                
                if (($courseStart >= $otherStart && $courseStart < $otherEnd) || ($otherStart >= $courseStart && $otherStart < $courseEnd)) {
                    $hasConflict = true;
                    $conflictMessage = "课程 {$course->course} ({$course->course_name}) 与 {$otherCourse->course} ({$otherCourse->course_name}) 在星期{$course->hari}时间重叠";
                    break 2;
                }
            }
        }
    }

    if ($hasConflict) {
        return response()->json(['errors' => ['kode_matkul' => [$conflictMessage]]]);
    }

    // 后续执行选课保存逻辑
    return response()->json(['success' => '选课成功']);
}

3. 可选:前端提前验证(提升用户体验)

可以在用户勾选时就做前端校验,避免提交后才报错:

// 监听所有复选框的变化事件
document.querySelectorAll('input[name="kode_matkul[]"]').forEach(checkbox => {
    checkbox.addEventListener('change', function() {
        // 获取所有选中的课程值和对应的行元素
        const selectedValues = Array.from(document.querySelectorAll('input[name="kode_matkul[]"]:checked')).map(el => el.value);
        const selectedRows = Array.from(document.querySelectorAll('input[name="kode_matkul[]"]:checked')).map(el => el.closest('tr'));
        
        // 检查重复选择
        if (new Set(selectedValues).size !== selectedValues.length) {
            alert('不能选择重复的课程Kode');
            this.checked = false;
            return;
        }
        
        // 检查时间冲突
        let hasConflict = false;
        for (let i = 0; i < selectedRows.length; i++) {
            for (let j = i + 1; j < selectedRows.length; j++) {
                const row1 = selectedRows[i];
                const row2 = selectedRows[j];
                
                const hari1 = row1.querySelector('td:nth-child(6)').textContent.trim();
                const hari2 = row2.querySelector('td:nth-child(6)').textContent.trim();
                
                if (hari1 === hari2) {
                    // 拆分时间区间
                    const time1 = row1.querySelector('td:nth-child(7)').textContent.split(' - ');
                    const time2 = row2.querySelector('td:nth-child(7)').textContent.split(' - ');
                    
                    // 转换为Date对象进行比较
                    const start1 = new Date(`2000-01-01T${time1[0]}`);
                    const end1 = new Date(`2000-01-01T${time1[1]}`);
                    const start2 = new Date(`2000-01-01T${time2[0]}`);
                    const end2 = new Date(`2000-01-01T${time2[1]}`);
                    
                    if ((start1 >= start2 && start1 < end2) || (start2 >= start1 && start2 < end1)) {
                        hasConflict = true;
                        alert(`课程${row1.querySelector('td:nth-child(1)').textContent}与${row2.querySelector('td:nth-child(1)').textContent}在星期${hari1}时间重叠`);
                        this.checked = false;
                        return;
                    }
                }
            }
        }
    });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:30:48