fix: edit table and migrations
This commit is contained in:
120
bo/src/components/admin/product/TabVariants.vue
Normal file
120
bo/src/components/admin/product/TabVariants.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div class="card-section space-y-4">
|
||||
|
||||
<div v-if="store.loading" class="flex justify-center py-10">
|
||||
<UIcon name="svg-spinners:ring-resize" class="text-3xl text-primary" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="store.variants.length === 0" class="flex flex-col items-center gap-3 py-10 text-gray-400">
|
||||
<UIcon name="i-lucide-layers" class="text-4xl" />
|
||||
<p class="text-sm text-center">
|
||||
{{ isEditMode ? 'No variants found for this product.' : 'Save the product first, then variants will appear here.' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<p class="text-sm text-gray-400">
|
||||
Each variant is a combination of attributes (e.g. Color: Red / Size: M).
|
||||
Edit price offset, stock and other details per variant independently.
|
||||
</p>
|
||||
|
||||
<div v-for="variant in store.variants" :key="variant.id_product_attribute"
|
||||
class="border border-(--border-light) dark:border-(--border-dark) rounded-xl p-4 space-y-4">
|
||||
|
||||
<!-- Variant header -->
|
||||
<div class="flex items-center justify-between flex-wrap gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-semibold text-black dark:text-white text-sm">
|
||||
{{ variant.attribute_label || `Variant #${variant.id_product_attribute}` }}
|
||||
</span>
|
||||
<UBadge v-if="variant.default_on" color="success" variant="subtle" size="sm">
|
||||
Default
|
||||
</UBadge>
|
||||
</div>
|
||||
|
||||
<UButton size="sm" color="info"
|
||||
:loading="!!store.variantSaving[variant.id_product_attribute!]"
|
||||
@click="handleSaveVariant(variant)">
|
||||
Save variant
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<UAlert v-if="store.variantErrors[variant.id_product_attribute!]" color="error"
|
||||
variant="subtle" :title="store.variantErrors[variant.id_product_attribute!]" />
|
||||
|
||||
<!-- Variant fields -->
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<UFormField label="Reference">
|
||||
<UInput v-model="variant.reference" placeholder="REF-001-A" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="EAN-13">
|
||||
<UInput v-model="variant.ean13" placeholder="4006381333931" :maxlength="13"
|
||||
class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Price offset">
|
||||
<UInputNumber v-model="variant.price" :step="0.01"
|
||||
:format-options="{ minimumFractionDigits: 2 }" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Wholesale price">
|
||||
<UInputNumber v-model="variant.wholesale_price" :min="0" :step="0.01"
|
||||
:format-options="{ minimumFractionDigits: 2 }" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Stock quantity">
|
||||
<UInputNumber v-model="variant.quantity" :min="0" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Min. quantity">
|
||||
<UInputNumber v-model="variant.minimal_quantity" :min="1" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="Weight offset (kg)">
|
||||
<UInputNumber v-model="variant.weight" :step="0.001" class="w-full" />
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="">
|
||||
<div class="flex items-center gap-2 pt-6">
|
||||
<USwitch v-model="variant.default_on" color="success"
|
||||
@update:model-value="onSetDefault(variant)" />
|
||||
<span class="text-sm text-black dark:text-white">Set as default</span>
|
||||
</div>
|
||||
</UFormField>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAddProductStore } from '@/stores/admin/addProduct'
|
||||
import type { ProductVariantForm } from '@/types/product'
|
||||
|
||||
const props = defineProps<{ isEditMode: boolean }>()
|
||||
|
||||
const store = useAddProductStore()
|
||||
|
||||
async function handleSaveVariant(variant: ProductVariantForm) {
|
||||
if (!variant.id_product_attribute) return
|
||||
await store.saveVariant(variant.id_product_attribute, {
|
||||
reference: variant.reference,
|
||||
ean13: variant.ean13,
|
||||
price: variant.price,
|
||||
wholesale_price: variant.wholesale_price,
|
||||
quantity: variant.quantity,
|
||||
minimal_quantity: variant.minimal_quantity,
|
||||
weight: variant.weight,
|
||||
default_on: variant.default_on,
|
||||
})
|
||||
}
|
||||
|
||||
function onSetDefault(selected: ProductVariantForm) {
|
||||
if (!selected.default_on) return
|
||||
store.variants.forEach(v => {
|
||||
if (v.id_product_attribute !== selected.id_product_attribute) v.default_on = false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user