feat: add is_active field to risk factors and update UI components for status display

This commit is contained in:
raul.velazco 2026-04-06 14:30:00 -06:00
parent ab04091306
commit 51dcf6f9a3
3 changed files with 56 additions and 12 deletions

View File

@ -44,7 +44,7 @@
<small v-if="errors.evaluation_context" class="p-error">{{ errors.evaluation_context[0] }}</small> <small v-if="errors.evaluation_context" class="p-error">{{ errors.evaluation_context[0] }}</small>
</div> </div>
<div class="flex flex-col gap-2 md:col-span-2"> <div class="flex flex-col gap-2 md:col-span-1">
<label for="description" class="font-semibold">Descripción (Opcional)</label> <label for="description" class="font-semibold">Descripción (Opcional)</label>
<Textarea id="description" <Textarea id="description"
v-model="form.description" v-model="form.description"
@ -52,6 +52,16 @@
autoResize autoResize
placeholder="Detalles sobre este factor de riesgo..." /> placeholder="Detalles sobre este factor de riesgo..." />
</div> </div>
<div class="flex flex-col gap-2 md:col-span-1 justify-center">
<div class="flex items-center gap-3 p-4 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700">
<InputSwitch v-model="form.is_active" :binary="true" inputId="is_active" />
<div class="flex flex-col">
<label for="is_active" class="font-bold mb-0 leading-tight">Estado Activo</label>
<small class="text-surface-500">Determina si este factor estará disponible en nuevas evaluaciones</small>
</div>
</div>
</div>
</div> </div>
<!-- Formulario Detalle (DataTable) --> <!-- Formulario Detalle (DataTable) -->
@ -92,6 +102,16 @@
</template> </template>
</Column> </Column>
<Column field="is_active" header="Estado" style="width: 10%" bodyStyle="text-align:center">
<template #editor="{ data, field }">
<InputSwitch v-model="data[field]" :binary="true" />
</template>
<template #body="{ data }">
<Tag :value="data.is_active !== false ? 'Activo' : 'Inactivo'"
:severity="data.is_active !== false ? 'success' : 'danger'" />
</template>
</Column>
<Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column> <Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column>
<Column style="width: 10%; min-width: 4rem" bodyStyle="text-align:center"> <Column style="width: 10%; min-width: 4rem" bodyStyle="text-align:center">
@ -100,7 +120,8 @@
severity="danger" severity="danger"
text text
rounded rounded
@click="removeOption(index)" /> @click="removeOption(index)"
title="Eliminar" />
</template> </template>
</Column> </Column>
@ -129,6 +150,7 @@ import Column from 'primevue/column';
import Button from 'primevue/button'; import Button from 'primevue/button';
import InputNumber from 'primevue/inputnumber'; import InputNumber from 'primevue/inputnumber';
import Tag from 'primevue/tag'; import Tag from 'primevue/tag';
import InputSwitch from 'primevue/inputswitch';
import { riskFactorServices } from '../../services/risk-factors.services'; import { riskFactorServices } from '../../services/risk-factors.services';
import type { RiskFactor, RiskOption, RiskFactorFormErrors } from '../../types/risk-factors.interfaces'; import type { RiskFactor, RiskOption, RiskFactorFormErrors } from '../../types/risk-factors.interfaces';
@ -150,7 +172,7 @@ const errors = ref<RiskFactorFormErrors>({});
const contextOptions = [ const contextOptions = [
{ label: 'Ruta', value: 1 }, { label: 'Ruta', value: 1 },
{ label: 'Programa', value: 2 } { label: 'Viaje', value: 2 }
]; ];
const form = reactive<RiskFactor & { options: ExtendedRiskOption[] }>({ const form = reactive<RiskFactor & { options: ExtendedRiskOption[] }>({
@ -158,6 +180,7 @@ const form = reactive<RiskFactor & { options: ExtendedRiskOption[] }>({
name: '', name: '',
description: '', description: '',
evaluation_context: 1, evaluation_context: 1,
is_active: true,
options: [] options: []
}); });
@ -172,7 +195,8 @@ onMounted(() => {
const addOption = () => { const addOption = () => {
const newOption: ExtendedRiskOption = { const newOption: ExtendedRiskOption = {
name: '', name: '',
value: 1, // Valor por defecto solicitado value: 1,
is_active: true,
tempId: Date.now() + Math.random() tempId: Date.now() + Math.random()
}; };
form.options.push(newOption); form.options.push(newOption);
@ -219,6 +243,12 @@ const handleSave = async () => {
loading.value = true; loading.value = true;
try { try {
const payload = JSON.parse(JSON.stringify(form)); const payload = JSON.parse(JSON.stringify(form));
payload.options = payload.options.map((option: any) => ({
id: option.id,
name: option.name,
value: option.value,
is_active: option.is_active !== false,
}));
let response; let response;
if (form.id && !isDuplicating.value) { if (form.id && !isDuplicating.value) {
@ -233,7 +263,9 @@ const handleSave = async () => {
if (error.response?.data?.errors) { if (error.response?.data?.errors) {
errors.value = error.response.data.errors; errors.value = error.response.data.errors;
} }
toast.add({ severity: 'error', summary: 'Error', detail: 'No se pudo guardar el factor de riesgo', life: 3000 });
const detail = error.response?.data?.error || error.response?.data?.message || 'No se pudo guardar el factor de riesgo';
toast.add({ severity: 'error', summary: 'Error', detail, life: 5000 });
} finally { } finally {
loading.value = false; loading.value = false;
} }

View File

@ -29,10 +29,17 @@
<Column field="name" header="Nombre" sortable /> <Column field="name" header="Nombre" sortable />
<Column field="is_active" header="Estado" sortable>
<template #body="{ data }">
<Tag :value="data.is_active !== false ? 'Activo' : 'Inactivo'"
:severity="data.is_active !== false ? 'success' : 'danger'" />
</template>
</Column>
<Column field="evaluation_context" header="Contexto" sortable> <Column field="evaluation_context" header="Contexto" sortable>
<template #body="{ data }"> <template #body="{ data }">
<Tag :value="data.evaluation_context === 1 ? 'Ruta' : 'Programa'" <Tag :value="data.evaluation_context === 1 ? 'Ruta' : 'Viaje'"
:severity="data.evaluation_context === 1 ? 'info' : 'success'" /> :severity="data.evaluation_context === 1 ? 'info' : 'secondary'" />
</template> </template>
</Column> </Column>
@ -50,7 +57,7 @@
</template> </template>
</Column> </Column>
<Column header="Acciones" headerStyle="min-width:10rem"> <Column header="Acciones" headerStyle="min-width:12rem">
<template #body="{ data }"> <template #body="{ data }">
<div class="flex gap-2"> <div class="flex gap-2">
<Button icon="pi pi-pencil" <Button icon="pi pi-pencil"
@ -58,7 +65,8 @@
text text
rounded rounded
@click="editFactor(data)" @click="editFactor(data)"
v-if="hasPermission('risk-factors.update')" /> v-if="hasPermission('risk-factors.update')"
title="Editar" />
<Button icon="pi pi-copy" <Button icon="pi pi-copy"
severity="secondary" severity="secondary"
@ -73,7 +81,8 @@
text text
rounded rounded
@click="confirmDelete(data)" @click="confirmDelete(data)"
v-if="hasPermission('risk-factors.destroy')" /> v-if="hasPermission('risk-factors.destroy')"
title="Eliminar" />
</div> </div>
</template> </template>
</Column> </Column>
@ -193,8 +202,9 @@ const confirmDelete = (factor: RiskFactor) => {
await riskFactorServices.deleteRiskFactor(factor.id!); await riskFactorServices.deleteRiskFactor(factor.id!);
toast.add({ severity: 'success', summary: 'Eliminado', detail: 'Factor eliminado correctamente', life: 3000 }); toast.add({ severity: 'success', summary: 'Eliminado', detail: 'Factor eliminado correctamente', life: 3000 });
fetchFactors(); fetchFactors();
} catch (error) { } catch (error: any) {
toast.add({ severity: 'error', summary: 'Error', detail: 'No se pudo eliminar el factor', life: 3000 }); const detail = error.response?.data?.error || error.response?.data?.message || 'No se pudo eliminar el factor';
toast.add({ severity: 'error', summary: 'Error de Eliminación', detail, life: 5000 });
} }
} }
}); });

View File

@ -7,6 +7,7 @@ export interface RiskOption {
risk_factor_id?: number; risk_factor_id?: number;
name: string; name: string;
value: number; value: number;
is_active?: boolean;
} }
export interface RiskFactor { export interface RiskFactor {
@ -15,6 +16,7 @@ export interface RiskFactor {
description: string | null; description: string | null;
evaluation_context: number; evaluation_context: number;
tenant_id?: number; tenant_id?: number;
is_active?: boolean;
options?: RiskOption[]; options?: RiskOption[];
created_at?: string; created_at?: string;
updated_at?: string; updated_at?: string;