FIX:Errores en creación de conceptos

This commit is contained in:
Rubi Almora 2026-03-06 11:44:15 -06:00
parent 76b1c6c02b
commit 104e2e327e
6 changed files with 203 additions and 151 deletions

View File

@ -17,6 +17,7 @@ const form = useForm({
legal_instrument: "", legal_instrument: "",
article: "", article: "",
content: "", content: "",
motivation: "",
min_amount_uma: "", min_amount_uma: "",
max_amount_uma: "", max_amount_uma: "",
min_amount_peso: "", min_amount_peso: "",
@ -35,6 +36,7 @@ const resetForm = () => {
form.legal_instrument = ""; form.legal_instrument = "";
form.article = ""; form.article = "";
form.content = ""; form.content = "";
form.motivation = "";
form.min_amount_uma = ""; form.min_amount_uma = "";
form.max_amount_uma = ""; form.max_amount_uma = "";
form.min_amount_peso = ""; form.min_amount_peso = "";
@ -91,6 +93,14 @@ const isFixedType = computed(() => {
); );
}); });
const conceptTypeId = computed(() => {
return typeof form.concept_type === "object" && form.concept_type?.id
? form.concept_type.id
: form.concept_type;
});
const isFineConcept = computed(() => conceptTypeId.value === "fine");
/** Cargar cosas */ /** Cargar cosas */
onMounted(async () => { onMounted(async () => {
api.get(apiURL("directions"), { api.get(apiURL("directions"), {
@ -114,16 +124,23 @@ const handleSubmit = () => {
? form.direction_id.id ? form.direction_id.id
: Number(form.direction_id), : Number(form.direction_id),
unit_id: unit_id:
typeof form.unit_id === "object" ? form.unit_id.id : Number(form.unit_id), form.unit_id != null
? typeof form.unit_id === "object"
? form.unit_id.id
: Number(form.unit_id)
: null,
concept_type: concept_type:
typeof form.concept_type === "object" typeof form.concept_type === "object"
? form.concept_type.id ? form.concept_type.id
: String(form.concept_type), : String(form.concept_type),
short_name: form.short_name, short_name: form.short_name,
name: form.name, name: form.name,
legal_instrument: form.legal_instrument, ...(isFineConcept.value && {
article: form.article, legal_instrument: form.legal_instrument,
content: form.content, article: form.article,
content: form.content,
motivation: form.motivation,
}),
charge_type: chargeTypeId.value, charge_type: chargeTypeId.value,
}; };
@ -218,29 +235,39 @@ const handleSubmit = () => {
required required
/> />
</div> </div>
<div class="mb-5 grid grid-cols-2 gap-4 py-2"> <template v-if="isFineConcept">
<Input <div class="mb-5 grid grid-cols-2 gap-4 py-2">
v-model="form.legal_instrument" <Input
class="col-span-2" v-model="form.legal_instrument"
:id="$t('concept.legal')" class="col-span-2"
type="text" :id="$t('concept.legal')"
:onError="form.errors.legal_instrument" type="text"
/> :onError="form.errors.legal_instrument"
<Input />
v-model="form.article" <Input
class="col-span-2" v-model="form.article"
:id="$t('concept.article')" class="col-span-2"
type="text" :id="$t('concept.article')"
:onError="form.errors.article" type="text"
/> :onError="form.errors.article"
</div> />
<Textarea </div>
v-model="form.content" <div class="mb-5 gap-4">
class="col-span-2" <Textarea
:id="$t('concept.description')" v-model="form.content"
:onError="form.errors.content" :id="$t('concept.description')"
required :onError="form.errors.content"
/> />
</div>
<div class="mb-5 gap-4 py-2">
<Input
v-model="form.motivation"
:id="$t('concept.motivation')"
type="text"
:onError="form.errors.motivation"
/>
</div>
</template>
<div class=""> <div class="">
<hr class="my-6 border-gray-300" /> <hr class="my-6 border-gray-300" />

View File

@ -0,0 +1,31 @@
<script setup>
import SingleFile from '@Holos/Form/SingleFile.vue';
import Error from '@Holos/Form/Elements/Error.vue';
defineProps({
modelValue: [Object, File, String],
required: Boolean,
title: { type: String, default: '' },
onError: [String, Array],
accept: { type: String, default: 'image/png, image/jpeg' },
});
const emit = defineEmits(['update:modelValue']);
</script>
<template>
<div class="flex flex-col">
<SingleFile
:model-value="modelValue"
:title="title"
:required="required"
:accept="accept"
@update:model-value="emit('update:modelValue', $event)"
>
<template #previous>
<slot name="previous" />
</template>
</SingleFile>
<Error :onError="onError" />
</div>
</template>

View File

@ -114,6 +114,7 @@ export default {
shortName: 'Nombre Corto', shortName: 'Nombre Corto',
name: 'Nombre', name: 'Nombre',
legal: 'Instrumento Legal', legal: 'Instrumento Legal',
motivation: 'Motivación',
article: 'Articulado', article: 'Articulado',
description: 'Contenido', description: 'Contenido',
chargeType: 'Tipo de Cobro', chargeType: 'Tipo de Cobro',
@ -153,6 +154,10 @@ export default {
}, },
membership: { membership: {
title: 'Membresías', title: 'Membresías',
curp: 'CURP',
name: 'Nombre',
tutor: 'Tutor',
photo: 'Foto',
create: { create: {
title: 'Crear membresía', title: 'Crear membresía',
description: 'Permite crear nuevas membresías.', description: 'Permite crear nuevas membresías.',

View File

@ -89,13 +89,16 @@ const editIsFixedType = computed(() => {
const handleUpdate = async () => { const handleUpdate = async () => {
const transformedData = { const transformedData = {
direction_id: typeof props.model.direction === 'object' ? props.model.direction.id : Number(props.model.direction_id), direction_id: typeof props.model.direction === 'object' ? props.model.direction.id : Number(props.model.direction_id),
unit_id: props.model.unit ? (typeof props.model.unit === 'object' ? props.model.unit.id : Number(props.model.unit)) : null, unit_id: editIsFixedType.value && props.model.unit
? (typeof props.model.unit === 'object' ? props.model.unit.id : Number(props.model.unit))
: null,
short_name: props.model.short_name, short_name: props.model.short_name,
concept_type: props.model.concept_type, concept_type: props.model.concept_type,
name: props.model.name, name: props.model.name,
legal_instrument: props.model.legal_instrument, legal_instrument: props.model.legal_instrument,
article: props.model.article, article: props.model.article,
content: props.model.content, content: props.model.content,
motivation: props.model.motivation,
charge_type: editChargeTypeId.value, charge_type: editChargeTypeId.value,
// Campos UMA para tipos de rango // Campos UMA para tipos de rango
min_amount_uma: (editShowUmaFields.value && editIsRangeType.value && props.model.min_amount_uma) ? Number(props.model.min_amount_uma) : null, min_amount_uma: (editShowUmaFields.value && editIsRangeType.value && props.model.min_amount_uma) ? Number(props.model.min_amount_uma) : null,
@ -161,20 +164,20 @@ const handleUpdate = async () => {
v-model="model.legal_instrument" v-model="model.legal_instrument"
:id="$t('concept.legal')" :id="$t('concept.legal')"
type="text" type="text"
required
/> />
<Input <Input
v-model="model.article" v-model="model.article"
:id="$t('concept.article')" :id="$t('concept.article')"
type="text" type="text"
required
/> />
<Textarea <Textarea
v-model="model.content" v-model="model.content"
:id="$t('concept.description')" :id="$t('concept.description')"
required
/> />
<Textarea
v-model="model.motivation"
:id="$t('concept.motivation')"
/>
<!-- Selector de tipo de cargo --> <!-- Selector de tipo de cargo -->
<Selectable <Selectable
v-model="chargeTypeObject" v-model="chargeTypeObject"
@ -184,8 +187,10 @@ const handleUpdate = async () => {
required required
/> />
<div v-if="editShowUmaFields && editIsRangeType" class="grid grid-cols-2 gap-4"> <!-- Rango: solo monto mínimo y monto máximo (UMA o pesos) -->
<div v-if="editIsRangeType" class="grid grid-cols-2 gap-4">
<Input <Input
v-if="editShowUmaFields"
v-model="model.min_amount_uma" v-model="model.min_amount_uma"
:id="$t('concept.minimumAmountUma')" :id="$t('concept.minimumAmountUma')"
type="number" type="number"
@ -193,16 +198,15 @@ const handleUpdate = async () => {
required required
/> />
<Input <Input
v-if="editShowUmaFields"
v-model="model.max_amount_uma" v-model="model.max_amount_uma"
:id="$t('concept.maximumAmountUma')" :id="$t('concept.maximumAmountUma')"
type="number" type="number"
step="0.01" step="0.01"
required required
/> />
</div>
<div v-if="editShowPesoFields && editIsRangeType" class="grid grid-cols-2 gap-4">
<Input <Input
v-if="editShowPesoFields"
v-model="model.min_amount_peso" v-model="model.min_amount_peso"
:id="$t('concept.minimumAmountPeso')" :id="$t('concept.minimumAmountPeso')"
type="number" type="number"
@ -210,6 +214,7 @@ const handleUpdate = async () => {
required required
/> />
<Input <Input
v-if="editShowPesoFields"
v-model="model.max_amount_peso" v-model="model.max_amount_peso"
:id="$t('concept.maximumAmountPeso')" :id="$t('concept.maximumAmountPeso')"
type="number" type="number"
@ -218,39 +223,32 @@ const handleUpdate = async () => {
/> />
</div> </div>
<Selectable <!-- Tabulador: unidad de medida y costo por unidad (UMA o pesos) -->
v-model="model.unit" <div v-if="editIsFixedType" class="grid grid-cols-2 gap-4">
label="name" <Selectable
value="id" v-model="model.unit"
:title="$t('concept.sizeUnit')" label="name"
:options="units" value="id"
required :title="$t('concept.sizeUnit')"
/> :options="units"
required
<div v-if="editIsFixedType"> />
<hr class="my-4 border-gray-300" /> <Input
<h4 class="text-lg font-semibold mb-2 text-gray-700"> v-if="editShowUmaFields"
{{ $t('concept.tabulator') }} v-model="model.unit_cost_uma"
</h4> :id="$t('concept.costUnitUma')"
<div class="grid grid-cols-2 gap-4"> type="number"
<Input step="0.01"
v-if="editShowUmaFields" required
v-model="model.unit_cost_uma" />
:id="$t('concept.costUnitUma')" <Input
type="number" v-if="editShowPesoFields"
step="0.01" v-model="model.unit_cost_peso"
required :id="$t('concept.costUnitPeso')"
/> type="number"
step="0.01"
<Input required
v-if="editShowPesoFields" />
v-model="model.unit_cost_peso"
:id="$t('concept.costUnitPeso')"
type="number"
step="0.01"
required
/>
</div>
</div> </div>
</div> </div>
</Editview> </Editview>

View File

@ -1,47 +1,31 @@
<script setup> <script setup>
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { api, useForm } from '@Services/Api'; import { useForm } from '@Services/Api';
import { apiTo, transl, viewTo } from './Module'; import { apiTo, transl, viewTo } from './Module';
import IconButton from '@Holos/Button/Icon.vue' import IconButton from '@Holos/Button/Icon.vue';
import Input from '@Holos/Form/Input.vue'; import PageHeader from '@Holos/PageHeader.vue';
import Selectable from '@Holos/Form/Selectable.vue'; import Form from './Form.vue';
import PageHeader from '@Holos/PageHeader.vue';
import Form from './Form.vue'
/** Definidores */
const router = useRouter(); const router = useRouter();
/** Propiedades */
const form = useForm({ const form = useForm({
name: '', curp: '',
paternal: '', name: '',
maternal: '', tutor: '',
curp: '', photo: null,
membership_number: '',
}); });
/** Métodos */
function submit() { function submit() {
form.transform(data => ({ form
...data, .transform((data) => ({ ...data }))
})).post(apiTo('store'), { .post(route('members.store'), {
onSuccess: () => { onSuccess: () => {
Notify.success(Lang('register.create.onSuccess')) Notify.success(transl('create.onSuccess'));
router.push(viewTo({ name: 'index' })); router.push(viewTo({ name: 'index' }));
} },
})
}
/** Ciclos */
onMounted(() => {
api.get(route('system.roles'), {
onSuccess: (r) => {
roles.value = r.roles;
}
}); });
}) }
</script> </script>
<template> <template>

View File

@ -2,66 +2,73 @@
import { transl } from './Module'; import { transl } from './Module';
import PrimaryButton from '@Holos/Button/Primary.vue'; import PrimaryButton from '@Holos/Button/Primary.vue';
import Input from '@Holos/Form/Input.vue'; import Input from '@Holos/Form/Input.vue';
import PhotoUpload from '@App/PhotoUpload.vue';
/** Eventos */ /** Eventos */
const emit = defineEmits([ const emit = defineEmits(['submit']);
'submit'
])
/** Propiedades */ /** Propiedades */
defineProps({ defineProps({
action: { action: {
default: 'create', default: 'create',
type: String type: String,
}, },
form: Object form: Object,
}) });
/** Métodos */ /** Métodos */
function submit() { function submit() {
emit('submit') emit('submit');
} }
</script> </script>
<template> <template>
<div class="w-full pb-2"> <div class="w-full pb-2">
<p class="text-justify text-sm" v-text="transl(`${action}.description`)" /> <p class="text-justify text-sm" v-text="transl(`${action}.description`)" />
</div> </div>
<div class="w-full"> <div class="w-full">
<form @submit.prevent="submit" class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <form
<Input @submit.prevent="submit"
v-model="form.name" class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
id="name" >
:onError="form.errors.name" <Input
autofocus v-model="form.curp"
required :id="$t('membership.curp')"
/> type="text"
<Input :onError="form.errors.curp"
v-model="form.paternal" required
id="paternal" autofocus
:onError="form.errors.paternal" />
required <Input
/> v-model="form.name"
<Input :id="$t('membership.name')"
v-model="form.maternal" type="text"
id="maternal" :onError="form.errors.name"
:onError="form.errors.maternal" required
/> />
<Input <Input
v-model="form.curp" v-model="form.tutor"
id="Curp" :id="$t('membership.tutor')"
:onError="form.errors.curp" type="text"
type="text" :onError="form.errors.tutor"
/> />
<slot /> <PhotoUpload
<div class="col-span-1 md:col-span-2 lg:col-span-3 xl:col-span-4 flex flex-col items-center justify-end space-y-4 mt-4"> v-model="form.photo"
<PrimaryButton :title="$t('membership.photo')"
v-text="$t(action)" :onError="form.errors.photo"
:class="{ 'opacity-25': form.processing }" required
:disabled="form.processing" />
/> <slot />
</div> <div
</form> class="col-span-1 md:col-span-2 lg:col-span-3 xl:col-span-4 flex flex-col items-center justify-end space-y-4 mt-4"
</div> >
<PrimaryButton
v-text="$t(action)"
:class="{ 'opacity-25': form.processing }"
:disabled="form.processing"
/>
</div>
</form>
</div>
</template> </template>