Browse Source

Finalización del módulo de gestión documental electrónica

Jose Brito 2 years ago
parent
commit
24c47192a3

+ 2 - 6
sistema-mantenimiento-front/src/app/components/gdel/gdel.component.ts

@@ -681,16 +681,12 @@ export class GDELComponent implements OnInit {
 
   openAssociationDialog(code: string, version: string, name: string){
     let idFile = `${code}=${version}=${name}`;
-    let dialogRef = this._dialog.open(OrderAssociatonComponent, {
-      width: '720px',
+    this._dialog.open(OrderAssociatonComponent, {
+      width: '840px',
       disableClose: true,
       data: {
         idFile: idFile,
       }
-    })
-
-    dialogRef.afterClosed().subscribe(res => {
-      console.log(res);
     });
   }
 

+ 8 - 0
sistema-mantenimiento-front/src/app/components/gdel/order-associaton/order-associaton.component.css

@@ -0,0 +1,8 @@
+.association-container{
+  width: 100%;
+  height: 320px;
+  overflow-x: hidden;
+  overflow-y: auto;
+  display: flex;
+  flex-direction: column;
+}

+ 120 - 2
sistema-mantenimiento-front/src/app/components/gdel/order-associaton/order-associaton.component.html

@@ -1,8 +1,126 @@
 <h1 mat-dialog-title class="prevent-select">Asociar archivo a órdenes de trabajo</h1>
 <div mat-dialog-content class="prevent-select">
+  <div class="is-loading animated fadeIn fast" *ngIf="isLoading">
+    <mat-spinner align="center"></mat-spinner>
+    <h3>Cargando datos ...</h3>
+  </div>
+  <div class="is-loading animated fadeIn fast" *ngIf="!isLoading && hasError">
+    <mat-icon style="transform: scale(4.5);margin: 45px 0;" class="red_primary_font">error</mat-icon>
+    <h3>{{ errorStr }}</h3>
+  </div>
+  <div [ngClass]="{ hidden: !(!hasError && !isLoading) }" class="animated fadeIn fast association-container">
+    <h3 style="margin: 8px 0;">{{ idFile }}</h3>
+    <table mat-table [dataSource]="dataSource!" class="animated fadeIn">
+      <ng-container matColumnDef="ID">
+        <th mat-header-cell *matHeaderCellDef>#</th>
+        <td mat-cell *matCellDef="let row">Orden #{{ row.IDORDEN }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="EQUIPAMIENTO">
+        <th mat-header-cell *matHeaderCellDef>Equipamiento</th>
+        <td mat-cell *matCellDef="let row">{{ row.EQUIPAMIENTO }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="ACTIVADOR">
+        <th mat-header-cell *matHeaderCellDef>Activador</th>
+        <td mat-cell *matCellDef="let row">Activador #{{ row.ACTIVADOR }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="CLASIFICACION">
+        <th mat-header-cell *matHeaderCellDef>Clasificación</th>
+        <td mat-cell *matCellDef="let row">{{ row.CLASIFICACION }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="PRIORIDAD">
+        <th mat-header-cell *matHeaderCellDef>Prioridad</th>
+        <td mat-cell *matCellDef="let row">
+          <span style="font-weight: 500;" [style.color]="getFontColor(row.PRIORIDAD)">
+            {{ getPriorityStr(row.PRIORIDAD) }}
+          </span>
+        </td>
+      </ng-container>
+      
+      <ng-container matColumnDef="ACCIONES">
+        <th mat-header-cell *matHeaderCellDef>Acciones</th>
+        <td mat-cell *matCellDef="let row">
+          <button mat-icon-button [matMenuTriggerFor]="menuAssociated">
+            <mat-icon>more_vert</mat-icon>
+          </button>
+          <mat-menu #menuAssociated>
+            <button mat-menu-item (click)="changeAssociationStatus('disassociate', row.IDORDEN)">
+              <mat-icon>close</mat-icon>
+              <span>Deshacer asociación</span>
+            </button>
+          </mat-menu>
+        </td>
+      </ng-container>
+  
+      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+      <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
 
+      <tr class="mat-row" *matNoDataRow>
+        <td class="mat-cell" colspan="100%" style="font-weight: 500;">
+          Este archivo no está asociado a ninguna orden de trabajo
+        </td>
+      </tr>
+    </table>
+    <h3 style="margin: 8px 0;">Asociar a otra orden de trabajo</h3>
+    <table mat-table [dataSource]="dataSourceOrders!" class="animated fadeIn">
+      <ng-container matColumnDef="ID">
+        <th mat-header-cell *matHeaderCellDef>#</th>
+        <td mat-cell *matCellDef="let row">Orden #{{ row.IDORDEN }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="EQUIPAMIENTO">
+        <th mat-header-cell *matHeaderCellDef>Equipamiento</th>
+        <td mat-cell *matCellDef="let row">{{ row.EQUIPAMIENTO }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="ACTIVADOR">
+        <th mat-header-cell *matHeaderCellDef>Activador</th>
+        <td mat-cell *matCellDef="let row">Activador #{{ row.ACTIVADOR }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="CLASIFICACION">
+        <th mat-header-cell *matHeaderCellDef>Clasificación</th>
+        <td mat-cell *matCellDef="let row">{{ row.CLASIFICACION }}</td>
+      </ng-container>
+      
+      <ng-container matColumnDef="PRIORIDAD">
+        <th mat-header-cell *matHeaderCellDef>Prioridad</th>
+        <td mat-cell *matCellDef="let row">
+          <span style="font-weight: 500;" [style.color]="getFontColor(row.PRIORIDAD)">
+            {{ getPriorityStr(row.PRIORIDAD) }}
+          </span>
+        </td>
+      </ng-container>
+      
+      <ng-container matColumnDef="ACCIONES">
+        <th mat-header-cell *matHeaderCellDef>Acciones</th>
+        <td mat-cell *matCellDef="let row">
+          <button mat-icon-button [matMenuTriggerFor]="menuDisassociated">
+            <mat-icon>more_vert</mat-icon>
+          </button>
+          <mat-menu #menuDisassociated>
+            <button mat-menu-item (click)="changeAssociationStatus('associate', row.IDORDEN)">
+              <mat-icon>done</mat-icon>
+              <span>Asociaciar archivo</span>
+            </button>
+          </mat-menu>
+        </td>
+      </ng-container>
+  
+      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+      <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+
+      <tr class="mat-row" *matNoDataRow>
+        <td class="mat-cell" colspan="100%" style="font-weight: 500;">
+          No se encontraron más órdenes de trabajo.
+        </td>
+      </tr>
+    </table>
+  </div>
 </div>
 <div mat-dialog-actions align="end">
-  <button mat-button mat-dialog-close>Cancelar</button>
-  <button mat-button>Guargar cambios</button>
+  <button mat-button mat-dialog-close>Cerrar</button>
 </div>

+ 203 - 1
sistema-mantenimiento-front/src/app/components/gdel/order-associaton/order-associaton.component.ts

@@ -1,5 +1,15 @@
 import { Component, Inject, OnInit } from '@angular/core';
 import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { MatTableDataSource } from '@angular/material/table';
+import { lastValueFrom } from 'rxjs';
+import { AssociatedWorkOrder, AssociatedWorkOrdersResponse } from 'src/app/interfaces/associated-work-orders.interface';
+import { GdelService } from 'src/app/services/document-management/gdel.service';
+import { EncService } from 'src/app/services/enc/enc.service';
+import { SystemAdminService } from 'src/app/services/system-admin.service';
+import { PriorityInterface } from '../../system-admin/system-params/system-params.component';
+import { PreventiveMaintenanceService } from 'src/app/services/preventive-maintenance.service';
+import { PreventiveWorkOrdersActive, PreventiveWorkOrdersActiveResponse } from 'src/app/interfaces/preventive-work-orders-active.interface';
+import { MatSnackBar } from '@angular/material/snack-bar';
 
 @Component({
   selector: 'app-order-associaton',
@@ -7,12 +17,204 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog';
   styleUrls: ['./order-associaton.component.css']
 })
 export class OrderAssociatonComponent implements OnInit {
+  isLoading: boolean;
+  hasError: boolean;
+  errorStr: string;
+  idFile: string;
+
+  displayedColumns = ['ID', 'EQUIPAMIENTO', 'ACTIVADOR', 'CLASIFICACION', 'PRIORIDAD', 'ACCIONES'];
+  dataSource: MatTableDataSource<AssociatedWorkOrder>;
+  orderPriorities: PriorityInterface[];
+
+  dataSourceOrders: MatTableDataSource<AssociatedWorkOrder>;
 
   constructor(
     @Inject(MAT_DIALOG_DATA) private _data: any,
-  ) {}
+    private _encService: EncService,
+    private _gdelService: GdelService,
+    private _sysAdminService: SystemAdminService,
+    private _prevMaintService: PreventiveMaintenanceService,
+    private _snackBar: MatSnackBar,
+  ) {
+    this.isLoading = true;
+    this.hasError = false;
+    this.errorStr = '';
+    this.idFile = '';
+
+    this.dataSource = new MatTableDataSource();
+    this.orderPriorities = [];
+
+    this.dataSourceOrders = new MatTableDataSource();
+  }
 
   ngOnInit(): void {
+    this.idFile = this._data.idFile;
+    this.getAssociatedOrders();
+  }
+
+  async getAssociatedOrders(){
+    try{
+      this.isLoading = true;
+      this.hasError = false;
+      this.errorStr = '';
+
+      let idUser = localStorage.getItem('idusuario');
+      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));
+      let idFileEnc = await this._encService.encrypt(this.idFile);
+      let idFileShort = await lastValueFrom(this._encService.shortEncrypt(idFileEnc));
+
+      let orders: AssociatedWorkOrdersResponse = await lastValueFrom(this._gdelService.getAssociatedWorkOrders(
+        idFileShort.response.encrypted,
+        shortEnc.response.encrypted,
+        1
+      ));
+
+      this.hasError = orders.error;
+      this.errorStr = orders.msg;
+
+      if(this.hasError){
+        this.isLoading = false
+      }else{
+        this.dataSource = new MatTableDataSource(orders.response);
+        this.getPriorities();
+      }
+    }catch(error: any){
+      if(error.error == undefined){
+        this.errorStr = 'Ocurrió un error inesperado.';
+      }else if(error.error.msg == undefined){
+        this.errorStr = 'Ocurrió un error inesperado.';
+      }else{
+        this.errorStr = error.error.msg;
+      }
+
+      this.hasError = true;
+      this.isLoading = false;
+    }
+  }
+
+  async getPriorities(){
+    try{
+      let idUser = localStorage.getItem('idusuario');
+      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));
+      let priorities = await lastValueFrom(this._sysAdminService.getOrderPriorities(shortEnc.response.encrypted, 1));
+
+      if(priorities.error){
+        this.hasError = priorities.error;
+        this.errorStr = priorities.msg;
+        this.isLoading = false;
+      }else{
+        this.orderPriorities = priorities.response.order_priorities;
+        this.getActiveOrders();
+      }
+    }catch(error: any){
+      if(error.error == undefined){
+        this.errorStr = 'Ocurrió un error inesperado.';
+      }else if(error.error.msg == undefined){
+        this.errorStr = 'Ocurrió un error inesperado.';
+      }else{
+        this.errorStr = error.error.msg;
+      }
+
+      this.hasError = true;
+      this.isLoading = false;
+    }
+  }
+
+  async getActiveOrders(){
+    try{
+      let idUser = localStorage.getItem('idusuario');
+      let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));
+
+      let activeOrders: PreventiveWorkOrdersActiveResponse = await lastValueFrom(this._prevMaintService.getActiveWorkOrders(shortEnc.response.encrypted, 1));
+
+      this.hasError = activeOrders.error;
+      this.errorStr = activeOrders.msg;
+
+      if(!this.hasError){
+        let nonAssociatedOrders: AssociatedWorkOrder[] = [];
+        let associatedOrders = this.dataSource.data;
+
+        activeOrders.response.forEach(order => {
+          let filt = associatedOrders.filter(item => order.IDORDEN == item.IDORDEN);
+          if(filt.length <= 0){
+            let nonAssociatedOrder: AssociatedWorkOrder = {
+              IDORDEN: order.IDORDEN,
+              EQUIPAMIENTO: order.EQUIPAMIENTO,
+              ACTIVADOR: order.ACTIVADOR,
+              CLASIFICACION: order.CLASIFICACION,
+              PRIORIDAD: order.PRIORIDAD,
+              TIPOACTIVADOR: order.TIPOACTIVADOR
+            };
+
+            nonAssociatedOrders.push(nonAssociatedOrder);
+          }
+        });
+
+        this.dataSourceOrders = new MatTableDataSource(nonAssociatedOrders);
+      }
+
+      this.isLoading = false;
+    }catch(error: any){
+      if(error.error == undefined){
+        this.errorStr = 'Ocurrió un error inesperado.';
+      }else if(error.error.msg == undefined){
+        this.errorStr = 'Ocurrió un error inesperado.';
+      }else{
+        this.errorStr = error.error.msg;
+      }
+
+      this.hasError = true;
+      this.isLoading = false;
+    }
+  }
+
+  getPriorityStr(priorityStr: string): string{
+    let priorityFiltered = this.orderPriorities.filter(item => item.value == priorityStr);
+    if(priorityFiltered.length == 0) return "-";
     
+    let priority = priorityFiltered[0];
+    return priority.label;
+  }
+
+  getFontColor(priorityStr: string): string{
+    let priorityFiltered = this.orderPriorities.filter(item => item.value == priorityStr);
+    if(priorityFiltered.length == 0) return "rgb(0, 0, 0)";
+    
+    let priority = priorityFiltered[0];
+    return priority.color;
+  }
+
+  async changeAssociationStatus(newStatus: string, idOrder: number){
+    try{
+      let idUser = localStorage.getItem('idusuario');
+      let idFileEnc = await this._encService.encrypt(this.idFile);
+      let idOrderEnc = await this._encService.encrypt(`${idOrder}`);
+      let formData = new FormData();
+
+      formData.append('id_user', idUser!);
+      formData.append('linea', '1');
+      formData.append('id_file', idFileEnc);
+      formData.append('action', newStatus);
+      formData.append('id_order', idOrderEnc);
+
+      await lastValueFrom(this._gdelService.changeAssociationStatus(formData));
+
+      this.openSnackBar('La asociación del documento se actualizó correctamente');
+      this.getAssociatedOrders();
+    }catch(error: any){
+      if(error.error == undefined){
+        this.openSnackBar('Ocurrió un error inesperado.');
+      }else if(error.error.msg == undefined){
+        this.openSnackBar('Ocurrió un error inesperado.');
+      }else{
+        this.openSnackBar(error.error.msg);
+      }
+    }
+  }
+
+  openSnackBar(msg: string){
+    this._snackBar.open(msg, undefined, {
+      duration: 2500,
+    })
   }
 }

+ 12 - 13
sistema-mantenimiento-front/src/app/components/preventive-maintenance/work-orders/work-orders.component.html

@@ -32,24 +32,23 @@
         </div>
       </nav>
 
-      <div>
-        <div class="is-loading animated fadeIn fast" *ngIf="isLoading">
-          <mat-spinner align="center"></mat-spinner>
-          <h3>Cargando datos ...</h3>
-        </div>
-        <div class="is-loading animated fadeIn fast" *ngIf="!isLoading && hasError">
-          <mat-icon style="transform: scale(4.5);margin: 45px 0;" class="red_primary_font">error</mat-icon>
-          <h3>{{ errorStr }}</h3>
-        </div>
+      <div class="is-loading animated fadeIn fast" *ngIf="isLoading">
+        <mat-spinner align="center"></mat-spinner>
+        <h3>Cargando datos ...</h3>
+      </div>
+
+      <div class="is-loading animated fadeIn fast" *ngIf="!isLoading && hasError">
+        <mat-icon style="transform: scale(4.5);margin: 45px 0;" class="red_primary_font">error</mat-icon>
+        <h3>{{ errorStr }}</h3>
       </div>
 
       <div class="animated fadeIn" *ngIf="!ordersHistoryEnabled">
         <h3 class="ml-20"><b>Su perfil no cuenta con los permisos necesarios para visualizar la información de esta sección.</b></h3>
       </div>
 
-      <div class="override-table">
+      <div class="override-table" [ngClass]="{ hidden: isLoading || hasError }">
         <table mat-table [dataSource]="dataSource!" matSort class="animated fadeIn" 
-        [style.display]="!isLoading && ordersHistoryEnabled ? 'revert' : 'none'">
+        [style.display]="!isLoading && ordersHistoryEnabled && !hasError ? 'revert' : 'none'">
           <ng-container matColumnDef="ID">
             <th mat-header-cell *matHeaderCellDef mat-sort-header>ID</th>
             <td mat-cell *matCellDef="let row">{{ row.IDORDEN }}</td>
@@ -104,7 +103,7 @@
           <ng-container matColumnDef="ACCIONES">
             <th mat-header-cell *matHeaderCellDef>Acciones</th>
             <td mat-cell *matCellDef="let row">
-              <button mat-mini-fab color="primary" class="no-shadow" [matMenuTriggerFor]="menu">
+              <button mat-mini-fab color="primary" class="no-shadow" [matMenuTriggerFor]="menu" [disabled]="row.ESTATUS == 'E'">
                 <mat-icon>settings</mat-icon>
               </button>
               <mat-menu #menu>
@@ -132,7 +131,7 @@
                   <mat-icon>content_copy</mat-icon>
                   <span>Copiar orden</span>
                 </button>
-                <button mat-menu-item>
+                <button mat-menu-item (click)="openActionConfirm(row.IDORDEN)">
                   <mat-icon>delete</mat-icon>
                   <span>Eliminar</span>
                 </button>

+ 44 - 0
sistema-mantenimiento-front/src/app/components/preventive-maintenance/work-orders/work-orders.component.ts

@@ -364,4 +364,48 @@ export class WorkOrdersComponent implements OnInit {
     let priority = priorityFiltered[0];
     return priority.color;
   }
+
+  openActionConfirm(idOrder: number){
+    let dialogRef = this._dialog.open(AlertComponent, {
+      width: '480px',
+      disableClose: true,
+      data: {
+        title: 'Confirmar acción',
+        icon: 'warning',
+        description: `¿Seguro que desea eliminar la orden de trabajo preventivo #${idOrder}?`,
+        description2: 'Esta acción no se puede deshacer'
+      }
+    });
+
+    dialogRef.afterClosed().subscribe(res => {
+      if(res == true){
+        this.deleteWorkOrder(idOrder);
+      }
+    });
+  }
+
+  async deleteWorkOrder(idOrder: number){
+    try{
+      let idUser = localStorage.getItem('idusuario');
+      let idOrderEnc = await this._encService.encrypt(`${idOrder}`);
+      let formData = new FormData();
+
+      formData.append('id_user', idUser!);
+      formData.append('linea', '1');
+      formData.append('id_order', idOrderEnc);
+
+      await lastValueFrom(this._prevMaintService.deleteWorkOrder(formData));
+      
+      this.openSnackBar('La orden se eliminó correctamente.');
+      this.getWorkOrders();
+    }catch(error: any){
+      if(error.error == undefined){
+        this.openSnackBar('Ocurrió un error inesperado.');
+      }else if(error.error.msg == undefined){
+        this.openSnackBar('Ocurrió un error inesperado.');
+      }else{
+        this.openSnackBar(error.error.msg);
+      }
+    }
+  }
 }

+ 14 - 0
sistema-mantenimiento-front/src/app/interfaces/associated-work-orders.interface.ts

@@ -0,0 +1,14 @@
+export interface AssociatedWorkOrdersResponse{
+  error: boolean;
+  msg: string;
+  response: AssociatedWorkOrder[];
+}
+
+export interface AssociatedWorkOrder{
+  IDORDEN: number;
+  EQUIPAMIENTO: string,
+  ACTIVADOR: number;
+  CLASIFICACION: string,
+  PRIORIDAD: string,
+  TIPOACTIVADOR: string
+}

+ 1 - 0
sistema-mantenimiento-front/src/app/interfaces/preventive-work-orders-active.interface.ts

@@ -11,6 +11,7 @@ export interface PreventiveWorkOrdersActive{
     FECHATERMINO: string,
     TIEMPOESTIMADO: number,
     TIEMPOTOTAL: number,
+    CLASIFICACION: string,
     ACTIVADOR: number,
     PRIORIDAD: string,
     TIPOACTIVADOR: string

+ 8 - 0
sistema-mantenimiento-front/src/app/services/document-management/gdel.service.ts

@@ -37,6 +37,10 @@ export class GdelService {
     return this.getQuery(`get-file-access/${id}/${idUser}/${line}`).pipe(map((data: any) => data));
   }
 
+  getAssociatedWorkOrders(id: string, idUser: string, line: number){
+    return this.getQuery(`get-associated-work-orders/${id}/${idUser}/${line}`).pipe(map((data: any) => data));
+  }
+
   uploadTempFile(body: any) {
     return this.postQuery('upload-temp-file', body).pipe(map((data: any) => data));
   }
@@ -57,6 +61,10 @@ export class GdelService {
     return this.postQuery('delete-file', body).pipe(map((data: any) => data));
   }
 
+  changeAssociationStatus(body: any) {
+    return this.postQuery('change-association-status', body).pipe(map((data: any) => data));
+  }
+
   postQuery(query: string, body: any){
     const JWT = `Bearer ${localStorage.getItem('token')}`;
     const URL = `${apiTemp}${query}`;

+ 8 - 1
sistema-mantenimiento-front/src/styles.css

@@ -488,8 +488,15 @@ body {
 }
 
 .is-loading {
+  width: 100%;
+  height: calc(100vh - 385px);
   text-align: center;
-  padding: 100px;
+  padding: 32px;
+  box-sizing: border-box;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
 }
 
 .is-loading mat-spinner {