feat: agregar funcionalidad para gestionar usuarios y folios de resguardo en la asignación de activos fijos

This commit is contained in:
Juan Felipe Zapata Moreno 2026-03-24 17:26:33 -06:00
parent 1a5e70890c
commit 8205d4203b
5 changed files with 72 additions and 3 deletions

View File

@ -1,11 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import Card from 'primevue/card'; import Card from 'primevue/card';
import InputText from 'primevue/inputtext'; import InputText from 'primevue/inputtext';
import Select from 'primevue/select';
import Textarea from 'primevue/textarea'; import Textarea from 'primevue/textarea';
import type { FixedAssetAssignmentFormData } from '../../types/fixedAssetAssignment'; import type { FixedAssetAssignmentFormData } from '../../types/fixedAssetAssignment';
import type { UserOption } from '../../services/fixedAssetsService';
interface Props { interface Props {
form: FixedAssetAssignmentFormData; form: FixedAssetAssignmentFormData;
users: UserOption[];
} }
defineProps<Props>(); defineProps<Props>();
@ -29,6 +32,26 @@ defineProps<Props>();
class="w-full" class="w-full"
/> />
</div> </div>
<div class="space-y-2">
<label class="text-sm font-semibold text-surface-800 dark:text-surface-100">Folio de Resguardo (Opcional)</label>
<InputText
v-model="form.receiptFolio"
class="w-full"
placeholder="Ej. GOLSRMVR-0170"
/>
</div>
<div class="space-y-2 md:col-span-2">
<label class="text-sm font-semibold text-surface-800 dark:text-surface-100">Autoriza (Opcional)</label>
<Select
v-model="form.authorizedById"
:options="users"
optionLabel="full_name"
optionValue="id"
placeholder="Seleccione quien autoriza..."
class="w-full"
showClear
/>
</div>
<div class="space-y-2 md:col-span-2"> <div class="space-y-2 md:col-span-2">
<label class="text-sm font-semibold text-surface-800 dark:text-surface-100">Notas o Comentarios (Opcional)</label> <label class="text-sm font-semibold text-surface-800 dark:text-surface-100">Notas o Comentarios (Opcional)</label>
<Textarea <Textarea

View File

@ -12,7 +12,7 @@ import type {
AssignmentEmployeeOption, AssignmentEmployeeOption,
FixedAssetAssignmentFormData FixedAssetAssignmentFormData
} from '../../types/fixedAssetAssignment'; } from '../../types/fixedAssetAssignment';
import { fixedAssetsService } from '../../services/fixedAssetsService'; import { fixedAssetsService, type UserOption } from '../../services/fixedAssetsService';
import { employeesService } from '@/modules/rh/components/employees/employees.services'; import { employeesService } from '@/modules/rh/components/employees/employees.services';
const router = useRouter(); const router = useRouter();
@ -24,20 +24,24 @@ const employeeSearch = ref('');
const assets = ref<AssignmentAssetOption[]>([]); const assets = ref<AssignmentAssetOption[]>([]);
const employees = ref<AssignmentEmployeeOption[]>([]); const employees = ref<AssignmentEmployeeOption[]>([]);
const users = ref<UserOption[]>([]);
const form = ref<FixedAssetAssignmentFormData>({ const form = ref<FixedAssetAssignmentFormData>({
assetId: null, assetId: null,
employeeId: null, employeeId: null,
authorizedById: null,
assignedAt: new Date().toISOString().slice(0, 10), assignedAt: new Date().toISOString().slice(0, 10),
receiptFolio: '',
notes: '' notes: ''
}); });
onMounted(async () => { onMounted(async () => {
loadingData.value = true; loadingData.value = true;
try { try {
const [assetsRes, employeesRes] = await Promise.all([ const [assetsRes, employeesRes, usersRes] = await Promise.all([
fixedAssetsService.getAssets({ paginate: false, status: 1 }), fixedAssetsService.getAssets({ paginate: false, status: 1 }),
employeesService.getEmployees({ paginate: false }), employeesService.getEmployees({ paginate: false }),
fixedAssetsService.getUsers(),
]); ]);
const allAssets = (assetsRes as any).data?.data ?? []; const allAssets = (assetsRes as any).data?.data ?? [];
@ -59,6 +63,8 @@ onMounted(async () => {
role: e.job_position?.name ?? '—', role: e.job_position?.name ?? '—',
department: e.department?.name ?? '—', department: e.department?.name ?? '—',
})); }));
users.value = usersRes;
} catch { } catch {
toast.add({ toast.add({
severity: 'error', severity: 'error',
@ -89,6 +95,8 @@ const save = async () => {
await fixedAssetsService.assignAsset(form.value.assetId, { await fixedAssetsService.assignAsset(form.value.assetId, {
employee_id: form.value.employeeId, employee_id: form.value.employeeId,
assigned_at: form.value.assignedAt, assigned_at: form.value.assignedAt,
receipt_folio: form.value.receiptFolio || undefined,
authorized_by: form.value.authorizedById ?? undefined,
notes: form.value.notes || undefined, notes: form.value.notes || undefined,
}); });
@ -139,7 +147,7 @@ const save = async () => {
@update:selected-employee-id="form.employeeId = $event" @update:selected-employee-id="form.employeeId = $event"
/> />
<AssignmentDetailsCard :form="form" /> <AssignmentDetailsCard :form="form" :users="users" />
<div class="flex flex-wrap items-center justify-end gap-3"> <div class="flex flex-wrap items-center justify-end gap-3">
<Button label="Cancelar" text severity="secondary" @click="cancel" /> <Button label="Cancelar" text severity="secondary" @click="cancel" />

View File

@ -77,6 +77,11 @@ const goToOffboarding = (assignment: AssetAssignment) => {
router.push(`/fixed-assets/assignments/${assignment.asset_id}/${assignment.id}/offboarding`); router.push(`/fixed-assets/assignments/${assignment.asset_id}/${assignment.id}/offboarding`);
}; };
const downloadResguardo = (assignment: AssetAssignment) => {
const url = fixedAssetsService.getResguardoUrl(assignment.asset_id, assignment.id);
window.open(url, '_blank');
};
onMounted(loadAssignments); onMounted(loadAssignments);
</script> </script>
@ -175,6 +180,15 @@ onMounted(loadAssignments);
</td> </td>
<td class="px-4 py-3 text-right"> <td class="px-4 py-3 text-right">
<div class="flex items-center justify-end gap-1"> <div class="flex items-center justify-end gap-1">
<Button
icon="pi pi-file-pdf"
text
rounded
size="small"
severity="secondary"
v-tooltip.top="'Descargar resguardo'"
@click="downloadResguardo(assignment)"
/>
<Button <Button
v-if="assignment.status.id === 1" v-if="assignment.status.id === 1"
icon="pi pi-times-circle" icon="pi pi-times-circle"

View File

@ -115,10 +115,22 @@ export interface AssetAssignmentsPaginatedResponse {
}; };
} }
export interface UserOption {
id: number;
full_name: string;
email: string;
}
export interface UsersResponse {
status: string;
data: { data: UserOption[] };
}
interface AssignAssetData { interface AssignAssetData {
employee_id: number; employee_id: number;
assigned_at?: string; assigned_at?: string;
receipt_folio?: string; receipt_folio?: string;
authorized_by?: number;
notes?: string; notes?: string;
} }
@ -184,6 +196,16 @@ class FixedAssetsService {
const response = await api.put<AssetAssignmentResponse>(`/api/assets/${assetId}/assignments/${assignmentId}/return`, data); const response = await api.put<AssetAssignmentResponse>(`/api/assets/${assetId}/assignments/${assignmentId}/return`, data);
return response.data; return response.data;
} }
async getUsers(): Promise<UserOption[]> {
const response = await api.get<UsersResponse>('/api/admin/users', { params: { paginate: false } });
return response.data.data.data;
}
getResguardoUrl(assetId: number, assignmentId: number): string {
const base = import.meta.env.VITE_API_URL || '';
return `${base}/api/asset-assignments-public/${assetId}/assignments/${assignmentId}/resguardo`;
}
} }
export const fixedAssetsService = new FixedAssetsService(); export const fixedAssetsService = new FixedAssetsService();

View File

@ -17,6 +17,8 @@ export interface AssignmentEmployeeOption {
export interface FixedAssetAssignmentFormData { export interface FixedAssetAssignmentFormData {
assetId: number | null; assetId: number | null;
employeeId: number | null; employeeId: number | null;
authorizedById: number | null;
assignedAt: string; assignedAt: string;
receiptFolio: string;
notes: string; notes: string;
} }