feat: Implement Stores management page with search, filters, and data table
This commit is contained in:
parent
1b64767aac
commit
c6eaa2ef75
@ -1,5 +1,314 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import Card from 'primevue/card';
|
||||||
|
import InputText from 'primevue/inputtext';
|
||||||
|
import Button from 'primevue/button';
|
||||||
|
import DataTable from 'primevue/datatable';
|
||||||
|
import Column from 'primevue/column';
|
||||||
|
import Tag from 'primevue/tag';
|
||||||
|
import IconField from 'primevue/iconfield';
|
||||||
|
import InputIcon from 'primevue/inputicon';
|
||||||
|
import Dropdown from 'primevue/dropdown';
|
||||||
|
|
||||||
|
// Search and filters
|
||||||
|
const searchQuery = ref('');
|
||||||
|
const selectedStatus = ref('all');
|
||||||
|
const selectedType = ref('all');
|
||||||
|
const selectedLocation = ref('all');
|
||||||
|
|
||||||
|
// Filter options
|
||||||
|
const statusOptions = [
|
||||||
|
{ label: 'Todos', value: 'all' },
|
||||||
|
{ label: 'Activo', value: 'active' },
|
||||||
|
{ label: 'Inactivo', value: 'inactive' },
|
||||||
|
{ label: 'Archivado', value: 'archived' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const typeOptions = [
|
||||||
|
{ label: 'Todos', value: 'all' },
|
||||||
|
{ label: 'Tienda', value: 'store' },
|
||||||
|
{ label: 'Kiosco', value: 'kiosk' },
|
||||||
|
{ label: 'Almacén', value: 'warehouse' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const locationOptions = [
|
||||||
|
{ label: 'Todas', value: 'all' },
|
||||||
|
{ label: 'Centro', value: 'centro' },
|
||||||
|
{ label: 'Norte', value: 'norte' },
|
||||||
|
{ label: 'Sur', value: 'sur' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Sample data
|
||||||
|
const stores = ref([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Tienda Principal',
|
||||||
|
location: 'Av. Siempre Viva 742',
|
||||||
|
status: 'active',
|
||||||
|
terminals: 5,
|
||||||
|
lastActivity: 'Hoy, 10:45 AM'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Sucursal Centro',
|
||||||
|
location: 'Calle Falsa 123',
|
||||||
|
status: 'active',
|
||||||
|
terminals: 3,
|
||||||
|
lastActivity: 'Ayer, 08:15 PM'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Kiosco del Parque',
|
||||||
|
location: 'Parque Central, Stand 4',
|
||||||
|
status: 'inactive',
|
||||||
|
terminals: 1,
|
||||||
|
lastActivity: '25/08/2023'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'Almacén Norte',
|
||||||
|
location: 'Blvd. Industrial 500',
|
||||||
|
status: 'active',
|
||||||
|
terminals: 8,
|
||||||
|
lastActivity: 'Hoy, 11:00 AM'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: 'Pop-Up de Verano',
|
||||||
|
location: 'Playa Grande, Paseo Marítimo',
|
||||||
|
status: 'archived',
|
||||||
|
terminals: 2,
|
||||||
|
lastActivity: '15/07/2023'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
const handleCreateStore = () => {
|
||||||
|
console.log('Create new store');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (store: any) => {
|
||||||
|
console.log('Edit store:', store);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleView = (store: any) => {
|
||||||
|
console.log('View store:', store);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleToggleStatus = (store: any) => {
|
||||||
|
console.log('Toggle status:', store);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilters = () => {
|
||||||
|
searchQuery.value = '';
|
||||||
|
selectedStatus.value = 'all';
|
||||||
|
selectedType.value = 'all';
|
||||||
|
selectedLocation.value = 'all';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get status label
|
||||||
|
const getStatusLabel = (status: string) => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
active: 'Activo',
|
||||||
|
inactive: 'Inactivo',
|
||||||
|
archived: 'Archivado'
|
||||||
|
};
|
||||||
|
return statusMap[status] || status;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get status severity
|
||||||
|
const getStatusSeverity = (status: string) => {
|
||||||
|
const severityMap: Record<string, 'success' | 'warning' | 'secondary'> = {
|
||||||
|
active: 'success',
|
||||||
|
inactive: 'warning',
|
||||||
|
archived: 'secondary'
|
||||||
|
};
|
||||||
|
return severityMap[status] || 'secondary';
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<p>
|
<div class="space-y-6">
|
||||||
Stores Index Component
|
<!-- Header -->
|
||||||
|
<div class="flex flex-wrap justify-between gap-4 items-center">
|
||||||
|
<div class="flex min-w-72 flex-col gap-1">
|
||||||
|
<h1 class="text-surface-900 dark:text-white text-3xl md:text-4xl font-black leading-tight tracking-tight">
|
||||||
|
Gestión de Puntos de Venta
|
||||||
|
</h1>
|
||||||
|
<p class="text-surface-500 dark:text-surface-400 text-base font-normal leading-normal">
|
||||||
|
Administra, rastrea y organiza todos tus puntos de venta en un solo lugar.
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
label="Crear Nuevo Punto de Venta"
|
||||||
|
icon="pi pi-plus"
|
||||||
|
@click="handleCreateStore"
|
||||||
|
class="min-w-[200px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Table Card -->
|
||||||
|
<Card class="shadow-sm">
|
||||||
|
<template #content>
|
||||||
|
<!-- Search and Filters -->
|
||||||
|
<div class="flex flex-col md:flex-row justify-between gap-4 mb-4">
|
||||||
|
<div class="flex-1">
|
||||||
|
<IconField iconPosition="left">
|
||||||
|
<InputIcon class="pi pi-search" />
|
||||||
|
<InputText
|
||||||
|
v-model="searchQuery"
|
||||||
|
placeholder="Buscar por nombre o ID..."
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</IconField>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2 flex-wrap">
|
||||||
|
<Dropdown
|
||||||
|
v-model="selectedStatus"
|
||||||
|
:options="statusOptions"
|
||||||
|
optionLabel="label"
|
||||||
|
optionValue="value"
|
||||||
|
placeholder="Estado: Todos"
|
||||||
|
class="w-40"
|
||||||
|
/>
|
||||||
|
<Dropdown
|
||||||
|
v-model="selectedType"
|
||||||
|
:options="typeOptions"
|
||||||
|
optionLabel="label"
|
||||||
|
optionValue="value"
|
||||||
|
placeholder="Tipo: Todos"
|
||||||
|
class="w-40"
|
||||||
|
/>
|
||||||
|
<Dropdown
|
||||||
|
v-model="selectedLocation"
|
||||||
|
:options="locationOptions"
|
||||||
|
optionLabel="label"
|
||||||
|
optionValue="value"
|
||||||
|
placeholder="Ubicación: Todas"
|
||||||
|
class="w-40"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label="Limpiar"
|
||||||
|
icon="pi pi-times"
|
||||||
|
outlined
|
||||||
|
@click="clearFilters"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<DataTable
|
||||||
|
:value="stores"
|
||||||
|
:paginator="true"
|
||||||
|
:rows="5"
|
||||||
|
:rowsPerPageOptions="[5, 10, 20, 50]"
|
||||||
|
stripedRows
|
||||||
|
responsiveLayout="scroll"
|
||||||
|
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown CurrentPageReport"
|
||||||
|
currentPageReportTemplate="Mostrando {first} a {last} de {totalRecords} resultados"
|
||||||
|
>
|
||||||
|
<!-- Name Column -->
|
||||||
|
<Column field="name" header="Nombre del Punto de Venta" :sortable="true">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<span class="font-medium text-surface-900 dark:text-white">
|
||||||
|
{{ data.name }}
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<!-- Location Column -->
|
||||||
|
<Column field="location" header="Ubicación" :sortable="true">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<span class="text-surface-500 dark:text-surface-400 text-sm">
|
||||||
|
{{ data.location }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<!-- Status Column -->
|
||||||
|
<Column field="status" header="Estado" :sortable="true">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<Tag
|
||||||
|
:value="getStatusLabel(data.status)"
|
||||||
|
:severity="getStatusSeverity(data.status)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<!-- Terminals Column -->
|
||||||
|
<Column field="terminals" header="Terminales" :sortable="true">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<span class="text-center block text-surface-500 dark:text-surface-400 text-sm">
|
||||||
|
{{ data.terminals }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<!-- Last Activity Column -->
|
||||||
|
<Column field="lastActivity" header="Última Actividad" :sortable="true">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<span class="text-surface-500 dark:text-surface-400 text-sm">
|
||||||
|
{{ data.lastActivity }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<!-- Actions Column -->
|
||||||
|
<Column header="Acciones" headerStyle="text-align: right" bodyStyle="text-align: right">
|
||||||
|
<template #body="{ data }">
|
||||||
|
<div class="flex gap-2 justify-end">
|
||||||
|
<Button
|
||||||
|
icon="pi pi-pencil"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
rounded
|
||||||
|
@click="handleEdit(data)"
|
||||||
|
v-tooltip.top="'Editar'"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon="pi pi-eye"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
rounded
|
||||||
|
@click="handleView(data)"
|
||||||
|
v-tooltip.top="'Ver detalles'"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-if="data.status === 'active'"
|
||||||
|
icon="pi pi-power-off"
|
||||||
|
severity="danger"
|
||||||
|
text
|
||||||
|
rounded
|
||||||
|
@click="handleToggleStatus(data)"
|
||||||
|
v-tooltip.top="'Desactivar'"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-else-if="data.status === 'inactive'"
|
||||||
|
icon="pi pi-check"
|
||||||
|
severity="success"
|
||||||
|
text
|
||||||
|
rounded
|
||||||
|
@click="handleToggleStatus(data)"
|
||||||
|
v-tooltip.top="'Activar'"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-else
|
||||||
|
icon="pi pi-inbox"
|
||||||
|
severity="secondary"
|
||||||
|
text
|
||||||
|
rounded
|
||||||
|
@click="handleToggleStatus(data)"
|
||||||
|
v-tooltip.top="'Desarchivar'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Column>
|
||||||
|
</DataTable>
|
||||||
|
</template>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Custom styles if needed */
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user