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

Laravel 11 + Livewire 切换年月后日历与模态框无法正常工作的问题求助

Laravel 11 + Livewire 切换年月后日历与模态框无法正常工作的问题求助

我现在在用Laravel 11开发,做了一个Livewire组件InvoiceDetail,对应detail blade页面,通过/invooice/{id}路由访问。这个页面本来是对应单个发票ID,但实际会显示当前用户在选中年月下的所有发票列表。

页面里的年、月下拉框可以切换筛选数据,日历和模态框打开按钮只有当发票状态为未付款时才可用(只要列表里有一张未付款发票,就判定为未付款状态)。

我遇到了一个棘手的问题:

  • 初始加载时一切正常,日历和模态框都能正常点击
  • 切换年月后,列表刷新,如果此时没有发票或者所有发票都是已付/转账状态,日历和模态框不可点击,这符合预期
  • 但当再次切换年月,回到有未付款发票的列表时,日历和模态框看起来是正常显示出来了,但点击完全没反应,整个过程都是无刷新的页面操作

我的InvoiceDetail.php组件代码如下:

<?php

namespace App\Livewire;

use Livewire\Component;
use App\Models\Invoice;
use Carbon\Carbon;
use App\Mail\InvoicePaymentTransferred;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\DB;

class InvoiceDetail extends Component
{
    public $year = '';
    public $month = '';
    public $years = [];
    public $invoice;
    public $paymentDate = [];
    public $relatedInvoices;
    public $errorMessage;

    public function render()
    {
        return view('livewire.invoice-detail');
    }

    public function mount(Invoice $invoice)
    {
        $this->loadData($invoice);
        $this->fetchRelatedInvoices();
    }

    public function loadData($invoice)
    {
        $this->invoice = $invoice;
        // Set default values for year, month, and payment date
        $this->year = $invoice->date->format('Y');
        $this->month = $invoice->date->format('n');
        if (empty($this->paymentDate)) {
            $this->paymentDate = $invoice->is_paid == 0
                ? now()->format('Y年m月d日')
                : Carbon::parse($invoice->payment_date)->format('Y年m月d日');
        }

        $this->years = $this->generateYears();
    }

    public function generateYears()
    {
        $years = Invoice::selectRaw('YEAR(date) as year')
            ->distinct()
            ->pluck('year')
            ->toArray();

        if (empty($years)) {
            $years = [now()->year, now()->subYear()->year, now()->subYears(2)->year];
        }

        // Sort the years in ascending order
        sort($years);

        // Get the minimum and maximum years
        $minYear = min($years);
        $maxYear = max($years);

        // Generate a range of years, including all years between the min and max
        $years = range($minYear, $maxYear);

        return $years;
    }

    public function transferPayment($invoiceId)
    {
        DB::beginTransaction();
        try {
            $invoice = Invoice::findOrFail($invoiceId);
            $paymentDate = $this->paymentDate ? Carbon::createFromFormat('Y年m月d日', $this->paymentDate)->format('Y-m-d') : null;

            // Find all unpaid invoices for the user and the given year and month
            $invoices = Invoice::where('user_id', $invoice->user_id)
                ->whereYear('date', $invoice->date->year)
                ->whereMonth('date', $invoice->date->month)
                ->where('is_paid', "0") // Only invoices that are not paid
                ->get();
            // Update all invoices' payment status to transfer and payment date
            foreach ($invoices as $invoice) {
                $invoice->is_paid = "1";  // Mark as paid
                $invoice->payment_date = $paymentDate ? Carbon::parse($paymentDate) : Carbon::now();  // Set payment date
                $invoice->save();
            }

            // Send email to the master's email
            // Try to get admin email from config, if not available, fall back to the user's email
            $adminEmail = config('companyinfos.admin_mail');

            // If admin email from config is not available, get it from the db
            if (empty($adminEmail)) {
                $user = User::where('role_id', 1)->first();
                $userInfo = $user ? $user->userInfo : null;
                if ($userInfo && $userInfo->email) {
                    $adminEmail = $userInfo->email;
                }
            }

            // Send email to the determined admin email
            if ($adminEmail) {
                // Mail::to($adminEmail)->send(new InvoicePaymentTransferred($invoice));
            }

            // Commit the transaction
            DB::commit();

            // Refresh the invoice
            $this->mount($invoice);
        } catch (\Exception $e) {
            // If any exception occurs, rollback the transaction
            DB::rollBack();
            $this->errorMessage = __('Invoice payment could not be transferred.');
        }
    }

    public function updated($field)
    {
        $this->fetchRelatedInvoices();
        if (in_array($field, ['year', 'month']) && $this->invoice != null) {
            $this->paymentDate = $this->invoice->payment_date ? Carbon::parse($this->invoice->payment_date)->format('Y年m月d日') : now()->format('Y年m月d日');
        }
    }

    public function fetchRelatedInvoices()
    {
        $query = Invoice::where('user_id', auth()->id());

        if ($this->year) {
            $query->whereYear('date', $this->year);
        }

        if ($this->month) {
            $query->whereMonth('date', $this->month);
        }

        $this->relatedInvoices = $query->with('survey')->orderBy('updated_at', 'asc')->get();

        // Ensure $this->invoice is not null before accessing its properties
        if ($this->relatedInvoices->isNotEmpty()) {
            $this->invoice = $this->relatedInvoices->first(); // Set the primary invoice based on the latest update
        } else {
            // If no invoices found, initialize $this->invoice to null
            $this->invoice = null;
        }

        // Handle the paid status based on the related invoices, ensuring $this->invoice is not null
        if ($this->invoice) {
            $this->invoice->paid_status = $this->relatedInvoices->every(function ($relatedInvoice) {
                return $relatedInvoice->is_paid == 2;
            }) ? "paid" : ($this->relatedInvoices->contains(function ($relatedInvoice) {
                return $relatedInvoice->is_paid == 0;
            }) ? "unpaid" : "transfer");
        }
    }

    public function downloadInvoice($invoiceId)
    {
        return redirect()->route('invoice.downloadPdf', ['id' => $invoiceId]);
    }

    public function downloadReceipt($invoiceId)
    {
        return redirect()->route('invoice.downloadReceipt', ['id' => $invoiceId]);
    }
}

对应的invoice-detail.blade.php视图代码:

<div>
    @if ($errorMessage)
        <p class="error-text">{{ $errorMessage }}</p>
    @endif
    <div class="questionnaire-top__left -fstart -mb">
        <h2 class="heading-primary">利用明細確認</h2>
    </div>
    <div class="usage__detail">
        <div class="fee-list__date-wpr">
            <div class="fee-list__date-select">
                <select class="date-selection-select" wire:model.live.debounce.300ms="year">
                    <option value="">-</option>
                    @foreach ($years as $yearOption)
                        <option value="{{ $yearOption }}" {{ $yearOption == $year ? 'selected' : '' }}>
                            {{ $yearOption }}
                        </option>
                    @endforeach
                </select>
                <p class="date-selection-txt">年</p>
            </div>
            <div class="fee-list__date-select">
                <select class="date-selection-select" wire:model.live.debounce.300ms="month">
                    <option value="">-</option>
                    @for ($i = 1; $i <= 12; $i++)
                        <option value="{{ $i }}" {{ $i == $month ? 'selected' : '' }}>
                            {{ $i }}
                        </option>
                    @endfor
                </select>
                <p class="date-selection-txt">月</p>
            </div>
        </div> 
        @if($invoice)
        <div class="usage__content">
            <h2 class="usage__title">{{$year}}年{{$month}}月分 ご利用料金</h2>
            <div class="usage__button">
                <div class="usage__button-wpr">
                    @if($invoice!=null && $invoice->paid_status == "paid")
                        <p class="usage__content-desc">{{ Carbon\Carbon::parse($invoice->payment_date)->format('Y年m月d日') }} 入金済み</p>
                    @elseif($invoice->paid_status == "transfer")
                        <p class="usage__content-desc">{{ Carbon\Carbon::parse($invoice->payment_date)->format('Y年m月d日') }} 振込済み</p>
                    @else
                        <div class="basic__calendar">
                            <div class="basic__calendar-input">
                                <input type="text"
                                        class="calendar flatpickr-input invoice-calendar active"
                                        wire:model.live.debounce.300ms="paymentDate" readonly="readonly">
                                <span class="calendar-icon -new"></span>
                            </div>
                        </div>
                        <a href="javascript:void(0);" class="btn-release modalOpen" wire:loading.attr="disabled" data-target="modal-invoice-payment">振込完了</a>
                    @endif
                </div>
                @if($invoice->paid_status == "unpaid")
                    <p class="usage__content-note">※振込が終わりましたらボタンを押してください</p>
                @endif
            </div>
        </div>
        @endif
        <div class="usage__table">
            <div class="usage__table-wpr">
                <table class="table -usage">
                    <thead>
                        <tr class="table-row -transparent">
                            <th class="table-heading -nosort">項目</th>
                            <th class="table-heading -nosort">ご利用回数</th>
                            <th class="table-heading -nosort">単価(税込)</th>
                            <th class="table-heading -nosort">金額(税込)</th>
                        </tr>
                    </thead>
                    <tbody>
                        @php
                            $totalAmount = 0; // Initialize total amount
                        @endphp
                        @forelse ($relatedInvoices as $relatedInvoice)
                            <!-- Multiple related invoices -->
                            <tr class="table-row -transparent">
                                <td class="table-cell">{{ $relatedInvoice->survey->name }}</td>
                                <td class="table-cell">1</td>
                                <td class="table-cell">¥{{ number_format($relatedInvoice->amount) }}</td>
                                <td class="table-cell">¥{{ number_format($relatedInvoice->amount) }}</td>
                            </tr>
                        @php
                            $totalAmount += $relatedInvoice->amount; // Add each invoice amount to total
                        @endphp
                        @empty
                            <tr class="table-row">
                                <td class="table-cell" colspan="4">{{ __('No search results found') }}</td>
                            </tr>
                        @endforelse
                            <!-- Display the total amount -->
                            <tr class="table-row -transparent">
                                <td class="table-cell -bold" colspan="3">ご請求額合計</td>
                                <td class="table-cell -bold -fz16">¥{{ number_format($totalAmount) }}</td>
                            </tr>
                    </tbody>
                </table>
            </div>
        </div>
        @if($invoice)
            <div class="usage__footnote">
                <div class="usage__footnote-left">
                    <a href="javascript:void(0);" target="_blank" class="btn-primary" wire:click="downloadInvoice({{ $invoice->id }})">請求書をダウンロードする</a>
                    @if($invoice->is_invoice_downloaded)
                    <p class="usage__footnote-circle">請求書ダウンロード済</p>
                    @endif
                </div>
                <div class="usage__footnote-right">
                    @if($invoice->paid_status == "paid")
                        <a href="javascript:void(0);" target="_blank" class="btn-primary -sec" wire:click="downloadReceipt({{ $invoice->id }})">領収書をダウンロードする</a>
                        @if($invoice->is_receipt_downloaded)
                            <p class="usage__footnote-circle">領収書ダウンロード済</p>
                        @endif
                    @endif
                        <p class="usage__footnote-txt">※当月分を月末までの入金で15日発行/ 翌月15日までの入金で月末に発行</p>
                </div>
            </div>
            {{-- modal start --}}
            <div class="modal modal-del" wire:loading.remove id="modal-invoice-payment">
                <div class="modal-inner">
                    <form class="modal-form">
                        <h2 class="modal-title">{{ __('Transfer payment') }}</h2>
                        <p class="modal-que">{{ __('Are you sure you want to complete transfer?') }}</p>
                        <div class="modal-btns-wpr">
                            <a href="javascript:void(0);" class="btn-submit -return">キャンセル</a>
                            <a href="javascript:void(0);" wire:click="transferPayment({{ $invoice->id }})" class="btn-submit -confirm">はい</a>
                        </div>
                    </form>
                </div>
            </div>
            {{-- modal end --}}
        @endif
    </div>
    <div class="snippet loading" wire:loading.flex>
        <p class="loading__para">{{ __('Loading, please wait ') }}</p>
        <div class="stage">
            <div class="dot-pulse"></div>
        </div>
    </div>
</div>

另外,模态框的JS逻辑写在app.js里,正常情况下是可以正常工作的,但切换年月后就出现了上面的问题。有没有大佬能帮忙看看怎么解决这个日历和模态框点击无响应的问题?

备注:内容来源于stack exchange,提问作者Tulsi Acharya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 03:13:54