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
相关产品推荐
相关产品推荐

