
本文介绍如何在不使用 ajax 的前提下,通过表单提交方式实现 laravel 后端驱动的日期范围筛选,涵盖控制器逻辑、 blade 视图整合、日期格式处理及 eloquent/query builder 正确用法。
本文介绍如何在不使用 ajax 的前提下,通过表单提交方式实现 laravel 后端驱动的日期范围筛选,涵盖控制器逻辑、 blade 视图整合、日期格式处理及 eloquent/query builder 正确用法。
在 Laravel 中实现纯服务端渲染的日期范围筛选(即不依赖 AJAX),关键在于:确保日期输入能随表单提交到达后端、正确解析为数据库可比对的格式,并将筛选结果重新渲染到视图中。你当前的代码存在几个核心问题:前端未包裹 <form></form> 表单导致日期无法提交;JavaScript 初始化了日期选择器但未绑定提交行为;后端 whereBetween 直接使用 created_at 字段与仅含日期的字符串比较,易因时间部分(时分秒)导致漏匹配;且未做空值或格式异常校验。
✅ 正确实现步骤
1. 修改 Blade 视图:添加表单与提交按钮
在 table.blade.php 中,将日期输入框包裹在 <form></form> 内,并指定 GET 方法(便于 URL 查看和刷新):
<form method="GET" action="{{ route('order.daterange') }}">
<table class="table">
<tbody>
<tr>
<td>最小日期:</td>
<td><input type="text" name="datepicker_from" id="datepicker_from"
value="{{ request('datepicker_from') }}"
class="form-control" placeholder="YYYY-MM-DD"></td>
</tr>
<tr>
<td>最大日期:</td>
<td><input type="text" name="datepicker_to" id="datepicker_to"
value="{{ request('datepicker_to') }}"
class="form-control" placeholder="YYYY-MM-DD"></td>
</tr>
<tr>
<td colspan="2">
<button type="submit" class="btn btn-primary">筛选</button>
<a href="{{ route('order.daterange') }}" class="btn btn-secondary">重置</a>
</td>
</tr>
</tbody>
</table>
</form>⚠️ 注意:
route('order.daterange')需在routes/web.php中正确定义,例如:Route::get('/orders/date-range', [OrderController::class, 'daterange'])->name('order.daterange');
2. 前端日期选择器(推荐使用 flatpickr 或原生 input[type="date"])
为简化兼容性,建议使用原生 HTML5 日期控件(无需额外 JS 库):
<input type="date" name="datepicker_from" id="datepicker_from"
value="{{ old('datepicker_from', request('datepicker_from')) }}">
<input type="date" name="datepicker_to" id="datepicker_to"
value="{{ old('datepicker_to', request('datepicker_to')) }}">若需更丰富交互(如范围联动),可引入 flatpickr 并启用 mode: 'range',但仍以表单提交为准。
3. 优化控制器逻辑(健壮 & 安全)
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\Models\OrderItem; // 推荐使用模型替代 DB::table()
public function daterange(Request $request)
{
// 初始化查询构建器
$query = OrderItem::query();
// 处理起始日期(允许为空)
if ($request->filled('datepicker_from')) {
try {
$from = Carbon::createFromFormat('Y-m-d', $request->input('datepicker_from'))
->startOfDay(); // 确保从当日 00:00:00 开始
$query->where('created_at', '>=', $from);
} catch (\Exception $e) {
\Log::warning('Invalid date format for from: ' . $request->input('datepicker_from'));
}
}
// 处理结束日期
if ($request->filled('datepicker_to')) {
try {
$to = Carbon::createFromFormat('Y-m-d', $request->input('datepicker_to'))
->endOfDay(); // 确保到当日 23:59:59 结束
$query->where('created_at', '<=', $to);
} catch (\Exception $e) {
\Log::warning('Invalid date format for to: ' . $request->input('datepicker_to'));
}
}
$dateRange = $query->get();
return view('profiles.dateRange', [
'date_range' => $dateRange,
'filters' => $request->only(['datepicker_from', 'datepicker_to'])
]);
}✅ 优势:
- 使用
startOfDay()/endOfDay()精确覆盖整日,避免whereBetween对DATETIME字段的隐式截断风险;filled()+try-catch防止空值或非法格式崩溃;- 传递
filters到视图,支持表单回显(见上文value="{{ request('...') }}")。
4. 视图中展示结果(示例)
在 profiles/dateRange.blade.php 中:
@if($date_range->count())
<h4>共找到 {{ $date_range->count() }} 条订单记录</h4>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>商品名称</th>
<th>创建时间</th>
</tr>
</thead>
<tbody>
@foreach($date_range as $item)
<tr>
<td>{{ $item->id }}</td>
<td>{{ $item->product_name ?? 'N/A' }}</td>
<td>{{ $item->created_at->format('Y-m-d H:i:s') }}</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="alert alert-info">未找到符合条件的数据。</div>
@endif? 关键注意事项
-
不要混用 DataTables 客户端搜索与服务端日期筛选:你原代码中
DataTable().search().draw()是纯前端过滤,与后端whereBetween无关。若需服务端分页+筛选,请改用yajra/laravel-datatables的服务端模式(需 AJAX),否则保持纯表单提交即可。 -
时间字段类型一致性:
created_at是DATETIME,务必用Carbon::startOfDay()/endOfDay()而非DATE(created_at)函数——后者无法利用索引,性能差。 -
路由缓存:修改路由后运行
php artisan route:clear。 -
CSRF 保护:
GET表单无需@csrf,但若改用POST则必须添加。
通过以上改造,即可实现简洁、可靠、无 AJAX 依赖的 Laravel 日期范围筛选功能,兼顾用户体验与服务端可控性。


















