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

Laravel10+Livewire3表单提交失败问题求助

问题

使用Laravel 10 + Livewire 3开发时,表单提交失败:点击提交按钮后URL变为http://127.0.0.1:8000/admin/jobTrackingByWorker/1_token=Zs6bzTAhWvQOoKU57IQI6GgN3iZ3gMoe5AANb6XE,Livewire控制器的saveAttendanceStatus方法未执行(该方法内有dd('saveAttendanceStatus')但无输出),尝试wire:submit.prevent也无效。

Blade模板tbody代码

@foreach ($daysInMonth as $day)
    @if ($day['status'] == 0)
        <tr>
            <form wire:submit="saveAttendanceStatus">
                @csrf
                <td class="text-black">{{ $day['day'] }}</td>
                <td>
                    <select wire:model="attendanceStatus">
                        <option value="">Seçiniz</option>
                        <option value="1">Geldi</option>
                        <option value="2">Yıllık İzin</option>
                        <option value="3">İzinli</option>
                        <option value="4">Hastalık (Raporlu)</option>
                        <option value="5">Hastalık (Raporsuz)</option>
                        <option value="6">Ücretli İzin</option>
                        <option value="7">Yakın Vefatı</option>
                        <option value="8">Evlilik</option>
                        <option value="9">Doğum</option>
                        <option value="10">Askerlik</option>
                        <option value="11">Haber Vermeden Gelmedi</option>
                        <option value="12">Diğer</option>
                    </select>
                </td>
                <td>
                    <button type="submit" class="btn btn-primary">Kaydet</button>
                </td>
            </form>
        </tr>
    @elseif ($day['status'] == 1)
        <tr>
            <form wire:submit="updateAttendanceStatus">
                @csrf
                <td class="text-black">{{ $day['day'] }}</td>
                <td>
                    <select class="form-select" wire:model="attendanceStatus.{{ $day['day'] }}">
                        <option value="">Seçiniz</option>
                        <option value="1" @if ($day['reason'] == 1) selected @endif>Geldi</option>
                        <option value="2" @if ($day['reason'] == 2) selected @endif>Yıllık İzin</option>
                        <option value="3" @if ($day['reason'] == 3) selected @endif>İzinli</option>
                        <option value="4" @if ($day['reason'] == 4) selected @endif>Hastalık (Raporlu)</option>
                        <option value="5" @if ($day['reason'] == 5) selected @endif>Hastalık (Raporsuz)</option>
                        <option value="6" @if ($day['reason'] == 6) selected @endif>Ücretli İzin</option>
                        <option value="7" @if ($day['reason'] == 7) selected @endif>Yakın Vefatı</option>
                        <option value="8" @if ($day['reason'] == 8) selected @endif>Evlilik</option>
                        <option value="9" @if ($day['reason'] == 9) selected @endif>Doğum</option>
                        <option value="10" @if ($day['reason'] == 10) selected @endif>Askerlik</option>
                        <option value="11" @if ($day['reason'] == 11) selected @endif>Haber Vermeden Gelmedi</option>
                        <option value="12" @if ($day['reason'] == 12) selected @endif>Diğer</option>
                    </select>
                </td>
                <td>
                    <button type="submit" class="btn btn-secondary">Güncelle</button>
                </td>
            </form>
        </tr>
    @else
        <tr>
            <td class="text-danger">HATA</td>
            <td class="text-danger">HATA</td>
            <td class="text-danger">HATA</td>
        </tr>
    @endif
@endforeach

Livewire控制器代码

<?php

namespace App\Livewire\Admin;

use App\Models\JobTracking;
use Carbon\Carbon;
use Livewire\Component;

class JobTrackingByWorker extends Component
{
    public $worker, $attendanceStatus;

    public function rules()
    {
        return [
            'worker' => ['required', 'numeric'],
            'attendanceStatus' => ['required', 'numeric'],
        ];
    }

    public function messages()
    {
        return [
            'worker.required' => 'Çalışan seçmelisiniz.',
            'worker.numeric' => 'Çalışan seçmelisiniz.',
            'attendanceStatus.required' => 'Durum seçmelisiniz.',
            'attendanceStatus.numeric' => 'Durum seçmelisiniz.',
        ];
    }

    public function render()
    {
        // Set start date of the month
        $startOfMonth = Carbon::now()->startOfMonth();

        // Take end date of the month
        $endOfMonth = Carbon::now()->endOfMonth();

        // Create an empty array to store the days of the month
        $daysInMonth = [];

        // Add days to the array, if the worker has a record for that day, add 1, if not, add 0
        $currentDate = $startOfMonth->copy();
        while ($currentDate->lte($endOfMonth)) {
            // Do the worker have a record for that day?
            $workerCalendar = JobTracking::where('day', $currentDate->toDateString())->where('worker_id', $this->worker)->first();

            // If the worker has a record for that day, set status to 1, if not, set status to 0
            $status = $workerCalendar ? 1 : 0;

            $daysInMonth[] = [
                'day' => $currentDate->toDateString(),
                'status' => $status,
                'reason' => $workerCalendar ? $workerCalendar->description->value : null,
            ];

            $currentDate->addDay();
        }

        return view('livewire.admin.job-tracking-by-worker', compact('daysInMonth'));
    }

    public function saveAttendanceStatus()
    {
        dd('saveAttendanceStatus');
    }
}

解决方案

1. 修复无效HTML结构

HTML规范中<tr>标签内只能直接包含<td>或<th>,不能嵌套<form>。这种无效结构会导致Livewire无法正确劫持表单提交,触发传统POST请求(URL出现_token就是明证)。

修改方式:去掉表单标签,改用wire:click直接调用Livewire方法,传递日期参数:

@foreach ($daysInMonth as $day)
    @if ($day['status'] == 0)
        <tr>
            <td class="text-black">{{ $day['day'] }}</td>
            <td>
                <select wire:model="attendanceStatus.{{ $day['day'] }}">
                    <option value="">Seçiniz</option>
                    <option value="1">Geldi</option>
                    <option value="2">Yıllık İzin</option>
                    <option value="3">İzinli</option>
                    <option value="4">Hastalık (Raporlu)</option>
                    <option value="5">Hastalık (Raporsuz)</option>
                    <option value="6">Ücretli İzin</option>
                    <option value="7">Yakın Vefatı</option>
                    <option value="8">Evlilik</option>
                    <option value="9">Doğum</option>
                    <option value="10">Askerlik</option>
                    <option value="11">Haber Vermeden Gelmedi</option>
                    <option value="12">Diğer</option>
                </select>
            </td>
            <td>
                <button type="button" wire:click="saveAttendanceStatus('{{ $day['day'] }}')" class="btn btn-primary">Kaydet</button>
            </td>
        </tr>
    @elseif ($day['status'] == 1)
        <tr>
            <td class="text-black">{{ $day['day'] }}</td>
            <td>
                <select class="form-select" wire:model="attendanceStatus.{{ $day['day'] }}">
                    <option value="">Seçiniz</option>
                    <option value="1" @if ($day['reason'] == 1) selected @endif>Geldi</option>
                    <option value="2" @if ($day['reason'] == 2) selected @endif>Yıllık İzin</option>
                    <option value="3" @if ($day['reason'] == 3) selected @endif>İzinli</option>
                    <option value="4" @if ($day['reason'] == 4) selected @endif>Hastalık (Raporlu)</option>
                    <option value="5" @if ($day['reason'] == 5) selected @endif>Hastalık (Raporsuz)</option>
                    <option value="6" @if ($day['reason'] == 6) selected @endif>Ücretli İzin</option>
                    <option value="7" @if ($day['reason'] == 7) selected @endif>Yakın Vefatı</option>
                    <option value="8" @if ($day['reason'] == 8) selected @endif>Evlilik</option>
                    <option value="9" @if ($day['reason'] == 9) selected @endif>Doğum</option>
                    <option value="10" @if ($day['reason'] == 10) selected @endif>Askerlik</option>
                    <option value="11" @if ($day['reason'] == 11) selected @endif>Haber Vermeden Gelmedi</option>
                    <option value="12" @if ($day['reason'] == 12) selected @endif>Diğer</option>
                </select>
            </td>
            <td>
                <button type="button" wire:click="updateAttendanceStatus('{{ $day['day'] }}')" class="btn btn-secondary">Güncelle</button>
            </td>
        </tr>
    @else
        <tr>
            <td class="text-danger">HATA</td>
            <td class="text-danger">HATA</td>
            <td class="text-danger">HATA</td>
        </tr>
    @endif
@endforeach

2. 调整Livewire属性与方法

  • 把$attendanceStatus改为数组,支持多日期的状态绑定
  • 修改saveAttendanceStatus方法,接收日期参数并验证对应字段
  • 移除无用的@csrf(Livewire自动处理CSRF防护)
<?php

namespace App\Livewire\Admin;

use App\Models\JobTracking;
use Carbon\Carbon;
use Livewire\Component;

class JobTrackingByWorker extends Component
{
    public $worker;
    public $attendanceStatus = []; // 改为数组

    public function rules()
    {
        return [
            'worker' => ['required', 'numeric'],
        ];
    }

    public function messages()
    {
        return [
            'worker.required' => 'Çalışan seçmelisiniz.',
            'worker.numeric' => 'Çalışan seçmelisiniz.',
            "attendanceStatus.*.required" => 'Durum seçmelisiniz.',
            "attendanceStatus.*.numeric" => 'Durum seçmelisiniz.',
        ];
    }

    public function render()
    {
        $startOfMonth = Carbon::now()->startOfMonth();
        $endOfMonth = Carbon::now()->endOfMonth();
        $daysInMonth = [];

        $currentDate = $startOfMonth->copy();
        while ($currentDate->lte($endOfMonth)) {
            $workerCalendar = JobTracking::where('day', $currentDate->toDateString())->where('worker_id', $this->worker)->first();
            $status = $workerCalendar ? 1 : 0;

            $daysInMonth[] = [
                'day' => $currentDate->toDateString(),
                'status' => $status,
                'reason' => $workerCalendar ? $workerCalendar->description->value : null,
            ];

            // 初始化已存在的状态值
            if ($status == 1) {
                $this->attendanceStatus[$currentDate->toDateString()] = $workerCalendar->description->value;
            }

            $currentDate->addDay();
        }

        return view('livewire.admin.job-tracking-by-worker', compact('daysInMonth'));
    }

    public function saveAttendanceStatus($day)
    {
        // 验证当前日期的状态字段
        $this->validate([
            "attendanceStatus.$day" => ['required', 'numeric'],
        ]);

        // 执行保存逻辑
        JobTracking::create([
            'day' => $day,
            'worker_id' => $this->worker,
            'description' => $this->attendanceStatus[$day],
        ]);

        // 重置该字段
        unset($this->attendanceStatus[$day]);
    }

    public function updateAttendanceStatus($day)
    {
        $this->validate([
            "attendanceStatus.$day" => ['required', 'numeric'],
        ]);

        JobTracking::where('day', $day)->where('worker_id', $this->worker)
            ->update(['description' => $this->attendanceStatus[$day]]);
    }
}

3. 关键说明

  • 无效HTML结构是导致表单提交失败的核心原因,Livewire依赖正确的DOM结构来绑定事件
  • 多表单共享单个attendanceStatus属性会导致数据冲突,改为数组绑定每个日期的状态更合理
  • Livewire不需要手动添加@csrf,框架会自动处理AJAX请求的CSRF验证

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 09:37:03