我使用 Laravel Livewire 创建了一个简单的收银系统,它具有从购物车中删除商品并重置购物车中所有商品的功能。 一开始一切都很好,但最近我遇到了一个问题,我必须单击删除或重置购物车按钮两次才能刷新它们,它实际上从第一次单击中删除,该组件似乎在之前渲染了购物车删除过程或者我不太明白。
抱歉我蹩脚的英语。
我尝试使用更新的钩子并将所有内容放入安装中,但它不起作用。 这是我的组件代码
<?php
namespace App\Http\Livewire;
use App\Models\CartStorage;
use App\Models\Category;
use App\Models\Customer;
use App\Models\Guide;
use App\Models\Package;
use App\Models\PaymentType;
use App\Models\Product;
use App\Models\Setting;
use App\Models\Treatment;
use Livewire\Component;
class CashierTreatment extends Component
{
// protected $listeners = [];
public $taxService, $paymentTypes, $categories, $customers;
public $category_id, $guide_id, $customer_id;
public $sub_total, $grand_total, $taxServiceValue, $payAmount, $change;
public function mount()
{
$this->taxService = Setting::where('id', 1)->first()->value;
$this->paymentTypes = PaymentType::all();
$this->categories = Category::all();
$this->customers = Customer::all();
}
protected function updateTotal()
{
$this->sub_total = 1000;
$this->taxServiceValue = $this->sub_total * $this->taxService / 100;
$this->grand_total = $this->sub_total + $this->taxServiceValue;
}
public function getCategory($category_id = null)
{
$this->category_id = $category_id;
}
public function addToCart($item)
{
Product::find($item['id'])->decrement('stock');
CartStorage::updateOrCreate(
['product_id' => $item['id']],
['user_id' => auth()->user()->id]
)->increment('qty');
$this->updateTotal();
}
public function incrementQty($item)
{
$product = Product::find($item['product']['id']);
if ($product->stock > 0) {
$product->decrement('stock');
CartStorage::where('product_id', $item['product']['id'])->increment('qty');
$this->updateTotal();
}
}
public function changeQty($item, $value)
{
$product = Product::find($item['product']['id']);
$baseStock = $product->stock + $item['qty'];
$value = $value > 1 ? $value : 1;
$value = $value > $baseStock ? $baseStock : $value;
CartStorage::where('product_id', $product->id)->update(['qty' => $value]);
$product->update(['stock' => $baseStock - $value]);
}
public function decrementQty($item)
{
$cartItem = CartStorage::where('product_id', $item['product']['id'])->first();
if ($cartItem->qty > 1) {
Product::find($item['product']['id'])->increment('stock');
$cartItem->decrement('qty');
$this->updateTotal();
}
}
// $orderNumber = sprintf('%04d', $orderNumber);
// $uid = Carbon::now()->format("Ymd") . $orderNumber;
public function removeFromCart($item)
{
Product::find($item['product']['id'])->update(['stock' => $item['product']['stock'] + $item['qty']]);
CartStorage::where('product_id', $item['product']['id'])->delete();
$this->updateTotal();
$this->render();
}
public function resetCart()
{
$cartItem = CartStorage::all();
foreach ($cartItem as $item) {
Product::find($item->product_id)->update(['stock' => $item->product->stock + $item->qty]);
}
CartStorage::truncate();
$this->reset(['sub_total', 'grand_total', 'taxServiceValue', 'guide_id', 'customer_id', 'payAmount']);
$this->render();
}
public function rightAmount()
{
$this->payAmount = $this->grand_total;
}
public function checkout()
{
//
}
public function render()
{
$categories = $this->categories;
$guides = Guide::where('check_in', 1)->get();
$customers = $this->customers;
$paymentTypes = $this->paymentTypes;
$products = Product::with('category')
->whereHas('CartStorage')
->orWhere('stock', '>', 0)
->when($this->category_id, function ($query) {
$query->where('category_id', $this->category_id);
})
->get();
$cartList = CartStorage::with(['product', 'product.category'])->get();
return view('livewire.cashier-treatment', compact('categories', 'products', 'guides', 'customers', 'paymentTypes', 'cartList'));
}
}
这是我的观点
<div class="flex flex-row h-screen">
<div class="basis-3/4 h-dvh">
<main class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex items-baseline justify-between border-b border-gray-200 pb-6 pt-24">
<h1 class="text-4xl font-bold tracking-tight text-gray-900">Treatments</h1>
<div class="flex items-center">
<a href="{{ route('kasir.dashboard.index') }}" class="rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
<span aria-hidden="true"> ←</span>
Back to Dashboard
</a>
</div>
</div>
<section aria-labelledby="products-heading" class="pb-24 pt-6">
<h2 id="products-heading" class="sr-only">Products</h2>
<div class="grid grid-cols-1 gap-x-8 gap-y-10 lg:grid-cols-4">
<!-- Filters -->
<h3 class="sr-only">Categories</h3>
<ul role="list" class="space-y-4 border-b border-gray-200 pb-6 text-sm font-medium text-gray-900">
<li class="cursor-pointer px-3.5 py-2.5 @if (!$category_id)
rounded-md bg-gray-400
@endif" wire:click="getCategory()">
All
</li>
@foreach ($categories as $category)
<li class="cursor-pointer px-3.5 py-2.5 @if ($category_id == $category->id)
rounded-md bg-gray-400
@endif" wire:key="{{ $category->name }}{{ $category->id }}" wire:click="getCategory({{ $category->id }})" wire:loading.class="opacity-50">
{{ $category->name }}
</li>
@endforeach
</ul>
<!-- Product grid -->
<div class="lg:col-span-3">
<fieldset class="grid grid-cols-2 gap-4">
<legend class="sr-only">Delivery</legend>
@foreach ($products as $product)
<div wire:key="{{ $product->id }}" wire:click="addToCart({{ $product }})" class="cursor-pointer" wire:loading.class="opacity-50">
<label
class="flex cursor-pointer justify-between gap-4 rounded-lg border border-gray-100 bg-white p-4 text-sm font-medium shadow-sm hover:border-gray-200 has-[:checked]:border-blue-500 has-[:checked]:ring-1 has-[:checked]:ring-blue-500"
>
<div class="flex items-center gap-3">
<img
src="{{ asset($product->image) }}"
alt="{{ $product->name }}"
class="w-1/4 aspect-square rounded-lg object-cover"
/>
<div class="w-full">
<small>{{ $product->category->name }}</small>
<p class="text-gray-700"><b>{{ $product->name }}</b></p>
<div class="flex justify-between items-center w-full">
<p class="mt-1 text-gray-900">Rp @money($product->price)</p>
<p class="text-black font-bold">Stock : {{ $product->stock }}</p>
</div>
</div>
</div>
</label>
</div>
@endforeach
</fieldset>
</div>
</div>
</section>
</main>
</div>
<div class="basis-1/4">
<div class="flex h-full flex-col overflow-y-scroll bg-white shadow-xl">
<div class="flex-1 overflow-y-auto px-4 py-6 sm:px-6">
<div class="flex items-start justify-between">
<h2 class="text-lg font-medium text-gray-900" id="slide-over-title">Shopping cart</h2>
<div class="ml-3 flex h-7 items-center">
</div>
</div>
<div class="mt-8">
<div class="flow-root">
<ul role="list" class="-my-6 divide-y divide-gray-200">
{{-- @if ($cartList) --}}
@foreach ($cartList as $cartItem)
<li class="flex py-6" wire:key="{{ $cartItem->product->id }}">
<div class="ml-4 flex flex-1 flex-col">
<div>
<div class="flex justify-between text-base font-medium text-gray-900">
{{-- <small>{{ $item['treatment']['name'] }}</small> --}}
<h3>
<a href="#">{{ $cartItem->product->name }}</a>
</h3>
<p class="ml-4">Rp @money($cartItem->product->price)</p>
</div>
<p class="mt-1 text-sm text-gray-500">{{ $cartItem->product->category->name }}</p>
</div>
<div class="flex flex-1 items-end justify-between text-sm">
{{-- <p class="text-gray-500">{{ $item['valid_period'] ? $item['valid_period']." Month(s)" : "-" }}</p> --}}
<div class="mt-2">
{{-- <label for="Quantity" class="sr-only"> Quantity </label> --}}
<div class="flex items-center gap-1">
<button type="button" wire:click="decrementQty({{ json_encode($cartItem) }})" class="size-10 leading-10 text-gray-600 transition hover:opacity-75">
−
</button>
<input
type="integer"
id="input{{ $cartItem->id }}"
value="{{ $cartItem->qty }}"
wire:change="changeQty({{ json_encode($cartItem) }}, $event.target.value)"
{{-- wire:model="cartList[{{ $cartItem }}]['qty']" --}}
class="h-10 w-16 rounded border-gray-200 text-center [-moz-appearance:_textfield] sm:text-sm [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none"
/>
<button type="button" wire:click="incrementQty({{ json_encode($cartItem) }})" class="size-10 leading-10 text-gray-600 transition hover:opacity-75">
+
</button>
</div>
</div>
<div class="flex">
<button type="button" wire:click="removeFromCart({{ json_encode($cartItem) }})" class="font-medium text-indigo-600 hover:text-indigo-500">Remove</button>
</div>
</div>
</div>
</li>
@endforeach
{{-- @endif --}}
</ul>
</div>
</div>
</div>
<div class="border-t border-gray-200 px-4 py-6 sm:px-6">
{{-- <form wire:submit="checkout"> --}}
<div class="flex flex-row items-center justify-center gap-2">
<div class="basis-1/2">
<label for="HeadlineAct" class="block text-sm font-medium text-gray-900"> Customer </label>
<select id="HeadlineAct" wire:model="customer_id" class="mt-1.5 w-full rounded-lg border-gray-300 text-gray-700 sm:text-sm">
<option value="">Please select</option>
@foreach ($customers as $customer)
<option value="{{ $customer->id }}" wire:key="{{ $customer->name.$customer->id }}">
{{ $customer->name }}
</option>
@endforeach
</select>
</div>
<div class="basis-1/2">
<label for="HeadlineAct1" class="block text-sm font-medium text-gray-900"> Guide </label>
<select wire:model="guide_id" id="HeadlineAct1" class="mt-1.5 w-full rounded-lg border-gray-300 text-gray-700 sm:text-sm">
<option value="">Please select</option>
@foreach ($guides as $guide)
<option value="{{ $guide->id }}" wire:key="{{ $guide->name.$guide->id }}">
{{ $guide->name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="mt-2">
<label for="amount" class="block text-sm font-medium text-gray-900"> Pay Amount </label>
<input
type="number"
id="amount"
placeholder="Rp"
wire:model="payAmount"
value="{{ $payAmount }}"
class="mt-1 w-full rounded-md border-gray-200 shadow-sm sm:text-sm"
/>
</div>
<div class="flex justify-between text-base font-medium text-gray-900 mt-2">
<p>Subtotal</p>
<p>Rp @money($sub_total)</p>
</div>
<div class="flex justify-between text-base font-medium text-gray-900 mt-2">
<p>Tax & Services</p>
<p>Rp @money($taxServiceValue)</p>
</div>
<div class="flex justify-between text-base font-medium text-gray-900 mt-2">
<p>Grandtotal</p>
<p>Rp @money($grand_total)</p>
</div>
<div class="flex justify-between text-base font-medium text-gray-900 mt-2">
<p>Change</p>
<p>Rp @money($change)</p>
</div>
{{-- <p class="mt-0.5 text-sm text-gray-500">Refreshing page will reset all data.</p> --}}
<span class="mt-6 inline-flex -space-x-px overflow-hidden rounded-md border bg-white shadow-sm w-full">
<button
type="reset"
wire:click="resetCart"
wire:loading.class="cursor-wait opacity-50"
class="inline-block w-1/3 px-5 py-1 text-sm font-medium text-white bg-red-600 shadow-sm hover:bg-red-700 focus:relative"
>
Reset Cart
</button>
<button
type="button"
wire:click="rightAmount"
wire:loading.class="cursor-wait opacity-50"
class="inline-block w-1/3 px-5 py-1 text-sm font-medium text-white bg-indigo-600 shadow-sm hover:bg-indigo-700 focus:relative"
>
Right Amount
</button>
<button
class="inline-block w-fit px-5 py-1 text-sm font-medium text-white bg-green-600 shadow-sm hover:bg-green-700 focus:relative"
>
Submit Payment
</button>
</span>
{{-- </form> --}}
{{-- <div class="mt-6 flex justify-center text-center text-sm text-gray-500">
<p>
or
<button type="button" wire:click="resetCart" class="font-medium text-indigo-600 hover:text-indigo-500">
Remove all item
<span aria-hidden="true"> →</span>
</button>
</p>
</div> --}}
</div>
</div>
</div>
终于找到答案了!
通过在 foreach 内元素的唯一键末尾添加“li”,如下所示
@foreach ($cartList->sortBy('product.name') as $key => $cartItem)
<li class="flex py-2" wire:key="{{ $key+1 }}li">
单个组件中的键确实不能相同,即使它处于不同的迭代中:)