feat: add modal for batch inventory item addition with responsive design and Tailwind CSS
This commit is contained in:
parent
730cae825c
commit
19753a0f48
648
src/modules/warehouse/components/BatchAddInventory.vue
Normal file
648
src/modules/warehouse/components/BatchAddInventory.vue
Normal file
@ -0,0 +1,648 @@
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- Toast Notifications -->
|
||||
<Toast position="bottom-right" />
|
||||
|
||||
<!-- Breadcrumb -->
|
||||
<Breadcrumb :home="breadcrumbHome" :model="breadcrumbItems" />
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="flex flex-wrap justify-between items-center gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h1 class="text-gray-900 dark:text-white text-3xl md:text-4xl font-black leading-tight tracking-tight">
|
||||
Agregar Items al Inventario
|
||||
</h1>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-base font-normal leading-normal">
|
||||
Busca y agrega múltiples productos a tu stock en un lote único.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search & Select Products Section -->
|
||||
<Card class="shadow-sm">
|
||||
<template #header>
|
||||
<div class="px-6 py-4">
|
||||
<h2 class="text-lg font-bold text-gray-900 dark:text-white">Seleccionar Productos del Catálogo</h2>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="flex flex-col lg:flex-row gap-4 items-end">
|
||||
<!-- Search Input -->
|
||||
<div class="flex-1 w-full">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Buscar Catálogo
|
||||
</label>
|
||||
<div class="relative">
|
||||
<i class="pi pi-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
<InputText
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
placeholder="Escribe Nombre del Producto o SKU..."
|
||||
class="w-full pl-10 h-11"
|
||||
@focus="showProductSearch = true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add Button -->
|
||||
<Button
|
||||
label="Agregar Producto"
|
||||
icon="pi pi-plus"
|
||||
@click="openProductModal"
|
||||
class="min-w-[200px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Selected Product Preview (shown when typing) -->
|
||||
<div v-if="showProductSearch && selectedProductPreview" class="mt-4 bg-gray-50 dark:bg-gray-800/30 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<!-- Product Info -->
|
||||
<div class="md:col-span-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">
|
||||
Producto Seleccionado
|
||||
</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<Avatar :image="selectedProductPreview.image" shape="square" size="large" class="w-12 h-12" />
|
||||
<div>
|
||||
<p class="font-bold text-gray-900 dark:text-white">{{ selectedProductPreview.name }}</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">SKU: {{ selectedProductPreview.sku }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Variants -->
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">
|
||||
Tamaño
|
||||
</label>
|
||||
<Select
|
||||
v-model="tempVariant.size"
|
||||
:options="selectedProductPreview.sizes"
|
||||
placeholder="Selecciona..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">
|
||||
Resolución
|
||||
</label>
|
||||
<Select
|
||||
v-model="tempVariant.resolution"
|
||||
:options="selectedProductPreview.resolutions"
|
||||
placeholder="Selecciona..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Quantity -->
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-2">
|
||||
Cantidad
|
||||
</label>
|
||||
<InputNumber
|
||||
v-model="tempVariant.quantity"
|
||||
:min="1"
|
||||
placeholder="0"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Add Button -->
|
||||
<div class="md:col-span-2 flex items-end">
|
||||
<Button
|
||||
label="Agregar"
|
||||
icon="pi pi-plus"
|
||||
@click="addItemToQueue"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
<!-- Queued Items Table -->
|
||||
<Card class="shadow-sm">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<h2 class="text-lg font-bold text-gray-900 dark:text-white">
|
||||
Items en Cola ({{ queuedItems.length }})
|
||||
</h2>
|
||||
<Button
|
||||
label="Limpiar Todo"
|
||||
severity="danger"
|
||||
text
|
||||
size="small"
|
||||
@click="clearAllItems"
|
||||
v-if="queuedItems.length > 0"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<DataTable
|
||||
v-if="queuedItems.length > 0"
|
||||
:value="queuedItems"
|
||||
stripedRows
|
||||
responsiveLayout="scroll"
|
||||
class="text-sm"
|
||||
>
|
||||
<Column field="productName" header="Nombre del Producto">
|
||||
<template #body="slotProps">
|
||||
<div class="flex items-center gap-3">
|
||||
<Avatar :image="slotProps.data.image" shape="square" size="large" class="w-8 h-8" />
|
||||
<span class="font-medium">{{ slotProps.data.productName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="sku" header="SKU">
|
||||
<template #body="slotProps">
|
||||
<span class="text-sm text-gray-500">{{ slotProps.data.sku }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="variant" header="Variante">
|
||||
<template #body="slotProps">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<Tag
|
||||
v-if="slotProps.data.size"
|
||||
:value="`Tamaño: ${slotProps.data.size}`"
|
||||
severity="info"
|
||||
class="text-xs"
|
||||
/>
|
||||
<Tag
|
||||
v-if="slotProps.data.resolution"
|
||||
:value="`Resolución: ${slotProps.data.resolution}`"
|
||||
severity="warning"
|
||||
class="text-xs"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="quantity" header="Cantidad">
|
||||
<template #body="slotProps">
|
||||
<InputNumber
|
||||
v-model="slotProps.data.quantity"
|
||||
:min="1"
|
||||
class="w-20"
|
||||
/>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="unit" header="Unidad">
|
||||
<template #body="slotProps">
|
||||
<span class="text-sm">{{ slotProps.data.unit }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column header="Acción" :exportable="false">
|
||||
<template #body="slotProps">
|
||||
<Button
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
@click="removeItem(slotProps.data.id)"
|
||||
/>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div v-else class="text-center py-12">
|
||||
<i class="pi pi-inbox text-4xl text-gray-300 dark:text-gray-600 mb-4 block"></i>
|
||||
<p class="text-gray-500 dark:text-gray-400">No hay items en la cola. Comienza a agregar productos.</p>
|
||||
</div>
|
||||
|
||||
<!-- Summary -->
|
||||
<div v-if="queuedItems.length > 0" class="mt-6 p-4 bg-gray-50 dark:bg-gray-800/30 border border-gray-200 dark:border-gray-700 rounded-lg">
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300">
|
||||
Total de items a agregar: <span class="font-bold text-gray-900 dark:text-white">{{ totalQueuedQuantity }} unidades</span>
|
||||
en {{ queuedItems.length }} productos únicos.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
<!-- Product Selection Modal -->
|
||||
<Dialog
|
||||
v-model:visible="showModal"
|
||||
:header="'Agregar Producto al Lote'"
|
||||
:modal="true"
|
||||
:style="{ width: '90vw' }"
|
||||
:maximizable="true"
|
||||
class="md:w-full max-w-2xl"
|
||||
>
|
||||
<div class="space-y-6">
|
||||
<!-- Search Input -->
|
||||
<div class="space-y-3">
|
||||
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300">
|
||||
Buscar Catálogo
|
||||
</label>
|
||||
<div class="relative">
|
||||
<i class="pi pi-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
<InputText
|
||||
v-model="modalSearchQuery"
|
||||
type="text"
|
||||
placeholder="Escribe Nombre del Producto o SKU..."
|
||||
class="w-full pl-10"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Selected Product Details -->
|
||||
<div class="bg-gray-50 dark:bg-gray-800/30 rounded-lg p-5 border border-gray-100 dark:border-gray-700 space-y-6">
|
||||
<!-- Product Info -->
|
||||
<div class="flex items-center gap-4">
|
||||
<Avatar :image="modalProduct.image" shape="square" size="xlarge" class="w-16 h-16" />
|
||||
<div>
|
||||
<p class="text-lg font-bold text-gray-900 dark:text-white">{{ modalProduct.name }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 font-medium">SKU: {{ modalProduct.sku }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Variants Grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">
|
||||
Tamaño
|
||||
</label>
|
||||
<Select
|
||||
v-model="modalProduct.selectedSize"
|
||||
:options="modalProduct.sizes"
|
||||
placeholder="Selecciona..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">
|
||||
Resolución
|
||||
</label>
|
||||
<Select
|
||||
v-model="modalProduct.selectedResolution"
|
||||
:options="modalProduct.resolutions"
|
||||
placeholder="Selecciona..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">
|
||||
Cantidad
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<InputNumber
|
||||
v-model="modalProduct.selectedQuantity"
|
||||
:min="1"
|
||||
placeholder="0"
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="text-sm font-medium text-gray-500">pcs</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stock Info -->
|
||||
<div class="flex items-end">
|
||||
<InlineMessage severity="info" class="w-full text-xs">
|
||||
<i class="pi pi-info-circle mr-2"></i>
|
||||
Stock actual: {{ modalProduct.currentStock }} unidades
|
||||
</InlineMessage>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<Button
|
||||
label="Cancelar"
|
||||
severity="secondary"
|
||||
@click="showModal = false"
|
||||
/>
|
||||
<Button
|
||||
label="Confirmar y Agregar a la Lista"
|
||||
icon="pi pi-check"
|
||||
@click="confirmAddFromModal"
|
||||
/>
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<!-- Bottom Action Bar -->
|
||||
<div class="fixed bottom-0 right-0 left-0 md:left-64 bg-white dark:bg-background-dark border-t border-gray-200 dark:border-gray-700 p-4 px-6 md:px-10 flex justify-between items-center shadow-lg">
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs font-medium text-gray-500 uppercase tracking-widest">Ubicación de Almacenamiento</span>
|
||||
<Select
|
||||
v-model="selectedLocation"
|
||||
:options="warehouseLocations"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
placeholder="Selecciona..."
|
||||
class="h-9 w-64"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<Button
|
||||
label="Cancelar"
|
||||
severity="secondary"
|
||||
@click="cancelBatch"
|
||||
/>
|
||||
<Button
|
||||
label="Confirmar y Guardar Inventario"
|
||||
icon="pi pi-check"
|
||||
@click="saveBatch"
|
||||
:disabled="queuedItems.length === 0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Spacing -->
|
||||
<div class="pb-24"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
|
||||
// PrimeVue Components
|
||||
import Toast from 'primevue/toast';
|
||||
import Breadcrumb from 'primevue/breadcrumb';
|
||||
import Card from 'primevue/card';
|
||||
import Button from 'primevue/button';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import InputNumber from 'primevue/inputnumber';
|
||||
import Select from 'primevue/select';
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
import Dialog from 'primevue/dialog';
|
||||
import Tag from 'primevue/tag';
|
||||
import Avatar from 'primevue/avatar';
|
||||
import InlineMessage from 'primevue/inlinemessage';
|
||||
|
||||
const router = useRouter();
|
||||
const toast = useToast();
|
||||
|
||||
// State
|
||||
const searchQuery = ref('');
|
||||
const modalSearchQuery = ref('Smart Display Panel');
|
||||
const selectedLocation = ref('main-warehouse');
|
||||
const showProductSearch = ref(false);
|
||||
const showModal = ref(false);
|
||||
|
||||
// Breadcrumb
|
||||
const breadcrumbHome = ref({ icon: 'pi pi-home', to: '/' });
|
||||
const breadcrumbItems = ref([
|
||||
{ label: 'Almacén', to: '/warehouse' },
|
||||
{ label: 'Agregar Items al Inventario' }
|
||||
]);
|
||||
|
||||
// Warehouse Locations
|
||||
const warehouseLocations = [
|
||||
{ label: 'Almacén Principal (A1)', value: 'main-warehouse' },
|
||||
{ label: 'Almacenamiento Sur (B4)', value: 'south-storage' },
|
||||
{ label: 'Almacenamiento Frío (C2)', value: 'cold-storage' },
|
||||
];
|
||||
|
||||
// Mock Product Data
|
||||
const mockProducts = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Smart Display Panel',
|
||||
sku: 'DISP-PNL-SD-001',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBMbZhSSPYoHEi3akXSqZXm-T6EghACuHJJ5NYeJ8g4XJIKtqXRhCSQ1kFcvo7Txk01ryR-r6RJ61NzPLENWMywvUVnCkQglsizZG0NKPBwRFQjXvtDULkGbGFm6EPocyHGfuzKJ0EoDr601zMBI34mfPCgn9AAaRkTMj2Ize2nCUcanlGn7QJEp6BdNcmf3JFlk-51jPTXj1-mM4Pw6AGIvarhxnZqtEAji6qRF7evVTR_56c48h5if21S3jD-wVhNVp8AltVn8KEH',
|
||||
sizes: ['24', '36', '64', '85'],
|
||||
resolutions: ['1080', '2K', '4K', '8K'],
|
||||
currentStock: 420,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Mechanical Keyboard RGB',
|
||||
sku: 'KYBD-RGB-US-02',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuBBMBDEGh1exdBX1lU--TOCsUwfsFkYhrl8DxxvxgH-hKLkcuVtuGP_ZhRS5l_YXFWls08Ecr-Ic748cVHqHexFMMzYTPH8YL2s9OISDgsMIwcDOPxitrPUn3RBCD_krFC8SrBXBeNC8ilcFdg_JCwD5BW5gaYjAAEUMFXyM1vd-YT27KyubBk1IKATsMdDkH-NtwAHcrPgNoXsRaAcubBQiebCG1hmxKVW3fAXoDoSqywrxhwZ7cmIuo7BTThJJ1KcczxQh1jYh_w4',
|
||||
switches: ['Red Switch', 'Blue Switch', 'Brown Switch'],
|
||||
currentStock: 230,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'USB-C Charging Cable 2m',
|
||||
sku: 'CBL-USBC-2M',
|
||||
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuAsb9nqDON7PeKGYYAU8hmHn7B2l3waP_ewMQTpsgnpJe2vFiY-k-zncE5VEf186tDzlTwVPA6-1SgAFagugq9Anw2WXloUFTNwOrOHgAi-MNhgs0FuxRKF8XMLk6W_u6YLF5xWh3K2q317JXFSUWtURtxCi8pYM4YtHYEyuT2aIrhbAnI2LQ7ja8DvSdvpO6t1IJ6HE9RqlnAFXuLG22igxiekKT2NjRpuK5Zzu_90rBPEjb0KitG9DwiBjzKa702pccHPRqupgXke',
|
||||
variants: ['Braided', 'Standard'],
|
||||
currentStock: 1200,
|
||||
},
|
||||
];
|
||||
|
||||
// Queued Items
|
||||
const queuedItems = ref<any[]>([]);
|
||||
|
||||
// Temporary variant selection
|
||||
const tempVariant = ref({
|
||||
size: null,
|
||||
resolution: null,
|
||||
quantity: 1,
|
||||
});
|
||||
|
||||
// Selected Product Preview
|
||||
const selectedProductPreview = ref<any>(null);
|
||||
|
||||
// Get default product
|
||||
const defaultProduct = mockProducts[0]!;
|
||||
|
||||
// Modal Product
|
||||
const modalProduct = ref({
|
||||
name: 'Smart Display Panel',
|
||||
sku: 'DISP-PNL-SD-001',
|
||||
image: defaultProduct.image,
|
||||
sizes: defaultProduct.sizes,
|
||||
resolutions: defaultProduct.resolutions,
|
||||
currentStock: defaultProduct.currentStock,
|
||||
selectedSize: '85',
|
||||
selectedResolution: '4K',
|
||||
selectedQuantity: 10,
|
||||
});
|
||||
|
||||
// Computed
|
||||
const totalQueuedQuantity = computed(() => {
|
||||
return queuedItems.value.reduce((sum, item) => sum + item.quantity, 0);
|
||||
});
|
||||
|
||||
// Methods
|
||||
const openProductModal = () => {
|
||||
showModal.value = true;
|
||||
resetModalProduct();
|
||||
};
|
||||
|
||||
const resetModalProduct = () => {
|
||||
modalProduct.value = {
|
||||
name: 'Smart Display Panel',
|
||||
sku: 'DISP-PNL-SD-001',
|
||||
image: defaultProduct.image,
|
||||
sizes: defaultProduct.sizes,
|
||||
resolutions: defaultProduct.resolutions,
|
||||
currentStock: defaultProduct.currentStock,
|
||||
selectedSize: '85',
|
||||
selectedResolution: '4K',
|
||||
selectedQuantity: 1,
|
||||
};
|
||||
};
|
||||
|
||||
const addItemToQueue = () => {
|
||||
if (!selectedProductPreview.value || !tempVariant.value.quantity) {
|
||||
toast.add({
|
||||
severity: 'warn',
|
||||
summary: 'Validación',
|
||||
detail: 'Por favor selecciona un producto y cantidad',
|
||||
life: 3000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const newItem = {
|
||||
id: Math.random(),
|
||||
productName: selectedProductPreview.value.name,
|
||||
sku: selectedProductPreview.value.sku,
|
||||
image: selectedProductPreview.value.image,
|
||||
size: tempVariant.value.size,
|
||||
resolution: tempVariant.value.resolution,
|
||||
quantity: tempVariant.value.quantity,
|
||||
unit: 'pcs',
|
||||
};
|
||||
|
||||
queuedItems.value.push(newItem);
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Producto Agregado',
|
||||
detail: `${selectedProductPreview.value.name} ha sido agregado a la cola`,
|
||||
life: 3000
|
||||
});
|
||||
|
||||
// Reset
|
||||
selectedProductPreview.value = null;
|
||||
showProductSearch.value = false;
|
||||
searchQuery.value = '';
|
||||
tempVariant.value = { size: null, resolution: null, quantity: 1 };
|
||||
};
|
||||
|
||||
const confirmAddFromModal = () => {
|
||||
if (!modalProduct.value.selectedQuantity || !modalProduct.value.selectedSize) {
|
||||
toast.add({
|
||||
severity: 'warn',
|
||||
summary: 'Validación',
|
||||
detail: 'Por favor completa todos los campos',
|
||||
life: 3000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const newItem = {
|
||||
id: Math.random(),
|
||||
productName: modalProduct.value.name,
|
||||
sku: modalProduct.value.sku,
|
||||
image: modalProduct.value.image,
|
||||
size: modalProduct.value.selectedSize,
|
||||
resolution: modalProduct.value.selectedResolution,
|
||||
quantity: modalProduct.value.selectedQuantity,
|
||||
unit: 'pcs',
|
||||
};
|
||||
|
||||
queuedItems.value.push(newItem);
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Producto Agregado',
|
||||
detail: `${modalProduct.value.name} ha sido agregado a la cola`,
|
||||
life: 3000
|
||||
});
|
||||
|
||||
showModal.value = false;
|
||||
resetModalProduct();
|
||||
};
|
||||
|
||||
const removeItem = (id: number) => {
|
||||
const index = queuedItems.value.findIndex(item => item.id === id);
|
||||
if (index > -1) {
|
||||
const removedItem = queuedItems.value.splice(index, 1)[0];
|
||||
toast.add({
|
||||
severity: 'info',
|
||||
summary: 'Item Removido',
|
||||
detail: `${removedItem.productName} ha sido removido`,
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const clearAllItems = () => {
|
||||
queuedItems.value = [];
|
||||
toast.add({
|
||||
severity: 'info',
|
||||
summary: 'Cola Limpiada',
|
||||
detail: 'Todos los items han sido removidos',
|
||||
life: 3000
|
||||
});
|
||||
};
|
||||
|
||||
const cancelBatch = () => {
|
||||
if (queuedItems.value.length > 0) {
|
||||
const confirmed = confirm('¿Estás seguro? Se perderán todos los items en la cola.');
|
||||
if (!confirmed) return;
|
||||
}
|
||||
router.back();
|
||||
};
|
||||
|
||||
const saveBatch = () => {
|
||||
if (queuedItems.value.length === 0) {
|
||||
toast.add({
|
||||
severity: 'warn',
|
||||
summary: 'Validación',
|
||||
detail: 'Agrega al menos un item a la cola',
|
||||
life: 3000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedLocation.value) {
|
||||
toast.add({
|
||||
severity: 'warn',
|
||||
summary: 'Validación',
|
||||
detail: 'Selecciona una ubicación de almacenamiento',
|
||||
life: 3000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Enviar datos al API
|
||||
console.log('Batch data:', {
|
||||
items: queuedItems.value,
|
||||
location: selectedLocation.value,
|
||||
});
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Éxito',
|
||||
detail: `${queuedItems.value.length} productos agregados al inventario exitosamente`,
|
||||
life: 3000
|
||||
});
|
||||
|
||||
// Reset y volver
|
||||
queuedItems.value = [];
|
||||
setTimeout(() => {
|
||||
router.push({ name: 'WarehouseHome' });
|
||||
}, 1500);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.p-dialog-header) {
|
||||
background-color: var(--surface-50);
|
||||
}
|
||||
|
||||
.dark :deep(.p-dialog-header) {
|
||||
background-color: var(--surface-800);
|
||||
}
|
||||
|
||||
:deep(.p-dialog-content) {
|
||||
max-height: calc(90vh - 200px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
551
src/modules/warehouse/components/WarehouseDetails.vue
Normal file
551
src/modules/warehouse/components/WarehouseDetails.vue
Normal file
@ -0,0 +1,551 @@
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- Toast Notifications -->
|
||||
<Toast position="bottom-right" />
|
||||
|
||||
<!-- Breadcrumb -->
|
||||
<Breadcrumb :home="breadcrumbHome" :model="breadcrumbItems" />
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h1 class="text-surface-900 dark:text-white text-3xl md:text-4xl font-black leading-tight tracking-tight">
|
||||
{{ warehouseData?.name || 'North Logistics Center' }}
|
||||
</h1>
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<div class="flex items-center gap-2 text-surface-500 dark:text-surface-400">
|
||||
<i class="pi pi-map-marker text-sm"></i>
|
||||
<span class="text-sm">{{ warehouseData?.location || 'Zone A, Building 4' }}</span>
|
||||
</div>
|
||||
<div class="size-1 bg-surface-300 dark:bg-surface-600 rounded-full"></div>
|
||||
<Tag :value="warehouseData?.isActive ? 'Operacional' : 'Inactivo'"
|
||||
:severity="warehouseData?.isActive ? 'success' : 'secondary'" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<Button label="Exportar Datos" icon="pi pi-download" outlined severity="secondary" />
|
||||
<Button icon="pi pi-print" outlined severity="secondary" />
|
||||
<Button label="Entradas" icon="pi pi-plus" @click="openBatchAdd" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Overview -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<!-- Total SKUs -->
|
||||
<Card class="shadow-sm">
|
||||
<template #content>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm font-medium text-surface-500 dark:text-surface-400">Total SKUs</p>
|
||||
<p class="text-2xl font-bold text-surface-900 dark:text-white">1,240</p>
|
||||
<div class="flex items-center gap-1 text-xs font-semibold text-green-600 dark:text-green-400">
|
||||
<i class="pi pi-arrow-up text-xs"></i>
|
||||
+2.4% vs mes anterior
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
<!-- Low Stock Items -->
|
||||
<Card class="shadow-sm border-l-4 border-l-red-500">
|
||||
<template #content>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm font-medium text-surface-500 dark:text-surface-400">Items con Stock Bajo</p>
|
||||
<p class="text-2xl font-bold text-surface-900 dark:text-white">18</p>
|
||||
<div class="flex items-center gap-1 text-xs font-semibold text-red-600 dark:text-red-400">
|
||||
<i class="pi pi-exclamation-triangle text-xs"></i>
|
||||
Acción requerida
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
<!-- Movements 24h -->
|
||||
<Card class="shadow-sm">
|
||||
<template #content>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm font-medium text-surface-500 dark:text-surface-400">Movimientos (24h)</p>
|
||||
<p class="text-2xl font-bold text-surface-900 dark:text-white">142</p>
|
||||
<div class="flex items-center gap-1 text-xs font-semibold text-blue-600 dark:text-blue-400">
|
||||
<i class="pi pi-refresh text-xs"></i>
|
||||
Alta actividad
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
<!-- Warehouse Utilization -->
|
||||
<Card class="shadow-sm">
|
||||
<template #content>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm font-medium text-surface-500 dark:text-surface-400">Utilización del Almacén</p>
|
||||
<p class="text-2xl font-bold text-surface-900 dark:text-white">84%</p>
|
||||
<ProgressBar :value="84" :showValue="false" class="h-2" />
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<!-- Tabs & Main Content Table -->
|
||||
<Card class="shadow-sm">
|
||||
<template #content>
|
||||
<TabView v-model:activeIndex="activeTab" class="w-full">
|
||||
<!-- Stock Actual Tab -->
|
||||
<TabPanel value="0">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="pi pi-box"></i>
|
||||
<span>Stock Actual</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Filters -->
|
||||
<div class="flex flex-wrap items-center justify-end gap-3 mb-4">
|
||||
<Select
|
||||
v-model="selectedCategory"
|
||||
:options="categoryOptions"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
placeholder="Todas las Categorías"
|
||||
class="w-full md:w-48"
|
||||
/>
|
||||
<Select
|
||||
v-model="selectedStockLevel"
|
||||
:options="stockLevelOptions"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
placeholder="Todos los Niveles"
|
||||
class="w-full md:w-48"
|
||||
/>
|
||||
<Button icon="pi pi-filter" outlined severity="secondary" />
|
||||
</div>
|
||||
|
||||
<!-- Current Stock Table -->
|
||||
<DataTable
|
||||
:value="inventoryData"
|
||||
:paginator="true"
|
||||
:rows="10"
|
||||
:rowsPerPageOptions="[10, 25, 50]"
|
||||
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown CurrentPageReport"
|
||||
currentPageReportTemplate="Mostrando {first} a {last} de {totalRecords} resultados"
|
||||
:loading="loading"
|
||||
stripedRows
|
||||
responsiveLayout="scroll"
|
||||
class="text-sm"
|
||||
>
|
||||
<Column field="sku" header="SKU" sortable class="font-mono">
|
||||
<template #body="slotProps">
|
||||
<span class="font-semibold">{{ slotProps.data.sku }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="product" header="Producto" sortable>
|
||||
<template #body="slotProps">
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="font-semibold">{{ slotProps.data.product }}</span>
|
||||
<span class="text-xs text-surface-500">{{ slotProps.data.category }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="quantity" header="Cantidad" sortable>
|
||||
<template #body="slotProps">
|
||||
<span class="font-bold tabular-nums">{{ slotProps.data.quantity.toLocaleString() }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="unit" header="Unidad" sortable />
|
||||
<Column field="location" header="Ubicación" sortable>
|
||||
<template #body="slotProps">
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="pi pi-map-marker text-surface-400 text-xs"></i>
|
||||
<span>{{ slotProps.data.location }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="status" header="Estado" sortable>
|
||||
<template #body="slotProps">
|
||||
<Tag
|
||||
:value="slotProps.data.status"
|
||||
:severity="getStatusSeverity(slotProps.data.status)"
|
||||
/>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="lastUpdate" header="Última Actualización" sortable>
|
||||
<template #body="slotProps">
|
||||
<span class="text-xs text-surface-500">{{ slotProps.data.lastUpdate }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column header="Acciones" :exportable="false">
|
||||
<template #body="slotProps">
|
||||
<div class="flex gap-2">
|
||||
<Button icon="pi pi-eye" outlined rounded size="small" severity="secondary" @click="viewItem(slotProps.data)" />
|
||||
<Button icon="pi pi-pencil" outlined rounded size="small" @click="editItem(slotProps.data)" />
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
</TabPanel>
|
||||
|
||||
<!-- Historial de Movimientos Tab -->
|
||||
<TabPanel value="1">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="pi pi-history"></i>
|
||||
<span>Historial de Movimientos</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Movement History Table -->
|
||||
<DataTable
|
||||
:value="movementHistory"
|
||||
:paginator="true"
|
||||
:rows="10"
|
||||
:rowsPerPageOptions="[10, 25, 50]"
|
||||
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown CurrentPageReport"
|
||||
currentPageReportTemplate="Mostrando {first} a {last} de {totalRecords} resultados"
|
||||
:loading="loading"
|
||||
stripedRows
|
||||
responsiveLayout="scroll"
|
||||
class="text-sm"
|
||||
>
|
||||
<Column field="date" header="Fecha" sortable />
|
||||
<Column field="type" header="Tipo" sortable>
|
||||
<template #body="slotProps">
|
||||
<Tag
|
||||
:value="slotProps.data.type"
|
||||
:severity="getMovementTypeSeverity(slotProps.data.type)"
|
||||
/>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="product" header="Producto" sortable />
|
||||
<Column field="quantity" header="Cantidad" sortable>
|
||||
<template #body="slotProps">
|
||||
<span class="font-bold tabular-nums">{{ slotProps.data.quantity }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="user" header="Usuario" sortable />
|
||||
<Column field="reference" header="Referencia" sortable />
|
||||
</DataTable>
|
||||
</TabPanel>
|
||||
</TabView>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
<!-- Secondary Section: Recent Movements & Insights -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Quick Activity Log -->
|
||||
<Card class="lg:col-span-2 shadow-sm">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between p-4">
|
||||
<h3 class="font-bold text-surface-900 dark:text-white">Registro Rápido de Actividad</h3>
|
||||
<Button label="Ver Todos los Movimientos" link class="text-sm" @click="viewAllMovements" />
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="space-y-4">
|
||||
<div v-for="activity in recentActivities" :key="activity.id"
|
||||
class="flex items-center gap-4 py-3 border-b border-surface-200 dark:border-surface-700 last:border-b-0">
|
||||
<div :class="[
|
||||
'flex items-center justify-center size-10 rounded-full',
|
||||
activity.type === 'in' ? 'bg-green-100 dark:bg-green-900/30' : 'bg-red-100 dark:bg-red-900/30'
|
||||
]">
|
||||
<i :class="[
|
||||
'pi text-sm',
|
||||
activity.type === 'in' ? 'pi-arrow-down text-green-600' : 'pi-arrow-up text-red-600'
|
||||
]"></i>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="font-semibold text-surface-900 dark:text-white">{{ activity.action }}</p>
|
||||
<p class="text-sm text-surface-500 dark:text-surface-400">{{ activity.product }}</p>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="font-bold text-surface-900 dark:text-white">{{ activity.quantity }}</p>
|
||||
<p class="text-xs text-surface-500 dark:text-surface-400">{{ activity.time }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
<!-- Warehouse Health Insights -->
|
||||
<Card class="shadow-sm bg-primary-50 dark:bg-primary-900/10 border border-primary-200 dark:border-primary-800">
|
||||
<template #content>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h3 class="font-bold text-surface-900 dark:text-white mb-2">Salud del Almacén</h3>
|
||||
<p class="text-sm text-surface-600 dark:text-surface-300 leading-relaxed">
|
||||
North Logistics Center está actualmente al 84% de capacidad. Recomendamos auditar la Zona B
|
||||
para optimización de espacio potencial.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-surface-700 dark:text-surface-200">Capacidad Total</span>
|
||||
<span class="font-bold text-surface-900 dark:text-white">50,000 m³</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-surface-700 dark:text-surface-200">Espacio Utilizado</span>
|
||||
<span class="font-bold text-surface-900 dark:text-white">42,000 m³</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-sm text-surface-700 dark:text-surface-200">Espacio Disponible</span>
|
||||
<span class="font-bold text-primary-700 dark:text-primary-400">8,000 m³</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
label="Generar Reporte Completo"
|
||||
class="w-full"
|
||||
outlined
|
||||
@click="generateReport"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
|
||||
// PrimeVue Components
|
||||
import Toast from 'primevue/toast';
|
||||
import Breadcrumb from 'primevue/breadcrumb';
|
||||
import Card from 'primevue/card';
|
||||
import Button from 'primevue/button';
|
||||
import Tag from 'primevue/tag';
|
||||
import TabView from 'primevue/tabview';
|
||||
import TabPanel from 'primevue/tabpanel';
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
import Select from 'primevue/select';
|
||||
import ProgressBar from 'primevue/progressbar';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const toast = useToast();
|
||||
|
||||
// Reactive State
|
||||
const warehouseData = ref<any>(null);
|
||||
const loading = ref(false);
|
||||
const activeTab = ref(0);
|
||||
const selectedCategory = ref('all');
|
||||
const selectedStockLevel = ref('all');
|
||||
|
||||
// Breadcrumb
|
||||
const breadcrumbHome = ref({ icon: 'pi pi-home', to: '/' });
|
||||
const breadcrumbItems = ref([
|
||||
{ label: 'Almacenes', to: '/warehouse' },
|
||||
{ label: 'North Logistics Center' }
|
||||
]);
|
||||
|
||||
// Filter Options
|
||||
const categoryOptions = [
|
||||
{ label: 'Todas las Categorías', value: 'all' },
|
||||
{ label: 'Electrónica', value: 'electronics' },
|
||||
{ label: 'Maquinaria', value: 'machinery' },
|
||||
{ label: 'Textiles', value: 'textiles' },
|
||||
];
|
||||
|
||||
const stockLevelOptions = [
|
||||
{ label: 'Todos los Niveles', value: 'all' },
|
||||
{ label: 'Stock Bajo', value: 'low' },
|
||||
{ label: 'En Stock', value: 'in_stock' },
|
||||
{ label: 'Sobrestock', value: 'overstock' },
|
||||
];
|
||||
|
||||
// Mock Data - Current Stock
|
||||
const inventoryData = ref([
|
||||
{
|
||||
sku: 'WH-2024-001',
|
||||
product: 'Laptop Dell XPS 15',
|
||||
category: 'Electrónica',
|
||||
quantity: 450,
|
||||
unit: 'Unidades',
|
||||
location: 'Rack A-12',
|
||||
status: 'En Stock',
|
||||
lastUpdate: 'Hace 2 horas'
|
||||
},
|
||||
{
|
||||
sku: 'WH-2024-002',
|
||||
product: 'Silla Ergonómica Pro',
|
||||
category: 'Mobiliario',
|
||||
quantity: 85,
|
||||
unit: 'Unidades',
|
||||
location: 'Zona B-04',
|
||||
status: 'Stock Bajo',
|
||||
lastUpdate: 'Hace 4 horas'
|
||||
},
|
||||
{
|
||||
sku: 'WH-2024-003',
|
||||
product: 'Monitor LG 27" 4K',
|
||||
category: 'Electrónica',
|
||||
quantity: 320,
|
||||
unit: 'Unidades',
|
||||
location: 'Rack A-15',
|
||||
status: 'En Stock',
|
||||
lastUpdate: 'Hace 1 hora'
|
||||
},
|
||||
{
|
||||
sku: 'WH-2024-004',
|
||||
product: 'Teclado Mecánico RGB',
|
||||
category: 'Periféricos',
|
||||
quantity: 12,
|
||||
unit: 'Unidades',
|
||||
location: 'Rack C-08',
|
||||
status: 'Stock Crítico',
|
||||
lastUpdate: 'Hace 30 min'
|
||||
},
|
||||
]);
|
||||
|
||||
// Mock Data - Movement History
|
||||
const movementHistory = ref([
|
||||
{
|
||||
date: '2024-01-30 14:30',
|
||||
type: 'Entrada',
|
||||
product: 'Laptop Dell XPS 15',
|
||||
quantity: '+50',
|
||||
user: 'Juan Pérez',
|
||||
reference: 'PO-2024-156'
|
||||
},
|
||||
{
|
||||
date: '2024-01-30 12:15',
|
||||
type: 'Salida',
|
||||
product: 'Monitor LG 27" 4K',
|
||||
quantity: '-25',
|
||||
user: 'María García',
|
||||
reference: 'SO-2024-892'
|
||||
},
|
||||
{
|
||||
date: '2024-01-30 10:00',
|
||||
type: 'Entrada',
|
||||
product: 'Silla Ergonómica Pro',
|
||||
quantity: '+100',
|
||||
user: 'Carlos López',
|
||||
reference: 'PO-2024-155'
|
||||
},
|
||||
]);
|
||||
|
||||
// Mock Data - Recent Activities
|
||||
const recentActivities = ref([
|
||||
{
|
||||
id: 1,
|
||||
type: 'in',
|
||||
action: 'Entrada de Stock',
|
||||
product: 'Laptop Dell XPS 15 - 50 unidades',
|
||||
quantity: '+50',
|
||||
time: 'Hace 2 horas'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'out',
|
||||
action: 'Salida de Stock',
|
||||
product: 'Monitor LG 27" - 25 unidades',
|
||||
quantity: '-25',
|
||||
time: 'Hace 4 horas'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'in',
|
||||
action: 'Entrada de Stock',
|
||||
product: 'Silla Ergonómica - 100 unidades',
|
||||
quantity: '+100',
|
||||
time: 'Hace 6 horas'
|
||||
},
|
||||
]);
|
||||
|
||||
// Methods
|
||||
const getStatusSeverity = (status: string) => {
|
||||
const severityMap: Record<string, string> = {
|
||||
'En Stock': 'success',
|
||||
'Stock Bajo': 'warn',
|
||||
'Stock Crítico': 'danger',
|
||||
'Sobrestock': 'info',
|
||||
};
|
||||
return severityMap[status] || 'secondary';
|
||||
};
|
||||
|
||||
const getMovementTypeSeverity = (type: string) => {
|
||||
const severityMap: Record<string, string> = {
|
||||
'Entrada': 'success',
|
||||
'Salida': 'danger',
|
||||
'Transferencia': 'info',
|
||||
'Ajuste': 'warn',
|
||||
};
|
||||
return severityMap[type] || 'secondary';
|
||||
};
|
||||
|
||||
const openBatchAdd = () => {
|
||||
router.push({ name: 'BatchAddInventory' });
|
||||
};
|
||||
|
||||
const viewItem = (item: any) => {
|
||||
toast.add({
|
||||
severity: 'info',
|
||||
summary: 'Ver Item',
|
||||
detail: `Visualizando: ${item.product}`,
|
||||
life: 3000
|
||||
});
|
||||
};
|
||||
|
||||
const editItem = (item: any) => {
|
||||
toast.add({
|
||||
severity: 'info',
|
||||
summary: 'Editar Item',
|
||||
detail: `Editando: ${item.product}`,
|
||||
life: 3000
|
||||
});
|
||||
};
|
||||
|
||||
const viewAllMovements = () => {
|
||||
activeTab.value = 1;
|
||||
};
|
||||
|
||||
const generateReport = () => {
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Generando Reporte',
|
||||
detail: 'El reporte se está generando...',
|
||||
life: 3000
|
||||
});
|
||||
};
|
||||
|
||||
// Lifecycle
|
||||
onMounted(async () => {
|
||||
const warehouseId = route.params.id;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// TODO: Cargar datos del almacén desde el API
|
||||
// const response = await warehouseService.getWarehouseById(warehouseId);
|
||||
// warehouseData.value = response.data;
|
||||
|
||||
// Mock data por ahora
|
||||
warehouseData.value = {
|
||||
id: warehouseId,
|
||||
name: 'North Logistics Center',
|
||||
location: 'Zone A, Building 4',
|
||||
isActive: true,
|
||||
};
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Error al cargar los datos del almacén',
|
||||
life: 3000
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tabular-nums {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
</style>
|
||||
@ -51,6 +51,13 @@ const createWarehouse = () => {
|
||||
router.push({ name: 'WarehouseCreate' });
|
||||
};
|
||||
|
||||
const viewWarehouseDetails = (warehouse: any) => {
|
||||
router.push({
|
||||
name: 'WarehouseDetails',
|
||||
params: { id: warehouse.id }
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
// Reload warehouses to show new data
|
||||
await warehouseStore.refreshWarehouses();
|
||||
@ -146,6 +153,8 @@ onMounted(async () => {
|
||||
responsiveLayout="scroll"
|
||||
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown CurrentPageReport"
|
||||
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} results"
|
||||
class="cursor-pointer"
|
||||
@row-click="(event) => viewWarehouseDetails(event.data)"
|
||||
>
|
||||
<Column field="code" header="Código" sortable>
|
||||
<template #body="slotProps">
|
||||
@ -186,13 +195,22 @@ onMounted(async () => {
|
||||
</Column>
|
||||
|
||||
<Column header="Acciones" headerStyle="text-align: right" bodyStyle="text-align: right">
|
||||
<template #body>
|
||||
<template #body="slotProps">
|
||||
<div class="flex gap-2 justify-end">
|
||||
<Button
|
||||
icon="pi pi-eye"
|
||||
text
|
||||
size="small"
|
||||
@click="(event) => { event.stopPropagation(); viewWarehouseDetails(slotProps.data); }"
|
||||
/>
|
||||
<Button
|
||||
icon="pi pi-ellipsis-v"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
@click="(event) => event.stopPropagation()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
|
||||
337
src/modules/warehouse/components/index.html
Normal file
337
src/modules/warehouse/components/index.html
Normal file
@ -0,0 +1,337 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="light" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>WMS - Batch Add Inventory Items</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Inter", "sans-serif"]
|
||||
},
|
||||
borderRadius: {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style type="text/tailwindcss">
|
||||
@layer utilities {
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark font-display text-gray-800 dark:text-gray-200 overflow-hidden">
|
||||
<div class="flex h-screen w-full">
|
||||
<aside class="flex w-64 flex-col border-r border-gray-200 dark:border-gray-800 bg-white dark:bg-background-dark">
|
||||
<div class="flex h-full flex-col justify-between p-4">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex items-center gap-3 p-2">
|
||||
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuCztlHhjKvu2qkn2Xi2zFHagNsNToKwcTg3vQr0KtTqBCo13dK1yyz9HzB2uLCiciLyDfnrf7pREvdblPqCcUiN0HqlSbkFwY1dpQLMbJ4hmpVgHVWaLaUCMXju06qyGQSdg2ChGVcbTQIrk-RNI2-hDOFnfrI1PD89RNSsByXGRsdkYWSyEYFOFk7bT4l7aIaasB6cdVxDfNwJdvVx15wb7-qOHZHFTPMbrkkzmjGec-f7iVqTi5U1ykNDclBSezBM97TfXajTwRJE");'></div>
|
||||
<div class="flex flex-col">
|
||||
<h1 class="text-gray-900 dark:text-white text-base font-medium leading-normal">Admin User</h1>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm font-normal leading-normal">Warehouse Manager</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="flex flex-col gap-2">
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<p class="text-sm font-medium leading-normal">Dashboard</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg bg-primary/10 text-primary dark:bg-primary/20" href="#">
|
||||
<span class="material-symbols-outlined">warehouse</span>
|
||||
<p class="text-sm font-medium leading-normal">Inventory</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">receipt_long</span>
|
||||
<p class="text-sm font-medium leading-normal">Orders</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">local_shipping</span>
|
||||
<p class="text-sm font-medium leading-normal">Suppliers</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">pie_chart</span>
|
||||
<p class="text-sm font-medium leading-normal">Reports</p>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<nav class="flex flex-col gap-1">
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">settings</span>
|
||||
<p class="text-sm font-medium leading-normal">Settings</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">help</span>
|
||||
<p class="text-sm font-medium leading-normal">Help</p>
|
||||
</a>
|
||||
</nav>
|
||||
<button class="flex min-w-[84px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-sm font-bold leading-normal hover:bg-gray-300 dark:hover:bg-gray-700">
|
||||
<span class="truncate">Logout</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<main class="flex-1 flex flex-col h-screen overflow-hidden">
|
||||
<header class="flex flex-none items-center justify-between whitespace-nowrap border-b border-solid border-gray-200 dark:border-gray-800 px-10 py-3 bg-white dark:bg-background-dark z-10">
|
||||
<div class="flex items-center gap-4 text-gray-900 dark:text-white">
|
||||
<div class="size-6 text-primary">
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.435 7.182a.75.75 0 0 0-.87-.11L12 10.435 3.435 7.072a.75.75 0 0 0-.87.11.75.75 0 0 0-.11.87l2.122 7.878a.75.75 0 0 0 .869.59l6-1.635a.75.75 0 0 0 .108 0l6 1.635a.75.75 0 0 0 .87-.59l2.12-7.878a.75.75 0 0 0-.11-.87zM12 12.18l-5.693-1.55L12 4.288l5.693 6.342L12 12.18z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-lg font-bold leading-tight tracking-[-0.015em]">WMS Dashboard</h2>
|
||||
</div>
|
||||
<div class="flex flex-1 justify-end items-center gap-4">
|
||||
<label class="relative grow max-w-sm">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-gray-500">search</span>
|
||||
<input class="form-input w-full rounded-lg border-none bg-gray-100 dark:bg-gray-800 h-10 pl-10 pr-4 text-sm text-gray-900 dark:text-white placeholder:text-gray-500 focus:ring-primary" placeholder="Search items, orders..." value=""/>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<button class="flex items-center justify-center rounded-lg h-10 w-10 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-700">
|
||||
<span class="material-symbols-outlined text-xl">notifications</span>
|
||||
</button>
|
||||
<button class="flex items-center justify-center rounded-lg h-10 w-10 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-700">
|
||||
<span class="material-symbols-outlined text-xl">help_outline</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuBNpxncwdjcD3fLZbRbit_NZyuFBZhcpV-Bvdlu6NiZL3kb65hsFRsDkTNHtC0zJxG3HGV1TInl_DCfafj3axNGSwW4-UNj1sZWhiHCYE2aK9hm-FYjrNGiEh0UqKya1EAYMTM5Z4k8qKOWPEPdIaZz9X98tPC5FIn5lbRRusCTuQmgRL-QxK9SdIMA3TflImwA1vyh3zq44j8EkkNTQWf94-e82GDHs5MwHIkK0S-Gg4d950IyRTpoABSa9qXA5yPzoaT9jCGjCodL");'></div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex-1 overflow-y-auto p-6 lg:p-10 pb-24 relative">
|
||||
<div class="mx-auto max-w-7xl">
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<a class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal" href="#">Dashboard</a>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal">/</span>
|
||||
<a class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal" href="#">Inventory</a>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal">/</span>
|
||||
<span class="text-gray-800 dark:text-gray-200 text-sm font-medium leading-normal">Batch Add Items</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-between items-center gap-4 mb-8">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h1 class="text-gray-900 dark:text-white text-3xl font-bold tracking-tight">Add Items to Inventory</h1>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-base font-normal leading-normal">Search and add multiple products to your stock in a single batch.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-gray-900/50 p-6 rounded-xl border border-gray-200 dark:border-gray-800 mb-8 shadow-sm">
|
||||
<h2 class="text-lg font-bold text-gray-900 dark:text-white mb-4">Select Products from Catalog</h2>
|
||||
<div class="flex flex-col lg:flex-row gap-4 items-end">
|
||||
<div class="flex-1 w-full relative">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Search Catalog</label>
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-gray-500">search</span>
|
||||
<input class="form-input w-full rounded-lg border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white pl-10 h-11 focus:ring-primary focus:border-primary" placeholder="Type Product Name or SKU..." type="text"/>
|
||||
</div>
|
||||
<div class="absolute top-full left-0 w-full mt-2 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-2xl z-20 p-5 grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider text-gray-400 mb-2">Selected Product</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-12 h-12 rounded bg-gray-100 dark:bg-gray-700 flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-gray-400">image</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-bold text-gray-900 dark:text-white">Smart Display Panel</p>
|
||||
<p class="text-xs text-gray-500">SKU: DISP-PNL-SD-001</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-xs font-semibold uppercase tracking-wider text-gray-400 mb-2">Medida</label>
|
||||
<select class="form-select w-full rounded-lg border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm focus:ring-primary">
|
||||
<option value="24">24</option>
|
||||
<option value="36">36</option>
|
||||
<option value="64">64</option>
|
||||
<option value="85">85</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-xs font-semibold uppercase tracking-wider text-gray-400 mb-2">Resolución</label>
|
||||
<select class="form-select w-full rounded-lg border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm focus:ring-primary">
|
||||
<option value="1080">1080</option>
|
||||
<option value="2K">2K</option>
|
||||
<option value="4K">4K</option>
|
||||
<option value="8K">8K</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-xs font-semibold uppercase tracking-wider text-gray-400 mb-2">Qty</label>
|
||||
<input class="form-input w-full rounded-lg border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm focus:ring-primary" type="number" value="10"/>
|
||||
</div>
|
||||
<div class="md:col-span-2 flex items-end">
|
||||
<button class="w-full bg-primary text-white h-11 px-4 rounded-lg font-bold hover:bg-primary/90 flex items-center justify-center gap-1">
|
||||
<span class="material-symbols-outlined text-lg">add</span> Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-gray-900/50 rounded-xl border border-gray-200 dark:border-gray-800 overflow-hidden shadow-sm">
|
||||
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-800 flex justify-between items-center">
|
||||
<h2 class="text-lg font-bold text-gray-900 dark:text-white">Queued Items (4)</h2>
|
||||
<button class="text-sm font-medium text-red-500 hover:text-red-600">Clear All</button>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gray-50 dark:bg-gray-800/50">
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Product Name</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">SKU</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Variant</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Quantity</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Unit</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100 dark:divide-gray-800">
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBMbZhSSPYoHEi3akXSqZXm-T6EghACuHJJ5NYeJ8g4XJIKtqXRhCSQ1kFcvo7Txk01ryR-r6RJ61NzPLENWMywvUVnCkQglsizZG0NKPBwRFQjXvtDULkGbGFm6EPocyHGfuzKJ0EoDr601zMBI34mfPCgn9AAaRkTMj2Ize2nCUcanlGn7QJEp6BdNcmf3JFlk-51jPTXj1-mM4Pw6AGIvarhxnZqtEAji6qRF7evVTR_56c48h5if21S3jD-wVhNVp8AltVn8KEH"/>
|
||||
</div>
|
||||
<span class="font-medium">Smart Display Panel</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">DISP-PNL-SD-001</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 rounded-full border border-blue-100 dark:border-blue-800/50 uppercase tracking-tight">Medida: 85</span>
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-purple-50 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-full border border-purple-100 dark:border-purple-800/50 uppercase tracking-tight">Resolución: 4K</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="25"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBBMBDEGh1exdBX1lU--TOCsUwfsFkYhrl8DxxvxgH-hKLkcuVtuGP_ZhRS5l_YXFWls08Ecr-Ic748cVHqHexFMMzYTPH8YL2s9OISDgsMIwcDOPxitrPUn3RBCD_krFC8SrBXBeNC8ilcFdg_JCwD5BW5gaYjAAEUMFXyM1vd-YT27KyubBk1IKATsMdDkH-NtwAHcrPgNoXsRaAcubBQiebCG1hmxKVW3fAXoDoSqywrxhwZ7cmIuo7BTThJJ1KcczxQh1jYh_w4"/>
|
||||
</div>
|
||||
<span class="font-medium">Mechanical Keyboard RGB</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">KYBD-RGB-US-02</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="px-2.5 py-1 text-xs font-medium bg-gray-100 dark:bg-gray-800 rounded-full border border-gray-200 dark:border-gray-700">Red Switch</span>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="12"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAsb9nqDON7PeKGYYAU8hmHn7B2l3waP_ewMQTpsgnpJe2vFiY-k-zncE5VEf186tDzlTwVPA6-1SgAFagugq9Anw2WXloUFTNwOrOHgAi-MNhgs0FuxRKF8XMLk6W_u6YLF5xWh3K2q317JXFSUWtURtxCi8pYM4YtHYEyuT2aIrhbAnI2LQ7ja8DvSdvpO6t1IJ6HE9RqlnAFXuLG22igxiekKT2NjRpuK5Zzu_90rBPEjb0KitG9DwiBjzKa702pccHPRqupgXke"/>
|
||||
</div>
|
||||
<span class="font-medium">USB-C Charging Cable 2m</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">CBL-USBC-2M</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="px-2.5 py-1 text-xs font-medium bg-gray-100 dark:bg-gray-800 rounded-full border border-gray-200 dark:border-gray-700">Braided</span>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="100"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuD1PtrsyrvB9KtL5DHjKotvi92lM1NsfdzyEkoW5DAEfSYoPI8MNsCJZDBMtrz6rXnIWApiymAIlp7Yq5P6JTQqpwaNJVw5I4G3KiefVME-D_jR_0iTDtPBxljmlcohkhIrSfK77wV9Wq1KL0yvjCB2UuDewIxBOs0RUl7_RbISQxYaSzVe9GbqnwI5cpj_N_1faxUA89ATStV6GovMDXFA881MUGKd4_ox_CzEG5zzPZYRe9JF7M33YH-rRHdxlpQWtRH9yw4X8sKp"/>
|
||||
</div>
|
||||
<span class="font-medium">Smart Display Panel</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">DISP-PNL-SD-001</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 rounded-full border border-blue-100 dark:border-blue-800/50 uppercase tracking-tight">Medida: 36</span>
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-purple-50 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-full border border-purple-100 dark:border-purple-800/50 uppercase tracking-tight">Resolución: 1080</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="5"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="p-6 bg-gray-50/50 dark:bg-gray-800/50 border-t border-gray-200 dark:border-gray-800 text-sm text-gray-500 dark:text-gray-400">
|
||||
Total items to be added: <span class="font-bold text-gray-900 dark:text-white">142 units</span> across 4 unique products.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="fixed bottom-0 right-0 left-64 bg-white dark:bg-background-dark border-t border-gray-200 dark:border-gray-800 p-4 px-10 flex justify-between items-center z-20 shadow-[0_-4px_6px_-1px_rgba(0,0,0,0.1)]">
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs font-medium text-gray-500 uppercase tracking-widest">Storage Location</span>
|
||||
<select class="form-select text-sm rounded-lg border-gray-300 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 focus:ring-primary h-9">
|
||||
<option>Main Warehouse (A1)</option>
|
||||
<option>South Storage (B4)</option>
|
||||
<option>Cold Storage (C2)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<button class="flex min-w-[100px] cursor-pointer items-center justify-center rounded-lg h-11 px-6 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-sm font-bold leading-normal hover:bg-gray-300 dark:hover:bg-gray-700 transition-all">
|
||||
Cancel
|
||||
</button>
|
||||
<button class="flex min-w-[200px] cursor-pointer items-center justify-center rounded-lg h-11 px-8 bg-primary text-white text-sm font-bold leading-normal tracking-[0.015em] hover:bg-primary/90 shadow-lg shadow-primary/20 transition-all">
|
||||
Confirm and Save Inventory
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
364
src/modules/warehouse/components/modal.html
Normal file
364
src/modules/warehouse/components/modal.html
Normal file
@ -0,0 +1,364 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="light" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>WMS - Batch Add Inventory Items</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Inter", "sans-serif"]
|
||||
},
|
||||
borderRadius: {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style type="text/tailwindcss">
|
||||
@layer utilities {
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background-light dark:bg-background-dark font-display text-gray-800 dark:text-gray-200 overflow-hidden">
|
||||
<div class="flex h-screen w-full relative">
|
||||
<aside class="flex w-64 flex-col border-r border-gray-200 dark:border-gray-800 bg-white dark:bg-background-dark">
|
||||
<div class="flex h-full flex-col justify-between p-4">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex items-center gap-3 p-2">
|
||||
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuCztlHhjKvu2qkn2Xi2zFHagNsNToKwcTg3vQr0KtTqBCo13dK1yyz9HzB2uLCiciLyDfnrf7pREvdblPqCcUiN0HqlSbkFwY1dpQLMbJ4hmpVgHVWaLaUCMXju06qyGQSdg2ChGVcbTQIrk-RNI2-hDOFnfrI1PD89RNSsByXGRsdkYWSyEYFOFk7bT4l7aIaasB6cdVxDfNwJdvVx15wb7-qOHZHFTPMbrkkzmjGec-f7iVqTi5U1ykNDclBSezBM97TfXajTwRJE");'></div>
|
||||
<div class="flex flex-col">
|
||||
<h1 class="text-gray-900 dark:text-white text-base font-medium leading-normal">Admin User</h1>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-sm font-normal leading-normal">Warehouse Manager</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="flex flex-col gap-2">
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<p class="text-sm font-medium leading-normal">Dashboard</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg bg-primary/10 text-primary dark:bg-primary/20" href="#">
|
||||
<span class="material-symbols-outlined">warehouse</span>
|
||||
<p class="text-sm font-medium leading-normal">Inventory</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">receipt_long</span>
|
||||
<p class="text-sm font-medium leading-normal">Orders</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">local_shipping</span>
|
||||
<p class="text-sm font-medium leading-normal">Suppliers</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">pie_chart</span>
|
||||
<p class="text-sm font-medium leading-normal">Reports</p>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<nav class="flex flex-col gap-1">
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">settings</span>
|
||||
<p class="text-sm font-medium leading-normal">Settings</p>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800" href="#">
|
||||
<span class="material-symbols-outlined">help</span>
|
||||
<p class="text-sm font-medium leading-normal">Help</p>
|
||||
</a>
|
||||
</nav>
|
||||
<button class="flex min-w-[84px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-10 px-4 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-sm font-bold leading-normal hover:bg-gray-300 dark:hover:bg-gray-700">
|
||||
<span class="truncate">Logout</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<main class="flex-1 flex flex-col h-screen overflow-hidden">
|
||||
<header class="flex flex-none items-center justify-between whitespace-nowrap border-b border-solid border-gray-200 dark:border-gray-800 px-10 py-3 bg-white dark:bg-background-dark z-10">
|
||||
<div class="flex items-center gap-4 text-gray-900 dark:text-white">
|
||||
<div class="size-6 text-primary">
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.435 7.182a.75.75 0 0 0-.87-.11L12 10.435 3.435 7.072a.75.75 0 0 0-.87.11.75.75 0 0 0-.11.87l2.122 7.878a.75.75 0 0 0 .869.59l6-1.635a.75.75 0 0 0 .108 0l6 1.635a.75.75 0 0 0 .87-.59l2.12-7.878a.75.75 0 0 0-.11-.87zM12 12.18l-5.693-1.55L12 4.288l5.693 6.342L12 12.18z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-lg font-bold leading-tight tracking-[-0.015em]">WMS Dashboard</h2>
|
||||
</div>
|
||||
<div class="flex flex-1 justify-end items-center gap-4">
|
||||
<label class="relative grow max-w-sm">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-gray-500">search</span>
|
||||
<input class="form-input w-full rounded-lg border-none bg-gray-100 dark:bg-gray-800 h-10 pl-10 pr-4 text-sm text-gray-900 dark:text-white placeholder:text-gray-500 focus:ring-primary" placeholder="Search items, orders..." value=""/>
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<button class="flex items-center justify-center rounded-lg h-10 w-10 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-700">
|
||||
<span class="material-symbols-outlined text-xl">notifications</span>
|
||||
</button>
|
||||
<button class="flex items-center justify-center rounded-lg h-10 w-10 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-700">
|
||||
<span class="material-symbols-outlined text-xl">help_outline</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuBNpxncwdjcD3fLZbRbit_NZyuFBZhcpV-Bvdlu6NiZL3kb65hsFRsDkTNHtC0zJxG3HGV1TInl_DCfafj3axNGSwW4-UNj1sZWhiHCYE2aK9hm-FYjrNGiEh0UqKya1EAYMTM5Z4k8qKOWPEPdIaZz9X98tPC5FIn5lbRRusCTuQmgRL-QxK9SdIMA3TflImwA1vyh3zq44j8EkkNTQWf94-e82GDHs5MwHIkK0S-Gg4d950IyRTpoABSa9qXA5yPzoaT9jCGjCodL");'></div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex-1 overflow-y-auto p-6 lg:p-10 pb-24">
|
||||
<div class="mx-auto max-w-7xl">
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<a class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal" href="#">Dashboard</a>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal">/</span>
|
||||
<a class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal" href="#">Inventory</a>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-sm font-medium leading-normal">/</span>
|
||||
<span class="text-gray-800 dark:text-gray-200 text-sm font-medium leading-normal">Batch Add Items</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-between items-center gap-4 mb-8">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h1 class="text-gray-900 dark:text-white text-3xl font-bold tracking-tight">Add Items to Inventory</h1>
|
||||
<p class="text-gray-500 dark:text-gray-400 text-base font-normal leading-normal">Manage your batch inventory addition list here.</p>
|
||||
</div>
|
||||
<button class="flex items-center justify-center gap-2 bg-primary text-white px-6 py-3 rounded-xl font-bold hover:bg-primary/90 transition-all shadow-lg shadow-primary/20">
|
||||
<span class="material-symbols-outlined">add_circle</span>
|
||||
Select Product to Add
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-white dark:bg-gray-900/50 rounded-xl border border-gray-200 dark:border-gray-800 overflow-hidden shadow-sm">
|
||||
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-800 flex justify-between items-center">
|
||||
<h2 class="text-lg font-bold text-gray-900 dark:text-white">Queued Items (4)</h2>
|
||||
<button class="text-sm font-medium text-red-500 hover:text-red-600">Clear All</button>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gray-50 dark:bg-gray-800/50">
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Product Name</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">SKU</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Variant</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Quantity</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Unit</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-gray-500 dark:text-gray-400 uppercase tracking-wider text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100 dark:divide-gray-800">
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBMbZhSSPYoHEi3akXSqZXm-T6EghACuHJJ5NYeJ8g4XJIKtqXRhCSQ1kFcvo7Txk01ryR-r6RJ61NzPLENWMywvUVnCkQglsizZG0NKPBwRFQjXvtDULkGbGFm6EPocyHGfuzKJ0EoDr601zMBI34mfPCgn9AAaRkTMj2Ize2nCUcanlGn7QJEp6BdNcmf3JFlk-51jPTXj1-mM4Pw6AGIvarhxnZqtEAji6qRF7evVTR_56c48h5if21S3jD-wVhNVp8AltVn8KEH"/>
|
||||
</div>
|
||||
<span class="font-medium">Smart Display Panel</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">DISP-PNL-SD-001</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 rounded-full border border-blue-100 dark:border-blue-800/50 uppercase tracking-tight">Medida: 85</span>
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-purple-50 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-full border border-purple-100 dark:border-purple-800/50 uppercase tracking-tight">Resolución: 4K</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="25"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuBBMBDEGh1exdBX1lU--TOCsUwfsFkYhrl8DxxvxgH-hKLkcuVtuGP_ZhRS5l_YXFWls08Ecr-Ic748cVHqHexFMMzYTPH8YL2s9OISDgsMIwcDOPxitrPUn3RBCD_krFC8SrBXBeNC8ilcFdg_JCwD5BW5gaYjAAEUMFXyM1vd-YT27KyubBk1IKATsMdDkH-NtwAHcrPgNoXsRaAcubBQiebCG1hmxKVW3fAXoDoSqywrxhwZ7cmIuo7BTThJJ1KcczxQh1jYh_w4"/>
|
||||
</div>
|
||||
<span class="font-medium">Mechanical Keyboard RGB</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">KYBD-RGB-US-02</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="px-2.5 py-1 text-xs font-medium bg-gray-100 dark:bg-gray-800 rounded-full border border-gray-200 dark:border-gray-700">Red Switch</span>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="12"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuAsb9nqDON7PeKGYYAU8hmHn7B2l3waP_ewMQTpsgnpJe2vFiY-k-zncE5VEf186tDzlTwVPA6-1SgAFagugq9Anw2WXloUFTNwOrOHgAi-MNhgs0FuxRKF8XMLk6W_u6YLF5xWh3K2q317JXFSUWtURtxCi8pYM4YtHYEyuT2aIrhbAnI2LQ7ja8DvSdvpO6t1IJ6HE9RqlnAFXuLG22igxiekKT2NjRpuK5Zzu_90rBPEjb0KitG9DwiBjzKa702pccHPRqupgXke"/>
|
||||
</div>
|
||||
<span class="font-medium">USB-C Charging Cable 2m</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">CBL-USBC-2M</td>
|
||||
<td class="px-6 py-4">
|
||||
<span class="px-2.5 py-1 text-xs font-medium bg-gray-100 dark:bg-gray-800 rounded-full border border-gray-200 dark:border-gray-700">Braided</span>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="100"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-gray-50/50 dark:hover:bg-gray-800/30 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded bg-gray-100 dark:bg-gray-800 overflow-hidden">
|
||||
<img alt="product" class="w-full h-full object-cover" src="https://lh3.googleusercontent.com/aida-public/AB6AXuD1PtrsyrvB9KtL5DHjKotvi92lM1NsfdzyEkoW5DAEfSYoPI8MNsCJZDBMtrz6rXnIWApiymAIlp7Yq5P6JTQqpwaNJVw5I4G3KiefVME-D_jR_0iTDtPBxljmlcohkhIrSfK77wV9Wq1KL0yvjCB2UuDewIxBOs0RUl7_RbISQxYaSzVe9GbqnwI5cpj_N_1faxUA89ATStV6GovMDXFA881MUGKd4_ox_CzEG5zzPZYRe9JF7M33YH-rRHdxlpQWtRH9yw4X8sKp"/>
|
||||
</div>
|
||||
<span class="font-medium">Smart Display Panel</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">DISP-PNL-SD-001</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 rounded-full border border-blue-100 dark:border-blue-800/50 uppercase tracking-tight">Medida: 36</span>
|
||||
<span class="px-2.5 py-1 text-[10px] font-semibold bg-purple-50 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400 rounded-full border border-purple-100 dark:border-purple-800/50 uppercase tracking-tight">Resolución: 1080</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<input class="w-20 form-input h-8 rounded border-gray-300 dark:border-gray-700 bg-transparent text-sm" type="number" value="5"/>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm">pcs</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<button class="text-gray-400 hover:text-red-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-xl">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="p-6 bg-gray-50/50 dark:bg-gray-800/50 border-t border-gray-200 dark:border-gray-800 text-sm text-gray-500 dark:text-gray-400">
|
||||
Total items to be added: <span class="font-bold text-gray-900 dark:text-white">142 units</span> across 4 unique products.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="fixed bottom-0 right-0 left-64 bg-white dark:bg-background-dark border-t border-gray-200 dark:border-gray-800 p-4 px-10 flex justify-between items-center z-20 shadow-[0_-4px_6px_-1px_rgba(0,0,0,0.1)]">
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs font-medium text-gray-500 uppercase tracking-widest">Storage Location</span>
|
||||
<select class="form-select text-sm rounded-lg border-gray-300 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 focus:ring-primary h-9">
|
||||
<option>Main Warehouse (A1)</option>
|
||||
<option>South Storage (B4)</option>
|
||||
<option>Cold Storage (C2)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<button class="flex min-w-[100px] cursor-pointer items-center justify-center rounded-lg h-11 px-6 bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-sm font-bold leading-normal hover:bg-gray-300 dark:hover:bg-gray-700 transition-all">
|
||||
Cancel
|
||||
</button>
|
||||
<button class="flex min-w-[200px] cursor-pointer items-center justify-center rounded-lg h-11 px-8 bg-primary text-white text-sm font-bold leading-normal tracking-[0.015em] hover:bg-primary/90 shadow-lg shadow-primary/20 transition-all">
|
||||
Confirm and Save Inventory
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
<div class="fixed inset-0 z-100 flex items-center justify-center">
|
||||
<div class="absolute inset-0 bg-gray-900/60 backdrop-blur-sm"></div>
|
||||
<div class="relative bg-white dark:bg-background-dark w-full max-w-2xl mx-4 rounded-2xl shadow-2xl border border-gray-200 dark:border-gray-800 overflow-hidden flex flex-col max-h-[90vh]">
|
||||
<div class="p-6 border-b border-gray-100 dark:border-gray-800 flex justify-between items-center">
|
||||
<div>
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">Add Product to Batch</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">Search and configure the product variant</p>
|
||||
</div>
|
||||
<button class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors">
|
||||
<span class="material-symbols-outlined text-2xl">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-6 overflow-y-auto space-y-8">
|
||||
<div class="space-y-3">
|
||||
<label class="block text-sm font-semibold text-gray-700 dark:text-gray-300">Search Catalog</label>
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-gray-500">search</span>
|
||||
<input class="form-input w-full rounded-xl border-gray-300 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 text-gray-900 dark:text-white pl-11 h-12 focus:ring-primary focus:border-primary" placeholder="Type Product Name or SKU..." type="text" value="Smart Display Panel"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 dark:bg-gray-800/30 rounded-xl p-5 border border-gray-100 dark:border-gray-700 space-y-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center shadow-sm">
|
||||
<span class="material-symbols-outlined text-3xl text-gray-400">image</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-lg font-bold text-gray-900 dark:text-white">Smart Display Panel</p>
|
||||
<p class="text-sm text-gray-500 font-medium tracking-tight">SKU: DISP-PNL-SD-001</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">Medida</label>
|
||||
<select class="form-select w-full rounded-lg border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm focus:ring-primary focus:border-primary h-11">
|
||||
<option value="24">24</option>
|
||||
<option value="36">36</option>
|
||||
<option value="64">64</option>
|
||||
<option selected="" value="85">85</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">Resolución</label>
|
||||
<select class="form-select w-full rounded-lg border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm focus:ring-primary focus:border-primary h-11">
|
||||
<option value="1080">1080</option>
|
||||
<option value="2K">2K</option>
|
||||
<option selected="" value="4K">4K</option>
|
||||
<option value="8K">8K</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="block text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400">Quantity</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input class="form-input flex-1 rounded-lg border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-sm focus:ring-primary focus:border-primary h-11" type="number" value="10"/>
|
||||
<span class="text-sm font-medium text-gray-500">pcs</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-end pb-1">
|
||||
<div class="bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 px-3 py-2 rounded-lg border border-blue-100 dark:border-blue-800/50 w-full flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-lg">info</span>
|
||||
<span class="text-xs font-medium">Current Stock: 420 units</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6 bg-gray-50 dark:bg-gray-800/50 border-t border-gray-100 dark:border-gray-800 flex justify-end gap-3">
|
||||
<button class="px-5 py-2.5 rounded-lg text-sm font-bold text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
|
||||
Cancel
|
||||
</button>
|
||||
<button class="bg-primary text-white px-8 py-2.5 rounded-lg text-sm font-bold hover:bg-primary/90 transition-all shadow-lg shadow-primary/20 flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-lg">add_task</span>
|
||||
Confirm and Add to List
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
@ -6,6 +6,8 @@ import Login from '../modules/auth/components/Login.vue';
|
||||
import MainLayout from '../MainLayout.vue';
|
||||
import WarehouseIndex from '../modules/warehouse/components/WarehouseIndex.vue';
|
||||
import WarehouseForm from '../modules/warehouse/components/WarehouseForm.vue';
|
||||
import WarehouseDetails from '../modules/warehouse/components/WarehouseDetails.vue';
|
||||
import BatchAddInventory from '../modules/warehouse/components/BatchAddInventory.vue';
|
||||
|
||||
import WarehouseClassification from '../modules/warehouse/components/WarehouseClassification.vue';
|
||||
import UnitOfMeasure from '../modules/catalog/components/UnitOfMeasure.vue';
|
||||
@ -71,6 +73,15 @@ const routes: RouteRecordRaw[] = [
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
name: 'WarehouseDetails',
|
||||
component: WarehouseDetails,
|
||||
meta: {
|
||||
title: 'Detalles del Almacén',
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'classifications',
|
||||
name: 'WarehouseClassifications',
|
||||
@ -80,6 +91,15 @@ const routes: RouteRecordRaw[] = [
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'batch-add',
|
||||
name: 'BatchAddInventory',
|
||||
component: BatchAddInventory,
|
||||
meta: {
|
||||
title: 'Agregar Items al Inventario',
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'inventory',
|
||||
name: 'WarehouseInventory',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user