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

Laravel 5.6控制器Store方法验证员工预约不重复求助

嘿,这个需求我之前也帮人处理过,在Laravel 5.6里实现起来很清晰,给你两种方案参考,按需选就行~


方案一:直接在Store方法中做检查

这是最直接的方式,适合逻辑简单的场景,直接在资源控制器的store方法里先验证基础字段,再检查重复:

public function store(Request $request)
{
    // 先做基础表单验证,确保必填字段合法
    $validatedData = $request->validate([
        'day' => 'required|date',
        'employee_id' => 'required|exists:employees,id',
        'resource_id' => 'required|exists:resources,id',
    ]);

    // 检查该员工当天是否已有预约
    $appointmentExists = Appointment::where('day', $request->day)
        ->where('employee_id', $request->employee_id)
        ->exists();

    if ($appointmentExists) {
        // 回退到创建页面,携带错误信息和用户之前的输入
        return back()->withErrors([
            'employee_id' => '该员工在所选日期已有预约,请选择其他日期或员工。'
        ])->withInput();
    }

    // 没有重复就创建新预约
    Appointment::create($validatedData);

    // 成功后跳转到预约列表页,带成功提示
    return redirect()->route('appointments.index')->with('success', '预约创建成功!');
}

方案二:用自定义验证规则(更优雅,可复用)

如果这个验证逻辑以后可能在其他地方用到(比如编辑预约时也要检查),那自定义验证规则会更优雅,也方便复用:

首先创建自定义规则:

php artisan make:rule EmployeeHasNoAppointmentOnDay

然后打开生成的app/Rules/EmployeeHasNoAppointmentOnDay.php,写入验证逻辑:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use App\Appointment;

class EmployeeHasNoAppointmentOnDay implements Rule
{
    protected $employeeId;

    // 接收员工ID作为参数
    public function __construct($employeeId)
    {
        $this->employeeId = $employeeId;
    }

    // 验证逻辑:检查该员工当天是否无预约
    public function passes($attribute, $value)
    {
        return !Appointment::where('day', $value)
            ->where('employee_id', $this->employeeId)
            ->exists();
    }

    // 验证失败时的提示信息
    public function message()
    {
        return '该员工在所选日期已有预约,请选择其他日期或员工。';
    }
}

接下来在store方法里使用这个规则:

public function store(Request $request)
{
    $validatedData = $request->validate([
        'day' => [
            'required',
            'date',
            // 实例化自定义规则,传入员工ID
            new EmployeeHasNoAppointmentOnDay($request->employee_id)
        ],
        'employee_id' => 'required|exists:employees,id',
        'resource_id' => 'required|exists:resources,id',
    ]);

    Appointment::create($validatedData);

    return redirect()->route('appointments.index')->with('success', '预约创建成功!');
}

视图层显示错误信息

不管用哪种方案,都要在预约创建页面(create.blade.php)的表单里加上错误提示,这样用户能直观看到哪里出错了,并且保留之前输入的内容:

<div class="form-group">
    <label for="employee_id">选择员工</label>
    <select name="employee_id" id="employee_id" class="form-control @error('employee_id') is-invalid @enderror">
        <!-- 这里循环输出员工选项 -->
        @foreach($employees as $employee)
            <option value="{{ $employee->id }}" {{ old('employee_id') == $employee->id ? 'selected' : '' }}>
                {{ $employee->name }}
            </option>
        @endforeach
    </select>
    @error('employee_id')
        <span class="invalid-feedback" role="alert">
            <strong>{{ $message }}</strong>
        </span>
    @enderror
</div>

<div class="form-group">
    <label for="day">预约日期</label>
    <input type="date" name="day" id="day" class="form-control @error('day') is-invalid @enderror" value="{{ old('day') }}">
    @error('day')
        <span class="invalid-feedback" role="alert">
            <strong>{{ $message }}</strong>
        </span>
    @enderror
</div>

<!-- 其他字段(比如resource_id)的表单也类似处理 -->

数据库层面的双重保障(可选但推荐)

为了防止极端情况下的并发提交(比如两个用户同时给同一个员工预约同一天),最好在数据库层面加唯一索引,从根源上避免重复:

创建一个新的迁移文件:

php artisan make:migration add_unique_index_to_appointments

打开迁移文件,添加唯一索引:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddUniqueIndexToAppointments extends Migration
{
    public function up()
    {
        Schema::table('appointments', function (Blueprint $table) {
            // 给day和employee_id组合添加唯一索引
            $table->unique(['day', 'employee_id']);
        });
    }

    public function down()
    {
        Schema::table('appointments', function (Blueprint $table) {
            $table->dropUnique(['day', 'employee_id']);
        });
    }
}

执行迁移:

php artisan migrate

之后如果数据库因为唯一约束报错,我们可以在store方法里捕获这个异常,给用户友好提示:

try {
    Appointment::create($validatedData);
} catch (\Illuminate\Database\QueryException $e) {
    // 23000是MySQL唯一约束违反的错误码
    if ($e->getCode() == 23000) {
        return back()->withErrors([
            'employee_id' => '该员工在所选日期已有预约,请选择其他日期或员工。'
        ])->withInput();
    }
    // 其他异常继续抛出,方便排查问题
    throw $e;
}

这样就实现了代码和数据库的双重验证,完全不用担心重复排班的问题啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:05:43