From c269f17febe7bdbffa438a161999f98d402e1e40 Mon Sep 17 00:00:00 2001 From: "edgar.mendez" Date: Wed, 25 Mar 2026 12:52:32 -0600 Subject: [PATCH] feat(document-concepts): add CRUD functionality for document concepts and models --- src/components/layout/Sidebar.vue | 6 + .../DocumentConceptsForm.vue | 127 +++++++++++++++ .../DocumentConceptsTable.vue | 86 ++++++++++ .../DocumentConceptsView.vue | 150 ++++++++++++++++++ .../document-concepts.interface.ts | 64 ++++++++ .../document-concepts.services.ts | 79 +++++++++ .../document-models.interface.ts | 48 ++++++ .../document-models.services.ts | 41 +++++ src/router/index.ts | 10 ++ 9 files changed, 611 insertions(+) create mode 100644 src/modules/catalog/components/document-concepts/DocumentConceptsForm.vue create mode 100644 src/modules/catalog/components/document-concepts/DocumentConceptsTable.vue create mode 100644 src/modules/catalog/components/document-concepts/DocumentConceptsView.vue create mode 100644 src/modules/catalog/components/document-concepts/document-concepts.interface.ts create mode 100644 src/modules/catalog/components/document-concepts/document-concepts.services.ts create mode 100644 src/modules/catalog/components/document-concepts/document-models.interface.ts create mode 100644 src/modules/catalog/components/document-concepts/document-models.services.ts diff --git a/src/components/layout/Sidebar.vue b/src/components/layout/Sidebar.vue index 1ee8f5d..272a739 100644 --- a/src/components/layout/Sidebar.vue +++ b/src/components/layout/Sidebar.vue @@ -62,6 +62,12 @@ const menuItems = ref([ 'companies.update', 'companies.destroy', ], + }, + { + label: 'Conceptos de Documentos', + icon: 'pi pi-book', + to: '/catalog/document-concepts', + permission: 'document_concepts.index' } ] }, diff --git a/src/modules/catalog/components/document-concepts/DocumentConceptsForm.vue b/src/modules/catalog/components/document-concepts/DocumentConceptsForm.vue new file mode 100644 index 0000000..0baf5ea --- /dev/null +++ b/src/modules/catalog/components/document-concepts/DocumentConceptsForm.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/src/modules/catalog/components/document-concepts/DocumentConceptsTable.vue b/src/modules/catalog/components/document-concepts/DocumentConceptsTable.vue new file mode 100644 index 0000000..80c569f --- /dev/null +++ b/src/modules/catalog/components/document-concepts/DocumentConceptsTable.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/modules/catalog/components/document-concepts/DocumentConceptsView.vue b/src/modules/catalog/components/document-concepts/DocumentConceptsView.vue new file mode 100644 index 0000000..51a7f07 --- /dev/null +++ b/src/modules/catalog/components/document-concepts/DocumentConceptsView.vue @@ -0,0 +1,150 @@ + + + + diff --git a/src/modules/catalog/components/document-concepts/document-concepts.interface.ts b/src/modules/catalog/components/document-concepts/document-concepts.interface.ts new file mode 100644 index 0000000..18bf293 --- /dev/null +++ b/src/modules/catalog/components/document-concepts/document-concepts.interface.ts @@ -0,0 +1,64 @@ +// document-concepts.interface.ts + +/** + * Entity: DocumentConcept + * Representa un concepto documental gestionado en el sistema. + */ +export interface DocumentConcept { + id: number; + tenant_id: number; + document_model_id: number; + name: string; + folder_path: string; // Generado automáticamente por el backend + serie?: string | null; // Opcional + initial_number: number; + created_at: string; // ISO string + updated_at: string; // ISO string + deleted_at: string | null; // Puede ser null (no borrado) +} + +/** + * DTO para creación de un concepto + */ +export interface CreateDocumentConceptDTO { + document_model_id: number; + name: string; + serie?: string | null; + initial_number: number; +} + +/** + * DTO para actualización parcial de un concepto + * Todos los campos son opcionales para permitir updates parciales. + */ +export interface UpdateDocumentConceptDTO { + document_model_id?: number; + name?: string; + serie?: string | null; + initial_number?: number; +} + +/** + * Respuesta de la API para listado de conceptos + */ +export interface ResponseDocumentConceptDTO { + data: DocumentConcept[]; + message?: string; + success?: boolean; +} + +/** + * Respuesta de la API para una sola entidad de concepto (por id o creación) + */ +export interface SingleDocumentConceptResponseDTO { + id: number; + tenant_id: number; + document_model_id: number; + name: string; + folder_path: string; + serie?: string | null; + initial_number: number; + created_at: string; + updated_at: string; + deleted_at: string | null; +} diff --git a/src/modules/catalog/components/document-concepts/document-concepts.services.ts b/src/modules/catalog/components/document-concepts/document-concepts.services.ts new file mode 100644 index 0000000..44157fe --- /dev/null +++ b/src/modules/catalog/components/document-concepts/document-concepts.services.ts @@ -0,0 +1,79 @@ +// document-concepts.services.ts +import api from '@/services/api'; +import type { + CreateDocumentConceptDTO, + ResponseDocumentConceptDTO, + SingleDocumentConceptResponseDTO +} from './document-concepts.interface'; + +/** + * Servicio para gestión de conceptos documentales. + */ +export class DocumentConceptsService { + /** + * Obtiene la lista de conceptos documentales, con filtros opcionales. + * @param filters name (string, opcional), document_model_id (number, opcional) + */ + public async getDocumentConcepts(filters?: { name?: string; document_model_id?: number }): Promise { + try { + const response = await api.get('/api/document-concepts', { params: filters }); + return response.data; + } catch (error) { + console.error('Error fetching document concepts:', error); + throw error; + } + } + + /** + * Crea un nuevo concepto documental. + * @param data Payload con los valores requeridos. + */ + public async createDocumentConcept(data: CreateDocumentConceptDTO): Promise { + try { + const response = await api.post('/api/document-concepts', data); + return response.data; + } catch (error) { + console.error('Error creating document concept:', error); + throw error; + } + } + + /** + * Consulta un concepto documental por su id. + * @param id Identificador único del concepto + */ + public async getDocumentConceptById(id: number): Promise { + try { + const response = await api.get(`/api/document-concepts/${id}`); + return response.data; + } catch (error) { + console.error('Error fetching document concept by id:', error); + throw error; + } + } + + /** + * Actualiza parcialmente un concepto documental (PATCH /document-concepts/:id) + */ + public async updateDocumentConcept(id: number, data: Partial): Promise { + try { + const response = await api.patch(`/api/document-concepts/${id}`, data); + return response.data; + } catch (error) { + console.error('Error updating document concept:', error); + throw error; + } + } + + /** + * Elimina un concepto documental por su id (DELETE /document-concepts/:id) + */ + public async deleteDocumentConcept(id: number): Promise { + try { + await api.delete(`/api/document-concepts/${id}`); + } catch (error) { + console.error('Error deleting document concept:', error); + throw error; + } + } +} diff --git a/src/modules/catalog/components/document-concepts/document-models.interface.ts b/src/modules/catalog/components/document-concepts/document-models.interface.ts new file mode 100644 index 0000000..b61b114 --- /dev/null +++ b/src/modules/catalog/components/document-concepts/document-models.interface.ts @@ -0,0 +1,48 @@ +// document-models.interface.ts + +export interface DocumentModel { + id: number; + name: string; + module: number; + type: number; + num_folio: number; + created_at: string; // ISO date + updated_at: string; // ISO date + deleted_at: string | null; +} + +export interface CreateDocumentModelDTO { + name: string; + module: number; + type: number; + num_folio?: number; +} + +export interface UpdateDocumentModelDTO { + name?: string; + module?: number; + type?: number; + num_folio?: number; +} + +export interface PaginatedDocumentModelsResponse { + current_page: number; + data: DocumentModel[]; + first_page_url: string; + from: number; + last_page: number; + last_page_url: string; + next_page_url: string | null; + path: string; + per_page: number; + prev_page_url: string | null; + to: number; + total: number; + links: PaginationLink[]; +} + +export interface PaginationLink { + url: string | null; + label: string; + active: boolean; +} diff --git a/src/modules/catalog/components/document-concepts/document-models.services.ts b/src/modules/catalog/components/document-concepts/document-models.services.ts new file mode 100644 index 0000000..b7cf4a5 --- /dev/null +++ b/src/modules/catalog/components/document-concepts/document-models.services.ts @@ -0,0 +1,41 @@ +import api from "@/services/api"; +import type { + DocumentModel, + PaginatedDocumentModelsResponse +} from "./document-models.interface"; + +export class DocumentModelsService { + /** + * Obtiene modelos de documento, con paginación o sin ella. + * @param paginate default: true. Si es false, devuelve DocumentModel[] directamente; + * @param per_paginate default: 15. Si se envía, cambia el page size. + */ + public async getDocumentModels(opts?: { + paginate?: boolean; + per_paginate?: number; + search?: string; + [key: string]: any; + }): Promise { + try { + // Construye params siempre + const params: Record = { + paginate: opts?.paginate, + per_paginate: opts?.per_paginate, + ...opts + }; + // Evita undefined + if (params.paginate === undefined) delete params.paginate; + if (params.per_paginate === undefined) delete params.per_paginate; + const response = await api.get("/api/catalogs/document-models", { params }); + if (opts?.paginate === false) { + return response.data.data; // Solo el array de modelos + } else { + return response.data as PaginatedDocumentModelsResponse; + } + } catch (error) { + console.error("Error fetching document models:", error); + throw error; + } + } +} + diff --git a/src/router/index.ts b/src/router/index.ts index 3ae6d0c..7ecc2e2 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -204,6 +204,16 @@ const routes: RouteRecordRaw[] = [ requiresAuth: true } }, + { + path: 'document-concepts', + name: 'DocumentConcepts', + component: () => import('@/modules/catalog/components/document-concepts/DocumentConceptsView.vue'), + meta: { + title: 'Conceptos de Documentos', + requiresAuth: true, + permission: 'document_concepts.index' + } + }, companiesRouter ] },