145 Commits

Author SHA1 Message Date
eithan 66272ff3ef Merge pull request 'Actualizar 'components/responsable/CuestionarioResponsable2.vue'' (#4) from eithan-patch-1 into master
Reviewed-on: #4
2025-03-10 15:03:41 -06:00
eithan 5b5c2d24ac Merge branch 'master' into eithan-patch-1 2025-03-10 15:03:05 -06:00
eithan 549e0dbc90 Actualizar 'components/responsable/CuestionarioResponsable2.vue' 2025-03-10 15:02:04 -06:00
eithan 98022ec605 Merge pull request 'Actualizar 'components/alumno/cuestionario2/FullCuestionario.vue'' (#3) from eithan-patch-1 into master
Reviewed-on: #3
2025-03-10 14:49:21 -06:00
eithan 3a560255dd Merge branch 'master' into eithan-patch-1 2025-03-10 14:49:07 -06:00
eithan 4ff5ef55fa Actualizar 'components/alumno/cuestionario2/FullCuestionario.vue'
limite de cuestionarios alumnos al 200
2025-03-10 14:48:50 -06:00
eithan 1b3088ed9f Merge pull request 'eithan-patch-1' (#2) from eithan-patch-1 into master
Reviewed-on: #2
2025-03-10 14:35:58 -06:00
eithan 96c387420e Actualizar 'components/alumno/cuestionario2/FullCuestionario.vue'
500 en las respuestas del cuestionairo alumno
2025-03-10 14:35:24 -06:00
eithan 02cb974be1 Actualizar 'components/responsable/CuestionarioResponsable2.vue'
limite de cuestionario responsable 2 a 500 caracteres en preguntas abiertas
2025-03-10 14:31:51 -06:00
eithan 728922136a Merge pull request 'dev' (#1) from dev into master
Reviewed-on: #1
2025-02-21 11:57:52 -06:00
Your Name 551c1518c0 props programa cuestionario, send token in cuestionarios, api a produccion 2025-02-21 11:56:14 -06:00
Your Name b39250a334 logout if localstorage 2025-02-21 10:25:25 -06:00
Your Name 87bfddff5a cuestionario validado, alerta de respuestas faltantes, ocultar preguntas, v2 en reportes 2025-02-17 09:39:26 -06:00
Your Name 6365291fe4 send twice questionnaries fixed 2025-02-14 12:15:32 -05:00
eithan 8d03b74cac Actualizar 'nuxt.config.js' 2025-02-13 16:33:59 -06:00
Your Name 019b9a3fa5 cuestionarios2 validation 2025-02-13 17:01:34 -05:00
Your Name 68e0787217 using idcuestionario2 in every render validation 2025-02-13 13:55:27 -05:00
Tu Nombre 0015f9bd03 devcontainer, dockerfile 2025-02-10 10:55:25 -06:00
Tu Nombre c514357032 preguntas verificadas 2025-01-30 15:27:40 -06:00
Tu Nombre cf286c9788 validar cuestionario de responsable 2 2025-01-30 09:57:46 -06:00
Tu Nombre 5eb9ca0d74 validar cuestionario de responsable 2025-01-30 09:54:08 -06:00
Tu Nombre 99f409c7c4 cuestionarios de pruebas 2025-01-28 13:09:02 -06:00
Lemuel Márquez a3e85f5a76 pruebas 2023-07-25 16:24:00 -06:00
Lemuel Márquez 5fd99341d3 Merge branch 'master' into dev 2023-07-25 16:22:45 -06:00
xXpuma99Xx 61fefbc32b a 2022-03-28 13:03:21 -06:00
xXpuma99Xx 34f3097de5 mensajes nuevos 2022-03-28 12:32:43 -06:00
xXpuma99Xx 66d185c8d7 correciones 2022-01-17 18:57:11 -06:00
xXpuma99Xx 3efe44f62c servidor producción 2022-01-02 19:37:17 -06:00
xXpuma99Xx 52d75e97b7 upgrade 2022-01-02 19:35:24 -06:00
xXpuma99Xx b52986360f activo programa 2022-01-02 19:34:25 -06:00
xXpuma99Xx 72c159f83f errores pequeños en editar corregidos 2022-01-01 14:06:34 -06:00
xXpuma99Xx 41c6a71698 editar servicio listo 2022-01-01 13:50:39 -06:00
xXpuma99Xx 931c2af40b uploads listos 2021-12-31 21:49:25 -06:00
xXpuma99Xx b2379e779e antes de cambiar uploads 2021-12-31 21:26:39 -06:00
xXpuma99Xx eeed183fda Merge branch 'master' of https://repositorio.acatlan.unam.mx/CIDWA/servicio_social_front 2021-12-31 19:14:01 -06:00
xXpuma99Xx 1c0ff7827f actualizacion paquetes 2021-12-31 19:13:34 -06:00
puma99 ccdb091a62 no restriccion en fechas de casos especiales 2021-12-10 14:22:02 -06:00
puma99 ce45a65b6d nombre de responsable y correo 2021-12-08 11:16:33 -06:00
xXpuma99Xx c94413cbb5 merge error corregidos versión producción 2021-12-07 13:52:25 -06:00
xXpuma99Xx 925e657ba1 correciones ortográficas 2021-12-07 13:31:55 -06:00
xXpuma99Xx 7fb5507bdb correciones ortográficas 2021-12-07 13:28:59 -06:00
xXpuma99Xx 25d496b10d ultimas correcciones 2021-12-07 13:18:49 -06:00
xXpuma99Xx 2309b9fb3e correciones pequeñas 2021-12-07 10:40:29 -06:00
xXpuma99Xx 79ea15fb9b servidor pruebas 2021-12-07 09:59:06 -06:00
xXpuma99Xx d2d2a8573d caso especial listo 2021-12-06 19:04:55 -06:00
xXpuma99Xx 0a8c860492 responsable listo 2021-12-06 18:51:08 -06:00
xXpuma99Xx bbb0f58602 admin casi terminado 2021-12-06 14:59:19 -06:00
xXpuma99Xx 97dfcfac4f pruebas 2021-11-30 12:23:33 -06:00
xXpuma99Xx cb2cab6062 pruebas 2021-11-30 12:22:17 -06:00
xXpuma99Xx afc119fa8b faltan cuestionario de alumno y editar servicio 2021-11-30 12:15:49 -06:00
xXpuma99Xx 24d02a71e6 aparentemente todo listo 2021-11-29 13:07:16 -06:00
xXpuma99Xx 772412f6a4 informe global listo 2021-11-29 10:15:45 -06:00
xXpuma99Xx e2b2da7a2e carta termino y cuestionario listos 2021-11-29 09:40:07 -06:00
xXpuma99Xx 97dbd5878d hasta registro listo 2021-11-29 09:16:55 -06:00
xXpuma99Xx 7bd50bf3d4 pre termino alumno listo para pruebas 2021-11-29 03:25:35 -06:00
xXpuma99Xx b962628dde barra progreso 2021-11-29 02:54:52 -06:00
xXpuma99Xx 813e251593 mensajes 2021-11-29 02:44:41 -06:00
xXpuma99Xx 302ab76f2c info servicio alumno 2021-11-29 02:18:57 -06:00
xXpuma99Xx 7c9c3900c0 confirmar pre registro listo 2021-11-29 01:15:23 -06:00
xXpuma99Xx f97a8a0068 crear servicio listo 2021-11-29 00:46:18 -06:00
xXpuma99Xx a50122e61f admin responsable listo 2021-11-28 23:28:05 -06:00
xXpuma99Xx 5f66fecde6 casos especiales proceso listo 2021-11-28 22:12:50 -06:00
xXpuma99Xx 8bded6e7e9 listo prueba caso especial, falta editar caso especial 2021-11-28 20:54:01 -06:00
xXpuma99Xx 3a3bf26918 nuevo caso especial 2021-11-28 19:04:47 -06:00
xXpuma99Xx 7e59f8f381 casos especiales tabla 2021-11-28 12:31:47 -06:00
xXpuma99Xx 8f2b3eaadd cuestionario responsable 2021-11-27 21:23:59 -06:00
xXpuma99Xx de98b7a1b3 carta aceptación 2021-11-27 12:55:07 -06:00
xXpuma99Xx c14cc0f860 upload archivo componente 2021-11-27 12:35:55 -06:00
xXpuma99Xx 8374f3ebdc validadción nuevo servicio 2021-11-25 14:56:15 -06:00
xXpuma99Xx 1f43c269c5 nuevo servicio 2021-11-25 14:51:33 -06:00
xXpuma99Xx 98af63e609 responsable tabla 2021-11-25 07:04:06 -06:00
xXpuma99Xx 8cf7bae82e style 2021-11-24 22:05:37 -06:00
xXpuma99Xx f09caf110b componentes carpeta menos confusa 2021-11-24 21:26:10 -06:00
xXpuma99Xx 954e2103e0 editar servicio 2021-11-24 21:02:01 -06:00
xXpuma99Xx db1a723605 ver servicio social 2021-11-24 18:02:15 -06:00
xXpuma99Xx c3ab1107cd editar responsable 2021-11-23 18:38:37 -06:00
xXpuma99Xx 58ca512bab responsable info 2021-11-23 18:25:54 -06:00
xXpuma99Xx 8d283707c4 reponsables listo 2021-11-23 18:09:06 -06:00
xXpuma99Xx 6c8ac6fff7 reportes falta mayuscula 2021-11-23 17:44:24 -06:00
xXpuma99Xx fdcebaa1d6 pendiente editar caso especial 2021-11-23 17:21:24 -06:00
xXpuma99Xx 17373f37c6 liberar caso especial 2021-11-23 15:28:38 -06:00
xXpuma99Xx f8dd0ccaf8 tablas con mayusculas 2021-11-23 14:51:37 -06:00
xXpuma99Xx e0a60215c9 tablas casos especiales y servicios sociales admin final 2021-11-23 14:49:00 -06:00
xXpuma99Xx 4e537ff938 tabla servicios sociales organizada 2021-11-23 14:39:41 -06:00
xXpuma99Xx ac8c088416 listo 2021-09-28 18:40:12 -05:00
puma99 31558bc14c Proyectos CEDETEC 2021-08-12 12:22:04 -05:00
puma99 48c483810a archivo e info 2021-08-05 21:54:35 -05:00
puma99 66fc25ccf7 actualizar responsable casi listo 2021-08-05 16:47:56 -05:00
puma99 3604d00a29 info responsable listo 2021-08-05 15:53:05 -05:00
puma99 7adde8ac4b admin responsalbes listo 2021-08-05 15:39:11 -05:00
puma99 08a786899e reportes listo 2021-08-05 15:12:22 -05:00
puma99 614a199f84 admin editar caso especial casi listo 2021-08-05 14:56:01 -05:00
Lemuel Marquez e291493089 listo admin caso especial 2021-08-05 14:12:22 -05:00
Lemuel Marquez 9431a783b8 admin tabla casos especiales listo 2021-08-05 13:52:10 -05:00
Lemuel Marquez 101f60f489 admin mini cambios 2021-08-04 18:25:24 -05:00
Lemuel Marquez db0a63854a admin caso especial funiones imprimir 2021-08-04 17:31:24 -05:00
Lemuel Marquez 68c1c95ff4 responsable funiones imprimir 2021-08-04 17:03:13 -05:00
Lemuel Marquez 90aad06995 reportes 2021-08-04 16:28:45 -05:00
Lemuel Marquez 089c23ec2b tabla servicios sociales 2021-08-04 16:12:05 -05:00
Lemuel Marquez f753b6860d se manda las funciones imprimir a los componentes 2021-08-04 15:02:08 -05:00
Lemuel Marquez 94ba35e988 funciones en componente principal de cada pagina 2021-08-04 14:49:40 -05:00
Lemuel Marquez 8085f2dc01 funciones para imprimir mejoradas y finales 2021-08-04 14:38:44 -05:00
puma99 0bbf324f30 update caso especial a medias 2021-06-09 17:34:46 -05:00
puma99 304490c015 caso especial listo 2021-06-09 13:44:18 -05:00
puma99 ac109a961a tabla casos especiales lista 2021-06-09 12:25:57 -05:00
Lemuel Marquez 38e3db0f30 codigo para acticar responsable en bases 2021-06-09 09:14:12 -05:00
Lemuel Marquez 12d160e058 actualizar listo 2021-06-08 22:45:32 -05:00
Lemuel Marquez b35e6b316d listo responsable info 2021-06-08 18:22:28 -05:00
Lemuel Marquez bdbd1866b1 carga masiva lista 2021-06-08 13:36:21 -05:00
Lemuel Marquez 147df99268 tabla responsables lista 2021-06-08 13:19:51 -05:00
Lemuel Marquez dbea788589 registros listos 2021-06-08 12:21:19 -05:00
Lemuel Marquez e305613757 tabla servicios admin lista 2021-06-07 23:42:00 -05:00
Lemuel Marquez dbf0b0dbb2 nuevo sse listo 2021-06-07 21:55:16 -05:00
Lemuel Marquez ba96a6c172 tabla casos especiales lista 2021-06-07 20:24:33 -05:00
Lemuel Marquez 6a12223c96 listo nuevo caso especial 2021-05-31 13:56:03 -05:00
Lemuel Marquez 61b29098e9 correciones minimas 2021-05-25 13:05:06 -05:00
Lemuel Marquez 44ba43a8ee casos especiales y caso especial listo 2021-05-17 01:09:05 -05:00
Lemuel Marquez 5a08433938 carta termino listo 2021-05-16 22:27:34 -05:00
Lemuel Marquez 9cd91c8752 vista carta de aceptación mejorado 2021-05-16 22:14:27 -05:00
Lemuel Marquez 1a55bcf7aa tabla responsable casos especiales 2021-05-15 01:35:46 -05:00
Lemuel Marquez 637b7bd0e3 busqueda con enter 2021-05-15 01:18:15 -05:00
Lemuel Marquez 736ac50110 table casos especiales lista 2021-05-15 00:58:24 -05:00
Lemuel Marquez f53b9a84da ya no pueden entrar a otra pagina que no sea la que les corresponde 2021-05-15 00:15:19 -05:00
Lemuel Marquez dbe3e93e86 tabla admin lista 2021-05-14 18:47:35 -05:00
Lemuel Marquez 1a1c309523 inicio responsable listo 2021-05-14 17:13:46 -05:00
Lemuel Marquez ccf4a95f8c tabla responsable aparentemente lista 2021-05-14 14:56:34 -05:00
Lemuel Marquez 75aa6d884d quitando código de table inecesario 2021-05-14 09:51:43 -05:00
Lemuel Marquez b81931d82c campos tabla mejorados 2021-05-13 23:16:27 -05:00
Lemuel Marquez a42f6711c5 login mejorado 2021-05-13 15:55:40 -05:00
Lemuel Marquez 04b47e2160 logout mejorado 2021-05-13 14:47:41 -05:00
Lemuel Marquez 388d476f36 plantillas layout 2021-05-13 14:32:58 -05:00
Lemuel Marquez 24cd81c73d nuevo formateo 2021-05-13 14:22:56 -05:00
Lemuel Marquez eaf298c4a9 nuxt mejorado 2021-04-20 21:47:01 -05:00
Lemuel Marquez 7c8c2a4060 antes de pasar a nuevo nuxt 2021-04-20 21:29:01 -05:00
Lemuel Marquez 439ce08606 merge ultima version con dev 2021-04-20 12:36:04 -05:00
puma99 81e84005d0 cambio de loco acatlan 2021-04-14 08:58:36 -05:00
Lemuel Marquez 1928931861 merge master dev registros 2021-04-06 08:20:22 -05:00
Lemuel Marquez 47f7513cd5 registros 2021-04-06 08:18:54 -05:00
Lemuel Marquez 55695092e3 datos faltantes en vista servicio 2021-04-06 08:10:31 -05:00
Lemuel Marquez 24265fc0b3 Merge branch 'marco' of https://repositorio.acatlan.unam.mx/CIDWA/servicio_social_front into dev 2021-04-06 07:54:16 -05:00
Lemuel Marquez 7b64f3f4fd merge 2021-04-06 07:54:09 -05:00
Lemuel Marquez a35c72da9a tipo usuario correcto 2021-03-24 20:55:13 -06:00
Lemuel Marquez 9e6e4c08cd en teoria listo 2021-03-24 20:31:42 -06:00
Lemuel Marquez 8418fdcc77 merge master casos especiales 2021-03-24 20:25:43 -06:00
puma99 e863d69e14 correo alumno texto 2021-03-17 17:22:48 -06:00
175 changed files with 21281 additions and 17818 deletions
+16
View File
@@ -0,0 +1,16 @@
{
"name": "Nuxt.js Dev Container",
"dockerFile": "../Dockerfile",
"appPort": ["3001"],
"runArgs": ["-p", "3001:3000"],
"postCreateCommand": "npm install",
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"editor.formatOnSave": true
},
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
+13
View File
@@ -0,0 +1,13 @@
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
-19
View File
@@ -1,19 +0,0 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:vue/essential",
"standard"
],
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"vue"
],
"rules": {
}
}
+4
View File
@@ -1,3 +1,6 @@
#.devcontainer
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
@@ -69,6 +72,7 @@ typings/
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
+4
View File
@@ -0,0 +1,4 @@
{
"semi": false,
"singleQuote": true
}
+20
View File
@@ -0,0 +1,20 @@
# Usa una imagen oficial de Node.js
FROM node:16-alpine
# Establece el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copia el package.json y el package-lock.json (si existe)
COPY package*.json ./
# Instala las dependencias
RUN npm install
# Copia el resto de los archivos del proyecto
COPY . .
# Expone el puerto de desarrollo de Nuxt.js
EXPOSE 3000
# Comando por defecto al iniciar el contenedor
CMD ["npm", "run", "dev"]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+273
View File
@@ -0,0 +1,273 @@
<template>
<div>
<b-table
:data="data"
:total="total"
:current-page="page"
:per-page="perPage"
:loading="isLoading"
:selected.sync="servicioSelected"
:row-class="(row, index) => addPointer()"
@page-change="onPageChange"
hoverable
striped
paginated
backend-pagination
>
<b-table-column
field="fechaCreado"
label="Fecha Registro"
v-slot="props"
v-if="columnaFechaCreado"
centered
>
<span>{{ fecha(props.row.createdAt) }}</span>
</b-table-column>
<b-table-column
field="numeroCuenta"
label="Número de Cuenta"
v-slot="props"
centered
>
<span>{{ props.row.Usuario.usuario }}</span>
</b-table-column>
<b-table-column field="nombre" label="Nombre" v-slot="props" centered>
<span>{{ props.row.Usuario.nombre }}</span>
</b-table-column>
<b-table-column field="carrera" label="Carrera" v-slot="props" centered>
<span>{{ props.row.Carrera.carrera }}</span>
</b-table-column>
<b-table-column
field="fechaInicio"
label="Fecha Inicio"
v-slot="props"
v-if="columnaFechaInicio"
centered
>
<span>{{ fecha(props.row.fechaInicio) }}</span>
</b-table-column>
<b-table-column
field="fechaFin"
label="Fecha Fin"
v-slot="props"
v-if="columnaFechaFin"
centered
>
<span>{{ fecha(props.row.fechaFin) }}</span>
</b-table-column>
<b-table-column field="status" label="Status" v-slot="props" centered>
<b-button
type="is-danger"
size="is-small"
class="tag"
@click="responsableUpdate(props.row, 'carta_aceptacion')"
v-if="columnasResponsable && props.row.Status.idStatus === 7"
>
Carta Aceptación Rechazada
</b-button>
<span class="tag" :class="types(props.row.Status.idStatus)" v-else>
{{ props.row.Status.status }}
</span>
</b-table-column>
<b-table-column
field="cartaTermino"
label="Carta Término"
v-slot="props"
v-if="columnasResponsable"
centered
>
<div
v-if="
props.row.Status.idStatus >= 4 &&
props.row.Status.idStatus != 7 &&
props.row.Status.idStatus != 10
"
>
<b-icon
class="tag is-success"
icon="check"
v-if="props.row.cartaTermino"
/>
<b-button
type="is-link is-light"
class="tag"
@click="responsableUpdate(props.row, 'carta_termino')"
v-else
>
Carta Término
</b-button>
</div>
</b-table-column>
<b-table-column
field="cuestionarioP"
label="Cuestionario"
v-slot="props"
v-if="columnasResponsable"
centered
>
<div
v-if="
props.row.Status.idStatus >= 4 &&
props.row.Status.idStatus != 7 &&
props.row.Status.idStatus != 10
"
>
<b-icon
class="tag is-success"
icon="check"
v-if="props.row.idCuestionarioPrograma || props.row.idCuestionarioPrograma2"
/>
<b-button
type="is-link is-light"
class="tag"
@click="responsableUpdate(props.row, 'cuestionario')"
v-else
>
Cuestionario
</b-button>
</div>
</b-table-column>
</b-table>
</div>
</template>
<script>
import moment from 'moment'
export default {
props: {
columnaFechaCreado: {
type: Boolean,
required: false,
default: true,
},
columnaFechaFin: {
type: Boolean,
required: false,
default: true,
},
columnaFechaInicio: {
type: Boolean,
required: false,
default: true,
},
columnasResponsable: {
type: Boolean,
required: false,
default: false,
},
isLoading: {
type: Boolean,
required: true,
},
path: {
type: String,
required: false,
},
idTipoUsuario: {
type: Number,
required: true,
},
page: {
type: Number,
required: true,
},
total: {
type: Number,
required: true,
},
data: {
type: Array,
required: true,
},
onPageChange: {
type: Function,
require: true,
},
},
data() {
return {
servicioSelected: {},
perPage: 25,
}
},
methods: {
fecha(date) {
if (date) {
const fecha = moment(date)
return `${fecha.date() < 10 ? '0' + fecha.date() : fecha.date()}/${
fecha.month() < 9 ? '0' + (fecha.month() + 1) : fecha.month() + 1
}/${fecha.year()}`
}
return ''
},
types(idStatus) {
switch (idStatus) {
case 1:
return 'is-dark'
case 2:
return 'is-info'
case 3:
return 'is-warning'
case 4:
return 'is-link'
case 5:
return 'is-success'
case 6:
return 'is-success is-light'
case 7:
case 8:
case 9:
case 10:
return 'is-danger'
case 11:
return 'is-link is-light'
case 12:
return 'is-info is-light'
case 13:
case 14:
return 'is-success is-light'
}
},
addPointer() {
return this.idTipoUsuario === 1 ? 'pointer' : ''
},
responsableUpdate(servicio, path) {
localStorage.setItem('idServicio', servicio.idServicio)
this.$router.push(`/responsable/${path}`)
},
},
watch: {
servicioSelected() {
if (this.idTipoUsuario === 1) {
if (this.servicioSelected.idServicio)
localStorage.setItem('idServicio', this.servicioSelected.idServicio)
if (this.servicioSelected.idCasoEspecial)
localStorage.setItem(
'idCasoEspecial',
this.servicioSelected.idCasoEspecial
)
this.$router.push(this.path)
} else if (
this.servicioSelected.idServicio ||
this.servicioSelected.idCasoEspecial
)
this.servicioSelected = {}
},
},
}
</script>
<style scoped></style>
+138
View File
@@ -0,0 +1,138 @@
<template>
<div class="mb-4">
<div class="is-flex is-align-items-center">
<h6 class="pr-4 is-size-5">Ver {{ title }}</h6>
<div class="pr-4">
<b-button
type="is-link is-light"
tag="a"
target="_blank"
:href="`https://drive.google.com/file/d/${this.archivo()}/view?usp=sharing`"
>
Ver
</b-button>
</div>
<div>
<b-button
type="is-danger"
@click="updateRechazar()"
v-if="
(alumno.Status.idStatus === 1 && title === 'carta de aceptación') ||
(alumno.Status.idStatus === 5 &&
(title === 'carta de termino' || title === 'informe global'))
"
>
Rechazar
</b-button>
</div>
</div>
<div v-if="rechazar" class="mt-2">
<b-field label="Razón del rechazo:">
<b-input maxlength="500" type="textarea" v-model="mensajeRechazo" />
</b-field>
<b-field>
<b-button
type="is-link"
:disabled="!mensajeRechazo"
@click="
imprimirWarning(
'¿Seguro(a) que quiere rechazar este documento?',
rechazarArchivo
)
"
>
Rechazar {{ title }}
</b-button>
</b-field>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
title: { type: String, required: true },
admin: { type: Object, required: true },
alumno: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
rechazar: false,
mensajeRechazo: '',
}
},
methods: {
updateRechazar() {
if (this.rechazar) this.mensajeRechazo = ''
this.rechazar = !this.rechazar
},
archivo() {
if (this.title === 'carta de aceptación')
return this.alumno.cartaAceptacion
else if (this.title === 'carta de termino')
return this.alumno.cartaTermino
else if (this.title === 'informe global') return this.alumno.informeGlobal
},
rechazarArchivo() {
if (this.title === 'carta de aceptación')
this.rechazarFunc(this.rechazarCartaAceptacion)
else if (this.title === 'carta de termino')
this.rechazarFunc(this.rechazarCartaTermino)
else if (this.title === 'informe global')
this.rechazarFunc(this.rechazarInformeGlobal)
},
rechazarFunc(funcRechazar) {
const data = {
idServicio: this.alumno.idServicio,
mensaje: this.mensajeRechazo,
}
this.updateIsLoading(true)
funcRechazar(data)
.then((res) => {
localStorage.removeItem('idServicio')
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
rechazarCartaAceptacion(data) {
return axios.put(
`${process.env.api}/servicio/rechazar_aceptacion`,
data,
this.admin.token
)
},
rechazarCartaTermino(data) {
return axios.put(
`${process.env.api}/servicio/rechazar_termino`,
data,
this.admin.token
)
},
rechazarInformeGlobal(data) {
return axios.put(
`${process.env.api}/servicio/rechazar_informe`,
data,
this.admin.token
)
},
},
}
</script>
<style scoped></style>
+86
View File
@@ -0,0 +1,86 @@
<template>
<div class="mt-5">
<b-field>
<b-button
type="is-danger"
:disabled="
alumno.Status.idStatus === 6 || alumno.Status.idStatus === 10
"
@click="updateCancelar()"
>
Cancelar
</b-button>
</b-field>
<div class="mt-2" v-if="cancelar">
<b-field label="Razón de la cancelación:">
<b-input maxlength="500" type="textarea" v-model="mensajeCancelar" />
</b-field>
<b-field>
<b-button
type="is-link"
:disabled="!mensajeCancelar"
@click="
imprimirWarning(
'¿Seguro(a) que quiere cancelar este servicio?',
cancelarServicio
)
"
>
Cancelar servicio
</b-button>
</b-field>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
idServicio: { type: Number, required: true },
admin: { type: Object, required: true },
alumno: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
cancelar: false,
mensajeCancelar: '',
}
},
methods: {
updateCancelar() {
if (this.cancelar) this.mensajeCancelar = ''
this.cancelar = !this.cancelar
},
cancelarServicio() {
const data = {
idServicio: this.idServicio,
mensaje: this.mensajeCancelar,
}
this.updateIsLoading(true)
axios
.put(`${process.env.api}/servicio/cancelar`, data, this.admin.token)
.then((res) => {
localStorage.removeItem('idServicio')
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
+104
View File
@@ -0,0 +1,104 @@
<template>
<div class="pb-6">
<h3 class="title">Carga Masiva</h3>
<b-field>
<b-upload
accept=".csv"
@input="validarExt()"
v-model="csv"
drag-drop
expanded
>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
csv.name || 'Arrastra aquí tu archivo o da click aquí para buscar'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
<p class="is-size-7">
Si al momento de elegir un archivo este no se selecciona, haga click
en cancelar en la ventana emergente e intente de nuevo.
</p>
</div>
</b-upload>
</b-field>
<div>
<b-button
type="is-info"
:disabled="!csv.name"
@click="
imprimirWarning(
'¿Seguro(a) que quieres enviar este archivo?',
enviarCargaMasiva
)
"
>
Enviar archivo
</b-button>
<b-button type="is-link" tag="a" target="_blank" :href="link">
Descargar plantilla
</b-button>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
link: `${process.env.api}/plantilla.csv`,
csv: {},
}
},
methods: {
validarExt() {
const extPermitidas = /(.csv)$/i
if (!extPermitidas.exec(this.csv.name)) {
this.imprimirError({ message: 'Asegurate de ingresar un archivo .CSV' })
this.csv = {}
}
},
enviarCargaMasiva() {
const formData = new FormData()
this.updateIsLoading(true)
formData.append('csv', this.csv)
axios
.post(
`${process.env.api}/programa/carga_masiva`,
formData,
this.admin.tokenArchivo
)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
+91
View File
@@ -0,0 +1,91 @@
<template>
<div>
<b-field v-if="alumno.Status.idStatus === 5 && alumno.Programa.acatlan">
<b-checkbox type="is-info" size="is-medium" v-model="vistoBuenoAcatlan">
Visto bueno Acatlán
</b-checkbox>
</b-field>
<b-field
class="mt-5"
v-if="alumno.Status.idStatus === 1 || alumno.Status.idStatus === 5"
>
<b-button
class="is-success"
:disabled="
alumno.Status.idStatus === 5 &&
alumno.Programa.acatlan &&
!vistoBuenoAcatlan
"
@click="
imprimirWarning(
'¿Seguro(a) que quieres confirmar este servicio?',
confirmarServicio
)
"
>
Confirmar
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
idServicio: { type: Number, required: true },
admin: { type: Object, required: true },
alumno: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return { vistoBuenoAcatlan: false }
},
methods: {
confirmarServicio() {
if (this.alumno.Status.idStatus === 1)
this.confirmar(this.confirmarPreRegistro)
else if (this.alumno.Status.idStatus === 5)
this.confirmar(this.confirmarLiberacion)
},
confirmar(funcConfirmar) {
const data = { idServicio: this.idServicio }
this.updateIsLoading(true)
funcConfirmar(data)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
confirmarPreRegistro(data) {
return axios.put(
`${process.env.api}/servicio/registro`,
data,
this.admin.token
)
},
confirmarLiberacion(data) {
if (this.vistoBuenoAcatlan)
data.vistoBuenoAcatlan = this.vistoBuenoAcatlan
return axios.put(
`${process.env.api}/servicio/liberacion`,
data,
this.admin.token
)
},
},
}
</script>
<style scoped></style>
+105
View File
@@ -0,0 +1,105 @@
<template>
<div>
<h4 class="is-size-4 mb-2">Descargar cuestionarios</h4>
<b-field label="Cuestionario:">
<b-select v-model="selectedCuestionario" expanded>
<option value="" disabled>Seleccione un cuestionario:</option>
<option value="cuestionario_alumno">Cuestionarios del Alumnos</option>
<option value="cuestionario_programa">
Cuestionarios del Programas
</option>
</b-select>
</b-field>
<b-field label="Version:">
<b-select v-model="version" expanded>
<option value="" disabled>Seleccione una version:</option>
<option value="v1">v1</option>
<option value="v2">
v2
</option>
</b-select>
</b-field>
<b-field label="Año:">
<b-select v-model="selectedYear" expanded>
<option value="" disabled>Seleccione un año:</option>
<option v-for="(y, i) in years" :key="i" :value="y">
{{ y }}
</option>
</b-select>
</b-field>
<b-field class="pb-5 pt-3">
<b-button
type="is-info"
@click="descargar()"
:disabled="!selectedYear || !selectedCuestionario"
>
Descargar Excel
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
import fileDownload from 'js-file-download'
export default {
props: {
years: { type: Array, required: true },
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
selectedCuestionario: '',
selectedYear: '',
version:''
}
},
methods: {
descargar() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/${this.selectedCuestionario}`, {
params: {
year: this.selectedYear,
version: this.version,
},
headers: {
Authorization: `Bearer ${this.admin.token}`,
},
}
)
.then((res) => {
fileDownload(
res.data,
`${this.selectedYear}_${this.selectedCuestionario}_${this.version}.csv`
)
this.selectedYear = ''
this.selectedCuestionario = ''
this.version = ''
this.updateIsLoading(false)
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
+198
View File
@@ -0,0 +1,198 @@
<template>
<div>
<h3 class="title">Editar información del alumno</h3>
<b-field label="Correo eletrónico">
<b-input
type="email"
:placeholder="viejo.correo"
v-model="nuevo.correo"
/>
</b-field>
<b-field label="Teléfono">
<b-input
type="tel"
maxlength="10"
:has-counter="false"
:placeholder="viejo.telefono"
v-model="nuevo.telefono"
/>
</b-field>
<b-field label="Dirección">
<b-input
type="text"
:placeholder="viejo.direccion"
v-model="nuevo.direccion"
/>
</b-field>
<b-field label="Fecha de inicio">
<b-datepicker
icon="calendar-today"
:min-date="minDate1"
:placeholder="fecha(viejo.fechaInicio)"
v-model="nuevo.fechaInicio"
/>
</b-field>
<transition name="fade">
<b-field label="Fecha de fin" v-if="nuevo.fechaInicio">
<b-datepicker
icon="calendar-today"
:min-date="minDate2"
:placeholder="fecha(viejo.fechaFin)"
v-model="nuevo.fechaFin"
/>
</b-field>
</transition>
<b-field label="Fecha de nacimiento">
<b-datepicker
icon="calendar-today"
:placeholder="fecha(viejo.fechaNacimiento)"
v-model="nuevo.fechaNacimiento"
/>
</b-field>
<b-field label="Motivo" v-if="viejo.motivo">
<b-select class="my-4" v-model="nuevo.motivo" expanded>
<option value="1">Tercera edad</option>
<option value="2">Capacidades diferentes</option>
</b-select>
</b-field>
<b-field label="Dependencia" v-if="viejo.dependencia">
<b-input
type="text"
v-model="nuevo.dependencia"
:placeholder="viejo.dependencia"
/>
</b-field>
<b-field label="Institución" v-if="viejo.institucion">
<b-input
type="text"
:placeholder="viejo.institucion"
v-model="nuevo.institucion"
/>
</b-field>
<b-field class="mt-5">
<b-button
type="is-success"
:disabled="!mostrarBoton()"
@click="
imprimirWarning(
'¿Estás segura(a) de querer actualizar estos datos?',
actualizar
)
"
>
Actualizar Datos
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
import moment from 'moment'
import validator from 'validator'
export default {
props: {
idCasoEspecial: { type: Number, required: true },
admin: { type: Object, required: true },
viejo: { type: Object, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
minDate1: new Date('2020-01-02'),
nuevo: {},
}
},
methods: {
fecha(date) {
if (date) {
const fecha = moment(date)
return `${fecha.date() < 10 ? '0' + fecha.date() : fecha.date()}/${
fecha.month() < 9 ? '0' + (fecha.month() + 1) : fecha.month() + 1
}/${fecha.year()}`
}
return ''
},
mostrarBoton() {
if (
this.nuevo.correo ||
this.nuevo.direccion ||
this.nuevo.telefono ||
this.nuevo.fechaNacimiento ||
this.nuevo.motivo ||
this.nuevo.institucion ||
this.nuevo.dependencia ||
(this.nuevo.fechaInicio && this.nuevo.fechaFin)
) {
if (this.nuevo.correo) {
if (validator.isEmail(this.nuevo.correo)) return true
else return false
}
return true
}
return false
},
actualizar() {
const data = { idCasoEspecial: this.idCasoEspecial }
this.updateIsLoading(true)
if (this.nuevo.direccion) data.direccion = this.nuevo.direccion
if (this.nuevo.correo) data.correo = this.nuevo.correo
if (this.nuevo.telefono) data.telefono = this.nuevo.telefono
if (this.nuevo.motivo) data.motivo = this.nuevo.motivo
if (this.nuevo.dependencia) data.dependencia = this.nuevo.dependencia
if (this.nuevo.institucion) data.institucion = this.nuevo.institucion
if (this.nuevo.fechaInicio)
data.fechaInicio = moment(this.nuevo.fechaInicio)
if (this.nuevo.fechaFin) data.fechaFin = moment(this.nuevo.fechaFin)
if (this.nuevo.fechaNacimiento)
data.fechaNacimiento = moment(this.nuevo.fechaNacimiento)
axios
.put(`${process.env.api}/caso_especial/update`, data, this.admin.token)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin/casos_especiales/caso_especial')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
computed: {
minDate2() {
const min = new Date(this.nuevo.fechaInicio)
return new Date(min.getFullYear(), min.getMonth() + 6, min.getDate())
},
},
}
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>
+131
View File
@@ -0,0 +1,131 @@
<template>
<div>
<h3 class="title">Editar información del responsable</h3>
<b-field label="Nombre">
<b-input
type="text"
:placeholder="responsable.nombre"
v-model="nuevo.nombre"
/>
</b-field>
<b-field label="Correo eletrónico">
<b-input
type="email"
:placeholder="responsable.usuario"
v-model="nuevo.correo"
/>
</b-field>
<!-- <b-field label="Estado:">
<b-select v-model="nuevo.activo" expanded>
<option :value="true">Activado</option>
<option :value="false">Desactivado</option>
</b-select>
</b-field> -->
<div class="pt-5">
<b-button
type="is-info"
:disabled="mostrarBoton()"
@click="
imprimirWarning(
'¿Seguro(a) que quiere actualizar la información de este usuario?',
actualizar
)
"
>
Guardar Cambios
</b-button>
<b-button
type="is-link"
@click="
imprimirWarning(
'¿Seguro(a) que quiere cambiar la contraseña para este usuario?',
password
)
"
>
Cambiar contraseña
</b-button>
</div>
</div>
</template>
<script>
import axios from 'axios'
import validator from 'validator'
export default {
props: {
admin: { type: Object, required: true },
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
nuevo: {},
}
},
methods: {
mostrarBoton() {
if (this.nuevo.correo) {
if (!validator.isEmail(this.nuevo.correo)) return true
if (this.nuevo.correo != this.responsable.usuario) return false
}
if (this.nuevo.nombre && this.nuevo.nombre != this.responsable.nombre)
return false
return true
},
actualizar() {
const data = { idUsuario: this.responsable.idUsuario }
this.updateIsLoading(true)
if (this.nuevo.correo) data.correo = this.nuevo.correo
if (this.nuevo.nombre) data.nombre = this.nuevo.nombre
axios
.put(
`${process.env.api}/usuario/responsable/update`,
data,
this.admin.token
)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin/responsables/responsable')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
password() {
const data = { idUsuario: this.responsable.idUsuario }
this.updateIsLoading(true)
axios
.put(
`${process.env.api}/usuario/new_password_responsable`,
data,
this.admin.token
)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin/responsables/responsable')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
+353
View File
@@ -0,0 +1,353 @@
<template>
<div>
<h3 class="title">Editar información del alumno</h3>
<div>
<b-field label="Correo eletrónico del alumno">
<b-input type="email" :placeholder="servicio.correo" v-model="correo" />
</b-field>
<b-field label="Fecha de inicio">
<b-datepicker
icon="calendar-today"
:min-date="minDate1"
v-model="fechaInicio"
/>
</b-field>
<b-field label="Fecha de fin">
<b-datepicker
icon="calendar-today"
:min-date="minDate2"
v-model="fechaFin"
/>
</b-field>
<b-field label="Dirección" v-if="servicio.direccion">
<b-input
type="text"
:placeholder="servicio.direccion"
v-model="direccion"
/>
</b-field>
<b-field label="Teléfono" v-if="servicio.telefono">
<b-input
type="tel"
maxlength="10"
:has-counter="false"
:placeholder="servicio.telefono"
v-model="telefono"
/>
</b-field>
<b-field label="Fecha de nacimiento" v-if="servicio.fechaNacimiento">
<b-datepicker
icon="calendar-today"
:placeholder="fecha(servicio.fechaNacimiento)"
:max-date="new Date()"
v-model="fechaNacimiento"
/>
</b-field>
<b-field label="Carta de aceptación">
<b-upload
accept="application/pdf"
v-model="cartaAceptacion"
drag-drop
expanded
>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
cartaAceptacion.name ||
'Arrastra aquí tu archivo o da click aquí para buscarlo.'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
</div>
</b-upload>
</b-field>
<b-field
label="Carta de término"
v-if="servicio.Status.idStatus > 4 && servicio.Status.idStatus != 7"
>
<b-upload
accept="application/pdf"
v-model="cartaTermino"
drag-drop
expanded
>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
cartaTermino.name ||
'Arrastra aquí tu archivo o da click aquí para buscarlo.'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
</div>
</b-upload>
</b-field>
<b-field
label="Informe global"
v-if="servicio.Status.idStatus > 4 && servicio.Status.idStatus != 7"
>
<b-upload
accept="application/pdf"
v-model="informeGlobal"
drag-drop
expanded
>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
informeGlobal.name ||
'Arrastra aquí tu archivo o da click aquí para buscarlo.'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
</div>
</b-upload>
</b-field>
</div>
<div class="mt-4">
<b-button
class="is-info"
:disabled="mostrar()"
@click="
imprimirWarning(
'¿Seguro(a) que quiere actualizar estos datos?',
actualizar
)
"
>
Actualizar Datos
</b-button>
<b-button
class="is-info"
@click="
imprimirWarning(
'¿Seguro(a) que quieres cambiar/reenviar la contraseña de este alumno?',
password
)
"
:disabled="
servicio.Status.idStatus === 1 || servicio.Status.idStatus === 7
"
>
Cambiar/Reenviar contraseña
</b-button>
</div>
</div>
</template>
<script>
import axios from 'axios'
import moment from 'moment'
import validator from 'validator'
export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
actualizarFechaFin: false,
idServicio: null,
correo: '',
telefono: '',
direccion: '',
fechaFin: new Date(),
fechaInicio: new Date(),
fechaNacimiento: new Date(),
cartaAceptacion: {},
cartaTermino: {},
informeGlobal: {},
minDate1: new Date('2020-01-01'),
minDate2: new Date(),
servicio: {
Status: {},
fechaFin: new Date(),
fechaInicio: new Date(),
fechaNacimiento: new Date(),
},
}
},
methods: {
fecha(date) {
if (date) {
const fecha = moment(date)
return `${fecha.date() < 10 ? '0' + fecha.date() : fecha.date()}/${
fecha.month() < 9 ? '0' + (fecha.month() + 1) : fecha.month() + 1
}/${fecha.year()}`
}
return ''
},
mostrar() {
if (
this.fechaInicio.toString().substr(0, 15) !==
this.servicio.fechaInicio.toString().substr(0, 15) ||
this.fechaFin.toString().substr(0, 15) !==
this.servicio.fechaFin.toString().substr(0, 15) ||
(this.servicio.fechaNacimiento &&
this.fechaNacimiento.toString().substr(0, 15) !==
this.servicio.fechaNacimiento.toString().substr(0, 15)) ||
(this.correo && validator.isEmail(this.correo)) ||
this.telefono ||
this.direccion ||
this.cartaTermino.name ||
this.cartaAceptacion.name ||
this.informeGlobal.name
)
return false
return true
},
sizeFileValido(file) {
if (file.size >= 20000000) {
this.imprimirError({ message: 'El tamaño del archivo exede los 20MB' })
return false
}
return true
},
updateFechas() {
if (this.actualizarFechaFin) {
this.fechaFin = new Date(
this.fechaInicio.getFullYear(),
this.fechaInicio.getMonth() + 6,
this.fechaInicio.getDate()
)
}
this.minDate2 = new Date(
this.fechaInicio.getFullYear(),
this.fechaInicio.getMonth() + 6,
this.fechaInicio.getDate()
)
this.actualizarFechaFin = true
},
obtenerRegistro() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/servicio/admin?idServicio=${this.idServicio}`,
this.admin.token
)
.then((res) => {
this.servicio = res.data
if (
this.servicio.Status.idStatus === 6 ||
this.servicio.Status.idStatus === 10
)
this.$router.push('/admin/servicio')
this.fechaInicio = new Date(this.servicio.fechaInicio)
this.servicio.fechaInicio = new Date(this.servicio.fechaInicio)
this.fechaFin = new Date(this.servicio.fechaFin)
this.servicio.fechaFin = new Date(this.servicio.fechaFin)
if (this.servicio.fechaNacimiento) {
this.fechaNacimiento = new Date(this.servicio.fechaNacimiento)
this.servicio.fechaNacimiento = new Date(
this.servicio.fechaNacimiento
)
}
this.updateIsLoading(false)
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
actualizar() {
const formData = new FormData()
const data = { idServicio: this.idServicio }
this.updateIsLoading(true)
if (this.cartaAceptacion)
formData.append('cartaAceptacion', this.cartaAceptacion)
if (this.cartaTermino) formData.append('cartaTermino', this.cartaTermino)
if (this.informeGlobal)
formData.append('informeGlobal', this.informeGlobal)
if (this.direccion) data.direccion = this.direccion
if (this.correo) data.correo = this.correo
if (this.telefono) data.telefono = this.telefono
if (this.fechaInicio) data.fechaInicio = this.fechaInicio
if (this.fechaFin) data.fechaFin = this.fechaFin
if (this.fechaNacimiento) data.fechaNacimiento = this.fechaNacimiento
formData.append('data', JSON.stringify(data))
axios
.put(
`${process.env.api}/servicio/update`,
formData,
this.admin.tokenArchivo
)
.then((res) => {
this.imprimirMensaje(res.data.message)
this.updateIsLoading(false)
this.$router.push('/admin/servicio')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
password() {
const data = { idServicio: this.idServicio }
this.updateIsLoading(true)
axios
.put(
`${process.env.api}/usuario/new_password_alumno`,
data,
this.admin.token
)
.then((res) => {
this.imprimirMensaje(res.data.message)
this.updateIsLoading(false)
this.$router.push('/admin')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
watch: {
fechaInicio() {
this.updateFechas()
},
cartaAceptacion() {
if (!this.sizeFileValido(this.cartaAceptacion)) this.cartaAceptacion = {}
},
cartaTermino() {
if (!this.sizeFileValido(this.cartaTermino)) this.cartaAceptacion = {}
},
informeGlobal() {
if (!this.sizeFileValido(this.informeGlobal)) this.informeGlobal = {}
},
},
created() {
this.idServicio = Number(localStorage.getItem('idServicio'))
if (!this.idServicio) this.$router.push('/admin')
else this.obtenerRegistro()
},
}
</script>
<style scoped></style>
+68
View File
@@ -0,0 +1,68 @@
<template>
<div>
<h4 class="is-size-4 mb-2">Gustavo Baz Prada</h4>
<b-field label="Año:">
<b-select v-model="selectedYearGustavoBaz" expanded>
<option value="" disabled>Seleccione un año:</option>
<option v-for="(y, i) in years" :key="i" :value="y">
{{ y }}
</option>
</b-select>
</b-field>
<b-field class="pb-5 pt-3">
<b-button
type="is-info"
@click="descargar()"
:disabled="!selectedYearGustavoBaz"
>
Descargar Excel
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
import fileDownload from 'js-file-download'
export default {
props: {
years: { type: Array, required: true },
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
selectedYearGustavoBaz: '',
}
},
methods: {
descargar() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/servicio/gustavo_baz_prada?year=${this.selectedYearGustavoBaz}`,
this.admin.token
)
.then((res) => {
fileDownload(
res.data,
`${this.selectedYearGustavoBaz}_gustavo_baz_prada.csv`
)
this.selectedYearGustavoBaz = ''
this.updateIsLoading(false)
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
@@ -0,0 +1,102 @@
<template>
<div>
<h3 class="title">{{ alumno.Status.status }}</h3>
<h4 class="is-size-4 mb-4">Datos personales</h4>
<b-field label="Número de Cuenta:">
<p class="input">{{ alumno.Usuario.usuario }}</p>
</b-field>
<b-field label="Nombre:">
<p class="input">{{ alumno.Usuario.nombre }}</p>
</b-field>
<b-field label="Carrera:">
<p class="input">{{ alumno.Carrera.carrera }}</p>
</b-field>
<b-field label="Créditos:">
<p class="input">{{ Number(alumno.creditos) }}%</p>
</b-field>
<b-field label="Correo:">
<p class="input">{{ alumno.correo }}</p>
</b-field>
<b-field label="Fecha de Nacimiento:">
<p class="input">{{ fecha(alumno.fechaNacimiento) }}</p>
</b-field>
<b-field label="Dirección:">
<p class="input">{{ alumno.direccion }}</p>
</b-field>
<b-field label="Teléfono:">
<p class="input">{{ alumno.telefono }}</p>
</b-field>
<b-field label="Motivo:" v-if="alumno.motivo">
<p class="input" v-if="alumno.motivo === '1'">Tercera edad</p>
<p class="input" v-if="alumno.motivo === '2'">Capacidades diferentes</p>
</b-field>
<b-field label="Institución:" v-if="alumno.institucion">
<p class="input">{{ alumno.institucion }}</p>
</b-field>
<b-field label="Dependencia:" v-if="alumno.dependencia">
<p class="input">{{ alumno.dependencia }}</p>
</b-field>
<b-field label="Fecha Inicio:">
<p class="input">{{ fecha(alumno.fechaInicio) }}</p>
</b-field>
<b-field label="Fecha Fin:">
<p class="input">{{ fecha(alumno.fechaFin) }}</p>
</b-field>
<b-field label="Fecha Registro:">
<p class="input">{{ fecha(alumno.createdAt) }}</p>
</b-field>
<b-field
class="py-5"
v-if="alumno.Status.idStatus === 11 || alumno.Status.idStatus === 12"
>
<b-button
type="is-info"
tag="router-link"
to="/admin/casos_especiales/caso_especial/editar"
>
Editar información
</b-button>
</b-field>
</div>
</template>
<script>
import moment from 'moment'
export default {
props: {
alumno: { type: Object, required: true },
},
methods: {
fecha(date) {
if (date) {
const fecha = moment(date)
return `${fecha.date() < 10 ? '0' + fecha.date() : fecha.date()}/${
fecha.month() < 9 ? '0' + (fecha.month() + 1) : fecha.month() + 1
}/${fecha.year()}`
}
return ''
},
},
}
</script>
<style scoped></style>
+124
View File
@@ -0,0 +1,124 @@
<template>
<div>
<h3 class="title">Información del responsable</h3>
<b-field label="Nombre:">
<p class="input">{{ responsable.nombre }}</p>
</b-field>
<b-field label="Correo:">
<p class="input">{{ responsable.usuario }}</p>
</b-field>
<b-field label="Activo:">
<p class="input">{{ responsable.activo ? 'Si' : 'No' }}</p>
</b-field>
<b-field label="Clave de programa:">
<b-select v-model="programa" expanded>
<option value="" disabled>Elija una clave de programa:</option>
<option v-for="(p, i) in programas" :key="i" :value="p">
{{ p.clavePrograma }}
</option>
</b-select>
</b-field>
<b-field label="Institucion:">
<p class="input">{{ programa.institucion }}</p>
</b-field>
<b-field label="Dependencia:">
<p class="input">{{ programa.dependencia }}</p>
</b-field>
<b-field label="Programa:">
<p class="input">{{ programa.programa }}</p>
</b-field>
<b-field label="Programa de Acatlan:">
<p class="input">
<span v-if="programa.idPrograma">
{{ programa.acatlan ? 'Si' : 'No' }}
</span>
</p>
</b-field>
<b-field label="Activo:">
<p class="input">
<span v-if="programa.idPrograma">
{{ programa.activo ? 'Si' : 'No' }}
</span>
</p>
</b-field>
<b-field class="mt-5">
<b-button
type="is-link"
tag="router-link"
to="/admin/responsables/responsable/editar"
>
Editar información
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
idResponsable: null,
programas: [],
programa: {},
responsable: {},
}
},
methods: {
obtenerResponsable() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/usuario/responsable?idUsuario=${this.idResponsable}`,
this.admin.token
)
.then((res) => {
this.responsable = res.data
this.obtenerProgramas()
this.updateIsLoading(false)
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
obtenerProgramas() {
axios
.get(
`${process.env.api}/programa/programas_admin?idUsuario=${this.idResponsable}`,
this.admin.token
)
.then((res) => {
this.programas = res.data
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
},
created() {
this.idResponsable = Number(localStorage.getItem('idResponsable'))
if (!this.idResponsable) this.$router.push('/admin/responsables')
else this.obtenerResponsable()
},
}
</script>
<style scoped></style>
+137
View File
@@ -0,0 +1,137 @@
<template>
<div class="mb-5">
<div class="mb-5">
<h4 class="is-size-4 pb-2">Datos del programa</h4>
<b-field label="Institución:">
<p class="input">{{ alumno.Programa.institucion }}</p>
</b-field>
<b-field label="Dependencia:">
<p class="input">{{ alumno.Programa.dependencia }}</p>
</b-field>
<b-field label="Programa:">
<p class="input">{{ alumno.Programa.programa }}</p>
</b-field>
<b-field label="Clave de programa:">
<p class="input">{{ alumno.Programa.clavePrograma }}</p>
</b-field>
<b-field label="Responsable:">
<p class="input">
{{ alumno.Programa.Usuario.nombre }}
</p>
</b-field>
<b-field label="Correo:">
<p class="input">
{{ alumno.Programa.Usuario.usuario }}
</p>
</b-field>
</div>
<div class="mb-5">
<h4 class="is-size-4 pb-2">Datos personales</h4>
<b-field label="Numero de cuenta:">
<p class="input">{{ alumno.Usuario.usuario }}</p>
</b-field>
<b-field label="Nombre:">
<p class="input">{{ alumno.Usuario.nombre }}</p>
</b-field>
<b-field label="Fecha de nacimiento:" v-if="alumno.fechaNacimiento">
<p class="input">{{ fecha(alumno.fechaNacimiento) }}</p>
</b-field>
<b-field label="Carrera:">
<p class="input">{{ alumno.Carrera.carrera }}</p>
</b-field>
<b-field label="Créditos">
<p class="input">
{{ alumno.creditos ? parseInt(alumno.creditos) : '' }}
<span v-if="alumno.creditos">%</span>
</p>
</b-field>
<b-field label="Teléfono:" v-if="alumno.telefono">
<p class="input">{{ alumno.telefono }}</p>
</b-field>
<b-field label="Dirección:" v-if="alumno.direccion">
<p class="input">{{ alumno.direccion }}</p>
</b-field>
<b-field label="Email:">
<p class="input">{{ alumno.correo }}</p>
</b-field>
<b-field label="Programa Interno:" v-if="alumno.programaInterno">
<p class="input">{{ alumno.programaInterno }}</p>
</b-field>
<b-field label="Profesor:" v-if="alumno.profesor">
<p class="input">{{ alumno.profesor }}</p>
</b-field>
<b-field label="Fecha de registro:" v-if="alumno.createdAt">
<p class="input">{{ fecha(alumno.createdAt) }}</p>
</b-field>
<b-field label="Fecha de inicio:">
<p class="input">{{ fecha(alumno.fechaInicio) }}</p>
</b-field>
<b-field label="Fecha de termino:">
<p class="input">{{ fecha(alumno.fechaFin) }}</p>
</b-field>
<b-field label="Fecha de liberación:" v-if="alumno.fechaLiberacion">
<p class="input">{{ fecha(alumno.fechaLiberacion) }}</p>
</b-field>
</div>
<b-field>
<b-button
type="is-info"
@click="editar()"
:disabled="
alumno.Status.idStatus === 6 || alumno.Status.idStatus === 10
"
>
Editar información
</b-button>
</b-field>
</div>
</template>
<script>
import moment from 'moment'
export default {
props: {
alumno: { type: Object, required: true },
},
methods: {
fecha(date) {
if (date) {
const fecha = moment(date)
return `${fecha.date() < 10 ? '0' + fecha.date() : fecha.date()}/${
fecha.month() < 9 ? '0' + (fecha.month() + 1) : fecha.month() + 1
}/${fecha.year()}`
}
return ''
},
editar() {
this.$router.push('/admin/servicio/editar')
},
},
}
</script>
<style scoped></style>
+54
View File
@@ -0,0 +1,54 @@
<template>
<b-field class="mt-2">
<b-button
type="is-success"
@click="
imprimirWarning(
'¿Esta seguro de querer liberar este caso especial?',
confirmarLiberacion
)
"
>
Liberar
</b-button>
</b-field>
</template>
<script>
import axios from 'axios'
export default {
props: {
idCasoEspecial: { type: Number, required: true },
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
methods: {
confirmarLiberacion() {
const data = { idCasoEspecial: this.idCasoEspecial }
this.updateIsLoading(true)
axios
.put(
`${process.env.api}/caso_especial/liberacion`,
data,
this.admin.token
)
.then((res) => {
this.imprimirMensaje(res.data.message)
this.updateIsLoading(false)
this.$router.push('/admin/casos_especiales')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
+90
View File
@@ -0,0 +1,90 @@
<template>
<div class="mt-6">
<h3 class="title">Reasignación de programas</h3>
<div class="is-size-6 mb-4">
<p>
A continuación inserte el usaurio que desea eliminiar, los programas que
este usuario tenga seran asignados a: {{ responsable.usuario }}
</p>
</div>
<b-field label="Usuario/Correo electrónico">
<b-input
type="email"
placeholder="Usuario"
v-model="correoOtroResponsable"
/>
</b-field>
<b-field class="pt-5">
<b-button
type="is-info"
:disabled="mostrarBoton()"
@click="
imprimirWarning(
`¿Seguro(a) que quiere eliminar a ${correoOtroResponsable} y pasar todos los programas a ${responsable.usuario}?`,
reasignarProgramas
)
"
>
Reasignar
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
import validator from 'validator'
export default {
props: {
admin: { type: Object, required: true },
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return { correoOtroResponsable: '' }
},
methods: {
mostrarBoton() {
if (
!this.correoOtroResponsable ||
!validator.isEmail(this.correoOtroResponsable) ||
this.responsable.usuario === this.correoOtroResponsable
)
return true
return false
},
reasignarProgramas() {
const data = {
idUsuario: this.responsable.idUsuario,
correoOtroResponsable: this.correoOtroResponsable,
}
this.updateIsLoading(true)
axios
.put(
`${process.env.api}/programa/reasignar_programas`,
data,
this.admin.token
)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/admin/responsables/responsable')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
+84
View File
@@ -0,0 +1,84 @@
<template>
<div>
<h4 class="is-size-4 mb-2">Descargar reporte</h4>
<b-field label="Seleccione una fecha de inicio:">
<b-datepicker
icon="calendar-today"
placeholder="Seleccione una fecha de inicio"
:min-date="minDate"
:max-date="maxDate"
v-model="selectedInicio"
trap-focus
/>
</b-field>
<b-field label="Seleccione una fecha de fin:">
<b-datepicker
placeholder="Seleccione una fecha de fin"
icon="calendar-today"
:min-date="minDate"
:max-date="maxDate"
v-model="selectedFin"
trap-focus
/>
</b-field>
<b-field class="pb-5 pt-3">
<b-button type="is-info" @click="descargar()" :disabled="validarFechas()">
Descargar Excel
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
import moment from 'moment'
import fileDownload from 'js-file-download'
export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
selectedFin: [],
selectedInicio: [],
maxDate: new Date(),
minDate: new Date('January 1, 2020'),
}
},
methods: {
validarFechas() {
const fechaInicio = moment(new Date(this.selectedInicio))
const fechaFin = moment(new Date(this.selectedFin))
if (!fechaInicio.isValid() || !fechaFin.isValid()) return true
return false
},
descargar() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/servicio/reporte?inicio=${this.selectedInicio}&fin=${this.selectedFin}`,
this.admin.token
)
.then((res) => {
fileDownload(res.data, `reporte.csv`)
this.selectedInicio = []
this.selectedFin = []
this.updateIsLoading(false)
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
@@ -0,0 +1,149 @@
<template>
<div>
<h3 class="title">Casos Especiales</h3>
<div class="columns">
<b-field class="column" label="Número de Cuenta">
<b-input
type="text"
placeholder="No.Cuenta"
icon="school"
maxlength="9"
@keyup.enter.native="obtenerCasosEspeciales()"
v-model="search.numeroCuenta"
rounded
/>
</b-field>
<b-field class="column" label="Nombre">
<b-input
type="name"
placeholder="Nombre"
icon="account"
@keyup.enter.native="obtenerCasosEspeciales()"
v-model="search.nombre"
rounded
/>
</b-field>
<b-field class="column" label="Status">
<b-select icon="information" v-model="search.idStatus" expanded rounded>
<option value="">Status</option>
<option
v-for="(s, i) in status"
:key="i"
:value="s.idStatus"
v-show="i > 9"
>
{{ s.status }}
</option>
</b-select>
</b-field>
<b-field class="column is-align-self-center">
<b-button
type="is-info"
@click="obtenerCasosEspeciales()"
expanded
rounded
>
Buscar
</b-button>
</b-field>
</div>
<TablaServiciosSociales
:columnaFechaFin="false"
:columnaFechaInicio="false"
:isLoading="isLoading"
:path="'/admin/casos_especiales/caso_especial'"
:idTipoUsuario="admin.idTipoUsuario"
:page="page"
:total="total"
:data="data"
:onPageChange="onPageChange"
/>
</div>
</template>
<script>
import axios from 'axios'
import TablaServiciosSociales from '@/components/TablaServiciosSociales'
export default {
components: { TablaServiciosSociales },
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
data() {
return {
isLoading: false,
page: 1,
total: 0,
data: [],
status: [],
search: {
idStatus: '',
},
searchAnterior: {},
}
},
methods: {
onPageChange(page) {
this.page = page
this.obtenerCasosEspeciales()
},
obtenerCasosEspeciales() {
let data = ''
this.isLoading = true
if (
this.search.numeroCuenta != this.searchAnterior.numeroCuenta ||
this.search.nombre != this.searchAnterior.nombre ||
this.search.idStatus != this.searchAnterior.idStatus
) {
this.page = 1
this.searchAnterior.numeroCuenta = this.search.numeroCuenta
this.searchAnterior.nombre = this.search.nombre
this.searchAnterior.idStatus = this.search.idStatus
}
if (this.search.idStatus) data += `&idStatus=${this.search.idStatus}`
if (this.search.nombre) data += `&nombre=${this.search.nombre}`
if (this.search.numeroCuenta)
data = `&numeroCuenta=${this.search.numeroCuenta}`
axios
.get(
`${process.env.api}/caso_especial/servicios_especiales?pagina=${this.page}${data}`,
this.admin.token
)
.then((res) => {
this.data = res.data.serviciosEspeciales
this.total = res.data.count
this.isLoading = false
})
.catch((err) => {
this.isLoading = false
this.imprimirError(err.response.data)
})
},
obtenerCatalogoStatus() {
axios
.get(`${process.env.api}/status`, this.admin.token)
.then((res) => {
this.status = res.data
this.obtenerCasosEspeciales()
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
},
created() {
if (this.admin.idTipoUsuario === 1) this.obtenerCatalogoStatus()
},
}
</script>
<style scoped></style>
+147
View File
@@ -0,0 +1,147 @@
<template>
<div>
<h3 class="title">Tabla de responsables</h3>
<div class="columns">
<b-field class="column" label="Correo Electrónico">
<b-input
type="text"
placeholder="Correo"
icon="mail"
@keyup.enter.native="obtenerResponsables()"
v-model="search.correo"
rounded
/>
</b-field>
<b-field class="column" label="Nombre">
<b-input
type="name"
placeholder="Nombre"
icon="account"
@keyup.enter.native="obtenerResponsables()"
v-model="search.nombre"
rounded
/>
</b-field>
<b-field class="column is-align-self-center">
<b-button
type="is-info"
@click="obtenerResponsables()"
expanded
rounded
>
Buscar
</b-button>
</b-field>
</div>
<b-table
:data="data"
:total="total"
:current-page="page"
:per-page="perPage"
:loading="isLoading"
:selected.sync="responsableSelected"
:row-class="(row, index) => 'pointer'"
@page-change="onPageChange"
hoverable
striped
paginated
backend-pagination
>
<b-table-column
field="correo"
label="Correo Electrónico"
v-slot="props"
centered
>
<span>{{ props.row.usuario }}</span>
</b-table-column>
<b-table-column field="nombre" label="Nombre" v-slot="props" centered>
<span>{{ props.row.nombre }} </span>
</b-table-column>
<b-table-column field="estado" label="Estado" v-slot="props" centered>
<span class="tag" :class="style(props.row.activo)">
{{ props.row.activo ? 'Activo' : 'Desactivado' }}
</span>
</b-table-column>
</b-table>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
data() {
return {
isLoading: false,
page: 1,
perPage: 25,
total: 0,
data: [],
responsableSelected: {},
search: {},
searchAnterior: {},
}
},
methods: {
style(activo) {
if (activo) return 'is-success'
else return 'is-danger'
},
onPageChange(page) {
this.page = page
this.obtenerResponsables()
},
obtenerResponsables() {
let data = ''
this.isLoading = true
if (
this.search.correo != this.searchAnterior.correo ||
this.search.nombre != this.searchAnterior.nombre
) {
this.page = 1
this.searchAnterior.correo = this.search.correo
this.searchAnterior.nombre = this.search.nombre
}
if (this.search.nombre) data += `&nombre=${this.search.nombre}`
if (this.search.correo) data = `&correo=${this.search.correo}`
axios
.get(
`${process.env.api}/usuario/responsables?pagina=${this.page}${data}`,
this.admin.token
)
.then((res) => {
this.data = res.data.responsables
this.total = res.data.count
this.isLoading = false
})
.catch((err) => {
this.isLoading = false
this.imprimirError(err.response.data)
})
},
},
watch: {
responsableSelected() {
localStorage.setItem('idResponsable', this.responsableSelected.idUsuario)
this.$router.push(`/admin/responsables/responsable`)
},
},
created() {
if (this.admin.idTipoUsuario === 1) this.obtenerResponsables()
},
}
</script>
<style scoped></style>
+142
View File
@@ -0,0 +1,142 @@
<template>
<div>
<h3 class="title">Servicios Sociales</h3>
<div class="columns">
<b-field class="column" label="Número de Cuenta">
<b-input
type="text"
placeholder="No.Cuenta"
icon="school"
maxlength="9"
@keyup.enter.native="obtenerServicios()"
v-model="search.numeroCuenta"
rounded
/>
</b-field>
<b-field class="column" label="Nombre">
<b-input
type="name"
placeholder="Nombre"
icon="account"
@keyup.enter.native="obtenerServicios()"
v-model="search.nombre"
rounded
/>
</b-field>
<b-field class="column" label="Status">
<b-select icon="information" v-model="search.idStatus" rounded>
<option value="">Status</option>
<option
v-for="(s, i) in status"
:key="i"
:value="s.idStatus"
v-show="i < 10"
>
{{ s.status }}
</option>
</b-select>
</b-field>
<b-field class="column is-align-self-center">
<b-button type="is-info" @click="obtenerServicios()" expanded rounded>
Buscar
</b-button>
</b-field>
</div>
<TablaServiciosSociales
:isLoading="isLoading"
:path="'/admin/servicio'"
:idTipoUsuario="admin.idTipoUsuario"
:page="page"
:total="total"
:data="data"
:onPageChange="onPageChange"
/>
</div>
</template>
<script>
import axios from 'axios'
import TablaServiciosSociales from '@/components/TablaServiciosSociales'
export default {
components: { TablaServiciosSociales },
data() {
return {
isLoading: false,
page: 1,
total: 0,
data: [],
status: [],
search: {
idStatus: '',
},
searchAnterior: {},
}
},
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
methods: {
onPageChange(page) {
this.page = page
this.obtenerServicios()
},
obtenerServicios() {
let data = ''
this.isLoading = true
if (
this.search.numeroCuenta != this.searchAnterior.numeroCuenta ||
this.search.nombre != this.searchAnterior.nombre ||
this.search.idStatus != this.searchAnterior.idStatus
) {
this.page = 1
this.searchAnterior.numeroCuenta = this.search.numeroCuenta
this.searchAnterior.nombre = this.search.nombre
this.searchAnterior.idStatus = this.search.idStatus
}
if (this.search.idStatus) data += `&idStatus=${this.search.idStatus}`
if (this.search.nombre) data += `&nombre=${this.search.nombre}`
if (this.search.numeroCuenta)
data += `&numeroCuenta=${this.search.numeroCuenta}`
axios
.get(
`${process.env.api}/servicio/servicios_admin?pagina=${this.page}${data}`,
this.admin.token
)
.then((res) => {
this.data = res.data.serviciosAdmin
this.total = res.data.count
this.isLoading = false
})
.catch((err) => {
this.isLoading = false
this.imprimirError(err.response.data)
})
},
obtenerCatalogoStatus() {
axios
.get(`${process.env.api}/status`, this.admin.token)
.then((res) => {
this.status = res.data
this.obtenerServicios()
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
},
created() {
if (this.admin.idTipoUsuario === 1) this.obtenerCatalogoStatus()
},
}
</script>
<style scoped></style>
+23
View File
@@ -0,0 +1,23 @@
<template>
<div class="mb-5">
<h3 class="title" v-if="alumno.Status.idStatus === 1">
Confirmar el pre-registro del alumno
</h3>
<h3 class="title" v-if="alumno.Status.idStatus === 4">Término</h3>
<h3 class="title" v-if="alumno.Status.idStatus === 5">
Validar el término del alumno
</h3>
</div>
</template>
<script>
export default {
props: {
alumno: { type: Object, required: true },
},
}
</script>
<style scoped></style>
-195
View File
@@ -1,195 +0,0 @@
<template>
<div
v-if="alumno.Status.idServicio != 11 || alumno.Status.idServicio != 12"
class="footter"
>
<p
class="is-size-2 mb-3"
v-if="alumno.Status">
{{ alumno.Status.status }}
</p>
<p class="is-size-3"><b>Datos personales</b></p>
<p class="is-size-5 mt-3">
<b>Número de cuenta: </b> {{ alumno.Usuario.usuario }}
</p>
<p class="is-size-5 mt-3"><b>Nombre: </b> {{ alumno.Usuario.nombre }}</p>
<p class="is-size-5 mt-3"><b>Carrera: </b> {{ alumno.Carrera.carrera }}</p>
<p class="is-size-5 mt-3"><b>Correo: </b> {{ alumno.correo }}</p>
<p class="is-size-5 mt-3"><b>Dirección: </b> {{ alumno.direccion }}</p>
<p class="is-size-5 mt-3"><b>Teléfono: </b> {{ alumno.telefono }}</p>
<p
class="is-size-5 mt-3"
v-if="alumno.motivo">
<b>Motivo: </b>{{ motivo(alumno.motivo) }}
</p>
<p
class="is-size-5 mt-3"
v-if="alumno.institucion">
<b>Institución: </b>{{ alumno.institucion }}
</p>
<p
class="is-size-5 mt-3"
v-if="alumno.dependencia">
<b>Dependencia: </b>{{ alumno.dependencia }}
</p>
<p class="is-size-5 mt-3"><b>Créditos: </b> {{ alumno.creditos + "%" }}</p>
<p class="is-size-5 mt-3">
<b>Fecha de nacimiento: </b>
{{ fecha(alumno.fechaNacimiento) }}
</p>
<p class="is-size-5 mt-3">
<b>Fecha de inicio: </b>
{{ fecha(alumno.fechaInicio) }}
</p>
<p class="is-size-5 mt-3">
<b>Fecha de fin: </b>
{{ fecha(alumno.fechaFin) }}
</p>
<b-button class="is-info my-4" @click="editar()">
Editar información
</b-button>
<b-field
v-if="alumno.Status.idStatus === 11 || alumno.Status.idStatus === 12"
class="centro"
>
<b-button
class="boton border-info my-5"
type="is-success"
@click="confirmarLiberacion()"
>
Liberar
</b-button>
</b-field>
<b-loading
:is-full-page="true"
v-model="isLoading"
:can-cancel="false"
></b-loading>
</div>
</template>
<script>
import moment from "moment";
import axios from "axios";
export default {
data() {
return {
alumno: {
fechaNacimiento: "",
fechaInicio: "",
fechaFin: "",
Usuario: {},
Carrera: {},
Status: {},
},
token: {
headers: {
token: localStorage.getItem("token"),
},
},
idCasoEspecial: localStorage.getItem("idCasoEspecial"),
isLoading: false,
};
},
methods: {
editar(){
this.$router.push("/admin/especial/casoEspecial/editar");
},
obtenerDatos() {
return axios
.get(
`${process.env.api}/caso_especial/?idCasoEspecial=${this.idCasoEspecial}`,
this.token
)
.then((res) => {
this.alumno = res.data;
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
confirmarLiberacion() {
this.isLoading = true;
const data = { idCasoEspecial: this.idCasoEspecial };
axios
.put(`${process.env.api}/caso_especial/liberacion`, data, this.token)
.then((res) => {
this.$buefy.dialog.alert("El servicio ha sido liberado");
localStorage.removeItem("idCasoEspecial");
this.$router.push("/admin/especial");
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
fecha(date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
},
motivo(n) {
if(n == 1) {
return "Tercera edad"
}else if(n == 2) {
return "Capacidades diferentes"
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
created() {
this.obtenerDatos();
},
};
</script>
<style>
.centro {
text-align: center;
}
.footter {
margin-bottom: 6rem;
}
</style>
-272
View File
@@ -1,272 +0,0 @@
<template>
<div class="container">
<p class="is-size-2">Editar información del alumno</p>
<br />
<div class="formulario">
<b-field label="Correo eletrónico">
<b-input
type="email"
v-model="nuevo.correo"
:placeholder="viejo.correo"
>
</b-input>
</b-field>
<b-field label="Teléfono">
<b-input
type="number"
v-model="nuevo.telefono"
maxlength="10"
:placeholder="viejo.telefono"
>
</b-input>
</b-field>
<b-field label="Dirección">
<b-input
type="text"
v-model="nuevo.direccion"
:placeholder="viejo.direccion"
>
</b-input>
</b-field>
<b-field label="Fecha de inicio">
<b-datepicker
:placeholder="fecha(viejo.fechaInicio)"
icon="calendar-today"
v-model="nuevo.fechaInicio"
:min-date="minDate1"
>
</b-datepicker>
</b-field>
<transition name="fade">
<b-field label="Fecha de fin" v-if="nuevo.fechaInicio">
<b-datepicker
:placeholder="fecha(viejo.fechaFin)"
v-model="nuevo.fechaFin"
:min-date="minDate2"
icon="calendar-today"
>
</b-datepicker>
</b-field>
</transition>
<b-field label="Fecha de nacimiento">
<b-datepicker
:placeholder="fecha(viejo.fechaNacimiento)"
icon="calendar-today"
v-model="nuevo.fechaNacimiento"
>
</b-datepicker>
</b-field>
<b-field label="Motivo" v-if="viejo.motivo">
<b-select
class="my-4"
expanded
v-model="nuevo.motivo"
>
<option value="1">Tercera edad</option>
<option value="2">Capacidades diferentes</option>
</b-select>
</b-field>
<b-field label="Dependencia" v-if="viejo.dependencia">
<b-input
type="text"
v-model="nuevo.dependencia"
:placeholder="viejo.dependencia"
>
</b-input>
</b-field>
<b-field label="Institución" v-if="viejo.institucion">
<b-input
type="text"
v-model="nuevo.institucion"
:placeholder="viejo.institucion"
>
</b-input>
</b-field>
</div>
<b-button
v-if="mostrar()"
@click="actualizarDialog()"
class="my-5 is-success">
Actualizar Datos
</b-button>
<b-button v-else disabled class="is-success my-5">Actualizar Datos</b-button>
<b-loading
:is-full-page="true"
v-model="isLoading"
:can-cancel="false"
></b-loading>
</div>
</template>
<script>
import axios from "axios";
import moment from "moment";
import validator from "validator";
export default {
data() {
return {
idCasoEspecial: localStorage.getItem("idCasoEspecial"),
isLoading: false,
minDate1: new Date("2020-01-01"),
viejo: {},
nuevo: {
idCasoEspecial: null,
correo: "",
telefono: "",
fechaInicio: null,
fechaFin: null,
fechaNacimiento: null,
institucion: "",
dependencia: "",
motivo: "",
direccion: "",
},
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
mostrar(){
if (
validator.isEmail(this.nuevo.correo) ||
this.nuevo.direccion ||
this.nuevo.telefono ||
this.nuevo.fechaNacimiento ||
this.nuevo.motivo ||
this.nuevo.institucion ||
this.nuevo.dependencia ||
(this.nuevo.fechaInicio && this.nuevo.fechaFin)
) {
if (this.nuevo.correo) {
if (validator.isEmail(this.nuevo.correo)) {
return true;
} else {
return false;
}
}
return true;
}
},
actualizarDialog() {
this.$buefy.dialog.confirm({
title: "Actualizar datos",
message: "¿Seguro(a) que quiere actualizar estos datos?",
confirmText: "Confirmar",
cancelText: "Cancelar",
type: "is-success",
hasIcon: true,
onConfirm: () => this.actualizar(),
});
},
actualizar() {
this.isLoading = true;
const data = { idCasoEspecial: this.idCasoEspecial };
if (this.nuevo.direccion) data.direccion = this.nuevo.direccion;
if (this.nuevo.correo) data.correo = this.nuevo.correo;
if (this.nuevo.telefono) data.telefono = this.nuevo.telefono;
if (this.nuevo.motivo) data.motivo = this.nuevo.motivo;
if (this.nuevo.dependencia) data.dependencia = this.nuevo.dependencia;
if (this.nuevo.institucion) data.institucion = this.nuevo.institucion;
if (this.nuevo.fechaInicio) data.fechaInicio = moment(this.nuevo.fechaInicio);
if (this.nuevo.fechaFin) data.fechaFin = moment(this.nuevo.fechaFin);
if (this.nuevo.fechaNacimiento) data.fechaNacimiento = moment(this.nuevo.fechaNacimiento);
axios
.put(`${process.env.api}/caso_especial/update`, data, this.token)
.then((res) => {
this.$buefy.dialog.alert("Los datos han sido actualizados");
this.$router.push("/admin/especial/casoEspecial");
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
obtenerDatos() {
this.isLoading = true;
return axios
.get(
`${process.env.api}/caso_especial/?idCasoEspecial=${this.idCasoEspecial}`,
this.token
)
.then((res) => {
console.log(res.data);
this.viejo = res.data;
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
fecha(date) {
if (date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
}
},
},
computed: {
minDate2() {
const min = new Date(this.nuevo.fechaInicio);
return new Date(min.getFullYear(), min.getMonth() + 6, min.getDate());
},
},
created() {
this.obtenerDatos();
},
};
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>
@@ -1,307 +0,0 @@
<template>
<div
v-if="this.idTipoUsuario == 1 && this.tipoUsuario == 'admin'"
class="container"
>
<div class="columns">
<div class="column is-3 mb-0">
<b-field>
<b-input
placeholder="No.Cuenta"
icon="school"
rounded
v-model="numeroCuenta"
maxlength="9"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4">
<b-field>
<b-input
type="name"
placeholder="Nombre"
icon="account"
rounded
v-model="nombre"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4 ">
<b-field>
<b-select
placeholder="Status"
icon="information"
expanded
rounded
v-model="idStatus"
>
<optgroup>
<option value=""> Status </option>
<option value="11">Artículo 52</option>
<option value="12">Artículo 91</option>
<option value="13">Liberación Articulo 52</option>
<option value="14">Liberación Articulo 91</option>
</optgroup>
</b-select>
</b-field>
</div>
<div class="buttons section pt-3 pl-5">
<b-button type="is-info" @click="obtenerDatos(idStatus)">
Buscar
</b-button>
</div>
</div>
<div class="columns">
<section class="column is-12">
<b-table
:data="data"
:loading="isLoading"
paginated
backend-pagination
:total="total"
:per-page="perPage"
@page-change="onPageChange"
hoverable
striped
>
<b-table-column field="nombre" label="Nombre" v-slot="props" centered>
<span @click="servicios(props.row.idCasoEspecial)">{{
props.row.nombre
}}</span>
</b-table-column>
<b-table-column
field="numeroCuenta"
label="Número de Cuenta"
v-slot="props"
centered
width="100"
>
<span @click="servicios(props.row.idCasoEspecial)">{{
props.row.numeroCuenta
}}</span>
</b-table-column>
<b-table-column
field="carrera"
label="Carrera"
v-slot="props"
centered
>
<span @click="servicios(props.row.idCasoEspecial)">{{
props.row.carrera
}}</span>
</b-table-column>
<b-table-column field="status" label="Status" v-slot="props" centered>
<span
@click="servicios(props.row.idCasoEspecial)"
class="tag"
:class="types(props.row.idStatus)"
>{{ props.row.status }}</span
>
</b-table-column>
<b-table-column
field="diaCreado"
label="Día de creación"
v-slot="props"
centered
>
<span @click="servicios(props.row.idCasoEspecial)">{{
fecha(props.row.diaCreado)
}}</span>
</b-table-column>
</b-table>
</section>
</div>
</div>
</template>
<script>
import axios from "axios";
import moment from "moment";
export default {
data() {
return {
idUsuario: "",
idTipoUsuario: "",
tipoUsuario: "",
data: [],
total: "",
isLoading: false,
page: 1,
perPage: 25,
numeroCuenta: "",
nombre: "",
idStatus: "",
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
onPageChange(page) {
this.page = page;
this.obtenerDatos();
},
types(idStatus) {
if (idStatus === 1) {
return "is-dark";
} else if (idStatus === 2) {
return "is-info";
} else if (idStatus === 3) {
return "is-link";
} else if (idStatus === 4) {
return "is-warning";
} else if (idStatus === 5) {
return "is-success";
} else if (idStatus === 6) {
return "is-link";
} else if (
idStatus === 7 ||
idStatus === 8 ||
idStatus === 9 ||
idStatus === 10
) {
return "is-danger";
} else if (idStatus === 11) {
return "is-link is-light";
} else if (idStatus === 12) {
return "is-danger is-light";
} else if (idStatus === 13 || idStatus === 14) {
return "is-success is-light";
}
},
fecha(date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
},
obtenerDatos(idStatus) {
this.isLoading = true;
this.data = [];
axios
.get(
`${process.env.api}/caso_especial/servicios_especiales?pagina=${this.page}&idStatus=${this.idStatus}&nombre=${this.nombre}&numeroCuenta=${this.numeroCuenta}`,
this.token
)
.then((res) => {
const servicios = res.data.servicios;
if (servicios.length !== 0) {
for (let i = 0; i < servicios.length; i++) {
this.data.push({
nombre: servicios[i].Usuario.nombre,
numeroCuenta: servicios[i].Usuario.usuario,
carrera: servicios[i].Carrera.carrera,
status: servicios[i].Status.status,
diaCreado: servicios[i].createdAt,
idStatus: servicios[i].Status.idStatus,
idCasoEspecial: servicios[i].idCasoEspecial,
});
}
}
let currentTotal = servicios.length;
let contador;
for (let i = 0; i < res.data.registros / 25 + 1; i++) {
contador = i;
}
currentTotal = this.perPage * contador;
this.total = currentTotal;
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
servicios(idCasoEspecial) {
window.localStorage.setItem("idCasoEspecial", idCasoEspecial);
this.$router.push("/admin/especial/casoEspecial");
},
getIdLocal() {
this.idUsuario = 1; //localStorage.getItem("idUsuario");
this.idTipoUsuario = 1; //localStorage.getItem("idTipoUsuario");
this.tipoUsuario = "admin"; //localStorage.getItem("tipoUsuario");
if (this.idTipoUsuario != 1 && this.tipoUsuario != "admin") {
localStorage.clear();
this.$router.push("/");
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
created() {
this.getIdLocal();
this.obtenerDatos(0);
},
};
</script>
<style>
.input:focus {
border: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select select:focus {
border-color: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select:not(.is-multiple):not(.is-loading)::after {
border-color: #1b3d70;
}
.pagination-link.is-current {
background-color: #1b3d70;
border-color: #1b3d70;
}
.b-table {
cursor: pointer;
}
</style>
-335
View File
@@ -1,335 +0,0 @@
<template>
<div
v-if="this.idTipoUsuario == 1 && this.tipoUsuario == 'admin'"
class="container"
>
<div class="columns">
<div class="column is-3 mb-0">
<b-field>
<b-input
placeholder="No.Cuenta"
icon="school"
rounded
v-model="numeroCuenta"
maxlength="9"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4">
<b-field>
<b-input
type="name"
placeholder="Nombre"
icon="account"
rounded
v-model="nombre"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4 ">
<b-field>
<b-select
placeholder="Status"
icon="information"
expanded
rounded
v-model="idStatus"
>
<optgroup>
<option value=""> Status </option>
<option value="1">Pre-registro</option>
<option value="2">Pre-registro Validado</option>
<option value="3">Registro</option>
<option value="4">Pre-Término</option>
<option value="5">Término</option>
<option value="6">Liberación</option>
<option value="7">Carta Aceptacion Rechazada</option>
<option value="8">Carta Termino Rechazada</option>
<option value="9">Informe Global Rechazado</option>
<option value="10">Cancelado</option>
</optgroup>
</b-select>
</b-field>
</div>
<div class="buttons section pt-3 pl-5">
<b-button type="is-info" @click="obtenerDatos(idStatus)">
Buscar
</b-button>
</div>
</div>
<div class="columns">
<section class="column is-12">
<b-table
:data="data"
:loading="isLoading"
paginated
backend-pagination
:total="total"
:per-page="perPage"
@page-change="onPageChange"
hoverable
striped
>
<b-table-column field="nombre" label="Nombre" v-slot="props" centered>
<span @click="servicios(props.row.idServicio)">{{
props.row.nombre
}}</span>
</b-table-column>
<b-table-column
field="numeroCuenta"
label="Número de Cuenta"
v-slot="props"
centered
width="100"
>
<span @click="servicios(props.row.idServicio)">{{
props.row.numeroCuenta
}}</span>
</b-table-column>
<b-table-column
field="carrera"
label="Carrera"
v-slot="props"
centered
>
<span @click="servicios(props.row.idServicio)">{{
props.row.carrera
}}</span>
</b-table-column>
<b-table-column
field="fechaInicio"
truncate="10"
label="Fecha Inicio"
v-slot="props"
centered
>
<span @click="servicios(props.row.idServicio)">{{
fecha(props.row.fechaInicio)
}}</span>
</b-table-column>
<b-table-column
field="fechaFin"
label="Fecha Fin"
v-slot="props"
centered
>
<span @click="servicios(props.row.idServicio)">{{
fecha(props.row.fechaFin)
}}</span>
</b-table-column>
<b-table-column field="status" label="Status" v-slot="props" centered>
<span
@click="servicios(props.row.idServicio)"
class="tag"
:class="types(props.row.idStatus)"
>{{ props.row.status }}</span
>
</b-table-column>
<b-table-column
field="diaCreado"
label="Día de creación"
v-slot="props"
centered
>
<span @click="servicios(props.row.idServicio)">{{
fecha(props.row.diaCreado)
}}</span>
</b-table-column>
</b-table>
</section>
</div>
</div>
</template>
<script>
import axios from "axios";
import moment from "moment";
export default {
data() {
return {
idUsuario: "",
idTipoUsuario: "",
tipoUsuario: "",
data: [],
total: "",
isLoading: false,
page: 1,
perPage: 25,
numeroCuenta: "",
nombre: "",
idStatus: "",
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
onPageChange(page) {
this.page = page;
this.obtenerDatos();
},
types(idStatus) {
if (idStatus === 1) {
return "is-dark";
} else if (idStatus === 2) {
return "is-info";
} else if (idStatus === 3) {
return "is-warning";
} else if (idStatus === 4) {
return "is-link";
} else if (idStatus === 5) {
return "is-success";
} else if (idStatus === 6) {
return "is-success is-light";
} else if (idStatus === 7) {
return "is-danger";
} else if (idStatus === 8) {
return "is-danger";
} else if (idStatus === 9) {
return "is-danger";
} else if (idStatus === 10) {
// admin
return "is-danger";
}
},
fecha(date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
},
obtenerDatos(idStatus) {
this.isLoading = true;
this.data = [];
axios
.get(
`${process.env.api}/servicio/servicios_admin?pagina=${this.page}&idStatus=${this.idStatus}&nombre=${this.nombre}&numeroCuenta=${this.numeroCuenta}`,
this.token
)
.then((res) => {
const servicios = res.data.servicios;
if (servicios.length !== 0) {
for (let i = 0; i < servicios.length; i++) {
this.data.push({
nombre: servicios[i].Usuario.nombre,
numeroCuenta: servicios[i].Usuario.usuario,
carrera: servicios[i].Carrera.carrera,
fechaInicio: servicios[i].fechaInicio,
fechaFin: servicios[i].fechaFin,
status: servicios[i].Status.status,
diaCreado: servicios[i].createdAt,
idStatus: servicios[i].Status.idStatus,
idServicio: servicios[i].idServicio,
});
}
}
let currentTotal = servicios.length;
let contador;
for (let i = 0; i < res.data.registros / 25 + 1; i++) {
contador = i;
}
currentTotal = this.perPage * contador;
this.total = currentTotal;
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
servicios(idServicio) {
window.localStorage.setItem("idServicio", idServicio);
this.$router.push("/admin/servicio");
},
getIdLocal() {
this.idUsuario = localStorage.getItem("idUsuario");
this.idTipoUsuario = localStorage.getItem("idTipoUsuario");
this.tipoUsuario = localStorage.getItem("tipoUsuario");
if (this.idTipoUsuario != 1 && this.tipoUsuario != "admin") {
localStorage.clear();
this.$router.push("/");
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
created() {
this.getIdLocal();
this.obtenerDatos(0);
},
};
</script>
<style>
.input:focus {
border: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select select:focus {
border-color: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select:not(.is-multiple):not(.is-loading)::after {
border-color: #1b3d70;
}
.pagination-link.is-current {
background-color: #1b3d70;
border-color: #1b3d70;
}
.b-table {
cursor: pointer;
}
</style>
-143
View File
@@ -1,143 +0,0 @@
<template>
<div>
<p class="is-size-2 mb-5">Carga Masiva</p>
<b-field v-if="true">
<b-upload
v-model="csv"
type="is-black"
v-on:input="validarExt()"
drag-drop
expanded
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
csv.name || "Arrastra aquí tu archivo o da click para buscar"
}}
</p>
</div>
</section>
</b-upload>
</b-field>
<b-button v-if="csv.name" @click="dialog()" class="is-info"
>Enviar archivo</b-button
>
<b-button v-else disabled class="is-info">Enviar archivo</b-button>
<b-loading
:is-full-page="true"
v-model="isLoading"
:can-cancel="false"
></b-loading>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
csv: {},
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
isLoading: false,
toastType: null,
toastMessage: null,
};
},
methods: {
validarExt() {
const extPermitidas = /(.csv)$/i;
if (!extPermitidas.exec(this.csv.name)) {
this.toastType = "is-danger";
this.toastMessage = "Asegurate de ingresar un archivo .CSV";
this.toast();
this.csv = {};
}
},
toast() {
this.$buefy.toast.open({
message: this.toastMessage,
type: this.toastType,
});
},
dialog() {
this.$buefy.dialog.confirm({
title: "Carga masiva",
message: "¿Seguro(a) que quiere enviar este archivo?",
confirmText: "Confirmar",
cancelText: "Cancelar",
type: "is-success",
hasIcon: true,
onConfirm: () => this.enviarCargaMasiva(),
});
},
enviarCargaMasiva() {
const formData = new FormData();
this.isLoading = true;
formData.append("csv", this.csv);
axios
.post(`${process.env.api}/programa/carga_masiva`, formData, {
headers: {
"Content-Type": "multipart/form-data",
token: this.token.headers.token,
},
})
.then((res) => {
this.isLoading = false;
this.toastType = "is-success";
this.toastMessage = "Se ha enviado la carga masiva con éxito";
this.toast();
this.$router.push("/admin");
})
.catch((err) => {
this.isLoading = false;
this.error(err.response.data.message);
});
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
};
</script>
@@ -1,201 +0,0 @@
<template>
<div class="container mt-5">
<p class="is-size-2 mb-5">Lista de responsables</p>
<div class="columns">
<div class="column is-3 mb-4 pb-4">
<b-field>
<b-input
type="name"
placeholder="Nombre"
icon="account"
rounded
v-model="nombre"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-0">
<b-field>
<b-input
placeholder="Correo electrónico"
icon="school"
rounded
v-model="correo"
>
</b-input>
</b-field>
</div>
<div class="buttons section pt-3 pl-5">
<b-button type="is-info" @click="obtenerDatos(idStatus)">
Buscar
</b-button>
</div>
</div>
<div class="columns mb-5">
<section class="column is-12">
<b-table
:data="data"
:loading="loading"
hoverable
striped
paginated
backend-pagination
:total="total"
:per-page="perPage"
@page-change="onPageChange"
>
<b-table-column field="nombre" label="Nombre" v-slot="props" centered>
<span @click="verRegistro(props.row)">{{ props.row.nombre }}</span>
</b-table-column>
<b-table-column
field="correo"
label="Correo electrónico"
v-slot="props"
centered
>
<span @click="verRegistro(props.row)">{{ props.row.usuario }}</span>
</b-table-column>
</b-table>
</section>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
idUsuario: "",
data: [],
total: "",
loading: false,
page: 1,
perPage: 25,
correo: "",
nombre: "",
idStatus: 1,
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
onPageChange(page) {
this.page = page;
this.obtenerDatos();
},
obtenerDatos(idStatus) {
this.loading = true;
this.data = [];
axios
.get(
`${process.env.api}/usuario/responsable?pagina=${this.page}&nombre=${this.nombre}&correo=${this.correo}`,
this.token
)
.then((res) => {
const servicios = res.data.servicios;
if (servicios.length !== 0) {
for (let i = 0; i < servicios.length; i++) {
this.data.push({
nombre: servicios[i].nombre,
usuario: servicios[i].usuario,
idUsuario: servicios[i].idUsuario,
});
}
}
let currentTotal = servicios.length;
let contador;
for (let i = 0; i < res.data.registros / this.perPage + 1; i++) {
contador = i;
}
currentTotal = this.perPage * contador;
this.total = currentTotal;
this.loading = false;
})
.catch((err) => {
this.loading = false;
this.error(err.response.data.message);
});
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
insertIdLocal() {
this.idUsuario = localStorage.getItem("idUsuario");
},
verRegistro(responsable) {
localStorage.setItem("correo", responsable.usuario);
localStorage.setItem("idResponsable", responsable.idUsuario);
localStorage.setItem("nombre", responsable.nombre);
this.$router.push("/admin/programa/infoResponsable");
},
},
computed: {
busquedaNombreResponsable() {
return this.responsables.filter((responsables) =>
responsables.nombreResp.includes(this.buscarNombreResponsable)
);
},
},
async created() {
await this.obtenerDatos();
this.insertIdLocal();
},
};
</script>
<style scoped>
.b-table {
cursor: pointer;
}
.input:focus {
border: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select select:focus {
border-color: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select:not(.is-multiple):not(.is-loading)::after {
border-color: #1b3d70;
}
.pagination-link.is-current {
background-color: #1b3d70;
border-color: #1b3d70;
}
</style>
@@ -1,51 +0,0 @@
<template>
<div id="datosPersonales">
<p class="is-size-3"><b>Datos personales</b></p>
<p class="is-size-5 mt-3" v-if="alumno.Usuario.nombre">
<b>Nombre: </b>{{ alumno.Usuario.nombre }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.Usuario.usuario">
<b>Número de cuenta: </b>{{ alumno.Usuario.usuario }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.Carrera.carrera">
<b>Carrera: </b>{{ alumno.Carrera.carrera }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.correo">
<b>Correo: </b>{{ alumno.correo }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.creditos">
<b>Créditos: </b>{{ alumno.creditos + "%" }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.fechaInicio">
<b>Fecha de inicio: </b>{{ fecha(alumno.fechaInicio) }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.fechaFin">
<b>Fecha de fin: </b>{{ fecha(alumno.fechaFin) }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.telefono">
<b>Teléfono: </b>{{ alumno.telefono }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.direccion">
<b>Dirección: </b>{{ alumno.direccion }}
</p>
<p class="is-size-5 mt-3" v-if="alumno.fechaNacimiento">
<b>Fecha de nacimiento: </b>{{ fecha(alumno.fechaNacimiento) }}
</p>
</div>
</template>
<script>
import moment from "moment";
export default {
props: {
alumno: Object,
},
methods: {
fecha(date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
},
},
};
</script>
@@ -1,28 +0,0 @@
<template>
<div id="programa">
<br />
<p class="is-size-3"><b>Datos del programa</b></p>
<br />
<p class="is-size-5 mb-3" v-if="programa.programa">
<b>Programa: </b><span> {{ programa.programa }} </span>
</p>
<p class="is-size-5 mb-3" v-if="programa.clavePrograma">
<b>Clave del programa: </b><span> {{ programa.clavePrograma }} </span>
</p>
<p class="is-size-5 mb-3" v-if="programa.dependencia">
<b>Dependecia: </b><span> {{ programa.dependencia }} </span>
</p>
<p class="is-size-5 mb-3" v-if="programa.institucion">
<b>Institución: </b><span> {{ programa.institucion }} </span>
</p>
<br />
</div>
</template>
<script>
export default {
props: {
programa: Object,
},
};
</script>
-209
View File
@@ -1,209 +0,0 @@
<template>
<div>
<span class="spanDoc"
><strong>{{ title }}</strong></span
>
<a :href="link" target="_blank">
<b-button class="is-info">
Ver
</b-button>
</a>
<b-button
class="is-danger"
v-if="esRechazable()"
@click="mensajeBool = !mensajeBool"
>
Rechazar
</b-button>
<b-field label="Razón del rechazo: " v-if="mensajeBool">
<b-input maxlength="500" type="textarea" v-model="mensajeRech"></b-input>
</b-field>
<b-button
v-if="mensajeRech && mensajeBool"
class="is-danger"
@click="rechazarDialog()"
>
Rechazar documento
</b-button>
<b-button v-else-if="mensajeBool" disabled>
Rechazar documento
</b-button>
<b-loading
:is-full-page="true"
v-model="isLoading"
:can-cancel="false"
></b-loading>
</div>
</template>
<script>
import axios from "axios";
export default {
props: {
title: String,
link: String,
idDoc: Number,
doc: String,
status: Number,
},
data() {
return {
mensajeRech: "",
mensajeBool: false,
idServicio: localStorage.getItem("idServicio"),
isLoading: false,
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
esRechazable() {
switch (this.idDoc) {
case 1:
if (this.status == 1) return true;
else return false;
case 2:
if (this.status == 5) return true;
else return false;
case 3:
if (this.status == 5) return true;
else return false;
}
},
rechazarDialog() {
this.$buefy.dialog.confirm({
title: "Confimar servicio",
message: "¿Seguro(a) que quiere rechazar este documento?",
confirmText: "Confirmar",
cancelText: "Cancelar",
type: "is-danger",
hasIcon: true,
onConfirm: () => {
switch (this.idDoc) {
case 1:
this.rechazarCartaAceptacion();
break;
case 2:
this.rechazarCartaTermino();
break;
case 3:
this.rechazarInformeGlobal();
}
},
});
},
rechazarCartaAceptacion() {
this.isLoading = true;
const data = {
mensaje: this.mensajeRech,
idServicio: this.idServicio,
};
axios
.put(
`${process.env.api}/servicio/rechazar_aceptacion`,
data,
this.token
)
.then((res) => {
this.isLoading = false;
this.$buefy.dialog.alert("Se ha rechazado el documento");
this.$router.push("/admin");
})
.catch((err) => {
this.isLoading = false;
this.error(err.response.data.message);
this.errorDoc();
});
},
rechazarCartaTermino() {
this.isLoading = true;
const data = {
mensaje: this.mensajeRech,
idServicio: this.idServicio,
};
axios
.put(`${process.env.api}/servicio/rechazar_termino`, data, this.token)
.then((res) => {
this.isLoading = false;
this.$buefy.dialog.alert("Se ha rechazado el documento");
this.$router.push("/admin");
})
.catch((err) => {
this.isLoading = false;
this.error(err.response.data.message);
this.errorDoc();
});
},
rechazarInformeGlobal() {
this.isLoading = true;
const data = {
mensaje: this.mensajeRech,
idServicio: this.idServicio,
};
axios
.put(`${process.env.api}/servicio/rechazar_informe`, data, this.token)
.then((res) => {
this.isLoading = false;
this.$buefy.dialog.alert("Se ha rechazado el documento");
this.$router.push("/admin");
})
.catch((err) => {
this.isLoading = false;
this.error(err.response.data.message);
this.errorDoc();
});
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
errorDoc() {
this.$buefy.dialog.alert({
title: "Error",
message: "Ha ocurrido un error al rechazar el documento",
type: "is-danger",
hasIcon: true,
icon: "times-circle",
iconPack: "fa",
ariaRole: "alertdialog",
ariaModal: true,
});
},
},
};
</script>
@@ -1,438 +0,0 @@
<template>
<div class="container" :class="{ pad: padding }">
<BotonRegresar :path="'/admin/servicio'" />
<br /><br />
<p class="is-size-2">Editar información del alumno</p>
<br />
<div class="formulario">
<b-field label="Correo eletrónico alumno">
<b-input
type="email"
v-model="nuevo.correo"
:placeholder="viejo.correo"
>
</b-input>
</b-field>
<div v-if="status6()">
<b-field label="Fecha de inicio">
<b-datepicker
:placeholder="fecha(viejo.fechaInicio)"
icon="calendar-today"
v-model="fechaInicio[0]"
:min-date="minDate1"
>
</b-datepicker>
</b-field>
<transition name="fade">
<b-field label="Fecha de fin" v-if="fechaInicio[0]">
<b-datepicker
:placeholder="fecha(viejo.fechaInicio)"
v-model="fechaFin[0]"
:min-date="minDate2"
icon="calendar-today"
>
</b-datepicker>
</b-field>
</transition>
<b-field label="Dirección">
<b-input
type="text"
v-model="nuevo.direccion"
:placeholder="viejo.direccion"
>
</b-input>
</b-field>
<b-field label="Teléfono">
<b-input
type="number"
:placeholder="viejo.telefono"
v-model="nuevo.telefono"
maxlength="10"
></b-input>
</b-field>
<b-field label="Fecha de nacimiento">
<b-datepicker
:placeholder="fecha(viejo.fechaNacimiento)"
v-model="fechaNacimiento[0]"
icon="calendar-today"
>
</b-datepicker>
</b-field>
<p class="is-size-5" v-if="viejo.cartaAceptacion">
Carta de aceptación
</p>
<br />
<b-field v-if="viejo.cartaAceptacion">
<b-upload
v-model="nuevo.cartaAceptacion"
type="is-black"
v-on:input="validarExt(1)"
accept="application/pdf"
drag-drop
expanded
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
nuevo.cartaAceptacion.name ||
"Arrastra aquí tu archivo o da click para buscar"
}}
</p>
</div>
</section>
</b-upload>
</b-field>
<p class="is-size-5" v-if="viejo.cartaTermino">Carta de término</p>
<br />
<b-field v-if="viejo.cartaTermino">
<b-upload
v-model="nuevo.cartaTermino"
type="is-black"
v-on:input="validarExt(2)"
accept="application/pdf"
drag-drop
expanded
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
nuevo.cartaTermino.name ||
"Arrastra aquí tu archivo o da click para buscar"
}}
</p>
</div>
</section>
</b-upload>
</b-field>
<p class="is-size-5" v-if="viejo.informeGlobal">Informe global</p>
<br />
<b-field v-if="viejo.informeGlobal">
<b-upload
v-model="nuevo.informeGlobal"
type="is-black"
v-on:input="validarExt(3)"
accept="application/pdf"
drag-drop
expanded
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
nuevo.informeGlobal.name ||
"Arrastra aquí tu archivo o da click para buscar"
}}
</p>
</div>
</section>
</b-upload>
</b-field>
</div>
<br />
<b-button v-if="mostrar()" @click="actualizarDialog()" class="is-info">
Actualizar Datos
</b-button>
<b-button v-else disabled class="is-info">Actualizar Datos</b-button>
<b-button @click="passwordDialog()" class="is-info">
Cambiar contraseña
</b-button>
<b-loading
:is-full-page="true"
v-model="isLoading"
:can-cancel="false"
></b-loading>
</div>
</div>
</template>
<script>
import axios from "axios";
import moment from "moment";
import validator from "validator";
import botonRegresar from "../../../botonRegresar";
export default {
components: {
botonRegresar,
},
data() {
return {
idServicio: localStorage.getItem("idServicio"),
idStatus: Number(localStorage.getItem("idStatus")),
viejo: {},
nuevo: {
correo: "",
fechaInicioFinal: "",
fechaFinFinal: null,
direccion: null,
telefono: null,
fechaNacimientoFinal: null,
cartaAceptacion: {},
cartaTermino: {},
informeGlobal: {},
},
fechaNacimiento: [],
fechaInicio: [],
fechaFin: [],
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
minDate1: new Date("2020-01-01"),
isLoading: false,
padding: false,
};
},
methods: {
status6() {
if (this.idStatus === 6) {
this.padding = true;
return false;
}
return true;
},
obtenerRegistro() {
this.isLoading = true;
return axios
.get(
`${process.env.api}/servicio/admin?idServicio=${this.idServicio}`,
this.token
)
.then((res) => {
this.viejo = res.data;
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
dangerToast() {
this.$buefy.toast.open({
message: "Asegurate de ingresar un PDF",
type: "is-danger",
});
},
toast() {
this.$buefy.toast.open({
message: "Se han actualizado los datos",
type: "is-success",
});
},
mostrar() {
if (
validator.isEmail(this.nuevo.correo) ||
this.nuevo.direccion ||
this.nuevo.telefono ||
this.nuevo.fechaNacimientoFinal ||
(this.nuevo.fechaInicioFinal && this.nuevo.fechaFinFinal) ||
this.nuevo.cartaTermino.name ||
this.nuevo.cartaAceptacion.name ||
this.nuevo.informeGlobal.name
) {
if (this.nuevo.correo) {
if (validator.isEmail(this.nuevo.correo)) {
return true;
} else {
return false;
}
}
return true;
}
},
validarExt(a) {
const extPermitidas = /(.pdf)$/i;
switch (a) {
case 1:
if (!extPermitidas.exec(this.nuevo.cartaAceptacion.name)) {
this.dangerToast();
this.nuevo.cartaAceptacion = {};
}
break;
case 2:
if (!extPermitidas.exec(this.nuevo.cartaTermino.name)) {
this.dangerToast();
this.nuevo.cartaTermino = {};
}
break;
case 3:
if (!extPermitidas.exec(this.nuevo.informeGlobal.name)) {
this.dangerToast();
this.nuevo.informeGlobal = {};
}
break;
}
},
actualizar() {
const formData = new FormData();
const data = { idServicio: this.idServicio };
this.isLoading = true;
if (this.nuevo.direccion) data.direccion = this.nuevo.direccion;
if (this.nuevo.correo) data.correo = this.nuevo.correo;
if (this.nuevo.telefono) data.telefono = this.nuevo.telefono;
if (this.nuevo.fechaInicioFinal)
data.fechaInicio = this.nuevo.fechaInicioFinal;
if (this.nuevo.fechaFinFinal) data.fechaFin = this.nuevo.fechaFinFinal;
if (this.nuevo.fechaNacimientoFinal)
data.fechaNacimiento = this.nuevo.fechaNacimientoFinal;
formData.append("data", JSON.stringify(data));
if (this.nuevo.cartaAceptacion)
formData.append("cartaAceptacion", this.nuevo.cartaAceptacion);
if (this.nuevo.cartaTermino)
formData.append("cartaTermino", this.nuevo.cartaTermino);
if (this.nuevo.informeGlobal)
formData.append("informeGlobal", this.nuevo.informeGlobal);
axios
.put(`${process.env.api}/servicio/update`, formData, {
headers: {
"Content-Type": "multipart/form-data",
token: this.token.headers.token,
},
})
.then((res) => {
this.toast();
this.$router.push("/admin/servicio");
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
actualizarDialog() {
this.$buefy.dialog.confirm({
title: "Actualizar datos",
message: "¿Seguro(a) que quiere actualizar estos datos?",
confirmText: "Confirmar",
cancelText: "Cancelar",
type: "is-success",
hasIcon: true,
onConfirm: () => this.actualizar(),
});
},
passwordDialog() {
this.$buefy.dialog.confirm({
title: "Actualizar datos",
message: "¿Seguro(a) que quiere actualizar la contraseña?",
confirmText: "Confirmar",
cancelText: "Cancelar",
type: "is-success",
hasIcon: true,
onConfirm: () => this.password(),
});
},
password() {
this.isLoading = true;
const data = { idServicio: this.idServicio };
axios
.put(`${process.env.api}/usuario/new_password_alumno`, data, this.token)
.then((res) => {
this.$buefy.toast.open({
message: "Se ha enviado el correo con la nueva contraseña",
type: "is-success",
});
this.$router.push("/admin");
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
fecha(date) {
if (date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
}
},
},
computed: {
minDate2() {
const min = new Date(this.fechaInicio);
return new Date(min.getFullYear(), min.getMonth() + 6, min.getDate());
},
},
watch: {
fechaInicio: function() {
this.nuevo.fechaInicioFinal = moment(this.fechaInicio[0]);
this.fechaFin[0] = null;
},
fechaFin: function() {
this.nuevo.fechaFinFinal = moment(this.fechaFin[0]);
},
fechaNacimiento: function() {
this.nuevo.fechaNacimientoFinal = moment(this.fechaNacimiento[0]);
},
},
created() {
this.obtenerRegistro();
},
};
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
.pad {
padding-bottom: 5%;
padding-top: 5%;
}
</style>
@@ -1,30 +0,0 @@
<template>
<div id="Status">
<p class="is-size-1" v-if="status == 1">
Pre Registro
</p>
<p class="is-size-1" v-else-if="status == 2">
Pre Registro Válidado
</p>
<p class="is-size-1" v-else-if="status == 3">
Registro
</p>
<p class="is-size-1" v-else-if="status == 4">
Pre Término
</p>
<p class="is-size-1" v-else-if="status == 5">
Término
</p>
<p class="is-size-1" v-else-if="status == 6">
Liberación
</p>
</div>
</template>
<script>
export default {
props: {
status: Number,
},
};
</script>
@@ -1,27 +0,0 @@
<template>
<div>
<h3 class="is-size-3 mb-5" v-if="status == 1">
<strong>
Confirmar el pre-registro del alumno
</strong>
</h3>
<h3 class="is-size-3 mb-5" v-if="status == 4">
<strong>
Término
</strong>
</h3>
<h3 class="is-size-3 mb-5" v-if="status == 5">
<strong>
Validar el término del alumno
</strong>
</h3>
</div>
</template>
<script>
export default {
props: {
status: Number,
},
};
</script>
-364
View File
@@ -1,364 +0,0 @@
<template>
<div class="container">
<div class="mb-5">
<BotonRegresar
:path="'/admin'"
:deleteFromLocalStorage="['idServicio', 'idStatus']"
/>
</div>
<TituloServicio :status="alumno.Status.idStatus" />
<DatosPrograma :programa="alumno.Programa" />
<DatosPersonales :alumno="alumno" />
<div id="enlaces">
<b-button class="boton is-info" @click="editar()" v-if="mostrarEditar()">
Editar información
</b-button>
<br /><br />
<TituloStatus :status="alumno.Status.idStatus" />
<div v-if="alumno.cartaAceptacion">
<Documento
:title="'Ver carta de aceptación'"
:link="linkCartaAceptacion"
:doc="alumno.cartaAceptacion"
:idDoc="1"
:status="alumno.Status.idStatus"
/>
</div>
<div v-if="alumno.cartaTermino" style="margin-top: 10px">
<Documento
:title="'Ver carta de término'"
:link="linkCartaTermino"
:doc="alumno.cartaTermino"
:idDoc="2"
:status="alumno.Status.idStatus"
/>
</div>
<div v-if="alumno.informeGlobal" style="margin-top: 10px">
<Documento
:title="'Ver informe global de actividades'"
:link="linkInformeGlobal"
:doc="alumno.InformeGlobal"
:idDoc="3"
:status="alumno.Status.idStatus"
/>
</div>
<b-checkbox
v-if="alumno.Programa.acatlan && alumno.Status.idStatus == 5"
v-model="alumno.vistoBuenoAcatlan"
size="is-medium"
type="is-info"
>
Visto bueno Acatlán
</b-checkbox>
<p v-if="alumno.idCuestionarioPrograma" class="my-4">
<strong>
Cuenta con cuestionario de programa resuelto.
</strong>
</p>
<p v-if="alumno.idCuestionarioAlumno" class="my-4">
<strong>
Cuenta con cuestionario de alumno resuelto.
</strong>
</p>
</div>
<div id="acciones" class="my-5">
<b-button
class="is-success"
@click="confirmarDialog(1)"
v-if="mostrarConfirmar1()"
>
Confirmar
</b-button>
<b-button
class="is-success"
@click="confirmarDialog(2)"
v-if="mostrarConfirmar2() && mostrarVistoBueno()"
>
Confirmar
</b-button>
<b-button
v-if="mostrarCancelar()"
class="is-danger"
@click="enviarCancel = !enviarCancel"
>
Cancelar
</b-button>
<br /><br />
<b-field label="Razón para cancelar: " v-if="enviarCancel">
<b-input
maxlength="500"
type="textarea"
v-model="mensajeCancel"
></b-input>
</b-field>
<b-button
v-if="mensajeCancel && enviarCancel"
class="is-danger"
@click="cancelarDialog()"
>
Cancelar servicio
</b-button>
<b-button v-else-if="enviarCancel" disabled>
Cancelar servicio
</b-button>
<div>
<BotonRegresar
:path="'/admin'"
:deleteFromLocalStorage="['idServicio', 'idStatus']"
/>
</div>
<b-loading
:is-full-page="true"
v-model="isLoading"
:can-cancel="false"
></b-loading>
</div>
</div>
</template>
<script>
import axios from "axios";
import tituloServicio from "./tituloServicio";
import tituloStatus from "./tituloStatus";
import datosPrograma from "./datosPrograma";
import datosPersonales from "./datosPersonales";
import documento from "./documento";
import botonRegresar from "../../botonRegresar";
export default {
components: {
tituloServicio,
datosPrograma,
datosPersonales,
tituloStatus,
documento,
botonRegresar,
},
data() {
return {
alumno: {
Programa: {},
Usuario: {},
Carrera: {},
Status: {},
},
idServicio: localStorage.getItem("idServicio"),
token: {
headers: {
token: localStorage.getItem("token"),
},
},
linkCartaAceptacion: "",
linkCartaTermino: "",
linkInformeGlobal: "",
enviarMensaje: false,
enviarCancel: false,
mensaje: "",
mensajeCancel: "",
isLoading: false,
};
},
methods: {
mostrarConfirmar1() {
if (this.alumno.Status.idStatus === 1) return true;
return false;
},
mostrarConfirmar2() {
if (this.alumno.Status.idStatus === 5) {
if (!this.alumno.acatlanContigo) return true;
else if (this.alumno.vistoBueno) return true;
}
return false;
},
mostrarCancelar() {
if (
this.alumno.Status.idStatus === 10 ||
this.alumno.Status.idStatus === 6
)
return false;
return true;
},
mostrarEditar() {
if (this.alumno.Status.idStatus === 10) return false;
return true;
},
mostrarVistoBueno() {
if (!this.alumno.Programa.acatlan) return true;
if (this.alumno.vistoBuenoAcatlan) return true;
return false;
},
editar() {
localStorage.setItem("idStatus", this.alumno.Status.idStatus);
this.$router.push("servicio/modificar");
},
obtenerRegistro() {
this.isLoading = true;
return axios
.get(
`${process.env.api}/servicio/admin?idServicio=${this.idServicio}`,
this.token
)
.then((res) => {
this.alumno = res.data;
this.alumno.creditos = Number(res.data.creditos);
if (this.alumno.cartaAceptacion)
this.linkCartaAceptacion = `https://drive.google.com/file/d/${this.alumno.cartaAceptacion}/view?usp=sharing`;
if (this.alumno.cartaTermino)
this.linkCartaTermino = `https://drive.google.com/file/d/${this.alumno.cartaTermino}/view?usp=sharing`;
if (this.alumno.informeGlobal)
this.linkInformeGlobal = `https://drive.google.com/file/d/${this.alumno.informeGlobal}/view?usp=sharing`;
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
cancelarDialog() {
this.$buefy.dialog.confirm({
title: "Cancelar sevicio",
message: "¿Seguro(a) que quiere cancelar este servicio?",
confirmText: "Cancelar servicio",
cancelText: "No",
type: "is-danger",
hasIcon: true,
onConfirm: () => this.cancelar(),
});
},
confirmarDialog(a) {
this.$buefy.dialog.confirm({
title: "Confimar servicio",
message: "¿Seguro(a) que quiere confirmar este servicio?",
confirmText: "Confirmar",
cancelText: "Cancelar",
type: "is-success",
hasIcon: true,
onConfirm: () => {
switch (a) {
case 1:
this.confirmarRegistro();
break;
case 2:
this.confirmarLiberacion();
break;
}
},
});
},
cancelar() {
this.isLoading = true;
const data = { idServicio: this.idServicio, mensaje: this.mensajeCancel };
axios
.put(`${process.env.api}/servicio/cancelar`, data, this.token)
.then((res) => {
this.$buefy.dialog.alert("El servicio ha sido cancelado con éxito");
localStorage.removeItem("idServicio");
this.$router.push("/admin");
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
confirmarRegistro() {
this.isLoading = true;
const data = { idServicio: this.idServicio };
axios
.put(`${process.env.api}/servicio/registro`, data, this.token)
.then((res) => {
this.$buefy.dialog.alert("El servicio ha sido aprobado");
localStorage.removeItem("idServicio");
this.$router.push("/admin");
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
confirmarLiberacion() {
this.isLoading = true;
const data = { idServicio: this.idServicio };
if (this.alumno.vistoBuenoAcatlan)
data.vistoBuenoAcatlan = this.alumno.vistoBuenoAcatlan;
axios
.put(`${process.env.api}/servicio/liberacion`, data, this.token)
.then((res) => {
this.$buefy.dialog.alert("El servicio ha sido liberado");
localStorage.removeItem("idServicio");
this.$router.push("/admin");
})
.catch((err) => {
this.error(err.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
async created() {
await this.obtenerRegistro();
},
};
</script>
<style scoped>
.boton {
margin-top: 2%;
}
.is-size-5 {
margin-bottom: 10px;
}
.link-f {
font-size: 27px !important;
}
.link {
display: flex;
justify-content: flex-start;
font-size: 20px;
margin-top: 10px;
}
.spanDoc {
margin-right: 5%;
}
</style>
+103
View File
@@ -0,0 +1,103 @@
<template>
<b-steps
class="mt-6 mb-5"
type="is-info"
size="is-large"
:has-navigation="false"
v-model="idStatus"
>
<b-step-item
label="Pre Registro"
icon="account-plus"
:visible="idStatus < 6"
:clickable="false"
/>
<b-step-item
label="Pre Registro Validado"
icon="account-clock"
:visible="idStatus < 6"
:clickable="false"
/>
<b-step-item
label="Registro"
icon="account"
:visible="idStatus < 6"
:clickable="false"
/>
<b-step-item
label="Pre Termino"
icon="account-details"
:visible="idStatus < 6"
:clickable="false"
/>
<b-step-item
label="Termino"
icon="account-clock"
:visible="idStatus < 6"
:clickable="false"
/>
<b-step-item
label="Liberacion"
icon="account-check"
:visible="idStatus < 6"
:clickable="false"
/>
<b-step-item
class="bad"
type="is-danger"
label="Carta Aceptación Rechazada"
icon="file"
:clickable="false"
:visible="idStatus === 6"
/>
<b-step-item
class="bad"
type="is-danger "
label="Carta Termino Rechazada"
icon="file"
:clickable="false"
:visible="idStatus === 7"
/>
<b-step-item
class="bad"
type="is-danger"
label="Informe Global Rechazado"
icon="file"
:clickable="false"
:visible="idStatus === 8"
/>
<b-step-item
class="bad"
type="is-danger bad"
label="Cancelado"
icon="account-cancel"
:clickable="false"
:visible="idStatus === 9"
/>
</b-steps>
</template>
<script>
export default {
props: {
idStatus: { type: Number, required: true },
},
}
</script>
<style>
.b-steps .steps .step-items .step-item.is-danger::before,
.b-steps .steps .step-items .step-item.is-danger::after {
display: none !important;
content: none !important;
}
</style>
@@ -0,0 +1,102 @@
<template>
<div>
<h3 class="title">Formulario Pre-registro</h3>
<b-field label="Fecha de nacimiento">
<b-datepicker
placeholder="Fecha de nacimiento"
icon="calendar-today"
:max-date="maxDate"
v-model="nacimiento"
/>
</b-field>
<b-field label="Teléfono">
<b-input
type="tel"
placeholder="Telefono"
maxlength="10"
:has-counter="false"
v-model="telefono"
/>
</b-field>
<b-field label="Direccion">
<b-input
type="text"
placeholder="Direccion"
maxlength="200"
v-model="direccion"
/>
</b-field>
<b-field class="has-text-centered">
<b-button
type="is-success"
:disabled="telefono == '' || direccion == ''"
@click="
imprimirWarning(
'¿Estas seguro(a) que tus datos son correctos?',
terminarPreRegistro
)
"
>
Enviar
</b-button>
</b-field>
</div>
</template>
<script>
import moment from 'moment'
import axios from 'axios'
export default {
props: {
idServicio: { type: Number, required: true },
alumno: { type: Object, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
imprimirError: { type: Function, required: true },
obtenerServicio: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
direccion: '',
telefono: '',
nacimiento: new Date(),
maxDate: new Date(),
}
},
methods: {
terminarPreRegistro() {
const data = {
idServicio: this.idServicio,
direccion: this.direccion,
telefono: this.telefono,
fechaNacimiento: moment(this.nacimiento),
}
this.updateIsLoading(true)
axios
.put(
`${process.env.api}/servicio/registro_validado`,
data,
this.alumno.token
)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.obtenerServicio()
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
+110
View File
@@ -0,0 +1,110 @@
<template>
<div>
<div class="mb-5">
<h4 class="is-size-4 pb-2">Datos del programa</h4>
<b-field label="Institución:">
<p class="input">{{ servicio.Programa.institucion }}</p>
</b-field>
<b-field label="Dependencia:">
<p class="input">{{ servicio.Programa.dependencia }}</p>
</b-field>
<b-field label="Programa:">
<p class="input">{{ servicio.Programa.programa }}</p>
</b-field>
<b-field label="Clave de programa:">
<p class="input">{{ servicio.Programa.clavePrograma }}</p>
</b-field>
</div>
<div class="mb-5">
<h4 class="is-size-4 pb-2">Datos personales</h4>
<b-field label="Numero de cuenta:">
<p class="input">{{ servicio.Usuario.usuario }}</p>
</b-field>
<b-field label="Nombre:">
<p class="input">{{ servicio.Usuario.nombre }}</p>
</b-field>
<!-- <b-field label="Fecha de nacimiento:" v-if="servicio.fechaNacimiento">
<p class="input">{{ fecha(servicio.fechaNacimiento) }}</p>
</b-field> -->
<b-field label="Carrera:">
<p class="input">{{ servicio.Carrera.carrera }}</p>
</b-field>
<b-field label="Créditos">
<p class="input">
{{ servicio.creditos ? parseInt(servicio.creditos) : '' }}
<span v-if="servicio.creditos">%</span>
</p>
</b-field>
<b-field label="Teléfono:" v-if="servicio.telefono">
<p class="input">{{ servicio.telefono }}</p>
</b-field>
<b-field label="Dirección:" v-if="servicio.direccion">
<p class="input">{{ servicio.direccion }}</p>
</b-field>
<b-field label="Email:">
<p class="input">{{ servicio.correo }}</p>
</b-field>
<b-field label="Programa Interno:" v-if="servicio.programaInterno">
<p class="input">{{ servicio.programaInterno }}</p>
</b-field>
<b-field label="Profesor:" v-if="servicio.profesor">
<p class="input">{{ servicio.profesor }}</p>
</b-field>
<b-field label="Fecha de registro:" v-if="servicio.createdAt">
<p class="input">{{ fecha(servicio.createdAt) }}</p>
</b-field>
<b-field label="Fecha de inicio:">
<p class="input">{{ fecha(servicio.fechaInicio) }}</p>
</b-field>
<b-field label="Fecha de termino:">
<p class="input">{{ fecha(servicio.fechaFin) }}</p>
</b-field>
<b-field label="Fecha de liberación:" v-if="servicio.fechaLiberacion">
<p class="input">{{ fecha(servicio.fechaLiberacion) }}</p>
</b-field>
</div>
</div>
</template>
<script>
import moment from 'moment'
export default {
props: {
servicio: { type: Object, required: true },
},
methods: {
fecha(date) {
if (date) {
const fecha = moment(date)
return `${fecha.date() < 10 ? '0' + fecha.date() : fecha.date()}/${
fecha.month() < 9 ? '0' + (fecha.month() + 1) : fecha.month() + 1
}/${fecha.year()}`
}
return ''
},
},
}
</script>
<style scoped></style>
+81
View File
@@ -0,0 +1,81 @@
<template>
<div class="mb-6">
<h4 class="block is-size-4">Estimado alumno(a):</h4>
<p class="has-text-justified is-size-6">
<span v-if="Status.idStatus === 2">
Estimado alumno(a): Para poder terminar con el registro de tu trámite de
servicio social te pedimos que verifiques que tus datos sean correctos,
de no ser así puedes acudir a las ventanillas de servicio social de la
Secretaría de Asuntos Académicos Estudiantiles, en la planta baja del
Edificio A-8 de lunes a viernes de 09:00 a 15:00 hrs. y de 17:00 a 19:00
hrs. o bien, comunicarte al 5623 1686 o al correo
tramites.ss@acatlan.unam.mx y también contesta el formulario que se
encuentra hasta el final de esta página.
</span>
<span v-if="Status.idStatus === 3">
Estimado alumno(a): Te informamos que el Área de Registro y Control de
Servicio Social ha validado tu solicitud de registro de servicio social
por lo que el siguiente trámite lo realizarás hasta que concluyas 480
horas en un periodo de mínimo 6 meses y obtengas tu carta de término por
parte de la institución, quien se encargará de subir dicho archivo a
este sistema, además de responder un cuestionario sobre tu desempeño. A
su vez, deberás responder el siguiente cuestionario de evaluación del
programa de servicio social en donde participaste y enviar el informe
global de actividades elaborado por ti, con firma y sello de visto bueno
de tu jefe inmediato. En cuanto el Área de Registro y Control de
Servicio Social valide tu solicitud, podrás revisar las indicaciones del
siguiente paso en el panel llamado Liberación Cualquier duda puedes
acudir a las ventanillas de servicio social de la Secretaría de Asuntos
Académicos Estudiantiles, en la planta baja del Edificio A-8 de lunes a
viernes de 09:00 a 15:00 hrs. y de 17:00 a 19:00 hrs. o bien,
comunicarte al 5623 1686 o al correo tramites.ss@acatlan.unam.mx
</span>
<span v-if="Status.idStatus === 4">
Estimado alumno(a): Para continuar con el proceso de término de tu
servicio social debes de subir tu informe global y contestar el
cuestionario que se encuentra hasta el final de esta página.
</span>
<span v-if="Status.idStatus === 5">
Estimado alumno(a): Espera a que tus documentos sean validados por el
Departamento de Servicio Social y Bolsa de Trabajo.
</span>
<span v-if="Status.idStatus === 6">
Estimado alumno(a): Te confirmamos que has concluido con los trámites
necesarios para la liberación de tu servicio social por lo que ahora
sólo queda esperar a que en máximo 15 días hábiles se te envíe por
correo tu carta de liberación. Cualquier duda puedes acudir a las
ventanillas de servicio social la Secretaría de Asuntos Académicos
Estudiantiles, en la planta baja del Edificio A-8 de lunes a viernes de
09:00 a 15:00 hrs. y de 17:00 a 19:00 hrs. o bien, comunicarte al 5623
1686 o al correo tramites.ss@acatlan.unam.mx
</span>
<span v-if="Status.idStatus === 8">
Estimado alumno(a): Te informamos que la carta de término que el(la)
responsable de tu servicio social mando fue rechazada. Espera a que la
vuelvan a subir al sistema para volver a verificarla.
</span>
<span v-if="Status.idStatus === 9">
Estimado alumno(a): Te informamos que el informe global que mandaste fue
rechazado. Súbelo nuevamente y asegúrate de que cumpla con todos los
requisitos.
</span>
</p>
</div>
</template>
<script>
export default {
props: {
Status: { type: Object, required: true },
},
}
</script>
<style scoped></style>
+21 -19
View File
@@ -49,33 +49,35 @@ export default {
data() {
return {
answers: {
sexo: "",
edad: "",
servicioMedico: "",
servicioMedicoOtro: "",
servicioMedicoAux: "",
sexo: '',
edad: '',
servicioMedico: '',
servicioMedicoOtro: '',
servicioMedicoAux: '',
},
servicioMedicoOptions: ["IMSS", "ISSSTE", "Ninguno", "Otro"],
};
servicioMedicoOptions: ['IMSS', 'ISSSTE', 'Ninguno', 'Otro'],
}
},
watch: {
"answers.servicioMedicoAux"() {
this.answers.servicioMedicoOtro = "";
this.answers.servicioMedico = this.answers.servicioMedicoAux;
'answers.servicioMedicoAux'() {
this.answers.servicioMedicoOtro = ''
this.answers.servicioMedico = this.answers.servicioMedicoAux
},
"answers.servicioMedicoOtro"() {
this.answers.servicioMedico = this.answers.servicioMedicoOtro;
'answers.servicioMedicoOtro'() {
this.answers.servicioMedico = this.answers.servicioMedicoOtro
},
"answers.sexo"() {
this.$emit("childAToParent", this.answers);
'answers.sexo'() {
this.$emit('childAToParent', this.answers)
},
"answers.edad"() {
this.$emit("childAToParent", this.answers);
'answers.edad'() {
this.$emit('childAToParent', this.answers)
},
"answers.servicioMedico"() {
this.$emit("childAToParent", this.answers);
'answers.servicioMedico'() {
this.$emit('childAToParent', this.answers)
},
},
};
}
</script>
<style scoped></style>
+29 -27
View File
@@ -37,7 +37,7 @@
v-model="answers.p3"
:disabled="
answers.p3.length >= 3 ||
(answers.p3.length >= 2 && answers.p3Otro != '')
(answers.p3.length >= 2 && answers.p3Otro != '')
"
/>
{{ b3 }}
@@ -58,41 +58,43 @@ export default {
data() {
return {
answers: {
p1: "",
p2: "",
p1: '',
p2: '',
p3: [], // selecciona 3 opciones
p3Otro: "",
p3Otro: '',
},
b3Options: [
"Actividades descritas en el programa",
"Apoyo económico",
"Asesoría académica",
"Dependencia de la UNAM",
"Flexibilidad en horarios",
"Institución del sector público",
"Institucíon del sector social",
"Invitación de profesores",
"Modalidad de titulación por servicio social",
"Objetivos del programa",
"Oportunidad de desarrollo de tesis",
"Prestigio de la institución",
"Recomendación de compañeros",
'Actividades descritas en el programa',
'Apoyo económico',
'Asesoría académica',
'Dependencia de la UNAM',
'Flexibilidad en horarios',
'Institución del sector público',
'Institucíon del sector social',
'Invitación de profesores',
'Modalidad de titulación por servicio social',
'Objetivos del programa',
'Oportunidad de desarrollo de tesis',
'Prestigio de la institución',
'Recomendación de compañeros',
],
};
}
},
watch: {
"answers.p1"() {
this.$emit("childBToParent", this.answers);
'answers.p1'() {
this.$emit('childBToParent', this.answers)
},
"answers.p2"() {
this.$emit("childBToParent", this.answers);
'answers.p2'() {
this.$emit('childBToParent', this.answers)
},
"answers.p3"() {
this.$emit("childBToParent", this.answers);
'answers.p3'() {
this.$emit('childBToParent', this.answers)
},
"answers.p3Otro"() {
this.$emit("childBToParent", this.answers);
'answers.p3Otro'() {
this.$emit('childBToParent', this.answers)
},
},
};
}
</script>
<style scoped></style>
+34 -32
View File
@@ -202,52 +202,54 @@ export default {
data() {
return {
answers: {
p4: "",
p4: '',
p5: [],
p6: "",
p7: "",
p6: '',
p7: '',
p8: [],
p9: "",
p10: "",
p11: "",
p12: "",
p13: "",
p9: '',
p10: '',
p11: '',
p12: '',
p13: '',
},
c5Options: ["ASESORIA", "ACOMPAÑAMIENTO", "SUPERVISION", "SEGUIMIENTO"],
c8Options: ["HIGIENE", "SEGURIDAD", "PROTECCIÓN CIVIL"],
};
c5Options: ['ASESORIA', 'ACOMPAÑAMIENTO', 'SUPERVISION', 'SEGUIMIENTO'],
c8Options: ['HIGIENE', 'SEGURIDAD', 'PROTECCIÓN CIVIL'],
}
},
watch: {
"answers.p4"() {
this.$emit("childCToParent", this.answers);
'answers.p4'() {
this.$emit('childCToParent', this.answers)
},
"answers.p5"() {
this.$emit("childCToParent", this.answers);
'answers.p5'() {
this.$emit('childCToParent', this.answers)
},
"answers.p6"() {
this.$emit("childCToParent", this.answers);
'answers.p6'() {
this.$emit('childCToParent', this.answers)
},
"answers.p7"() {
this.$emit("childCToParent", this.answers);
'answers.p7'() {
this.$emit('childCToParent', this.answers)
},
"answers.p8"() {
this.$emit("childCToParent", this.answers);
'answers.p8'() {
this.$emit('childCToParent', this.answers)
},
"answers.p9"() {
this.$emit("childCToParent", this.answers);
'answers.p9'() {
this.$emit('childCToParent', this.answers)
},
"answers.p10"() {
this.$emit("childCToParent", this.answers);
'answers.p10'() {
this.$emit('childCToParent', this.answers)
},
"answers.p11"() {
this.$emit("childCToParent", this.answers);
'answers.p11'() {
this.$emit('childCToParent', this.answers)
},
"answers.p12"() {
this.$emit("childCToParent", this.answers);
'answers.p12'() {
this.$emit('childCToParent', this.answers)
},
"answers.p13"() {
this.$emit("childCToParent", this.answers);
'answers.p13'() {
this.$emit('childCToParent', this.answers)
},
},
};
}
</script>
<style scoped></style>
+47 -47
View File
@@ -1,8 +1,6 @@
<template>
<div class="D apartado">
<p class="is-size-3">
D.INFORMACIÓN SOBRE EL PROGRAMA DE SERVICIO SOCIAL
</p>
<p class="is-size-3">D.INFORMACIÓN SOBRE EL PROGRAMA DE SERVICIO SOCIAL</p>
<div class="manyInputs">
<p>14.De acuerdo con el programa registrado:</p>
<table class="table is-fullwidth">
@@ -128,68 +126,70 @@ export default {
answers: {
p14: [],
p15: [],
p16: "",
p16: '',
p17: [],
},
d14Options: [
"Se cumplieron los objetivos señalados",
"Se cumplieron las actividades decritas",
"Las actividades del programa son congruentes con el objetivo",
"Las actividades del programa retribuyen a la sociedad",
'Se cumplieron los objetivos señalados',
'Se cumplieron las actividades decritas',
'Las actividades del programa son congruentes con el objetivo',
'Las actividades del programa retribuyen a la sociedad',
],
d15Options: [
"Aplicaste conocimientos",
"Desarrollaste habilidades",
"Enriqueciste tus conocimientos",
"Fortaleciste tus habilidades",
'Aplicaste conocimientos',
'Desarrollaste habilidades',
'Enriqueciste tus conocimientos',
'Fortaleciste tus habilidades',
],
d16Options: [
"Apoyo administrativo",
"Arte, cultura y recreación",
"Ciencia, tecnología e innovación",
"Derechos humanos, seguridad social y jurídica",
"Desarrollo social",
"Educación",
"Equipamiento e infraestructura urbana y rural",
"Medio ambiente y desarrollo sustentable",
"Medio de comunicación",
"Modernización y automatización de la gestión administrativa",
"Salud",
"Seguridad alimentaria",
"Seguridad energética",
"Investigación",
'Apoyo administrativo',
'Arte, cultura y recreación',
'Ciencia, tecnología e innovación',
'Derechos humanos, seguridad social y jurídica',
'Desarrollo social',
'Educación',
'Equipamiento e infraestructura urbana y rural',
'Medio ambiente y desarrollo sustentable',
'Medio de comunicación',
'Modernización y automatización de la gestión administrativa',
'Salud',
'Seguridad alimentaria',
'Seguridad energética',
'Investigación',
],
d17Options: [
"Coordinador administrativo del programa",
"Responsable directo del programa",
"Alguien diferente a los dos anteriores",
'Coordinador administrativo del programa',
'Responsable directo del programa',
'Alguien diferente a los dos anteriores',
],
frecuencia: [
"Diario",
"Semana",
"Quincena",
"Mes",
"Bimestre",
"Trimestre",
"Semestre",
"No recibí asesoría",
'Diario',
'Semana',
'Quincena',
'Mes',
'Bimestre',
'Trimestre',
'Semestre',
'No recibí asesoría',
],
};
}
},
watch: {
"answers.p14"() {
this.$emit("childDToParent", this.answers);
'answers.p14'() {
this.$emit('childDToParent', this.answers)
},
"answers.p15"() {
this.$emit("childDToParent", this.answers);
'answers.p15'() {
this.$emit('childDToParent', this.answers)
},
"answers.p16"() {
this.$emit("childDToParent", this.answers);
'answers.p16'() {
this.$emit('childDToParent', this.answers)
},
"answers.p17"() {
this.$emit("childDToParent", this.answers);
'answers.p17'() {
this.$emit('childDToParent', this.answers)
},
},
};
}
</script>
<style scoped></style>
+20 -20
View File
@@ -3,9 +3,7 @@
<p class="is-size-3">E.APOYOS</p>
<div class="field is-flex is-flex-direction-column SINO">
<p>
18.¿El programa en el que participaste ofrece apoyos académicos?
</p>
<p>18.¿El programa en el que participaste ofrece apoyos académicos?</p>
<b-radio v-model="answers.p18" native-value="true" type="is-info">
Si
@@ -82,34 +80,36 @@ export default {
data() {
return {
answers: {
p18: "",
p19: "",
p20: "",
p18: '',
p19: '',
p20: '',
p21: [],
},
e21Options: [
"Te fueron otorgados en tiempo y forma",
"Fueron condicionados",
'Te fueron otorgados en tiempo y forma',
'Fueron condicionados',
`Hubo procedimientos transparentes
en la asignación y entrega`,
"Se te proporcionó sólo una parte",
"No se te proporcionó el apoyo",
'Se te proporcionó sólo una parte',
'No se te proporcionó el apoyo',
],
};
}
},
watch: {
"answers.p18"() {
this.$emit("childEToParent", this.answers);
'answers.p18'() {
this.$emit('childEToParent', this.answers)
},
"answers.p19"() {
this.$emit("childEToParent", this.answers);
'answers.p19'() {
this.$emit('childEToParent', this.answers)
},
"answers.p20"() {
this.$emit("childEToParent", this.answers);
'answers.p20'() {
this.$emit('childEToParent', this.answers)
},
"answers.p21"() {
this.$emit("childEToParent", this.answers);
'answers.p21'() {
this.$emit('childEToParent', this.answers)
},
},
};
}
</script>
<style scoped></style>
+49 -47
View File
@@ -179,76 +179,78 @@ export default {
p22: [],
p23: [],
p24: [],
p25: "",
p26: "",
p27: "",
p25: '',
p26: '',
p27: '',
p28: null,
p29: null,
p30: "",
p30: '',
},
f22Options: [
"Alguien diferente a los dos anteriores",
"Contribuiste en el logro de los objetivos indicados en el programa",
"Adquiriste nuevos conocimientos",
"Fortaleciste habilidades",
"Obtuviste herramientas para tu inserción en el medio laboral",
"Fortaleciste tu formación profesional",
"Enriqueciste tu formación personal",
"Tu participación en el programa de servicio tuvo impacto social",
'Alguien diferente a los dos anteriores',
'Contribuiste en el logro de los objetivos indicados en el programa',
'Adquiriste nuevos conocimientos',
'Fortaleciste habilidades',
'Obtuviste herramientas para tu inserción en el medio laboral',
'Fortaleciste tu formación profesional',
'Enriqueciste tu formación personal',
'Tu participación en el programa de servicio tuvo impacto social',
],
f23Options: [
"Un medio para retribuir a la sociedad",
"La actividad que permite fortalecer habilidades y destrezas",
"El complemento a la formación profesional",
'Un medio para retribuir a la sociedad',
'La actividad que permite fortalecer habilidades y destrezas',
'El complemento a la formación profesional',
],
f24Options: [
"Impacto social",
"Formación profesional",
"Formación personal",
'Impacto social',
'Formación profesional',
'Formación personal',
],
frecuencia: [
"Diario",
"Semana",
"Quincena",
"Mes",
"Bimestre",
"Trimestre",
"Semestre",
"No recibí asesoría",
'Diario',
'Semana',
'Quincena',
'Mes',
'Bimestre',
'Trimestre',
'Semestre',
'No recibí asesoría',
],
adjetivos: ["muy mala", "mala", "regular", "buena", "excelente"],
};
adjetivos: ['muy mala', 'mala', 'regular', 'buena', 'excelente'],
}
},
watch: {
"answers.p22"() {
this.$emit("childFToParent", this.answers);
'answers.p22'() {
this.$emit('childFToParent', this.answers)
},
"answers.p23"() {
this.$emit("childFToParent", this.answers);
'answers.p23'() {
this.$emit('childFToParent', this.answers)
},
"answers.p24"() {
this.$emit("childFToParent", this.answers);
'answers.p24'() {
this.$emit('childFToParent', this.answers)
},
"answers.p25"() {
this.$emit("childFToParent", this.answers);
'answers.p25'() {
this.$emit('childFToParent', this.answers)
},
"answers.p26"() {
this.$emit("childFToParent", this.answers);
'answers.p26'() {
this.$emit('childFToParent', this.answers)
},
"answers.p27"() {
this.$emit("childFToParent", this.answers);
'answers.p27'() {
this.$emit('childFToParent', this.answers)
},
"answers.p28"() {
this.$emit("childFToParent", this.answers);
'answers.p28'() {
this.$emit('childFToParent', this.answers)
},
"answers.p29"() {
this.$emit("childFToParent", this.answers);
'answers.p29'() {
this.$emit('childFToParent', this.answers)
},
"answers.p30"() {
this.$emit("childFToParent", this.answers);
'answers.p30'() {
this.$emit('childFToParent', this.answers)
},
},
};
}
</script>
<style scoped></style>
+27 -25
View File
@@ -69,33 +69,33 @@ export default {
data() {
return {
current2: 1,
};
}
},
props: ["answers"],
props: ['answers'],
methods: {
navB() {
if (
this.answers.sexo !== "" &&
this.answers.edad !== "" &&
this.answers.servicioMedico !== ""
this.answers.sexo !== '' &&
this.answers.edad !== '' &&
this.answers.servicioMedico !== ''
)
if (
this.answers.servicioMedico == "Otro" &&
this.answers.servicioMedico == 'Otro' &&
!this.answers.servicioMedicoOtro
)
return true;
else return false;
else return true;
return true
else return false
else return true
},
navC() {
if (
this.answers.p1 !== "" &&
this.answers.p2 !== "" &&
this.answers.p1 !== '' &&
this.answers.p2 !== '' &&
(this.answers.p3.length == 3 ||
(this.answers.p3.length == 2 && this.answers.p3Otro !== ""))
(this.answers.p3.length == 2 && this.answers.p3Otro !== ''))
)
return false;
else return true;
return false
else return true
},
navD() {
if (
@@ -115,8 +115,8 @@ export default {
this.answers.p12 &&
this.answers.p13
)
return false;
else return true;
return false
else return true
},
navE() {
if (
@@ -131,8 +131,8 @@ export default {
this.answers.p17.length == 3 &&
this.answers.p16 != null
)
return false;
else return true;
return false
else return true
},
navF() {
if (
@@ -145,8 +145,8 @@ export default {
this.answers.p21[3] != null &&
this.answers.p21[4] != null
)
return false;
else return true;
return false
else return true
},
available() {
if (
@@ -171,18 +171,20 @@ export default {
this.answers.p29 !== null &&
this.answers.p30
)
return false;
return false
// activar boton
else return true;
else return true
},
enviar() {
this.$parent.enviarCuestionario();
this.$parent.enviarCuestionario()
},
},
watch: {
current2() {
this.$emit("childNAVToParent", this.current2);
this.$emit('childNAVToParent', this.current2)
},
},
};
}
</script>
<style scoped></style>
@@ -0,0 +1,718 @@
<template>
<div>
<b-notification
v-if="pendingItems.length && !isMobile"
type="is-warning"
class="floating-pop"
:closable="false"
>
<p><strong>Te faltan contestar:</strong></p>
<ul>
<li v-for="(item, idx) in pendingItems" :key="idx">
{{ item }}
</li>
</ul>
</b-notification>
<div class="container mt-5">
<div
v-for="(item, index) in sortedItems"
:key="item.id || item.idTabla"
class="mb-4 mt-6"
v-if="isItemVisible(item)"
>
<div v-if="item.tipo">
<label :for="item.id" class="form-label">
{{ item.numeroPregunta }}. {{ item.texto }}
</label>
<div v-if="item.tipo === 'seleccionUnica'">
<div v-for="opcion in item.opciones" :key="item.id + '-' + opcion" class="SINO">
<b-radio
v-model="respuestas[item.id]"
:native-value="opcion"
type="is-info"
@change="updateRespuestas(item.id, opcion)"
>
{{ opcion }}
</b-radio>
</div>
</div>
<div v-if="item.tipo === 'seleccionMultiple'">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<input
class="checkb"
type="checkbox"
:value="opcion"
:checked="respuestas[item.id].includes(opcion)"
@change="toggleSelection(item.id, opcion, $event)"
/>
{{ opcion }}
</div>
</div>
<div v-if="item.tipo === 'texto'">
<b-input
:id="item.id"
v-model="respuestas[item.id]"
:maxlength="item.limite"
show-counter
placeholder="Escribe tu respuesta aquí"
></b-input>
</div>
</div>
<div class="table-responsive" v-else>
<template
v-if="index === 0 || item.numeroPregunta !== sortedItems[index - 1].numeroPregunta"
>
<h3 class="mb-3">
{{ item.numeroPregunta }}. {{ item.preguntaTabla }}
</h3>
</template>
<h5 v-if="item.subPreguntaTabla" class="mb-3">
{{ item.subPreguntaTabla }}
</h5>
<table class="table table-bordered text-center">
<thead>
<tr>
<th></th>
<th v-for="opcion in item.renglones[0].opciones" :key="opcion">
{{ opcion }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="renglon in item.renglones" :key="renglon.idRenglon">
<td>{{ renglon.textoRenglon }}</td>
<td
v-for="opcion in renglon.opciones"
:key="opcion"
>
<input
type="radio"
:name="`tabla-${item.idTabla}-renglon-${renglon.idRenglon}`"
:value="opcion"
v-model="respuestas[item.idTabla][renglon.idRenglon]"
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="my-6 mb-6 has-text-centered">
<b-field>
<button
class="button is-success is-medium"
@click="submitForm"
:disabled="!isFormComplete"
>
Enviar
</button>
</b-field>
</div>
</div>
</div>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
export default {
data() {
return {
respuestas: {},
formulario: {
preguntas: [
{
id: 'criterios',
tipo: 'seleccionMultiple',
numeroPregunta: 1,
texto:
'Señala los tres principales criterios que utilizaste para seleccionar el programa de servicio social',
opciones: [
'Actividades adscritas al programa',
'Apoyo económico',
'Asesoría académica',
'Dependencia de la UNAM',
'Flexibilidad en horarios',
'Institución del sector público',
'Institución del sector social',
'Invitación de profesores',
'Modalidad de titulación por servicio social',
'Objetivo del programa',
'Oportunidad de desarrollo de tesis',
'Prestigio de la institución',
'Recomendación de compañeros',
]
},
{
numeroPregunta: 2,
id: 'inscripcion',
tipo: 'seleccionUnica',
texto: '¿Cómo evalúas tu proceso de inscripción?',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
numeroPregunta: 4,
id: 'actividades',
tipo: 'seleccionUnica',
texto: '¿Las actividades que realizaste fueron acordes a lo descrito en el programa?',
opciones: ['Sí', 'No']
},
{
numeroPregunta: 5,
id: 'actividadesComentarios2',
tipo: 'texto',
texto:
'En caso de que las actividades que realizaste hayan sido distintas a las descritas en el programa, enlistas ¿Cuáles fueron?',
limite: 200,
condicional: {
preguntaId: 'actividades',
valor: 'No'
}
},
{
numeroPregunta: 6,
id: 'espacioFisico',
tipo: 'seleccionUnica',
texto:
'¿Contaste con un espacio físico adecuado para realizar tus actividades?',
opciones: ['Sí', 'No']
},
{
numeroPregunta: 7,
id: 'instalaciones',
tipo: 'seleccionUnica',
texto: 'Las instalaciones en las que te desempeñaste, contaban con condiciones adecuadas para la realización de las actividades que te encomendaron',
opciones: ['Sí', 'No']
},
{
numeroPregunta: 8,
id: 'instalacionesComentarios',
tipo: 'texto',
texto: 'Si respondiste NO, ¿Por qué?',
limite: 200,
condicional: {
preguntaId: 'instalaciones',
valor: 'No'
}
},
{
numeroPregunta: 9,
id: 'materialProporcionado',
tipo: 'seleccionUnica',
texto: '¿La institución te proporciono material/equipo necesario para el desempeño de tus actividades?',
opciones: ['Sí', 'No']
},
{
numeroPregunta: 13,
id: 'supervisor',
tipo: 'seleccionUnica',
texto: '¿Quién asesoró y supervisó las actividades que realizaste?',
opciones: [
'Coordinador administrativo del programa',
'Responsable directo del programa',
'Alguien diferente a los dos anteriores',
]
},
{
numeroPregunta: 14,
id: 'apoyoEconomico',
tipo: 'seleccionUnica',
texto: 'El apoyo económico señalado en el programa...',
opciones: [
'Se te otorgó de acuerdo a lo establecido',
'Fue condicionado',
'Se te proporcionó solo una parte',
'No aplica'
]
},
{
numeroPregunta: 15,
id: 'recomendacion',
tipo: 'seleccionUnica',
texto: '¿Recomendarías el programa en que participaste?',
opciones: ['Sí', 'No']
},
{
numeroPregunta: 16,
id: 'actividadesComentarios3',
tipo: 'texto',
texto: '¿Por qué?',
limite: 200,
condicional: {
preguntaId: 'recomendacion',
valor: 'No'
}
},
{
numeroPregunta: 18,
id: 'actividadesComentarios1',
tipo: 'texto',
texto:
'Menciona los conocimiento o habilidades que te ayudarían a un mejor desempeño para tu actividad profesional a futuro',
limite: 200
}
],
tablas: [
{
idTabla: 130,
preguntaTabla: '¿En la entidad o programa donde realizaste tu servicio social recibiste…?',
numeroPregunta: 3,
renglones: [
{ idRenglon: 1, textoRenglon: 'Asesoría', opciones: ['si', 'no'] },
{ idRenglon: 2, textoRenglon: 'Acompañamiento', opciones: ['si', 'no'] },
{ idRenglon: 3, textoRenglon: 'Supervisión', opciones: ['si', 'no'] },
{ idRenglon: 4, textoRenglon: 'Seguimiento', opciones: ['si', 'no'] }
]
},
{
idTabla: 104,
preguntaTabla: 'El trato que recibiste fue:',
numeroPregunta: 10,
renglones: [
{ idRenglon: 1, textoRenglon: 'Profesional', opciones: ['si', 'no'] },
{ idRenglon: 2, textoRenglon: 'Amable', opciones: ['si', 'no'] },
{ idRenglon: 3, textoRenglon: 'Respetuoso', opciones: ['si', 'no'] }
]
},
{
idTabla: 105,
preguntaTabla: 'En tu servicio social…',
numeroPregunta: 11,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Aplicaste conocimientos',
opciones: ['Nunca', 'Rara vez', 'Algunas veces', 'Regularmente', 'Siempre']
},
{
idRenglon: 2,
textoRenglon: 'Desarrollaste habilidades',
opciones: ['Nunca', 'Rara vez', 'Algunas veces', 'Regularmente', 'Siempre']
},
{
idRenglon: 3,
textoRenglon: 'Enriqueciste conocimientos',
opciones: ['Nunca', 'Rara vez', 'Algunas veces', 'Regularmente', 'Siempre']
},
{
idRenglon: 4,
textoRenglon: 'Fortaleciste tus habilidades',
opciones: ['Nunca', 'Rara vez', 'Algunas veces', 'Regularmente', 'Siempre']
}
]
},
{
idTabla: 106,
preguntaTabla: 'Con respecto a la plataforma SIASSyPP web.',
subPreguntaTabla: 'La información que te proporcionaron sobre los programas fue:',
numeroPregunta: 17,
renglones: [
{ idRenglon: 1, textoRenglon: 'Adecuada', opciones: ['si', 'no'] },
{ idRenglon: 2, textoRenglon: 'Suficiente', opciones: ['si', 'no'] },
{ idRenglon: 3, textoRenglon: 'Actualizada', opciones: ['si', 'no'] }
]
},
{
idTabla: 101,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'A. Habilidades personales',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Puntualidad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 2,
textoRenglon: 'Eficiencia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 3,
textoRenglon: 'Organización',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 4,
textoRenglon: 'Eficacia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
}
]
},
{
idTabla: 102,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'B. Habilidades profesionales',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Disposición',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 2,
textoRenglon: 'Proactivo/anticipación',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 3,
textoRenglon: 'Propositivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 4,
textoRenglon: 'Resolutivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
}
]
},
{
idTabla: 103,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'C. Habilidades sociales',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Empatía',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 2,
textoRenglon: 'Trabajo en equipo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 3,
textoRenglon: 'Comunicación asertiva',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 4,
textoRenglon: 'Receptividad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 5,
textoRenglon: 'Tolerancia a la frustración',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
}
]
},
{
idTabla: 1042,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'D. Conocimientos',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Conocimientos teóricos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 2,
textoRenglon: 'Conocimientos metodológicos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 3,
textoRenglon: 'Pensamiento critico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 4,
textoRenglon: 'Formación académica general',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
},
{
idRenglon: 5,
textoRenglon: 'Uso tecnológico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado']
}
]
}
]
}
}
},
created() {
this.formulario.preguntas.forEach((p) => {
if (!(p.id in this.respuestas)) {
if (p.tipo === 'seleccionMultiple') {
this.$set(this.respuestas, p.id, [])
} else {
this.$set(this.respuestas, p.id, null)
}
}
})
this.formulario.tablas.forEach((tabla) => {
if (!(tabla.idTabla in this.respuestas)) {
this.$set(this.respuestas, tabla.idTabla, {})
}
tabla.renglones.forEach((r) => {
if (!(r.idRenglon in this.respuestas[tabla.idTabla])) {
this.$set(this.respuestas[tabla.idTabla], r.idRenglon, null)
}
})
})
},
computed: {
isMobile() {
return window.innerWidth < 576
},
sortedItems() {
const items = [...this.formulario.preguntas, ...this.formulario.tablas]
return items.sort((a, b) => {
if (a.numeroPregunta === b.numeroPregunta) {
return (a.idTabla || 0) - (b.idTabla || 0)
}
return a.numeroPregunta - b.numeroPregunta
})
},
pendingItems() {
let missing = []
this.formulario.preguntas.forEach((p) => {
if (!this.isItemVisible(p)) return
let answer = this.respuestas[p.id]
let answered = false
if (p.tipo === 'seleccionMultiple') {
if (p.id === 'criterios') {
answered = answer && answer.length === 3
} else {
answered = answer && answer.length > 0
}
} else {
answered = answer !== null && answer !== ''
}
if (!answered) {
missing.push(`Pregunta ${p.numeroPregunta}`)
}
})
this.formulario.tablas.forEach((t) => {
let allAnswered = t.renglones.every(
(r) =>
this.respuestas[t.idTabla] &&
this.respuestas[t.idTabla][r.idRenglon] !== null
)
if (!allAnswered) {
missing.push(`Tabla ${t.numeroPregunta}`)
}
})
return missing
},
isFormComplete() {
return this.pendingItems.length === 0
}
},
methods: {
isItemVisible(item) {
if (item.condicional) {
const resp = this.respuestas[item.condicional.preguntaId]
return resp === item.condicional.valor
}
return true
},
toggleSelection(id, opcion, event) {
const selected = this.respuestas[id]
if (event.target.checked) {
if (selected.length >= 3) {
event.target.checked = false
this.$buefy.dialog.alert({
title: 'Límite alcanzado',
message: 'Solo puedes seleccionar hasta 3 opciones.',
type: 'is-warning'
})
} else {
selected.push(opcion)
}
} else {
const index = selected.indexOf(opcion)
if (index !== -1) {
selected.splice(index, 1)
}
}
},
updateRespuestas(id, valor) {
this.$set(this.respuestas, id, valor)
},
validateResponses() {
for (const pregunta of this.formulario.preguntas) {
if (!this.isItemVisible(pregunta)) continue
const resp = this.respuestas[pregunta.id]
if (pregunta.tipo === 'seleccionMultiple') {
if (pregunta.id === 'criterios') {
if (!resp || resp.length !== 3) {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, selecciona exactamente 3 opciones en la pregunta ${pregunta.numeroPregunta}.`,
type: 'is-danger'
})
return false
}
} else {
if (!resp || resp.length === 0) {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, selecciona al menos una opción en la pregunta ${pregunta.numeroPregunta}.`,
type: 'is-danger'
})
return false
}
}
} else {
if (resp === null || resp === '') {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, responde la pregunta ${pregunta.numeroPregunta}.`,
type: 'is-danger'
})
return false
}
if (pregunta.tipo === 'texto') {
const limite = pregunta.limite || 200
if (resp.length > limite) {
this.$buefy.dialog.alert({
title: 'Error',
message: `La respuesta de la pregunta ${pregunta.numeroPregunta} excede el límite de ${limite} caracteres.`,
type: 'is-danger'
})
return false
}
}
}
}
for (const tabla of this.formulario.tablas) {
for (const renglon of tabla.renglones) {
const respuesta = this.respuestas[tabla.idTabla]?.[renglon.idRenglon]
if (respuesta === null) {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, contesta la tabla ${tabla.numeroPregunta}, fila "${renglon.textoRenglon}".`,
type: 'is-danger'
})
return false
}
}
}
return true
},
submitForm() {
if (!this.validateResponses()) return
const respuestaFormateada = this.formatearRespuestas(this.respuestas)
let data = {
...respuestaFormateada,
idServicio: localStorage.getItem('idServicio')
}
axios
.post(`${process.env.api}/cuestionario_alumno`, data, this.token)
.then(() => {
this.$buefy.dialog.alert({
title: 'Success',
message: 'Se enviaron los datos correctamente',
type: 'is-success',
hasIcon: true,
icon: 'checkbox-marked-circle',
ariaRole: 'alertdialog',
ariaModal: true
})
localStorage.removeItem('idCuestionarioAlumno')
this.$router.push('/alumno')
})
.catch((error) => {
this.$buefy.dialog.alert({
title: 'Error',
message: error.response?.data?.message || 'Error al enviar el formulario',
type: 'is-danger'
})
})
},
formatearRespuestas(respuestas) {
const resultado = {}
for (const key in respuestas) {
const esTabla = !isNaN(Number(key))
if (esTabla) {
const idTabla = parseInt(key, 10)
const tablaDef = this.formulario.tablas.find((t) => t.idTabla === idTabla)
if (!tablaDef) continue
const numPregunta = tablaDef.numeroPregunta
let subLetra = ''
if (tablaDef.subPreguntaTabla) {
const match = tablaDef.subPreguntaTabla.match(/^([A-E])\./)
if (match) {
subLetra = match[1]
}
}
const respuestasTabla = respuestas[key]
for (const idRenglon in respuestasTabla) {
const valor = respuestasTabla[idRenglon]
let clave = `p${numPregunta}_${idRenglon}`
if (subLetra) {
clave = `p${numPregunta}_${subLetra}_${idRenglon}`
}
resultado[clave] = valor
}
} else {
const preguntaDef = this.formulario.preguntas.find((p) => p.id === key)
if (!preguntaDef) continue
const numPregunta = preguntaDef.numeroPregunta
const clave = `p${numPregunta}`
resultado[clave] = respuestas[key]
}
}
return resultado
}
}
}
</script>
<style scoped>
.floating-pop {
position: fixed !important;
bottom: 1rem;
right: 1rem;
z-index: 9999;
max-width: 320px;
animation: fadeInUp 0.4s ease;
max-height: 60vh;
overflow-y: auto;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 576px) {
.floating-pop {
left: 0.5rem;
right: 0.5rem;
max-width: none;
width: auto;
max-height: 50vh;
}
}
.table-responsive {
width: 100%;
overflow-x: auto;
}
</style>
@@ -0,0 +1,951 @@
<template>
<div class="container mt-5">
<!-- <h1 class="text-center mb-4">{{ formulario.titulo }}</h1>
<p class="text-center">{{ formulario.descripcion }}</p> -->
<div >
<div v-for="(item, index) in sortedItems" :key="item.id || item.idTabla" class="mb-4 mt-6">
<div v-if="item.tipo" class="mt-6">
<label :for="item.id" class="form-label">{{ item.numeroPregunta }}. {{ item.texto }}</label>
<div v-if="item.tipo === 'seleccionUnica'" :key="item.id">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<!-- :id="item.id" -->
<b-radio
v-model="respuestas[item.id]"
:key="item.id + '-' + opcion"
:native-value="opcion"
type="is-info"
@change="updateRespuestas(item.id, opcion)"
>
{{ opcion }}
</b-radio>
</div>
</div>
<div v-if="item.tipo === 'seleccionMultiple'">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<input
class="checkb"
type="checkbox"
:value="opcion"
:checked="respuestas[item.id].includes(opcion)"
@change="toggleSelection(item.id, opcion, $event)"
/>
{{ opcion }}
</div>
</div>
<!-- v-model="respuestas[item.id]" -->
<div v-if="item.tipo === 'texto'">
<b-input
:id="item.id"
v-model="respuestas[item.id]"
placeholder="Escribe tu respuesta aquí"
></b-input>
</div>
</div>
<div v-else>
<!-- <h3 class="mb-3">{{ item.numeroPregunta }}. {{ item.preguntaTabla }}</h3>
<h5 v-if="item.subPreguntaTabla" class="mb-3">{{ item.subPreguntaTabla }}</h5>
-->
<template v-if="index === 0 || item.numeroPregunta !== sortedItems[index - 1].numeroPregunta">
<h3 class="mb-3">
{{ item.numeroPregunta }}. {{ item.preguntaTabla }}
</h3>
</template>
<!-- Subtítulo (h5) siempre que exista -->
<h5 v-if="item.subPreguntaTabla" class="mb-3">
{{ item.subPreguntaTabla }}
</h5>
<table class="table table-bordered text-center">
<thead>
<tr>
<th></th>
<th v-for="opcion in item.renglones[0].opciones" :key="opcion">{{ opcion }}</th>
</tr>
</thead>
<tbody>
<tr v-for="renglon in item.renglones" :key="renglon.idRenglon">
<td>{{ renglon.textoRenglon }}</td>
<td v-for="opcion in renglon.opciones" :key="opcion">
<input
type="radio"
:name="`tabla-${item.idTabla}-renglon-${renglon.idRenglon}`"
:value="opcion"
v-model="respuestas[item.idTabla][renglon.idRenglon]"
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="my-6 mb-6 has-text-centered">
<b-field class="centro">
<button
class="button is-success is-medium"
@click="() => { submitForm() }"
:disabled="!isFormComplete"
>
Enviar
</button>
</b-field>
</div>
</div>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
export default {
data() {
return {
respuestas: {}, // Inicialización para almacenar las respuestas
formulario: {
titulo: '2025 Evaluación del Universitario(a)',
descripcion:
'Te invitamos a compartir tu experiencia respecto al programa de servicio social en el que participaste. Tus respuestas son confidenciales.',
preguntas: [
{
id: 'criterios',
tipo: 'seleccionMultiple',
numeroPregunta:1,
texto:
'Señala los tres principales criterios que utilizaste para seleccionar el programa de servicio social',
opciones: [
'Actividades adscritas al programa',
'Apoyo económico',
'Asesoría académica',
'Dependencia de la UNAM',
'Flexibilidad en horarios',
'Institución del sector público',
'Institución del sector social',
'Invitación de profesores',
'Modalidad de titulación por servicio social',
'Objetivo del programa',
'Oportunidad de desarrollo de tesis',
'Prestigio de la institución',
'Recomendación de compañeros',
],
},
{
numeroPregunta:2,
id: 'inscripcion',
tipo: 'seleccionUnica',
texto: '¿Cómo evalúas tu proceso de inscripción?',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
numeroPregunta:4,
id: 'actividades',
tipo: 'seleccionUnica',
texto: '¿Las actividades que realizaste fueron acordes a lo descrito en el programa?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:5,
id: 'actividadesComentarios2',
tipo: 'texto',
texto:
'En caso de que las actividades que realizaste hayan sido distintas a las descritas en el programa, enlistas ¿Cuáles fueron?',
condicional: {
preguntaId: 'actividades',
valor: 'No',
},
},
{
numeroPregunta:6,
id: 'espacioFisico',
tipo: 'seleccionUnica',
texto:
'¿Contaste con un espacio físico adecuado para realizar tus actividades?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:7,
id: 'instalaciones',
tipo: 'seleccionUnica',
texto: 'Las instalaciones en las que te desempeñaste, contaban con condiciones adecuadas para la realización de las actividades que te encomendaron',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:8,
id: 'instalacionesComentarios',
tipo: 'texto',
texto: 'Si respondiste NO, ¿Por qué?',
condicional: {
preguntaId: 'instalaciones',
valor: 'No',
},
},
{
numeroPregunta:9,
id: 'materialProporcionado',
tipo: 'seleccionUnica',
texto: '¿La institución te proporciono material/equipo necesario para el desempeño de tus actividades?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:13,
id: 'supervisor',
tipo: 'seleccionUnica',
texto: '¿Quién asesoró y supervisó las actividades que realizaste?',
opciones: [
'Coordinador administrativo del programa',
'Responsable directo del programa',
'Alguien diferente a los dos anteriores',
],
},
{
numeroPregunta:14,
id: 'apoyoEconomico',
tipo: 'seleccionUnica',
texto: 'El apoyo económico señalado en el programa...',
opciones: [
'Se te otorgó de acuerdo a lo establecido',
'Fue condicionado',
'Se te proporcionó solo una parte',
],
},
{
numeroPregunta:15,
id: 'recomendacion',
tipo: 'seleccionUnica',
texto: '¿Recomendarías el programa en que participaste?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:16,
id: 'actividadesComentarios3',
tipo: 'texto',
texto:
'¿Por qué?',
condicional: {
preguntaId: 'actividades',
valor: 'No',
},
},
{
numeroPregunta:18,
id: 'actividadesComentarios1',
tipo: 'texto',
texto:
'Enlista los conocimiento o habilidades que te ayudarían a un mejor desempeño para tu actividad profesional a futuro',
condicional: {
preguntaId: 'actividades',
valor: 'No',
},
},
],
tablas: [
{
idTabla: 130,
preguntaTabla: '¿En la entidad o programa donde realizaste tu servicio social recibiste…?',
subPreguntaTabla: '',
numeroPregunta: 3,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Asesoría',
opciones: ['si', 'no'],
},
{
idRenglon: 2,
textoRenglon: 'Acompañamiento',
opciones: ['si', 'no'],
},
{
idRenglon: 3,
textoRenglon: 'Supervisión',
opciones: ['si', 'no'],
},
{
idRenglon: 4,
textoRenglon: 'Seguimiento',
opciones: ['si', 'no'],
},
],
},
{
idTabla: 104,
preguntaTabla: 'El trato que recibiste fue:',
subPreguntaTabla: '',
numeroPregunta: 10,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Profesional',
opciones: ['si', 'no'],
},
{
idRenglon: 2,
textoRenglon: 'Amable',
opciones: ['si', 'no'],
},
{
idRenglon: 3,
textoRenglon: 'Respetuoso',
opciones: ['si', 'no'],
},
],
},
{
idTabla: 105,
preguntaTabla: 'En tu servicio social…',
subPreguntaTabla: '',
numeroPregunta: 11,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Aplicaste conocimientos',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
{
idRenglon: 2,
textoRenglon: 'Desarrollaste habilidades',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
{
idRenglon: 3,
textoRenglon: 'Enriqueciste conocimientos',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
{
idRenglon: 4,
textoRenglon: 'Fortaleciste tus habilidades',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
],
},
{
idTabla: 106,
preguntaTabla: 'Con respecto a la plataforma SIASSyPP web.',
subPreguntaTabla: 'La información que te proporcionaron sobre los programas fue:',
numeroPregunta: 17,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Adecuada',
opciones: ['si', 'no'],
},
{
idRenglon: 2,
textoRenglon: 'Suficiente',
opciones: ['si', 'no'],
},
{
idRenglon: 3,
textoRenglon: 'Actualizada',
opciones: ['si', 'no'],
},
],
},
{
idTabla: 101,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'A. Habilidades personales',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Puntualidad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Eficiencia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Organización',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Eficacia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 102,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'B. Habilidades profesionales ',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Disposición',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Proactivo/anticipación',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Propositivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Resolutivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 103,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'C. Habilidades sociales',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Empatía',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Trabajo en equipo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Comunicación asertiva',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Receptividad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Tolerancia a la frustación',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 1042,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'D. Conocimientos',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Conocimientos teóricos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Conocimientos metodológicos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Pensamiento critico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Formación académica general',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Uso tecnológico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
],
},
}
},
created() {
this.respuestas = this.respuestas || {};
this.formulario.preguntas.forEach((pregunta) => {
if (!(pregunta.id in this.respuestas)) { // Solo inicializa si no existe
if (pregunta.tipo === 'seleccionMultiple') {
this.$set(this.respuestas, pregunta.id, []);
} else {
this.$set(this.respuestas, pregunta.id, null); // Usa null en lugar de ''
}
}
});
this.formulario.tablas.forEach((tabla) => {
if (!(tabla.idTabla in this.respuestas)) {
this.$set(this.respuestas, tabla.idTabla, {});
}
tabla.renglones.forEach((renglon) => {
if (!(renglon.idRenglon in this.respuestas[tabla.idTabla])) {
this.$set(this.respuestas[tabla.idTabla], renglon.idRenglon, null);
}
});
});
},
watch: {
respuestas: {
handler(newVal) {
console.log("Estado actualizado de respuestas:", newVal);
},
deep: true
}
},
computed: {
sortedItems() {
const items = [...this.formulario.preguntas, ...this.formulario.tablas]
return items.sort((a, b) => {
if (a.numeroPregunta === b.numeroPregunta) {
return (a.idTabla || 0) - (b.idTabla || 0)
}
return a.numeroPregunta - b.numeroPregunta
})
},
isFormComplete() {
// Verifica todas las preguntas individuales
const allQuestionsAnswered = this.formulario.preguntas.every((pregunta) => {
const respuesta = this.respuestas[pregunta.id];
if (pregunta.tipo === "seleccionMultiple") {
return respuesta && respuesta.length > 0; // Debe tener al menos una opción seleccionada
}
return respuesta !== null && respuesta !== ""; // No debe ser null ni vacío
});
// Verifica todas las respuestas de la tabla
const allTablesAnswered = this.formulario.tablas.every((tabla) => {
return tabla.renglones.every((renglon) => {
return this.respuestas[tabla.idTabla] && this.respuestas[tabla.idTabla][renglon.idRenglon] !== null;
});
});
return allQuestionsAnswered && allTablesAnswered;
}
},
methods: {
toggleSelection(id, opcion, event) {
let selectedOptions = this.respuestas[id];
if (selectedOptions.includes(opcion)) {
// Si ya está seleccionada, se deselecciona
this.respuestas[id] = selectedOptions.filter(opt => opt !== opcion);
} else {
if (selectedOptions.length < 3) {
// Si hay espacio, se agrega la opción
this.respuestas[id].push(opcion);
} else {
// Evita la selección de más de 3 opciones
event.preventDefault();
this.$buefy.dialog.alert({
title: "Límite alcanzado",
message: "Solo puedes seleccionar hasta 3 opciones.",
type: "is-warning",
});
}
}
},
limitSelection(id, opcion, event) {
if (this.respuestas[id].length >= 3 && !this.respuestas[id].includes(opcion)) {
// Evita que se seleccione la opción adicional
event.preventDefault();
this.$buefy.dialog.alert({
title: "Límite alcanzado",
message: "Solo puedes seleccionar hasta 3 opciones.",
type: "is-warning",
});
}
},
updateRespuestas(id, valor) {
this.$set(this.respuestas, id, valor);
console.log("Radio seleccionado:", id, valor);
},
validateResponses() {
for (const pregunta of this.formulario.preguntas) {
const respuesta = this.respuestas[pregunta.id];
// Verifica que no haya respuestas vacías
if (respuesta === null || respuesta === "") {
this.$buefy.dialog.alert({
title: "Error",
message: `Por favor, responde la pregunta: "${pregunta.texto}"`,
type: "is-danger",
});
return false;
}
// Para selección múltiple, al menos un elemento debe estar seleccionado
if (pregunta.tipo === "seleccionMultiple" && (!respuesta || respuesta.length === 0)) {
this.$buefy.dialog.alert({
title: "Error",
message: `Por favor, selecciona al menos una opción en: "${pregunta.texto}"`,
type: "is-danger",
});
return false;
}
// Validación adicional si la pregunta es de texto (evitar respuestas peligrosas)
if (pregunta.tipo === "texto" && respuesta.length > 500) {
this.$buefy.dialog.alert({
title: "Error",
message: `La respuesta de la pregunta "${pregunta.texto}" es demasiado larga.`,
type: "is-danger",
});
return false;
}
}
// Verifica que todas las respuestas en las tablas estén completas
for (const tabla of this.formulario.tablas) {
for (const renglon of tabla.renglones) {
const respuesta = this.respuestas[tabla.idTabla]?.[renglon.idRenglon];
if (respuesta === null) {
this.$buefy.dialog.alert({
title: "Error",
message: `Por favor, responde la pregunta en la tabla: "${tabla.preguntaTabla}" en la fila "${renglon.textoRenglon}"`,
type: "is-danger",
});
return false;
}
}
}
return true;
},
submitForm() {
if (!this.validateResponses()) return; // Detiene el envío si la validación falla
console.log('Respuestas a enviar:', this.respuestas)
//alert('Formulario enviado. Gracias por tu participación.')
// Aquí formateamos las respuestas
const respuestaFormateada = this.formatearRespuestas(this.respuestas)
console.log('Respuestas formateadas:', respuestaFormateada)
// this.sendAnswers(respuestaFormateada)
let data = { ...respuestaFormateada,
idServicio: localStorage.getItem('idServicio'), // 4,
p1: 'respuesta1 - trabajando para que sea una string',
}
axios
.post(`${process.env.api}/cuestionario_alumno`, data, this.token
)
.then((res) => {
this.$buefy.dialog.alert({
title: 'Success',
message: 'Se enviaron los datos correctamente',
type: 'is-success',
hasIcon: true,
icon: 'checkbox-marked-circle',
ariaRole: 'alertdialog',
ariaModal: true,
})
//this.reset()
localStorage.removeItem('idCuestionarioAlumno')
this.$router.push('/alumno')
})
.catch((error) => {
// this.error(error.response.data.message)
this.$buefy.dialog.alert({
title: "Error",
message: error.response?.data?.message || "Error al enviar el formulario",
type: "is-danger",
});
})
.finally(() => {
this.isLoading = false
})
},
formatearRespuestas(respuestas) {
// Objeto final a devolver
const resultado = {}
// Recorremos todas las claves de "respuestas"
for (const key in respuestas) {
// Verificamos si es un ID de tabla (numérico) o un ID de pregunta (string)
const esTabla = !isNaN(Number(key)) // true si la clave se puede convertir a número
if (esTabla) {
// 1) BUSCAMOS LA DEFINICIÓN DE LA TABLA
const idTabla = parseInt(key, 10)
const tablaDef = this.formulario.tablas.find(t => t.idTabla === idTabla)
if (!tablaDef) {
// Si no se encontró la tabla, continuamos
continue
}
// 2) OBTENEMOS EL NÚMERO DE PREGUNTA Y, OPCIONALMENTE, LA LETRA (A, B, C...)
const numPregunta = tablaDef.numeroPregunta
// Si quieres “sacar” la letra (A, B, C…) de algo como "A. Habilidades sociales"
// Se puede hacer un match sencillo al principio
let subLetra = ''
if (tablaDef.subPreguntaTabla) {
// Ejemplo: "A. Habilidades personales"
const coincidencia = tablaDef.subPreguntaTabla.match(/^([A-E])\./)
if (coincidencia) {
subLetra = coincidencia[1] // 'A', 'B', 'C', etc.
}
}
// 3) LUEGO RECORREMOS LAS RESPUESTAS DE LA TABLA (por cada idRenglon)
const respuestasTabla = respuestas[key] // p.ej: { "1": "Deficiente", "2": "Básico", ... }
for (const idRenglon in respuestasTabla) {
const valor = respuestasTabla[idRenglon]
// Formamos la clave final.
// Si hay subLetra, hacemos `p3_A_1`. Sino, solo `p3_1`.
let clave = `p${numPregunta}_${idRenglon}`
if (subLetra) {
clave = `p${numPregunta}_${subLetra}_${idRenglon}`
}
resultado[clave] = valor
}
} else {
// NO ES UNA TABLA => ES UNA PREGUNTA NORMAL
// Buscamos su definición para obtener el numeroPregunta
const preguntaDef = this.formulario.preguntas.find(p => p.id === key)
if (!preguntaDef) {
// No se encontró la definición (caso raro)
continue
}
const numPregunta = preguntaDef.numeroPregunta
// Creamos algo como `p2`, `p5`, etc.
const clave = `p${numPregunta}`
resultado[clave] = respuestas[key]
}
}
return resultado
},
},
}
</script>
<style scoped></style>
<!-- respuestas de cuestionario formulario2
todas las preguntas se guardan correctamente
{
"p3_A_1": "Deficiente",
"p3_A_2": "Deficiente",
"p3_A_3": "Deficiente",
"p3_A_4": "Deficiente",
"p3_B_1": "Básico",
"p3_B_2": "Básico",
"p3_B_3": "Básico",
"p3_B_4": "Básico",
"p3_C_1": "Intermedio",
"p3_C_2": "Intermedio",
"p3_C_3": "Intermedio",
"p3_C_4": "Intermedio",
"p3_C_5": "Intermedio",
"p3_D_1": "Destacado",
"p3_D_2": "Destacado",
"p3_D_3": "Destacado",
"p3_D_4": "Destacado",
"p3_D_5": "Destacado",
"p3_E_1": "Deficiente",
"p1": "respuesta1",
"p2": "Excelente",
"p4": "respuesta4",
"p5": "Sí",
"p6": "respuesta 6"
} -->
<!-- respuestas de cuestionario formulario alumno
{
"p12_A_1": "Deficiente",
"p12_A_2": "Deficiente",
"p12_A_3": "Deficiente",
"p12_A_4": "Deficiente",
"p12_B_1": "Básico",
"p12_B_2": "Básico",
"p12_B_3": "Básico",
"p12_B_4": "Básico",
"p12_C_1": "Intermedio",
"p12_C_2": "Intermedio",
"p12_C_3": "Intermedio",
"p12_C_4": "Intermedio",
"p10_1": "si",
"p10_2": "si",
"p10_3": "si",
"p11_1": "Nunca",
"p11_2": "Rara vez",
"p11_3": "Algunas veces",
"p11_4": "Siempre",
"p17_1": "si",
"p17_2": "no",
"p17_3": "si",
"p3_1": "si",
"p3_2": "si",
"p3_3": "si",
"p3_4": "si",
"p12_D_1": "Destacado",
"p12_D_2": "Destacado",
"p12_D_3": "Destacado",
"p12_D_4": "Destacado",
"p12_D_5": "Destacado",
"p1": [
"Dependencia de la UNAM",
"Asesoría académica",
"Oportunidad de desarrollo de tesis"
],
"p2": "Deficiente",
"p4": "No",
"p5": "respuesta5",
"p6": "Sí",
"p7": "Sí",
"p8": "respuesta8",
"p9": "Sí",
"p13": "Responsable directo del programa",
"p14": "Se te otorgó de acuerdo a lo establecido",
"p15": "Sí",
"p16": "respuesta 16",
"p18": "respuesta18"
}
-->
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,951 @@
<template>
<div class="container mt-5">
<!-- <h1 class="text-center mb-4">{{ formulario.titulo }}</h1>
<p class="text-center">{{ formulario.descripcion }}</p> -->
<div >
<div v-for="(item, index) in sortedItems" :key="item.id || item.idTabla" class="mb-4 mt-6">
<div v-if="item.tipo" class="mt-6">
<label :for="item.id" class="form-label">{{ item.numeroPregunta }}. {{ item.texto }}</label>
<div v-if="item.tipo === 'seleccionUnica'" :key="item.id">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<!-- :id="item.id" -->
<b-radio
v-model="respuestas[item.id]"
:key="item.id + '-' + opcion"
:native-value="opcion"
type="is-info"
@change="updateRespuestas(item.id, opcion)"
>
{{ opcion }}
</b-radio>
</div>
</div>
<div v-if="item.tipo === 'seleccionMultiple'">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<input
class="checkb"
type="checkbox"
:value="opcion"
:checked="respuestas[item.id].includes(opcion)"
@change="toggleSelection(item.id, opcion, $event)"
/>
{{ opcion }}
</div>
</div>
<!-- v-model="respuestas[item.id]" -->
<div v-if="item.tipo === 'texto'">
<b-input
:id="item.id"
v-model="respuestas[item.id]"
placeholder="Escribe tu respuesta aquí"
></b-input>
</div>
</div>
<div v-else>
<!-- <h3 class="mb-3">{{ item.numeroPregunta }}. {{ item.preguntaTabla }}</h3>
<h5 v-if="item.subPreguntaTabla" class="mb-3">{{ item.subPreguntaTabla }}</h5>
-->
<template v-if="index === 0 || item.numeroPregunta !== sortedItems[index - 1].numeroPregunta">
<h3 class="mb-3">
{{ item.numeroPregunta }}. {{ item.preguntaTabla }}
</h3>
</template>
<!-- Subtítulo (h5) siempre que exista -->
<h5 v-if="item.subPreguntaTabla" class="mb-3">
{{ item.subPreguntaTabla }}
</h5>
<table class="table table-bordered text-center">
<thead>
<tr>
<th></th>
<th v-for="opcion in item.renglones[0].opciones" :key="opcion">{{ opcion }}</th>
</tr>
</thead>
<tbody>
<tr v-for="renglon in item.renglones" :key="renglon.idRenglon">
<td>{{ renglon.textoRenglon }}</td>
<td v-for="opcion in renglon.opciones" :key="opcion">
<input
type="radio"
:name="`tabla-${item.idTabla}-renglon-${renglon.idRenglon}`"
:value="opcion"
v-model="respuestas[item.idTabla][renglon.idRenglon]"
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="my-6 mb-6" >
<b-field class="centro">
<button
class="button is-success is-medium"
@click="() => { submitForm() }"
:disabled="!isFormComplete"
>
Enviar
</button>
</b-field>
</div>
</div>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
export default {
data() {
return {
respuestas: {}, // Inicialización para almacenar las respuestas
formulario: {
titulo: '2025 Evaluación del Universitario(a)',
descripcion:
'Te invitamos a compartir tu experiencia respecto al programa de servicio social en el que participaste. Tus respuestas son confidenciales.',
preguntas: [
{
id: 'criterios',
tipo: 'seleccionMultiple',
numeroPregunta:1,
texto:
'Señala los tres principales criterios que utilizaste para seleccionar el programa de servicio social',
opciones: [
'Actividades adscritas al programa',
'Apoyo económico',
'Asesoría académica',
'Dependencia de la UNAM',
'Flexibilidad en horarios',
'Institución del sector público',
'Institución del sector social',
'Invitación de profesores',
'Modalidad de titulación por servicio social',
'Objetivo del programa',
'Oportunidad de desarrollo de tesis',
'Prestigio de la institución',
'Recomendación de compañeros',
],
},
{
numeroPregunta:2,
id: 'inscripcion',
tipo: 'seleccionUnica',
texto: '¿Cómo evalúas tu proceso de inscripción?',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
numeroPregunta:4,
id: 'actividades',
tipo: 'seleccionUnica',
texto: '¿Las actividades que realizaste fueron acordes a lo descrito en el programa?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:5,
id: 'actividadesComentarios2',
tipo: 'texto',
texto:
'En caso de que las actividades que realizaste hayan sido distintas a las descritas en el programa, enlistas ¿Cuáles fueron?',
condicional: {
preguntaId: 'actividades',
valor: 'No',
},
},
{
numeroPregunta:6,
id: 'espacioFisico',
tipo: 'seleccionUnica',
texto:
'¿Contaste con un espacio físico adecuado para realizar tus actividades?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:7,
id: 'instalaciones',
tipo: 'seleccionUnica',
texto: 'Las instalaciones en las que te desempeñaste, contaban con condiciones adecuadas para la realización de las actividades que te encomendaron',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:8,
id: 'instalacionesComentarios',
tipo: 'texto',
texto: 'Si respondiste NO, ¿Por qué?',
condicional: {
preguntaId: 'instalaciones',
valor: 'No',
},
},
{
numeroPregunta:9,
id: 'materialProporcionado',
tipo: 'seleccionUnica',
texto: '¿La institución te proporciono material/equipo necesario para el desempeño de tus actividades?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:13,
id: 'supervisor',
tipo: 'seleccionUnica',
texto: '¿Quién asesoró y supervisó las actividades que realizaste?',
opciones: [
'Coordinador administrativo del programa',
'Responsable directo del programa',
'Alguien diferente a los dos anteriores',
],
},
{
numeroPregunta:14,
id: 'apoyoEconomico',
tipo: 'seleccionUnica',
texto: 'El apoyo económico señalado en el programa...',
opciones: [
'Se te otorgó de acuerdo a lo establecido',
'Fue condicionado',
'Se te proporcionó solo una parte',
],
},
{
numeroPregunta:15,
id: 'recomendacion',
tipo: 'seleccionUnica',
texto: '¿Recomendarías el programa en que participaste?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta:16,
id: 'actividadesComentarios3',
tipo: 'texto',
texto:
'¿Por qué?',
condicional: {
preguntaId: 'actividades',
valor: 'No',
},
},
{
numeroPregunta:18,
id: 'actividadesComentarios1',
tipo: 'texto',
texto:
'Enlista los conocimiento o habilidades que te ayudarían a un mejor desempeño para tu actividad profesional a futuro',
condicional: {
preguntaId: 'actividades',
valor: 'No',
},
},
],
tablas: [
{
idTabla: 130,
preguntaTabla: '¿En la entidad o programa donde realizaste tu servicio social recibiste…?',
subPreguntaTabla: '',
numeroPregunta: 3,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Asesoría',
opciones: ['si', 'no'],
},
{
idRenglon: 2,
textoRenglon: 'Acompañamiento',
opciones: ['si', 'no'],
},
{
idRenglon: 3,
textoRenglon: 'Supervisión',
opciones: ['si', 'no'],
},
{
idRenglon: 4,
textoRenglon: 'Seguimiento',
opciones: ['si', 'no'],
},
],
},
{
idTabla: 104,
preguntaTabla: 'El trato que recibiste fue:',
subPreguntaTabla: '',
numeroPregunta: 10,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Profesional',
opciones: ['si', 'no'],
},
{
idRenglon: 2,
textoRenglon: 'Amable',
opciones: ['si', 'no'],
},
{
idRenglon: 3,
textoRenglon: 'Respetuoso',
opciones: ['si', 'no'],
},
],
},
{
idTabla: 105,
preguntaTabla: 'En tu servicio social…',
subPreguntaTabla: '',
numeroPregunta: 11,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Aplicaste conocimientos',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
{
idRenglon: 2,
textoRenglon: 'Desarrollaste habilidades',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
{
idRenglon: 3,
textoRenglon: 'Enriqueciste conocimientos',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
{
idRenglon: 4,
textoRenglon: 'Fortaleciste tus habilidades',
opciones: ['Nunca', 'Rara vez', 'Algunas veces','Regularmente', 'Siempre'],
},
],
},
{
idTabla: 106,
preguntaTabla: 'Con respecto a la plataforma SIASSyPP web.',
subPreguntaTabla: 'La información que te proporcionaron sobre los programas fue:',
numeroPregunta: 17,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Adecuada',
opciones: ['si', 'no'],
},
{
idRenglon: 2,
textoRenglon: 'Suficiente',
opciones: ['si', 'no'],
},
{
idRenglon: 3,
textoRenglon: 'Actualizada',
opciones: ['si', 'no'],
},
],
},
{
idTabla: 101,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'A. Habilidades personales',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Puntualidad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Eficiencia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Organización',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Eficacia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 102,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'B. Habilidades profesionales ',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Disposición',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Proactivo/anticipación',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Propositivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Resolutivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 103,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'C. Habilidades sociales',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Empatía',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Trabajo en equipo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Comunicación asertiva',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Receptividad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Tolerancia a la frustación',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 1042,
preguntaTabla: 'Evalúa tu propio desempeño en el servicio social en relación con',
subPreguntaTabla: 'D. Conocimientos',
numeroPregunta: 12,
renglones: [
{
idRenglon: 1,
textoRenglon: 'Conocimientos teóricos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Conocimientos metodológicos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Pensamiento critico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Formación académica general',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Uso tecnológico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
],
},
}
},
created() {
this.respuestas = this.respuestas || {};
this.formulario.preguntas.forEach((pregunta) => {
if (!(pregunta.id in this.respuestas)) { // Solo inicializa si no existe
if (pregunta.tipo === 'seleccionMultiple') {
this.$set(this.respuestas, pregunta.id, []);
} else {
this.$set(this.respuestas, pregunta.id, null); // Usa null en lugar de ''
}
}
});
this.formulario.tablas.forEach((tabla) => {
if (!(tabla.idTabla in this.respuestas)) {
this.$set(this.respuestas, tabla.idTabla, {});
}
tabla.renglones.forEach((renglon) => {
if (!(renglon.idRenglon in this.respuestas[tabla.idTabla])) {
this.$set(this.respuestas[tabla.idTabla], renglon.idRenglon, null);
}
});
});
},
watch: {
respuestas: {
handler(newVal) {
console.log("Estado actualizado de respuestas:", newVal);
},
deep: true
}
},
computed: {
sortedItems() {
const items = [...this.formulario.preguntas, ...this.formulario.tablas]
return items.sort((a, b) => {
if (a.numeroPregunta === b.numeroPregunta) {
return (a.idTabla || 0) - (b.idTabla || 0)
}
return a.numeroPregunta - b.numeroPregunta
})
},
isFormComplete() {
// Verifica todas las preguntas individuales
const allQuestionsAnswered = this.formulario.preguntas.every((pregunta) => {
const respuesta = this.respuestas[pregunta.id];
if (pregunta.tipo === "seleccionMultiple") {
return respuesta && respuesta.length > 0; // Debe tener al menos una opción seleccionada
}
return respuesta !== null && respuesta !== ""; // No debe ser null ni vacío
});
// Verifica todas las respuestas de la tabla
const allTablesAnswered = this.formulario.tablas.every((tabla) => {
return tabla.renglones.every((renglon) => {
return this.respuestas[tabla.idTabla] && this.respuestas[tabla.idTabla][renglon.idRenglon] !== null;
});
});
return allQuestionsAnswered && allTablesAnswered;
}
},
methods: {
toggleSelection(id, opcion, event) {
let selectedOptions = this.respuestas[id];
if (selectedOptions.includes(opcion)) {
// Si ya está seleccionada, se deselecciona
this.respuestas[id] = selectedOptions.filter(opt => opt !== opcion);
} else {
if (selectedOptions.length < 3) {
// Si hay espacio, se agrega la opción
this.respuestas[id].push(opcion);
} else {
// Evita la selección de más de 3 opciones
event.preventDefault();
this.$buefy.dialog.alert({
title: "Límite alcanzado",
message: "Solo puedes seleccionar hasta 3 opciones.",
type: "is-warning",
});
}
}
},
limitSelection(id, opcion, event) {
if (this.respuestas[id].length >= 3 && !this.respuestas[id].includes(opcion)) {
// Evita que se seleccione la opción adicional
event.preventDefault();
this.$buefy.dialog.alert({
title: "Límite alcanzado",
message: "Solo puedes seleccionar hasta 3 opciones.",
type: "is-warning",
});
}
},
updateRespuestas(id, valor) {
this.$set(this.respuestas, id, valor);
console.log("Radio seleccionado:", id, valor);
},
validateResponses() {
for (const pregunta of this.formulario.preguntas) {
const respuesta = this.respuestas[pregunta.id];
// Verifica que no haya respuestas vacías
if (respuesta === null || respuesta === "") {
this.$buefy.dialog.alert({
title: "Error",
message: `Por favor, responde la pregunta: "${pregunta.texto}"`,
type: "is-danger",
});
return false;
}
// Para selección múltiple, al menos un elemento debe estar seleccionado
if (pregunta.tipo === "seleccionMultiple" && (!respuesta || respuesta.length === 0)) {
this.$buefy.dialog.alert({
title: "Error",
message: `Por favor, selecciona al menos una opción en: "${pregunta.texto}"`,
type: "is-danger",
});
return false;
}
// Validación adicional si la pregunta es de texto (evitar respuestas peligrosas)
if (pregunta.tipo === "texto" && respuesta.length > 500) {
this.$buefy.dialog.alert({
title: "Error",
message: `La respuesta de la pregunta "${pregunta.texto}" es demasiado larga.`,
type: "is-danger",
});
return false;
}
}
// Verifica que todas las respuestas en las tablas estén completas
for (const tabla of this.formulario.tablas) {
for (const renglon of tabla.renglones) {
const respuesta = this.respuestas[tabla.idTabla]?.[renglon.idRenglon];
if (respuesta === null) {
this.$buefy.dialog.alert({
title: "Error",
message: `Por favor, responde la pregunta en la tabla: "${tabla.preguntaTabla}" en la fila "${renglon.textoRenglon}"`,
type: "is-danger",
});
return false;
}
}
}
return true;
},
submitForm() {
if (!this.validateResponses()) return; // Detiene el envío si la validación falla
console.log('Respuestas a enviar:', this.respuestas)
//alert('Formulario enviado. Gracias por tu participación.')
// Aquí formateamos las respuestas
const respuestaFormateada = this.formatearRespuestas(this.respuestas)
console.log('Respuestas formateadas:', respuestaFormateada)
// this.sendAnswers(respuestaFormateada)
let data = { ...respuestaFormateada,
idServicio: localStorage.getItem('idServicio'), // 4,
p1: 'respuesta1 - trabajando para que sea una string',
}
axios
.post(`${process.env.api}/cuestionario_alumno`, data, this.token
)
.then((res) => {
this.$buefy.dialog.alert({
title: 'Success',
message: 'Se enviaron los datos correctamente',
type: 'is-success',
hasIcon: true,
icon: 'checkbox-marked-circle',
ariaRole: 'alertdialog',
ariaModal: true,
})
//this.reset()
localStorage.removeItem('idCuestionarioAlumno')
this.$router.push('/alumno')
})
.catch((error) => {
// this.error(error.response.data.message)
this.$buefy.dialog.alert({
title: "Error",
message: error.response?.data?.message || "Error al enviar el formulario",
type: "is-danger",
});
})
.finally(() => {
this.isLoading = false
})
},
formatearRespuestas(respuestas) {
// Objeto final a devolver
const resultado = {}
// Recorremos todas las claves de "respuestas"
for (const key in respuestas) {
// Verificamos si es un ID de tabla (numérico) o un ID de pregunta (string)
const esTabla = !isNaN(Number(key)) // true si la clave se puede convertir a número
if (esTabla) {
// 1) BUSCAMOS LA DEFINICIÓN DE LA TABLA
const idTabla = parseInt(key, 10)
const tablaDef = this.formulario.tablas.find(t => t.idTabla === idTabla)
if (!tablaDef) {
// Si no se encontró la tabla, continuamos
continue
}
// 2) OBTENEMOS EL NÚMERO DE PREGUNTA Y, OPCIONALMENTE, LA LETRA (A, B, C...)
const numPregunta = tablaDef.numeroPregunta
// Si quieres “sacar” la letra (A, B, C…) de algo como "A. Habilidades sociales"
// Se puede hacer un match sencillo al principio
let subLetra = ''
if (tablaDef.subPreguntaTabla) {
// Ejemplo: "A. Habilidades personales"
const coincidencia = tablaDef.subPreguntaTabla.match(/^([A-E])\./)
if (coincidencia) {
subLetra = coincidencia[1] // 'A', 'B', 'C', etc.
}
}
// 3) LUEGO RECORREMOS LAS RESPUESTAS DE LA TABLA (por cada idRenglon)
const respuestasTabla = respuestas[key] // p.ej: { "1": "Deficiente", "2": "Básico", ... }
for (const idRenglon in respuestasTabla) {
const valor = respuestasTabla[idRenglon]
// Formamos la clave final.
// Si hay subLetra, hacemos `p3_A_1`. Sino, solo `p3_1`.
let clave = `p${numPregunta}_${idRenglon}`
if (subLetra) {
clave = `p${numPregunta}_${subLetra}_${idRenglon}`
}
resultado[clave] = valor
}
} else {
// NO ES UNA TABLA => ES UNA PREGUNTA NORMAL
// Buscamos su definición para obtener el numeroPregunta
const preguntaDef = this.formulario.preguntas.find(p => p.id === key)
if (!preguntaDef) {
// No se encontró la definición (caso raro)
continue
}
const numPregunta = preguntaDef.numeroPregunta
// Creamos algo como `p2`, `p5`, etc.
const clave = `p${numPregunta}`
resultado[clave] = respuestas[key]
}
}
return resultado
},
},
}
</script>
<!-- respuestas de cuestionario formulario2
todas las preguntas se guardan correctamente
{
"p3_A_1": "Deficiente",
"p3_A_2": "Deficiente",
"p3_A_3": "Deficiente",
"p3_A_4": "Deficiente",
"p3_B_1": "Básico",
"p3_B_2": "Básico",
"p3_B_3": "Básico",
"p3_B_4": "Básico",
"p3_C_1": "Intermedio",
"p3_C_2": "Intermedio",
"p3_C_3": "Intermedio",
"p3_C_4": "Intermedio",
"p3_C_5": "Intermedio",
"p3_D_1": "Destacado",
"p3_D_2": "Destacado",
"p3_D_3": "Destacado",
"p3_D_4": "Destacado",
"p3_D_5": "Destacado",
"p3_E_1": "Deficiente",
"p1": "respuesta1",
"p2": "Excelente",
"p4": "respuesta4",
"p5": "Sí",
"p6": "respuesta 6"
} -->
<!-- respuestas de cuestionario formulario alumno
{
"p12_A_1": "Deficiente",
"p12_A_2": "Deficiente",
"p12_A_3": "Deficiente",
"p12_A_4": "Deficiente",
"p12_B_1": "Básico",
"p12_B_2": "Básico",
"p12_B_3": "Básico",
"p12_B_4": "Básico",
"p12_C_1": "Intermedio",
"p12_C_2": "Intermedio",
"p12_C_3": "Intermedio",
"p12_C_4": "Intermedio",
"p10_1": "si",
"p10_2": "si",
"p10_3": "si",
"p11_1": "Nunca",
"p11_2": "Rara vez",
"p11_3": "Algunas veces",
"p11_4": "Siempre",
"p17_1": "si",
"p17_2": "no",
"p17_3": "si",
"p3_1": "si",
"p3_2": "si",
"p3_3": "si",
"p3_4": "si",
"p12_D_1": "Destacado",
"p12_D_2": "Destacado",
"p12_D_3": "Destacado",
"p12_D_4": "Destacado",
"p12_D_5": "Destacado",
"p1": [
"Dependencia de la UNAM",
"Asesoría académica",
"Oportunidad de desarrollo de tesis"
],
"p2": "Deficiente",
"p4": "No",
"p5": "respuesta5",
"p6": "Sí",
"p7": "Sí",
"p8": "respuesta8",
"p9": "Sí",
"p13": "Responsable directo del programa",
"p14": "Se te otorgó de acuerdo a lo establecido",
"p15": "Sí",
"p16": "respuesta 16",
"p18": "respuesta18"
}
-->
-69
View File
@@ -1,69 +0,0 @@
<template>
<div class="info">
<div class="info-programa">
<h3 class="title is-3">Información del programa</h3>
<p><strong> Programa: </strong> {{ programa.programa }}</p>
<p><strong> Institución: </strong> {{ programa.institucion }}</p>
<p><strong> Dependencia: </strong> {{ programa.dependencia }}</p>
<p><strong> Clave del programa: </strong> {{ programa.clave }}</p>
<div v-if="programa.acatlan == true">
<p>
<strong> Programa Interno: </strong>
{{ programa.programaInterno }}
</p>
<p><strong> Profesor: </strong> {{ programa.profesor }}</p>
</div>
</div>
<div class="info-alumno mt-6">
<h3 class="title is-3">Información del alumno</h3>
<p><strong> Nombre: </strong> {{ alumno.nombre }}</p>
<p><strong> Número de cuenta: </strong> {{ alumno.cuenta }}</p>
<p><strong> Carrera: </strong> {{ alumno.carrera }}</p>
<p>
<strong> Créditos: </strong>{{ alumno.creditos
}}<span v-if="alumno.creditos">%</span>
</p>
<p><strong> Correo del alumno: </strong> {{ alumno.correo }}</p>
<p><strong> Fecha de inicio: </strong> {{ fecha(alumno.inicio) }}</p>
<p><strong> Fecha de finalización: </strong> {{ fecha(alumno.fin) }}</p>
<p><strong> Fecha de registro: </strong> {{ fecha(alumno.registro) }}</p>
<div class="mt-4 info-extra" v-if="status >= 3">
<p><strong> Direccion: </strong> {{ alumno.direccion }}</p>
<p><strong> Telefono: </strong> {{ alumno.telefono }}</p>
<p>
<strong> Fecha de nacimiento: </strong>
{{ fecha(alumno.nacimiento) }}
</p>
</div>
</div>
</div>
</template>
<style scoped>
.info-alumno p {
margin-bottom: 0.8rem;
}
.info-programa p {
margin-bottom: 0.8rem;
}
</style>
<script>
import moment from "moment";
export default {
data() {
return {};
},
props: ["status", "alumno", "programa"],
methods: {
fecha(date) {
// const fecha = moment(date);
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
},
},
};
</script>
-59
View File
@@ -1,59 +0,0 @@
<template>
<div>
<div class="mensajeDiv" v-for="mensaje in Mensajes" :key="mensaje.status">
<div v-if="mensaje.mensaje != '' && mensaje.status == status">
<p class="mensaje has-text-justified">
<span class="block is-size-5">Estimado alumno(a): </span><br /><br />
{{ mensaje.mensaje }}
</p>
</div>
</div>
</div>
</template>
<style scoped>
.mensaje {
margin: 3.5rem 0;
}
</style>
<script>
export default {
data() {
return {
Mensajes: [
{ status: 1, mensaje: "" },
{ status: 2, mensaje: "" },
{
status: 3,
mensaje:
"Te informamos que el Área de Registro y Control de Servicio Social ha validado tu solicitud de registro de servicio social por lo que el siguiente trámite lo realizarás hasta que concluyas 480 horas en un periodo de mínimo 6 meses y obtengas tu carta de término por parte de la institución, quien se encargará de subir dicho archivo a este sistema, además de responder un cuestionario sobre tu desempeño. A su vez, deberás responder el siguiente cuestionario de evaluación del programa de servicio social en donde participaste y enviar el informe global de actividades elaborado por ti, con firma y sello de visto bueno de tu jefe inmediato. En cuanto el Área de Registro y Control de Servicio Social valide tu solicitud, podrás revisar las indicaciones del siguiente paso en el panel llamado “Liberación” Cualquier duda puedes acudir al área de Registro y Control de Servicio Social en COESI de lunes a viernes de 10:00 a 14:00 hrs. y de 16:00 a 20:00 hrs. o bien, comunicarte al 5623 1686 o al correo registross@acatlan.unam.mx",
},
{ status: 4, mensaje: "" },
{
status: 5,
mensaje:
"Espera a que tus documentos sean validados por el Departamento de Servicio Social y Bolsa de Trabajo",
},
{
status: 6,
mensaje:
"Te confirmamos que has concluido con los trámites necesarios para la liberación de tu servicio social por lo que ahora sólo queda esperar a que en máximo 15 días hábiles se te notifique por correo electrónico a partir de cuándo puedes recoger la copia de tu carta de liberación en las ventanillas del Área de Registro y Control de Servicio Social. Cualquier duda puedes acudir al área de Registro y Control de Servicio Social en COESI de lunes a viernes de 10:00 a 13:00 hrs. y de 16:00 a 19:00 hrs. o bien, comunicarte al 5623 1686 o al correo registross@apolo.acatlan.unam.mx",
},
{ status: 7, mensaje: "carta de aceptacion rechazada" },
{ status: 8, mensaje: "carta de termino rechazada" },
{
status: 9,
mensaje:
"Informe global de actividades rechazado. Por favor reenvia el informe correctamente",
},
{
status: 10,
mensaje: "servicio cancelado",
},
],
};
},
props: ["status"],
};
</script>
-154
View File
@@ -1,154 +0,0 @@
<template>
<div>
<h3 class="title is-3 my-5">Formulario Pre-registro</h3>
<form>
<b-field label="Fecha de nacimiento">
<b-datepicker
placeholder="Fecha de nacimiento"
icon="calendar-today"
v-model="nacimiento"
:min-date="minDate"
:max-date="maxDate"
>
</b-datepicker>
</b-field>
<b-field label="Telefono">
<b-input
placeholder="Telefono"
maxlength="10"
v-model="telefono"
type="tel"
pattern="^[0-9-+\s()]*$"
>
</b-input>
</b-field>
<b-field label="Direccion">
<b-input
maxlength="200 "
placeholder="Direccion"
type="textarea"
v-model="direccion"
></b-input>
</b-field>
</form>
<div class="my-4 mb-6">
<b-field>
<button
:disabled="nacimiento == '' || telefono == '' || direccion == ''"
class="button is-success is-medium"
@click="enviarRegistro()"
>
Enviar
</button>
</b-field>
</div>
<b-loading :is-full-page="true" v-model="isLoading" :can-cancel="false" />
</div>
</template>
<script>
import moment from "moment";
import axios from "axios";
export default {
data() {
return {
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
nacimiento: [],
minDate: new Date(),
maxDate: new Date(),
telefono: "",
direccion: "",
isLoading: false,
};
},
props: ["idServicio"],
methods: {
reset() {
this.nacimiento = [];
this.telefono = "";
this.direccion = "";
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
enviarRegistro() {
this.isLoading = true;
const data = {
idServicio: this.idServicio,
direccion: this.direccion,
telefono: this.telefono,
fechaNacimiento: moment(this.nacimiento),
};
axios
.put(`${process.env.api}/servicio/registro_validado`, data, this.token)
.then((res) => {
this.$buefy.dialog.alert({
title: "Success",
message: "Se enviaron los datos correctamente",
type: "is-success",
hasIcon: true,
icon: "checkbox-marked-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
this.reset();
this.$parent.getData();
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
},
created() {
let i = new Date().getFullYear() - 80; // hoy - 80 años fecha minima
let j = new Date().getFullYear() - 10; //hoy - 10 años
this.minDate.setFullYear(i);
this.maxDate.setFullYear(j);
},
};
</script>
+99 -147
View File
@@ -1,181 +1,133 @@
<template>
<div>
<h3 class="title is-4 mt-6">
Cuestionario de evaluación del programa de servicio social
<h3 class="label">
Cuestionario de evaluación del programa de servicio social.
</h3>
<div class="my-6" v-if="idCuestionario == null">
<b-field
class="mb-6"
v-if="!servicio.idCuestionarioAlumno && !servicio.idCuestionarioAlumno2"
>
<b-button
type="is-info is-light"
tag="router-link"
to="/alumno/cuestionario"
type="is-info is-light "
icon-left="book-open"
class="border-info"
size="is-medium"
>
cuestionario
Cuestionario
</b-button>
</div>
<div class="is-flex" v-else>
<p class="block is-size-5">Cuestionario contestado</p>
<b-icon icon="check-bold" size="is-small" type="is-success"> </b-icon>
</b-field>
<div class="mb-6" v-else>
<p class="block is-size-6">
Cuestionario contestado
<b-icon type="is-success" icon="check-bold" />
</p>
</div>
<h3 class="title is-4 mt-6">
Informe global de actividades (en formato .PDF. No se aceptan fotos).
<h3 class="label">
Informe global de actividades
<span v-if="!servicio.informeGlobal">
(en formato .PDF. No se aceptan fotos)
</span>
.
</h3>
<div v-if="!informeGlobal">
<b-field type="black">
<b-upload
v-model="file"
type="black"
drag-drop
expanded
accept="application/pdf"
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
file.name || "Arrastra aquí tu archivo o da click para buscar"
}}
</p>
<p>Tamaño máximo 20MB</p>
</div>
</section>
<div v-if="!servicio.informeGlobal">
<b-field>
<b-upload accept="application/pdf" v-model="file" drag-drop expanded>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
file.name ||
'Arrastra aquí tu archivo o da click aquí para buscarlo.'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
</div>
</b-upload>
</b-field>
<b-field style="text-align:center;">
<button
:disabled="file == ''"
class="button is-success is-medium mb-4"
@click="enviarInforme()"
<b-field class="has-text-centered my-5">
<b-button
type="is-success"
:disabled="!file.name"
@click="
imprimirWarning(
`¿Estas seguro(a) de querer subir este informe global?`,
enviarInformeGlobal
)
"
>
Enviar
</button>
</b-button>
</b-field>
</div>
<div class="is-flex" v-else>
<p class="block is-size-5">Informe Global enviado.</p>
<b-icon icon="check-bold" size="is-small" type="is-success"> </b-icon>
<div v-else>
<p class="block is-size-6">
Informe Global enviado.
<b-icon type="is-success" icon="check-bold" />
</p>
</div>
<b-loading :is-full-page="true" v-model="isLoading" :can-cancel="false" />
</div>
</template>
<script>
import axios from "axios";
import axios from 'axios'
export default {
props: {
alumno: { type: Object, required: true },
servicio: { type: Object, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
imprimirError: { type: Function, required: true },
obtenerServicio: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
isLoading: false,
file: [],
};
file: {},
}
},
methods: {
enviarInformeGlobal() {
const formData = new FormData()
const data = {
idServicio: this.servicio.idServicio,
}
this.updateIsLoading(true)
formData.append('data', JSON.stringify(data))
formData.append('informeGlobal', this.file)
axios
.put(
`${process.env.api}/servicio/informe_global`,
formData,
this.alumno.tokenArchivo
)
.then((res) => {
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.obtenerServicio()
})
.catch((error) => {
this.updateIsLoading(false)
this.imprimirError(error.response.data)
})
},
},
props: ["idCuestionario", "informeGlobal", "idServicio"],
watch: {
file() {
if (this.file.size >= 20000000) {
this.$buefy.dialog.alert({
title: "Error",
message: "El tamaño del archivo exede los 20MB",
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
this.file = [];
this.imprimirError({ message: 'El tamaño del archivo exede los 20MB' })
this.file = {}
}
},
},
methods: {
reset() {
this.file = [];
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
enviarInforme() {
this.isLoading = true;
const data = {
idServicio: this.idServicio,
};
const formData = new FormData();
formData.append("data", JSON.stringify(data));
formData.append("informeGlobal", this.file);
axios
.put(`${process.env.api}/servicio/informe_global`, formData, {
headers: {
"Content-Type": "multipart/form-data",
token: this.token.headers.token,
},
})
.then((res) => {
this.$buefy.dialog.alert({
title: "Success",
message: "Se enviaron los datos correctamente",
type: "is-success",
hasIcon: true,
icon: "checkbox-marked-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
this.reset();
this.$parent.getData();
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
},
};
}
</script>
-97
View File
@@ -1,97 +0,0 @@
<template>
<div class="progressBar my-6">
<b-steps
type="is-success"
size="is-large"
:has-navigation="false"
v-model="activeStep"
>
<b-step-item
:visible="activeStep < 6"
:clickable="false"
label="Pre Registro"
icon="account-plus"
></b-step-item>
<b-step-item
:visible="activeStep < 6"
:clickable="false"
label="Pre Registro Validado"
icon="account-clock"
></b-step-item>
<b-step-item
:visible="activeStep < 6"
:clickable="false"
label="Registro"
icon="account"
></b-step-item>
<b-step-item
:visible="activeStep < 6"
:clickable="false"
label="Pre Termino"
icon="account-details"
></b-step-item>
<b-step-item
:visible="activeStep < 6"
:clickable="false"
label="Termino"
icon="account-clock"
></b-step-item>
<b-step-item
:visible="activeStep < 6"
:clickable="false"
label="Liberacion"
icon="account-check"
></b-step-item>
<b-step-item
:clickable="false"
:visible="activeStep == 6"
label="Carta Aceptación Rechazada"
class="bad"
icon="file"
type="is-danger"
></b-step-item>
<b-step-item
:clickable="false"
:visible="activeStep == 7"
label="Carta Termino Rechazada"
icon="file"
class="bad"
type="is-danger "
></b-step-item>
<b-step-item
:clickable="false"
:visible="activeStep == 8"
label="Informe Global Rechazado"
icon="file"
class="bad"
type="is-danger"
></b-step-item>
<b-step-item
:clickable="false"
:visible="activeStep == 9"
label="Cancelado"
icon="account-cancel"
class="bad"
type="is-danger bad"
></b-step-item>
</b-steps>
</div>
</template>
<script>
export default {
data() {
return {};
},
props: ["activeStep"],
};
</script>
<style>
.b-steps .steps .step-items .step-item.is-danger::before,
.b-steps .steps .step-items .step-item.is-danger::after {
display: none !important;
content: none !important;
}
</style>
+21 -17
View File
@@ -1,29 +1,33 @@
<template>
<b-button
class="boton border-info my-5"
type="is-info is-light "
icon-left="arrow-left-box"
@click="regresar()"
>
Regresar
</b-button>
<b-field class="pb-5 pt-6">
<b-button
type="is-info is-light"
icon-left="arrow-left-box"
@click="regresar()"
>
Regresar
</b-button>
</b-field>
</template>
<script>
export default {
props: {
path: String,
deleteFromLocalStorage: Array,
path: {
type: String,
required: true,
},
deleteFromLocalStorage: {
type: Array,
default: () => [],
},
},
methods: {
regresar() {
if (this.deleteFromLocalStorage) {
for (let i = 0; i < this.deleteFromLocalStorage.length; i++) {
localStorage.removeItem(this.deleteFromLocalStorage[i]);
}
}
this.$router.push(this.path);
for (let i = 0; i < this.deleteFromLocalStorage.length; i++)
localStorage.removeItem(this.deleteFromLocalStorage[i])
this.$router.push(this.path)
},
},
};
}
</script>
@@ -0,0 +1,331 @@
<template>
<div>
<b-field label="Número de Cuenta">
<b-input
type="text"
placeholder="Número de Cuenta"
icon="school"
maxlength="9"
@keyup.enter.native="buscarAlumno()"
v-model="numeroCuenta"
expanded
/>
<b-button type="is-info" @click="buscarAlumno()"> Buscar </b-button>
</b-field>
<b-field label="Nombre">
<p class="input">{{ alumno.nombre }}</p>
</b-field>
<b-field label="Carrera">
<p class="input">{{ alumno.carrera }}</p>
</b-field>
<b-field label="Créditos">
<p class="input">
{{ alumno.creditos ? parseInt(alumno.creditos) : '' }}
<span v-if="alumno.creditos">%</span>
</p>
</b-field>
<b-field label="Dirección">
<b-input
type="text"
placeholder="Dirección"
maxlength="200"
v-model="direccion"
/>
</b-field>
<b-field label="Teléfono">
<b-input
type="tel"
placeholder="Teléfono"
maxlength="10"
:has-counter="false"
v-model="telefono"
/>
</b-field>
<b-field label="Correo electrónico">
<b-input type="email" placeholder="Correo electrónico" v-model="correo" />
</b-field>
<b-field label="Fecha de inicio">
<b-datepicker
icon="calendar-today"
:min-date="minDate"
v-model="fechaInicio"
/>
</b-field>
<b-field label="Fecha de fin" v-if="fechaInicio">
<b-datepicker
icon="calendar-today"
:min-date="minDate2"
v-model="fechaFin"
/>
</b-field>
<b-field label="Fecha de nacimiento">
<b-datepicker
placeholder="Nacimiento"
icon="calendar-today"
:max-date="new Date()"
v-model="fechaNacimiento"
/>
</b-field>
<b-field label="Artículo">
<b-select
placeholder="Seleccione el articulo correspondiente"
v-model="idStatus"
expanded
>
<option value="" disabled>Selecciona una opción</option>
<option value="11">Artículo 52</option>
<option value="12">Artículo 91</option>
</b-select>
</b-field>
<b-field label="Motivo" v-if="idStatus === '11'">
<b-select placeholder="Motivo" v-model="motivo" expanded>
<option value="" disabled>Selecciona una opción</option>
<option value="1">Tercera edad</option>
<option value="2">Capacidades diferentes</option>
</b-select>
</b-field>
<div v-if="idStatus === '12'">
<b-field label="Institución">
<b-input
placeholder="Institución"
maxlength="250"
v-model="institucion"
/>
</b-field>
<b-field label="Dependencia">
<b-input
placeholder="Dependencia"
maxlength="250"
v-model="dependencia"
/>
</b-field>
</div>
<b-field label="Añade un archivo (.zip, .rar).">
<b-upload
accept=".zip,.rar,.7zip"
@input="validarExtencion()"
v-model="file"
drag-drop
expanded
>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
file.name ||
'Arrastra aquí tu archivo o da click aquí para buscar'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
<p class="is-size-7">
Si al momento de elegir un archivo este no se selecciona, haga click
en cancelar en la ventana emergente e intente de nuevo.
</p>
</div>
</b-upload>
</b-field>
<div class="has-text-centered mt-4">
<b-button
type="is-success"
:disabled="mostrarBoton()"
@click="
imprimirWarning(
'¿Estas seguro(a) de querer crear un nuevo caso especial?',
enviar
)
"
>
Enviar
</b-button>
</div>
</div>
</template>
<script>
import axios from 'axios'
import moment from 'moment'
export default {
props: {
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
dependencia: '',
direccion: '',
correo: '',
idStatus: '',
institucion: '',
motivo: '',
numeroCuenta: '',
telefono: '',
alumno: {},
fechaFin: new Date(),
fechaInicio: new Date(),
fechaNacimiento: new Date(),
file: {},
minDate: new Date('2020-01-02'),
minDate2: new Date(),
}
},
methods: {
resetear() {
this.dependencia = ''
this.direccion = ''
this.correo = ''
this.idStatus = ''
this.institucion = ''
this.motivo = ''
this.telefono = ''
this.alumno = {}
this.fechaNacimiento = new Date()
this.fechaInicio = new Date()
this.fechaFin = new Date()
this.file = {}
},
validarExtencion() {
const extencionesPermitidas = [/(.zip)$/i, /(.rar)$/i]
for (let i = 0; i < extencionesPermitidas.length; i++)
if (extencionesPermitidas[i].exec(this.file.name)) return
this.file = {}
this.imprimirError({
message: 'Asegurate de ingresar un archivo con la extensión correcta.',
})
},
mostrarBoton() {
if (
!this.alumno.idUsuario ||
!this.telefono ||
!this.direccion ||
!this.correo ||
!this.idStatus ||
(this.idStatus == '11' && !this.motivo) ||
(this.idStatus == '12' && (!this.dependencia || !this.institucion)) ||
!this.file.name
)
return true
return false
},
buscarAlumno() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/usuario/escolares?numeroCuenta=${this.numeroCuenta}`,
this.responsable.token
)
.then((res) => {
this.resetear()
this.alumno = res.data
this.updateIsLoading(false)
})
.catch((err) => {
this.resetear()
this.numeroCuenta = ''
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
enviar() {
const formData = new FormData()
const data = {
idUsuario: this.alumno.idUsuario,
idCarrera: this.alumno.idCarrera,
idStatus: this.idStatus,
numeroCuenta: this.numeroCuenta,
creditos: this.alumno.creditos,
correo: this.correo,
fechaInicio: moment(this.fechaInicio),
fechaFin: moment(this.fechaFin),
fechaNacimiento: moment(this.fechaNacimiento),
direccion: this.direccion,
telefono: this.telefono,
institucion: this.institucion,
dependencia: this.dependencia,
motivo: this.motivo,
}
this.updateIsLoading(true)
formData.append('alumno', JSON.stringify(data))
formData.append('archivos', this.file)
axios
.post(
`${process.env.api}/caso_especial/nuevo`,
formData,
this.responsable.tokenArchivo
)
.then((res) => {
this.numeroCuenta = ''
this.resetear()
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
updateFechas() {
this.fechaFin = new Date(
this.fechaInicio.getFullYear(),
this.fechaInicio.getMonth() + 6,
this.fechaInicio.getDate()
)
this.minDate2 = new Date(
this.fechaInicio.getFullYear(),
this.fechaInicio.getMonth() + 6,
this.fechaInicio.getDate()
)
},
},
watch: {
idStatus() {
this.motivo = ''
this.institucion = ''
this.dependencia = ''
},
file() {
if (this.file.size >= 20000000) {
this.imprimirError({ message: 'El tamaño del archivo exede los 20MB' })
this.file = {}
}
},
fechaInicio() {
this.updateFechas()
},
},
created() {
this.minDate.setDate(this.minDate.getDate() - 1)
this.updateFechas()
},
}
</script>
<style scoped></style>
@@ -0,0 +1,148 @@
<template>
<div class="mb-6">
<h3 class="title">Casos Especiales</h3>
<div class="columns">
<b-field class="column" label="Número de Cuenta">
<b-input
type="text"
icon="school"
placeholder="No.Cuenta"
maxlength="9"
@keyup.enter.native="obtenerCasosEspeciales()"
v-model="search.numeroCuenta"
rounded
/>
</b-field>
<b-field class="column" label="Nombre">
<b-input
type="name"
icon="account"
placeholder="Nombre"
@keyup.enter.native="obtenerCasosEspeciales()"
v-model="search.nombre"
rounded
/>
</b-field>
<b-field class="column" label="Status">
<b-select icon="information" v-model="search.idStatus" expanded rounded>
<option value="">Status</option>
<option
v-for="(s, i) in status"
:key="i"
:value="s.idStatus"
v-show="i > 9 && i < 14"
>
{{ s.status }}
</option>
</b-select>
</b-field>
<b-field class="column is-align-self-center">
<b-button
type="is-info"
@click="obtenerCasosEspeciales()"
expanded
rounded
>
Buscar
</b-button>
</b-field>
</div>
<TablaServiciosSociales
:columnaFechaFin="false"
:columnaFechaInicio="false"
:isLoading="isLoading"
:idTipoUsuario="responsable.idTipoUsuario"
:page="page"
:total="total"
:data="data"
:onPageChange="onPageChange"
/>
</div>
</template>
<script>
import axios from 'axios'
import TablaServiciosSociales from '@/components/TablaServiciosSociales'
export default {
components: { TablaServiciosSociales },
props: {
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
data() {
return {
isLoading: false,
page: 1,
total: 0,
data: [],
status: [],
search: {
idStatus: '',
},
searchAnterior: {},
}
},
methods: {
onPageChange(page) {
this.page = page
this.obtenerCasosEspeciales()
},
obtenerCasosEspeciales() {
let data = ''
this.isLoading = true
if (
this.search.numeroCuenta != this.searchAnterior.numeroCuenta ||
this.search.nombre != this.searchAnterior.nombre ||
this.search.idStatus != this.searchAnterior.idStatus
) {
this.page = 1
this.searchAnterior.numeroCuenta = this.search.numeroCuenta
this.searchAnterior.nombre = this.search.nombre
this.searchAnterior.idStatus = this.search.idStatus
}
if (this.search.idStatus) data += `&idStatus=${this.search.idStatus}`
if (this.search.nombre) data += `&nombre=${this.search.nombre}`
if (this.search.numeroCuenta)
data += `&numeroCuenta=${this.search.numeroCuenta}`
axios
.get(
`${process.env.api}/caso_especial/servicios_especiales?pagina=${this.page}${data}`,
this.responsable.token
)
.then((res) => {
this.data = res.data.serviciosEspeciales
this.total = res.data.count
this.isLoading = false
})
.catch((err) => {
this.isLoading = false
this.imprimirError(err.response.data)
})
},
obtenerCatalogoStatus() {
axios
.get(`${process.env.api}/status`, this.responsable.token)
.then((res) => {
this.status = res.data
this.obtenerCasosEspeciales()
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
},
created() {
if (this.responsable.idTipoUsuario === 4) this.obtenerCatalogoStatus()
},
}
</script>
<style scoped></style>
@@ -1,410 +0,0 @@
<template>
<div>
<p class="is-size-3 mb-5"><b>Agregar un servicio social</b></p>
<form>
<b-field label="Número de cuenta" class="column p-0 my-5 is-full">
<input
class="input column"
v-model="noCuenta"
message="Solo numeros"
required="required"
maxlength="9"
type="number"
placeholder="Número de cuenta"
min="0"
/>
<p class="control">
<b-button class="button is-info" @click="buscarAlumno()"
>Buscar</b-button
>
</p>
</b-field>
<b-field label="Nombre">
<div class="input" placeholder="Nombre">{{ alumno.nombre }}</div>
</b-field>
<b-field label="Carrera">
<div class="input" placeholder="Carrera">{{ alumno.carrera }}</div>
</b-field>
<b-field label="Créditos">
<div class="input" placeholder="Créditos">
{{ `${alumno.creditos}%` }}
</div>
</b-field>
<b-field label="Dirección">
<b-input
class="my-4"
placeholder="Dirección"
v-model="alumno.direccion"
></b-input>
</b-field>
<b-field label="Fecha de inicio">
<b-datepicker
placeholder="Fecha Inicio"
icon="calendar-today"
v-model="alumno.fechaInicio"
:min-date="minDate1"
>
</b-datepicker>
</b-field>
<b-field label="Fecha de fin">
<b-datepicker
placeholder="Fecha fin"
v-model="alumno.fechaFin"
:min-date="minDate2"
icon="calendar-today"
>
</b-datepicker>
</b-field>
<b-field label="Fecha de nacimiento">
<b-datepicker
placeholder="Nacimiento"
icon="calendar-today"
v-model="alumno.fechaNacimiento"
>
</b-datepicker>
</b-field>
<b-field label="Teléfono">
<b-input
class="my-4"
placeholder="Teléfono"
maxlength="10"
v-model="alumno.telefono"
></b-input>
</b-field>
<b-field label="Correo electrónico">
<b-input
class="my-4"
placeholder="Correo electrónico"
v-model="alumno.correoElectronico"
></b-input>
</b-field>
</form>
<b-field label="Artículo">
<b-select
placeholder="Seleccione el articulo correspondiente"
expanded
v-model="alumno.articulo"
>
<option value="11">Artículo 52</option>
<option value="12">Artículo 91</option>
</b-select>
</b-field>
<b-field label="Motivo" v-if="alumno.articulo === '11'">
<b-select
class="my-4"
expanded
placeholder="Motivo"
v-model="alumno.motivo"
>
<option value="1">Tercera edad</option>
<option value="2">Capacidades diferentes</option>
</b-select>
</b-field>
<div v-if="alumno.articulo === '12'">
<b-field label="Institución">
<b-input
class="my-4"
placeholder="Institución"
maxlength="250"
v-model="alumno.institucion"
></b-input>
</b-field>
<b-field label="Dependencia">
<b-input
placeholder="Dependencia"
maxlength="250"
v-model="alumno.dependencia"
></b-input>
</b-field>
</div>
<b-field label="Añade un archivo (.zip, .rar)">
<b-upload
v-model="file"
drag-drop
type="is-black"
expanded
accept=".zip,.rar,.7zip"
v-on:input="validarExt()"
>
<section>
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
file.name || "Arrastra aquí tu archivo o da click para buscar"
}}
</p>
</div>
</section>
</b-upload>
</b-field>
<b-field class="centro">
<b-button
:disabled="
alumno.articulo == '' ||
alumno.numeroCuenta == '' ||
alumno.nombre == '' ||
alumno.carrera == '' ||
alumno.direccion == '' ||
alumno.fechaNacimiento == '' ||
alumno.fechaInicio == '' ||
alumno.fechaFin == '' ||
alumno.correoElectronico == '' ||
file == ''
"
class="border-success my-5"
type="is-success"
@click="enviar()"
>Enviar</b-button
>
</b-field>
<b-loading :is-full-page="true" v-model="isLoading" :can-cancel="false" />
</div>
</template>
<script>
import "buefy/dist/buefy.css";
import axios from "axios";
import validator from "validator";
import moment from "moment";
export default {
data() {
return {
file: {},
isLoading: false,
searched: false,
noCuenta: "",
alumno: {
cuenta: "",
nombre: "",
carrera: "",
creditos: "",
discapacidad: "",
institucion: "",
dependencia: "",
idAlumno: "",
idCarrera: "",
telefono: "",
fechaNacimiento: [],
fechaInicio: [],
fechaFin: [],
correoElectronico: "",
},
minDate1: new Date("2020-01-01"),
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
reset() {
this.alumno.cuenta = "";
this.alumno.nombre = "";
this.alumno.carrera = "";
this.alumno.creditos = "";
this.alumno.institucion = "";
this.alumno.dependencia = "";
this.alumno.motivo = "";
this.alumno.idAlumno = "";
this.alumno.articulo = "";
this.alumno.direccion = "";
this.alumno.idCarrera = "";
this.alumno.fechaNacimiento = [];
this.alumno.fechaInicio = [];
this.alumno.fechaFin = [];
this.alumno.correoElectronico = "";
this.alumno.telefono = "";
this.noCuenta = "";
this.file = {};
},
validarExt() {
const extPermitidas1 = /(.zip)$/i;
const extPermitidas2 = /(.rar)$/i;
if(this.file.name){
if ((extPermitidas1.exec(this.file.name)
|| extPermitidas2.exec(this.file.name))
== false)
{
this.dangerToast();
this.file = {};
}
}
},
dangerToast() {
this.$buefy.toast.open({
message: "Asegurate de ingresar un archivo con la extensión correcta",
type: "is-danger",
});
},
buscarAlumno() {
this.isLoading = true;
axios
.get(
`${process.env.api}/usuario/escolares?numeroCuenta=${this.noCuenta}`,
this.token
)
.then((res) => {
this.alumno = res.data;
this.alumno.cuenta = this.noCuenta;
this.alumno.creditos = Number(res.data.creditos);
this.searched = true;
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
enviar() {
this.isLoading = true;
const data = {
idUsuario: this.alumno.idUsuario,
idStatus: this.alumno.articulo,
idCarrera: this.alumno.idCarrera,
numeroCuenta: this.alumno.cuenta,
creditos: this.alumno.creditos.toString(),
correo: this.alumno.correoElectronico,
fechaInicio: moment(this.alumno.fechaInicio),
fechaFin: moment(this.alumno.fechaFin),
fechaNacimiento: moment(this.alumno.fechaNacimiento),
direccion: this.alumno.direccion,
telefono: this.alumno.telefono,
institucion: this.alumno.institucion,
dependencia: this.alumno.dependencia,
motivo: this.alumno.motivo,
};
const formData = new FormData();
formData.append("alumno", JSON.stringify(data));
formData.append("archivos", this.file);
axios
.post(`${process.env.api}/caso_especial/nuevo`, formData, {
headers: {
"Content-Type": "multipart/form-data",
token: this.token.headers.token,
},
})
.then((res) => {
this.$buefy.dialog.alert({
title: "Success",
message: "Se enviaron los datos correctamente",
type: "is-success",
hasIcon: true,
icon: "checkbox-marked-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
this.reset();
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
esNumero(numero) {
const ultimaLetra = numero.length - 1;
if (numero && !validator.isNumeric(numero[ultimaLetra])) {
return numero.substr(0, ultimaLetra);
}
return numero;
},
maxLength(str, max) {
if (str.length > max) return str.substr(0, max);
return str;
},
correoValidado() {
if (validator.isEmail(this.alumno.correoElectronico)) {
return "";
}
},
},
computed: {
minDate2() {
const min = new Date(this.alumno.fechaInicio);
return new Date(min.getFullYear(), min.getMonth() + 6, min.getDate());
},
},
watch: {
noCuenta() {
if (this.searched === false) {
this.noCuenta = Number(this.noCuenta) < 0 ? "" : this.noCuenta;
this.noCuenta = this.esNumero(this.noCuenta);
this.noCuenta = this.maxLength(this.noCuenta, 9);
} else {
this.noCuenta = "";
this.searched = false;
this.reset();
}
},
},
};
</script>
<style>
.centro {
text-align: center;
}
.upload .upload-draggable {
padding: 2.5em;
}
</style>
-288
View File
@@ -1,288 +0,0 @@
<template>
<div
v-if="this.idTipoUsuario == 2 && this.tipoUsuario == 'responsable'"
class="container"
>
<div class="columns">
<div class="column is-3 mb-0">
<b-field>
<b-input
placeholder="No.Cuenta"
icon="school"
rounded
v-model="numeroCuenta"
maxlength="9"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4">
<b-field>
<b-input
type="name"
placeholder="Nombre"
icon="account"
rounded
v-model="nombre"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4 ">
<b-field>
<b-select icon="information" expanded rounded v-model="idStatus">
<optgroup>
<option value="">Status</option>
<option value="11">Artículo 52</option>
<option value="12">Artículo 91</option>
<option value="13">Liberación Articulo 52</option>
<option value="14">Liberación Articulo 91</option>
</optgroup>
</b-select>
</b-field>
</div>
<div class="buttons section pt-3 pl-5">
<b-button type="is-info" @click="obtenerDatos(idStatus)">
Buscar
</b-button>
</div>
</div>
<div class="columns">
<section class="column is-12">
<b-table
:data="data"
:loading="isLoading"
hoverable
striped
paginated
backend-pagination
:total="total"
:per-page="perPage"
@page-change="onPageChange"
>
<b-table-column field="nombre" label="Nombre" v-slot="props" centered>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.nombre }}</span
>
<span v-else>{{ props.row.nombre }}</span>
</b-table-column>
<b-table-column
field="numeroCuenta"
label="Número de Cuenta"
v-slot="props"
centered
width="100"
>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.numeroCuenta }}</span
>
<span v-else>{{ props.row.numeroCuenta }}</span>
</b-table-column>
<b-table-column
field="carrera"
label="Carrera"
v-slot="props"
centered
>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.carrera }}</span
>
<span v-else>{{ props.row.carrera }}</span>
</b-table-column>
<b-table-column field="status" label="Status" v-slot="props" centered>
<span
v-if="props.row.idStatus == 7"
class="cursorR tag"
:class="types(props.row.idStatus)"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.status }}</span
>
<span v-else class="tag" :class="types(props.row.idStatus)">{{
props.row.status
}}</span>
</b-table-column>
</b-table>
</section>
</div>
</div>
</template>
<script>
import axios from "axios";
import moment from "moment";
export default {
data() {
return {
idTipoUsuario: "",
idUsuario: "",
tipoUsuario: "",
data: [],
total: "",
isLoading: false,
page: 1,
perPage: 25,
numeroCuenta: "",
nombre: "",
idStatus: "",
idServicio: "",
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
onPageChange(page) {
this.page = page;
this.obtenerDatos();
},
types(idStatus) {
if (idStatus === 1) {
return "is-dark";
} else if (idStatus === 2) {
return "is-info";
} else if (idStatus === 3) {
return "is-link";
} else if (idStatus === 4) {
return "is-warning";
} else if (idStatus === 5) {
return "is-success";
} else if (idStatus === 6) {
return "is-link";
} else if (idStatus === 7 || idStatus === 8 || idStatus === 9) {
return "is-danger";
} else if (idStatus === 11) {
return "is-link is-light";
} else if (idStatus === 12) {
return "is-danger is-light";
} else if (idStatus === 13 || idStatus === 14) {
return "is-success is-light";
}
},
fecha(date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
},
obtenerDatos(idStatus) {
this.isLoading = true;
this.data = [];
axios
.get(
`${process.env.api}/caso_especial/servicios_especiales?pagina=${this.page}&idStatus=${this.idStatus}&nombre=${this.nombre}&numeroCuenta=${this.numeroCuenta}`,
this.token
)
.then((res) => {
const servicios = res.data.servicios;
if (servicios.length !== 0) {
for (let i = 0; i < servicios.length; i++) {
this.data.push({
nombre: servicios[i].Usuario.nombre,
numeroCuenta: servicios[i].Usuario.usuario,
carrera: servicios[i].Carrera.carrera,
status: servicios[i].Status.status,
idStatus: servicios[i].Status.idStatus,
});
}
}
let currentTotal = servicios.length;
let contador;
for (let i = 0; i < res.data.registros / 25 + 1; i++) {
contador = i;
}
currentTotal = this.perPage * contador;
this.total = currentTotal;
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
getIdLocal() {
this.idUsuario = localStorage.getItem("idUsuario");
this.idTipoUsuario = localStorage.getItem("idTipoUsuario");
this.tipoUsuario = localStorage.getItem("tipoUsuario");
if (this.idTipoUsuario != 2 && this.tipoUsuario != "responsable") {
localStorage.clear();
this.$router.push("/");
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
created() {
this.getIdLocal();
this.obtenerDatos(0);
},
};
</script>
<style>
.input:focus {
border: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select select:focus {
border-color: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select:not(.is-multiple):not(.is-loading)::after {
border-color: #1b3d70;
}
.pagination-link.is-current {
background-color: #1b3d70;
border-color: #1b3d70;
}
.cursorR {
cursor: pointer;
}
</style>
+20 -19
View File
@@ -1,32 +1,33 @@
<template>
<footer class="py-4">
<div class="container is-flex is-justify-content-center is-size-7 py-4">
<div class="has-text-white has-text-centered">
<p class="mb-1">
Hecho en México, todos los derechos reservados 2020.
</p>
<footer class="footer">
<div class="container has-text-centered is-size-7-touch is-size-6-desktop">
<p>Hecho en México, todos los derechos reservados {{ year() }}.</p>
<p>
Esta página puede ser reproducida con fines no lucrativos, siempre y
cuando no se mutile, se cite la fuente completa y su dirección
electrónica. De otra forma, requiere permiso previo por escrito de la
institución.
</p>
</div>
<p>
Esta página puede ser reproducida con fines no lucrativos, siempre y
cuando no se mutile, se cite la fuente completa y su dirección
electrónica. De otra forma, requiere permiso previo por escrito de la
institución.
</p>
</div>
</footer>
</template>
<script>
export default {};
import moment from 'moment'
export default {
methods: {
year() {
return moment().year()
},
},
}
</script>
<style scoped>
footer {
background-color: #1b3d70;
/* position: fixed;
bottom: 0px;
left: 0px;
right: 0px; */
background-color: #1d3d6f;
color: #fff;
}
</style>
+32 -9
View File
@@ -1,13 +1,13 @@
<template>
<header>
<div class="container">
<header class="header-page">
<div class="container py-3">
<div
class="columns is-mobile is-vcentered is-gapless is-justify-content-space-between"
class="columns is-gapless is-vcentered is-justify-content-space-between is-mobile"
>
<a
href="https://www.unam.mx/"
class="column is-5-mobile is-3-tablet is-one-fifth-widescreen ml-3"
target="_blank"
class="column is-one-fifth-desktop is-one-third-tablet is-5-mobile my-3 ml-2"
>
<b-image
:src="require('@/assets/logo_unam.png')"
@@ -17,12 +17,12 @@
<a
href="https://www.acatlan.unam.mx/"
class="column is-5-mobile is-3-tablet is-one-fifth-widescreen mr-3"
target="_blank"
class="column is-one-fifth-desktop is-one-third-tablet is-5-mobile my-3 mr-2"
>
<b-image
:src="require('@/assets/logo_acatlan.png')"
alt="logo_unam"
alt="logo_acatlan"
></b-image>
</a>
</div>
@@ -31,11 +31,34 @@
</template>
<script>
export default {};
export default {}
</script>
<style scoped>
header {
<style>
.header-page {
background-color: #1d3d6f;
}
.input:focus {
border: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select select:focus {
border-color: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select:not(.is-multiple):not(.is-loading)::after {
border-color: #1b3d70;
}
.pagination-link.is-current {
background-color: #1b3d70;
border-color: #1b3d70;
}
.pointer {
cursor: pointer;
}
</style>
+26 -26
View File
@@ -1,49 +1,49 @@
<template>
<section>
<nav
class="container is-flex is-justify-content-space-between has-text-white is-align-items-center"
<div
class="container is-flex is-justify-content-space-between is-align-items-center"
>
<h2>{{ usuario }}</h2>
<b-button type="is-danger is-small my-1 rojo" @click="cerrarSesion()"
<h2 class="m-2 has-text-white">{{ usuario }}</h2>
<b-button
type="is-danger"
size="is-small"
class="m-2 rojo"
@click="cerrarSesion()"
>Cerrar Sesión</b-button
>
</nav>
</div>
</section>
</template>
<script>
export default {
data() {
return {
usuario: localStorage.getItem("usuario")
? localStorage.getItem("usuario")
: "",
};
return { usuario: localStorage.getItem('usuario') }
},
// created() {
// if (
// !localStorage.getItem("usuario") ||
// !localStorage.getItem("idUsuario") ||
// !localStorage.getItem("idTipoUsuario") ||
// !localStorage.getItem("nombre") ||
// !localStorage.getItem("tipoUsuario") ||
// !localStorage.getItem("token")
// )
// this.$router.push("/");
// },
methods: {
cerrarSesion() {
localStorage.clear();
this.$router.push("/");
localStorage.clear()
this.$router.push('/')
},
},
};
created() {
if (
!localStorage.getItem('usuario') ||
!localStorage.getItem('idUsuario') ||
!localStorage.getItem('idTipoUsuario') ||
!localStorage.getItem('nombre') ||
!localStorage.getItem('tipoUsuario') ||
!localStorage.getItem('token')
)
this.cerrarSesion()
},
}
</script>
<style scoped>
section {
background-color: #bb8800;
background-color: #bb8704;
}
.rojo {
@@ -0,0 +1,161 @@
<template>
<div>
<div class="mb-4">
<h4 class="is-size-4">
Estimad(a) responsable de programa de servicio social:
</h4>
<p>
Te solicitamos llenar cuidadosamente los campos solicitados a
continuación para poder validar el término del servicio social de
nuestro alumno(a).
</p>
</div>
<b-field
class="mb-4"
label="Mencione 5 actividades desempeñadas por el alumno:"
>
<div>
<b-field v-for="(a, i) in actividades" :key="i">
<b-input
maxlength="400"
:placeholder="`${i + 1})`"
v-model="actividades[i]"
/>
</b-field>
</div>
</b-field>
<div class="mb-4">
<p>Selecciona una opción para cada uno de lo siguientes reactivos.</p>
</div>
<div class="columns" v-for="(uAC, i) in unoAlCinco" :key="i">
<div class="column">
<p class="label">{{ i + 1 }}) {{ uAC }}</p>
</div>
<b-field class="column is-4">
<b-select v-model="retroalimentacion[i]" expanded>
<option value="" disabled>Seleccionar</option>
<option v-for="(sR, i) in selectRespuestas" :key="i" :value="i + 1">
{{ sR }}
</option>
</b-select>
</b-field>
</div>
<div class="mb-4">
<p>Contesta, con 800 letras o menos, las siguientes preguntas.</p>
</div>
<b-field
label="6) De acuerdo a lo observado ¿cuáles considera que son las cualidades de
nuestros alumnos de esta licenciatura?"
>
<b-input placeholder="Respuesta" maxlength="800" v-model="p6" />
</b-field>
<b-field
label="7) De acuerdo a lo observado ¿cuáles considera que son los aspectos a
mejorar en la formación de nuestros alumnos de esta licenciatura?"
>
<b-input placeholder="Respuesta" maxlength="800" v-model="p7" />
</b-field>
<b-field class="has-text-centered">
<b-button
type="is-success"
:disabled="
validarActividades() || validarRetroalimentacion() || !p6 || !p7
"
@click="
imprimirWarning(
'¿Estas seguro(a) de querer enviar este cuestionario?',
enviarCuestionario
)
"
>
Enviar
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
idServicio: { type: Number, required: true },
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
p6: '',
p7: '',
actividades: ['', '', '', '', ''],
retroalimentacion: ['', '', '', '', ''],
selectRespuestas: ['Deficiente', 'Regular', 'Bueno', 'Excelente'],
unoAlCinco: [
'Conocimiento teóricos para las funciones encomendadas.',
'Conocimientos técnicos para las funciones encomendadas.',
'Iniciativa para la implementación de mejoras en la empresa.',
'Puntualidad en la entrega de los trabajos de las tareas encomendadas.',
'Desempeño general de sus funciones.',
],
}
},
methods: {
validarActividades() {
for (let i = 0; i < this.actividades.length; i++)
if (!this.actividades[i]) return true
return false
},
validarRetroalimentacion() {
for (let i = 0; i < this.retroalimentacion.length; i++)
if (!this.retroalimentacion[i]) return true
return false
},
enviarCuestionario() {
const data = {
idServicio: this.idServicio,
actividad1: this.actividades[0],
actividad2: this.actividades[1],
actividad3: this.actividades[2],
actividad4: this.actividades[3],
actividad5: this.actividades[4],
retroalimentacion: this.retroalimentacion,
p6: this.p6,
p7: this.p7,
}
this.updateIsLoading(true)
axios
.post(
`${process.env.api}/cuestionario_programa`,
data,
this.responsable.token
)
.then((res) => {
localStorage.removeItem('idServicio')
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/responsable')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
}
</script>
<style scoped></style>
@@ -0,0 +1,618 @@
<template>
<div class="container mt-5">
<!-- Notificación flotante sin botón de cierre -->
<b-notification
v-if="pendingItems.length && !isMobile"
type="is-warning"
class="notification-floating"
aria-close-label="Not applicable"
:closable="false"
>
<p><strong>Te faltan contestar:</strong></p>
<ul>
<li v-for="(item, idx) in pendingItems" :key="idx">
{{ item }}
</li>
</ul>
</b-notification>
<div>
<div
v-for="(item, index) in sortedItems"
:key="item.id || item.idTabla"
class="mb-6"
v-if="isItemVisible(item)"
>
<!-- PREGUNTAS (texto, selección única, selección múltiple) -->
<div v-if="item.tipo" class="mt-6">
<label :for="item.id" class="form-label">
{{ item.numeroPregunta }}. {{ item.texto }}
</label>
<!-- Selección Única -->
<div v-if="item.tipo === 'seleccionUnica'">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<b-radio
v-model="respuestas[item.id]"
:id="item.id"
:native-value="opcion"
type="is-info"
>
{{ opcion }}
</b-radio>
</div>
</div>
<!-- Selección Múltiple -->
<div v-if="item.tipo === 'seleccionMultiple'">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<input
class="checkb"
type="checkbox"
:value="opcion"
v-model="respuestas[item.id]"
/>
{{ opcion }}
</div>
</div>
<!-- Texto -->
<div v-if="item.tipo === 'texto'">
<b-input
:id="item.id"
v-model="respuestas[item.id]"
:maxlength="item.limite"
show-counter
placeholder="Escribe tu respuesta aquí"
></b-input>
</div>
</div>
<!-- TABLAS -->
<div class="table-responsive" v-else>
<template
v-if="
index === 0 ||
item.numeroPregunta !== sortedItems[index - 1].numeroPregunta
"
>
<h3 class="mb-3">
{{ item.numeroPregunta }}. {{ item.preguntaTabla }}
</h3>
</template>
<h5 v-if="item.subPreguntaTabla" class="mb-3">
{{ item.subPreguntaTabla }}
</h5>
<table class="table table-bordered text-center">
<thead>
<tr>
<th></th>
<th v-for="opcion in item.renglones[0].opciones" :key="opcion">
{{ opcion }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="renglon in item.renglones" :key="renglon.idRenglon">
<td>{{ renglon.textoRenglon }}</td>
<td v-for="opcion in renglon.opciones" :key="opcion">
<input
type="radio"
:name="`tabla-${item.idTabla}-renglon-${renglon.idRenglon}`"
:value="opcion"
v-model="respuestas[item.idTabla][renglon.idRenglon]"
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- BOTÓN ENVIAR -->
<div class="my-6 mb-6">
<b-field class="centro">
<button
class="button is-success is-medium"
@click="submitForm"
:disabled="!isFormComplete"
>
Enviar
</button>
</b-field>
</div>
</div>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
export default {
props: {
idServicio: { type: Number, required: true },
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
isLoading: false,
respuestas: {},
formulario: {
titulo:
'2025 Evaluación de la institución receptora de servicio social',
descripcion: `Estimado(a) responsable de programa de servicio social:
Te solicitamos llenar cuidadosamente los campos solicitados a continuación para poder
validar el término del servicio social de nuestro alumno(a).
Los datos están sujetos al aviso de privacidad integral que se puede consultar en el sitio web: www.acatlan.unam.mx/normatividad`,
preguntas: [
{
numeroPregunta: 1,
id: 'actividadesUniversitario',
tipo: 'texto',
limite: 200,
texto:
'Mencione las principales actividades que realizó el/la universitario(a) en su programa de servicio social',
},
{
numeroPregunta: 2,
id: 'calificacionGeneral',
tipo: 'seleccionUnica',
texto:
'Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
opciones: ['Excelente', 'Bueno', 'Regular', 'Deficiente'],
},
{
numeroPregunta: 4,
id: 'cursosComplementarios',
tipo: 'texto',
limite: 200,
texto:
'¿Qué cursos considera que complementarían la formación de nuestros egresados?',
},
{
numeroPregunta: 5,
id: 'contratariaFuturo',
tipo: 'seleccionUnica',
texto: '¿Considera contratar en un futuro al universitario(a)?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta: 6,
id: 'porqueNoContrataria',
tipo: 'texto',
limite: 200,
texto:
'Si su respuesta a la pregunta anterior fue NO, comente ¿por qué?',
condicional: {
preguntaId: 'contratariaFuturo',
valor: 'No',
},
},
],
tablas: [
// ----- PREGUNTA 3, dividida en sub-secciones A, B, C, D ------
{
idTabla: 301,
numeroPregunta: 3,
preguntaTabla:
'Haciendo una evaluación general, ¿Cómo Califica el desempeño del universitario(a)?',
subPreguntaTabla: 'A. Habilidades personales',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Puntualidad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Eficiencia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Organizado',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Eficacia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 302,
numeroPregunta: 3,
preguntaTabla:
'3. Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
subPreguntaTabla: 'B. Habilidades profesionales',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Disposición',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Proactivo/anticipación',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Propositivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Resolutivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 303,
numeroPregunta: 3,
preguntaTabla:
'3. Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
subPreguntaTabla: 'C. Habilidades sociales',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Empatía',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Trabajo en equipo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Comunicación asertiva',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Receptividad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Tolerancia a la frustración',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 304,
numeroPregunta: 3,
preguntaTabla:
'3. Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
subPreguntaTabla: 'D. Conocimientos',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Conocimientos teóricos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Conocimientos metodológicos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Pensamiento crítico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Formación académica general',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Uso tecnológico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
],
},
}
},
created() {
// Inicializa las respuestas de cada pregunta
this.formulario.preguntas.forEach((pregunta) => {
if (pregunta.tipo === 'seleccionMultiple') {
this.$set(this.respuestas, pregunta.id, [])
} else {
this.$set(this.respuestas, pregunta.id, '')
}
})
// Inicializa las respuestas para cada tabla
this.formulario.tablas.forEach((tabla) => {
this.$set(this.respuestas, tabla.idTabla, {})
tabla.renglones.forEach((renglon) => {
this.$set(this.respuestas[tabla.idTabla], renglon.idRenglon, null)
})
})
},
computed: {
isMobile() {
return window.innerWidth < 576
},
// Combina preguntas y tablas en un array ordenado
sortedItems() {
const items = [...this.formulario.preguntas, ...this.formulario.tablas]
return items.sort((a, b) => {
if (a.numeroPregunta === b.numeroPregunta) {
return (a.idTabla || 0) - (b.idTabla || 0)
}
return a.numeroPregunta - b.numeroPregunta
})
},
// Determina los ítems (preguntas/tablas) que siguen pendientes
pendingItems() {
let missing = []
// Revisar preguntas (solo las que estén visibles)
this.formulario.preguntas.forEach((p) => {
if (!this.isItemVisible(p)) return
const answer = this.respuestas[p.id]
let answered = false
if (p.tipo === 'seleccionMultiple') {
answered = answer && answer.length > 0
} else {
answered = answer !== null && answer !== ''
}
if (!answered) {
missing.push(`Pregunta ${p.numeroPregunta}`)
}
})
// Revisar tablas
this.formulario.tablas.forEach((t) => {
let allAnswered = t.renglones.every(
(r) =>
this.respuestas[t.idTabla] &&
this.respuestas[t.idTabla][r.idRenglon] !== null
)
if (!allAnswered) {
missing.push(`Tabla ${t.numeroPregunta}`)
}
})
return missing
},
// El formulario se considera completo si no hay ítems pendientes
isFormComplete() {
return this.pendingItems.length === 0
},
},
methods: {
// Determina si un item (pregunta/tabla) debe mostrarse (condicional)
isItemVisible(item) {
if (item.condicional) {
// Checa la respuesta de la pregunta 'preguntaId'
const respuestaCond = this.respuestas[item.condicional.preguntaId]
return respuestaCond === item.condicional.valor
}
return true
},
submitForm() {
if (!this.validateResponses()) {
return
}
console.log("tokens", this.responsable.token );
console.log('Respuestas enviadas:', this.respuestas)
// Convertir a formato p1, p2, p3_A_1, etc.
const respuestaFormateada = this.formatearRespuestas(this.respuestas)
console.log('Respuestas formateadas:', respuestaFormateada)
let data = {
...respuestaFormateada,
idServicio: localStorage.getItem('idServicio'),
}
this.isLoading = true
axios
.post(`${process.env.api}/cuestionario_programa`, data , this.responsable.token)
.then(() => {
this.$buefy.dialog.alert({
title: 'Success',
message: 'Se enviaron los datos correctamente',
type: 'is-success',
hasIcon: true,
icon: 'checkbox-marked-circle',
ariaRole: 'alertdialog',
ariaModal: true,
})
localStorage.removeItem('idCuestionarioAlumno')
this.$router.push('/alumno')
})
.catch((error) => {
this.$buefy.dialog.alert({
title: 'Error',
message:
error.response?.data?.message || 'Error al enviar el formulario',
type: 'is-danger',
})
})
.finally(() => {
this.isLoading = false
})
},
// Valida que las preguntas y tablas visibles estén contestadas
validateResponses() {
// Validar preguntas
for (const pregunta of this.formulario.preguntas) {
if (!this.isItemVisible(pregunta)) continue
const respuesta = this.respuestas[pregunta.id]
// Verifica que no esté vacía
if (pregunta.tipo === 'seleccionMultiple') {
if (!respuesta || respuesta.length === 0) {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, selecciona al menos una opción en la pregunta ${pregunta.numeroPregunta}.`,
type: 'is-danger',
})
return false
}
} else {
if (respuesta === null || respuesta === '') {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, responde la pregunta ${pregunta.numeroPregunta}.`,
type: 'is-danger',
})
return false
}
}
// Si es texto y excede 500 caracteres
if (pregunta.tipo === 'texto' && respuesta.length > 500) {
this.$buefy.dialog.alert({
title: 'Error',
message: `La respuesta de la pregunta ${pregunta.numeroPregunta} es demasiado larga (máx. 500 caracteres).`,
type: 'is-danger',
})
return false
}
}
// Validar tablas
for (const tabla of this.formulario.tablas) {
for (const renglon of tabla.renglones) {
const respRenglon = this.respuestas[tabla.idTabla]?.[renglon.idRenglon]
if (respRenglon === null) {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, responde la tabla ${tabla.numeroPregunta}, fila "${renglon.textoRenglon}".`,
type: 'is-danger',
})
return false
}
}
}
return true
},
// Convierte las respuestas en formato { p1: ..., p3_A_1: ..., etc. }
formatearRespuestas(respuestas) {
const resultado = {}
for (const key in respuestas) {
const esTabla = !isNaN(Number(key))
if (esTabla) {
// Es una tabla
const idTabla = parseInt(key, 10)
const tablaDef = this.formulario.tablas.find(
(t) => t.idTabla === idTabla
)
if (!tablaDef) continue
const numPregunta = tablaDef.numeroPregunta
let subLetra = ''
if (tablaDef.subPreguntaTabla) {
const match = tablaDef.subPreguntaTabla.match(/^([A-E])\./)
if (match) subLetra = match[1]
}
const respuestasTabla = respuestas[key]
for (const idRenglon in respuestasTabla) {
const valor = respuestasTabla[idRenglon]
let clave = `p${numPregunta}_${idRenglon}`
if (subLetra) {
clave = `p${numPregunta}_${subLetra}_${idRenglon}`
}
resultado[clave] = valor
}
} else {
// Es una pregunta normal
const preguntaDef = this.formulario.preguntas.find(
(p) => p.id === key
)
if (!preguntaDef) continue
const numPregunta = preguntaDef.numeroPregunta
const clave = `p${numPregunta}`
resultado[clave] = respuestas[key]
}
}
return resultado
},
},
}
</script>
<style scoped>
/* Notificación flotante en parte inferior derecha, sin botón de cerrar */
.notification-floating {
position: fixed !important;
bottom: 2rem;
right: 2rem;
z-index: 9999;
max-width: 350px;
width: auto; /* o 90% si prefieres */
box-sizing: border-box;
}
/* Ajustes en pantallas pequeñas (ej. < 480px) */
@media (max-width: 480px) {
.notification-floating {
right: 1rem;
left: 1rem; /* Opcional: para centrar la notificación */
bottom: 1rem;
max-width: none; /* Para que no se limite a 350px */
width: auto; /* O 90%, como prefieras */
}
}
.table-responsive {
width: 100%;
overflow-x: auto;
}
</style>
@@ -0,0 +1,680 @@
<template>
<div class="container mt-5">
<!--
<h1 class="text-center mb-4">{{ formulario.titulo }}</h1>
<p class="text-center">{{ formulario.descripcion }}</p> -->
<div>
<div
v-for="(item, index) in sortedItems"
:key="item.id || item.idTabla"
class="mb-6"
>
<div v-if="item.tipo" class="mt-6">
<label :for="item.id" class="form-label"
>{{ item.numeroPregunta }}. {{ item.texto }}</label
>
<div v-if="item.tipo === 'seleccionUnica'">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<b-radio
v-model="respuestas[item.id]"
:id="item.id"
:native-value="opcion"
type="is-info"
>
{{ opcion }}
</b-radio>
</div>
</div>
<div v-if="item.tipo === 'seleccionMultiple'">
<div v-for="opcion in item.opciones" :key="opcion" class="SINO">
<input
class="checkb"
type="checkbox"
:value="opcion"
v-model="respuestas[item.id]"
/>
{{ opcion }}
</div>
</div>
<div v-if="item.tipo === 'texto'">
<b-input
:id="item.id"
v-model="respuestas[item.id]"
placeholder="Escribe tu respuesta aquí"
></b-input>
</div>
</div>
<div v-else>
<!-- <h3 class="mb-3">{{ item.numeroPregunta }}. {{ item.preguntaTabla }}</h3>
<h5 v-if="item.subPreguntaTabla" class="mb-3">{{ item.subPreguntaTabla }}</h5>
-->
<template
v-if="
index === 0 ||
item.numeroPregunta !== sortedItems[index - 1].numeroPregunta
"
>
<h3 class="mb-3">
{{ item.numeroPregunta }}. {{ item.preguntaTabla }}
</h3>
</template>
<!-- Subtítulo (h5) siempre que exista -->
<h5 v-if="item.subPreguntaTabla" class="mb-3">
{{ item.subPreguntaTabla }}
</h5>
<table class="table table-bordered text-center">
<thead>
<tr>
<th></th>
<th v-for="opcion in item.renglones[0].opciones" :key="opcion">
{{ opcion }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="renglon in item.renglones" :key="renglon.idRenglon">
<td>{{ renglon.textoRenglon }}</td>
<td v-for="opcion in renglon.opciones" :key="opcion">
<input
type="radio"
:name="`tabla-${item.idTabla}-renglon-${renglon.idRenglon}`"
:value="opcion"
v-model="respuestas[item.idTabla][renglon.idRenglon]"
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="my-6 mb-6">
<b-field class="centro">
<button
class="button is-success is-medium"
@click="() => {submitForm()}"
:disabled="!isFormComplete"
>
Enviar
</button>
</b-field>
</div>
</div>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
export default {
data() {
return {
respuestas: {}, // Inicialización para almacenar las respuestas
formulario: {
titulo:
'2025 Evaluación de la institución receptora de servicio social',
descripcion: `Estimado(a) responsable de programa de servicio social:
Te solicitamos llenar cuidadosamente los campos solicitados a continuación para poder
validar el término del servicio social de nuestro alumno(a).
Los datos están sujetos al aviso de privacidad integral que se puede consultar en el sitio web: www.acatlan.unam.mx/normatividad`,
preguntas: [
{
numeroPregunta: 1,
id: 'actividadesUniversitario',
tipo: 'texto',
texto:
'Mencione las principales actividades que realizó el/la universitario(a) en su programa de servicio social',
},
{
numeroPregunta: 2,
id: 'calificacionGeneral',
tipo: 'seleccionUnica',
texto:
'Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
opciones: ['Excelente', 'Bueno', 'Regular', 'Deficiente'],
},
{
numeroPregunta: 4,
id: 'cursosComplementarios',
tipo: 'texto',
texto:
'¿Qué cursos considera que complementarían la formación de nuestros egresados?',
},
{
numeroPregunta: 5,
id: 'contratariaFuturo',
tipo: 'seleccionUnica',
texto: '¿Considera contratar en un futuro al universitario(a)?',
opciones: ['Sí', 'No'],
},
{
numeroPregunta: 6,
id: 'porqueNoContrataria',
tipo: 'texto',
texto:
'Si su respuesta a la pregunta anterior fue NO, comente ¿por qué?',
condicional: {
preguntaId: 'contratariaFuturo',
valor: 'No',
},
},
],
tablas: [
// ----- PREGUNTA 3, dividida en sub-secciones A, B, C, D, E ------
{
idTabla: 301,
numeroPregunta: 3,
preguntaTabla:
'Haciendo una evaluación general, ¿Cómo Califica el desempeño del universitario(a)?',
subPreguntaTabla: 'A. Habilidades personales',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Puntualidad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Eficiencia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Organizado',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Eficacia',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 302,
numeroPregunta: 3,
preguntaTabla:
'3. Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
subPreguntaTabla: 'B. Habilidades profesionales',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Disposición',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Proactivo/anticipación',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Propositivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Resolutivo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 303,
numeroPregunta: 3,
preguntaTabla:
'3. Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
subPreguntaTabla: 'C. Habilidades sociales',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Empatía',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Trabajo en equipo',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Comunicación asertiva',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Receptividad',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Tolerancia a la frustración',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
{
idTabla: 304,
numeroPregunta: 3,
preguntaTabla:
'3. Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
subPreguntaTabla: 'D. Conocimientos',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Conocimientos teóricos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 2,
textoRenglon: 'Conocimientos metodológicos',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 3,
textoRenglon: 'Pensamiento crítico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 4,
textoRenglon: 'Formación académica general',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
{
idRenglon: 5,
textoRenglon: 'Uso tecnológico',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
},
/* {
idTabla: 305,
numeroPregunta: 3,
preguntaTabla:
'3. Haciendo una evaluación general, ¿Cómo califica el desempeño del universitario(a)?',
subPreguntaTabla: 'E. Otro',
renglones: [
{
idRenglon: 1,
textoRenglon: 'Otro',
opciones: ['Deficiente', 'Básico', 'Intermedio', 'Destacado'],
},
],
}, */
],
},
}
},
/* created() {
// Inicializa las respuestas vacías para cada pregunta
this.formulario.preguntas.forEach((pregunta) => {
if (pregunta.tipo === 'evaluacion') {
this.respuestas[pregunta.id] = {}
pregunta.categorias.forEach((categoria) => {
categoria.items.forEach((item) => {
this.respuestas[pregunta.id][item] = ''
})
})
} else if (
pregunta.tipo === 'checkbox' ||
pregunta.tipo === 'seleccionMultiple'
) {
this.respuestas[pregunta.id] = []
} else {
this.respuestas[pregunta.id] = ''
}
})
// Inicializa respuestas para cada tabla
this.formulario.tablas.forEach((tabla) => {
this.$set(this.respuestas, tabla.idTabla, {}); // Asegura que exista respuestas[tabla.idTabla]
tabla.renglones.forEach((renglon) => {
this.$set(this.respuestas[tabla.idTabla], renglon.idRenglon, null); // Asegura que exista respuestas[tabla.idTabla][renglon.idRenglon]
});
});
}, */
created() {
this.formulario.preguntas.forEach((pregunta) => {
if (pregunta.tipo === 'seleccionMultiple') {
this.$set(this.respuestas, pregunta.id, []) // Inicializar correctamente selección múltiple
} else {
this.$set(this.respuestas, pregunta.id, '') // Otras preguntas como texto o selección única
}
})
// Inicializa respuestas para cada tabla
this.formulario.tablas.forEach((tabla) => {
this.$set(this.respuestas, tabla.idTabla, {})
tabla.renglones.forEach((renglon) => {
this.$set(this.respuestas[tabla.idTabla], renglon.idRenglon, null)
})
})
},
computed: {
sortedItems() {
const items = [...this.formulario.preguntas, ...this.formulario.tablas]
return items.sort((a, b) => {
if (a.numeroPregunta === b.numeroPregunta) {
return (a.idTabla || 0) - (b.idTabla || 0)
}
return a.numeroPregunta - b.numeroPregunta
})
},
isFormComplete() {
// Verifica todas las preguntas individuales
const allQuestionsAnswered = this.formulario.preguntas.every(
(pregunta) => {
const respuesta = this.respuestas[pregunta.id]
if (pregunta.tipo === 'seleccionMultiple') {
return respuesta && respuesta.length > 0 // Debe tener al menos una opción seleccionada
}
return respuesta !== null && respuesta !== '' // No debe ser null ni vacío
}
)
// Verifica todas las respuestas de la tabla
const allTablesAnswered = this.formulario.tablas.every((tabla) => {
return tabla.renglones.every((renglon) => {
return (
this.respuestas[tabla.idTabla] &&
this.respuestas[tabla.idTabla][renglon.idRenglon] !== null
)
})
})
return allQuestionsAnswered && allTablesAnswered
},
},
methods: {
submitForm() {
if (!this.validateResponses()) {
return // Detiene el envío si la validación falla
}
console.log('Respuestas enviadas:', this.respuestas)
//alert('Formulario enviado. Gracias por tu participación.')
// Aquí formateamos las respuestas
const respuestaFormateada = this.formatearRespuestas(this.respuestas)
console.log('Respuestas formateadas:', respuestaFormateada)
// this.sendAnswers(respuestaFormateada)
let data = {
...respuestaFormateada,
idServicio: localStorage.getItem('idServicio'),
p1: 'respuesta1 - trabajando para que sea una string',
}
axios
.post(
`${process.env.api}/cuestionario_programa`,
data ,
this.token
)
.then((res) => {
this.$buefy.dialog.alert({
title: 'Success',
message: 'Se enviaron los datos correctamente',
type: 'is-success',
hasIcon: true,
icon: 'checkbox-marked-circle',
ariaRole: 'alertdialog',
ariaModal: true,
})
//this.reset()
localStorage.removeItem('idCuestionarioAlumno')
this.$router.push('/alumno')
})
.catch((error) => {
// this.error(error.response.data.message)
this.$buefy.dialog.alert({
title: 'Error',
message:
error.response?.data?.message || 'Error al enviar el formulario',
type: 'is-danger',
})
})
.finally(() => {
this.isLoading = false
})
},
formatearRespuestas(respuestas) {
// Objeto final a devolver
const resultado = {}
// Recorremos todas las claves de "respuestas"
for (const key in respuestas) {
// Verificamos si es un ID de tabla (numérico) o un ID de pregunta (string)
const esTabla = !isNaN(Number(key)) // true si la clave se puede convertir a número
if (esTabla) {
// 1) BUSCAMOS LA DEFINICIÓN DE LA TABLA
const idTabla = parseInt(key, 10)
const tablaDef = this.formulario.tablas.find(
(t) => t.idTabla === idTabla
)
if (!tablaDef) {
// Si no se encontró la tabla, continuamos
continue
}
// 2) OBTENEMOS EL NÚMERO DE PREGUNTA Y, OPCIONALMENTE, LA LETRA (A, B, C...)
const numPregunta = tablaDef.numeroPregunta
// Si quieres “sacar” la letra (A, B, C…) de algo como "A. Habilidades sociales"
// Se puede hacer un match sencillo al principio
let subLetra = ''
if (tablaDef.subPreguntaTabla) {
// Ejemplo: "A. Habilidades personales"
const coincidencia = tablaDef.subPreguntaTabla.match(/^([A-E])\./)
if (coincidencia) {
subLetra = coincidencia[1] // 'A', 'B', 'C', etc.
}
}
// 3) LUEGO RECORREMOS LAS RESPUESTAS DE LA TABLA (por cada idRenglon)
const respuestasTabla = respuestas[key] // p.ej: { "1": "Deficiente", "2": "Básico", ... }
for (const idRenglon in respuestasTabla) {
const valor = respuestasTabla[idRenglon]
// Formamos la clave final.
// Si hay subLetra, hacemos `p3_A_1`. Sino, solo `p3_1`.
let clave = `p${numPregunta}_${idRenglon}`
if (subLetra) {
clave = `p${numPregunta}_${subLetra}_${idRenglon}`
}
resultado[clave] = valor
}
} else {
// NO ES UNA TABLA => ES UNA PREGUNTA NORMAL
// Buscamos su definición para obtener el numeroPregunta
const preguntaDef = this.formulario.preguntas.find(
(p) => p.id === key
)
if (!preguntaDef) {
// No se encontró la definición (caso raro)
continue
}
const numPregunta = preguntaDef.numeroPregunta
// Creamos algo como `p2`, `p5`, etc.
const clave = `p${numPregunta}`
resultado[clave] = respuestas[key]
}
}
return resultado
},
validateResponses() {
for (const pregunta of this.formulario.preguntas) {
const respuesta = this.respuestas[pregunta.id]
// Verifica que no haya respuestas vacías
if (respuesta === null || respuesta === '') {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, responde la pregunta: "${pregunta.texto}"`,
type: 'is-danger',
})
return false
}
// Para selección múltiple, al menos un elemento debe estar seleccionado
if (
pregunta.tipo === 'seleccionMultiple' &&
(!respuesta || respuesta.length === 0)
) {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, selecciona al menos una opción en: "${pregunta.texto}"`,
type: 'is-danger',
})
return false
}
// Validación adicional si la pregunta es de texto (evitar respuestas peligrosas)
if (pregunta.tipo === 'texto' && respuesta.length > 500) {
this.$buefy.dialog.alert({
title: 'Error',
message: `La respuesta de la pregunta "${pregunta.texto}" es demasiado larga.`,
type: 'is-danger',
})
return false
}
}
// Verifica que todas las respuestas en las tablas estén completas
for (const tabla of this.formulario.tablas) {
for (const renglon of tabla.renglones) {
const respuesta = this.respuestas[tabla.idTabla]?.[renglon.idRenglon]
if (respuesta === null) {
this.$buefy.dialog.alert({
title: 'Error',
message: `Por favor, responde la pregunta en la tabla: "${tabla.preguntaTabla}" en la fila "${renglon.textoRenglon}"`,
type: 'is-danger',
})
return false
}
}
}
return true
},
updateRespuestas(id, valor) {
this.$set(this.respuestas, id, valor)
console.log('Radio seleccionado:', id, valor)
},
},
}
</script>
<!-- respuestas de cuestionario formulario2
todas las preguntas se guardan correctamente
{
"p3_A_1": "Deficiente",
"p3_A_2": "Deficiente",
"p3_A_3": "Deficiente",
"p3_A_4": "Deficiente",
"p3_B_1": "Básico",
"p3_B_2": "Básico",
"p3_B_3": "Básico",
"p3_B_4": "Básico",
"p3_C_1": "Intermedio",
"p3_C_2": "Intermedio",
"p3_C_3": "Intermedio",
"p3_C_4": "Intermedio",
"p3_C_5": "Intermedio",
"p3_D_1": "Destacado",
"p3_D_2": "Destacado",
"p3_D_3": "Destacado",
"p3_D_4": "Destacado",
"p3_D_5": "Destacado",
"p3_E_1": "Deficiente",
"p1": "respuesta1",
"p2": "Excelente",
"p4": "respuesta4",
"p5": "Sí",
"p6": "respuesta 6"
} -->
<!-- respuestas de cuestionario formulario alumno
{
"p12_A_1": "Deficiente",
"p12_A_2": "Deficiente",
"p12_A_3": "Deficiente",
"p12_A_4": "Deficiente",
"p12_B_1": "Básico",
"p12_B_2": "Básico",
"p12_B_3": "Básico",
"p12_B_4": "Básico",
"p12_C_1": "Intermedio",
"p12_C_2": "Intermedio",
"p12_C_3": "Intermedio",
"p12_C_4": "Intermedio",
"p10_1": "si",
"p10_2": "si",
"p10_3": "si",
"p11_1": "Nunca",
"p11_2": "Rara vez",
"p11_3": "Algunas veces",
"p11_4": "Siempre",
"p17_1": "si",
"p17_2": "no",
"p17_3": "si",
"p3_1": "si",
"p3_2": "si",
"p3_3": "si",
"p3_4": "si",
"p12_D_1": "Destacado",
"p12_D_2": "Destacado",
"p12_D_3": "Destacado",
"p12_D_4": "Destacado",
"p12_D_5": "Destacado",
"p1": [
"Dependencia de la UNAM",
"Asesoría académica",
"Oportunidad de desarrollo de tesis"
],
"p2": "Deficiente",
"p4": "No",
"p5": "respuesta5",
"p6": "Sí",
"p7": "Sí",
"p8": "respuesta8",
"p9": "Sí",
"p13": "Responsable directo del programa",
"p14": "Se te otorgó de acuerdo a lo establecido",
"p15": "Sí",
"p16": "respuesta 16",
"p18": "respuesta18"
}
-->
+279
View File
@@ -0,0 +1,279 @@
<template>
<div>
<b-field label="Número de Cuenta">
<b-input
type="text"
placeholder="Número de Cuenta"
icon="school"
maxlength="9"
@keyup.enter.native="buscarAlumno()"
v-model="numeroCuenta"
expanded
/>
<b-button type="is-info" @click="buscarAlumno()"> Buscar </b-button>
</b-field>
<b-field label="Nombre">
<p class="input">{{ alumno.nombre }}</p>
</b-field>
<b-field label="Carrera">
<p class="input">{{ alumno.carrera }}</p>
</b-field>
<b-field label="Créditos">
<p class="input">
{{ alumno.creditos ? parseInt(alumno.creditos) : '' }}
<span v-if="alumno.creditos">%</span>
</p>
</b-field>
<b-field label="Seleccione programa">
<b-select placeholder="Seleccionar" v-model="programa" expanded>
<option :value="{}" disabled>Seleccionar</option>
<option v-for="(p, i) in programas" :key="i" :value="p">
{{ p.programa }}
</option>
</b-select>
</b-field>
<b-field label="Institución">
<p class="input">{{ programa.institucion }}</p>
</b-field>
<b-field label="Dependencia">
<p class="input">{{ programa.dependencia }}</p>
</b-field>
<b-field label="Clave del programa">
<p class="input">{{ programa.clavePrograma }}</p>
</b-field>
<div v-if="programa.acatlan">
<b-field label="Programa interno">
<b-input placeholder="Programa interno" v-model="programaInterno" />
</b-field>
<b-field class="mb-3" label="Profesor/Responsable de Programa">
<b-input
placeholder="Profesor/Responsable de Programa"
v-model="profesor"
/>
</b-field>
</div>
<b-field label="Fecha de inicio">
<b-datepicker
icon="calendar-today"
:min-date="minDate"
v-model="fechaInicio"
/>
</b-field>
<b-field label="Fecha de fin" v-if="fechaInicio">
<b-datepicker
icon="calendar-today"
:min-date="minDate2"
v-model="fechaFin"
/>
</b-field>
<b-field label="Correo electrónico del Alumno">
<b-input type="email" placeholder="Email" v-model="correo" />
</b-field>
<b-field
label="Carta de aceptación (en formato .PDF. No se aceptan fotos)."
>
<b-upload accept="application/pdf" v-model="file" drag-drop expanded>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
file.name ||
'Arrastra aquí tu archivo o da click aquí para buscar'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
<p class="is-size-7">
Si al momento de elegir un archivo este no se selecciona, haga click
en cancelar en la ventana emergente e intente de nuevo.
</p>
</div>
</b-upload>
</b-field>
<b-field class="has-text-centered mt-4">
<b-button
type="is-success"
:disabled="mostrarBoton()"
@click="
imprimirWarning(
'¿Esta seguro(a) de querer Pre-Registrar a este alumno?',
preRegistrar
)
"
>
Enviar
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
import moment from 'moment'
export default {
props: {
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
correo: '',
numeroCuenta: '',
profesor: '',
programaInterno: '',
programas: [],
alumno: {},
fechaFin: new Date(),
fechaInicio: new Date(),
file: {},
minDate: new Date(),
minDate2: new Date(),
programa: {},
}
},
methods: {
resetar() {
this.correo = ''
this.profesor = ''
this.programaInterno = ''
this.fechaFin = new Date()
this.fechaInicio = new Date()
this.file = {}
this.alumno = {}
this.programa = {}
},
mostrarBoton() {
if (
!this.alumno.idUsuario ||
!this.correo ||
!this.programa.idPrograma ||
(this.programa.acatlan && (!this.profesor || !this.programaInterno)) ||
!this.file.name
)
return true
return false
},
buscarAlumno() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/usuario/escolares?numeroCuenta=${this.numeroCuenta}`,
this.responsable.token
)
.then((res) => {
this.resetar()
this.alumno = res.data
this.updateIsLoading(false)
})
.catch((err) => {
this.numeroCuenta = ''
this.resetar()
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
preRegistrar() {
const formData = new FormData()
const data = {
idUsuario: this.alumno.idUsuario,
idPrograma: this.programa.idPrograma,
idCarrera: this.alumno.idCarrera,
numeroCuenta: this.numeroCuenta,
creditos: this.alumno.creditos.toString(),
correo: this.correo,
programaInterno: this.programaInterno,
profesor: this.profesor,
fechaInicio: moment(this.fechaInicio),
fechaFin: moment(this.fechaFin),
}
this.updateIsLoading(true)
formData.append('alumno', JSON.stringify(data))
formData.append('cartaAceptacion', this.file)
axios
.post(
`${process.env.api}/servicio/nuevo`,
formData,
this.responsable.tokenArchivo
)
.then((res) => {
this.numeroCuenta = ''
this.resetar()
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
obtenerProgramas() {
axios
.get(
`${process.env.api}/programa/programas_responsable?idUsuario=${this.responsable.idUsuario}`,
this.responsable.token
)
.then((res) => {
this.programas = res.data
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
updateFechas() {
this.fechaFin = new Date(
this.fechaInicio.getFullYear(),
this.fechaInicio.getMonth() + 6,
this.fechaInicio.getDate()
)
this.minDate2 = new Date(
this.fechaInicio.getFullYear(),
this.fechaInicio.getMonth() + 6,
this.fechaInicio.getDate()
)
},
},
watch: {
file() {
if (this.file.size >= 20000000) {
this.imprimirError({ message: 'El tamaño del archivo exede los 20MB' })
this.file = {}
}
},
fechaInicio() {
this.updateFechas()
},
},
created() {
if (this.responsable.idTipoUsuario === 2) {
this.minDate.setDate(this.minDate.getDate() - 16)
this.updateFechas()
this.obtenerProgramas()
}
},
}
</script>
<style scoped></style>
@@ -0,0 +1,143 @@
<template>
<div>
<div class="columns">
<b-field class="column" label="Número de Cuenta">
<b-input
type="text"
placeholder="No.Cuenta"
icon="school"
maxlength="9"
@keyup.enter.native="obtenerServicios()"
v-model="search.numeroCuenta"
rounded
/>
</b-field>
<b-field class="column" label="Nombre">
<b-input
type="name"
placeholder="Nombre"
icon="account"
@keyup.enter.native="obtenerServicios()"
v-model="search.nombre"
rounded
/>
</b-field>
<b-field class="column" label="Status">
<b-select icon="information" v-model="search.idStatus" expanded rounded>
<option value="">Status</option>
<option
v-for="(s, i) in status"
:key="i"
:value="s.idStatus"
v-show="i < 9"
>
{{ s.status }}
</option>
</b-select>
</b-field>
<b-field class="column is-align-self-center">
<b-button type="is-info" @click="obtenerServicios()" expanded rounded>
Buscar
</b-button>
</b-field>
</div>
<TablaServiciosSociales
:columnaFechaCreado="false"
:columnasResponsable="true"
:isLoading="isLoading"
:idTipoUsuario="responsable.idTipoUsuario"
:page="page"
:total="total"
:data="data"
:onPageChange="onPageChange"
/>
</div>
</template>
<script>
import axios from 'axios'
import TablaServiciosSociales from '@/components/TablaServiciosSociales'
export default {
components: {
TablaServiciosSociales,
},
props: {
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
data() {
return {
isLoading: false,
page: 1,
total: 0,
data: [],
status: [],
search: {
idStatus: '',
},
searchAnterior: {},
}
},
methods: {
onPageChange(page) {
this.page = page
this.obtenerServicios()
},
obtenerServicios() {
let data = ''
this.isLoading = true
if (
this.search.numeroCuenta != this.searchAnterior.numeroCuenta ||
this.search.nombre != this.searchAnterior.nombre ||
this.search.idStatus != this.searchAnterior.idStatus
) {
this.page = 1
this.searchAnterior.numeroCuenta = this.search.numeroCuenta
this.searchAnterior.nombre = this.search.nombre
this.searchAnterior.idStatus = this.search.idStatus
}
if (this.search.idStatus) data += `&idStatus=${this.search.idStatus}`
if (this.search.nombre) data += `&nombre=${this.search.nombre}`
if (this.search.numeroCuenta)
data += `&numeroCuenta=${this.search.numeroCuenta}`
axios
.get(
`${process.env.api}/servicio/servicios_responsable?idUsuario=${this.responsable.idUsuario}&pagina=${this.page}${data}`,
this.responsable.token
)
.then((res) => {
this.data = res.data.serviciosResponsable
this.total = res.data.count
this.isLoading = false
})
.catch((err) => {
this.isLoading = false
this.imprimirError(err.response.data)
})
},
obtenerCatalogoStatus() {
axios
.get(`${process.env.api}/status`, this.responsable.token)
.then((res) => {
this.status = res.data
this.obtenerServicios()
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
},
created() {
if (this.responsable.idTipoUsuario === 2) this.obtenerCatalogoStatus()
},
}
</script>
<style scoped></style>
+96
View File
@@ -0,0 +1,96 @@
<template>
<div>
<b-field
:label="`Carta de ${tipoCarta} (en formato .pdf, no se aceptan fotos).`"
>
<b-upload accept="application/pdf" v-model="file" drag-drop expanded>
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5">
{{
file.name ||
'Arrastra aquí tu archivo o da click aquí para buscarlo.'
}}
</p>
<p class="is-size-6">Tamaño máximo 20MB</p>
</div>
</b-upload>
</b-field>
<b-field class="has-text-centered my-5">
<b-button
type="is-success"
:disabled="!file.name"
@click="
imprimirWarning(
`¿Estas seguro(a) de querer subir esta carta de ${tipoCarta}?`,
subir
)
"
>
Enviar
</b-button>
</b-field>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
idServicio: { type: Number, required: true },
path: { type: String, required: true },
tipoCarta: { type: String, required: true },
variableName: { type: String, required: true },
responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() {
return {
file: {},
}
},
methods: {
subir() {
const formData = new FormData()
const data = { idServicio: this.idServicio }
this.updateIsLoading(true)
formData.append('data', JSON.stringify(data))
formData.append(this.variableName, this.file)
axios
.put(
`${process.env.api}/servicio/${this.path}`,
formData,
this.responsable.tokenArchivo
)
.then((res) => {
localStorage.removeItem('idServicio')
this.updateIsLoading(false)
this.imprimirMensaje(res.data.message)
this.$router.push('/responsable')
})
.catch((err) => {
this.updateIsLoading(false)
this.imprimirError(err.response.data)
})
},
},
watch: {
file() {
if (this.file.size >= 20000000) {
this.imprimirError({ message: 'El tamaño del archivo exede los 20MB' })
this.file = {}
}
},
},
}
</script>
<style scoped></style>
-189
View File
@@ -1,189 +0,0 @@
<template>
<div
v-if="idServicio != null && cartaAceptacion != null"
class="container footter"
>
<b-button
class="border-info mt-5"
type="is-info is-light"
icon-left="arrow-left-box"
tag="router-link"
to="/responsable"
>Regresar</b-button
>
<h3 class="title is-4 mt-4">
Carta de aceptación (en formato .PDF. No se aceptan fotos).
</h3>
<b-field>
<b-upload
v-model="file"
drag-drop
type="is-black"
expanded
accept="application/pdf"
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
file.name || "Arrastra aquí tu archivo o da click para buscar"
}}
</p>
<p>Tamaño máximo para el archivo: 20MB</p>
</div>
</section>
</b-upload>
</b-field>
<b-field class="centro">
<b-button
:disabled="file == ''"
class="border-success my-5"
type="is-success"
@click="Enviar()"
>Enviar</b-button
>
</b-field>
<b-loading :is-full-page="true" v-model="isLoading" :can-cancel="false">
</b-loading>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
isFullPage: true,
file: [],
idServicio: "",
cartaAceptacion: "",
isLoading: false,
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
validarTamaño() {
const TamMax = 20000000;
const archivo = this.file;
if (archivo.size > TamMax) {
this.toast();
this.file = "";
}
},
toast() {
this.$buefy.toast.open({
message: "El archivo excede el tamaño permitido",
type: "is-danger",
});
},
Enviar() {
const data = { idServicio: this.idServicio };
const formData = new FormData();
formData.append("data", JSON.stringify(data));
formData.append("cartaAceptacion", this.file);
this.isLoading = true;
axios
.put(`${process.env.api}/servicio/carta_aceptacion`, formData, {
headers: {
"Content-Type": "multipart/form-data",
token: this.token.headers.token,
},
})
.then((res) => {
this.$buefy.dialog.alert({
title: "Success",
message: "Se enviaron los datos correctamente",
type: "is-success",
hasIcon: true,
icon: "checkbox-marked-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
localStorage.removeItem("idServicio");
localStorage.removeItem("cartaAceptacion");
this.$router.push("/responsable");
});
},
getIdLocal() {
this.idServicio = localStorage.getItem("idServicio");
this.cartaAceptacion = localStorage.getItem("cartaAceptacion");
if (this.idServicio === null || this.cartaAceptacion === null) {
this.$router.push("/responsable");
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
watch: {
file: function(newFile, oldFile) {
this.validarTamaño();
},
},
created() {
this.getIdLocal();
},
};
</script>
<style>
.centro {
text-align: center;
}
.footter {
margin-bottom: 10rem;
}
</style>
-190
View File
@@ -1,190 +0,0 @@
<template>
<div
v-if="idServicio != null && cartaTermino != null"
class="container footter"
>
<b-button
class="border-info mt-5"
type="is-info is-light"
icon-left="arrow-left-box"
tag="router-link"
to="/responsable"
>Regresar</b-button
>
<h3 class="title is-4 mt-4">
Carta de termino (en formato .PDF. No se aceptan fotos).
</h3>
<b-field>
<b-upload
v-model="file"
drag-drop
type="is-black"
expanded
accept="application/pdf"
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
file.name || "Arrastra aquí tu archivo o da click para buscar"
}}
</p>
<p>Tamaño máximo para el archivo: 20MB</p>
</div>
</section>
</b-upload>
</b-field>
<b-field class="centro">
<b-button
:disabled="file == ''"
class="border-success my-5 is-medium"
type="is-success"
@click="Enviar()"
>
Enviar
</b-button>
</b-field>
<b-loading :is-full-page="true" v-model="isLoading" :can-cancel="true">
</b-loading>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
isFullPage: true,
file: [],
idServicio: "",
cartaTermino: "",
isLoading: false,
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
validarTamaño() {
const TamMax = 20000000;
const archivo = this.file;
if (archivo.size > TamMax) {
this.toast();
this.file = "";
}
},
toast() {
this.$buefy.toast.open({
message: "El archivo excede el tamaño permitido",
type: "is-danger",
});
},
Enviar() {
const data = { idServicio: this.idServicio };
const formData = new FormData();
formData.append("data", JSON.stringify(data));
formData.append("cartaTermino", this.file);
this.isLoading = true;
axios
.put(`${process.env.api}/servicio/carta_termino`, formData, {
headers: {
"Content-Type": "multipart/form-data",
token: this.token.headers.token,
},
})
.then((res) => {
this.$buefy.dialog.alert({
title: "Success",
message: "Se enviaron los datos correctamente",
type: "is-success",
hasIcon: true,
icon: "checkbox-marked-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
localStorage.removeItem("idServicio");
localStorage.removeItem("cartaTermino");
this.$router.push("/responsable");
});
},
getIdLocal() {
this.idServicio = localStorage.getItem("idServicio");
this.cartaTermino = localStorage.getItem("cartaTermino");
if (this.idServicio === null || this.cartaTermino === null) {
this.$router.push("/responsable");
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
watch: {
file: function(newFile, oldFile) {
this.validarTamaño();
},
},
created() {
this.getIdLocal();
},
};
</script>
<style>
.centro {
text-align: center;
}
.footter {
margin-bottom: 10rem;
}
</style>
-287
View File
@@ -1,287 +0,0 @@
<template>
<div v-if="this.idServicio && this.cuestionario" class="container">
<div class="section">
<b-button
class="border-info mb-5"
type="is-info is-light"
icon-left="arrow-left-box"
tag="router-link"
to="/responsable"
>Regresar</b-button
>
<h1 class="title is-3 mt-2">
Estimad(a) responsable de programa de servicio social:
</h1>
<p>
Te solicitamos llenar cuidadosamente los campos solicitados a
continuación para poder validar el término del servicio social de
nuestro alumno(a)
</p>
</div>
<section class="section pt-0">
<h3 class="subtitle is-5">
Mencione 5 actividades desempeñadas por el alumno:
</h3>
<b-input
class="my-4"
placeholder="1.-"
v-model="actividad1"
maxlength="400"
></b-input>
<b-input
class="my-4"
placeholder="2.-"
v-model="actividad2"
maxlength="400"
></b-input>
<b-input
class="my-4"
placeholder="3.-"
v-model="actividad3"
maxlength="400"
></b-input>
<b-input
class="my-4"
placeholder="4.-"
v-model="actividad4"
maxlength="400"
></b-input>
<b-input
class="mt-3"
placeholder="5.-"
v-model="actividad5"
maxlength="400"
></b-input>
</section>
<section class="section pt-0">
<div class="columns">
<p class="column is- 9">
1. Conocimiento teóricos para las funciones encomendadas
</p>
<b-field class="column is-2">
<b-select placeholder="Seleccionar" v-model="retroalimentacion[0]">
<option value="1">Deficiente</option>
<option value="2">Regular</option>
<option value="3">Bueno</option>
<option value="4">Excelente</option>
</b-select>
</b-field>
</div>
<br />
<div class="columns">
<p class="column is- 9">
2. Conocimientos técnicos para las funciones encomendadas
</p>
<b-field class="column is-2">
<b-select placeholder="Seleccionar" v-model="retroalimentacion[1]">
<option value="1">Deficiente</option>
<option value="2">Regular</option>
<option value="3">Bueno</option>
<option value="4">Excelente</option>
</b-select>
</b-field>
</div>
<br />
<div class="columns">
<p class="column is- 9">
3. Iniciativa para la implementación de mejoras en la empresa
</p>
<b-field class="column is-2">
<b-select placeholder="Seleccionar" v-model="retroalimentacion[2]">
<option value="1">Deficiente</option>
<option value="2">Regular</option>
<option value="3">Bueno</option>
<option value="4">Excelente</option>
</b-select>
</b-field>
</div>
<br />
<div class="columns">
<p class="column is- 9">
4. Puntualidad en la entrega de los trabajos de las tareas
encomendadas
</p>
<b-field class="column is-2">
<b-select placeholder="Seleccionar" v-model="retroalimentacion[3]">
<option value="1">Deficiente</option>
<option value="2">Regular</option>
<option value="3">Bueno</option>
<option value="4">Excelente</option>
</b-select>
</b-field>
</div>
<br />
<div class="columns">
<p class="column is- 9">5. Desempeño general de sus funciones</p>
<b-field class="column is-2">
<b-select placeholder="Seleccionar" v-model="retroalimentacion[4]">
<option value="1">Deficiente</option>
<option value="2">Regular</option>
<option value="3">Bueno</option>
<option value="4">Excelente</option>
</b-select>
</b-field>
</div>
<p class="my-5">
6. De acuerdo a lo observado ¿cuáles considera que son las cualidades de
nuestros alumnos de esta licenciatura?
</p>
<b-input placeholder="Respuesta" maxlength="800" v-model="p6"></b-input>
<p class="my-5">
7. De acuerdo a lo observado ¿cuáles considera que son los aspectos a
mejorar en la formación de nuestros alumnos de esta licenciatura?
</p>
<b-input placeholder="Respuesta" maxlength="800" v-model="p7"></b-input>
<b-field class="centro">
<b-button
:disabled="
actividad1 == '' ||
actividad2 == '' ||
actividad3 == '' ||
actividad4 == '' ||
actividad5 == '' ||
retroalimentacion.length < 5 ||
p6 == '' ||
p7 == ''
"
class="border-success my-5"
type="is-success"
@click="enviarCuestionario()"
>Enviar</b-button
>
</b-field>
</section>
<b-loading :is-full-page="true" v-model="isLoading" :can-cancel="true">
</b-loading>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
idServicio: localStorage.getItem("idServicio"),
cuestionario: "",
isLoading: false,
actividad1: "",
actividad2: "",
actividad3: "",
actividad4: "",
actividad5: "",
retroalimentacion: [],
p6: "",
p7: "",
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
enviarCuestionario() {
const data = {
idServicio: this.idServicio,
actividad1: this.actividad1,
actividad2: this.actividad2,
actividad3: this.actividad3,
actividad4: this.actividad4,
actividad5: this.actividad5,
retroalimentacion: this.retroalimentacion,
p6: this.p6,
p7: this.p7,
idServicio: this.idServicio,
};
this.isLoading = true;
axios
.post(`${process.env.api}/cuestionario_programa`, data, this.token)
.then((res) => {
this.$buefy.dialog.alert({
title: "Success",
message: "Se enviaron los datos correctamente",
type: "is-success",
hasIcon: true,
icon: "checkbox-marked-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
localStorage.removeItem("idServicio");
localStorage.removeItem("cuestionario");
this.$router.push("/responsable");
});
},
getIdLocal() {
this.idServicio = localStorage.getItem("idServicio");
this.cuestionario = localStorage.getItem("cuestionario");
if (this.idServicio === null || this.cuestionario === null) {
this.$router.push("/responsable");
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
created() {
this.getIdLocal();
},
};
</script>
<style>
.centro {
text-align: center;
}
</style>
@@ -1,508 +0,0 @@
<template>
<section>
<h1 class="title is-1 titleAnadir">
Añadir Servicio Social
</h1>
<div
class="columns is-variable is-1-mobile is-0-tablet is-3-desktop is-8-widescreen is-2-fullhd pl-0"
>
<div class="column pl-0">
<form>
<b-field class="column p-0 my-5 is-full">
<input
class="input column "
v-model="noCuenta"
message="Solo numeros"
required="required"
maxlength="9"
type="number"
placeholder="Cuenta"
min="0"
/>
<p class="control">
<b-button class="button is-info" @click="buscarAlumno()"
>Buscar</b-button
>
</p>
</b-field>
<b-field label="Nombre">
<div class="input">{{ alumno.nombre }}</div>
</b-field>
<b-field label="Carrera">
<div class="input">{{ alumno.carrera }}</div>
</b-field>
<b-field label="Créditos">
<div class="input">
{{ alumno.creditos }}<span v-if="alumno.creditos">%</span>
</div>
</b-field>
<b-field label="Seleccione programa">
<b-select
placeholder="Seleccionar"
expanded
v-model="programaSelectedID"
>
<option value="">Seleccionar</option>
<option
v-for="programa in programas"
v-bind:key="programa.idPrograma"
:value="programa.idPrograma"
>{{ programa.programa }}</option
>
</b-select>
</b-field>
<b-field label="Institución">
<div class="input">{{ programaSelected.institucion }}</div>
</b-field>
<b-field label="Dependencia">
<div class="input">{{ programaSelected.dependencia }}</div>
</b-field>
<b-field label="Clave del programa">
<div class="input">{{ programaSelected.clavePrograma }}</div>
</b-field>
<div v-if="programaSelected.acatlan == true">
<b-field label="Programa interno">
<b-input
v-model="programaSelected.programaInterno"
placeholder="Programa interno"
></b-input>
</b-field>
<b-field label="Profesor/Responsable de Programa">
<b-input
v-model="programaSelected.profesor"
placeholder="Profesor/Responsable de Programa"
></b-input>
</b-field>
</div>
<b-field label="Fecha de inicio">
<b-datepicker
placeholder="Inicio"
icon="calendar-today"
v-model="alumno.inicio"
:min-date="minDate"
>
</b-datepicker>
</b-field>
<b-field label="Fecha de fin" v-if="alumno.inicio">
<b-datepicker
placeholder="Fin"
v-model="alumno.fin"
:min-date="minDate2"
icon="calendar-today"
>
</b-datepicker>
</b-field>
<b-field label="Correo">
<b-input
placeholder="Email"
type="email"
v-model="alumno.correo"
></b-input>
</b-field>
<h3 class="title is-4 mt-6">
Carta de aceptación (en formato .PDF. No se aceptan fotos).
</h3>
<b-field>
<b-upload
v-model="file"
drag-drop
type="is-black"
expanded
accept="application/pdf"
>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>
{{
file.name ||
"Arrastra aquí tu archivo o da click para buscar"
}}
</p>
<p>Tamaño máximo 20MB</p>
</div>
</section>
</b-upload>
</b-field>
</form>
<div class="my-6">
<b-button
tag="router-link"
to="/responsable"
type="is-info is-light "
icon-left="arrow-left-box"
class="border-info"
style="float: left;"
size="is-mediumm"
>
Regresar
</b-button>
<!-- <BotonRegresar :path="'/responsable'" /> -->
<b-field class="derecha">
<button
:disabled="disabled()"
class="button enviar is-success is-mediumm"
@click="Enviar()"
>
Enviar
</button>
</b-field>
</div>
</div>
</div>
<b-loading :is-full-page="true" v-model="isLoading" :can-cancel="false" />
</section>
</template>
<script>
import "buefy/dist/buefy.css";
import validator from "validator";
import axios from "axios";
import moment from "moment";
export default {
data() {
return {
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
isLoading: false,
noCuenta: "",
sizeOk: "",
searched: false,
minDate: new Date(),
programaSelectedID: "",
file: [],
programas: [],
programaSelected: {
idPrograma: null,
institucion: "",
dependencia: "",
programa: "",
clavePrograma: "",
acatlan: "",
activo: "",
idUsuario: "",
programaInterno: "",
profesor: "",
},
alumno: {
cuenta: "",
nombre: "",
carrera: "",
creditos: "",
idAlumno: "",
idCarrera: "",
inicio: [],
fin: [],
correo: "",
},
};
},
methods: {
reset() {
this.programaSelected.idPrograma = "";
this.programaSelected.institucion = "";
this.programaSelected.dependencia = "";
this.programaSelected.programa = "";
this.programaSelected.clavePrograma = "";
this.programaSelected.acatlan = "";
this.programaSelected.activo = "";
this.programaSelected.idUsuario = "";
this.programaSelected.programaInterno = "";
this.programaSelected.profesor = "";
this.alumno.cuenta = "";
this.alumno.nombre = "";
this.alumno.creditos = "";
this.alumno.carrera = "";
this.alumno.idAlumno = "";
this.alumno.idCarrera = "";
this.alumno.correo = "";
this.alumno.inicio = [];
this.alumno.fin = [];
this.noCuenta = "";
this.file = [];
this.programaSelectedID = "";
},
disabled() {
if (this.programaSelected.acatlan == false) {
if (
this.file != "" &&
this.noCuenta != "" &&
this.alumno.correo != "" &&
this.alumno.inicio != "" &&
this.alumno.fin != "" &&
this.programaSelectedID != ""
)
return false;
else return true;
} else {
if (
this.file != "" &&
this.noCuenta != "" &&
this.alumno.correo != "" &&
this.alumno.inicio != "" &&
this.alumno.fin != "" &&
this.programaSelectedID != "" &&
this.programaSelected.programaInterno != "" &&
this.programaSelected.profesor != ""
)
return false;
else return true;
}
},
esNumero(numero) {
const ultimaLetra = numero.length - 1;
if (numero && !validator.isNumeric(numero[ultimaLetra])) {
return numero.substr(0, ultimaLetra);
}
return numero;
},
maxLength(str, max) {
if (str.length > max) return str.substr(0, max);
return str;
},
correoValidado() {
if (validator.isEmail(this.alumno.correo)) {
return "";
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
buscarAlumno() {
this.isLoading = true;
axios
.get(
`${process.env.api}/usuario/escolares?numeroCuenta=${this.noCuenta}`,
this.token
)
.then((resp) => {
this.alumno.cuenta = this.noCuenta;
this.alumno.nombre = resp.data.nombre;
this.alumno.carrera = resp.data.carrera;
this.alumno.creditos = parseInt(resp.data.creditos, 10);
this.alumno.idCarrera = resp.data.idCarrera;
this.alumno.idAlumno = resp.data.idUsuario;
this.searched = true;
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
Enviar() {
this.isLoading = true;
const data = {
idUsuario: this.alumno.idAlumno,
idPrograma: this.programaSelected.idPrograma,
idCarrera: this.alumno.idCarrera,
numeroCuenta: this.alumno.cuenta,
creditos: this.alumno.creditos.toString(),
correo: this.alumno.correo,
programaInterno: this.programaSelected.programaInterno,
profesor: this.programaSelected.profesor,
fechaInicio: moment(this.alumno.inicio),
fechaFin: moment(this.alumno.fin),
};
const formData = new FormData();
formData.append("alumno", JSON.stringify(data));
formData.append("cartaAceptacion", this.file);
axios
.post(`${process.env.api}/servicio/nuevo`, formData, {
headers: {
"Content-Type": "multipart/form-data",
token: this.token.headers.token,
},
})
.then((res) => {
this.$buefy.dialog.alert({
title: "Success",
message: "Se enviaron los datos correctamente",
type: "is-success",
hasIcon: true,
icon: "checkbox-marked-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
this.reset();
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
},
watch: {
noCuenta() {
if (this.searched === false) {
this.noCuenta = Number(this.noCuenta) < 0 ? "" : this.noCuenta;
this.noCuenta = this.esNumero(this.noCuenta);
this.noCuenta = this.maxLength(this.noCuenta, 9);
} else {
this.noCuenta = "";
this.searched = false;
this.reset();
}
},
programaSelectedID() {
if (this.programaSelectedID) {
for (let i = 0; i < this.programas.length; i++) {
if (this.programas[i].idPrograma === this.programaSelectedID) {
this.programaSelected.idPrograma = this.programas[i].idPrograma;
this.programaSelected.programa = this.programas[i].programa;
this.programaSelected.institucion = this.programas[i].institucion;
this.programaSelected.dependencia = this.programas[i].dependencia;
this.programaSelected.clavePrograma = this.programas[
i
].clavePrograma;
this.programaSelected.acatlan = this.programas[i].acatlan;
this.programaSelected.activo = this.programas[i].activo;
}
}
} else {
this.programaSelected.institucion = "";
this.programaSelected.dependencia = "";
this.programaSelected.programa = "";
this.programaSelected.clavePrograma = "";
this.programaSelected.acatlan = "";
this.programaSelected.activo = "";
//this.programaSelected.idUsuario = "";
this.programaSelected.programaInterno = "";
this.programaSelected.profesor = "";
}
},
file() {
if (this.file.size >= 20000000) {
this.$buefy.dialog.alert({
title: "Error",
message: "El tamaño del archivo exede los 20MB",
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
this.file = [];
}
},
"alumno.inicio"() {
this.alumno.fin = [];
},
},
mounted() {
axios
.get(
`${
process.env.api
}/programa/programas_responsable?idUsuario=${localStorage.getItem(
"idUsuario"
)}`,
this.token
)
.then((resp) => {
this.programas = resp.data;
})
.catch((error) => {
this.error(error.response.data.message);
});
this.minDate.setDate(this.minDate.getDate() - 16);
},
computed: {
minDate2() {
const min = new Date(this.alumno.inicio);
return new Date(min.getFullYear(), min.getMonth() + 6, min.getDate());
},
},
};
</script>
<style scoped>
.titleAnadir,
pre {
margin: 4rem 0 0rem 0;
}
.derecha {
text-align: center;
}
.file-cta {
background-color: #167df0 !important;
}
.disabled {
cursor: help !important;
pointer-events: all !important;
}
.columns {
margin: 0;
}
@media (min-width: 600px) {
.derecha {
padding-right: 120px;
}
}
</style>
-426
View File
@@ -1,426 +0,0 @@
<template>
<div
v-if="this.idTipoUsuario == 2 && this.tipoUsuario == 'responsable'"
class="container"
>
<div class="columns">
<div class="column is-3 mb-0">
<b-field>
<b-input
placeholder="No.Cuenta"
icon="school"
rounded
v-model="numeroCuenta"
maxlength="9"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4">
<b-field>
<b-input
type="name"
placeholder="Nombre"
icon="account"
rounded
v-model="nombre"
></b-input>
</b-field>
</div>
<div class="column is-3 mb-4 pb-4 ">
<b-field>
<b-select icon="information" expanded rounded v-model="idStatus">
<optgroup>
<option value="">Status</option>
<option value="1">Pre-Registro</option>
<option value="2">Pre-Registro Validado</option>
<option value="3">Registro</option>
<option value="4">Pre-Término</option>
<option value="5">Término</option>
<option value="6">Liberación</option>
<option value="7">Carta Aceptación Rechazada</option>
<option value="8">Carta Termino Rechazada</option>
<option value="9">Informe Global Rechazado</option>
</optgroup>
</b-select>
</b-field>
</div>
<div class="buttons section pt-3 pl-5">
<b-button type="is-info" @click="obtenerDatos(idStatus)">
Buscar
</b-button>
</div>
</div>
<div class="columns">
<section class="column is-12">
<b-table
:data="data"
:loading="isLoading"
hoverable
striped
paginated
backend-pagination
:total="total"
:per-page="perPage"
@page-change="onPageChange"
>
<b-table-column field="nombre" label="Nombre" v-slot="props" centered>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.nombre }}</span
>
<span v-else>{{ props.row.nombre }}</span>
</b-table-column>
<b-table-column
field="numeroCuenta"
label="Número de Cuenta"
v-slot="props"
centered
width="100"
>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.numeroCuenta }}</span
>
<span v-else>{{ props.row.numeroCuenta }}</span>
</b-table-column>
<b-table-column
field="carrera"
label="Carrera"
v-slot="props"
centered
>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.carrera }}</span
>
<span v-else>{{ props.row.carrera }}</span>
</b-table-column>
<b-table-column
field="fechaInicio"
truncate="10"
label="Fecha Inicio"
v-slot="props"
centered
>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ fecha(props.row.fechaInicio) }}</span
>
<span v-else>{{ fecha(props.row.fechaInicio) }}</span>
</b-table-column>
<b-table-column
field="fechaFin"
label="Fecha Fin"
v-slot="props"
centered
>
<span
class="cursorR"
v-if="props.row.idStatus == 7"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ fecha(props.row.fechaFin) }}</span
>
<span v-else>{{ fecha(props.row.fechaFin) }}</span>
</b-table-column>
<b-table-column field="status" label="Status" v-slot="props" centered>
<span
v-if="props.row.idStatus == 7"
class="cursorR tag"
:class="types(props.row.idStatus)"
@click="cartaAceptacion(props.row.idServicio, props.row.idStatus)"
>{{ props.row.status }}</span
>
<span v-else class="tag" :class="types(props.row.idStatus)">{{
props.row.status
}}</span>
</b-table-column>
<b-table-column
field="cartaTermino"
label="Carta Término"
v-slot="props"
centered
v-if="idTipoUsuario == 2"
>
<div v-if="props.row.idStatus >= 4 && props.row.idStatus != 7">
<span v-if="props.row.cartaTermino">
<b-icon
:icon="iconoCarta(props.row.cartaTermino)"
class="tag is-success"
></b-icon>
</span>
<b-button
v-else
size="is-small"
@click="
botonCarta(props.row.cartaTermino, props.row.idServicio)
"
class="tag is-danger"
:icon="iconoCarta(props.row.cartaTermino)"
>
Carta Término
</b-button>
</div>
</b-table-column>
<b-table-column
field="cuestionario"
label="Cuestionario"
v-slot="props"
centered
v-if="idTipoUsuario == 2"
>
<div v-if="props.row.idStatus >= 4 && props.row.idStatus != 7">
<span v-if="props.row.cuestionario != null">
<b-icon
:icon="iconoCuestionario(props.row.cuestionario)"
class="tag is-success"
></b-icon>
</span>
<b-button
v-if="props.row.cuestionario === null"
size="is-small"
@click="
botonCuestionario(
props.row.cuestionario,
props.row.idServicio
)
"
class="tag is-danger"
:icon="iconoCuestionario(props.row.cuestionario)"
>
Cuestionario
</b-button>
</div>
</b-table-column>
</b-table>
</section>
</div>
</div>
</template>
<script>
import axios from "axios";
import moment from "moment";
export default {
data() {
return {
idTipoUsuario: "",
idUsuario: "",
tipoUsuario: "",
data: [],
total: "",
isLoading: false,
page: 1,
perPage: 25,
numeroCuenta: "",
nombre: "",
idStatus: "",
idServicio: "",
token: {
headers: {
token: window.localStorage.getItem("token"),
},
},
};
},
methods: {
onPageChange(page) {
this.page = page;
this.obtenerDatos();
},
types(idStatus) {
if (idStatus === 1) {
return "is-dark";
} else if (idStatus === 2) {
return "is-info";
} else if (idStatus === 3) {
return "is-warning";
} else if (idStatus === 4) {
return "is-link";
} else if (idStatus === 5) {
return "is-success";
} else if (idStatus === 6) {
return "is-success is-light";
} else if (idStatus === 7) {
return "is-danger";
} else if (idStatus === 8) {
return "is-danger";
} else if (idStatus === 9) {
return "is-danger";
}
},
botonCarta(cartaTermino, idServicio) {
window.localStorage.setItem("idServicio", idServicio);
window.localStorage.setItem("cartaTermino", cartaTermino);
this.$router.push("/responsable/carta_termino");
if (cartaTermino === 1) {
return "is-success";
} else {
return "is-danger";
}
},
botonCuestionario(cuestionario, idServicio) {
window.localStorage.setItem("idServicio", idServicio);
window.localStorage.setItem("cuestionario", cuestionario);
this.$router.push("/responsable/cuestionario");
if (cuestionario === 1) {
return "is-success";
} else {
return "is-danger";
}
},
iconoCarta(cartaTermino) {
if (cartaTermino != null) {
return "check";
}
},
iconoCuestionario(cuestionario) {
if (cuestionario != null) {
return "check";
}
},
fecha(date) {
const fecha = moment(date.substr(0, 10));
return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}`;
},
obtenerDatos(idStatus) {
this.isLoading = true;
this.data = [];
axios
.get(
`${process.env.api}/servicio/servicios_responsable?idUsuario=${this.idUsuario}&pagina=${this.page}&idStatus=${this.idStatus}&nombre=${this.nombre}&numeroCuenta=${this.numeroCuenta}`,
this.token
)
.then((res) => {
const servicios = res.data.servicios;
if (servicios.length !== 0) {
for (let i = 0; i < servicios.length; i++) {
this.data.push({
nombre: servicios[i].Usuario.nombre,
numeroCuenta: servicios[i].Usuario.usuario,
carrera: servicios[i].Carrera.carrera,
fechaInicio: servicios[i].fechaInicio,
fechaFin: servicios[i].fechaFin,
status: servicios[i].Status.status,
idStatus: servicios[i].Status.idStatus,
cuestionario: servicios[i].idCuestionarioPrograma,
cartaTermino: servicios[i].cartaTermino,
idServicio: servicios[i].idServicio,
});
}
}
let currentTotal = servicios.length;
let contador;
for (let i = 0; i < res.data.registros / 25 + 1; i++) {
contador = i;
}
currentTotal = this.perPage * contador;
this.total = currentTotal;
})
.catch((error) => {
this.error(error.response.data.message);
})
.finally(() => {
this.isLoading = false;
});
},
cartaAceptacion(idServicio, idStatus) {
window.localStorage.setItem("idServicio", idServicio);
window.localStorage.setItem("cartaAceptacion", idStatus);
this.$router.push("/responsable/carta_aceptacion");
},
getIdLocal() {
this.idUsuario = localStorage.getItem("idUsuario");
this.idTipoUsuario = localStorage.getItem("idTipoUsuario");
this.tipoUsuario = localStorage.getItem("tipoUsuario");
if (this.idTipoUsuario != 2 && this.tipoUsuario != "responsable") {
localStorage.clear();
this.$router.push("/");
}
},
error(msj) {
let salir = false;
switch (msj) {
case "invalid signature":
msj = "Tu token no es valido, inicia sesión de nuevo.";
salir = true;
break;
case "jwt expired":
msj = "Tu sesión ha expirado, inicia sesión de nuevo.";
salir = true;
break;
case "jwt malformed":
msj = "No se encontro tu token, inicia sesión de nuevo.";
salir = true;
break;
case "No hay token":
msj = "Ocurrio un error al enviar tu token, inicia sesión de nuevo.";
salir = true;
break;
}
this.$buefy.dialog.alert({
title: "Error",
message: msj,
type: "is-danger",
hasIcon: true,
icon: "alert-circle",
iconPack: "mdi",
ariaRole: "alertdialog",
ariaModal: true,
});
if (salir == true) {
localStorage.clear();
this.$router.push(`/`);
}
},
},
created() {
this.getIdLocal();
this.obtenerDatos(0);
},
};
</script>
<style>
.input:focus {
border: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select select:focus {
border-color: #1b3d70;
box-shadow: 0 0 8px 0 #1b3d70;
}
.select:not(.is-multiple):not(.is-loading)::after {
border-color: #1b3d70;
}
.pagination-link.is-current {
background-color: #1b3d70;
border-color: #1b3d70;
}
.cursorR {
cursor: pointer;
}
</style>
-27
View File
@@ -1,27 +0,0 @@
<template>
<section class="mensaje has-text-justified is-size-6 ">
<p class="block is-size-5">
Estimado(a) responsable de programa de servicio social:
</p>
<p class="block ">
Te solicitamos llenar cuidadosamente los campos solicitados a continuación
para iniciar el trámite de registro de servicio social de nuestro
alumno(a), quien a su vez completará posteriormente el proceso en este
mismo sistema con otros datos.
</p>
<p class="block ">
Es muy importante escribir correctamente el correo del alumno para que el
sistema pueda enviarle la notificación correspondiente de que ya puede
ingresar a completar su registro. También debes tomar en cuenta que la
fecha de inicio NO se podrá modificar, sólo la fecha de término en caso de
que el alumno no cumpla las 480 horas en el periodo mínimo de 6 meses. Al
siguiente día de la fecha de término programada, se activará la opción de
cargar la carta de término y llenar el cuestionario de desempeño del
alumno. En caso de que exista algún error en los datos o cartas emitidas
se les notificará en este panel en cuanto el Departamento de Servicio
Social y Bolsa de Trabajo revise su solicitud, para que realicen la
corrección correspondiente.
</p>
</section>
</template>
View File
-9
View File
@@ -1,9 +0,0 @@
<!doctype html>
<html>
<head>
<title>servicio_social_front</title><meta data-n-head="1" charset="utf-8"><meta data-n-head="1" name="viewport" content="width=device-width,initial-scale=1"><meta data-n-head="1" data-hid="description" name="description" content=""><link data-n-head="1" rel="icon" type="image/x-icon" href="/favicon.ico"><link data-n-head="1" rel="stylesheet" type="text/css" href="//cdn.materialdesignicons.com/5.0.45/css/materialdesignicons.min.css"><link rel="preload" href="/_nuxt/e53a321.js" as="script"><link rel="preload" href="/_nuxt/df5b311.js" as="script"><link rel="preload" href="/_nuxt/9aa6f10.js" as="script"><link rel="preload" href="/_nuxt/7184dd6.js" as="script">
</head>
<body>
<div id="__nuxt"><style>#nuxt-loading{background:#fff;visibility:hidden;opacity:0;position:absolute;left:0;right:0;top:0;bottom:0;display:flex;justify-content:center;align-items:center;flex-direction:column;animation:nuxtLoadingIn 10s ease;-webkit-animation:nuxtLoadingIn 10s ease;animation-fill-mode:forwards;overflow:hidden}@keyframes nuxtLoadingIn{0%{visibility:hidden;opacity:0}20%{visibility:visible;opacity:0}100%{visibility:visible;opacity:1}}@-webkit-keyframes nuxtLoadingIn{0%{visibility:hidden;opacity:0}20%{visibility:visible;opacity:0}100%{visibility:visible;opacity:1}}#nuxt-loading>div,#nuxt-loading>div:after{border-radius:50%;width:5rem;height:5rem}#nuxt-loading>div{font-size:10px;position:relative;text-indent:-9999em;border:.5rem solid #f5f5f5;border-left:.5rem solid #000;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:nuxtLoading 1.1s infinite linear;animation:nuxtLoading 1.1s infinite linear}#nuxt-loading.error>div{border-left:.5rem solid #ff4500;animation-duration:5s}@-webkit-keyframes nuxtLoading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes nuxtLoading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}</style><script>window.addEventListener("error",function(){var e=document.getElementById("nuxt-loading");e&&(e.className+=" error")})</script><div id="nuxt-loading" aria-live="polite" role="status"><div>Loading...</div></div></div><script>window.__NUXT__={config:{},staticAssetsBase:void 0}</script>
<script src="/_nuxt/e53a321.js"></script><script src="/_nuxt/df5b311.js"></script><script src="/_nuxt/9aa6f10.js"></script><script src="/_nuxt/7184dd6.js"></script></body>
</html>
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{241:function(e,t,r){"use strict";r.r(t);var o={props:{path:String,deleteFromLocalStorage:Array},methods:{regresar:function(){if(this.deleteFromLocalStorage)for(var i=0;i<this.deleteFromLocalStorage.length;i++)localStorage.removeItem(this.deleteFromLocalStorage[i]);this.$router.push(this.path)}}},n=r(8),component=Object(n.a)(o,(function(){var e=this,t=e.$createElement;return(e._self._c||t)("b-button",{staticClass:"boton border-info my-5",attrs:{type:"is-info is-light ","icon-left":"arrow-left-box"},on:{click:function(t){return e.regresar()}}},[e._v("\n Regresar\n")])}),[],!1,null,null,null);t.default=component.exports},431:function(e,t,r){var content=r(571);"string"==typeof content&&(content=[[e.i,content,""]]),content.locals&&(e.exports=content.locals);(0,r(27).default)("37987058",content,!0,{sourceMap:!1})},570:function(e,t,r){"use strict";r(431)},571:function(e,t,r){(t=r(26)(!1)).push([e.i,".programa[data-v-242c55e7]{margin-right:20px;padding-right:20px}",""]),e.exports=t},594:function(e,t,r){"use strict";r.r(t);r(108);var o=r(44),n=r.n(o),c={components:{botonRegresar:r(241).default},data:function(){return{idResponsable:localStorage.getItem("idResponsable"),correo:localStorage.getItem("correo"),nombre:localStorage.getItem("nombre"),programas:[],selected:{},token:{headers:{token:window.localStorage.getItem("token")}}}},methods:{obtenerProgramas:function(){var e=this;return n.a.get("".concat("https://venus.acatlan.unam.mx/ss-pruebas","/programa/programas_admin?idUsuario=").concat(this.idResponsable),this.token).then((function(t){e.programas=t.data})).catch((function(t){e.error(t.response.data.message)}))},error:function(e){var t=!1;switch(e){case"invalid signature":e="Tu token no es valido, inicia sesión de nuevo.",t=!0;break;case"jwt expired":e="Tu sesión ha expirado, inicia sesión de nuevo.",t=!0;break;case"jwt malformed":e="No se encontro tu token, inicia sesión de nuevo.",t=!0;break;case"No hay token":e="Ocurrio un error al enviar tu token, inicia sesión de nuevo.",t=!0}this.$buefy.dialog.alert({title:"Error",message:e,type:"is-danger",hasIcon:!0,icon:"alert-circle",iconPack:"mdi",ariaRole:"alertdialog",ariaModal:!0}),1==t&&(localStorage.clear(),this.$router.push("/"))}},created:function(){this.obtenerProgramas()},beforeCreate:function(){localStorage.getItem("idResponsable")||this.$router.push("/admin/programa")}},l=(r(570),r(8)),component=Object(l.a)(c,(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("div",{staticClass:"container"},[r("BotonRegresar",{attrs:{path:"/admin/programa",deleteFromLocalStorage:["correo","idResponsable","nombre"]}}),e._v(" "),r("p",{staticClass:"is-size-2 mb-4"},[e._v("Información del responsable")]),e._v(" "),r("p",{staticClass:"is-size-4 mb-4"},[r("strong",[e._v("Nombre: ")]),e._v(" "+e._s(e.nombre))]),e._v(" "),r("p",{staticClass:"is-size-4 mb-4"},[r("strong",[e._v("Correo: ")]),e._v(" "+e._s(e.correo))]),e._v(" "),r("div",{staticClass:"columns"},[e._m(0),e._v(" "),r("b-select",{staticClass:"column",attrs:{placeholder:"Elija una clave: "},model:{value:e.selected,callback:function(t){e.selected=t},expression:"selected"}},e._l(e.programas,(function(t){return r("option",{key:t.id,domProps:{value:t}},[e._v("\n "+e._s(t.clavePrograma)+"\n ")])})),0)],1),e._v(" "),r("p",{staticClass:"is-size-4 mb-4"},[r("strong",[e._v("Programa: ")]),e._v(" "+e._s(e.selected.programa)+"\n ")]),e._v(" "),r("p",{staticClass:"is-size-4 mb-4"},[r("strong",[e._v("Institución: ")]),e._v(" "+e._s(e.selected.institucion)+"\n ")]),e._v(" "),r("p",{staticClass:"is-size-4 mb-4"},[r("strong",[e._v("Dependencia: ")]),e._v(" "+e._s(e.selected.dependencia)+"\n ")]),e._v(" "),r("div",{},[r("b-button",{staticClass:"boton is-info my-5",attrs:{tag:"router-link",to:"/admin/programa/infoResponsable/modificar"}},[e._v("\n Editar información\n ")])],1),e._v(" "),r("BotonRegresar",{attrs:{path:"/admin/programa",deleteFromLocalStorage:["correo","idResponsable","nombre"]}})],1)}),[function(){var e=this.$createElement,t=this._self._c||e;return t("p",{staticClass:"is-size-4 column is-narrow",staticStyle:{width:"250px"}},[t("strong",[this._v("Clave de programa: ")])])}],!1,null,"242c55e7",null);t.default=component.exports;installComponents(component,{BotonRegresar:r(241).default})}}]);
-1
View File
File diff suppressed because one or more lines are too long
-2
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-27
View File
@@ -1,27 +0,0 @@
/*!
* vue-router v3.4.9
* (c) 2020 Evan You
* @license MIT
*/
/*!
* Vue.js v2.6.12
* (c) 2014-2020 Evan You
* Released under the MIT License.
*/
/*!
* vue-client-only v2.0.0
* (c) 2019-present egoist <0x142857@gmail.com>
* Released under the MIT License.
*/
/*!
* vue-no-ssr v1.1.1
* (c) 2018-present egoist <0x142857@gmail.com>
* Released under the MIT License.
*/
//! moment.js
//! moment.js locale configuration
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{241:function(e,o,t){"use strict";t.r(o);var n={props:{path:String,deleteFromLocalStorage:Array},methods:{regresar:function(){if(this.deleteFromLocalStorage)for(var i=0;i<this.deleteFromLocalStorage.length;i++)localStorage.removeItem(this.deleteFromLocalStorage[i]);this.$router.push(this.path)}}},r=t(8),component=Object(r.a)(n,(function(){var e=this,o=e.$createElement;return(e._self._c||o)("b-button",{staticClass:"boton border-info my-5",attrs:{type:"is-info is-light ","icon-left":"arrow-left-box"},on:{click:function(o){return e.regresar()}}},[e._v("\n Regresar\n")])}),[],!1,null,null,null);o.default=component.exports},597:function(e,o,t){"use strict";t.r(o);t(16);var n=t(383),r=t.n(n),c=t(241),l=t(44),d=t.n(l),m={components:{botonRegresar:c.default},data:function(){return{idResponsable:localStorage.getItem("idResponsable"),viejo:{nombre:localStorage.getItem("nombre"),correo:localStorage.getItem("correo")},nuevo:{nombre:"",correo:""},idServicio:localStorage.getItem("idServicio"),token:{headers:{token:window.localStorage.getItem("token")}},isLoading:!1}},methods:{mostrar:function(){if(r.a.isEmail(this.nuevo.correo)||this.nuevo.nombre)return!this.nuevo.correo||!!r.a.isEmail(this.nuevo.correo)},actualizar:function(){var e=this,data={idUsuario:this.idResponsable};this.isLoading=!0,this.nuevo.correo&&(data.correo=this.nuevo.correo),this.nuevo.nombre&&(data.nombre=this.nuevo.nombre),d.a.put("".concat("https://venus.acatlan.unam.mx/ss-pruebas","/usuario/responsable/update"),data,this.token).then((function(o){e.isLoading=!1,e.toast(),e.$router.push("/admin/programa")})).catch((function(o){e.isLoading=!1,e.error(o.response.data.message)}))},passwordDialog:function(){var e=this;this.$buefy.dialog.confirm({title:"Actualizar datos",message:"¿Seguro(a) que quiere actualizar la contraseña?",confirmText:"Confirmar",cancelText:"Cancelar",type:"is-success",hasIcon:!0,onConfirm:function(){return e.password()}})},password:function(){var e=this;this.isLoading=!0;var data={idUsuario:this.idResponsable};d.a.put("".concat("https://venus.acatlan.unam.mx/ss-pruebas","/usuario/new_password_responsable"),data,this.token).then((function(o){e.$buefy.toast.open({message:"Se ha enviado el correo con la nueva contraseña",type:"is-success"}),e.$router.push("/admin")})).catch((function(o){e.error(o.response.data.message)})).finally((function(){e.isLoading=!1}))},toast:function(){this.$buefy.toast.open({message:"Se han actualizado los datos del responsable",type:"is-success"})},error:function(e){var o=!1;switch(e){case"invalid signature":e="Tu token no es valido, inicia sesión de nuevo.",o=!0;break;case"jwt expired":e="Tu sesión ha expirado, inicia sesión de nuevo.",o=!0;break;case"jwt malformed":e="No se encontro tu token, inicia sesión de nuevo.",o=!0;break;case"No hay token":e="Ocurrio un error al enviar tu token, inicia sesión de nuevo.",o=!0}this.$buefy.dialog.alert({title:"Error",message:e,type:"is-danger",hasIcon:!0,icon:"alert-circle",iconPack:"mdi",ariaRole:"alertdialog",ariaModal:!0}),1==o&&(localStorage.clear(),this.$router.push("/"))}},beforeCreate:function(){localStorage.getItem("idResponsable")||this.$router.push("/admin/programa")}},h=t(8),component=Object(h.a)(m,(function(){var e=this,o=e.$createElement,t=e._self._c||o;return t("div",{staticClass:"container",staticStyle:{"margin-bottom":"10%","margin-top":"2%"}},[t("BotonRegresar",{attrs:{path:"/admin/programa/infoResponsable"}}),e._v(" "),t("p",{staticClass:"is-size-2"},[e._v("Editar información del responsable")]),e._v(" "),t("b-field",{attrs:{label:"Nombre"}},[t("b-input",{attrs:{type:"text",placeholder:e.viejo.nombre},model:{value:e.nuevo.nombre,callback:function(o){e.$set(e.nuevo,"nombre",o)},expression:"nuevo.nombre"}})],1),e._v(" "),t("b-field",{attrs:{label:"Correo eletrónico"}},[t("b-input",{attrs:{type:"email",placeholder:e.viejo.correo},model:{value:e.nuevo.correo,callback:function(o){e.$set(e.nuevo,"correo",o)},expression:"nuevo.correo"}})],1),e._v(" "),e.mostrar()?t("b-button",{staticClass:"boton is-info my-5",on:{click:function(o){return e.actualizar()}}},[e._v("\n Editar responsable\n ")]):t("b-button",{staticClass:"boton is-info my-5",attrs:{disabled:""}},[e._v("\n Editar responsable\n ")]),e._v(" "),t("b-button",{staticClass:"is-info my-5",on:{click:function(o){return e.passwordDialog()}}},[e._v("\n Cambiar contraseña\n ")]),e._v(" "),t("b-loading",{attrs:{"is-full-page":!0,"can-cancel":!1},model:{value:e.isLoading,callback:function(o){e.isLoading=o},expression:"isLoading"}})],1)}),[],!1,null,null,null);o.default=component.exports;installComponents(component,{BotonRegresar:t(241).default})}}]);
-1
View File
@@ -1 +0,0 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{389:function(e,t,o){var content=o(397);"string"==typeof content&&(content=[[e.i,content,""]]),content.locals&&(e.exports=content.locals);(0,o(27).default)("661b075c",content,!0,{sourceMap:!1})},396:function(e,t,o){"use strict";o(389)},397:function(e,t,o){(t=o(26)(!1)).push([e.i,".centro{text-align:center}.footter{margin-bottom:10rem}",""]),e.exports=t},400:function(e,t,o){"use strict";o(16);var n=o(44),r=o.n(n),c={data:function(){return{isFullPage:!0,file:[],idServicio:"",cartaTermino:"",isLoading:!1,token:{headers:{token:window.localStorage.getItem("token")}}}},methods:{"validarTamaño":function(){this.file.size>2e7&&(this.toast(),this.file="")},toast:function(){this.$buefy.toast.open({message:"El archivo excede el tamaño permitido",type:"is-danger"})},Enviar:function(){var e=this,data={idServicio:this.idServicio},t=new FormData;t.append("data",JSON.stringify(data)),t.append("cartaTermino",this.file),this.isLoading=!0,r.a.put("".concat("https://venus.acatlan.unam.mx/ss-pruebas","/servicio/carta_termino"),t,{headers:{"Content-Type":"multipart/form-data",token:this.token.headers.token}}).then((function(t){e.$buefy.dialog.alert({title:"Success",message:"Se enviaron los datos correctamente",type:"is-success",hasIcon:!0,icon:"checkbox-marked-circle",iconPack:"mdi",ariaRole:"alertdialog",ariaModal:!0})})).catch((function(t){e.error(t.response.data.message)})).finally((function(){e.isLoading=!1,localStorage.removeItem("idServicio"),localStorage.removeItem("cartaTermino"),e.$router.push("/responsable")}))},getIdLocal:function(){this.idServicio=localStorage.getItem("idServicio"),this.cartaTermino=localStorage.getItem("cartaTermino"),null!==this.idServicio&&null!==this.cartaTermino||this.$router.push("/responsable")},error:function(e){var t=!1;switch(e){case"invalid signature":e="Tu token no es valido, inicia sesión de nuevo.",t=!0;break;case"jwt expired":e="Tu sesión ha expirado, inicia sesión de nuevo.",t=!0;break;case"jwt malformed":e="No se encontro tu token, inicia sesión de nuevo.",t=!0;break;case"No hay token":e="Ocurrio un error al enviar tu token, inicia sesión de nuevo.",t=!0}this.$buefy.dialog.alert({title:"Error",message:e,type:"is-danger",hasIcon:!0,icon:"alert-circle",iconPack:"mdi",ariaRole:"alertdialog",ariaModal:!0}),1==t&&(localStorage.clear(),this.$router.push("/"))}},watch:{file:function(e,t){this.validarTamaño()}},created:function(){this.getIdLocal()}},l=(o(396),o(8)),component=Object(l.a)(c,(function(){var e=this,t=e.$createElement,o=e._self._c||t;return null!=e.idServicio&&null!=e.cartaTermino?o("div",{staticClass:"container footter"},[o("b-button",{staticClass:"border-info mt-5",attrs:{type:"is-info is-light","icon-left":"arrow-left-box",tag:"router-link",to:"/responsable"}},[e._v("Regresar")]),e._v(" "),o("h3",{staticClass:"title is-4 mt-4"},[e._v("\n Carta de termino (en formato .PDF. No se aceptan fotos).\n ")]),e._v(" "),o("b-field",[o("b-upload",{attrs:{"drag-drop":"",type:"is-black",expanded:"",accept:"application/pdf"},model:{value:e.file,callback:function(t){e.file=t},expression:"file"}},[o("section",{staticClass:"section"},[o("div",{staticClass:"content has-text-centered"},[o("p",[o("b-icon",{attrs:{icon:"upload",size:"is-large"}})],1),e._v(" "),o("p",[e._v("\n "+e._s(e.file.name||"Arrastra aquí tu archivo o da click para buscar")+"\n ")]),e._v(" "),o("p",[e._v("Tamaño máximo para el archivo: 20MB")])])])])],1),e._v(" "),o("b-field",{staticClass:"centro"},[o("b-button",{staticClass:"border-success my-5 is-medium",attrs:{disabled:""==e.file,type:"is-success"},on:{click:function(t){return e.Enviar()}}},[e._v("\n Enviar\n ")])],1),e._v(" "),o("b-loading",{attrs:{"is-full-page":!0,"can-cancel":!0},model:{value:e.isLoading,callback:function(t){e.isLoading=t},expression:"isLoading"}})],1):e._e()}),[],!1,null,null,null);t.a=component.exports},591:function(e,t,o){"use strict";o.r(t);var n={components:{cartaTermino:o(400).a}},r=o(8),component=Object(r.a)(n,(function(){var e=this.$createElement,t=this._self._c||e;return t("section",[t("cartaTermino")],1)}),[],!1,null,null,null);t.default=component.exports}}]);

Some files were not shown because too many files have changed in this diff Show More