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

Laravel 8预订系统取消预订功能实现求助

预订系统取消功能实现问题

需求说明

  • 仅当min_before_cancel不等于0时,取消按钮才可用(否则预订不可退款)
  • 当前时间距预订start_date的天数小于min_before_cancel时,取消按钮才显示(反之隐藏)

当前代码存在的问题

视图代码错误

原视图代码逻辑和语法都有问题:

@if ($service =booking->service->time_before_cancel != 0 && \Carbon\Carbon::now() >$booking->start_date->subDays($service->min_before_cancel))
<button class="btn btn-danger">Cancel</button>
@endif

问题点:

  1. 变量赋值错误:把time_before_cancel的值直接赋给$service,没拿到服务模型
  2. 逻辑判断反了:需求是当前时间早于start_date - min_before_cancel才显示按钮,这里用了>
  3. 污染原始数据:subDays()会直接修改$booking->start_date的Carbon实例值

控制器方法问题

cancel方法

public function cancel($code)
{
// Retrieve the booking from the database
$booking = Booking::find($code);

 // Update the booking status
$booking->status = 'cancelled';
$booking->save();

 // Return a success message to the user
return redirect()->back()->with('success', 'Your booking has been canceled.');
}

问题点:

  1. 查询逻辑错误:find($code)是按主键查,但路由参数是booking_code,会找不到数据
  2. 无权限校验:没判断当前用户是否能操作这个订单
  3. 无后端校验:前端条件可以被绕过,后端没再次验证取消时间
  4. 无异常处理:找不到订单时会直接报错

showCancelOption方法

public function showCancelOption($bookingCode)
{
// Retrieve the booking from the database
$booking = Booking::where('booking_code', $bookingCode)->first();

// Retrieve the service associated with the booking
$service = $booking->service;

// Calculate the difference in days between the start date and today
$startDate = new Carbon($booking->start_date);
$today = Carbon::now();
$diffInDays = $startDate->diffInDays($today);

}

问题点:

  1. 无返回值:没把计算好的结果传给视图
  2. 无权限校验:随便输入一个booking_code就能访问
  3. 无空值处理:找不到订单时会报错

路由与视图文件问题

  • 按钮没包裹在表单里:POST路由无法触发请求
  • cancel.blade.php没被合理使用,逻辑混乱

模型关联问题

要确认Booking模型是否正确关联了Boat(即$booking->service能正常拿到服务数据)


修复方案

1. 修复视图代码

替换原视图代码,解决语法、逻辑问题,同时支持POST请求:

@php
    $service = $booking->service;
    // 复制start_date实例,避免修改原始数据
    $cancelDeadline = $booking->start_date->copy()->subDays($service->min_before_cancel);
    // 整合所有取消条件:可退款、未到截止时间、订单未取消
    $canCancel = $service->min_before_cancel != 0 && \Carbon\Carbon::now()->lt($cancelDeadline) && $booking->status != 'cancelled';
@endphp

@if($canCancel)
    <form action="{{ route('booking.cancel', $booking->booking_code) }}" method="POST" onsubmit="return confirm('确定要取消预订吗?')">
        @csrf
        <button type="submit" class="btn btn-danger">取消预订</button>
    </form>
@endif

2. 修复控制器cancel方法

增加校验逻辑,避免非法操作:

use Illuminate\Support\Facades\Auth;

public function cancel($code)
{
    // 按booking_code查找订单,找不到直接返回404
    $booking = Booking::where('booking_code', $code)->firstOrFail();

    // 校验当前用户是否是订单所有者(根据你的用户关联逻辑调整)
    if($booking->user_id != Auth::id()) {
        return redirect()->back()->with('error', '无权限取消该预订');
    }

    // 校验订单状态
    if($booking->status == 'cancelled') {
        return redirect()->back()->with('error', '该订单已取消');
    }

    // 后端再次校验取消时间,防止前端绕过
    $service = $booking->service;
    $cancelDeadline = $booking->start_date->copy()->subDays($service->min_before_cancel);
    if($service->min_before_cancel == 0 || \Carbon\Carbon::now()->gte($cancelDeadline)) {
        return redirect()->back()->with('error', '已过取消时限,无法取消');
    }

    // 更新订单状态
    $booking->status = 'cancelled';
    $booking->save();

    // 如果需要退款,这里可以添加退款逻辑
    // ...

    return redirect()->back()->with('success', '预订已成功取消');
}

3. 调整showCancelOption方法(如果需要单独页面)

如果要单独做取消确认页面,修改方法如下:

use Illuminate\Support\Facades\Auth;

public function showCancelOption($bookingCode)
{
    $booking = Booking::where('booking_code', $bookingCode)->firstOrFail();

    // 权限校验
    if($booking->user_id != Auth::id()) {
        abort(403, '无权限访问');
    }

    $service = $booking->service;
    $cancelDeadline = $booking->start_date->copy()->subDays($service->min_before_cancel);
    $canCancel = $service->min_before_cancel != 0 && \Carbon\Carbon::now()->lt($cancelDeadline) && $booking->status != 'cancelled';

    return view('booking.cancel', compact('booking', 'canCancel'));
}

同时添加GET路由:

Route::get('/booking/{bookingCode}/cancel-option', 'BookingController@showCancelOption')->name('booking.cancel.option');

4. 确认模型关联

确保Booking模型正确关联Boat:

class Booking extends Model
{
    // ...

    // 根据你的实际关联字段调整,这里假设用service_id关联Boat
    public function service()
    {
        return $this->belongsTo(Boat::class, 'service_id');
    }

    // 用户关联(如果有)
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

5. 整理视图文件

如果使用单独取消页面,cancel.blade.php可以这样写:

@extends('layouts.app')

@section('content')
    <div class="container">
        <h1>取消预订</h1>
        @if($canCancel)
            <form action="{{ route('booking.cancel', $booking->booking_code) }}" method="POST" onsubmit="return confirm('确定要取消预订吗?')">
                @csrf
                <button type="submit" class="btn btn-danger">确认取消预订</button>
            </form>
        @else
            <p>无法取消该预订,已过取消时限或订单不可退款</p>
        @endif
    </div>
@endsection

如果不需要单独页面,直接删除cancel.blade.php即可


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 19:50:25