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

基于日期选择筛选可用时段的Livewire实现方案咨询

解决方案

你的思路完全正确,不需要额外创建pivot表,现有Schedules和Timeslots的表结构已经能满足需求。下面是具体的实现步骤:

1. 模型关联配置

先在Schedule和Timeslot模型中建立关联,让查询更简洁:

Schedule.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Schedule extends Model
{
    public function timeslot()
    {
        return $this->belongsTo(Timeslot::class);
    }
}

Timeslot.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Timeslot extends Model
{
    public function schedules()
    {
        return $this->hasMany(Schedule::class);
    }
}

2. Livewire组件实现可用时段查询

在updatedSelectedScheduledAt方法中,通过统计当日各时段的预约数,筛选出未达上限的时段:

public $selectedScheduledAt = NULL;
public $timeslots = NULL;

public function updatedSelectedScheduledAt($scheduled_at)
{
    // 统计当日每个时段的预约数量
    $slotBookings = Schedule::whereDate('scheduled_at', $scheduled_at)
        ->select('timeslot_id', \DB::raw('count(*) as booking_count'))
        ->groupBy('timeslot_id')
        ->pluck('booking_count', 'timeslot_id');

    // 获取所有时段,筛选出预约数小于上限的
    $this->timeslots = Timeslot::where(function ($query) use ($slotBookings) {
        // 未被预约过的时段直接保留
        $query->whereNotIn('id', $slotBookings->keys())
              // 已预约但未达上限的时段
              ->orWhereRaw('limit > (select booking_count from (?) as bookings where bookings.timeslot_id = timeslots.id)', [$slotBookings]);
    })->get();

    // 可选:无可用时段时清空已选时段
    if ($this->timeslots->isEmpty()) {
        $this->slot_id = null;
    }
}

如果数据量不大,也可以用更直观的筛选方式:

public function updatedSelectedScheduledAt($scheduled_at)
{
    $this->timeslots = Timeslot::get()->filter(function ($timeslot) use ($scheduled_at) {
        $bookingCount = Schedule::whereDate('scheduled_at', $scheduled_at)
            ->where('timeslot_id', $timeslot->id)
            ->count();
        
        return $bookingCount < $timeslot->limit;
    });
}

3. 优化原校验逻辑

利用模型关联简化原校验代码,提升效率:

// 替换原校验逻辑
$timeslot = Timeslot::find($this->timeslot_id);
$bookingCount = $timeslot->schedules()
    ->whereDate('scheduled_at', $this->selectedScheduledAt)
    ->count();

if ($bookingCount >= $timeslot->limit) {
    session()->flash('callout', ['type' => 'error', 'message' => '该时段预约已满,请选择其他日期或时段!']);
}

4. 视图代码小调整

修正视图中错误提示的变量名,与组件保持一致:

@error('slot_id') <span class="error">{{ $message }}</span> @enderror

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:15:39