MOD: actualizar rutas y mejorar la interfaz de usuario en secciones de dirección y concepto

This commit is contained in:
Juan Felipe Zapata Moreno 2025-11-28 12:50:27 -06:00
parent 8d513d215c
commit d79552fafc
16 changed files with 402 additions and 402 deletions

View File

@ -25,33 +25,33 @@ const handleSubmit = () => {
</script>
<template>
<div class="bg-white rounded-xl p-6 m-3 max-w-auto shadow-lg mb-10">
<h3 class="text-xl font-semibold mb-4 text-gray-800">
{{ $t('address.create.title') }}
</h3>
<div class="bg-white rounded-lg p-8 mx-4 mt-4 mb-6 shadow-md">
<h2 class="text-2xl font-bold mb-6 text-gray-900">
Crear nueva dirección
</h2>
<form @submit.prevent="handleSubmit">
<div class="mb-5">
<div class="mb-6">
<label
for="addressName"
class="block text-sm text-gray-600 font-medium mb-2"
class="block text-sm text-gray-700 font-medium mb-2"
>
{{ $t('address.name') }}:
Nombre de la Dirección:
</label>
<input
type="text"
id="addressName"
v-model="addressName"
:placeholder="$t('address.placeholder')"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="Ingrese el nombre de la dirección"
class="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-all"
/>
</div>
<div class="mb-3 flex justify-center">
<div class="flex justify-center">
<button
type="submit"
class="w-1/4 bg-[#7a0b3a] hover:bg-[#68082e] text-white font-medium py-3.5 rounded-lg transition-colors"
class="px-16 bg-primary hover:bg-primary/90 text-white font-semibold py-3 rounded-md transition-all duration-200 shadow-sm hover:shadow-md"
>
{{ $t('save') }}
Guardar
</button>
</div>
</form>

View File

@ -7,7 +7,7 @@ import Textarea from "@Holos/Form/Textarea.vue";
import Selectable from "@Holos/Form/Selectable.vue";
/** Eventos */
const emit = defineEmits(['concept-created']);
const emit = defineEmits(["concept-created"]);
const form = useForm({
direction_id: null,
@ -43,58 +43,71 @@ const resetForm = () => {
form.charge_type = null;
};
const isFormOpen = ref(false);
const addresses = ref([]);
const units = ref([]);
const chargeTypeId = computed(() => {
return typeof form.charge_type === 'object' && form.charge_type?.id
? form.charge_type.id
return typeof form.charge_type === "object" && form.charge_type?.id
? form.charge_type.id
: form.charge_type;
});
const chargeTypesOptions = ref([
{ id: 'uma_range', name: 'Rango en UMA' },
{ id: 'peso_range', name: 'Rango en Peso' },
{ id: 'uma_fixed', name: 'UMA unitario' },
{ id: 'peso_fixed', name: 'Peso unitario' },
{ id: "uma_range", name: "Rango en UMA" },
{ id: "peso_range", name: "Rango en Peso" },
{ id: "uma_fixed", name: "UMA unitario" },
{ id: "peso_fixed", name: "Peso unitario" },
]);
const showUmaFields = computed(() => {
return chargeTypeId.value === 'uma_range' || chargeTypeId.value === 'uma_fixed';
return (
chargeTypeId.value === "uma_range" || chargeTypeId.value === "uma_fixed"
);
});
const showPesoFields = computed(() => {
return chargeTypeId.value === 'peso_range' || chargeTypeId.value === 'peso_fixed';
return (
chargeTypeId.value === "peso_range" || chargeTypeId.value === "peso_fixed"
);
});
const isRangeType = computed(() => {
return chargeTypeId.value === 'uma_range' || chargeTypeId.value === 'peso_range';
return (
chargeTypeId.value === "uma_range" || chargeTypeId.value === "peso_range"
);
});
const isFixedType = computed(() => {
return chargeTypeId.value === 'uma_fixed' || chargeTypeId.value === 'peso_fixed';
return (
chargeTypeId.value === "uma_fixed" || chargeTypeId.value === "peso_fixed"
);
});
/** Cargar cosas */
onMounted(async () => {
api.get(apiURL('directions'), {
api.get(apiURL("directions"), {
onSuccess: (data) => {
addresses.value = data.models?.data || data.data || [];
}
},
});
api.get(apiURL('units'), {
api.get(apiURL("units"), {
onSuccess: (data) => {
units.value = data.models?.data || data.data || [];
}
},
});
});
/** Métodos */
const handleSubmit = () => {
const baseData = {
direction_id: typeof form.direction_id === 'object' ? form.direction_id.id : Number(form.direction_id),
unit_id: typeof form.unit_id === 'object' ? form.unit_id.id : Number(form.unit_id),
direction_id:
typeof form.direction_id === "object"
? form.direction_id.id
: Number(form.direction_id),
unit_id:
typeof form.unit_id === "object" ? form.unit_id.id : Number(form.unit_id),
short_name: form.short_name,
name: form.name,
legal_instrument: form.legal_instrument,
@ -105,13 +118,17 @@ const handleSubmit = () => {
// Agregar campos condicionales solo si tienen valor
if (showUmaFields.value && isRangeType.value) {
if (form.min_amount_uma) baseData.min_amount_uma = Number(form.min_amount_uma);
if (form.max_amount_uma) baseData.max_amount_uma = Number(form.max_amount_uma);
if (form.min_amount_uma)
baseData.min_amount_uma = Number(form.min_amount_uma);
if (form.max_amount_uma)
baseData.max_amount_uma = Number(form.max_amount_uma);
}
if (showPesoFields.value && isRangeType.value) {
if (form.min_amount_peso) baseData.min_amount_peso = Number(form.min_amount_peso);
if (form.max_amount_peso) baseData.max_amount_peso = Number(form.max_amount_peso);
if (form.min_amount_peso)
baseData.min_amount_peso = Number(form.min_amount_peso);
if (form.max_amount_peso)
baseData.max_amount_peso = Number(form.max_amount_peso);
}
if (showUmaFields.value && isFixedType.value && form.unit_cost_uma) {
@ -122,153 +139,182 @@ const handleSubmit = () => {
baseData.unit_cost_peso = Number(form.unit_cost_peso);
}
emit('concept-created', baseData);
emit("concept-created", baseData);
resetForm();
isFormOpen.value = false;
};
</script>
<template>
<div class="bg-white rounded-xl p-6 m-3 max-w-auto shadow-lg mb-10">
<h3 class="text-xl font-semibold mb-4 text-gray-800">
{{ $t('concept.create.title') }}
</h3>
<form @submit.prevent="handleSubmit">
<div class="mb-5 grid grid-cols-2 gap-4">
<Selectable
v-model="form.direction_id"
label="name"
value="id"
:title="$t('concept.direction')"
:options="addresses"
required
/>
<Input
v-model="form.short_name"
class="col-span-2"
:id="$t('concept.shortName')"
type="text"
:onError="form.errors.short_name"
required
/>
</div>
<Input
v-model="form.name"
class="col-span-2"
:id="$t('concept.name')"
type="text"
:onError="form.errors.name"
required
/>
<div class="mb-5 grid grid-cols-2 gap-4 py-2">
<Input
v-model="form.legal_instrument"
class="col-span-2"
:id="$t('concept.legal')"
type="text"
:onError="form.errors.legal_instrument"
required
/>
<Input
v-model="form.article"
class="col-span-2"
:id="$t('concept.article')"
type="text"
:onError="form.errors.article"
required
/>
</div>
<Textarea
v-model="form.content"
class="col-span-2"
:id="$t('concept.description')"
:onError="form.errors.content"
required
/>
<div class="mb-5 py-2">
<Selectable
v-model="form.charge_type"
label="name"
value="id"
:title="$t('concept.chargeType')"
:options="chargeTypesOptions"
required
/>
</div>
<div v-if="showUmaFields && isRangeType" class="mb-5 grid grid-cols-2 gap-4 py-2">
<Input
v-model="form.min_amount_uma"
:id="$t('concept.minimumAmountUma')"
type="number"
step="0.01"
:onError="form.errors.min_amount_uma"
/>
<Input
v-model="form.max_amount_uma"
:id="$t('concept.maximumAmountUma')"
type="number"
step="0.01"
:onError="form.errors.max_amount_uma"
/>
</div>
<div v-if="showPesoFields && isRangeType" class="mb-5 grid grid-cols-2 gap-4 py-2">
<Input
v-model="form.min_amount_peso"
:id="$t('concept.minimumAmountPeso')"
type="number"
step="0.01"
:onError="form.errors.min_amount_peso"
/>
<Input
v-model="form.max_amount_peso"
:id="$t('concept.maximumAmountPeso')"
type="number"
step="0.01"
:onError="form.errors.max_amount_peso"
/>
</div>
<Selectable
v-model="form.unit_id"
label="name"
value="id"
:title="$t('concept.sizeUnit')"
:options="units"
required
/>
<div v-if="isFixedType" >
<hr class="my-4 border-gray-300" />
<h4 class="text-lg font-semibold mb-4 text-gray-700">
{{ $t('concept.tabulator') }}
</h4>
<div class="mb-5 grid grid-cols-3 gap-4 py-2">
<Input
v-if="showUmaFields"
v-model="form.unit_cost_uma"
:id="$t('concept.costUnitUma')"
type="number"
step="0.01"
:onError="form.errors.unit_cost_uma"
/>
<Input
v-if="showPesoFields"
v-model="form.unit_cost_peso"
:id="$t('concept.costUnitPeso')"
type="number"
step="0.01"
:onError="form.errors.unit_cost_peso"
/>
</div>
</div>
<div class="mb-3 p-7 flex justify-center">
<div class="mx-4 mt-4 mb-6">
<button
v-if="!isFormOpen"
@click="isFormOpen = true"
class="w-full bg-primary hover:bg-primary/90 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 shadow-md hover:shadow-lg flex items-center justify-center space-x-2"
>
<span class="text-2xl">+</span>
<span>Nuevo Concepto</span>
</button>
<div
v-if="isFormOpen"
class="bg-white rounded-lg p-8 mx-4 mt-4 mb-6 shadow-md"
>
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold text-gray-900">
{{ $t("concept.create.title") }}
</h2>
<button
type="submit"
:disabled="form.processing"
class="w-1/4 bg-[#7a0b3a] hover:bg-[#68082e] text-white font-medium py-3.5 rounded-lg transition-colors disabled:opacity-50"
@click="isFormOpen = false"
class="text-gray-400 hover:text-gray-600 transition-colors"
title="Cerrar"
>
{{ form.processing ? 'Guardando...' : $t('save') }}
<span class="text-2xl">&times;</span>
</button>
</div>
</form>
<form @submit.prevent="handleSubmit">
<div class="mb-5 grid grid-cols-2 gap-4">
<Selectable
v-model="form.direction_id"
label="name"
value="id"
:title="$t('concept.direction')"
:options="addresses"
required
/>
<Input
v-model="form.short_name"
class="col-span-2"
:id="$t('concept.shortName')"
type="text"
:onError="form.errors.short_name"
required
/>
</div>
<Input
v-model="form.name"
class="col-span-2"
:id="$t('concept.name')"
type="text"
:onError="form.errors.name"
required
/>
<div class="mb-5 grid grid-cols-2 gap-4 py-2">
<Input
v-model="form.legal_instrument"
class="col-span-2"
:id="$t('concept.legal')"
type="text"
:onError="form.errors.legal_instrument"
required
/>
<Input
v-model="form.article"
class="col-span-2"
:id="$t('concept.article')"
type="text"
:onError="form.errors.article"
required
/>
</div>
<Textarea
v-model="form.content"
class="col-span-2"
:id="$t('concept.description')"
:onError="form.errors.content"
required
/>
<div class="mb-5 py-2">
<Selectable
v-model="form.charge_type"
label="name"
value="id"
:title="$t('concept.chargeType')"
:options="chargeTypesOptions"
required
/>
</div>
<div
v-if="showUmaFields && isRangeType"
class="mb-5 grid grid-cols-2 gap-4 py-2"
>
<Input
v-model="form.min_amount_uma"
:id="$t('concept.minimumAmountUma')"
type="number"
step="0.01"
:onError="form.errors.min_amount_uma"
/>
<Input
v-model="form.max_amount_uma"
:id="$t('concept.maximumAmountUma')"
type="number"
step="0.01"
:onError="form.errors.max_amount_uma"
/>
</div>
<div
v-if="showPesoFields && isRangeType"
class="mb-5 grid grid-cols-2 gap-4 py-2"
>
<Input
v-model="form.min_amount_peso"
:id="$t('concept.minimumAmountPeso')"
type="number"
step="0.01"
:onError="form.errors.min_amount_peso"
/>
<Input
v-model="form.max_amount_peso"
:id="$t('concept.maximumAmountPeso')"
type="number"
step="0.01"
:onError="form.errors.max_amount_peso"
/>
</div>
<Selectable
v-model="form.unit_id"
label="name"
value="id"
:title="$t('concept.sizeUnit')"
:options="units"
required
/>
<div v-if="isFixedType">
<hr class="my-4 border-gray-300" />
<h4 class="text-lg font-semibold mb-4 text-gray-700">
{{ $t("concept.tabulator") }}
</h4>
<div class="mb-5 grid grid-cols-3 gap-4 py-2">
<Input
v-if="showUmaFields"
v-model="form.unit_cost_uma"
:id="$t('concept.costUnitUma')"
type="number"
step="0.01"
:onError="form.errors.unit_cost_uma"
/>
<Input
v-if="showPesoFields"
v-model="form.unit_cost_peso"
:id="$t('concept.costUnitPeso')"
type="number"
step="0.01"
:onError="form.errors.unit_cost_peso"
/>
</div>
</div>
<div class="flex justify-center mt-4">
<button
type="submit"
:disabled="form.processing"
class="w-full max-w-xs bg-primary hover:bg-primary/90 text-white font-semibold py-3 rounded-md transition-all duration-200 shadow-sm hover:shadow-md disabled:opacity-50"
>
{{ form.processing ? "Guardando..." : "Guardar" }}
</button>
</div>
</form>
</div>
</div>
</template>

View File

@ -49,7 +49,7 @@ onMounted(() => {
/>
</div>
<main class="flex h-full justify-center md:p-2">
<div class="mt-14 md:mt-0 w-full shadow-lg dark:shadow-xs md:dark:shadow-white h-[calc(100vh-4.5rem)] px-2 pb-4 md:rounded-sm overflow-y-auto overflow-x-auto transition-colors duration-300">
<div class="mt-14 md:mt-0 w-full h-[calc(100vh-4.5rem)] pb-4 md:rounded-sm overflow-y-auto overflow-x-auto bg-gray-50 transition-colors duration-300">
<slot />
</div>
</main>

View File

@ -18,7 +18,7 @@ const props = defineProps({
/** Métodos */
const home = () => {
if(hasToken()) {
router.push({ name: 'dashboard.index' });
router.push({ name: 'address.index' });
} else {
location.replace('/');
}

View File

@ -1,32 +1,19 @@
<script setup>
import { RouterLink } from 'vue-router';
import IconButton from '@Holos/Button/Icon.vue'
defineProps({
title: String
});
</script>
<template>
<div v-if="title" class="flex w-full justify-center">
<h2
class="font-bold text-xl uppercase"
<div v-if="title" class="flex w-full justify-center py-4">
<h1
class="font-bold text-2xl tracking-wide"
v-text="title"
/>
</div>
<div class="flex w-full justify-end py-[0.31rem] mb-2 border-y-2 border-page-t dark:border-page-dt">
<div v-if="$slots.default" class="flex w-full justify-end py-2 mb-3">
<div id="buttons" class="flex items-center space-x-1 text-sm">
<slot />
<RouterLink :to="$view({ name: 'index' })">
<IconButton
:title="$t('home')"
class="text-white"
icon="home"
filled
/>
</RouterLink>
</div>
</div>
</template>

View File

@ -69,14 +69,6 @@ const clear = () => {
</div>
<div class="flex items-center space-x-1 text-sm" id="buttons">
<slot />
<RouterLink :to="$view({name:'index'})">
<IconButton
:title="$t('home')"
class="text-white"
icon="home"
filled
/>
</RouterLink>
</div>
</div>
</template>

View File

@ -66,22 +66,6 @@ const loader = useLoader()
/>
<span class="text-xs">{{ notifier.counter }}</span>
</li>
<li v-if="darkMode.isDark">
<GoogleIcon
class="text-xl mt-1"
name="light_mode"
:title="$t('notifications.title')"
@click="darkMode.applyLight()"
/>
</li>
<li v-else>
<GoogleIcon
class="text-xl mt-1"
name="dark_mode"
:title="$t('notifications.title')"
@click="darkMode.applyDark()"
/>
</li>
<li>
<div class="relative">
<Dropdown align="right" width="48">

View File

@ -18,10 +18,10 @@ const props = defineProps({
const classes = computed(() => {
let status = props.to === vroute.name
? 'bg-secondary/30 dark:bg-secondary-d/30 border-secondary dark:border-secondary-d'
? 'bg-white/20 dark:bg-white/20 border-white dark:border-white font-semibold'
: 'border-transparent';
return `flex items-center h-11 focus:outline-hidden hover:bg-secondary/30 dark:hover:bg-secondary-d/30 border-l-4 hover:border-secondary dark:hover:border-secondary-d pr-6 ${status} transition`
return `flex items-center h-11 focus:outline-hidden hover:bg-white/10 dark:hover:bg-white/10 border-l-4 hover:border-white/50 dark:hover:border-white/50 pr-6 ${status} transition-all duration-200`
});
const closeSidebar = () => {

View File

@ -16,15 +16,15 @@ const props = defineProps({
<template>
<section class="pb-2">
<div class="w-full overflow-hidden rounded-sm shadow-lg dark:shadow-xs dark:shadow-white">
<div class="w-full overflow-hidden">
<div class="w-full overflow-x-auto">
<table v-if="!processing" class="w-full">
<table v-if="!processing" class="w-full bg-white">
<thead class="bg-primary text-primary-t dark:bg-primary-d dark:text-primary-dt">
<tr>
<slot name="head" />
</tr>
</thead>
<tbody>
<tbody class="bg-white divide-y divide-gray-200">
<template v-if="items?.total > 0">
<slot
name="body"

View File

@ -56,15 +56,15 @@
}
.table-row {
@apply hover:bg-secondary/10 dark:hover:bg-secondary-d/10 transition-colors duration-100
@apply hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors duration-150
}
.table-cell {
@apply px-2 py-0.5 text-sm border border-primary/30 dark:border-primary-dt/30;
@apply px-6 py-4 text-sm;
}
.table-actions {
@apply flex justify-center items-center space-x-1;
@apply flex justify-center items-center space-x-2;
}
nav a.router-link-active {

View File

@ -29,11 +29,6 @@ onMounted(() => {
<template #leftSidebar>
<Section name="Principal">
<Link
icon="monitoring"
name="dashboard"
to="dashboard.index"
/>
<Link
icon="add_home"
name="Gestionar Direcciones"

View File

@ -56,29 +56,27 @@ onMounted(() => {
@click="searcher.search()"
/>
</SearcherHead>
<div class="pt-2 space-y-2 w-full">
<p class="text-sm">
<div class="pt-2 space-y-2 w-full px-4">
<p class="text-sm text-gray-600">
{{ transl('description') }}
</p>
<Table
:items="models"
@send-pagination="(page) => searcher.pagination(page)"
:processing="searcher.processing"
>
<template #head>
<th v-text="$t('name')" />
<th
v-text="$t('actions')"
class="w-32 text-center"
/>
</template>
<template #body="{items}">
<tr v-for="model in items" class="table-row">
<td class="table-cell border">
{{ model.description }}
</td>
<td class="table-cell">
<div class="table-actions">
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<Table
:items="models"
@send-pagination="(page) => searcher.pagination(page)"
:processing="searcher.processing"
>
<template #head>
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="$t('name')" />
<th class="px-6 py-3 text-center text-sm font-semibold w-32" v-text="$t('actions')" />
</template>
<template #body="{items}">
<tr v-for="model in items" class="border-b border-gray-200 hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.description }}
</td>
<td class="px-6 py-4">
<div class="flex justify-center items-center space-x-2">
<IconButton
v-if="can('edit') && ![1,2].includes(model.id)"
icon="license"
@ -108,7 +106,8 @@ onMounted(() => {
</td>
</tr>
</template>
</Table>
</Table>
</div>
</div>
<Permissions

View File

@ -58,51 +58,49 @@ onMounted(() => {
@click="searcher.search()"
/>
</SearcherHead>
<div class="pt-2 w-full">
<Table
:items="models"
:processing="searcher.processing"
@send-pagination="(page) => searcher.pagination(page)"
>
<template #head>
<th v-text="$t('user')" />
<th v-text="$t('contact')" />
<th
v-text="$t('actions')"
class="w-32 text-center"
/>
</template>
<template #body="{items}">
<tr
v-for="model in items"
class="table-row"
>
<td class="table-cell">
{{ `${model.name} ${model.paternal}` }}
</td>
<td class="table-cell">
<p>
<a
class="hover:underline"
target="_blank"
:href="`mailto:${model.email}`"
>
{{ model.email }}
</a>
</p>
<p v-if="model.phone" class="font-semibold text-xs">
<b>Teléfono: </b>
<span
class="hover:underline"
target="_blank"
:href="`tel:${model.phone}`"
>
{{ model.phone }}
</span>
</p>
</td>
<td class="table-cell">
<div class="table-actions">
<div class="pt-2 w-full px-4">
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<Table
:items="models"
:processing="searcher.processing"
@send-pagination="(page) => searcher.pagination(page)"
>
<template #head>
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="$t('user')" />
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="$t('contact')" />
<th class="px-6 py-3 text-center text-sm font-semibold w-32" v-text="$t('actions')" />
</template>
<template #body="{items}">
<tr
v-for="model in items"
class="border-b border-gray-200 hover:bg-gray-50 transition-colors"
>
<td class="px-6 py-4 text-sm text-gray-700">
{{ `${model.name} ${model.paternal}` }}
</td>
<td class="px-6 py-4 text-sm text-gray-700">
<p>
<a
class="hover:underline"
target="_blank"
:href="`mailto:${model.email}`"
>
{{ model.email }}
</a>
</p>
<p v-if="model.phone" class="font-semibold text-xs">
<b>Teléfono: </b>
<span
class="hover:underline"
target="_blank"
:href="`tel:${model.phone}`"
>
{{ model.phone }}
</span>
</p>
</td>
<td class="px-6 py-4">
<div class="flex justify-center items-center space-x-2">
<IconButton
icon="visibility"
:title="$t('crud.show')"
@ -152,17 +150,12 @@ onMounted(() => {
</tr>
</template>
<template #empty>
<td class="table-cell">
<div class="flex items-center text-sm">
<p class="font-semibold">
{{ $t('registers.empty') }}
</p>
</div>
<td colspan="3" class="px-6 py-8 text-center text-gray-500 text-sm">
{{ $t('registers.empty') }}
</td>
<td class="table-cell">-</td>
<td class="table-cell">-</td>
</template>
</Table>
</Table>
</div>
</div>
<ShowView

View File

@ -73,47 +73,49 @@ const handleAddressUpdated = async () => {
</script>
<template>
<PageHeader :title="transl('title')" />
<PageHeader title="DIRECCIONES" />
<AddressForm @address-created="handleAddressCreated" />
<div class="m-3">
<Table
:items="models"
:processing="searcher.processing"
@send-pagination="(page) => searcher.pagination(page)"
>
<template #head>
<th v-text="$t('name')" />
<th v-text="$t('actions')" class="w-32 text-center" />
</template>
<template #body="{ items }">
<tr v-for="model in items" :key="model.id" class="table-row">
<td class="table-cell border">
{{ model.name }}
<div class="mx-4 mb-4">
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<Table
:items="models"
:processing="searcher.processing"
@send-pagination="(page) => searcher.pagination(page)"
>
<template #head>
<th class="px-6 py-3 text-left text-sm font-semibold">Nombre</th>
<th class="px-6 py-3 text-center text-sm font-semibold w-32">Acciones</th>
</template>
<template #body="{ items }">
<tr v-for="model in items" :key="model.id" class="border-b border-gray-200 hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.name }}
</td>
<td class="px-6 py-4">
<div class="flex justify-center items-center space-x-2">
<IconButton
icon="edit"
title="Editar"
@click="Modal.switchEditModal(model)"
outline
/>
<IconButton
icon="delete"
title="Eliminar"
@click="Modal.switchDestroyModal(model)"
outline
/>
</div>
</td>
</tr>
</template>
<template #empty>
<td colspan="2" class="px-6 py-8 text-center text-gray-500 text-sm">
{{ transl('list.empty') }}
</td>
<td class="table-cell">
<div class="table-actions">
<IconButton
icon="edit"
:title="$t('crud.edit')"
@click="Modal.switchEditModal(model)"
outline
/>
<IconButton
icon="delete"
:title="$t('crud.destroy')"
@click="Modal.switchDestroyModal(model)"
outline
/>
</div>
</td>
</tr>
</template>
<template #empty>
<td colspan="2" class="table-cell text-center py-4 text-gray-500">
{{ transl('list.empty') }}
</td>
</template>
</Table>
</template>
</Table>
</div>
<DestroyView
title="name"
subtitle=""

View File

@ -76,65 +76,67 @@ const handleConceptUpdated = () => {
<template>
<PageHeader :title="transl('title')" />
<ConceptForm @concept-created="handleConceptCreated" />
<div class="m-3">
<Table
:items="models"
:processing="searcher.processing"
@send-pagination="(page) => searcher.pagination(page)"
>
<template #head>
<th v-text="transl('direction')" />
<th v-text="transl('shortName')" />
<th v-text="transl('name')" />
<th v-text="transl('legal')" />
<th v-text="transl('article')" />
<th v-text="transl('description')" />
<th v-text="$t('actions')" class="w-32 text-center" />
</template>
<template #body="{ items }">
<tr v-for="model in items" :key="model.id" class="table-row">
<td class="table-cell border">
{{ model.direction?.name || "-" }}
<div class="mx-4 mb-4">
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<Table
:items="models"
:processing="searcher.processing"
@send-pagination="(page) => searcher.pagination(page)"
>
<template #head>
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="transl('direction')" />
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="transl('shortName')" />
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="transl('name')" />
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="transl('legal')" />
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="transl('article')" />
<th class="px-6 py-3 text-left text-sm font-semibold" v-text="transl('description')" />
<th class="px-6 py-3 text-center text-sm font-semibold w-32" v-text="$t('actions')" />
</template>
<template #body="{ items }">
<tr v-for="model in items" :key="model.id" class="border-b border-gray-200 hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.direction?.name || "-" }}
</td>
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.short_name }}
</td>
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.name }}
</td>
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.legal_instrument }}
</td>
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.article }}
</td>
<td class="px-6 py-4 text-sm text-gray-700">
{{ model.content }}
</td>
<td class="px-6 py-4">
<div class="flex justify-center items-center space-x-2">
<IconButton
icon="edit"
title="Editar"
@click="Modal.switchEditModal(model)"
outline
/>
<IconButton
icon="delete"
title="Eliminar"
@click="Modal.switchDestroyModal(model)"
outline
/>
</div>
</td>
</tr>
</template>
<template #empty>
<td colspan="7" class="px-6 py-8 text-center text-gray-500 text-sm">
{{ transl("list.empty") }}
</td>
<td class="table-cell border">
{{ model.short_name }}
</td>
<td class="table-cell border">
{{ model.name }}
</td>
<td class="table-cell border">
{{ model.legal_instrument }}
</td>
<td class="table-cell border">
{{ model.article }}
</td>
<td class="table-cell border">
{{ model.content }}
</td>
<td class="table-cell">
<div class="table-actions">
<IconButton
icon="edit"
:title="$t('crud.edit')"
@click="Modal.switchEditModal(model)"
outline
/>
<IconButton
icon="delete"
:title="$t('crud.destroy')"
@click="Modal.switchDestroyModal(model)"
outline
/>
</div>
</td>
</tr>
</template>
<template #empty>
<td colspan="7" class="table-cell text-center py-4 text-gray-500">
{{ transl("list.empty") }}
</td>
</template>
</Table>
</template>
</Table>
</div>
<DestroyView
title="name"
subtitle="content"

View File

@ -21,7 +21,7 @@ const router = createRouter({
{
path: '',
name: 'index',
redirect: '/dashboard'
redirect: '/address'
},
{
path: 'dashboard',