CTL-51: feat(catalog): implement model document service and store
- Added model-document.services.ts for handling API interactions related to model documents. - Created modelDocumentStore.ts using Pinia for state management of model documents, including actions for fetching, creating, updating, and deleting documents. - Defined model document types in modelDocument.interface.ts for better type safety and clarity. - Removed obsolete index.html file from warehouse components. - Updated router to include a new route for model documents.
This commit is contained in:
parent
d1c203cd0e
commit
df0b707064
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -31,6 +31,7 @@ declare module 'vue' {
|
||||
InputGroupAddon: typeof import('primevue/inputgroupaddon')['default']
|
||||
InputIcon: typeof import('primevue/inputicon')['default']
|
||||
InputNumber: typeof import('primevue/inputnumber')['default']
|
||||
InputSwitch: typeof import('primevue/inputswitch')['default']
|
||||
InputText: typeof import('primevue/inputtext')['default']
|
||||
KpiCard: typeof import('./src/components/shared/KpiCard.vue')['default']
|
||||
Menu: typeof import('primevue/menu')['default']
|
||||
@ -39,6 +40,7 @@ declare module 'vue' {
|
||||
ProgressSpinner: typeof import('primevue/progressspinner')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Select: typeof import('primevue/select')['default']
|
||||
Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default']
|
||||
Tag: typeof import('primevue/tag')['default']
|
||||
Textarea: typeof import('primevue/textarea')['default']
|
||||
|
||||
@ -25,6 +25,7 @@ const menuItems = ref<MenuItem[]>([
|
||||
{ label: 'Unidades de Medida', icon: 'pi pi-calculator', to: '/catalog/units-of-measure' },
|
||||
{ label: 'Clasificaciones Comerciales', icon: 'pi pi-tags', to: '/catalog/classifications-comercial' },
|
||||
{ label: 'Proveedores', icon: 'pi pi-briefcase', to: '/catalog/suppliers' },
|
||||
{ label: 'Documentos del Modelo', icon: 'pi pi-file', to: '/catalog/model-documents' }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
193
src/modules/catalog/components/ModelDocuments.vue
Normal file
193
src/modules/catalog/components/ModelDocuments.vue
Normal file
@ -0,0 +1,193 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useModelDocumentStore } from '../stores/modelDocumentStore';
|
||||
import { MODULE_NAMES } from '../types/modelDocument.interface';
|
||||
|
||||
const router = useRouter();
|
||||
const documentStore = useModelDocumentStore();
|
||||
|
||||
// Breadcrumb
|
||||
const breadcrumbItems = ref([
|
||||
{ label: 'Inicio', route: '/' },
|
||||
{ label: 'Configuración', route: '/catalog' },
|
||||
{ label: 'Tipos de Documento' }
|
||||
]);
|
||||
|
||||
const home = ref({
|
||||
icon: 'pi pi-home',
|
||||
route: '/'
|
||||
});
|
||||
|
||||
// State
|
||||
const searchTerm = ref('');
|
||||
const selectedModule = ref<number | null>(null);
|
||||
|
||||
// Computed
|
||||
const documents = computed(() => documentStore.documents);
|
||||
const pagination = computed(() => documentStore.pagination);
|
||||
const loading = computed(() => documentStore.loading);
|
||||
|
||||
const filteredDocuments = computed(() => {
|
||||
let filtered = documents.value;
|
||||
|
||||
// Filter by search term
|
||||
if (searchTerm.value) {
|
||||
const search = searchTerm.value.toLowerCase();
|
||||
filtered = filtered.filter(doc =>
|
||||
doc.name.toLowerCase().includes(search) ||
|
||||
getModuleName(doc.module).toLowerCase().includes(search)
|
||||
);
|
||||
}
|
||||
|
||||
// Filter by module
|
||||
if (selectedModule.value !== null) {
|
||||
filtered = filtered.filter(doc => doc.module === selectedModule.value);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
});
|
||||
|
||||
|
||||
// Helper functions
|
||||
const getModuleName = (moduleId: number): string => {
|
||||
return MODULE_NAMES[moduleId] || `Módulo ${moduleId}`;
|
||||
};
|
||||
|
||||
|
||||
const getStatusIcon = (deletedAt: string | null) => {
|
||||
return deletedAt === null ? 'pi pi-circle-fill' : 'pi pi-circle';
|
||||
};
|
||||
|
||||
const getStatusColor = (deletedAt: string | null) => {
|
||||
return deletedAt === null ? '#10b981' : '#ef4444';
|
||||
};
|
||||
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
return new Date(dateString).toLocaleDateString('es-MX', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
const onPageChange = (event: any) => {
|
||||
documentStore.changePage(event.page + 1);
|
||||
};
|
||||
|
||||
// Lifecycle
|
||||
onMounted(async () => {
|
||||
await documentStore.fetchDocuments();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- Breadcrumb -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<Breadcrumb :home="home" :model="breadcrumbItems">
|
||||
<template #item="{ item }">
|
||||
<a
|
||||
v-if="item.route"
|
||||
:href="item.route"
|
||||
@click.prevent="router.push(item.route)"
|
||||
class="text-primary hover:underline"
|
||||
>
|
||||
{{ item.label }}
|
||||
</a>
|
||||
<span v-else class="text-surface-600 dark:text-surface-400">
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</template>
|
||||
</Breadcrumb>
|
||||
|
||||
<!-- Title -->
|
||||
<div>
|
||||
<h1 class="text-3xl font-black leading-tight tracking-tight text-surface-900 dark:text-white">
|
||||
Tipos de Documento
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Table Card -->
|
||||
<Card>
|
||||
<template #content>
|
||||
<!-- Loading State -->
|
||||
<div v-if="loading && documents.length === 0" class="flex justify-center items-center py-12">
|
||||
<ProgressSpinner
|
||||
style="width: 50px; height: 50px"
|
||||
strokeWidth="4"
|
||||
animationDuration="1s"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Data Table -->
|
||||
<DataTable
|
||||
v-else
|
||||
:value="filteredDocuments"
|
||||
:loading="loading"
|
||||
stripedRows
|
||||
responsiveLayout="scroll"
|
||||
>
|
||||
<!-- ID Column -->
|
||||
<Column field="id" header="ID" sortable style="width: 100px">
|
||||
<template #body="slotProps">
|
||||
<span class="font-semibold text-surface-400 dark:text-surface-500">
|
||||
#{{ slotProps.data.id }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
|
||||
<!-- Name Column -->
|
||||
<Column field="name" header="Nombre" sortable>
|
||||
<template #body="slotProps">
|
||||
<div class="flex items-center gap-2">
|
||||
<i
|
||||
:class="getStatusIcon(slotProps.data.deleted_at)"
|
||||
class="text-xs"
|
||||
:style="{ color: getStatusColor(slotProps.data.deleted_at) }"
|
||||
/>
|
||||
<span class="font-semibold text-surface-700 dark:text-surface-200">
|
||||
{{ slotProps.data.name }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
|
||||
<!-- Folio Column -->
|
||||
<Column field="num_folio" header="Folio Actual" sortable style="width: 150px">
|
||||
<template #body="slotProps">
|
||||
<span class="font-mono text-sm text-surface-600 dark:text-surface-300">
|
||||
{{ String(slotProps.data.num_folio).padStart(6, '0') }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
|
||||
<!-- Created At Column -->
|
||||
<Column field="created_at" header="Fecha Creación" sortable style="width: 150px">
|
||||
<template #body="slotProps">
|
||||
<span class="text-sm text-surface-500 dark:text-surface-400">
|
||||
{{ formatDate(slotProps.data.created_at) }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
</template>
|
||||
|
||||
<!-- Pagination -->
|
||||
<template #footer>
|
||||
<Paginator
|
||||
v-if="pagination.total > 0"
|
||||
:rows="pagination.perPage"
|
||||
:totalRecords="pagination.total"
|
||||
:first="(pagination.currentPage - 1) * pagination.perPage"
|
||||
@page="onPageChange"
|
||||
template="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
|
||||
:rowsPerPageOptions="[10, 15, 20, 50]"
|
||||
currentPageReportTemplate="Mostrando {first} a {last} de {totalRecords} documentos"
|
||||
/>
|
||||
</template>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
378
src/modules/catalog/components/index.html
Normal file
378
src/modules/catalog/components/index.html
Normal file
@ -0,0 +1,378 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="es">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||
<title>System Document Types Management</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" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
|
||||
rel="stylesheet" />
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#195de6",
|
||||
"background-light": "#f6f6f8",
|
||||
"background-dark": "#111621",
|
||||
"neutral-dark": "#1a202c",
|
||||
"neutral-sidebar": "#0f172a",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Inter", "sans-serif"]
|
||||
},
|
||||
borderRadius: {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-background-light dark:bg-background-dark font-display text-slate-900 overflow-hidden">
|
||||
<div class="flex h-screen w-full">
|
||||
<!-- Sidebar -->
|
||||
<aside class="w-64 bg-neutral-sidebar flex flex-col h-full border-r border-slate-800 text-slate-300">
|
||||
<div class="p-6 flex items-center gap-3 border-b border-slate-800">
|
||||
<div class="bg-primary p-1.5 rounded-lg">
|
||||
<span class="material-symbols-outlined text-white">inventory_2</span>
|
||||
</div>
|
||||
<h2 class="text-white text-lg font-bold tracking-tight">LogisPro</h2>
|
||||
</div>
|
||||
<nav class="flex-1 px-4 py-6 space-y-2 overflow-y-auto">
|
||||
<div class="text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2 px-2">Navegación</div>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-800 transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-xl">dashboard</span>
|
||||
<span class="text-sm font-medium">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-800 transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-xl">warehouse</span>
|
||||
<span class="text-sm font-medium">Almacén</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-800 transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-xl">factory</span>
|
||||
<span class="text-sm font-medium">Producción</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-800 transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-xl">analytics</span>
|
||||
<span class="text-sm font-medium">Reportes</span>
|
||||
</a>
|
||||
<div class="pt-6 text-xs font-semibold text-slate-500 uppercase tracking-wider mb-2 px-2">Sistema</div>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg bg-primary text-white transition-colors"
|
||||
href="#">
|
||||
<span class="material-symbols-outlined text-xl">settings</span>
|
||||
<span class="text-sm font-medium">Configuración</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-800 transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-xl">group</span>
|
||||
<span class="text-sm font-medium">Usuarios</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="p-4 border-t border-slate-800">
|
||||
<div class="flex items-center gap-3 px-3 py-2">
|
||||
<div class="w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center text-primary font-bold text-xs"
|
||||
data-alt="User avatar placeholder">AD</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-semibold text-white truncate">Admin Warehouse</p>
|
||||
<p class="text-xs text-slate-500 truncate">admin@logispro.com</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<!-- Main Content -->
|
||||
<main class="flex-1 flex flex-col min-w-0 bg-background-light overflow-hidden">
|
||||
<!-- Top Header -->
|
||||
<header class="h-16 bg-white border-b border-slate-200 flex items-center justify-between px-8 shrink-0">
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="material-symbols-outlined text-slate-400">menu</span>
|
||||
<h1 class="text-xl font-semibold text-slate-800">Administración de Documentos</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<button class="p-2 text-slate-500 hover:bg-slate-100 rounded-full relative">
|
||||
<span class="material-symbols-outlined">notifications</span>
|
||||
<span
|
||||
class="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full border-2 border-white"></span>
|
||||
</button>
|
||||
<button class="p-2 text-slate-500 hover:bg-slate-100 rounded-full">
|
||||
<span class="material-symbols-outlined">help_outline</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Scrollable Body -->
|
||||
<div class="flex-1 overflow-y-auto p-8 space-y-6">
|
||||
<!-- Breadcrumbs & Action -->
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||
<div>
|
||||
<nav class="flex text-xs font-semibold uppercase tracking-wider text-slate-500 space-x-2">
|
||||
<a class="hover:text-primary transition-colors" href="#">Inicio</a>
|
||||
<span>/</span>
|
||||
<a class="hover:text-primary transition-colors" href="#">Configuración</a>
|
||||
<span>/</span>
|
||||
<span class="text-primary/70">Tipos de Documento</span>
|
||||
</nav>
|
||||
<h2 class="text-3xl font-black text-slate-900 mt-1 tracking-tight">Tipos de Documento</h2>
|
||||
<p class="text-slate-500 text-sm mt-1">Gestione los formatos y folios permitidos para los
|
||||
módulos de almacén y producción.</p>
|
||||
</div>
|
||||
<button
|
||||
class="bg-primary text-white px-6 py-2.5 rounded-lg font-bold text-sm shadow-lg shadow-primary/20 hover:bg-primary/90 transition-all flex items-center gap-2 shrink-0 self-start md:self-center">
|
||||
<span class="material-symbols-outlined text-lg">add</span>
|
||||
Agregar Nuevo Documento
|
||||
</button>
|
||||
</div>
|
||||
<!-- Filters -->
|
||||
<div class="bg-white p-4 rounded-xl border border-slate-200 shadow-sm flex flex-wrap gap-4 items-end">
|
||||
<div class="flex-1 min-w-[240px]">
|
||||
<label class="block text-xs font-bold text-slate-700 uppercase mb-1.5 ml-1">Buscar por
|
||||
nombre</label>
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined absolute left-3 top-2.5 text-slate-400">search</span>
|
||||
<input
|
||||
class="w-full pl-10 pr-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all text-sm"
|
||||
placeholder="Ej. Cotización, Factura..." type="text" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full md:w-64">
|
||||
<label class="block text-xs font-bold text-slate-700 uppercase mb-1.5 ml-1">Módulo</label>
|
||||
<select
|
||||
class="w-full px-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all text-sm appearance-none bg-white">
|
||||
<option>Todos los módulos</option>
|
||||
<option>Almacén</option>
|
||||
<option>Producción</option>
|
||||
<option>Ventas</option>
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
class="px-4 py-2 text-primary font-bold text-sm hover:bg-primary/5 rounded-lg transition-colors flex items-center gap-1.5">
|
||||
<span class="material-symbols-outlined text-lg">filter_alt</span>
|
||||
Más Filtros
|
||||
</button>
|
||||
<button
|
||||
class="px-4 py-2 text-slate-500 font-medium text-sm hover:bg-slate-100 rounded-lg transition-colors">
|
||||
Limpiar
|
||||
</button>
|
||||
</div>
|
||||
<!-- Table Card -->
|
||||
<div class="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead class="bg-slate-50 border-b border-slate-200">
|
||||
<tr>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-600 uppercase tracking-wider">ID
|
||||
</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-600 uppercase tracking-wider">
|
||||
Nombre</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-600 uppercase tracking-wider">
|
||||
Módulo ID</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-600 uppercase tracking-wider">Tipo
|
||||
ID</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-600 uppercase tracking-wider">
|
||||
Folio Actual</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-600 uppercase tracking-wider">
|
||||
Fecha Creación</th>
|
||||
<th
|
||||
class="px-6 py-4 text-xs font-bold text-slate-600 uppercase tracking-wider text-right">
|
||||
Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100">
|
||||
<tr class="hover:bg-primary/5 transition-colors group">
|
||||
<td class="px-6 py-4 text-sm font-semibold text-slate-400">#1024</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-2 h-2 rounded-full bg-emerald-500"></span>
|
||||
<span class="text-sm font-semibold text-slate-700">Cotización</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<span
|
||||
class="px-2.5 py-1 rounded-full bg-slate-100 text-slate-600 text-[10px] font-bold uppercase">ALM-01</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">CT-DOC</td>
|
||||
<td class="px-6 py-4 font-mono text-sm text-slate-600">000542</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">12/10/2023</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<div class="flex justify-end gap-2">
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-primary transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">edit</span>
|
||||
</button>
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-red-500 transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">archive</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-primary/5 transition-colors group">
|
||||
<td class="px-6 py-4 text-sm font-semibold text-slate-400">#1025</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-2 h-2 rounded-full bg-emerald-500"></span>
|
||||
<span class="text-sm font-semibold text-slate-700">Orden de Compra</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<span
|
||||
class="px-2.5 py-1 rounded-full bg-slate-100 text-slate-600 text-[10px] font-bold uppercase">PRO-05</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">OC-PRO</td>
|
||||
<td class="px-6 py-4 font-mono text-sm text-slate-600">000128</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">15/10/2023</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<div class="flex justify-end gap-2">
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-primary transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">edit</span>
|
||||
</button>
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-red-500 transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">archive</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-primary/5 transition-colors group">
|
||||
<td class="px-6 py-4 text-sm font-semibold text-slate-400">#1026</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-2 h-2 rounded-full bg-emerald-500"></span>
|
||||
<span class="text-sm font-semibold text-slate-700">Vale de Salida</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<span
|
||||
class="px-2.5 py-1 rounded-full bg-slate-100 text-slate-600 text-[10px] font-bold uppercase">ALM-01</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">VS-INV</td>
|
||||
<td class="px-6 py-4 font-mono text-sm text-slate-600">000891</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">18/10/2023</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<div class="flex justify-end gap-2">
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-primary transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">edit</span>
|
||||
</button>
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-red-500 transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">archive</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="hover:bg-primary/5 transition-colors group">
|
||||
<td class="px-6 py-4 text-sm font-semibold text-slate-400">#1027</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-2 h-2 rounded-full bg-amber-400"></span>
|
||||
<span class="text-sm font-semibold text-slate-700">Ticket de
|
||||
Mantenimiento</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<span
|
||||
class="px-2.5 py-1 rounded-full bg-slate-100 text-slate-600 text-[10px] font-bold uppercase">PRO-02</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">TM-MAI</td>
|
||||
<td class="px-6 py-4 font-mono text-sm text-slate-600">000042</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-500">20/10/2023</td>
|
||||
<td class="px-6 py-4 text-right">
|
||||
<div class="flex justify-end gap-2">
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-primary transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">edit</span>
|
||||
</button>
|
||||
<button
|
||||
class="p-1.5 text-slate-400 hover:text-red-500 transition-colors hover:bg-white rounded-md shadow-none group-hover:shadow-sm">
|
||||
<span class="material-symbols-outlined text-lg">archive</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Pagination -->
|
||||
<div class="px-6 py-4 bg-slate-50 border-t border-slate-200 flex items-center justify-between">
|
||||
<p class="text-sm text-slate-500">Mostrando <span class="font-bold text-slate-700">1-4</span> de
|
||||
<span class="font-bold text-slate-700">24</span> tipos de documento</p>
|
||||
<div class="flex items-center gap-1">
|
||||
<button
|
||||
class="p-2 rounded hover:bg-slate-200 text-slate-500 transition-colors disabled:opacity-30"
|
||||
disabled="">
|
||||
<span class="material-symbols-outlined text-lg">chevron_left</span>
|
||||
</button>
|
||||
<button class="w-8 h-8 rounded bg-primary text-white text-sm font-bold shadow-sm">1</button>
|
||||
<button
|
||||
class="w-8 h-8 rounded hover:bg-slate-200 text-slate-600 text-sm font-medium transition-colors">2</button>
|
||||
<button
|
||||
class="w-8 h-8 rounded hover:bg-slate-200 text-slate-600 text-sm font-medium transition-colors">3</button>
|
||||
<span class="px-1 text-slate-400">...</span>
|
||||
<button
|
||||
class="w-8 h-8 rounded hover:bg-slate-200 text-slate-600 text-sm font-medium transition-colors">6</button>
|
||||
<button class="p-2 rounded hover:bg-slate-200 text-slate-500 transition-colors">
|
||||
<span class="material-symbols-outlined text-lg">chevron_right</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Summary Cards -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="bg-white p-6 rounded-xl border border-slate-200 flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center text-primary">
|
||||
<span class="material-symbols-outlined">description</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate-500 uppercase">Total Activos</p>
|
||||
<p class="text-2xl font-black text-slate-900">24</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-6 rounded-xl border border-slate-200 flex items-center gap-4">
|
||||
<div
|
||||
class="w-12 h-12 bg-amber-100 rounded-full flex items-center justify-center text-amber-600">
|
||||
<span class="material-symbols-outlined">update</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate-500 uppercase">Último Folio Emitido</p>
|
||||
<p class="text-2xl font-black text-slate-900">ALM-542</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-6 rounded-xl border border-slate-200 flex items-center gap-4">
|
||||
<div
|
||||
class="w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center text-indigo-600">
|
||||
<span class="material-symbols-outlined">archive</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-bold text-slate-500 uppercase">Archivados</p>
|
||||
<p class="text-2xl font-black text-slate-900">12</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
44
src/modules/catalog/services/model-document.services.ts
Normal file
44
src/modules/catalog/services/model-document.services.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import api from '../../../services/api';
|
||||
import type {
|
||||
ModelDocument,
|
||||
ModelDocumentPaginatedResponse,
|
||||
CreateModelDocumentData,
|
||||
UpdateModelDocumentData
|
||||
} from '../types/modelDocument.interface';
|
||||
|
||||
export const modelDocumentService = {
|
||||
// Obtener todos los documentos con paginación
|
||||
getDocuments: async (page = 1, perPage = 15) => {
|
||||
const response = await api.get<ModelDocumentPaginatedResponse>('/api/catalogs/document-models', {
|
||||
params: {
|
||||
page,
|
||||
per_page: perPage
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// Obtener un documento por ID
|
||||
getDocumentById: async (id: number) => {
|
||||
const response = await api.get<{ data: ModelDocument }>(`/api/catalogs/document-models/${id}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// Crear nuevo documento
|
||||
createDocument: async (data: CreateModelDocumentData) => {
|
||||
const response = await api.post<{ data: ModelDocument }>('/api/catalogs/document-models', data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// Actualizar documento
|
||||
updateDocument: async (id: number, data: UpdateModelDocumentData) => {
|
||||
const response = await api.put<{ data: ModelDocument }>(`/api/catalogs/document-models/${id}`, data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// Eliminar documento (soft delete)
|
||||
deleteDocument: async (id: number) => {
|
||||
const response = await api.delete(`/api/catalogs/document-models/${id}`);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
115
src/modules/catalog/stores/modelDocumentStore.ts
Normal file
115
src/modules/catalog/stores/modelDocumentStore.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed } from 'vue';
|
||||
import { modelDocumentService } from '../services/model-document.services';
|
||||
import type { ModelDocument, CreateModelDocumentData, UpdateModelDocumentData } from '../types/modelDocument.interface';
|
||||
|
||||
export const useModelDocumentStore = defineStore('modelDocument', () => {
|
||||
// State
|
||||
const documents = ref<ModelDocument[]>([]);
|
||||
const pagination = ref({
|
||||
currentPage: 1,
|
||||
perPage: 15,
|
||||
total: 0,
|
||||
lastPage: 1
|
||||
});
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
// Getters
|
||||
const activeDocuments = computed(() =>
|
||||
documents.value.filter(doc => doc.deleted_at === null)
|
||||
);
|
||||
|
||||
const deletedDocuments = computed(() =>
|
||||
documents.value.filter(doc => doc.deleted_at !== null)
|
||||
);
|
||||
|
||||
// Actions
|
||||
const fetchDocuments = async (page = 1) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
const response = await modelDocumentService.getDocuments(page, pagination.value.perPage);
|
||||
documents.value = response.data;
|
||||
pagination.value = {
|
||||
currentPage: response.current_page,
|
||||
perPage: response.per_page,
|
||||
total: response.total,
|
||||
lastPage: response.last_page
|
||||
};
|
||||
} catch (err: any) {
|
||||
error.value = err.message || 'Error al cargar documentos';
|
||||
console.error('Error fetching documents:', err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const createDocument = async (data: CreateModelDocumentData) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
await modelDocumentService.createDocument(data);
|
||||
// Recargar la lista después de crear
|
||||
await fetchDocuments(pagination.value.currentPage);
|
||||
} catch (err: any) {
|
||||
error.value = err.message || 'Error al crear documento';
|
||||
throw err;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const updateDocument = async (id: number, data: UpdateModelDocumentData) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
const response = await modelDocumentService.updateDocument(id, data);
|
||||
const index = documents.value.findIndex(doc => doc.id === id);
|
||||
if (index !== -1) {
|
||||
documents.value[index] = response.data;
|
||||
}
|
||||
} catch (err: any) {
|
||||
error.value = err.message || 'Error al actualizar documento';
|
||||
throw err;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteDocument = async (id: number) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
await modelDocumentService.deleteDocument(id);
|
||||
// Recargar la lista después de eliminar
|
||||
await fetchDocuments(pagination.value.currentPage);
|
||||
} catch (err: any) {
|
||||
error.value = err.message || 'Error al eliminar documento';
|
||||
throw err;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const changePage = async (page: number) => {
|
||||
await fetchDocuments(page);
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
documents,
|
||||
pagination,
|
||||
loading,
|
||||
error,
|
||||
// Getters
|
||||
activeDocuments,
|
||||
deletedDocuments,
|
||||
// Actions
|
||||
fetchDocuments,
|
||||
createDocument,
|
||||
updateDocument,
|
||||
deleteDocument,
|
||||
changePage
|
||||
};
|
||||
});
|
||||
64
src/modules/catalog/types/modelDocument.interface.ts
Normal file
64
src/modules/catalog/types/modelDocument.interface.ts
Normal file
@ -0,0 +1,64 @@
|
||||
// Tipos para Documentos del Sistema
|
||||
export interface ModelDocument {
|
||||
id: number;
|
||||
name: string;
|
||||
module: number;
|
||||
type: number;
|
||||
num_folio: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deleted_at: string | null;
|
||||
}
|
||||
|
||||
export interface PaginationLink {
|
||||
url: string | null;
|
||||
label: string;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface ModelDocumentPaginatedResponse {
|
||||
current_page: number;
|
||||
data: ModelDocument[];
|
||||
first_page_url: string;
|
||||
from: number;
|
||||
last_page: number;
|
||||
last_page_url: string;
|
||||
links: PaginationLink[];
|
||||
next_page_url: string | null;
|
||||
path: string;
|
||||
per_page: number;
|
||||
prev_page_url: string | null;
|
||||
to: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface CreateModelDocumentData {
|
||||
name: string;
|
||||
module: number;
|
||||
type: number;
|
||||
num_folio?: number;
|
||||
}
|
||||
|
||||
export interface UpdateModelDocumentData extends Partial<CreateModelDocumentData> {
|
||||
}
|
||||
|
||||
export interface ModelDocumentStats {
|
||||
total_active: number;
|
||||
last_folio: string;
|
||||
archived: number;
|
||||
}
|
||||
|
||||
// Module mapping
|
||||
export const MODULE_NAMES: Record<number, string> = {
|
||||
1: 'Ventas',
|
||||
2: 'Compras',
|
||||
3: 'Clientes',
|
||||
4: 'Proveedores',
|
||||
5: 'Inventarios'
|
||||
};
|
||||
|
||||
// Type mapping
|
||||
export const TYPE_NAMES: Record<number, string> = {
|
||||
0: 'Sin Folio',
|
||||
1: 'Con Folio'
|
||||
};
|
||||
@ -1,448 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="light" lang="es">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||
<title>Multi-Warehouse Goods Receipt Entry | Logistics Pro</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;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 id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"primary": "#137fec",
|
||||
"background-light": "#f6f7f8",
|
||||
"background-dark": "#101922",
|
||||
},
|
||||
fontFamily: {
|
||||
"display": ["Inter"]
|
||||
},
|
||||
borderRadius: { "DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px" },
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.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 min-h-screen">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<aside
|
||||
class="w-64 bg-white dark:bg-slate-900 border-r border-slate-200 dark:border-slate-800 flex flex-col shrink-0">
|
||||
<div class="p-6 flex items-center gap-3">
|
||||
<div class="w-10 h-10 bg-primary rounded-lg flex items-center justify-center text-white">
|
||||
<span class="material-symbols-outlined">inventory_2</span>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-slate-900 dark:text-white text-base font-bold leading-none">Logistics Pro</h1>
|
||||
<p class="text-slate-500 dark:text-slate-400 text-xs mt-1">Warehouse Admin</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="flex-1 px-4 py-4 space-y-1">
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800 rounded-lg transition-colors"
|
||||
href="#">
|
||||
<span class="material-symbols-outlined">dashboard</span>
|
||||
<span class="text-sm font-medium">Dashboard</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800 rounded-lg transition-colors"
|
||||
href="#">
|
||||
<span class="material-symbols-outlined">package_2</span>
|
||||
<span class="text-sm font-medium">Inventario</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 bg-primary/10 text-primary rounded-lg transition-colors"
|
||||
href="#">
|
||||
<span class="material-symbols-outlined"
|
||||
style="font-variation-settings: 'FILL' 1">shopping_cart</span>
|
||||
<span class="text-sm font-medium">Órdenes de Compra</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800 rounded-lg transition-colors"
|
||||
href="#">
|
||||
<span class="material-symbols-outlined">warehouse</span>
|
||||
<span class="text-sm font-medium">Almacenes</span>
|
||||
</a>
|
||||
<a class="flex items-center gap-3 px-3 py-2 text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800 rounded-lg transition-colors"
|
||||
href="#">
|
||||
<span class="material-symbols-outlined">bar_chart</span>
|
||||
<span class="text-sm font-medium">Reportes</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="p-4 border-t border-slate-200 dark:border-slate-800">
|
||||
<div class="flex items-center gap-3 px-3 py-2">
|
||||
<div class="size-8 rounded-full bg-slate-200 dark:bg-slate-700 bg-cover bg-center"
|
||||
style="background-image: url('https://lh3.googleusercontent.com/aida-public/AB6AXuDa90XPiU0x0vWPCwSkY-b0XPWxuaglsKdsGDuVxfyQKkMYEU5M9ZhbSQkCrmRlRjYEiSLJ6gAeZWIORr6MFvWrYq-WoJFzzEUf18zJjkqmJK9oU270B7r6BRVz-ynoNSS6rUNF4_PE2az4uQgysTtym0Akce2JSv5s077kdSfpUvEYPzeMM4Oi9SSMG9kAIjTiQbCrRVUcE81w8a1TwD-JHuzmXutnjRS3BaPKKcT57SiJhYhoSkL1waAxm7SWR_fWDpTzxbnDlHnl')">
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-medium text-slate-900 dark:text-white truncate">Carlos Ruiz</p>
|
||||
<p class="text-xs text-slate-500 truncate">Supervisor</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<main class="flex-1 flex flex-col min-w-0 overflow-hidden">
|
||||
<header
|
||||
class="h-16 bg-white dark:bg-slate-900 border-b border-slate-200 dark:border-slate-800 flex items-center justify-between px-8 shrink-0">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center gap-2 text-slate-400 text-sm font-medium">
|
||||
<a class="hover:text-primary" href="#">Inicio</a>
|
||||
<span class="material-symbols-outlined text-xs">chevron_right</span>
|
||||
<a class="hover:text-primary" href="#">Órdenes de Compra</a>
|
||||
<span class="material-symbols-outlined text-xs">chevron_right</span>
|
||||
<span class="text-slate-900 dark:text-white">Registrar Entrada (Multialmacén)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="relative w-64">
|
||||
<span
|
||||
class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-lg">search</span>
|
||||
<input
|
||||
class="w-full pl-10 pr-4 py-1.5 bg-slate-100 dark:bg-slate-800 border-none rounded-lg text-sm focus:ring-2 focus:ring-primary/20"
|
||||
placeholder="Buscar PO, SKU..." type="text" />
|
||||
</div>
|
||||
<button class="p-2 text-slate-400 hover:text-slate-600 dark:hover:text-white">
|
||||
<span class="material-symbols-outlined">notifications</span>
|
||||
</button>
|
||||
<button class="p-2 text-slate-400 hover:text-slate-600 dark:hover:text-white">
|
||||
<span class="material-symbols-outlined">settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex-1 overflow-y-auto p-8">
|
||||
<div class="max-w-7xl mx-auto space-y-6">
|
||||
<div class="flex flex-col md:flex-row md:items-end justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="text-3xl font-black text-slate-900 dark:text-white tracking-tight">Registrar
|
||||
Entrada de Mercancía</h2>
|
||||
<p class="text-slate-500 dark:text-slate-400 mt-1 flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-base">receipt_long</span>
|
||||
Purchase Order #ORD-2023-001 | <span class="text-primary font-semibold">Distribución
|
||||
Multi-Almacén</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="flex gap-4 bg-white dark:bg-slate-900 px-4 py-2 rounded-lg border border-slate-200 dark:border-slate-800 shadow-sm">
|
||||
<div class="text-center">
|
||||
<p class="text-[10px] text-slate-500 uppercase tracking-wider font-bold">Total Items
|
||||
PO</p>
|
||||
<p class="text-lg font-black text-slate-900 dark:text-white leading-tight">12</p>
|
||||
</div>
|
||||
<div class="w-px bg-slate-200 dark:bg-slate-800 h-8 self-center"></div>
|
||||
<div class="text-center">
|
||||
<p class="text-[10px] text-slate-500 uppercase tracking-wider font-bold">Recibidos
|
||||
</p>
|
||||
<p class="text-lg font-black text-primary leading-tight">0</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="inline-flex items-center gap-2 px-4 py-2 bg-slate-200 dark:bg-slate-800 text-slate-700 dark:text-slate-200 font-bold text-sm rounded-lg hover:bg-slate-300 transition-colors">
|
||||
<span class="material-symbols-outlined text-lg">visibility</span>
|
||||
Ver Detalles
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 shadow-sm overflow-hidden">
|
||||
<div
|
||||
class="px-6 py-4 border-b border-slate-200 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-800/50 flex justify-between items-center">
|
||||
<h3 class="font-bold text-slate-900 dark:text-white">Productos de la Orden</h3>
|
||||
<span class="text-xs text-slate-500 flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-sm">info</span>
|
||||
Seleccione el almacén de destino por cada producto
|
||||
</span>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr
|
||||
class="text-left text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider bg-slate-50 dark:bg-slate-800/30">
|
||||
<th class="px-6 py-4">Producto</th>
|
||||
<th class="px-6 py-4">SKU / Ref</th>
|
||||
<th class="px-6 py-4 text-center">Cant. PO</th>
|
||||
<th class="px-6 py-4 text-center">Recibida</th>
|
||||
<th class="px-6 py-4">Almacén de Destino</th>
|
||||
<th class="px-6 py-4">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-200 dark:divide-slate-800">
|
||||
<tr class="group hover:bg-slate-50 dark:hover:bg-slate-800/50 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="size-10 bg-slate-100 dark:bg-slate-800 rounded-lg flex items-center justify-center text-slate-400">
|
||||
<span class="material-symbols-outlined">inventory</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span
|
||||
class="text-sm font-semibold text-slate-900 dark:text-white">Cables
|
||||
de Red Cat6 2m</span>
|
||||
<span class="text-xs text-slate-500">Accesorios Networking</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-600 dark:text-slate-400">NET-C62M-WH
|
||||
</td>
|
||||
<td
|
||||
class="px-6 py-4 text-center text-sm font-bold text-slate-900 dark:text-white">
|
||||
50</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex justify-center">
|
||||
<input
|
||||
class="w-20 text-center px-2 py-1 bg-slate-100 dark:bg-slate-800 border-none rounded-lg text-sm font-bold focus:ring-2 focus:ring-primary"
|
||||
max="50" min="0" type="number" value="0" />
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<select
|
||||
class="w-full px-3 py-1.5 bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg text-xs focus:ring-primary focus:border-primary">
|
||||
<option value="">Seleccione Almacén...</option>
|
||||
<option selected="" value="1">Almacén Principal (CDMX)</option>
|
||||
<option value="2">Bodega Regional (MTY)</option>
|
||||
<option value="3">CEDIS (GDL)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<span
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-[10px] font-bold bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-400 uppercase">Estándar</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="bg-primary/[0.02] dark:bg-primary/[0.05]">
|
||||
<td class="px-6 py-4 border-l-4 border-primary">
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="size-10 bg-primary/10 rounded-lg flex items-center justify-center text-primary">
|
||||
<span class="material-symbols-outlined">laptop_mac</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span
|
||||
class="text-sm font-semibold text-slate-900 dark:text-white">MacBook
|
||||
Pro M2 14"</span>
|
||||
<span class="text-xs text-slate-500">Equipos de Cómputo</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-600 dark:text-slate-400">LAP-MBP14-M2
|
||||
</td>
|
||||
<td
|
||||
class="px-6 py-4 text-center text-sm font-bold text-slate-900 dark:text-white">
|
||||
5</td>
|
||||
<td class="px-6 py-4 text-center">
|
||||
<span class="text-sm font-black text-primary">1 / 5</span>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="text-xs text-slate-400 italic">Asignación por número de serie
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<button
|
||||
class="inline-flex items-center gap-2 px-3 py-1.5 bg-primary text-white text-xs font-bold rounded-lg hover:bg-primary/90 transition-all shadow-sm">
|
||||
<span class="material-symbols-outlined text-sm">barcode_scanner</span>
|
||||
GESTIONAR SERIES
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="bg-primary/[0.02] dark:bg-primary/[0.05]">
|
||||
<td class="px-10 pb-6 pt-2" colspan="6">
|
||||
<div
|
||||
class="bg-white dark:bg-slate-800 rounded-xl border border-primary/20 p-5 shadow-sm">
|
||||
<div
|
||||
class="flex items-center justify-between mb-4 pb-3 border-b border-slate-100 dark:border-slate-700">
|
||||
<div>
|
||||
<h4
|
||||
class="text-sm font-bold text-slate-700 dark:text-slate-200">
|
||||
Entrada de Números de Serie (4 Pendientes)</h4>
|
||||
<p class="text-[11px] text-slate-500">Defina el almacén para
|
||||
cada equipo escaneado</p>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center gap-2 text-xs text-primary font-bold bg-primary/10 px-3 py-1.5 rounded-full">
|
||||
<span class="material-symbols-outlined text-sm">barcode</span>
|
||||
Listo para escanear
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||
<div class="lg:col-span-5 space-y-4">
|
||||
<div>
|
||||
<label
|
||||
class="block text-[10px] font-bold text-slate-500 uppercase mb-1">Número
|
||||
de Serie</label>
|
||||
<div class="relative">
|
||||
<span
|
||||
class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-slate-400">qr_code_scanner</span>
|
||||
<input
|
||||
class="w-full pl-10 pr-4 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-200 dark:border-slate-600 rounded-lg text-sm focus:ring-primary focus:border-primary"
|
||||
placeholder="Escanear o escribir serie..."
|
||||
type="text" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
class="block text-[10px] font-bold text-slate-500 uppercase mb-1">Almacén
|
||||
Destino</label>
|
||||
<select
|
||||
class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-200 dark:border-slate-600 rounded-lg text-sm focus:ring-primary focus:border-primary">
|
||||
<option value="1">Almacén Principal (CDMX)</option>
|
||||
<option value="2">Bodega Regional (MTY)</option>
|
||||
<option value="3">CEDIS (GDL)</option>
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
class="w-full py-2 bg-slate-900 dark:bg-slate-700 text-white text-xs font-bold rounded-lg hover:bg-black transition-colors">
|
||||
Registrar Serie
|
||||
</button>
|
||||
</div>
|
||||
<div class="lg:col-span-7">
|
||||
<div
|
||||
class="bg-slate-50 dark:bg-slate-900/50 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden">
|
||||
<table class="w-full text-xs">
|
||||
<thead class="bg-slate-100 dark:bg-slate-800">
|
||||
<tr>
|
||||
<th
|
||||
class="px-3 py-2 text-left font-bold text-slate-500 uppercase">
|
||||
Nº Serie</th>
|
||||
<th
|
||||
class="px-3 py-2 text-left font-bold text-slate-500 uppercase">
|
||||
Almacén Destino</th>
|
||||
<th class="px-3 py-2 text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody
|
||||
class="divide-y divide-slate-200 dark:divide-slate-700">
|
||||
<tr>
|
||||
<td
|
||||
class="px-3 py-2 font-mono text-slate-900 dark:text-white">
|
||||
SN-LAP-M2-00192</td>
|
||||
<td class="px-3 py-2">
|
||||
<span
|
||||
class="inline-flex items-center gap-1.5">
|
||||
<span
|
||||
class="w-2 h-2 rounded-full bg-emerald-500"></span>
|
||||
<span
|
||||
class="text-slate-600 dark:text-slate-300">Almacén
|
||||
Principal (CDMX)</span>
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 py-2 text-right">
|
||||
<button
|
||||
class="text-slate-400 hover:text-red-500 transition-colors">
|
||||
<span
|
||||
class="material-symbols-outlined text-lg">delete</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-3 py-4 text-center text-slate-400 italic bg-slate-50/50 dark:bg-slate-800/30"
|
||||
colspan="3">
|
||||
Escanee el siguiente equipo para asignar
|
||||
almacén...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="group hover:bg-slate-50 dark:hover:bg-slate-800/50 transition-colors">
|
||||
<td class="px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="size-10 bg-slate-100 dark:bg-slate-800 rounded-lg flex items-center justify-center text-slate-400">
|
||||
<span class="material-symbols-outlined">print</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span
|
||||
class="text-sm font-semibold text-slate-900 dark:text-white">Impresora
|
||||
Zebra ZT411</span>
|
||||
<span class="text-xs text-slate-500">Hardware Almacén</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-slate-600 dark:text-slate-400">PRN-ZB411-IND
|
||||
</td>
|
||||
<td
|
||||
class="px-6 py-4 text-center text-sm font-bold text-slate-900 dark:text-white">
|
||||
2</td>
|
||||
<td class="px-6 py-4 text-center text-sm font-bold text-slate-400">0 / 2</td>
|
||||
<td class="px-6 py-4">
|
||||
<div class="text-xs text-slate-400 italic">Asignación por serie requerida
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<button
|
||||
class="inline-flex items-center gap-2 px-3 py-1.5 border border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-300 text-xs font-bold rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors">
|
||||
<span class="material-symbols-outlined text-sm">barcode_scanner</span>
|
||||
GESTIONAR SERIES
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div
|
||||
class="md:col-span-2 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-900/50 p-4 rounded-xl flex items-start gap-4">
|
||||
<span class="material-symbols-outlined text-amber-600 dark:text-amber-500">warning</span>
|
||||
<div>
|
||||
<p class="text-sm font-bold text-amber-800 dark:text-amber-400">Pendiente de Validación
|
||||
y Distribución</p>
|
||||
<p class="text-sm text-amber-700 dark:text-amber-500/80">Faltan registrar 6 números de
|
||||
serie y asignar almacén de destino a 1 item de tipo estándar antes de confirmar.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white dark:bg-slate-900 p-4 rounded-xl border border-slate-200 dark:border-slate-800 shadow-sm">
|
||||
<h4 class="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3">Resumen de
|
||||
Destinos</h4>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between text-xs">
|
||||
<span class="text-slate-600 dark:text-slate-400">Almacén Principal (CDMX)</span>
|
||||
<span class="font-bold text-slate-900 dark:text-white">1 Unidad</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-xs">
|
||||
<span class="text-slate-600 dark:text-slate-400">Bodega Regional (MTY)</span>
|
||||
<span class="font-bold text-slate-900 dark:text-white">0 Unidades</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-xs">
|
||||
<span class="text-slate-600 dark:text-slate-400">CEDIS (GDL)</span>
|
||||
<span class="font-bold text-slate-900 dark:text-white">0 Unidades</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer
|
||||
class="h-20 bg-white dark:bg-slate-900 border-t border-slate-200 dark:border-slate-800 flex items-center justify-end px-8 gap-4 shrink-0">
|
||||
<button
|
||||
class="px-6 py-2.5 text-sm font-bold text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-white transition-colors">
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
class="px-8 py-2.5 bg-primary text-white text-sm font-bold rounded-lg shadow-lg shadow-primary/20 hover:bg-primary/90 transition-all opacity-50 cursor-not-allowed">
|
||||
Confirmar Recepción Multi-Almacén
|
||||
</button>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -27,6 +27,8 @@ import Purchases from '../modules/purchases/components/Purchases.vue';
|
||||
import PurchaseDetails from '../modules/purchases/components/PurchaseDetails.vue';
|
||||
import PurchaseForm from '../modules/purchases/components/PurchaseForm.vue';
|
||||
import WarehouseAddInventory from '../modules/warehouse/components/WarehouseAddInventory.vue';
|
||||
import ModelDocuments from '../modules/catalog/components/ModelDocuments.vue';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/login',
|
||||
@ -161,6 +163,15 @@ const routes: RouteRecordRaw[] = [
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'model-documents',
|
||||
name: 'ModelDocuments',
|
||||
component: ModelDocuments,
|
||||
meta: {
|
||||
title: 'Documentos del Modelo',
|
||||
requiresAuth: true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user