Jelajahi Sumber

Avances mantenimiento correctivo

Jose Brito 3 bulan lalu
induk
melakukan
d97473e4a0
18 mengubah file dengan 1108 tambahan dan 938 penghapusan
  1. 7 470
      package-lock.json
  2. 1 0
      package.json
  3. 2 0
      src/app/app.module.ts
  4. 1 1
      src/app/components/corrective-maintenance/operations-management/corrective-order-details/corrective-order-details.component.html
  5. 77 78
      src/app/components/corrective-maintenance/operations-management/corrective-order-details/corrective-order-details.component.ts
  6. 181 71
      src/app/components/corrective-maintenance/operations-management/corrective-order-form/corrective-order-form.component.html
  7. 484 299
      src/app/components/corrective-maintenance/operations-management/corrective-order-form/corrective-order-form.component.ts
  8. 1 1
      src/app/components/corrective-maintenance/operations-management/operations-management.component.html
  9. 27 8
      src/app/components/corrective-maintenance/operations-management/operations-management.component.ts
  10. 0 0
      src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.css
  11. 41 0
      src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.html
  12. 23 0
      src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.spec.ts
  13. 258 0
      src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.ts
  14. 2 0
      src/app/components/equipment-management/equipment-documents/equipment-documents.component.css
  15. 1 1
      src/app/components/equipment-management/equipment-documents/equipment-documents.component.html
  16. 1 1
      src/app/components/preventive-maintenance/work-orders/new-work-order/new-work-order.component.html
  17. 0 8
      src/app/components/preventive-maintenance/work-orders/new-work-order/new-work-order.component.ts
  18. 1 0
      src/app/interfaces/personal-managment/employee.interface.ts

+ 7 - 470
package-lock.json

@@ -45,6 +45,7 @@
         "ngx-socket-io": "^4.7.0",
         "quill": "^2.0.2",
         "rxjs": "~7.8.0",
+        "signature_pad": "^5.0.10",
         "tslib": "^2.3.0",
         "vite-compatible-readable-stream": "^3.6.1",
         "xlsx": "^0.18.5",
@@ -310,40 +311,6 @@
         }
       }
     },
-    "node_modules/@angular-devkit/architect/node_modules/chokidar": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
-      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "dependencies": {
-        "readdirp": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 14.16.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@angular-devkit/architect/node_modules/readdirp": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
-      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "engines": {
-        "node": ">= 14.18.0"
-      },
-      "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
     "node_modules/@angular-devkit/build-angular": {
       "version": "19.2.7",
       "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.7.tgz",
@@ -557,24 +524,6 @@
         }
       }
     },
-    "node_modules/@angular-devkit/build-angular/node_modules/chokidar": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
-      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "dependencies": {
-        "readdirp": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 14.16.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
     "node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -611,22 +560,6 @@
         "node": "^10 || ^12 || >=14"
       }
     },
-    "node_modules/@angular-devkit/build-angular/node_modules/readdirp": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
-      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "engines": {
-        "node": ">= 14.18.0"
-      },
-      "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
     "node_modules/@angular-devkit/build-angular/node_modules/semver": {
       "version": "7.7.1",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
@@ -732,40 +665,6 @@
         }
       }
     },
-    "node_modules/@angular-devkit/schematics/node_modules/chokidar": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
-      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "dependencies": {
-        "readdirp": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 14.16.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@angular-devkit/schematics/node_modules/readdirp": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
-      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "engines": {
-        "node": ">= 14.18.0"
-      },
-      "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
     "node_modules/@angular-material-components/datetime-picker": {
       "version": "16.0.1",
       "resolved": "https://registry.npmjs.org/@angular-material-components/datetime-picker/-/datetime-picker-16.0.1.tgz",
@@ -1461,40 +1360,6 @@
         }
       }
     },
-    "node_modules/@angular/cli/node_modules/chokidar": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
-      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "dependencies": {
-        "readdirp": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 14.16.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@angular/cli/node_modules/readdirp": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
-      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "engines": {
-        "node": ">= 14.18.0"
-      },
-      "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
     "node_modules/@angular/cli/node_modules/semver": {
       "version": "7.7.1",
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
@@ -5622,306 +5487,6 @@
         "node": ">=14"
       }
     },
-    "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz",
-      "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz",
-      "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz",
-      "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz",
-      "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-freebsd-arm64": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz",
-      "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-freebsd-x64": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz",
-      "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz",
-      "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz",
-      "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz",
-      "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz",
-      "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz",
-      "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz",
-      "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz",
-      "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-riscv64-musl": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz",
-      "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-s390x-gnu": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz",
-      "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz",
-      "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz",
-      "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz",
-      "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz",
-      "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "peer": true
-    },
-    "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.40.0",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz",
-      "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "peer": true
-    },
     "node_modules/@schematics/angular": {
       "version": "19.2.7",
       "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-19.2.7.tgz",
@@ -5985,40 +5550,6 @@
         }
       }
     },
-    "node_modules/@schematics/angular/node_modules/chokidar": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
-      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "dependencies": {
-        "readdirp": "^4.0.1"
-      },
-      "engines": {
-        "node": ">= 14.16.0"
-      },
-      "funding": {
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
-    "node_modules/@schematics/angular/node_modules/readdirp": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
-      "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "engines": {
-        "node": ">= 14.18.0"
-      },
-      "funding": {
-        "type": "individual",
-        "url": "https://paulmillr.com/funding/"
-      }
-    },
     "node_modules/@sigstore/bundle": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-3.0.0.tgz",
@@ -14432,6 +13963,12 @@
       "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
       "dev": true
     },
+    "node_modules/signature_pad": {
+      "version": "5.0.10",
+      "resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-5.0.10.tgz",
+      "integrity": "sha512-t7rLjpAtxYAIrTHr7EKfY8ulTWF+G/LFMto502a61KZvZNWZSwhTPeLE6171YMDd2sSYRBwQ17ENK5huAi9Rsg==",
+      "license": "MIT"
+    },
     "node_modules/sigstore": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-3.0.0.tgz",

+ 1 - 0
package.json

@@ -47,6 +47,7 @@
     "ngx-socket-io": "^4.7.0",
     "quill": "^2.0.2",
     "rxjs": "~7.8.0",
+    "signature_pad": "^5.0.10",
     "tslib": "^2.3.0",
     "vite-compatible-readable-stream": "^3.6.1",
     "xlsx": "^0.18.5",

+ 2 - 0
src/app/app.module.ts

@@ -439,6 +439,7 @@ import { EquipmentLruUploadComponent } from './components/initial-data-upload/eq
 import { IndividualUploadComponent } from './components/initial-data-upload/individual-upload/individual-upload.component';
 import { MultipleUploadComponent } from './components/initial-data-upload/multiple-upload/multiple-upload.component';
 import { PreviewExcelDocumentComponent } from './components/initial-data-upload/preview-excel-document/preview-excel-document.component';
+import { StaffSelectionComponent } from './components/corrective-maintenance/operations-management/staff-selection/staff-selection.component';
 /*FIN Componentes SAM*/
 
 @NgModule({
@@ -821,6 +822,7 @@ import { PreviewExcelDocumentComponent } from './components/initial-data-upload/
     IndividualUploadComponent,
     MultipleUploadComponent,
     PreviewExcelDocumentComponent,
+    StaffSelectionComponent,
   ],
   imports: [
     SocketIoModule.forRoot(config),

+ 1 - 1
src/app/components/corrective-maintenance/operations-management/corrective-order-details/corrective-order-details.component.html

@@ -47,7 +47,7 @@
     <ul class="m-0">
       @if (workOrder!.PERSONAL_ARR!.length > 0) {
         <li *ngFor="let item of workOrder!.PERSONAL_ARR">
-          {{ item.NAME }} - {{ item.TYPE }}
+          {{ item.NAME }} - {{ item.CANT }} operario(s) requerido(s).
         </li>
       } @else {
         <li><b>Sin personal</b></li>

+ 77 - 78
src/app/components/corrective-maintenance/operations-management/corrective-order-details/corrective-order-details.component.ts

@@ -9,59 +9,10 @@ import { SystemAdminService } from '../../../../services/system-admin.service';
 import { lastValueFrom } from 'rxjs';
 import { CounterLastMeasuresListItem } from '../../../../interfaces/counters-activators.interface';
 import { TempFileInfo } from '../../../../interfaces/temp-file-info.interface';
+import { ResponseDataGetToolsAndSpare, ToolsAndSpare } from '../../../../interfaces/inventory-management/tools-and-spare.interface';
+import { ResourcesService } from '../../../../services/resources.service';
+import { InventoryManagementService } from '../../../../services/inventory-management/inventory-management.service';
 
-interface ToolInfo{
-  ID: string;
-  NOMB: string;
-  MODE: string;
-  CANTDISP: number;
-  TYPE: string;
-  UNIT: string;
-}
-const TOOLS_TMP: ToolInfo[] = [
-  {ID: 'H1', NOMB: 'Pinzas eléctricas', MODE: 'PE-862', CANTDISP: 35, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H2', NOMB: 'Pinzas mecánicas', MODE: 'M985', CANTDISP: 27, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H3', NOMB: 'Pinzas de presión', MODE: 'RG-12', CANTDISP: 30, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H4', NOMB: 'Juego de llaves Allen', MODE: 'ALL88', CANTDISP: 75, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H5', NOMB: 'Extractor de rodamientos', MODE: 'EX-ROD-1500', CANTDISP: 3, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H6', NOMB: 'Kit llaves inglesas', MODE: '5530S', CANTDISP: 7, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H7', NOMB: 'Kit llaves españolas', MODE: '964F', CANTDISP: 8, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H8', NOMB: 'Juego de llaves Torx', MODE: 'TORX3423W', CANTDISP: 42, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H9', NOMB: 'Cautín de lápiz 33W', MODE: '33WCL', CANTDISP: 15, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H10', NOMB: 'Juego de dados milimétricos', MODE: 'DMM450', CANTDISP: 6, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H11', NOMB: 'Juego de dados pulgadas', MODE: 'DIN865', CANTDISP: 9, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H12', NOMB: 'Probador de corriente', MODE: '569', CANTDISP: 33, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H13', NOMB: 'Multímetro', MODE: 'TGH885', CANTDISP: 17, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H14', NOMB: 'Planta generadora para soldadura', MODE: 'PLAGEN-589', CANTDISP: 1, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H15', NOMB: 'Amperímetro de gancho', MODE: 'A0032', CANTDISP: 4, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H16', NOMB: 'Rotomartillo', MODE: '551', CANTDISP: 2, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H17', NOMB: 'Kit taladro inalámbrico', MODE: 'FP581', CANTDISP: 12, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H18', NOMB: 'Kit taládro alámbrico', MODE: 'HG862', CANTDISP: 10, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H19', NOMB: 'Juego de desarmadores', MODE: '8913-KSOA', CANTDISP: 5, TYPE: 'Herramienta', UNIT: 'Pieza'},
-  {ID: 'H20', NOMB: 'Martillo', MODE: 'TS438', CANTDISP: 23, TYPE: 'Herramienta', UNIT: 'Pieza'},
-];
-const SPARE_PARTS_TMP: ToolInfo[] = [
-  {ID: 'S1', NOMB: 'Neumático para NM-16', MODE: 'NM16NEU235', CANTDISP: 45, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S2', NOMB: 'Neumático para NM-22', MODE: 'NM22NEU652', CANTDISP: 51, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S3', NOMB: 'Rodamiento cónico', MODE: 'RC-4265', CANTDISP: 84, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S4', NOMB: 'Rodamiento axial', MODE: 'RA-5130', CANTDISP: 96, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S5', NOMB: 'Rodamiento angular', MODE: 'RN-3541', CANTDISP: 79, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S6', NOMB: 'Grasa 1-310', MODE: 'G1.310', CANTDISP: 9, TYPE: 'Refaccción', UNIT: 'Kilogramo'},
-  {ID: 'S7', NOMB: 'Aceite 10W-40', MODE: 'A10W40', CANTDISP: 16, TYPE: 'Refaccción', UNIT: 'Litro'},
-  {ID: 'S8', NOMB: 'Soldadura de estaño', MODE: 'LDA-913', CANTDISP: 39, TYPE: 'Refaccción', UNIT: 'Metro'},
-  {ID: 'S9', NOMB: 'Soldadura de plata', MODE: 'BDA-516', CANTDISP: 21, TYPE: 'Refaccción', UNIT: 'Metro'},
-  {ID: 'S10', NOMB: 'Pastilla de frenado', MODE: '754SSV', CANTDISP: 25, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S11', NOMB: 'Cable de cobre calibre 0', MODE: 'CC0-884', CANTDISP: 120, TYPE: 'Refaccción', UNIT: 'Metro'},
-  {ID: 'S12', NOMB: 'Rosetas de cable Ethernet', MODE: '165-BFS', CANTDISP: 12, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S13', NOMB: 'Pintura', MODE: '53469', CANTDISP: 250, TYPE: 'Refaccción', UNIT: 'Litro'},
-  {ID: 'S14', NOMB: 'Solvente de pintura', MODE: '2516', CANTDISP: 310, TYPE: 'Refaccción', UNIT: 'Litro'},
-  {ID: 'S15', NOMB: 'Lámina galvanizada', MODE: 'SFAS-320', CANTDISP: 38, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S16', NOMB: 'Botón de freno de emergencia', MODE: 'B-51321', CANTDISP: 14, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S17', NOMB: 'Disco duro de estado sólido 512GB', MODE: 'SSD-512', CANTDISP: 22, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S18', NOMB: 'Mouse óptico', MODE: 'MO1165', CANTDISP: 26, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S19', NOMB: 'Teclado para PC', MODE: '5413', CANTDISP: 24, TYPE: 'Refaccción', UNIT: 'Pieza'},
-  {ID: 'S20', NOMB: 'Cable HDMI 2m', MODE: 'ASD-181', CANTDISP: 6, TYPE: 'Refaccción', UNIT: 'Pieza'},
-];
 @Component({
     selector: 'app-corrective-order-details',
     templateUrl: './corrective-order-details.component.html',
@@ -75,8 +26,8 @@ export class CorrectiveOrderDetailsComponent implements OnInit {
   errorStr: string;
 
   orderPriorities: PriorityInterface[];
-  tools: ToolInfo[];
-  spareParts: ToolInfo[];
+  tools: ToolsAndSpare[];
+  spareParts: ToolsAndSpare[];
 
   workOrder: CorrectiveWorkOrderDetails | null;
 
@@ -86,6 +37,8 @@ export class CorrectiveOrderDetailsComponent implements OnInit {
     private _encService: EncService,
     private _functionsService: FunctionsService,
     private _sysAdminService: SystemAdminService,
+    private _resourcesService: ResourcesService,
+    private _inventoryManagementService: InventoryManagementService,
   ) {
     this.idOrder = '';
     this.isLoading = true;
@@ -93,14 +46,55 @@ export class CorrectiveOrderDetailsComponent implements OnInit {
     this.errorStr = '';
 
     this.orderPriorities = [];
-    this.tools = TOOLS_TMP;
-    this.spareParts = SPARE_PARTS_TMP;
+    this.tools = [];
+    this.spareParts = [];
 
     this.workOrder = null;
   }
 
   ngOnInit(): void {
-    this.getOrderPriorities();
+    this._getToolsAndSpare();
+  }
+
+  private async _getToolsAndSpare () {
+    try{
+      const USER: string = this._resourcesService.getUser();
+      const LINE: number = this._resourcesService.getLineNumber();
+
+      let responseData: ResponseDataGetToolsAndSpare = await lastValueFrom(this._inventoryManagementService.getToolsAndSpare(USER, LINE));
+
+      this.hasError = responseData.error;
+      this.errorStr = responseData.msg;
+
+      if(this.hasError){
+        this.isLoading = false;
+      }else{
+        let toolsArr: ToolsAndSpare[] = [];
+        for(const tool of responseData.response.HERRAMIENTAS){
+          toolsArr.push(tool);
+        }
+
+        let sparePartsArr: ToolsAndSpare[] = [];
+        for(const part of responseData.response.REFACCIONES){
+          sparePartsArr.push(part);
+        }
+
+        this.tools = toolsArr;
+        this.spareParts = sparePartsArr;
+        this.getOrderPriorities();
+      }
+    }catch(error: any){
+      if(error.error == undefined){
+        this.errorStr = 'Ocurrió un error inesperado (9).';
+      }else if(error.error.msg == undefined){
+        this.errorStr = 'Ocurrió un error inesperado (10).';
+      }else{
+        this.errorStr = error.error.msg;
+      }
+      
+      this.hasError = true;
+      this.isLoading = false;
+    }
   }
 
   async getOrderPriorities(){
@@ -164,7 +158,9 @@ export class CorrectiveOrderDetailsComponent implements OnInit {
         order.response.MODELO_EQUIPAMIENTO = `${order.response.MODELO_EQUIPAMIENTO} (${idEquipmentDec})`;
 
         let measureObj = JSON.parse(order.response.MEDIDAS);
-        if(measureObj.length > 0){
+        let measureObjKeys = Object.keys(measureObj);
+        
+        if(measureObjKeys.length > 0){
           let idSWDec = await this._encService.decrypt(measureObj.ID_SERVICIO_WEB);
           let measure: CounterLastMeasuresListItem = {
             ID_MEDIDA: await this._encService.decrypt (measureObj.ID_MEDIDA),
@@ -190,28 +186,36 @@ export class CorrectiveOrderDetailsComponent implements OnInit {
         }
 
         let resourcesArr = JSON.parse(order.response.RECURSOS);
-        let resourcesArrFn: any[] = [];
+        let resourcesSelected: string[] = [];
+
         for(const resource of resourcesArr){
-          let toolFilt = this.tools.filter(item => item.ID == resource.ID);
-          let sparePartFilt = this.spareParts.filter(item => item.ID == resource.ID);
+          if(resource.ID != 'SH'){
+            let idDec = await this._encService.decrypt(resource.ID);
+            resourcesSelected.push(`${idDec}-${resource.TYPE}`);
+          }
+        }
 
-          if(toolFilt.length > 0){
-            let tool = toolFilt[0];
+        let resourcesArrFn: any[] = [];
+        for(const tool of this.tools){
+          let toolID = await this._encService.decrypt(tool.ID);
+          if(resourcesSelected.includes(`${toolID}-T`)){
             resourcesArrFn.push({
-              label: `${tool.NOMB} - ${tool.MODE} (${tool.ID})`,
+              label: `${tool.NOMB} - ${tool.MODE} (${toolID})`,
               type: tool.TYPE,
               unit: tool.UNIT,
-              required: resource.REQ
+              required: tool.CANTDISP
             });
           }
+        }
 
-          if(sparePartFilt.length > 0){
-            let sparePart = sparePartFilt[0];
+        for(const part of this.spareParts){
+          let partID = await this._encService.decrypt(part.ID);
+          if(resourcesSelected.includes(`${partID}-S`)){
             resourcesArrFn.push({
-              label: `${sparePart.NOMB} - ${sparePart.MODE} (${sparePart.ID})`,
-              type: sparePart.TYPE,
-              unit: sparePart.UNIT,
-              required: resource.REQ
+              label: `${part.NOMB} - ${part.MODE} (${partID})`,
+              type: part.TYPE,
+              unit: part.UNIT,
+              required: part.CANTDISP
             });
           }
         }
@@ -219,15 +223,10 @@ export class CorrectiveOrderDetailsComponent implements OnInit {
         let staffArr = JSON.parse(order.response.PERSONAL);
         let staffArrFn: any[] = [];
         for(const item of staffArr){
-          let type = '';
-          if(item.TYPE == 'EQ') type = 'Equipo de trabajo';
-          else if(item.TYPE == 'SU') type = 'Subcontratista';
-          else if(item.TYPE == 'EM') type = 'Empleado';
-
           staffArrFn.push({
             ID: item.ID,
-            TYPE: type,
-            NAME: item.NAME
+            NAME: item.NAME,
+            CANT: item.CANT
           });
         }
 

+ 181 - 71
src/app/components/corrective-maintenance/operations-management/corrective-order-form/corrective-order-form.component.html

@@ -18,7 +18,7 @@ items_container_full_width: screenSize <= 640 }">
 
       <div class="form-order-container" *ngIf="!isLoading && hasError">
         <div class="has-error animated fadeIn fast">
-          <mat-icon class="red_primary_font mb-40" >error</mat-icon>
+          <mat-icon class="red_primary_font mb-40">error</mat-icon>
           <h3>{{ errorStr }}</h3>
         </div>
       </div>
@@ -26,14 +26,14 @@ items_container_full_width: screenSize <= 640 }">
       <div class="form-order-container animated fadeIn pt-2" *ngIf="!isLoading && !hasError">
         <div class="form-column" [formGroup]="orderFormGroup">
           <div class="form-row">
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }" 
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }" 
             *ngIf="action == 'Editar'">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>ID orden de trabajo</mat-label>
                 <input matInput formControlName="idOrderControl">
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Responsable de atender la solicitud</mat-label>
                 <mat-select formControlName="responsibleUserControl">
@@ -53,7 +53,7 @@ items_container_full_width: screenSize <= 640 }">
                 </mat-error>
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Gerencia de seguridad</mat-label>
                 <mat-select formControlName="securityManagementControl">
@@ -61,9 +61,12 @@ items_container_full_width: screenSize <= 640 }">
                     Gerencia de seguridad #{{ management.ID_GERENCIA_SEGURIDAD }}
                   </mat-option>
                 </mat-select>
+                <mat-error *ngIf="orderFormGroup.controls['securityManagementControl'].hasError('required')">
+                  Este campo es requerido.
+                </mat-error>
               </mat-form-field>
             </div>
-            <div class="form-cell C12">
+            <div class="form-cell mt-8 C12">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Descripción de la intervención</mat-label>
                 <textarea matInput rows="4" style="resize: none;" formControlName="interventionDescriptionControl"
@@ -76,20 +79,78 @@ items_container_full_width: screenSize <= 640 }">
                 </mat-error>
               </mat-form-field>
             </div>
-            <div class="form-cell C12">
+            <div class="form-cell mt-8 C12">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Equipamiento relacionado</mat-label>
-                <mat-select formControlName="equipmentControl" (valueChange)="equipmentChange(equipmentSel.value)" #equipmentSel>
+                <!--<mat-select formControlName="equipmentControl" (valueChange)="equipmentChange(equipmentSel.value)" #equipmentSel>
                   <mat-option *ngFor="let equipment of equipments" [value]="equipment.CODIGO">
                     {{ equipment.TIPO }} - {{ equipment.MODELO }}
                   </mat-option>
-                </mat-select>
+                </mat-select>-->
+                <input type="text" matInput formControlName="equipmentControl" [matAutocomplete]="equipmentComplete" 
+                #equipmentInp (blur)="changeEquipmentTable(equipmentInp.value)">
+                <mat-autocomplete #equipmentComplete>
+                  @if(searchingEquipments){
+                    <mat-option><p class="m-0 search-text">Buscando resultados...</p></mat-option>
+                  }
+                  @if(autoCompleteEquipments.length == 0 && !searchingEquipments){
+                    <mat-option><p class="m-0" style="font-weight: 500;">No se encontraron resultados.</p></mat-option>
+                  }
+                  @for(equipment of autoCompleteEquipments; track equipment){
+                    <mat-option [value]="equipment">{{ equipment }}</mat-option>
+                  }
+                </mat-autocomplete>
+                <mat-hint align="end">
+                  <a class="hint-button blue_send_font" (click)="openArborescenceSearch()">Búsqueda gráfica</a>
+                </mat-hint>
                 <mat-error *ngIf="orderFormGroup.controls['equipmentControl'].hasError('required')">
                   Este campo es requerido.
                 </mat-error>
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8 C12">
+              <table mat-table [dataSource]="dataSource!" class="animated fadeIn" style="background: #f8f4f4 !important;">
+                <ng-container matColumnDef="EQUIPO">
+                  <th mat-header-cell *matHeaderCellDef>Equipamiento</th>
+                  <td mat-cell *matCellDef="let row" style="word-break: break-all;max-lines: 5;">
+                    {{ row.TIPO_EQUIPAMIENTO }} - {{ row.MODELO }}
+                  </td>
+                </ng-container>
+                
+                <ng-container matColumnDef="ACCIONES">
+                  <th mat-header-cell *matHeaderCellDef>Acciones</th>
+                  <td mat-cell *matCellDef="let row">
+                    <button mat-mini-fab class="transparent_background gray_dark_font override_no_shadow" [matMenuTriggerFor]="menu">
+                      <mat-icon>more_vert</mat-icon>
+                    </button>
+                    <mat-menu #menu="matMenu">
+                      <button mat-menu-item (click)="openEquipmentDetails(row.CODIGO)">
+                        <mat-icon>visibility</mat-icon>
+                        <span>Detalles del equipamiento</span>
+                      </button>
+                      <button mat-menu-item (click)="openEquipmentArborescence(row.CODIGO)">
+                        <mat-icon>description</mat-icon>
+                        <span>Ficha de detalles</span>
+                      </button>
+                      <button mat-menu-item (click)="openEquipmentDocuments(row.CODIGO)">
+                        <mat-icon>description</mat-icon>
+                        <span>Ver documentació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 centre" colspan="100%">
+                    No se encontró información del equipamiento.
+                  </td>
+                </tr>
+              </table>
+            </div>
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Fecha de inicio de la falla</mat-label>
                 <input matInput formControlName="failStartDateControl" [matDatepicker]="failStartDatePicker">
@@ -97,7 +158,7 @@ items_container_full_width: screenSize <= 640 }">
                 <mat-datepicker #failStartDatePicker></mat-datepicker>
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Tiempo estimado de la solución</mat-label>
                 <input matInput formControlName="solutionTimeControl" (input)="validateTime(solutionTime.value, 'input')" 
@@ -108,7 +169,7 @@ items_container_full_width: screenSize <= 640 }">
                 </mat-error>
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Prioridad</mat-label>
                 <mat-select formControlName="priorityControl">
@@ -120,7 +181,7 @@ items_container_full_width: screenSize <= 640 }">
                 </mat-select>
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline" *ngIf="!loadingCounters">
                 <mat-label>Contador relacionado</mat-label>
                 <mat-select formControlName="counterControl" #counterSelect (valueChange)="counterChange(counterSelect.value)">
@@ -140,8 +201,8 @@ items_container_full_width: screenSize <= 640 }">
               </mat-form-field>
               <mat-progress-bar mode="indeterminate" *ngIf="loadingCounters" class="mb-20"></mat-progress-bar>
             </div>
-            <div class="form-cell C12 mb-20">
-              <table mat-table [dataSource]="symptomsDataSource" *ngIf="!loadingMeasures" class="animated fadeIn">
+            <div class="form-cell mt-8 C12 mb-20">
+              <table mat-table [dataSource]="symptomsDataSource" *ngIf="!loadingMeasures" class="animated fadeIn" style="background: #f8f4f4 !important;">
                 <ng-container matColumnDef="ID">
                   <th mat-header-cell *matHeaderCellDef>#</th>
                   <td mat-cell *matCellDef="let row">{{ row.ID_MEDIDA }}</td>
@@ -195,7 +256,51 @@ items_container_full_width: screenSize <= 640 }">
               </table>
               <mat-progress-bar mode="indeterminate" *ngIf="loadingMeasures" class="animated fadeIn w-100"></mat-progress-bar>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8 C12">
+              <mat-form-field appearance="outline" class="w-100">
+                <mat-label>Especialidades y/o oficios</mat-label>
+                <mat-select multiple formControlName="personalControl" (valueChange)="updateSpecialty(staff.value)" #staff>
+                  <mat-option *ngFor="let specialty of specialties" [value]="specialty.CODIGO_ESPECIALIDAD">
+                    {{ specialty.NOMBRE_ESPECIALIDAD }}
+                  </mat-option>
+                </mat-select>
+              </mat-form-field>
+            </div>
+            <div class="form-cell mt-8 C12">
+              <table mat-table [dataSource]="specialtiesDataSource!" class="animated fadeIn" style="background: #f8f4f4 !important;">
+                <ng-container matColumnDef="ITEM">
+                  <th mat-header-cell *matHeaderCellDef>Especialidad u oficio</th>
+                  <td mat-cell *matCellDef="let row">{{ row.NOMBRE_ESPECIALIDAD }}</td>
+                </ng-container>
+                
+                <ng-container matColumnDef="CANTREQ">
+                  <th mat-header-cell *matHeaderCellDef>Cantidad de operarios requerida</th>
+                  <td mat-cell *matCellDef="let row">
+                    <mat-form-field appearance="outline" style="width: 192px;">
+                      <button mat-mini-fab color="primary" class="override_no_shadow ml-8" matPrefix [disabled]="cantReq.value == '1'" 
+                      (click)="changeReq('rem', row.CODIGO_ESPECIALIDAD)">
+                        <mat-icon>remove</mat-icon>
+                      </button>
+                      <input matInput style="text-align: center;" value="1" [id]="'cant-req-' + row.CODIGO_ESPECIALIDAD" 
+                      (input)="validateCant(cantReq.value, row.CODIGO_ESPECIALIDAD)" #cantReq>
+                      <button mat-mini-fab color="primary" class="override_no_shadow mr-8" matSuffix (click)="changeReq('add', row.CODIGO_ESPECIALIDAD)">
+                        <mat-icon>add</mat-icon>
+                      </button>
+                    </mat-form-field>
+                  </td>
+                </ng-container>
+                  
+                <tr mat-header-row *matHeaderRowDef="specialtiesDisplayedColumns"></tr>
+                <tr mat-row *matRowDef="let row; columns: specialtiesDisplayedColumns;"></tr>
+        
+                <tr class="mat-row" *matNoDataRow>
+                  <td class="mat-cell centre" colspan="100%">
+                    No se ha seleccionado ninguna especialidad u oficio.
+                  </td>
+                </tr>
+              </table>
+            </div>
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Clasificación</mat-label>
                 <input matInput formControlName="clasificationControl" (input)="orderFormGroup.controls['clasificationControl'].markAsTouched()" 
@@ -213,7 +318,7 @@ items_container_full_width: screenSize <= 640 }">
                 </mat-error>
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <!--<div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Personal involucrado</mat-label>
                 <mat-select multiple formControlName="personalControl">
@@ -237,99 +342,104 @@ items_container_full_width: screenSize <= 640 }">
                   Este campo es requerido.
                 </mat-error>
               </mat-form-field>
-            </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            </div>-->
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Tipo de activación</mat-label>
                 <input matInput formControlName="activationType">
               </mat-form-field>
             </div>
-            <div class="form-cell" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
               <mat-form-field class="w-100" appearance="outline">
-                <mat-label>Refacciones y herramientas necesarias</mat-label>
-                <mat-select multiple formControlName="resourcesControl" #resourcesSel (valueChange)="spareAndToolsChange(resourcesSel.value)">
-                  <mat-option value="N">--Ninguna--</mat-option>
-                  <mat-optgroup label="Refacciones">
-                    <mat-option *ngFor="let sparePart of spareParts" [value]="sparePart.ID + '-R'" [disabled]="resourcesSel.value.includes('N')">
-                      {{ sparePart.NOMB }} - {{ sparePart.MODE }}
-                    </mat-option>
-                  </mat-optgroup>
-                  <mat-optgroup label="Herramientas">
-                    <mat-option *ngFor="let tool of tools" [value]="tool.ID + '-H'" [disabled]="resourcesSel.value.includes('N')">
-                      {{ tool.NOMB }} - {{ tool.MODE }}
-                    </mat-option>
-                  </mat-optgroup>
+                <mat-label>Herramientas requeridas</mat-label>
+                <mat-select #toolsSel (valueChange)="toolsChange(toolsSel.value, partsSel.value)" multiple formControlName="toolsControl">
+                  <mat-option value="SH">
+                    Ninguna
+                  </mat-option>
+                  <mat-option *ngFor="let tool of tools" [value]="tool.ID" [disabled]="toolsSel.value.includes('SH')">
+                    <span style="font-weight: 500;">
+                      {{ tool.NOMB }}
+                    </span> - {{ tool.MODE }} <span style="font-weight: 100;">
+                      ({{ tool.CANTDISP }} disponibles)
+                    </span>
+                  </mat-option>
                 </mat-select>
-                <mat-error *ngIf="orderFormGroup.controls['resourcesControl'].hasError('required')">
+                <mat-error *ngIf="orderFormGroup.controls['toolsControl'].hasError('required')">
                   Este campo es requerido.
                 </mat-error>
               </mat-form-field>
             </div>
-            <div class="form-cell C12 mb-20">
-              <table mat-table [dataSource]="resourcesDataSource" class="animated fadeIn">
-                <ng-container matColumnDef="ID">
-                  <th mat-header-cell *matHeaderCellDef>#</th>
-                  <td mat-cell *matCellDef="let row">{{ row.ID }}</td>
-                </ng-container>
-                
-                <ng-container matColumnDef="NOMB">
-                  <th mat-header-cell *matHeaderCellDef>Nombre</th>
-                  <td mat-cell *matCellDef="let row">{{ row.NOMB }}</td>
-                </ng-container>
-                
-                <ng-container matColumnDef="MODE">
-                  <th mat-header-cell *matHeaderCellDef>Modelo</th>
-                  <td mat-cell *matCellDef="let row">{{ row.MODE }}</td>
+            <div class="form-cell mt-8" [ngClass]="{ C03: screenSize > 1460, C06: screenSize <= 1460 && screenSize > 840, C12: screenSize <= 840 }">
+              <mat-form-field class="w-100" appearance="outline">
+                <mat-label>Refacciones requeridas</mat-label>
+                <mat-select #partsSel (valueChange)="toolsChange(toolsSel.value, partsSel.value)" multiple formControlName="sparePartsControl">
+                  <mat-option value="SH">
+                    Ninguna
+                  </mat-option>
+                  <mat-option *ngFor="let item of spareParts" [value]="item.ID" [disabled]="partsSel.value.includes('SH')">
+                    <span style="font-weight: 500;">
+                      {{ item.NOMB }}
+                    </span> - {{ item.MODE }} <span style="font-weight: 100;">
+                      ({{ item.CANTDISP }} disponibles)
+                    </span>
+                  </mat-option>
+                </mat-select>
+                <mat-error *ngIf="orderFormGroup.controls['sparePartsControl'].hasError('required')">
+                  Este campo es requerido.
+                </mat-error>
+              </mat-form-field>
+            </div>
+            <div class="form-cell mt-8 C12 mb-20">
+              <table mat-table [dataSource]="toolsDataSource!" class="animated fadeIn" style="background: #f8f4f4 !important;">
+                <ng-container matColumnDef="ITEM">
+                  <th mat-header-cell *matHeaderCellDef>Herramienta / Refacción</th>
+                  <td mat-cell *matCellDef="let row">{{ row.NOMB }} - {{ row.MODE }}</td>
                 </ng-container>
-                
-                <ng-container matColumnDef="TYPE">
+
+                <ng-container matColumnDef="TIPO">
                   <th mat-header-cell *matHeaderCellDef>Tipo</th>
                   <td mat-cell *matCellDef="let row">{{ row.TYPE }}</td>
                 </ng-container>
-                
+
                 <ng-container matColumnDef="CANTDISP">
                   <th mat-header-cell *matHeaderCellDef>Cantidad disponible</th>
                   <td mat-cell *matCellDef="let row">{{ row.CANTDISP }} {{ row.UNIT }}(s)</td>
                 </ng-container>
-                
-                <ng-container matColumnDef="CANTREC">
+
+                <ng-container matColumnDef="CANTNEC">
                   <th mat-header-cell *matHeaderCellDef>Cantidad requerida</th>
                   <td mat-cell *matCellDef="let row">
-                    <input type="hidden" [id]="'cant-req-' + row.ID" value="1" #cantReq>
-                    <div class="required-resource">
-                      <button mat-icon-button [disabled]="cantReq.value == '1'" (click)="changeCantReq('remove', row.ID, row.CANTDISP)">
+                    <mat-form-field appearance="outline" style="width: 192px;">
+                      <button mat-mini-fab color="primary" class="override_no_shadow ml-8" matPrefix [disabled]="cantReq.value == '1'" 
+                      (click)="changeReq('rem', row.ID)">
                         <mat-icon>remove</mat-icon>
                       </button>
-                      <p matRipple (click)="openSpecificRequiredNumber(row.ID, row.CANTDISP)">{{ cantReq.value }}</p>
-                      <button mat-icon-button (click)="changeCantReq('add', row.ID, row.CANTDISP)">
+                      <input matInput style="text-align: center;" value="1" [id]="'cant-req-' + row.ID" (input)="validateCant(cantReq.value, row.ID)" #cantReq>
+                      <button mat-mini-fab color="primary" class="override_no_shadow mr-8" matSuffix (click)="changeReq('add', row.ID)">
                         <mat-icon>add</mat-icon>
                       </button>
-                    </div>
+                    </mat-form-field>
                   </td>
                 </ng-container>
-                
-                <ng-container matColumnDef="CANTREST">
+
+                <ng-container matColumnDef="CANTRES">
                   <th mat-header-cell *matHeaderCellDef>Cantidad restante</th>
-                  <td mat-cell *matCellDef="let row">
-                    <input type="hidden" [id]="'cant-rest-' + row.ID" value="1" #cantRest>
-                    <p style="font-weight: 500;" [ngClass]="{green_primary_font: intval(cantRest.value) > 0, amber_primary_font: intval(cantRest.value) == 0,
-                    red_primary_font: intval(cantRest.value) < 0}">
-                      {{ cantRest.value }} {{ row.UNIT }}(s)
-                    </p>
+                  <td mat-cell *matCellDef="let row" [ngClass]="{ green_primary_font: isPositive(row.CANTDISP, row.ID), red_primary_font: !isPositive(row.CANTDISP, row.ID) }">
+                    {{ calcRest(row.CANTDISP, row.ID) }} {{ row.UNIT }}(s)
                   </td>
                 </ng-container>
                   
-                <tr mat-header-row *matHeaderRowDef="resourcesDisplayedColumns"></tr>
-                <tr mat-row *matRowDef="let row; columns: resourcesDisplayedColumns;"></tr>
+                <tr mat-header-row *matHeaderRowDef="toolsDisplayedColumns"></tr>
+                <tr mat-row *matRowDef="let row; columns: toolsDisplayedColumns;"></tr>
         
                 <tr class="mat-row" *matNoDataRow>
                   <td class="mat-cell centre" colspan="100%">
-                    No se ha seleccionado ninguna herramiento o refacción.
+                    No se ha seleccionado ninguna herramienta o refacción.
                   </td>
                 </tr>
               </table>
             </div>
-            <div class="form-cell w-100" [ngClass]="{ attached_horizontal: screenSize > 960, attached_vertical: screenSize <= 960 }">
+            <div class="form-cell mt-8 C12" [ngClass]="{ attached_horizontal: screenSize > 960, attached_vertical: screenSize <= 960 }">
               <div class="attached-container" [ngClass]="{ ac_horizontal: screenSize > 960, ac_vertical: screenSize <= 960 }">
                 <div class="buttons-container" [ngClass]="{ bc_horizontal: screenSize > 960, bc_vertical: screenSize <= 960 }">
                   <div class="attach-button raised-button-background" (click)="openFileUploader()" matRipple [ngClass]="{

File diff ditekan karena terlalu besar
+ 484 - 299
src/app/components/corrective-maintenance/operations-management/corrective-order-form/corrective-order-form.component.ts


+ 1 - 1
src/app/components/corrective-maintenance/operations-management/operations-management.component.html

@@ -141,7 +141,7 @@
                   <mat-icon>change_circle</mat-icon>
                   <span>Traspasar orden</span>
                 </button>
-                <button mat-menu-item *ngIf="row.ESTADO == 'Pendiente'" (click)="openConfirmDialog('APR', row.ID_ORDEN)">
+                <button mat-menu-item *ngIf="row.ESTADO == 'Pendiente'" (click)="openStaffSelectionDialog(row.ID_ORDEN)">
                   <mat-icon>done</mat-icon>
                   <span>Aprobar orden</span>
                 </button>

+ 27 - 8
src/app/components/corrective-maintenance/operations-management/operations-management.component.ts

@@ -29,6 +29,7 @@ import { NoMeasuresOrderCloseValidationComponent } from './no-measures-order-clo
 import { NoMeasuresOrderReportComponent } from './no-measures-order-report/no-measures-order-report.component';
 import { GdelService } from '../../../services/gdel.service';
 import { DOCUMENT } from '@angular/common';
+import { StaffSelectionComponent } from './staff-selection/staff-selection.component';
 
 const ID_MODULE = "S002V01M09GMCO";
 @Component({
@@ -513,6 +514,25 @@ export class OperationsManagementComponent implements OnInit {
     }
   }
 
+  async openStaffSelectionDialog(idOrder: string){
+    let idOrderStr = idOrder.replace('Orden #', '').trim();
+    let idOrderEnc = await this._encService.encrypt(idOrderStr);
+    let dialogRef = this._dialog.open(StaffSelectionComponent, {
+      disableClose: true,
+      width: '540px',
+      maxWidth: '540px',
+      data: {
+        idOrder: idOrderEnc,
+      }
+    });
+
+    dialogRef.afterClosed().subscribe(res => {
+      if(res != null && res != undefined && res != ''){
+        this.approveWorkOrder(idOrderEnc, res);
+      }
+    });
+  }
+
   openConfirmDialog(action: string, idOrder: string){
     let idOrderStr = idOrder.replace('Orden #', '').trim();
     let actionStr = '';
@@ -548,7 +568,6 @@ export class OperationsManagementComponent implements OnInit {
             this.deleteWorkOrder(idOrder);
           break;
           case 'APR':
-            this.approveWorkOrder(idOrder);
           break;
         }
       }
@@ -580,20 +599,20 @@ export class OperationsManagementComponent implements OnInit {
     }
   }
 
-  private async approveWorkOrder(idOrder: string){
+  private async approveWorkOrder(idOrder: string, config: string){
     try{
-      let idOrderStr = idOrder.replace('Orden #', '').trim();
-      let idOrderEnc = await this._encService.encrypt(idOrderStr);
       let idUser = localStorage.getItem('idusuario')!;
       let formData = new FormData();
 
       formData.append('id_user', idUser);
       formData.append('linea', '1');
-      formData.append('id_order', idOrderEnc);
+      formData.append('id_order', idOrder);
+      formData.append('config', config);
+      console.log(formData);
 
       await lastValueFrom(this._correctiveMaintenanceService.approveWorkOrder(formData));
-      this._resourcesService.openSnackBar('La orden de trabajo se aprobó correctamente.');
-      this.getworkOrders(false);
+      /*this._resourcesService.openSnackBar('La orden de trabajo se aprobó correctamente.');
+      this.getworkOrders(false);*/
     }catch(error: any){
       if(error.error == undefined){
         this._resourcesService.openSnackBar('Ocurrió un error inesperado (14).');
@@ -730,7 +749,7 @@ export class OperationsManagementComponent implements OnInit {
       if(res != null && res != undefined && res != ''){
         this.validateNoMeasuresOrder(idOrder, res);
       }
-    })
+    });
   }
 
   private async validateNoMeasuresOrder(idOrder: string, dataEnc: string){

+ 0 - 0
src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.css


+ 41 - 0
src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.html

@@ -0,0 +1,41 @@
+<h1 mat-dialog-title class="prevent-select">Seleccionar operarios</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="has-error animated fadeIn pt-64" *ngIf="!isLoading && hasError">
+    <mat-icon class="red_primary_font">error</mat-icon>
+    <h2>{{ errorStr }}</h2>
+  </div>
+  <div class="dialog_details_column animated fadeIn" *ngIf="!isLoading && !hasError" [formGroup]="formGroup">
+    @for (specialtyKey of staffSpecialtiesMap.keys(); track $index) {
+      <p><b>{{ specialtyKey }} - {{ staffSpecialtiesMap.get(specialtyKey) }}</b></p>
+      @for (specialtyOperaryID of staffOperariesMap.get(specialtyKey); track $index) {
+        <mat-form-field appearance="outline" class="w-100 animated fadeIn mt-8">
+          <mat-label>Seleccionar empleado o subcontratista</mat-label>
+          <mat-select [formControlName]="specialtyOperaryID">
+            @for (employee of employees; track $index) {
+              @if (employee.SPECIALITY_ARR != undefined && employee.SPECIALITY_ARR.includes(specialtyKey)) {
+                <mat-option [value]="employee.ID_EMPLOYEE + '|E'" [disabled]="isSelected(employee.ID_EMPLOYEE + '|E')">
+                  {{ employee.NAME }} - Empleado
+                </mat-option>
+              }
+            }
+            @for (employee of subcontratists; track $index) {
+              @if (employee.SPECIALITY_ARR != undefined && employee.SPECIALITY_ARR.includes(specialtyKey)) {
+                <mat-option [value]="employee.ID_EMPLOYEE + '|S'">
+                  {{ employee.NAME }} - Subcontratista
+                </mat-option>
+              }
+            }
+          </mat-select>
+        </mat-form-field>
+      }
+    }
+  </div>
+</div>
+<div mat-dialog-actions align="end">
+  <button mat-button mat-dialog-close>Cancelar</button>
+  <button mat-button [disabled]="formGroup.invalid || isLoading || hasError" (click)="saveConfig()">Continuar</button>
+</div>

+ 23 - 0
src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { StaffSelectionComponent } from './staff-selection.component';
+
+describe('StaffSelectionComponent', () => {
+  let component: StaffSelectionComponent;
+  let fixture: ComponentFixture<StaffSelectionComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [StaffSelectionComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(StaffSelectionComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 258 - 0
src/app/components/corrective-maintenance/operations-management/staff-selection/staff-selection.component.ts

@@ -0,0 +1,258 @@
+import { DOCUMENT } from '@angular/common';
+import { Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { ResourcesService } from '../../../../services/resources.service';
+import { CorrectiveWorkOrderDetailsResponse } from '../../../../interfaces/corrective-maintenance.interface';
+import { lastValueFrom } from 'rxjs';
+import { CorrectiveMaintenanceService } from '../../../../services/corrective-maintenance.service';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { EncService } from '../../../../services/enc.service';
+import { EmployeeService } from '../../../../services/personal-management/employee.service';
+import { EmployeesListItem, EmployeesListResponse } from '../../../../interfaces/personal-managment/employee.interface';
+import { SubcontratistService } from '../../../../services/personal-management/subcontratist.service';
+import { SubcontratistItem, SubcontratistsResponse } from '../../../../interfaces/personal-managment/subcontratists.interface';
+
+@Component({
+  selector: 'app-staff-selection',
+  standalone: false,
+  templateUrl: './staff-selection.component.html',
+  styleUrl: './staff-selection.component.css'
+})
+export class StaffSelectionComponent implements OnInit {
+  isLoading: boolean;
+  hasError: boolean;
+  errorStr: string;
+  staffSpecialtiesMap: Map<string, string>;
+  staffOperariesMap: Map<string, string[]>;
+  employees: EmployeesListItem[];
+  subcontratists: EmployeesListItem[];
+
+  formGroup: FormGroup;
+
+  constructor(
+    @Inject(MAT_DIALOG_DATA) private _data: any,
+    @Inject(DOCUMENT) private _document: Document,
+    private _resourcesService: ResourcesService,
+    private _dialogRef: MatDialogRef<StaffSelectionComponent>,
+    private _correctiveMaintenanceService: CorrectiveMaintenanceService,
+    private _encService: EncService,
+    private _employeeService: EmployeeService,
+    private _subcontratistService: SubcontratistService,
+  ) {
+    this.isLoading = true;
+    this.hasError = true;
+    this.errorStr = "";
+    this.staffSpecialtiesMap = new Map();
+    this.staffOperariesMap = new Map();
+    this.employees = [];
+    this.subcontratists = [];
+
+    this.formGroup = new FormGroup({});
+  }
+
+  ngOnInit(): void {
+    if(this._data.idOrder != null && this._data.idOrder != undefined){
+      this.getOrderDetails();
+    }else{
+      this._resourcesService.openSnackBar('No se envió el ID de la orden de mantenimiento.');
+      this._dialogRef.close();
+    }
+  }
+
+  private async getOrderDetails(){
+    try{
+      let idUser = localStorage.getItem('idusuario')!;
+      let order: CorrectiveWorkOrderDetailsResponse = await lastValueFrom(this._correctiveMaintenanceService.getWorkOrder(
+        this._data.idOrder,
+        idUser,
+        1
+      ));
+
+      this.hasError = order.error;
+      this.errorStr = order.msg;
+
+      if(this.hasError){
+        this.isLoading = false;
+      }else{
+        let staffArr = JSON.parse(order.response.PERSONAL);
+        for(const specialty of staffArr){
+          let idDec = await this._encService.decrypt(specialty.ID);
+          this.staffSpecialtiesMap.set(idDec, specialty.NAME);
+
+          let operaries: string[] = this.staffOperariesMap.get(idDec) === undefined ? [] : this.staffOperariesMap.get(idDec)!;
+          for(let i = 0; i < specialty.CANT; i++){
+            let index = `${idDec}${i}Control`;
+            this.formGroup.addControl(index, new FormControl('', Validators.required));
+            
+            operaries.push(index);
+          }
+
+          this.staffOperariesMap.set(idDec, operaries);
+        }
+
+        this.getEmployees();
+      }
+    }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;
+      }
+    }
+  }
+
+  private async getEmployees(){
+    try{
+      let idUser = localStorage.getItem('idusuario')!;
+      let employees: EmployeesListResponse = await lastValueFrom(this._employeeService.getConsultOfEmployees(idUser, 1));
+
+      this.hasError = employees.error;
+      this.errorStr = employees.msg;
+
+      if(this.hasError){
+        this.isLoading = false;
+      }else{
+        let employeesArr: EmployeesListItem[] = [];
+        let subcontratistsEmployees: EmployeesListItem[] = [];
+        
+        for(const employee of employees.response){
+          let idEmployee = await this._encService.decrypt(employee.ID_EMPLOYEE);
+          employee.NAME = `${employee.NAME} (${idEmployee})`;
+
+          if(employee.CONTRACT_TYPE == 'Interno' && employee.STATUS == 'Activo'){
+            let specialtiesArr = JSON.parse(employee.SPECIALITY);
+            let specialtiesStrArr: string[] = [];
+
+            for(const specialtyStr of specialtiesArr){
+              let specialtyEnc = await this._encService.isEncrypted(specialtyStr);
+              let specialtyDec = specialtyEnc ? await this._encService.decrypt(specialtyStr) : specialtyStr;
+              let specialtyArr = specialtyDec.split(" - ");
+              let specialtyInd = specialtyArr[0];
+
+              specialtiesStrArr.push(specialtyInd);
+            }
+
+            employee.SPECIALITY_ARR = specialtiesStrArr;
+            employeesArr.push(employee);
+          }else if(employee.CONTRACT_TYPE == 'Subcontratista'){
+            subcontratistsEmployees.push(employee);
+          }
+        }
+
+        this.employees = employeesArr;
+        this.getSubcontratists(subcontratistsEmployees);
+      }
+    }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;
+      }
+    }
+  }
+
+  private async getSubcontratists(subcontratistsEmployees: EmployeesListItem[]){
+    try{
+      let idUser = localStorage.getItem('idusuario')!;
+      let subcontratists: SubcontratistsResponse = await lastValueFrom(this._subcontratistService.getConsultOfSubcontratists(idUser, 1));
+
+      this.hasError = subcontratists.error;
+      this.errorStr = subcontratists.msg;
+
+      if(!this.hasError){
+        let subcontratistsArr: SubcontratistItem[] = [];
+        for(const subcontratist of subcontratists.response){
+          subcontratist.ID_SUBCONTRATIST = await this._encService.decrypt(subcontratist.ID_SUBCONTRATIST);
+          subcontratistsArr.push(subcontratist);
+        }
+
+        let subcontratistEmployeesArr: EmployeesListItem[] = [];
+        for(const employee of subcontratistsEmployees){
+          let idSubcontratistDec = await this._encService.decrypt(employee.ID_SUBCONTRATISTA!);
+          let subcontratistFilt = subcontratistsArr.filter(item => item.ID_SUBCONTRATIST == idSubcontratistDec);
+
+          if(subcontratistFilt.length > 0){
+            let specialtiesArr = JSON.parse(employee.SPECIALITY);
+            let specialtiesStrArr: string[] = [];
+
+            for(const specialtyStr of specialtiesArr){
+              let specialtyEnc = await this._encService.isEncrypted(specialtyStr);
+              let specialtyDec = specialtyEnc ? await this._encService.decrypt(specialtyStr) : specialtyStr;
+              let specialtyArr = specialtyDec.split(" - ");
+              let specialtyInd = specialtyArr[0];
+
+              specialtiesStrArr.push(specialtyInd);
+            }
+            
+            employee.SPECIALITY_ARR = specialtiesStrArr;
+            employee.NAME = `${subcontratistFilt[0].NAME} - ${employee.NAME}`;
+            subcontratistEmployeesArr.push(employee);
+          }
+        }
+
+        this.subcontratists = subcontratistEmployeesArr;
+      }
+
+      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;
+      }
+    }
+  }
+
+  isSelected(value: string): boolean{
+    let isSelected = false;
+
+    for(const key in this.formGroup.controls){
+      let control = this.formGroup.controls[key];
+      let selection = control.value;
+
+      if(selection != null && selection != undefined && selection != '' && selection == value){
+        isSelected = true;
+      }
+    }
+
+    return isSelected;
+  }
+
+  async saveConfig(){
+    let config = [];
+    for(const key of this.staffOperariesMap.keys()){
+      let operaries = this.staffOperariesMap.get(key)!;
+      let operariesConfig = [];
+
+      for(const control of operaries){
+        let controlValue = this.formGroup.controls[control].value;
+        let valueArr = controlValue.split('|');
+
+        if(valueArr.length > 1){
+          let operaryConfig = {
+            ID: valueArr[0],
+            TYPE: valueArr[1],
+          };
+
+          operariesConfig.push(operaryConfig);
+        }
+      }
+
+      let specialtyConfig = {
+        SPECIALTY: await this._encService.encrypt(key),
+        STAFF: operariesConfig
+      };
+
+      config.push(specialtyConfig);
+    }
+
+    let configStr = JSON.stringify(config);
+    this._dialogRef.close(configStr);
+  }
+}

+ 2 - 0
src/app/components/equipment-management/equipment-documents/equipment-documents.component.css

@@ -6,6 +6,8 @@
   align-items: center;
   justify-content: space-between;
   margin-bottom: 4px;
+  padding: 8px 0;
+  box-sizing: border-box;
 }
 
 .equipment-document p{

+ 1 - 1
src/app/components/equipment-management/equipment-documents/equipment-documents.component.html

@@ -1,4 +1,4 @@
-<h1 mat-dialog-title class="prevent-select center_text">{{ equipment }}</h1>
+<h1 mat-dialog-title class="prevent-select center_text" style="overflow-wrap: anywhere;">{{ equipment }}</h1>
 <div mat-dialog-content class="prevent-select">
   <a id="download" class="hidden"></a>
   <div class="equipment-document" *ngFor="let document of documents">

+ 1 - 1
src/app/components/preventive-maintenance/work-orders/new-work-order/new-work-order.component.html

@@ -119,7 +119,7 @@
               <mat-form-field class="w-100" appearance="outline">
                 <mat-label>Equipamiento relacionado</mat-label>
                 <input type="text" matInput formControlName="equipmentControl" [matAutocomplete]="equipmentComplete" 
-                #equipment (blur)="changeEquipmentTable(equipment.value)">
+                #equipmentInp (blur)="changeEquipmentTable(equipmentInp.value)">
                 <mat-autocomplete #equipmentComplete>
                   @if(searchingEquipments){
                     <mat-option><p class="m-0 search-text">Buscando resultados...</p></mat-option>

+ 0 - 8
src/app/components/preventive-maintenance/work-orders/new-work-order/new-work-order.component.ts

@@ -529,14 +529,6 @@ export class NewWorkOrderComponent implements OnInit {
         this.orderFormGroup.controls['inmTimeControl'].setValue(`${order.response.TIEMPOINMOESTI}`);
         this.orderFormGroup.controls['clasificationControl'].setValue(`${order.response.CLASIFICACION}`);
 
-        let resources = JSON.parse(order.response.RECURSOS);
-        let resCont = 0;
-
-        //PENDIENTE INCLUIR STOCK
-        /*this.orderFormGroup.controls['toolsControl'].setValue(['SH']);
-        this.orderFormGroup.controls['sparePartsControl'].setValue(['SH']);
-        this.toolsChange(['SH'], ['SH']);*/
-
         if(order.response.DOCUMENTOS != null){
           let attached = JSON.parse(order.response.DOCUMENTOS!);
           attached.forEach((document: TempFileInfo) => {

+ 1 - 0
src/app/interfaces/personal-managment/employee.interface.ts

@@ -122,6 +122,7 @@ export interface EmployeesListItem{
   ID_EMPLOYEE: string | string;
   NAME: string;
   CONTRACT_TYPE: string;
+  ID_SUBCONTRATISTA: string | null;
   SPECIALITY: string;
   SPECIALITY_ARR?: string[];
   TEAM_ID: string | null;

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini