ADD: Mejora en la gestión de direcciones y conceptos, incluyendo validaciones y traducciones
This commit is contained in:
parent
740f7f5b78
commit
7f82f57588
@ -11,7 +11,5 @@ COPY . .
|
||||
COPY install.sh /usr/local/bin/install.sh
|
||||
RUN chmod +x /usr/local/bin/install.sh
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/install.sh"]
|
||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||
@ -10,15 +10,15 @@ const addressName = ref("");
|
||||
/** Métodos */
|
||||
const handleSubmit = () => {
|
||||
if (!addressName.value.trim()) {
|
||||
alert("Por favor ingresa un nombre de dirección");
|
||||
window.Notify.warning(window.Lang('address.validation.required'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Emitir evento al padre con la nueva dirección
|
||||
emit('address-created', {
|
||||
name: addressName.value
|
||||
});
|
||||
|
||||
|
||||
// Limpiar el formulario
|
||||
addressName.value = "";
|
||||
};
|
||||
@ -27,7 +27,7 @@ const handleSubmit = () => {
|
||||
<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">
|
||||
Crear nueva dirección
|
||||
{{ $t('address.create.title') }}
|
||||
</h3>
|
||||
|
||||
<form @submit.prevent="handleSubmit">
|
||||
@ -36,12 +36,13 @@ const handleSubmit = () => {
|
||||
for="addressName"
|
||||
class="block text-sm text-gray-600 font-medium mb-2"
|
||||
>
|
||||
Nombre de la Dirección:
|
||||
{{ $t('address.name') }}:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="adddressName"
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
@ -50,7 +51,7 @@ const handleSubmit = () => {
|
||||
type="submit"
|
||||
class="w-1/4 bg-[#7a0b3a] hover:bg-[#68082e] text-white font-medium py-3.5 rounded-lg transition-colors"
|
||||
>
|
||||
Guardar
|
||||
{{ $t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -1,136 +1,194 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { useForm } from "@Services/Api";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useForm, api, apiURL } from "@Services/Api";
|
||||
|
||||
import Input from "@Holos/Form/Input.vue";
|
||||
import Textarea from "@Holos/Form/Textarea.vue";
|
||||
import Selectable from "@Holos/Form/Selectable.vue";
|
||||
|
||||
/** Eventos */
|
||||
const emit = defineEmits(['concept-created']);
|
||||
|
||||
const form = useForm({
|
||||
address: [],
|
||||
shortName: "",
|
||||
direction_id: null,
|
||||
unit_id: null,
|
||||
short_name: "",
|
||||
name: "",
|
||||
legal: "",
|
||||
legal_instrument: "",
|
||||
article: "",
|
||||
description: "",
|
||||
minimumAmount: "",
|
||||
maximumAmount: "",
|
||||
sizeUnit: [],
|
||||
content: "",
|
||||
min_amount_uma: "",
|
||||
max_amount_uma: "",
|
||||
min_amount_peso: "",
|
||||
max_amount_peso: "",
|
||||
unit_cost_uma: "",
|
||||
unit_cost_peso: "",
|
||||
});
|
||||
|
||||
const addresses = ref([]);
|
||||
const sizeUnit = ref([]);
|
||||
const units = ref([]);
|
||||
|
||||
/** Cargar cosas */
|
||||
onMounted(async () => {
|
||||
api.get(apiURL('directions'), {
|
||||
onSuccess: (data) => {
|
||||
addresses.value = data.models?.data || data.data || [];
|
||||
}
|
||||
});
|
||||
|
||||
api.get(apiURL('units'), {
|
||||
onSuccess: (data) => {
|
||||
units.value = data.models?.data || data.data || [];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/** Métodos */
|
||||
const handleSubmit = () => {
|
||||
const transformedData = {
|
||||
direction_id: typeof modelModal.value.direction === 'object' ? modelModal.value.direction.id : Number(modelModal.value.direction_id),
|
||||
unit_id: modelModal.value.unit ? (typeof modelModal.value.unit === 'object' ? modelModal.value.unit.id : Number(modelModal.value.unit)) : null,
|
||||
short_name: modelModal.value.short_name,
|
||||
name: modelModal.value.name,
|
||||
legal_instrument: modelModal.value.legal_instrument,
|
||||
article: modelModal.value.article,
|
||||
content: modelModal.value.content,
|
||||
min_amount_uma: modelModal.value.min_amount_uma ? Number(modelModal.value.min_amount_uma) : null,
|
||||
max_amount_uma: modelModal.value.max_amount_uma ? Number(modelModal.value.max_amount_uma) : null,
|
||||
min_amount_peso: modelModal.value.min_amount_peso ? Number(modelModal.value.min_amount_peso) : null,
|
||||
max_amount_peso: modelModal.value.max_amount_peso ? Number(modelModal.value.max_amount_peso) : null,
|
||||
unit_cost_uma: form.unit_cost_uma ? Number(form.unit_cost_uma) : null,
|
||||
unit_cost_peso: form.unit_cost_peso ? Number(form.unit_cost_peso) : null,
|
||||
};
|
||||
|
||||
emit('concept-created', transformedData);
|
||||
};
|
||||
</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">
|
||||
Crear nuevo concepto de cobro
|
||||
{{ $t('concept.create.title') }}
|
||||
</h3>
|
||||
|
||||
<form>
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="mb-5 grid grid-cols-2 gap-4">
|
||||
<Selectable
|
||||
v-model="form.address"
|
||||
label="description"
|
||||
title="Direcciones"
|
||||
v-model="form.direction"
|
||||
label="name"
|
||||
value="id"
|
||||
:title="$t('concept.direction')"
|
||||
:options="addresses"
|
||||
multiple
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
v-model="form.shortName"
|
||||
v-model="form.short_name"
|
||||
class="col-span-2"
|
||||
id="Nombre corto"
|
||||
:id="$t('concept.shortName')"
|
||||
type="text"
|
||||
:onError="form.errors.shortName"
|
||||
:onError="form.errors.short_name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
v-model="form.name"
|
||||
class="col-span-2"
|
||||
id="Nombre"
|
||||
: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"
|
||||
v-model="form.legal_instrument"
|
||||
class="col-span-2"
|
||||
id="Instrumento Legal"
|
||||
:id="$t('concept.legal')"
|
||||
type="text"
|
||||
:onError="form.errors.legal"
|
||||
:onError="form.errors.legal_instrument"
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
v-model="form.article"
|
||||
class="col-span-2"
|
||||
id="Articulado"
|
||||
:id="$t('concept.article')"
|
||||
type="text"
|
||||
:onError="form.errors.article"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Textarea
|
||||
v-model="form.description"
|
||||
v-model="form.content"
|
||||
class="col-span-2"
|
||||
id="Descripción"
|
||||
:onError="form.errors.description"
|
||||
:id="$t('concept.description')"
|
||||
:onError="form.errors.content"
|
||||
required
|
||||
/>
|
||||
<div class="mb-5 grid grid-cols-2 gap-4 py-2">
|
||||
<Input
|
||||
v-model="form.minimumAmount"
|
||||
class="col-span-2"
|
||||
id="Monto mínimo (UMAs)"
|
||||
type="text"
|
||||
:onError="form.errors.minimumAmount"
|
||||
required
|
||||
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.maximumAmount"
|
||||
class="col-span-2"
|
||||
id="Monto máximo (UMAs)"
|
||||
type="text"
|
||||
:onError="form.errors.maximumAmount"
|
||||
required
|
||||
v-model="form.max_amount_uma"
|
||||
:id="$t('concept.maximumAmountUma')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
:onError="form.errors.max_amount_uma"
|
||||
/>
|
||||
</div>
|
||||
<div 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>
|
||||
<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">
|
||||
<Selectable
|
||||
v-model="form.sizeUnit"
|
||||
label="description"
|
||||
title="Unidad de medida"
|
||||
:options="sizeUnit"
|
||||
multiple
|
||||
required
|
||||
v-model="form.unit"
|
||||
label="name"
|
||||
value="id"
|
||||
:title="$t('concept.sizeUnit')"
|
||||
:options="units"
|
||||
/>
|
||||
<Input
|
||||
v-model="form.costMin"
|
||||
class="col-span-2"
|
||||
id="Costo mínimo (UMAs)"
|
||||
type="text"
|
||||
:onError="form.errors.costMin"
|
||||
required
|
||||
v-model="form.unit_cost_uma"
|
||||
:id="$t('concept.costUnitUma')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
:onError="form.errors.unit_cost_uma"
|
||||
/>
|
||||
<Input
|
||||
v-model="form.costMax"
|
||||
class="col-span-2"
|
||||
id="Costo máximo (UMAs)"
|
||||
type="text"
|
||||
:onError="form.errors.costMax"
|
||||
required
|
||||
/>
|
||||
v-model="form.unit_cost_peso"
|
||||
:id="$t('concept.costUnitPeso')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
:onError="form.errors.unit_cost_peso"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3 p-7 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"
|
||||
: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"
|
||||
>
|
||||
Guardar
|
||||
{{ form.processing ? 'Guardando...' : $t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -82,8 +82,13 @@ export default {
|
||||
},
|
||||
address: {
|
||||
title: 'Direcciones',
|
||||
name: 'Nombre de la Dirección',
|
||||
placeholder: 'Ingrese el nombre de la dirección',
|
||||
validation: {
|
||||
required: 'Por favor ingresa un nombre de dirección'
|
||||
},
|
||||
create: {
|
||||
title: 'Crear dirección',
|
||||
title: 'Crear nueva dirección',
|
||||
description: 'Permite crear nuevas direcciones.',
|
||||
onSuccess: 'Dirección creada exitosamente',
|
||||
onError: 'Error al crear la dirección'
|
||||
@ -94,11 +99,55 @@ export default {
|
||||
onSuccess: 'Dirección actualizada exitosamente',
|
||||
onError: 'Error al actualizar la dirección'
|
||||
},
|
||||
list: {
|
||||
title: 'Listado de Direcciones',
|
||||
empty: 'No hay direcciones registradas'
|
||||
},
|
||||
deleted: 'Dirección eliminada',
|
||||
permissions: {
|
||||
title: 'Permisos de dirección'
|
||||
}
|
||||
},
|
||||
concept: {
|
||||
title: 'Conceptos de Cobro',
|
||||
direction: 'Dirección',
|
||||
shortName: 'Nombre Corto',
|
||||
name: 'Nombre',
|
||||
legal: 'Instrumento Legal',
|
||||
article: 'Articulado',
|
||||
description: 'Contenido',
|
||||
minimumAmountUma: 'Monto Mínimo (UMAs)',
|
||||
maximumAmountUma: 'Monto Máximo (UMAs)',
|
||||
minimumAmountPeso: 'Monto Mínimo (Pesos)',
|
||||
maximumAmountPeso: 'Monto Máximo (Pesos)',
|
||||
tabulator: 'Tabulador',
|
||||
sizeUnit: 'Unidad de Medida',
|
||||
costUnitUma: 'Costo Unitario (UMAs)',
|
||||
costUnitPeso: 'Costo Unitario (Pesos)',
|
||||
validation: {
|
||||
required: 'Por favor complete todos los campos requeridos'
|
||||
},
|
||||
create: {
|
||||
title: 'Nuevo Concepto de Cobro',
|
||||
description: 'Permite crear nuevos conceptos de cobro.',
|
||||
onSuccess: 'Concepto creado exitosamente',
|
||||
onError: 'Error al crear el concepto'
|
||||
},
|
||||
edit: {
|
||||
title: 'Editar concepto',
|
||||
description: 'Permite editar conceptos existentes.',
|
||||
onSuccess: 'Concepto actualizado exitosamente',
|
||||
onError: 'Error al actualizar el concepto'
|
||||
},
|
||||
list: {
|
||||
title: 'Listado de Conceptos',
|
||||
empty: 'No hay conceptos registrados'
|
||||
},
|
||||
deleted: 'Concepto eliminado',
|
||||
permissions: {
|
||||
title: 'Permisos de concepto'
|
||||
}
|
||||
},
|
||||
membership: {
|
||||
title: 'Membresías',
|
||||
create: {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useSearcher, useForm } from "@Services/Api";
|
||||
import { can, apiTo, viewTo, transl } from "./Module";
|
||||
import { apiTo, transl } from "./Module";
|
||||
|
||||
import Table from "@Holos/Table.vue";
|
||||
import IconButton from "@Holos/Button/Icon.vue";
|
||||
@ -45,8 +45,12 @@ const handleAddressCreated = async (address) => {
|
||||
|
||||
form.post(apiTo("store"), {
|
||||
onSuccess: () => {
|
||||
Notify.success(transl('create.onSuccess'));
|
||||
searcher.refresh();
|
||||
},
|
||||
onError: () => {
|
||||
Notify.error(transl('create.onError'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -55,17 +59,21 @@ const handleAddressUpdated = async () => {
|
||||
name: modelModal.value.name,
|
||||
});
|
||||
|
||||
form.put(apiTo("update", { id: modelModal.value.id }), {
|
||||
form.put(apiTo("update", { direction: modelModal.value.id }), {
|
||||
onSuccess: () => {
|
||||
Notify.success(transl('edit.onSuccess'));
|
||||
searcher.refresh();
|
||||
Modal.switchEditModal();
|
||||
},
|
||||
onError: () => {
|
||||
Notify.error(transl('edit.onError'));
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageHeader title="Creación de Dirección" />
|
||||
<PageHeader :title="transl('title')" />
|
||||
<AddressForm @address-created="handleAddressCreated" />
|
||||
<div class="m-3">
|
||||
<Table
|
||||
@ -102,7 +110,7 @@ const handleAddressUpdated = async () => {
|
||||
</template>
|
||||
<template #empty>
|
||||
<td colspan="2" class="table-cell text-center py-4 text-gray-500">
|
||||
No hay direcciones registradas
|
||||
{{ transl('list.empty') }}
|
||||
</td>
|
||||
</template>
|
||||
</Table>
|
||||
@ -111,7 +119,7 @@ const handleAddressUpdated = async () => {
|
||||
subtitle=""
|
||||
:model="modelModal"
|
||||
:show="destroyModal"
|
||||
:to="(address) => apiTo('destroy', { id: address.id })"
|
||||
:to="(id) => apiTo('destroy', { direction: id })"
|
||||
@close="Modal.switchDestroyModal"
|
||||
@update="
|
||||
() => {
|
||||
@ -125,7 +133,7 @@ const handleAddressUpdated = async () => {
|
||||
/>
|
||||
<Editview
|
||||
:show="editModal"
|
||||
:title="$t('crud.edit')"
|
||||
:title="transl('edit.title')"
|
||||
@close="Modal.switchEditModal"
|
||||
@update="handleAddressUpdated"
|
||||
>
|
||||
@ -134,12 +142,13 @@ const handleAddressUpdated = async () => {
|
||||
for="editAddressName"
|
||||
class="block text-sm text-gray-600 font-medium mb-2"
|
||||
>
|
||||
Nombre de la Dirección:
|
||||
{{ transl('name') }}:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="editAddressName"
|
||||
v-model="modelModal.name"
|
||||
:placeholder="transl('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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { RouterLink } from "vue-router";
|
||||
import { useSearcher } from "@Services/Api";
|
||||
import { can, apiTo, viewTo, transl } from "./Module";
|
||||
import { useSearcher, useForm, api, apiURL } from "@Services/Api";
|
||||
import { apiTo, transl } from "./Module";
|
||||
|
||||
import Table from "@Holos/Table.vue";
|
||||
import IconButton from "@Holos/Button/Icon.vue";
|
||||
@ -10,6 +9,10 @@ import PageHeader from "@Holos/PageHeader.vue";
|
||||
import ConceptForm from "@App/ConceptSection.vue";
|
||||
import DestroyView from "@Holos/Modal/Template/Destroy.vue";
|
||||
import ModalController from "@Controllers/ModalController.js";
|
||||
import Editview from "@Holos/Modal/Edit.vue";
|
||||
import Input from "@Holos/Form/Input.vue";
|
||||
import Textarea from "@Holos/Form/Textarea.vue";
|
||||
import Selectable from "@Holos/Form/Selectable.vue";
|
||||
|
||||
/** Controladores */
|
||||
const Modal = new ModalController();
|
||||
@ -19,67 +22,133 @@ const destroyModal = ref(Modal.destroyModal);
|
||||
const editModal = ref(Modal.editModal);
|
||||
const modelModal = ref(Modal.modelModal);
|
||||
|
||||
/** Inicializar searcher */
|
||||
//const models = ref(searcher.models);
|
||||
const addresses = ref([]);
|
||||
const units = ref([]);
|
||||
|
||||
const models = ref({
|
||||
data: [],
|
||||
total: 0,
|
||||
});
|
||||
const processing = ref(false);
|
||||
//const searcher = useSearcher(apiTo("index"));
|
||||
const searcher = {
|
||||
models,
|
||||
processing,
|
||||
pagination: () => {},
|
||||
search: () => {},
|
||||
};
|
||||
|
||||
/** Inicializar searcher */
|
||||
const searcher = useSearcher({
|
||||
url: apiTo("index"),
|
||||
filters: {},
|
||||
onSuccess: (data) => {
|
||||
models.value = data.models;
|
||||
},
|
||||
});
|
||||
|
||||
api.get(apiURL("directions"), {
|
||||
onSuccess: (data) => {
|
||||
addresses.value = data.models?.data || data.data || [];
|
||||
},
|
||||
});
|
||||
|
||||
api.get(apiURL("units"), {
|
||||
onSuccess: (data) => {
|
||||
units.value = data.models?.data || data.data || [];
|
||||
},
|
||||
});
|
||||
|
||||
/** Cargar datos iniciales */
|
||||
onMounted(() => {
|
||||
searcher.search();
|
||||
});
|
||||
|
||||
/** crear concepto */
|
||||
const handleConceptCreated = async (conceptData) => {
|
||||
const form = useForm(conceptData);
|
||||
|
||||
form.post(apiTo("store"), {
|
||||
onSuccess: () => {
|
||||
Notify.success(transl("create.onSuccess"));
|
||||
searcher.refresh();
|
||||
},
|
||||
onError: () => {
|
||||
Notify.error(transl("create.onError"));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleConceptUpdated = async () => {
|
||||
const transformedData = {
|
||||
direction_id: typeof modelModal.value.direction === 'object' ? modelModal.value.direction.id : Number(modelModal.value.direction_id),
|
||||
unit_id: modelModal.value.unit ? (typeof modelModal.value.unit === 'object' ? modelModal.value.unit.id : Number(modelModal.value.unit)) : null,
|
||||
short_name: modelModal.value.short_name,
|
||||
name: modelModal.value.name,
|
||||
legal_instrument: modelModal.value.legal_instrument,
|
||||
article: modelModal.value.article,
|
||||
content: modelModal.value.content,
|
||||
min_amount_uma: modelModal.value.min_amount_uma ? Number(modelModal.value.min_amount_uma) : null,
|
||||
max_amount_uma: modelModal.value.max_amount_uma ? Number(modelModal.value.max_amount_uma) : null,
|
||||
min_amount_peso: modelModal.value.min_amount_peso ? Number(modelModal.value.min_amount_peso) : null,
|
||||
max_amount_peso: modelModal.value.max_amount_peso ? Number(modelModal.value.max_amount_peso) : null,
|
||||
unit_cost_uma: modelModal.value.unit_cost_uma ? Number(modelModal.value.unit_cost_uma) : null,
|
||||
unit_cost_peso: modelModal.value.unit_cost_peso ? Number(modelModal.value.unit_cost_peso) : null,
|
||||
};
|
||||
|
||||
const form = useForm(transformedData);
|
||||
|
||||
form.put(apiTo("update", { charge_concept: modelModal.value.id }), {
|
||||
onSuccess: () => {
|
||||
Notify.success(transl("edit.onSuccess"));
|
||||
searcher.refresh();
|
||||
Modal.switchEditModal();
|
||||
},
|
||||
onError: () => {
|
||||
Notify.error(transl("edit.onError"));
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<PageHeader title="Creación de Concepto" />
|
||||
<ConceptForm />
|
||||
<PageHeader :title="transl('title')" />
|
||||
<ConceptForm @concept-created="handleConceptCreated" />
|
||||
<div class="m-3">
|
||||
<Table
|
||||
:items="models"
|
||||
:processing="searcher.processing.value"
|
||||
:processing="searcher.processing"
|
||||
@send-pagination="(page) => searcher.pagination(page)"
|
||||
>
|
||||
<template #head>
|
||||
<th v-text="'Dirección'" />
|
||||
<th v-text="'Nombre corto'" />
|
||||
<th v-text="'Nombre'" />
|
||||
<th v-text="'Instrumento Legal'" />
|
||||
<th v-text="'Articulado'" />
|
||||
<th v-text="'Descripción'" />
|
||||
<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.description }}
|
||||
{{ model.direction?.name || "-" }}
|
||||
</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
|
||||
v-if="can('edit') && ![1, 2].includes(model.id)"
|
||||
icon="license"
|
||||
:title="transl('permissions.title')"
|
||||
icon="edit"
|
||||
:title="$t('crud.edit')"
|
||||
@click="Modal.switchEditModal(model)"
|
||||
outline
|
||||
/>
|
||||
<RouterLink
|
||||
v-if="can('edit')"
|
||||
class="h-fit"
|
||||
:to="viewTo({ name: 'edit', params: { id: model.id } })"
|
||||
>
|
||||
<IconButton icon="edit" :title="$t('crud.edit')" outline />
|
||||
</RouterLink>
|
||||
<IconButton
|
||||
v-if="can('destroy') && ![1, 2].includes(model.id)"
|
||||
icon="delete"
|
||||
:title="$t('crud.destroy')"
|
||||
@click="Modal.switchDestroyModal(model)"
|
||||
@ -90,18 +159,17 @@ onMounted(() => {
|
||||
</tr>
|
||||
</template>
|
||||
<template #empty>
|
||||
<td colspan="2" class="table-cell text-center py-4 text-gray-500">
|
||||
No hay direcciones registradas
|
||||
<td colspan="7" class="table-cell text-center py-4 text-gray-500">
|
||||
{{ transl("list.empty") }}
|
||||
</td>
|
||||
</template>
|
||||
</Table>
|
||||
<DestroyView
|
||||
v-if="can('destroy')"
|
||||
title="description"
|
||||
subtitle=""
|
||||
title="name"
|
||||
subtitle="content"
|
||||
:model="modelModal"
|
||||
:show="destroyModal"
|
||||
:to="(address) => apiTo('destroy', { address: address.id })"
|
||||
:to="(id) => apiTo('destroy', { charge_concept: id })"
|
||||
@close="Modal.switchDestroyModal"
|
||||
@update="
|
||||
() => {
|
||||
@ -113,5 +181,104 @@ onMounted(() => {
|
||||
}
|
||||
"
|
||||
/>
|
||||
<Editview
|
||||
:show="editModal"
|
||||
:title="transl('edit.title')"
|
||||
@close="Modal.switchEditModal"
|
||||
@update="handleConceptUpdated"
|
||||
>
|
||||
<div class="p-4 space-y-4">
|
||||
<Selectable
|
||||
v-model="modelModal.direction"
|
||||
label="name"
|
||||
value="id"
|
||||
:title="$t('concept.direction')"
|
||||
:options="addresses"
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
v-model="modelModal.short_name"
|
||||
:id="$t('concept.shortName')"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
v-model="modelModal.name"
|
||||
:id="$t('concept.name')"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
v-model="modelModal.legal_instrument"
|
||||
:id="$t('concept.legal')"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
v-model="modelModal.article"
|
||||
:id="$t('concept.article')"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
<Textarea
|
||||
v-model="modelModal.content"
|
||||
:id="$t('concept.description')"
|
||||
required
|
||||
/>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<Input
|
||||
v-model="modelModal.min_amount_uma"
|
||||
:id="$t('concept.minimumAmountUma')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
/>
|
||||
<Input
|
||||
v-model="modelModal.max_amount_uma"
|
||||
:id="$t('concept.maximumAmountUma')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<Input
|
||||
v-model="modelModal.min_amount_peso"
|
||||
:id="$t('concept.minimumAmountPeso')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
/>
|
||||
<Input
|
||||
v-model="modelModal.max_amount_peso"
|
||||
:id="$t('concept.maximumAmountPeso')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
/>
|
||||
</div>
|
||||
<hr class="my-4 border-gray-300" />
|
||||
<h4 class="text-lg font-semibold mb-2 text-gray-700">
|
||||
{{ $t('concept.tabulator') }}
|
||||
</h4>
|
||||
<Selectable
|
||||
v-model="modelModal.unit"
|
||||
label="name"
|
||||
value="id"
|
||||
:title="$t('concept.sizeUnit')"
|
||||
:options="units"
|
||||
/>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<Input
|
||||
v-model="modelModal.unit_cost_uma"
|
||||
:id="$t('concept.costUnitUma')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
/>
|
||||
<Input
|
||||
v-model="modelModal.unit_cost_peso"
|
||||
:id="$t('concept.costUnitPeso')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Editview>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -2,7 +2,7 @@ import { lang } from '@Lang/i18n';
|
||||
import { hasPermission } from '@Plugins/RolePermission.js';
|
||||
|
||||
// Ruta API
|
||||
const apiTo = (name, params = {}) => route(`concept.${name}`, params)
|
||||
const apiTo = (name, params = {}) => route(`charge-concepts.${name}`, params)
|
||||
|
||||
// Ruta visual
|
||||
const viewTo = ({ name = '', params = {}, query = {} }) => view({ name: `concept.${name}`, params, query })
|
||||
|
||||
21
src/pages/App/Fine/Module.js
Normal file
21
src/pages/App/Fine/Module.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { lang } from '@Lang/i18n';
|
||||
import { hasPermission } from '@Plugins/RolePermission.js';
|
||||
|
||||
// Ruta API
|
||||
const apiTo = (name, params = {}) => route(`fines.${name}`, params)
|
||||
|
||||
// Ruta visual
|
||||
const viewTo = ({ name = '', params = {}, query = {} }) => view({ name: `fine.${name}`, params, query })
|
||||
|
||||
// Obtener traducción del componente
|
||||
const transl = (str) => lang(`fine.${str}`)
|
||||
|
||||
// Determina si un usuario puede hacer algo no en base a los permisos
|
||||
const can = (permission) => hasPermission(`fine.${permission}`)
|
||||
|
||||
export {
|
||||
can,
|
||||
viewTo,
|
||||
apiTo,
|
||||
transl
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user