362 lines
10 KiB
Vue
362 lines
10 KiB
Vue
<script setup>
|
|
import { onMounted, ref, computed } 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({
|
|
direction_id: null,
|
|
unit_id: null,
|
|
short_name: "",
|
|
name: "",
|
|
legal_instrument: "",
|
|
article: "",
|
|
content: "",
|
|
min_amount_uma: "",
|
|
max_amount_uma: "",
|
|
min_amount_peso: "",
|
|
max_amount_peso: "",
|
|
unit_cost_uma: "",
|
|
unit_cost_peso: "",
|
|
charge_type: null,
|
|
concept_type: null,
|
|
});
|
|
|
|
const resetForm = () => {
|
|
form.direction_id = null;
|
|
form.unit_id = null;
|
|
form.short_name = "";
|
|
form.name = "";
|
|
form.legal_instrument = "";
|
|
form.article = "";
|
|
form.content = "";
|
|
form.min_amount_uma = "";
|
|
form.max_amount_uma = "";
|
|
form.min_amount_peso = "";
|
|
form.max_amount_peso = "";
|
|
form.unit_cost_uma = "";
|
|
form.unit_cost_peso = "";
|
|
form.charge_type = null;
|
|
form.concept_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
|
|
: form.charge_type;
|
|
});
|
|
|
|
const chargeTypesOptions = ref([
|
|
{ id: "uma_range", name: "Rango por UMA" },
|
|
{ id: "peso_range", name: "Rango en pesos (MXN$)" },
|
|
{ id: "uma_fixed", name: "Tabulador en UMA" },
|
|
{ id: "peso_fixed", name: "Tabulador en pesos (MXN$)" },
|
|
]);
|
|
|
|
const conceptTypesOptions = ref([
|
|
{ id: "membership", name: "Membresía" },
|
|
{ id: "fine", name: "Multa" }
|
|
]);
|
|
|
|
const showUmaFields = computed(() => {
|
|
return (
|
|
chargeTypeId.value === "uma_range" || chargeTypeId.value === "uma_fixed"
|
|
);
|
|
});
|
|
|
|
const showPesoFields = computed(() => {
|
|
return (
|
|
chargeTypeId.value === "peso_range" || chargeTypeId.value === "peso_fixed"
|
|
);
|
|
});
|
|
|
|
const isRangeType = computed(() => {
|
|
return (
|
|
chargeTypeId.value === "uma_range" || chargeTypeId.value === "peso_range"
|
|
);
|
|
});
|
|
|
|
const isFixedType = computed(() => {
|
|
return (
|
|
chargeTypeId.value === "uma_fixed" || chargeTypeId.value === "peso_fixed"
|
|
);
|
|
});
|
|
|
|
/** 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 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),
|
|
concept_type:
|
|
typeof form.concept_type === "object"
|
|
? form.concept_type.id
|
|
: String(form.concept_type),
|
|
short_name: form.short_name,
|
|
name: form.name,
|
|
legal_instrument: form.legal_instrument,
|
|
article: form.article,
|
|
content: form.content,
|
|
charge_type: chargeTypeId.value,
|
|
};
|
|
|
|
// 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 (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 (showUmaFields.value && isFixedType.value && form.unit_cost_uma) {
|
|
baseData.unit_cost_uma = Number(form.unit_cost_uma);
|
|
}
|
|
|
|
if (showPesoFields.value && isFixedType.value && form.unit_cost_peso) {
|
|
baseData.unit_cost_peso = Number(form.unit_cost_peso);
|
|
}
|
|
|
|
emit("concept-created", baseData);
|
|
resetForm();
|
|
isFormOpen.value = false;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<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
|
|
@click="isFormOpen = false"
|
|
class="text-gray-400 hover:text-gray-600 transition-colors"
|
|
title="Cerrar"
|
|
>
|
|
<span class="text-2xl">×</span>
|
|
</button>
|
|
</div>
|
|
|
|
<form @submit.prevent="handleSubmit">
|
|
<div class="mb-5 grid grid-cols-2 gap-4">
|
|
<Selectable
|
|
v-model="form.concept_type"
|
|
label="name"
|
|
value="id"
|
|
:title="$t('concept.conceptType')"
|
|
:options="conceptTypesOptions"
|
|
required
|
|
/>
|
|
<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
|
|
/>
|
|
<Input
|
|
v-model="form.name"
|
|
class="col-span-2"
|
|
:id="$t('concept.name')"
|
|
type="text"
|
|
:onError="form.errors.name"
|
|
required
|
|
/>
|
|
</div>
|
|
<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="">
|
|
<hr class="my-6 border-gray-300" />
|
|
<h4 class="text-lg font-semibold mb-4 text-gray-700">
|
|
{{ $t("concept.defineChargeType") }}
|
|
</h4>
|
|
<div class="mb-5 grid grid-cols-3 gap-4 py-2">
|
|
<Selectable
|
|
v-model="form.charge_type"
|
|
label="name"
|
|
value="id"
|
|
:title="$t('concept.chargeType')"
|
|
:options="chargeTypesOptions"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="showUmaFields && isRangeType"
|
|
class="mb-5 grid grid-cols-3 gap-4 py-2"
|
|
>
|
|
<Selectable
|
|
v-model="form.unit_id"
|
|
label="name"
|
|
value="id"
|
|
:title="$t('concept.sizeUnit')"
|
|
:options="units"
|
|
required
|
|
/>
|
|
<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-3 gap-4 py-2"
|
|
>
|
|
<Selectable
|
|
v-model="form.unit_id"
|
|
label="name"
|
|
value="id"
|
|
:title="$t('concept.sizeUnit')"
|
|
:options="units"
|
|
required
|
|
/>
|
|
<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>
|
|
<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">
|
|
<Selectable
|
|
v-model="form.unit_id"
|
|
label="name"
|
|
value="id"
|
|
:title="$t('concept.sizeUnit')"
|
|
:options="units"
|
|
required
|
|
/>
|
|
<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>
|