48 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 ac8c088416 listo 2021-09-28 18:40:12 -05:00
62 changed files with 14821 additions and 6912 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"
]
}
+3
View File
@@ -1,3 +1,6 @@
#.devcontainer
# Created by .ignore support plugin (hsz.mobi) # Created by .ignore support plugin (hsz.mobi)
### Node template ### Node template
# Logs # Logs
+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"]
+18 -34
View File
@@ -22,7 +22,6 @@
centered centered
> >
<span>{{ fecha(props.row.createdAt) }}</span> <span>{{ fecha(props.row.createdAt) }}</span>
<!-- <span>{{ props.row }}</span> -->
</b-table-column> </b-table-column>
<b-table-column <b-table-column
@@ -73,7 +72,7 @@
Carta Aceptación Rechazada Carta Aceptación Rechazada
</b-button> </b-button>
<span :class="types(props.row.Status.idStatus)" v-else> <span class="tag" :class="types(props.row.Status.idStatus)" v-else>
{{ props.row.Status.status }} {{ props.row.Status.status }}
</span> </span>
</b-table-column> </b-table-column>
@@ -126,7 +125,7 @@
<b-icon <b-icon
class="tag is-success" class="tag is-success"
icon="check" icon="check"
v-if="props.row.idCuestionarioPrograma" v-if="props.row.idCuestionarioPrograma || props.row.idCuestionarioPrograma2"
/> />
<b-button <b-button
@@ -205,63 +204,48 @@ export default {
}, },
methods: { methods: {
fecha(date) { fecha(date) {
const fecha = moment(date) if (date) {
const fecha = moment(date)
if (date) return `${fecha.date()}/${fecha.month() + 1}/${fecha.year()}` return `${fecha.date() < 10 ? '0' + fecha.date() : fecha.date()}/${
fecha.month() < 9 ? '0' + (fecha.month() + 1) : fecha.month() + 1
}/${fecha.year()}`
}
return '' return ''
}, },
types(idStatus) { types(idStatus) {
let style = 'tag'
switch (idStatus) { switch (idStatus) {
case 1: case 1:
style += ' is-dark' return 'is-dark'
break
case 2: case 2:
style += ' is-info' return 'is-info'
break
case 3: case 3:
style += ' is-warning' return 'is-warning'
break
case 4: case 4:
style += ' is-link' return 'is-link'
break
case 5: case 5:
style += ' is-success' return 'is-success'
break
case 6: case 6:
style += ' is-success is-light' return 'is-success is-light'
break
case 7: case 7:
case 8: case 8:
case 9: case 9:
case 10: case 10:
style += ' is-danger' return 'is-danger'
break
case 11: case 11:
style += ' is-link is-light' return 'is-link is-light'
break
case 12: case 12:
style += ' is-info is-light' return 'is-info is-light'
break
case 13: case 13:
case 14: case 14:
style += ' is-success is-light' return 'is-success is-light'
break
} }
return style
}, },
addPointer() { addPointer() {
return this.idTipoUsuario === 1 ? 'pointer' : '' return this.idTipoUsuario === 1 ? 'pointer' : ''
}, },
responsableUpdate(servicio, path) { responsableUpdate(servicio, path) {
/*pendiente*/
localStorage.setItem('idServicio', servicio.idServicio) localStorage.setItem('idServicio', servicio.idServicio)
localStorage.setItem(
// 'idCuestionarioPrograma',
'cuestionario',
servicio.idCuestionarioPrograma
)
this.$router.push(`/responsable/${path}`) this.$router.push(`/responsable/${path}`)
}, },
}, },
+10 -10
View File
@@ -34,9 +34,9 @@
<b-input maxlength="500" type="textarea" v-model="mensajeRechazo" /> <b-input maxlength="500" type="textarea" v-model="mensajeRechazo" />
</b-field> </b-field>
<div> <b-field>
<b-button <b-button
class="is-link" type="is-link"
:disabled="!mensajeRechazo" :disabled="!mensajeRechazo"
@click=" @click="
imprimirWarning( imprimirWarning(
@@ -45,9 +45,9 @@
) )
" "
> >
Rechazar documento Rechazar {{ title }}
</b-button> </b-button>
</div> </b-field>
</div> </div>
</div> </div>
</template> </template>
@@ -56,12 +56,6 @@
import axios from 'axios' import axios from 'axios'
export default { export default {
data() {
return {
rechazar: false,
mensajeRechazo: '',
}
},
props: { props: {
title: { type: String, required: true }, title: { type: String, required: true },
admin: { type: Object, required: true }, admin: { type: Object, required: true },
@@ -71,6 +65,12 @@ export default {
imprimirWarning: { type: Function, required: true }, imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true }, updateIsLoading: { type: Function, required: true },
}, },
data() {
return {
rechazar: false,
mensajeRechazo: '',
}
},
methods: { methods: {
updateRechazar() { updateRechazar() {
if (this.rechazar) this.mensajeRechazo = '' if (this.rechazar) this.mensajeRechazo = ''
+13 -13
View File
@@ -1,8 +1,8 @@
<template> <template>
<div class="my-5"> <div class="mt-5">
<div> <b-field>
<b-button <b-button
class="is-danger" type="is-danger"
:disabled=" :disabled="
alumno.Status.idStatus === 6 || alumno.Status.idStatus === 10 alumno.Status.idStatus === 6 || alumno.Status.idStatus === 10
" "
@@ -10,16 +10,16 @@
> >
Cancelar Cancelar
</b-button> </b-button>
</div> </b-field>
<div class="mt-2" v-if="cancelar"> <div class="mt-2" v-if="cancelar">
<b-field label="Razón de la cancelación:"> <b-field label="Razón de la cancelación:">
<b-input maxlength="500" type="textarea" v-model="mensajeCancelar" /> <b-input maxlength="500" type="textarea" v-model="mensajeCancelar" />
</b-field> </b-field>
<div> <b-field>
<b-button <b-button
class="is-link" type="is-link"
:disabled="!mensajeCancelar" :disabled="!mensajeCancelar"
@click=" @click="
imprimirWarning( imprimirWarning(
@@ -30,7 +30,7 @@
> >
Cancelar servicio Cancelar servicio
</b-button> </b-button>
</div> </b-field>
</div> </div>
</div> </div>
</template> </template>
@@ -39,12 +39,6 @@
import axios from 'axios' import axios from 'axios'
export default { export default {
data() {
return {
cancelar: false,
mensajeCancelar: '',
}
},
props: { props: {
idServicio: { type: Number, required: true }, idServicio: { type: Number, required: true },
admin: { type: Object, required: true }, admin: { type: Object, required: true },
@@ -54,6 +48,12 @@ export default {
imprimirWarning: { type: Function, required: true }, imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true }, updateIsLoading: { type: Function, required: true },
}, },
data() {
return {
cancelar: false,
mensajeCancelar: '',
}
},
methods: { methods: {
updateCancelar() { updateCancelar() {
if (this.cancelar) this.mensajeCancelar = '' if (this.cancelar) this.mensajeCancelar = ''
+7 -7
View File
@@ -23,7 +23,7 @@
<p class="is-size-7"> <p class="is-size-7">
Si al momento de elegir un archivo este no se selecciona, haga click Si al momento de elegir un archivo este no se selecciona, haga click
en cancelar en la ventana emergente y trate de nuevo. en cancelar en la ventana emergente e intente de nuevo.
</p> </p>
</div> </div>
</b-upload> </b-upload>
@@ -54,12 +54,6 @@
import axios from 'axios' import axios from 'axios'
export default { export default {
data() {
return {
csv: {},
link: `${process.env.api}/plantilla.csv`,
}
},
props: { props: {
admin: { type: Object, required: true }, admin: { type: Object, required: true },
imprimirError: { type: Function, required: true }, imprimirError: { type: Function, required: true },
@@ -67,6 +61,12 @@ export default {
imprimirWarning: { type: Function, required: true }, imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true }, updateIsLoading: { type: Function, required: true },
}, },
data() {
return {
link: `${process.env.api}/plantilla.csv`,
csv: {},
}
},
methods: { methods: {
validarExt() { validarExt() {
const extPermitidas = /(.csv)$/i const extPermitidas = /(.csv)$/i
+4 -4
View File
@@ -7,7 +7,7 @@
</b-field> </b-field>
<b-field <b-field
class="my-5" class="mt-5"
v-if="alumno.Status.idStatus === 1 || alumno.Status.idStatus === 5" v-if="alumno.Status.idStatus === 1 || alumno.Status.idStatus === 5"
> >
<b-button <b-button
@@ -34,9 +34,6 @@
import axios from 'axios' import axios from 'axios'
export default { export default {
data() {
return { vistoBuenoAcatlan: false }
},
props: { props: {
idServicio: { type: Number, required: true }, idServicio: { type: Number, required: true },
admin: { type: Object, required: true }, admin: { type: Object, required: true },
@@ -46,6 +43,9 @@ export default {
imprimirWarning: { type: Function, required: true }, imprimirWarning: { type: Function, required: true },
updateIsLoading: { type: Function, required: true }, updateIsLoading: { type: Function, required: true },
}, },
data() {
return { vistoBuenoAcatlan: false }
},
methods: { methods: {
confirmarServicio() { confirmarServicio() {
if (this.alumno.Status.idStatus === 1) if (this.alumno.Status.idStatus === 1)
+34 -11
View File
@@ -14,6 +14,20 @@
</b-select> </b-select>
</b-field> </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-field label="Año:">
<b-select v-model="selectedYear" expanded> <b-select v-model="selectedYear" expanded>
<option value="" disabled>Seleccione un año:</option> <option value="" disabled>Seleccione un año:</option>
@@ -24,7 +38,7 @@
</b-select> </b-select>
</b-field> </b-field>
<div class="pb-5 pt-3"> <b-field class="pb-5 pt-3">
<b-button <b-button
type="is-info" type="is-info"
@click="descargar()" @click="descargar()"
@@ -32,7 +46,7 @@
> >
Descargar Excel Descargar Excel
</b-button> </b-button>
</div> </b-field>
</div> </div>
</template> </template>
@@ -41,33 +55,42 @@ import axios from 'axios'
import fileDownload from 'js-file-download' import fileDownload from 'js-file-download'
export default { export default {
data() {
return {
selectedCuestionario: '',
selectedYear: '',
}
},
props: { props: {
years: { type: Array, required: true }, years: { type: Array, required: true },
admin: { type: Object, required: true }, admin: { type: Object, required: true },
imprimirError: { type: Function, required: true }, imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true }, updateIsLoading: { type: Function, required: true },
}, },
data() {
return {
selectedCuestionario: '',
selectedYear: '',
version:''
}
},
methods: { methods: {
descargar() { descargar() {
this.updateIsLoading(true) this.updateIsLoading(true)
axios axios
.get( .get(
`${process.env.api}/${this.selectedCuestionario}?year=${this.selectedYear}`, `${process.env.api}/${this.selectedCuestionario}`, {
this.admin.token params: {
year: this.selectedYear,
version: this.version,
},
headers: {
Authorization: `Bearer ${this.admin.token}`,
},
}
) )
.then((res) => { .then((res) => {
fileDownload( fileDownload(
res.data, res.data,
`${this.selectedYear}_${this.selectedCuestionario}.csv` `${this.selectedYear}_${this.selectedCuestionario}_${this.version}.csv`
) )
this.selectedYear = '' this.selectedYear = ''
this.selectedCuestionario = '' this.selectedCuestionario = ''
this.version = ''
this.updateIsLoading(false) this.updateIsLoading(false)
}) })
.catch((err) => { .catch((err) => {
+17 -15
View File
@@ -12,8 +12,9 @@
<b-field label="Teléfono"> <b-field label="Teléfono">
<b-input <b-input
type="number" type="tel"
maxlength="10" maxlength="10"
:has-counter="false"
:placeholder="viejo.telefono" :placeholder="viejo.telefono"
v-model="nuevo.telefono" v-model="nuevo.telefono"
/> />
@@ -79,18 +80,20 @@
/> />
</b-field> </b-field>
<b-button <b-field class="mt-5">
class="my-5 is-success" <b-button
@click=" type="is-success"
imprimirWarning( :disabled="!mostrarBoton()"
'¿Estás segura(a) de querer actualizar estos datos?', @click="
actualizar imprimirWarning(
) '¿Estás segura(a) de querer actualizar estos datos?',
" actualizar
:disabled="!mostrarBoton()" )
> "
Actualizar Datos >
</b-button> Actualizar Datos
</b-button>
</b-field>
</div> </div>
</template> </template>
@@ -111,8 +114,7 @@ export default {
}, },
data() { data() {
return { return {
isLoading: false, minDate1: new Date('2020-01-02'),
minDate1: new Date('2020-01-01'),
nuevo: {}, nuevo: {},
} }
}, },
+260 -350
View File
@@ -1,159 +1,156 @@
<template> <template>
<div class="container" :class="{ pad: padding }"> <div>
<BotonRegresar path="/admin/servicio" /> <h3 class="title">Editar información del alumno</h3>
<p class="is-size-2">Editar información del alumno</p> <div>
<b-field label="Correo eletrónico del alumno">
<b-input type="email" :placeholder="servicio.correo" v-model="correo" />
</b-field>
<div class="formulario"> <b-field label="Fecha de inicio">
<b-field label="Correo eletrónico alumno"> <b-datepicker
<b-input icon="calendar-today"
type="email" :min-date="minDate1"
v-model="nuevo.correo" v-model="fechaInicio"
:placeholder="viejo.correo"
/> />
</b-field> </b-field>
<div v-if="status6()"> <b-field label="Fecha de fin">
<b-field label="Fecha de inicio"> <b-datepicker
<b-datepicker icon="calendar-today"
:placeholder="fecha(viejo.fechaInicio)" :min-date="minDate2"
icon="calendar-today" v-model="fechaFin"
v-model="fechaInicio[0]" />
:min-date="minDate1" </b-field>
/>
</b-field>
<transition name="fade"> <b-field label="Dirección" v-if="servicio.direccion">
<b-field label="Fecha de fin" v-if="fechaInicio[0]"> <b-input
<b-datepicker type="text"
:placeholder="fecha(viejo.fechaInicio)" :placeholder="servicio.direccion"
v-model="fechaFin[0]" v-model="direccion"
:min-date="minDate2" />
icon="calendar-today" </b-field>
/>
</b-field>
</transition>
<b-field label="Dirección"> <b-field label="Teléfono" v-if="servicio.telefono">
<b-input <b-input
type="text" type="tel"
v-model="nuevo.direccion" maxlength="10"
:placeholder="viejo.direccion" :has-counter="false"
/> :placeholder="servicio.telefono"
</b-field> v-model="telefono"
/>
</b-field>
<b-field label="Teléfono"> <b-field label="Fecha de nacimiento" v-if="servicio.fechaNacimiento">
<b-input <b-datepicker
type="number" icon="calendar-today"
:placeholder="viejo.telefono" :placeholder="fecha(servicio.fechaNacimiento)"
v-model="nuevo.telefono" :max-date="new Date()"
maxlength="10" v-model="fechaNacimiento"
/> />
</b-field> </b-field>
<b-field label="Fecha de nacimiento"> <b-field label="Carta de aceptación">
<b-datepicker <b-upload
:placeholder="fecha(viejo.fechaNacimiento)" accept="application/pdf"
v-model="fechaNacimiento[0]" v-model="cartaAceptacion"
icon="calendar-today" drag-drop
/> expanded
</b-field> >
<div class="section has-text-centered">
<b-icon icon="upload" size="is-large" class="mb-2" />
<p class="is-size-5" v-if="viejo.cartaAceptacion"> <p class="is-size-5">
Carta de aceptación {{
</p> cartaAceptacion.name ||
'Arrastra aquí tu archivo o da click aquí para buscarlo.'
}}
</p>
<b-field v-if="viejo.cartaAceptacion"> <p class="is-size-6">Tamaño máximo 20MB</p>
<b-upload </div>
v-model="nuevo.cartaAceptacion" </b-upload>
type="is-black" </b-field>
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> <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" />
<b-field v-if="viejo.cartaTermino"> <p class="is-size-5">
<b-upload {{
v-model="nuevo.cartaTermino" cartaTermino.name ||
type="is-black" 'Arrastra aquí tu archivo o da click aquí para buscarlo.'
v-on:input="validarExt(2)" }}
accept="application/pdf" </p>
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> <p class="is-size-6">Tamaño máximo 20MB</p>
</div>
</b-upload>
</b-field>
<b-field v-if="viejo.informeGlobal"> <b-field
<b-upload label="Informe global"
v-model="nuevo.informeGlobal" v-if="servicio.Status.idStatus > 4 && servicio.Status.idStatus != 7"
type="is-black" >
v-on:input="validarExt(3)" <b-upload
accept="application/pdf" accept="application/pdf"
drag-drop v-model="informeGlobal"
expanded drag-drop
> expanded
<section class="section"> >
<div class="content has-text-centered"> <div class="section has-text-centered">
<p> <b-icon icon="upload" size="is-large" class="mb-2" />
<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>
<b-button v-if="mostrar()" @click="actualizarDialog()" class="is-info"> <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 Actualizar Datos
</b-button> </b-button>
<b-button v-else disabled class="is-info">Actualizar Datos</b-button> <b-button
class="is-info"
<b-button @click="passwordDialog()" class="is-info"> @click="
Cambiar contraseña 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> </b-button>
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</div> </div>
</div> </div>
</template> </template>
@@ -162,39 +159,36 @@
import axios from 'axios' import axios from 'axios'
import moment from 'moment' import moment from 'moment'
import validator from 'validator' import validator from 'validator'
import botonRegresar from '../botonRegresar'
export default { export default {
components: { props: {
botonRegresar, 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() { data() {
return { return {
idServicio: localStorage.getItem('idServicio'), actualizarFechaFin: false,
idStatus: Number(localStorage.getItem('idStatus')), idServicio: null,
viejo: {}, correo: '',
nuevo: { telefono: '',
correo: '', direccion: '',
fechaInicioFinal: '', fechaFin: new Date(),
fechaFinFinal: null, fechaInicio: new Date(),
direccion: null, fechaNacimiento: new Date(),
telefono: null, cartaAceptacion: {},
fechaNacimientoFinal: null, cartaTermino: {},
cartaAceptacion: {}, informeGlobal: {},
cartaTermino: {},
informeGlobal: {},
},
fechaNacimiento: [],
fechaInicio: [],
fechaFin: [],
token: {
headers: {
token: localStorage.getItem('token'),
},
},
minDate1: new Date('2020-01-01'), minDate1: new Date('2020-01-01'),
isLoading: false, minDate2: new Date(),
padding: false, servicio: {
Status: {},
fechaFin: new Date(),
fechaInicio: new Date(),
fechaNacimiento: new Date(),
},
} }
}, },
methods: { methods: {
@@ -208,236 +202,152 @@ export default {
} }
return '' return ''
}, },
status6() { mostrar() {
if (this.idStatus === 6) { if (
this.padding = true 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 false
} }
return true 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() { obtenerRegistro() {
this.isLoading = true this.updateIsLoading(true)
return axios axios
.get( .get(
`${process.env.api}/servicio/admin?idServicio=${this.idServicio}`, `${process.env.api}/servicio/admin?idServicio=${this.idServicio}`,
this.token this.admin.token
) )
.then((res) => { .then((res) => {
this.viejo = res.data 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) => { .catch((err) => {
this.error(err.response.data.message) this.updateIsLoading(false)
this.imprimirError(err.response.data)
}) })
.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() { actualizar() {
const formData = new FormData() const formData = new FormData()
const data = { idServicio: this.idServicio } const data = { idServicio: this.idServicio }
this.isLoading = true this.updateIsLoading(true)
if (this.nuevo.direccion) data.direccion = this.nuevo.direccion if (this.cartaAceptacion)
if (this.nuevo.correo) data.correo = this.nuevo.correo formData.append('cartaAceptacion', this.cartaAceptacion)
if (this.nuevo.telefono) data.telefono = this.nuevo.telefono if (this.cartaTermino) formData.append('cartaTermino', this.cartaTermino)
if (this.nuevo.fechaInicioFinal) if (this.informeGlobal)
data.fechaInicio = this.nuevo.fechaInicioFinal formData.append('informeGlobal', this.informeGlobal)
if (this.nuevo.fechaFinFinal) data.fechaFin = this.nuevo.fechaFinFinal if (this.direccion) data.direccion = this.direccion
if (this.nuevo.fechaNacimientoFinal) if (this.correo) data.correo = this.correo
data.fechaNacimiento = this.nuevo.fechaNacimientoFinal 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)) 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 axios
.put(`${process.env.api}/servicio/update`, formData, { .put(
headers: { `${process.env.api}/servicio/update`,
'Content-Type': 'multipart/form-data', formData,
token: this.token.headers.token, this.admin.tokenArchivo
}, )
})
.then((res) => { .then((res) => {
this.toast() this.imprimirMensaje(res.data.message)
this.updateIsLoading(false)
this.$router.push('/admin/servicio') this.$router.push('/admin/servicio')
}) })
.catch((err) => { .catch((err) => {
this.error(err.response.data.message) this.updateIsLoading(false)
this.imprimirError(err.response.data)
}) })
.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() { password() {
this.isLoading = true
const data = { idServicio: this.idServicio } const data = { idServicio: this.idServicio }
this.updateIsLoading(true)
axios axios
.put(`${process.env.api}/usuario/new_password_alumno`, data, this.token) .put(
`${process.env.api}/usuario/new_password_alumno`,
data,
this.admin.token
)
.then((res) => { .then((res) => {
this.$buefy.toast.open({ this.imprimirMensaje(res.data.message)
message: 'Se ha enviado el correo con la nueva contraseña', this.updateIsLoading(false)
type: 'is-success',
})
this.$router.push('/admin') this.$router.push('/admin')
}) })
.catch((err) => { .catch((err) => {
this.error(err.response.data.message) this.updateIsLoading(false)
this.imprimirError(err.response.data)
}) })
.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',
ariaRole: 'alertdialog',
ariaModal: true,
})
if (salir == true) {
localStorage.clear()
this.$router.push(`/`)
}
},
},
computed: {
minDate2() {
const min = new Date(this.fechaInicio)
return new Date(min.getFullYear(), min.getMonth() + 6, min.getDate())
}, },
}, },
watch: { watch: {
fechaInicio: function () { fechaInicio() {
this.nuevo.fechaInicioFinal = moment(this.fechaInicio[0]) this.updateFechas()
this.fechaFin[0] = null
}, },
fechaFin: function () { cartaAceptacion() {
this.nuevo.fechaFinFinal = moment(this.fechaFin[0]) if (!this.sizeFileValido(this.cartaAceptacion)) this.cartaAceptacion = {}
}, },
fechaNacimiento: function () { cartaTermino() {
this.nuevo.fechaNacimientoFinal = moment(this.fechaNacimiento[0]) if (!this.sizeFileValido(this.cartaTermino)) this.cartaAceptacion = {}
},
informeGlobal() {
if (!this.sizeFileValido(this.informeGlobal)) this.informeGlobal = {}
}, },
}, },
created() { created() {
this.obtenerRegistro() this.idServicio = Number(localStorage.getItem('idServicio'))
if (!this.idServicio) this.$router.push('/admin')
else this.obtenerRegistro()
}, },
} }
</script> </script>
<style scoped> <style scoped></style>
.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>
+7 -7
View File
@@ -12,7 +12,7 @@
</b-select> </b-select>
</b-field> </b-field>
<div class="pb-5 pt-3"> <b-field class="pb-5 pt-3">
<b-button <b-button
type="is-info" type="is-info"
@click="descargar()" @click="descargar()"
@@ -20,7 +20,7 @@
> >
Descargar Excel Descargar Excel
</b-button> </b-button>
</div> </b-field>
</div> </div>
</template> </template>
@@ -29,17 +29,17 @@ import axios from 'axios'
import fileDownload from 'js-file-download' import fileDownload from 'js-file-download'
export default { export default {
data() {
return {
selectedYearGustavoBaz: '',
}
},
props: { props: {
years: { type: Array, required: true }, years: { type: Array, required: true },
admin: { type: Object, required: true }, admin: { type: Object, required: true },
imprimirError: { type: Function, required: true }, imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true }, updateIsLoading: { type: Function, required: true },
}, },
data() {
return {
selectedYearGustavoBaz: '',
}
},
methods: { methods: {
descargar() { descargar() {
this.updateIsLoading(true) this.updateIsLoading(true)
+14 -6
View File
@@ -44,7 +44,15 @@
</p> </p>
</b-field> </b-field>
<b-field class="my-5"> <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 <b-button
type="is-link" type="is-link"
tag="router-link" tag="router-link"
@@ -60,6 +68,11 @@
import axios from 'axios' import axios from 'axios'
export default { export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() { data() {
return { return {
idResponsable: null, idResponsable: null,
@@ -68,11 +81,6 @@ export default {
responsable: {}, responsable: {},
} }
}, },
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
methods: { methods: {
obtenerResponsable() { obtenerResponsable() {
this.updateIsLoading(true) this.updateIsLoading(true)
+11 -8
View File
@@ -1,5 +1,5 @@
<template> <template>
<section class="mb-5"> <div class="mb-5">
<div class="mb-5"> <div class="mb-5">
<h4 class="is-size-4 pb-2">Datos del programa</h4> <h4 class="is-size-4 pb-2">Datos del programa</h4>
@@ -19,11 +19,15 @@
<p class="input">{{ alumno.Programa.clavePrograma }}</p> <p class="input">{{ alumno.Programa.clavePrograma }}</p>
</b-field> </b-field>
<b-field label="Programa de Acatlan:"> <b-field label="Responsable:">
<p class="input"> <p class="input">
<span> {{ alumno.Programa.Usuario.nombre }}
{{ alumno.Programa.acatlan ? 'Si' : 'No' }} </p>
</span> </b-field>
<b-field label="Correo:">
<p class="input">
{{ alumno.Programa.Usuario.usuario }}
</p> </p>
</b-field> </b-field>
</div> </div>
@@ -93,7 +97,7 @@
<b-field> <b-field>
<b-button <b-button
class="boton is-info" type="is-info"
@click="editar()" @click="editar()"
:disabled=" :disabled="
alumno.Status.idStatus === 6 || alumno.Status.idStatus === 10 alumno.Status.idStatus === 6 || alumno.Status.idStatus === 10
@@ -102,7 +106,7 @@
Editar información Editar información
</b-button> </b-button>
</b-field> </b-field>
</section> </div>
</template> </template>
<script> <script>
@@ -124,7 +128,6 @@ export default {
return '' return ''
}, },
editar() { editar() {
localStorage.setItem('idStatus', this.alumno.Status.idStatus)
this.$router.push('/admin/servicio/editar') this.$router.push('/admin/servicio/editar')
}, },
}, },
+6 -4
View File
@@ -2,10 +2,12 @@
<div class="mt-6"> <div class="mt-6">
<h3 class="title">Reasignación de programas</h3> <h3 class="title">Reasignación de programas</h3>
<p class="is-size-6 mb-4"> <div class="is-size-6 mb-4">
A continuación inserte el usaurio que desea eliminiar, los programas que <p>
este usuario tenga seran asignados a este: {{ responsable.usuario }} A continuación inserte el usaurio que desea eliminiar, los programas que
</p> este usuario tenga seran asignados a: {{ responsable.usuario }}
</p>
</div>
<b-field label="Usuario/Correo electrónico"> <b-field label="Usuario/Correo electrónico">
<b-input <b-input
+7 -7
View File
@@ -24,11 +24,11 @@
/> />
</b-field> </b-field>
<div class="pb-5 pt-3"> <b-field class="pb-5 pt-3">
<b-button type="is-info" @click="descargar()" :disabled="validarFechas()"> <b-button type="is-info" @click="descargar()" :disabled="validarFechas()">
Descargar Excel Descargar Excel
</b-button> </b-button>
</div> </b-field>
</div> </div>
</template> </template>
@@ -38,6 +38,11 @@ import moment from 'moment'
import fileDownload from 'js-file-download' import fileDownload from 'js-file-download'
export default { export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
data() { data() {
return { return {
selectedFin: [], selectedFin: [],
@@ -46,11 +51,6 @@ export default {
minDate: new Date('January 1, 2020'), minDate: new Date('January 1, 2020'),
} }
}, },
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
updateIsLoading: { type: Function, required: true },
},
methods: { methods: {
validarFechas() { validarFechas() {
const fechaInicio = moment(new Date(this.selectedInicio)) const fechaInicio = moment(new Date(this.selectedInicio))
@@ -73,6 +73,10 @@ import TablaServiciosSociales from '@/components/TablaServiciosSociales'
export default { export default {
components: { TablaServiciosSociales }, components: { TablaServiciosSociales },
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
data() { data() {
return { return {
isLoading: false, isLoading: false,
@@ -86,10 +90,6 @@ export default {
searchAnterior: {}, searchAnterior: {},
} }
}, },
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
methods: { methods: {
onPageChange(page) { onPageChange(page) {
this.page = page this.page = page
+7 -10
View File
@@ -65,7 +65,7 @@
</b-table-column> </b-table-column>
<b-table-column field="estado" label="Estado" v-slot="props" centered> <b-table-column field="estado" label="Estado" v-slot="props" centered>
<span :class="style(props.row.activo)"> <span class="tag" :class="style(props.row.activo)">
{{ props.row.activo ? 'Activo' : 'Desactivado' }} {{ props.row.activo ? 'Activo' : 'Desactivado' }}
</span> </span>
</b-table-column> </b-table-column>
@@ -77,6 +77,10 @@
import axios from 'axios' import axios from 'axios'
export default { export default {
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
data() { data() {
return { return {
isLoading: false, isLoading: false,
@@ -89,17 +93,10 @@ export default {
searchAnterior: {}, searchAnterior: {},
} }
}, },
props: {
admin: { type: Object, required: true },
imprimirError: { type: Function, required: true },
},
methods: { methods: {
style(activo) { style(activo) {
let style = 'tag' if (activo) return 'is-success'
else return 'is-danger'
if (activo) style += ' is-success'
else style += ' is-danger'
return style
}, },
onPageChange(page) { onPageChange(page) {
this.page = page this.page = page
+2 -4
View File
@@ -41,11 +41,11 @@
</b-select> </b-select>
</b-field> </b-field>
<div class="column is-align-self-center"> <b-field class="column is-align-self-center">
<b-button type="is-info" @click="obtenerServicios()" expanded rounded> <b-button type="is-info" @click="obtenerServicios()" expanded rounded>
Buscar Buscar
</b-button> </b-button>
</div> </b-field>
</div> </div>
<TablaServiciosSociales <TablaServiciosSociales
@@ -81,8 +81,6 @@ export default {
}, },
props: { props: {
admin: { type: Object, required: true }, admin: { type: Object, required: true },
imprimirMensaje: { type: Function, required: true },
imprimirWarning: { type: Function, required: true },
imprimirError: { type: Function, required: true }, imprimirError: { type: Function, required: true },
}, },
methods: { methods: {
+3 -5
View File
@@ -1,15 +1,13 @@
<template> <template>
<div class="mb-5"> <div class="mb-5">
<h3 class="title" v-if="alumno.Status.idStatus === 1"> <h3 class="title" v-if="alumno.Status.idStatus === 1">
<strong> Confirmar el pre-registro del alumno </strong> Confirmar el pre-registro del alumno
</h3> </h3>
<h3 class="title" v-if="alumno.Status.idStatus === 4"> <h3 class="title" v-if="alumno.Status.idStatus === 4">Término</h3>
<strong> Término </strong>
</h3>
<h3 class="title" v-if="alumno.Status.idStatus === 5"> <h3 class="title" v-if="alumno.Status.idStatus === 5">
<strong> Validar el término del alumno </strong> Validar el término del alumno
</h3> </h3>
</div> </div>
</template> </template>
@@ -11,11 +11,12 @@
/> />
</b-field> </b-field>
<b-field label="Telefono"> <b-field label="Teléfono">
<b-input <b-input
type="tel" type="tel"
placeholder="Telefono" placeholder="Telefono"
maxlength="10" maxlength="10"
:has-counter="false"
v-model="telefono" v-model="telefono"
/> />
</b-field> </b-field>
+2 -10
View File
@@ -18,14 +18,6 @@
<b-field label="Clave de programa:"> <b-field label="Clave de programa:">
<p class="input">{{ servicio.Programa.clavePrograma }}</p> <p class="input">{{ servicio.Programa.clavePrograma }}</p>
</b-field> </b-field>
<b-field label="Programa de Acatlan:">
<p class="input">
<span>
{{ servicio.Programa.acatlan ? 'Si' : 'No' }}
</span>
</p>
</b-field>
</div> </div>
<div class="mb-5"> <div class="mb-5">
@@ -39,9 +31,9 @@
<p class="input">{{ servicio.Usuario.nombre }}</p> <p class="input">{{ servicio.Usuario.nombre }}</p>
</b-field> </b-field>
<b-field label="Fecha de nacimiento:" v-if="servicio.fechaNacimiento"> <!-- <b-field label="Fecha de nacimiento:" v-if="servicio.fechaNacimiento">
<p class="input">{{ fecha(servicio.fechaNacimiento) }}</p> <p class="input">{{ fecha(servicio.fechaNacimiento) }}</p>
</b-field> </b-field> -->
<b-field label="Carrera:"> <b-field label="Carrera:">
<p class="input">{{ servicio.Carrera.carrera }}</p> <p class="input">{{ servicio.Carrera.carrera }}</p>
+42 -36
View File
@@ -4,61 +4,67 @@
<p class="has-text-justified is-size-6"> <p class="has-text-justified is-size-6">
<span v-if="Status.idStatus === 2"> <span v-if="Status.idStatus === 2">
Para poder terminar con el registro de tu trámite de servicio social te Estimado alumno(a): Para poder terminar con el registro de tu trámite de
pedimos que verifiques que tus datos sean correctos, de no ser asi servicio social te pedimos que verifiques que tus datos sean correctos,
comunícate con COESI, y también contesta el formulario que se encuentra de no ser así puedes acudir a las ventanillas de servicio social de la
hasta el final de esta página. 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>
<span v-if="Status.idStatus === 3"> <span v-if="Status.idStatus === 3">
Te informamos que el Área de Registro y Control de Servicio Social ha Estimado alumno(a): Te informamos que el Área de Registro y Control de
validado tu solicitud de registro de servicio social por lo que el Servicio Social ha validado tu solicitud de registro de servicio social
siguiente trámite lo realizarás hasta que concluyas 480 horas en un por lo que el siguiente trámite lo realizarás hasta que concluyas 480
periodo de mínimo 6 meses y obtengas tu carta de término por parte de la horas en un periodo de mínimo 6 meses y obtengas tu carta de término por
institución, quien se encargará de subir dicho archivo a este sistema, parte de la institución, quien se encargará de subir dicho archivo a
además de responder un cuestionario sobre tu desempeño. A su vez, este sistema, además de responder un cuestionario sobre tu desempeño. A
deberás responder el siguiente cuestionario de evaluación del programa su vez, deberás responder el siguiente cuestionario de evaluación del
de servicio social en donde participaste y enviar el informe global de programa de servicio social en donde participaste y enviar el informe
actividades elaborado por ti, con firma y sello de visto bueno de tu global de actividades elaborado por ti, con firma y sello de visto bueno
jefe inmediato. En cuanto el Área de Registro y Control de Servicio de tu jefe inmediato. En cuanto el Área de Registro y Control de
Social valide tu solicitud, podrás revisar las indicaciones del Servicio Social valide tu solicitud, podrás revisar las indicaciones del
siguiente paso en el panel llamado Liberación Cualquier duda puedes siguiente paso en el panel llamado Liberación Cualquier duda puedes
acudir al área de Registro y Control de Servicio Social en COESI de acudir a las ventanillas de servicio social de la Secretaría de Asuntos
lunes a viernes de 10:00 a 14:00 hrs. y de 16:00 a 20:00 hrs. o bien, Académicos Estudiantiles, en la planta baja del Edificio A-8 de lunes a
comunicarte al 5623 1686 o al correo registross@acatlan.unam.mx 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>
<span v-if="Status.idStatus === 4"> <span v-if="Status.idStatus === 4">
Para continuar con el proceso de término de tu servicio social debes de Estimado alumno(a): Para continuar con el proceso de término de tu
subir tu informe global y contesta el cuestionario. servicio social debes de subir tu informe global y contestar el
cuestionario que se encuentra hasta el final de esta página.
</span> </span>
<span v-if="Status.idStatus === 5"> <span v-if="Status.idStatus === 5">
Espera a que tus documentos sean validados por el Departamento de Estimado alumno(a): Espera a que tus documentos sean validados por el
Servicio Social y Bolsa de Trabajo. Departamento de Servicio Social y Bolsa de Trabajo.
</span> </span>
<span v-if="Status.idStatus === 6"> <span v-if="Status.idStatus === 6">
Te confirmamos que has concluido con los trámites necesarios para la Estimado alumno(a): Te confirmamos que has concluido con los trámites
liberación de tu servicio social por lo que ahora sólo queda esperar a necesarios para la liberación de tu servicio social por lo que ahora
que en máximo 15 días hábiles se te notifique por correo electrónico a sólo queda esperar a que en máximo 15 días hábiles se te envíe por
partir de cuándo puedes recoger la copia de tu carta de liberación en correo tu carta de liberación. Cualquier duda puedes acudir a las
las ventanillas del Área de Registro y Control de Servicio Social. ventanillas de servicio social la Secretaría de Asuntos Académicos
Cualquier duda puedes acudir al área de Registro y Control de Servicio Estudiantiles, en la planta baja del Edificio A-8 de lunes a viernes de
Social en COESI de lunes a viernes de 10:00 a 13:00 hrs. y de 16:00 a 09:00 a 15:00 hrs. y de 17:00 a 19:00 hrs. o bien, comunicarte al 5623
19:00 hrs. o bien, comunicarte al 5623 1686 o al correo 1686 o al correo tramites.ss@acatlan.unam.mx
registross@apolo.acatlan.unam.mx
</span> </span>
<span v-if="Status.idStatus === 8"> <span v-if="Status.idStatus === 8">
Te informamos que la carta de término que el(la) responsable de tu Estimado alumno(a): Te informamos que la carta de término que el(la)
servicio social mando fue rechazada. Espera a que la vuelvan a subir al responsable de tu servicio social mando fue rechazada. Espera a que la
sistema para volver a verificarla. vuelvan a subir al sistema para volver a verificarla.
</span> </span>
<span v-if="Status.idStatus === 9"> <span v-if="Status.idStatus === 9">
Te informamos que el informe global que mandaste fue rechazado. Subelo Estimado alumno(a): Te informamos que el informe global que mandaste fue
nuevamente y asegurate de que cumpla con todos los requicitos. rechazado. Súbelo nuevamente y asegúrate de que cumpla con todos los
requisitos.
</span> </span>
</p> </p>
</div> </div>
@@ -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"
}
-->
+8 -4
View File
@@ -4,7 +4,10 @@
Cuestionario de evaluación del programa de servicio social. Cuestionario de evaluación del programa de servicio social.
</h3> </h3>
<b-field class="mb-6" v-if="!servicio.idCuestionarioAlumno"> <b-field
class="mb-6"
v-if="!servicio.idCuestionarioAlumno && !servicio.idCuestionarioAlumno2"
>
<b-button <b-button
type="is-info is-light" type="is-info is-light"
tag="router-link" tag="router-link"
@@ -24,9 +27,10 @@
<h3 class="label"> <h3 class="label">
Informe global de actividades Informe global de actividades
<span v-if="!servicio.informeGlobal" <span v-if="!servicio.informeGlobal">
>(en formato .PDF. No se aceptan fotos)</span (en formato .PDF. No se aceptan fotos)
>. </span>
.
</h3> </h3>
<div v-if="!servicio.informeGlobal"> <div v-if="!servicio.informeGlobal">
+2 -2
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="pb-5 pt-6"> <b-field class="pb-5 pt-6">
<b-button <b-button
type="is-info is-light" type="is-info is-light"
icon-left="arrow-left-box" icon-left="arrow-left-box"
@@ -7,7 +7,7 @@
> >
Regresar Regresar
</b-button> </b-button>
</div> </b-field>
</template> </template>
<script> <script>
@@ -39,7 +39,13 @@
</b-field> </b-field>
<b-field label="Teléfono"> <b-field label="Teléfono">
<b-input type="tel" placeholder="Teléfono" v-model="telefono" /> <b-input
type="tel"
placeholder="Teléfono"
maxlength="10"
:has-counter="false"
v-model="telefono"
/>
</b-field> </b-field>
<b-field label="Correo electrónico"> <b-field label="Correo electrónico">
@@ -135,7 +141,7 @@
<p class="is-size-7"> <p class="is-size-7">
Si al momento de elegir un archivo este no se selecciona, haga click Si al momento de elegir un archivo este no se selecciona, haga click
en cancelar en la ventana emergente y trate de nuevo. en cancelar en la ventana emergente e intente de nuevo.
</p> </p>
</div> </div>
</b-upload> </b-upload>
@@ -185,7 +191,7 @@ export default {
fechaInicio: new Date(), fechaInicio: new Date(),
fechaNacimiento: new Date(), fechaNacimiento: new Date(),
file: {}, file: {},
minDate: new Date(), minDate: new Date('2020-01-02'),
minDate2: new Date(), minDate2: new Date(),
} }
}, },
@@ -34,14 +34,14 @@
v-for="(s, i) in status" v-for="(s, i) in status"
:key="i" :key="i"
:value="s.idStatus" :value="s.idStatus"
v-show="i > 8 && i < 14" v-show="i > 9 && i < 14"
> >
{{ s.status }} {{ s.status }}
</option> </option>
</b-select> </b-select>
</b-field> </b-field>
<div class="column is-align-self-center"> <b-field class="column is-align-self-center">
<b-button <b-button
type="is-info" type="is-info"
@click="obtenerCasosEspeciales()" @click="obtenerCasosEspeciales()"
@@ -50,7 +50,7 @@
> >
Buscar Buscar
</b-button> </b-button>
</div> </b-field>
</div> </div>
<TablaServiciosSociales <TablaServiciosSociales
+1 -1
View File
@@ -37,7 +37,7 @@ export default {
!localStorage.getItem('token') !localStorage.getItem('token')
) )
this.cerrarSesion() this.cerrarSesion()
}, },
} }
</script> </script>
@@ -1,14 +1,14 @@
<template> <template>
<div> <div>
<div class="mb-6"> <div class="mb-4">
<h2 class="title"> <h4 class="is-size-4">
Estimad(a) responsable de programa de servicio social: Estimad(a) responsable de programa de servicio social:
</h2> </h4>
<p> <p>
Te solicitamos llenar cuidadosamente los campos solicitados a Te solicitamos llenar cuidadosamente los campos solicitados a
continuación para poder validar el término del servicio social de continuación para poder validar el término del servicio social de
nuestro alumno(a) nuestro alumno(a).
</p> </p>
</div> </div>
@@ -27,6 +27,10 @@
</div> </div>
</b-field> </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="columns" v-for="(uAC, i) in unoAlCinco" :key="i">
<div class="column"> <div class="column">
<p class="label">{{ i + 1 }}) {{ uAC }}</p> <p class="label">{{ i + 1 }}) {{ uAC }}</p>
@@ -43,6 +47,10 @@
</b-field> </b-field>
</div> </div>
<div class="mb-4">
<p>Contesta, con 800 letras o menos, las siguientes preguntas.</p>
</div>
<b-field <b-field
label="6) De acuerdo a lo observado ¿cuáles considera que son las cualidades de label="6) De acuerdo a lo observado ¿cuáles considera que son las cualidades de
nuestros alumnos de esta licenciatura?" nuestros alumnos de esta licenciatura?"
@@ -81,6 +89,7 @@ import axios from 'axios'
export default { export default {
props: { props: {
idServicio: { type: Number, required: true },
responsable: { type: Object, required: true }, responsable: { type: Object, required: true },
imprimirError: { type: Function, required: true }, imprimirError: { type: Function, required: true },
imprimirMensaje: { type: Function, required: true }, imprimirMensaje: { type: Function, required: true },
@@ -89,11 +98,9 @@ export default {
}, },
data() { data() {
return { return {
cuestionario: '',
p6: '', p6: '',
p7: '', p7: '',
idServicio: null, actividades: ['', '', '', '', ''],
actividades: [],
retroalimentacion: ['', '', '', '', ''], retroalimentacion: ['', '', '', '', ''],
selectRespuestas: ['Deficiente', 'Regular', 'Bueno', 'Excelente'], selectRespuestas: ['Deficiente', 'Regular', 'Bueno', 'Excelente'],
unoAlCinco: [ unoAlCinco: [
@@ -112,7 +119,6 @@ export default {
return false return false
}, },
validarRetroalimentacion() { validarRetroalimentacion() {
if (this.retroalimentacion.length != 5) return true
for (let i = 0; i < this.retroalimentacion.length; i++) for (let i = 0; i < this.retroalimentacion.length; i++)
if (!this.retroalimentacion[i]) return true if (!this.retroalimentacion[i]) return true
return false return false
@@ -128,7 +134,6 @@ export default {
retroalimentacion: this.retroalimentacion, retroalimentacion: this.retroalimentacion,
p6: this.p6, p6: this.p6,
p7: this.p7, p7: this.p7,
idServicio: this.idServicio,
} }
this.updateIsLoading(true) this.updateIsLoading(true)
@@ -140,7 +145,6 @@ export default {
) )
.then((res) => { .then((res) => {
localStorage.removeItem('idServicio') localStorage.removeItem('idServicio')
localStorage.removeItem('cuestionario')
this.updateIsLoading(false) this.updateIsLoading(false)
this.imprimirMensaje(res.data.message) this.imprimirMensaje(res.data.message)
this.$router.push('/responsable') this.$router.push('/responsable')
@@ -151,11 +155,6 @@ export default {
}) })
}, },
}, },
created() {
this.idServicio = Number(localStorage.getItem('idServicio'))
this.cuestionario = localStorage.getItem('cuestionario')
for (let i = 0; i < 5; i++) this.actividades.push('')
},
} }
</script> </script>
@@ -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"
}
-->
+2 -2
View File
@@ -80,7 +80,7 @@
/> />
</b-field> </b-field>
<b-field label="Correo del Alumno"> <b-field label="Correo electrónico del Alumno">
<b-input type="email" placeholder="Email" v-model="correo" /> <b-input type="email" placeholder="Email" v-model="correo" />
</b-field> </b-field>
@@ -102,7 +102,7 @@
<p class="is-size-7"> <p class="is-size-7">
Si al momento de elegir un archivo este no se selecciona, haga click Si al momento de elegir un archivo este no se selecciona, haga click
en cancelar en la ventana emergente y trate de nuevo. en cancelar en la ventana emergente e intente de nuevo.
</p> </p>
</div> </div>
</b-upload> </b-upload>
+1 -1
View File
@@ -78,7 +78,7 @@ export default {
}) })
.catch((err) => { .catch((err) => {
this.updateIsLoading(false) this.updateIsLoading(false)
this.imprimirerr(err.response.data) this.imprimirError(err.response.data)
}) })
}, },
}, },
+23 -23
View File
@@ -2,18 +2,16 @@
<section class="hero is-light is-bold is-fullheight"> <section class="hero is-light is-bold is-fullheight">
<div class="container hero-body"> <div class="container hero-body">
<transition name="slide-fade" appear> <transition name="slide-fade" appear>
<div class="container columns"> <div class="columns">
<div class="column animate__animated animate__fadeIn animate__slow">
<b-image
class="image"
:src="require('@/assets/404.webp')"
alt="404 image"
></b-image>
</div>
<div class="column"> <div class="column">
<h1 class="title">ERROR 404 LA PÁGINA NO HA SIDO ENCONTRADA</h1> <b-image :src="require('@/assets/404.webp')" alt="404 image" />
<b-button class="is-dark" outlined @click="cerrarSesion()" </div>
>Ir a la página principal
<div class="column">
<h2 class="title">ERROR 404 LA PÁGINA NO HA SIDO ENCONTRADA</h2>
<b-button type="is-dark" @click="redireccionar()" outlined>
Ir a la página principal
</b-button> </b-button>
</div> </div>
</div> </div>
@@ -24,23 +22,25 @@
<script> <script>
export default { export default {
layout: 'login',
methods: { methods: {
cerrarSesion() { redireccionar() {
localStorage.clear() if (
localStorage.getItem('token') &&
this.$router.push('/') localStorage.getItem('idUsuario') &&
localStorage.getItem('usuario') &&
localStorage.getItem('nombre') &&
localStorage.getItem('idTipoUsuario') &&
localStorage.getItem('tipoUsuario')
)
this.$router.push(`/${localStorage.getItem('tipoUsuario')}`)
else localStorage.clear()
}, },
}, },
layout: 'login',
} }
</script> </script>
<style scoped> <style scoped>
.image {
height: 100%;
width: 100%;
}
.title { .title {
margin-top: 40%; margin-top: 40%;
} }
@@ -53,8 +53,8 @@ export default {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1); transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
} }
.slide-fade-enter, .slide-fade-leave-to .slide-fade-enter,
/* .slide-fade-leave-active below version 2.1.8 */ { .slide-fade-leave-to {
transform: translateX(10px); transform: translateX(10px);
opacity: 0; opacity: 0;
} }
+3 -3
View File
@@ -24,9 +24,9 @@ export default {
axios: {}, axios: {},
build: {}, build: {},
env: { env: {
// api: 'http://localhost:3000', //api: 'http://localhost:3000',
// api: "https://890af9d598a4.ngrok.io" // api: "https://890af9d598a4.ngrok.io"
api: 'https://venus.acatlan.unam.mx/ss-pruebas', //api: 'https://venus.acatlan.unam.mx/ss-pruebas',
// api: "https://venus.acatlan.unam.mx/serviciosocial", api: 'https://venus.acatlan.unam.mx/serviciosocial',
}, },
} }
+7578 -5811
View File
File diff suppressed because it is too large Load Diff
@@ -12,6 +12,8 @@
:updateIsLoading="updateIsLoading" :updateIsLoading="updateIsLoading"
/> />
<BotonRegresar path="/admin/casos_especiales/caso_especial" />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" /> <b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</section> </section>
</template> </template>
+2
View File
@@ -3,6 +3,8 @@
<BotonRegresar path="/admin" /> <BotonRegresar path="/admin" />
<TablaCasosEspecialesAdmin :admin="admin" :imprimirError="imprimirError" /> <TablaCasosEspecialesAdmin :admin="admin" :imprimirError="imprimirError" />
<BotonRegresar path="/admin" />
</section> </section>
</template> </template>
+5 -46
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container px-2 pb-6">
<div class="pb-5 pt-6"> <div class="pb-5 pt-6">
<b-button type="is-info" tag="router-link" to="/admin/responsables"> <b-button type="is-info" tag="router-link" to="/admin/responsables">
Ver responsables Ver responsables
@@ -14,21 +14,16 @@
</b-button> </b-button>
</div> </div>
<TablaServiciosSocialesAdmin <TablaServiciosSociales :admin="admin" :imprimirError="imprimirError" />
:admin="admin" </section>
:imprimirMensaje="imprimirMensaje"
:imprimirWarning="imprimirWarning"
:imprimirError="imprimirError"
/>
</div>
</template> </template>
<script> <script>
import TablaServiciosSocialesAdmin from '@/components/admin/TablaServiciosSociales' import TablaServiciosSociales from '@/components/admin/TablaServiciosSociales'
export default { export default {
components: { components: {
TablaServiciosSocialesAdmin, TablaServiciosSociales,
}, },
data() { data() {
return { return {
@@ -54,42 +49,6 @@ export default {
this.$router.push('/') this.$router.push('/')
} }
}, },
imprimirMensaje(message, title = '¡Felicidades!', onConfirm = () => {}) {
this.$buefy.dialog.alert({
ariaRole: 'alertdialog',
ariaModal: true,
type: 'is-success',
title,
message,
confirmText: 'Ok',
hasIcon: true,
iconPack: 'mdi',
icon: 'check-circle',
onConfirm: () => onConfirm(),
})
},
imprimirWarning(
message,
onConfirm = () => {},
title = '¡Espera un minuto!',
onCancel = () => {}
) {
this.$buefy.dialog.alert({
ariaRole: 'alertdialog',
ariaModal: true,
type: 'is-warning',
title,
message,
confirmText: 'Confirmar',
canCancel: true,
cancelText: 'Cancelar',
hasIcon: true,
iconPack: 'mdi',
icon: 'help-circle',
onConfirm: () => onConfirm(),
onCancel: () => onCancel(),
})
},
getLocalhostInfo() { getLocalhostInfo() {
this.admin.idUsuario = Number(localStorage.getItem('idUsuario')) this.admin.idUsuario = Number(localStorage.getItem('idUsuario'))
this.admin.idTipoUsuario = Number(localStorage.getItem('idTipoUsuario')) this.admin.idTipoUsuario = Number(localStorage.getItem('idTipoUsuario'))
+2 -38
View File
@@ -14,8 +14,6 @@
<Reporte <Reporte
:admin="admin" :admin="admin"
:imprimirError="imprimirError" :imprimirError="imprimirError"
:imprimirMensaje="imprimirMensaje"
:imprimirWarning="imprimirWarning"
:updateIsLoading="updateIsLoading" :updateIsLoading="updateIsLoading"
/> />
@@ -26,6 +24,8 @@
:updateIsLoading="updateIsLoading" :updateIsLoading="updateIsLoading"
/> />
<BotonRegresar path="/admin" />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" /> <b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</section> </section>
</template> </template>
@@ -77,42 +77,6 @@ export default {
this.$router.push('/') this.$router.push('/')
} }
}, },
imprimirMensaje(message, title = '¡Felicidades!', onConfirm = () => {}) {
this.$buefy.dialog.alert({
ariaRole: 'alertdialog',
ariaModal: true,
type: 'is-success',
title,
message,
confirmText: 'Ok',
hasIcon: true,
iconPack: 'mdi',
icon: 'check-circle',
onConfirm: () => onConfirm(),
})
},
imprimirWarning(
message,
onConfirm = () => {},
title = '¡Espera un minuto!',
onCancel = () => {}
) {
this.$buefy.dialog.alert({
ariaRole: 'alertdialog',
ariaModal: true,
type: 'is-warning',
title,
message,
confirmText: 'Confirmar',
canCancel: true,
cancelText: 'Cancelar',
hasIcon: true,
iconPack: 'mdi',
icon: 'help-circle',
onConfirm: () => onConfirm(),
onCancel: () => onCancel(),
})
},
getLocalhostInfo() { getLocalhostInfo() {
this.admin.idUsuario = Number(localStorage.getItem('idUsuario')) this.admin.idUsuario = Number(localStorage.getItem('idUsuario'))
this.admin.idTipoUsuario = Number(localStorage.getItem('idTipoUsuario')) this.admin.idTipoUsuario = Number(localStorage.getItem('idTipoUsuario'))
+2
View File
@@ -12,6 +12,8 @@
<TablaResponsables :admin="admin" :imprimirError="imprimirError" /> <TablaResponsables :admin="admin" :imprimirError="imprimirError" />
<BotonRegresar path="/admin" />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" /> <b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</section> </section>
</template> </template>
@@ -59,7 +59,6 @@ export default {
) )
.then((res) => { .then((res) => {
this.responsable = res.data this.responsable = res.data
// this.nuevo.activo = this.responsable.activo
this.updateIsLoading(false) this.updateIsLoading(false)
}) })
.catch((err) => { .catch((err) => {
+19 -1
View File
@@ -1,27 +1,40 @@
<template> <template>
<section class="container px-2 pb-6"> <section class="container px-2 pb-6">
<BotonRegresar path="/admin/servicio" />
<EditarServicio <EditarServicio
:admin="admin" :admin="admin"
:imprimirMensaje="imprimirMensaje" :imprimirMensaje="imprimirMensaje"
:imprimirWarning="imprimirWarning" :imprimirWarning="imprimirWarning"
:imprimirError="imprimirError" :imprimirError="imprimirError"
:updateIsLoading="updateIsLoading"
/> />
<BotonRegresar path="/admin/servicio" />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</section> </section>
</template> </template>
<script> <script>
import EditarServicio from '@/components/admin/EditarServicio' import EditarServicio from '@/components/admin/EditarServicio'
import BotonRegresar from '@/components/botonRegresar'
export default { export default {
components: { components: {
BotonRegresar,
EditarServicio, EditarServicio,
}, },
data() { data() {
return { return {
isLoading: false,
admin: {}, admin: {},
} }
}, },
methods: { methods: {
updateIsLoading(booleanValue) {
this.isLoading = booleanValue
},
imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) { imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) {
this.$buefy.dialog.alert({ this.$buefy.dialog.alert({
ariaRole: 'alertdialog', ariaRole: 'alertdialog',
@@ -85,6 +98,12 @@ export default {
token: localStorage.getItem('token'), token: localStorage.getItem('token'),
}, },
} }
this.admin.tokenArchivo = {
headers: {
'Content-Type': 'multipart/form-data',
token: localStorage.getItem('token'),
},
}
}, },
}, },
created() { created() {
@@ -92,7 +111,6 @@ export default {
if (this.admin.idTipoUsuario === 2) this.$router.push('/responsable') if (this.admin.idTipoUsuario === 2) this.$router.push('/responsable')
if (this.admin.idTipoUsuario === 3) this.$router.push('/alumno') if (this.admin.idTipoUsuario === 3) this.$router.push('/alumno')
if (this.admin.idTipoUsuario === 4) this.$router.push('/casoEspecial') if (this.admin.idTipoUsuario === 4) this.$router.push('/casoEspecial')
if (!localStorage.getItem('idServicio')) this.$router.push('/admin')
}, },
} }
</script> </script>
+7 -6
View File
@@ -4,7 +4,7 @@
<h3 class="title">{{ alumno.Status.status }}</h3> <h3 class="title">{{ alumno.Status.status }}</h3>
<Informacion :alumno="alumno" /> <InformacionServicio :alumno="alumno" />
<TituloStatus :alumno="alumno" /> <TituloStatus :alumno="alumno" />
@@ -16,6 +16,7 @@
:updateIsLoading="updateIsLoading" :updateIsLoading="updateIsLoading"
:alumno="alumno" :alumno="alumno"
:title="'carta de aceptación'" :title="'carta de aceptación'"
v-if="alumno.cartaAceptacion"
/> />
<Archivo <Archivo
@@ -41,11 +42,11 @@
/> />
<div> <div>
<p v-if="alumno.idCuestionarioPrograma" class="my-4"> <p v-if="alumno.idCuestionarioPrograma || alumno.idCuestionarioPrograma2" class="my-4">
<strong> Cuenta con cuestionario de programa resuelto. </strong> <strong> Cuenta con cuestionario de programa resuelto. </strong>
</p> </p>
<p v-if="alumno.idCuestionarioAlumno" class="my-4"> <p v-if="alumno.idCuestionarioAlumno || alumno.idCuestionarioAlumno2" class="my-4">
<strong> Cuenta con cuestionario de alumno resuelto. </strong> <strong> Cuenta con cuestionario de alumno resuelto. </strong>
</p> </p>
</div> </div>
@@ -81,7 +82,7 @@ import axios from 'axios'
import Archivo from '@/components/admin/Archivo' import Archivo from '@/components/admin/Archivo'
import CancelarServicio from '@/components/admin/CancelarServicio' import CancelarServicio from '@/components/admin/CancelarServicio'
import ConfirmarServicio from '@/components/admin/ConfirmarServicio' import ConfirmarServicio from '@/components/admin/ConfirmarServicio'
import Informacion from '@/components/admin/InformacionServicio' import InformacionServicio from '@/components/admin/InformacionServicio'
import TituloStatus from '@/components/admin/TituloStatus' import TituloStatus from '@/components/admin/TituloStatus'
export default { export default {
@@ -89,7 +90,7 @@ export default {
Archivo, Archivo,
CancelarServicio, CancelarServicio,
ConfirmarServicio, ConfirmarServicio,
Informacion, InformacionServicio,
TituloStatus, TituloStatus,
}, },
data() { data() {
@@ -98,7 +99,7 @@ export default {
idServicio: null, idServicio: null,
admin: {}, admin: {},
alumno: { alumno: {
Programa: {}, Programa: { Usuario: {} },
Usuario: {}, Usuario: {},
Carrera: {}, Carrera: {},
Status: {}, Status: {},
+383 -371
View File
@@ -1,384 +1,396 @@
<template> <template>
<section class="container my-5 px-3"> <section class="container my-5 px-3">
<div v-if="idCuestionario === 'null'"> <div v-if="idCuestionario === 'null'">
<BotonRegresar path="/alumno" /> <BotonRegresar path="/alumno" />
<div class="my-5 mensaje"> <div class="my-5 mensaje">
<p class="is-size-2">Evaluación de programas de servicio social</p> <p class="is-size-2">2025 evaluación del universitario(a) sobre su servicio social</p>
<p> <p>
Te invitamos a compartir tu experiencia respecto del programa de Te invitamos a compartir tu experiencia respecto del programa de servicio social en el que
servicio social en el que participaste, a efecto de mejorar la oferta participaste, a efecto de mejorar la oferta de programas disponibles para los alumnos que
de programas disponibles para los alumnos que desean liberar este desean liberar este requisito. Te recordamos que tus respuestas son confidenciales.
requisito. Te recordamos qe tus respues son confidenciales. Los datos están sujetos al aviso de privacidad integral que se puede consultar en el sitio
web: <a
href="https://www.acatlan.unam.mx/normatividad"
class="column "
target="_blank"> www.acatlan.unam.mx/normatividad </a>
</p> </p>
</div> </div>
<!-- <parteA v-show="current == 1" v-on:childAToParent="onChildA" />
<parteB v-show="current == 2" v-on:childBToParent="onChildB" />
<parteC v-show="current == 3" v-on:childCToParent="onChildC" />
<parteD v-show="current == 4" v-on:childDToParent="onChildD" />
<parteE v-show="current == 5" v-on:childEToParent="onChildE" />
<parteF v-show="current == 6" v-on:childFToParent="onChildF" />
<navCues :answers="answers" v-on:childNAVToParent="onChildNAV" /> -->
<parteA v-show="current == 1" v-on:childAToParent="onChildA" /> <FullCuestionario />
<parteB v-show="current == 2" v-on:childBToParent="onChildB" /> </div>
<div v-else class="vh">
<h2>Ya has contestado tu cuestionario :)</h2>
</div>
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading">
</b-loading>
</section>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
import parteA from '@/components/alumno/cuestionario/A'
import parteB from '@/components/alumno/cuestionario/B'
import parteC from '@/components/alumno/cuestionario/C'
import parteD from '@/components/alumno/cuestionario/D'
import parteE from '@/components/alumno/cuestionario/E'
import parteF from '@/components/alumno/cuestionario/F'
import navCues from '@/components/alumno/cuestionario/navCues'
import BotonRegresar from '@/components/botonRegresar'
<parteC v-show="current == 3" v-on:childCToParent="onChildC" /> import FullCuestionario from '@/components/alumno/cuestionario2/FullCuestionario'
<parteD v-show="current == 4" v-on:childDToParent="onChildD" /> export default {
components: {
<parteE v-show="current == 5" v-on:childEToParent="onChildE" /> parteA,
parteB,
<parteF v-show="current == 6" v-on:childFToParent="onChildF" /> parteC,
parteD,
<navCues :answers="answers" v-on:childNAVToParent="onChildNAV" /> parteE,
</div> parteF,
navCues,
<div v-else class="vh"> BotonRegresar,
<h1>Ya has contestado tu cuestionario :)</h1> FullCuestionario
</div>
},
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading"> data() {
</b-loading> return {
</section> token: {
</template> headers: {
token: localStorage.getItem('token'),
<script> },
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
import parteA from '@/components/alumno/cuestionario/A'
import parteB from '@/components/alumno/cuestionario/B'
import parteC from '@/components/alumno/cuestionario/C'
import parteD from '@/components/alumno/cuestionario/D'
import parteE from '@/components/alumno/cuestionario/E'
import parteF from '@/components/alumno/cuestionario/F'
import navCues from '@/components/alumno/cuestionario/navCues'
import BotonRegresar from '@/components/botonRegresar'
export default {
components: {
parteA,
parteB,
parteC,
parteD,
parteE,
parteF,
navCues,
BotonRegresar,
},
data() {
return {
token: {
headers: {
token: localStorage.getItem('token'),
}, },
isLoading: false,
current: 1,
idCuestionario: "null",
answers: {
sexo: '',
edad: '',
servicioMedico: '',
servicioMedicoOtro: '',
servicioMedicoAux: '',
p1: '',
p2: '',
p3: [], // selecciona 3 opciones
p3Otro: '',
p4: '',
p5: [],
p6: '',
p7: '',
p8: [],
p9: '',
p10: '',
p11: '',
p12: '',
p13: '',
p14: [],
p15: [],
p16: '',
p17: [],
p18: '',
p19: '',
p20: '',
p21: [],
p22: [],
p23: [],
p24: [],
p25: '',
p26: '',
p27: '',
p28: null,
p29: null,
p30: '',
},
}
},
methods: {
onChildA(value) {
this.answers.servicioMedico = value.servicioMedico
this.answers.sexo = value.sexo
this.answers.edad = value.edad
}, },
isLoading: false, onChildB(value) {
current: 1, this.answers.p1 = value.p1
idCuestionario: '', this.answers.p2 = value.p2
answers: { this.answers.p3 = value.p3
sexo: '', this.answers.p3Otro = value.p3Otro
edad: '',
servicioMedico: '',
servicioMedicoOtro: '',
servicioMedicoAux: '',
p1: '',
p2: '',
p3: [], // selecciona 3 opciones
p3Otro: '',
p4: '',
p5: [],
p6: '',
p7: '',
p8: [],
p9: '',
p10: '',
p11: '',
p12: '',
p13: '',
p14: [],
p15: [],
p16: '',
p17: [],
p18: '',
p19: '',
p20: '',
p21: [],
p22: [],
p23: [],
p24: [],
p25: '',
p26: '',
p27: '',
p28: null,
p29: null,
p30: '',
}, },
} onChildC(value) {
}, this.answers.p4 = value.p4
methods: { this.answers.p5 = value.p5
onChildA(value) { this.answers.p6 = value.p6
this.answers.servicioMedico = value.servicioMedico this.answers.p7 = value.p7
this.answers.sexo = value.sexo this.answers.p8 = value.p8
this.answers.edad = value.edad this.answers.p9 = value.p9
}, this.answers.p10 = value.p10
onChildB(value) { this.answers.p11 = value.p11
this.answers.p1 = value.p1 this.answers.p12 = value.p12
this.answers.p2 = value.p2 this.answers.p13 = value.p13
this.answers.p3 = value.p3 },
this.answers.p3Otro = value.p3Otro onChildD(value) {
}, this.answers.p14 = value.p14
onChildC(value) { this.answers.p15 = value.p15
this.answers.p4 = value.p4 this.answers.p16 = value.p16
this.answers.p5 = value.p5 this.answers.p17 = value.p17
this.answers.p6 = value.p6 },
this.answers.p7 = value.p7 onChildE(value) {
this.answers.p8 = value.p8 this.answers.p18 = value.p18
this.answers.p9 = value.p9 this.answers.p19 = value.p19
this.answers.p10 = value.p10 this.answers.p20 = value.p20
this.answers.p11 = value.p11 this.answers.p21 = value.p21
this.answers.p12 = value.p12 },
this.answers.p13 = value.p13 onChildF(value) {
}, this.answers.p22 = value.p22
onChildD(value) { this.answers.p23 = value.p23
this.answers.p14 = value.p14 this.answers.p24 = value.p24
this.answers.p15 = value.p15 this.answers.p25 = value.p25
this.answers.p16 = value.p16 this.answers.p26 = value.p26
this.answers.p17 = value.p17 this.answers.p27 = value.p27
}, this.answers.p28 = value.p28
onChildE(value) { this.answers.p29 = value.p29
this.answers.p18 = value.p18 this.answers.p30 = value.p30
this.answers.p19 = value.p19 },
this.answers.p20 = value.p20 onChildNAV(value) {
this.answers.p21 = value.p21 this.current = value
}, },
onChildF(value) { error(msj) {
this.answers.p22 = value.p22 let salir = false
this.answers.p23 = value.p23 switch (msj) {
this.answers.p24 = value.p24 case 'invalid signature':
this.answers.p25 = value.p25 msj = 'Tu token no es valido, inicia sesión de nuevo.'
this.answers.p26 = value.p26 salir = true
this.answers.p27 = value.p27 break
this.answers.p28 = value.p28 case 'jwt expired':
this.answers.p29 = value.p29 msj = 'Tu sesión ha expirado, inicia sesión de nuevo.'
this.answers.p30 = value.p30 salir = true
}, break
onChildNAV(value) { case 'jwt malformed':
this.current = value msj = 'No se encontro tu token, inicia sesión de nuevo.'
}, salir = true
error(msj) { break
let salir = false case 'No hay token':
switch (msj) { msj = 'Ocurrio un error al enviar tu token, inicia sesión de nuevo.'
case 'invalid signature': salir = true
msj = 'Tu token no es valido, inicia sesión de nuevo.' break
salir = true }
break
case 'jwt expired': this.$buefy.dialog.alert({
msj = 'Tu sesión ha expirado, inicia sesión de nuevo.' title: 'Error',
salir = true message: msj,
break type: 'is-danger',
case 'jwt malformed': hasIcon: true,
msj = 'No se encontro tu token, inicia sesión de nuevo.' icon: 'alert-circle',
salir = true ariaRole: 'alertdialog',
break ariaModal: true,
case 'No hay token': })
msj = 'Ocurrio un error al enviar tu token, inicia sesión de nuevo.' if (salir == true) {
salir = true localStorage.clear()
break this.$router.push(`/`)
} }
},
this.$buefy.dialog.alert({ enviarCuestionario() {
title: 'Error', this.isLoading = true
message: msj, if (this.answers.p3Otro != '' && this.maxCheckbox < 3) {
type: 'is-danger', this.answers.p3.push(this.answers.p3Otro)
hasIcon: true, }
icon: 'alert-circle', const data = {
ariaRole: 'alertdialog', idServicio: localStorage.getItem('idServicio'),
ariaModal: true, sexo: this.answers.sexo,
}) edad: this.answers.edad,
if (salir == true) { servicioMedico: this.answers.servicioMedico,
localStorage.clear() p1: this.answers.p1,
this.$router.push(`/`) p2: this.answers.p2,
} p3: this.answers.p3,
}, p4: this.answers.p4,
enviarCuestionario() { p5: this.answers.p5,
this.isLoading = true p6: this.answers.p6,
if (this.answers.p3Otro != '' && this.maxCheckbox < 3) { p7: this.answers.p7,
this.answers.p3.push(this.answers.p3Otro) p8: this.answers.p8,
} p9: this.answers.p9,
const data = { p10: this.answers.p10,
idServicio: localStorage.getItem('idServicio'), p11: this.answers.p11,
sexo: this.answers.sexo, p12: this.answers.p12,
edad: this.answers.edad, p13: this.answers.p13,
servicioMedico: this.answers.servicioMedico, p14: this.answers.p14,
p1: this.answers.p1, p15: this.answers.p15,
p2: this.answers.p2, p16: this.answers.p16,
p3: this.answers.p3, p17: this.answers.p17,
p4: this.answers.p4, p18: this.answers.p18,
p5: this.answers.p5, p19: this.answers.p19,
p6: this.answers.p6, p20: this.answers.p20,
p7: this.answers.p7, p21: this.answers.p21,
p8: this.answers.p8, p22: this.answers.p22,
p9: this.answers.p9, p23: this.answers.p23,
p10: this.answers.p10, p24: this.answers.p24,
p11: this.answers.p11, p25: this.answers.p25,
p12: this.answers.p12, p26: this.answers.p26,
p13: this.answers.p13, p27: this.answers.p27,
p14: this.answers.p14, p28: this.answers.p28,
p15: this.answers.p15, p29: this.answers.p29,
p16: this.answers.p16, p30: this.answers.p30,
p17: this.answers.p17, }
p18: this.answers.p18, axios
p19: this.answers.p19, .post(`${process.env.api}/cuestionario_alumno`, data, this.token)
p20: this.answers.p20, .then((res) => {
p21: this.answers.p21, this.$buefy.dialog.alert({
p22: this.answers.p22, title: 'Success',
p23: this.answers.p23, message: 'Se enviaron los datos correctamente',
p24: this.answers.p24, type: 'is-success',
p25: this.answers.p25, hasIcon: true,
p26: this.answers.p26, icon: 'checkbox-marked-circle',
p27: this.answers.p27, ariaRole: 'alertdialog',
p28: this.answers.p28, ariaModal: true,
p29: this.answers.p29, })
p30: this.answers.p30,
} //this.reset()
axios localStorage.removeItem('idCuestionarioAlumno')
.post(`${process.env.api}/cuestionario_alumno`, data, this.token) this.$router.push('/alumno')
.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,
}) })
.catch((error) => {
//this.reset() this.error(error.response.data.message)
localStorage.removeItem('idCuestionarioAlumno') })
this.$router.push('/alumno') .finally(() => {
}) this.isLoading = false
.catch((error) => { })
this.error(error.response.data.message) },
})
.finally(() => {
this.isLoading = false
})
}, },
}, /* mounted() {
mounted() { this.idCuestionario = localStorage.getItem('idCuestionarioAlumno')
this.idCuestionario = localStorage.getItem('idCuestionarioAlumno') }, */
}, // data() {
// data() { // return {
// return { // admin: {},
// admin: {}, // }
// } // },
// }, // methods: {
// methods: { // imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) {
// imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) { // this.$buefy.dialog.alert({
// this.$buefy.dialog.alert({ // ariaRole: 'alertdialog',
// ariaRole: 'alertdialog', // ariaModal: true,
// ariaModal: true, // type: 'is-danger',
// type: 'is-danger', // title,
// title, // message: err.message,
// message: err.message, // confirmText: 'Entendido',
// confirmText: 'Entendido', // hasIcon: true,
// hasIcon: true, // iconPack: 'mdi',
// iconPack: 'mdi', // icon: 'alert-octagon',
// icon: 'alert-octagon', // onConfirm: () => onConfirm(),
// onConfirm: () => onConfirm(), // })
// }) // if (err.err && err.err === 'token error') {
// if (err.err && err.err === 'token error') { // localStorage.clear()
// localStorage.clear() // this.$router.push('/')
// this.$router.push('/') // }
// } // },
// }, // imprimirMensaje(message, title = '¡Felicidades!', onConfirm = () => {}) {
// imprimirMensaje(message, title = '¡Felicidades!', onConfirm = () => {}) { // this.$buefy.dialog.alert({
// this.$buefy.dialog.alert({ // ariaRole: 'alertdialog',
// ariaRole: 'alertdialog', // ariaModal: true,
// ariaModal: true, // type: 'is-success',
// type: 'is-success', // title,
// title, // message,
// message, // confirmText: 'Ok',
// confirmText: 'Ok', // hasIcon: true,
// hasIcon: true, // iconPack: 'mdi',
// iconPack: 'mdi', // icon: 'check-circle',
// icon: 'check-circle', // onConfirm: () => onConfirm(),
// onConfirm: () => onConfirm(), // })
// }) // },
// }, // imprimirWarning(
// imprimirWarning( // message,
// message, // onConfirm = () => {},
// onConfirm = () => {}, // title = '¡Espera un minuto!',
// title = '¡Espera un minuto!', // onCancel = () => {}
// onCancel = () => {} // ) {
// ) { // this.$buefy.dialog.alert({
// this.$buefy.dialog.alert({ // ariaRole: 'alertdialog',
// ariaRole: 'alertdialog', // ariaModal: true,
// ariaModal: true, // type: 'is-warning',
// type: 'is-warning', // title,
// title, // message,
// message, // confirmText: 'Confirmar',
// confirmText: 'Confirmar', // canCancel: true,
// canCancel: true, // cancelText: 'Cancelar',
// cancelText: 'Cancelar', // hasIcon: true,
// hasIcon: true, // iconPack: 'mdi',
// iconPack: 'mdi', // icon: 'help-circle',
// icon: 'help-circle', // onConfirm: () => onConfirm(),
// onConfirm: () => onConfirm(), // onCancel: () => onCancel(),
// onCancel: () => onCancel(), // })
// }) // },
// }, // getLocalhostInfo() {
// getLocalhostInfo() { // this.admin.idUsuario = Number(localStorage.getItem('idUsuario'))
// this.admin.idUsuario = Number(localStorage.getItem('idUsuario')) // this.admin.idTipoUsuario = Number(localStorage.getItem('idTipoUsuario'))
// this.admin.idTipoUsuario = Number(localStorage.getItem('idTipoUsuario')) // this.admin.tipoUsuario = localStorage.getItem('tipoUsuario')
// this.admin.tipoUsuario = localStorage.getItem('tipoUsuario') // this.admin.token = {
// this.admin.token = { // headers: {
// headers: { // token: localStorage.getItem('token'),
// token: localStorage.getItem('token'), // },
// }, // }
// } // },
// }, // },
// }, // created() {
// created() { // this.getLocalhostInfo()
// this.getLocalhostInfo() // if (this.admin.idTipoUsuario === 1) this.$router.push('/admin')
// if (this.admin.idTipoUsuario === 1) this.$router.push('/admin') // if (this.admin.idTipoUsuario === 2) this.$router.push('/responsable')
// if (this.admin.idTipoUsuario === 2) this.$router.push('/responsable') // if (this.admin.idTipoUsuario === 4) this.$router.push('/casoEspecial')
// if (this.admin.idTipoUsuario === 4) this.$router.push('/casoEspecial') // },
// }, }
} </script>
</script> <style>
<style> .SINO * {
.SINO * { margin: 0.5rem 0 !important;
margin: 0.5rem 0 !important; }
} .apartado,
.apartado, .pag {
.pag { margin: 5rem 0;
margin: 5rem 0; }
} .manyInputs {
.manyInputs { margin: 1.5rem 0;
margin: 1.5rem 0; }
} .checkb {
.checkb { width: 20px;
width: 20px; height: 20px;
height: 20px; }
} .navPages {
.navPages { padding: 1rem;
padding: 1rem; }
} .td-w {
.td-w { width: 2000px;
width: 2000px; }
} .active,
.active, .active:hover {
.active:hover { background-color: #bb8800 !important;
background-color: #bb8800 !important; }
} .centro {
.centro { text-align: center;
text-align: center; }
} .vh {
.vh { height: 75vh;
height: 75vh; display: flex;
display: flex; justify-content: center;
justify-content: center; align-items: center;
align-items: center; }
} .vh h1 {
.vh h1 { font-size: 60px;
font-size: 60px; }
} </style>
</style>
+384
View File
@@ -0,0 +1,384 @@
<template>
<section class="container my-5 px-3">
<div v-if="idCuestionario === 'null'">
<BotonRegresar path="/alumno" />
<div class="my-5 mensaje">
<p class="is-size-2">Evaluación de programas de servicio social</p>
<p>
Te invitamos a compartir tu experiencia respecto del programa de
servicio social en el que participaste, a efecto de mejorar la oferta
de programas disponibles para los alumnos que desean liberar este
requisito. Te recordamos qe tus respues son confidenciales.
</p>
</div>
<parteA v-show="current == 1" v-on:childAToParent="onChildA" />
<parteB v-show="current == 2" v-on:childBToParent="onChildB" />
<parteC v-show="current == 3" v-on:childCToParent="onChildC" />
<parteD v-show="current == 4" v-on:childDToParent="onChildD" />
<parteE v-show="current == 5" v-on:childEToParent="onChildE" />
<parteF v-show="current == 6" v-on:childFToParent="onChildF" />
<navCues :answers="answers" v-on:childNAVToParent="onChildNAV" />
</div>
<div v-else class="vh">
<h2>Ya has contestado tu cuestionario :)</h2>
</div>
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading">
</b-loading>
</section>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
import parteA from '@/components/alumno/cuestionario/A'
import parteB from '@/components/alumno/cuestionario/B'
import parteC from '@/components/alumno/cuestionario/C'
import parteD from '@/components/alumno/cuestionario/D'
import parteE from '@/components/alumno/cuestionario/E'
import parteF from '@/components/alumno/cuestionario/F'
import navCues from '@/components/alumno/cuestionario/navCues'
import BotonRegresar from '@/components/botonRegresar'
export default {
components: {
parteA,
parteB,
parteC,
parteD,
parteE,
parteF,
navCues,
BotonRegresar,
},
data() {
return {
token: {
headers: {
token: localStorage.getItem('token'),
},
},
isLoading: false,
current: 1,
idCuestionario: '',
answers: {
sexo: '',
edad: '',
servicioMedico: '',
servicioMedicoOtro: '',
servicioMedicoAux: '',
p1: '',
p2: '',
p3: [], // selecciona 3 opciones
p3Otro: '',
p4: '',
p5: [],
p6: '',
p7: '',
p8: [],
p9: '',
p10: '',
p11: '',
p12: '',
p13: '',
p14: [],
p15: [],
p16: '',
p17: [],
p18: '',
p19: '',
p20: '',
p21: [],
p22: [],
p23: [],
p24: [],
p25: '',
p26: '',
p27: '',
p28: null,
p29: null,
p30: '',
},
}
},
methods: {
onChildA(value) {
this.answers.servicioMedico = value.servicioMedico
this.answers.sexo = value.sexo
this.answers.edad = value.edad
},
onChildB(value) {
this.answers.p1 = value.p1
this.answers.p2 = value.p2
this.answers.p3 = value.p3
this.answers.p3Otro = value.p3Otro
},
onChildC(value) {
this.answers.p4 = value.p4
this.answers.p5 = value.p5
this.answers.p6 = value.p6
this.answers.p7 = value.p7
this.answers.p8 = value.p8
this.answers.p9 = value.p9
this.answers.p10 = value.p10
this.answers.p11 = value.p11
this.answers.p12 = value.p12
this.answers.p13 = value.p13
},
onChildD(value) {
this.answers.p14 = value.p14
this.answers.p15 = value.p15
this.answers.p16 = value.p16
this.answers.p17 = value.p17
},
onChildE(value) {
this.answers.p18 = value.p18
this.answers.p19 = value.p19
this.answers.p20 = value.p20
this.answers.p21 = value.p21
},
onChildF(value) {
this.answers.p22 = value.p22
this.answers.p23 = value.p23
this.answers.p24 = value.p24
this.answers.p25 = value.p25
this.answers.p26 = value.p26
this.answers.p27 = value.p27
this.answers.p28 = value.p28
this.answers.p29 = value.p29
this.answers.p30 = value.p30
},
onChildNAV(value) {
this.current = value
},
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',
ariaRole: 'alertdialog',
ariaModal: true,
})
if (salir == true) {
localStorage.clear()
this.$router.push(`/`)
}
},
enviarCuestionario() {
this.isLoading = true
if (this.answers.p3Otro != '' && this.maxCheckbox < 3) {
this.answers.p3.push(this.answers.p3Otro)
}
const data = {
idServicio: localStorage.getItem('idServicio'),
sexo: this.answers.sexo,
edad: this.answers.edad,
servicioMedico: this.answers.servicioMedico,
p1: this.answers.p1,
p2: this.answers.p2,
p3: this.answers.p3,
p4: this.answers.p4,
p5: this.answers.p5,
p6: this.answers.p6,
p7: this.answers.p7,
p8: this.answers.p8,
p9: this.answers.p9,
p10: this.answers.p10,
p11: this.answers.p11,
p12: this.answers.p12,
p13: this.answers.p13,
p14: this.answers.p14,
p15: this.answers.p15,
p16: this.answers.p16,
p17: this.answers.p17,
p18: this.answers.p18,
p19: this.answers.p19,
p20: this.answers.p20,
p21: this.answers.p21,
p22: this.answers.p22,
p23: this.answers.p23,
p24: this.answers.p24,
p25: this.answers.p25,
p26: this.answers.p26,
p27: this.answers.p27,
p28: this.answers.p28,
p29: this.answers.p29,
p30: this.answers.p30,
}
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)
})
.finally(() => {
this.isLoading = false
})
},
},
mounted() {
this.idCuestionario = localStorage.getItem('idCuestionarioAlumno')
},
// data() {
// return {
// admin: {},
// }
// },
// methods: {
// imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) {
// this.$buefy.dialog.alert({
// ariaRole: 'alertdialog',
// ariaModal: true,
// type: 'is-danger',
// title,
// message: err.message,
// confirmText: 'Entendido',
// hasIcon: true,
// iconPack: 'mdi',
// icon: 'alert-octagon',
// onConfirm: () => onConfirm(),
// })
// if (err.err && err.err === 'token error') {
// localStorage.clear()
// this.$router.push('/')
// }
// },
// imprimirMensaje(message, title = '¡Felicidades!', onConfirm = () => {}) {
// this.$buefy.dialog.alert({
// ariaRole: 'alertdialog',
// ariaModal: true,
// type: 'is-success',
// title,
// message,
// confirmText: 'Ok',
// hasIcon: true,
// iconPack: 'mdi',
// icon: 'check-circle',
// onConfirm: () => onConfirm(),
// })
// },
// imprimirWarning(
// message,
// onConfirm = () => {},
// title = '¡Espera un minuto!',
// onCancel = () => {}
// ) {
// this.$buefy.dialog.alert({
// ariaRole: 'alertdialog',
// ariaModal: true,
// type: 'is-warning',
// title,
// message,
// confirmText: 'Confirmar',
// canCancel: true,
// cancelText: 'Cancelar',
// hasIcon: true,
// iconPack: 'mdi',
// icon: 'help-circle',
// onConfirm: () => onConfirm(),
// onCancel: () => onCancel(),
// })
// },
// getLocalhostInfo() {
// this.admin.idUsuario = Number(localStorage.getItem('idUsuario'))
// this.admin.idTipoUsuario = Number(localStorage.getItem('idTipoUsuario'))
// this.admin.tipoUsuario = localStorage.getItem('tipoUsuario')
// this.admin.token = {
// headers: {
// token: localStorage.getItem('token'),
// },
// }
// },
// },
// created() {
// this.getLocalhostInfo()
// if (this.admin.idTipoUsuario === 1) this.$router.push('/admin')
// if (this.admin.idTipoUsuario === 2) this.$router.push('/responsable')
// if (this.admin.idTipoUsuario === 4) this.$router.push('/casoEspecial')
// },
}
</script>
<style>
.SINO * {
margin: 0.5rem 0 !important;
}
.apartado,
.pag {
margin: 5rem 0;
}
.manyInputs {
margin: 1.5rem 0;
}
.checkb {
width: 20px;
height: 20px;
}
.navPages {
padding: 1rem;
}
.td-w {
width: 2000px;
}
.active,
.active:hover {
background-color: #bb8800 !important;
}
.centro {
text-align: center;
}
.vh {
height: 75vh;
display: flex;
justify-content: center;
align-items: center;
}
.vh h1 {
font-size: 60px;
}
</style>
+309
View File
@@ -0,0 +1,309 @@
<template>
<section class="container my-5 px-3">
<!-- <div v-if="idCuestionario === 'null'"> -->
<div class="my-5 mensaje">
<p class="is-size-2">Evaluación de programas de servicio social</p>
<p>
Te invitamos a compartir tu experiencia respecto del programa de
servicio social en el que participaste, a efecto de mejorar la oferta
de programas disponibles para los alumnos que desean liberar este
requisito. Te recordamos qe tus respues son confidenciales.
</p>
</div>
<!-- <parteA />
<parteB />
<parteC />
<parteD />
<parteE />
<parteF /> -->
<FullCuestionario />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading">
</b-loading>
</section>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
import parteA from '@/components/alumno/cuestionario/A'
import parteB from '@/components/alumno/cuestionario/B'
import parteC from '@/components/alumno/cuestionario/C'
import parteD from '@/components/alumno/cuestionario/D'
import parteE from '@/components/alumno/cuestionario/E'
import parteF from '@/components/alumno/cuestionario/F'
import navCues from '@/components/alumno/cuestionario/navCues'
import BotonRegresar from '@/components/botonRegresar'
import FullCuestionario from '@/components/alumno/cuestionario2/FullCuestionario'
export default {
components: {
parteA,
parteB,
parteC,
parteD,
parteE,
parteF,
navCues,
BotonRegresar,
FullCuestionario
},
data() {
return {
token: {
headers: {
token: localStorage.getItem('token'),
},
},
isLoading: false,
current: 1,
idCuestionario: "null",
answers: {
sexo: '',
edad: '',
servicioMedico: '',
servicioMedicoOtro: '',
servicioMedicoAux: '',
p1: '',
p2: '',
p3: [], // selecciona 3 opciones
p3Otro: '',
p4: '',
p5: [],
p6: '',
p7: '',
p8: [],
p9: '',
p10: '',
p11: '',
p12: '',
p13: '',
p14: [],
p15: [],
p16: '',
p17: [],
p18: '',
p19: '',
p20: '',
p21: [],
p22: [],
p23: [],
p24: [],
p25: '',
p26: '',
p27: '',
p28: null,
p29: null,
p30: '',
},
}
},
methods: {
onChildA(value) {
this.answers.servicioMedico = value.servicioMedico
this.answers.sexo = value.sexo
this.answers.edad = value.edad
},
onChildB(value) {
this.answers.p1 = value.p1
this.answers.p2 = value.p2
this.answers.p3 = value.p3
this.answers.p3Otro = value.p3Otro
},
onChildC(value) {
this.answers.p4 = value.p4
this.answers.p5 = value.p5
this.answers.p6 = value.p6
this.answers.p7 = value.p7
this.answers.p8 = value.p8
this.answers.p9 = value.p9
this.answers.p10 = value.p10
this.answers.p11 = value.p11
this.answers.p12 = value.p12
this.answers.p13 = value.p13
},
onChildD(value) {
this.answers.p14 = value.p14
this.answers.p15 = value.p15
this.answers.p16 = value.p16
this.answers.p17 = value.p17
},
onChildE(value) {
this.answers.p18 = value.p18
this.answers.p19 = value.p19
this.answers.p20 = value.p20
this.answers.p21 = value.p21
},
onChildF(value) {
this.answers.p22 = value.p22
this.answers.p23 = value.p23
this.answers.p24 = value.p24
this.answers.p25 = value.p25
this.answers.p26 = value.p26
this.answers.p27 = value.p27
this.answers.p28 = value.p28
this.answers.p29 = value.p29
this.answers.p30 = value.p30
},
onChildNAV(value) {
this.current = value
},
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',
ariaRole: 'alertdialog',
ariaModal: true,
})
if (salir == true) {
localStorage.clear()
this.$router.push(`/`)
}
},
enviarCuestionario() {
this.isLoading = true
if (this.answers.p3Otro != '' && this.maxCheckbox < 3) {
this.answers.p3.push(this.answers.p3Otro)
}
const data = {
idServicio: localStorage.getItem('idServicio'),
sexo: this.answers.sexo,
edad: this.answers.edad,
servicioMedico: this.answers.servicioMedico,
p1: this.answers.p1,
p2: this.answers.p2,
p3: this.answers.p3,
p4: this.answers.p4,
p5: this.answers.p5,
p6: this.answers.p6,
p7: this.answers.p7,
p8: this.answers.p8,
p9: this.answers.p9,
p10: this.answers.p10,
p11: this.answers.p11,
p12: this.answers.p12,
p13: this.answers.p13,
p14: this.answers.p14,
p15: this.answers.p15,
p16: this.answers.p16,
p17: this.answers.p17,
p18: this.answers.p18,
p19: this.answers.p19,
p20: this.answers.p20,
p21: this.answers.p21,
p22: this.answers.p22,
p23: this.answers.p23,
p24: this.answers.p24,
p25: this.answers.p25,
p26: this.answers.p26,
p27: this.answers.p27,
p28: this.answers.p28,
p29: this.answers.p29,
p30: this.answers.p30,
}
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)
})
.finally(() => {
this.isLoading = false
})
},
},
}
</script>
<style>
.SINO * {
margin: 0.5rem 0 !important;
}
.apartado,
.pag {
margin: 5rem 0;
}
.manyInputs {
margin: 1.5rem 0;
}
.checkb {
width: 20px;
height: 20px;
}
.navPages {
padding: 1rem;
}
.td-w {
width: 2000px;
}
.active,
.active:hover {
background-color: #bb8800 !important;
}
.centro {
text-align: center;
}
.vh {
height: 75vh;
display: flex;
justify-content: center;
align-items: center;
}
.vh h1 {
font-size: 60px;
}
</style>
+6
View File
@@ -89,6 +89,12 @@ export default {
'idCuestionarioAlumno', 'idCuestionarioAlumno',
res.data.idCuestionarioAlumno res.data.idCuestionarioAlumno
) )
localStorage.setItem(
'idCuestionarioAlumno2',
res.data.idCuestionarioAlumno2
)
localStorage.setItem('idServicio', res.data.idServicio) localStorage.setItem('idServicio', res.data.idServicio)
this.updateIsLoading(false) this.updateIsLoading(false)
}) })
+4 -4
View File
@@ -1,16 +1,16 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container px-2 pb-6">
<div class="pb-5 pt-6"> <b-field class="pb-5 pt-6">
<b-button type="is-info" tag="router-link" to="/casoEspecial/nuevo"> <b-button type="is-info" tag="router-link" to="/casoEspecial/nuevo">
Nuevo Caso Especial Nuevo Caso Especial
</b-button> </b-button>
</div> </b-field>
<TablaServiciosEspeciales <TablaServiciosEspeciales
:responsable="responsable" :responsable="responsable"
:imprimirError="imprimirError" :imprimirError="imprimirError"
/> />
</div> </section>
</template> </template>
<script> <script>
+2 -2
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container px-2 pb-6">
<BotonRegresar path="/casoEspecial" /> <BotonRegresar path="/casoEspecial" />
<h2 class="title">Agregar un Servicio Social</h2> <h2 class="title">Agregar un Servicio Social</h2>
@@ -15,7 +15,7 @@
<BotonRegresar path="/casoEspecial" /> <BotonRegresar path="/casoEspecial" />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" /> <b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</div> </section>
</template> </template>
<script> <script>
+9 -11
View File
@@ -4,27 +4,27 @@
> >
<form class="box"> <form class="box">
<div class="has-text-centered"> <div class="has-text-centered">
<h2 class="is-size-1">IRIS</h2> <h1 class="is-size-1">IRIS</h1>
</div> </div>
<b-field label="Usuario" :type="error"> <b-field label="Usuario" :type="error">
<b-input v-model="usuario" @keyup.enter.native="login()" /> <b-input @keyup.enter.native="login()" v-model="usuario" />
</b-field> </b-field>
<b-field label="Contraseña" :type="error"> <b-field label="Contraseña" :type="error">
<b-input <b-input
type="password" type="password"
password-reveal
v-model="password"
@keyup.enter.native="login()" @keyup.enter.native="login()"
v-model="password"
password-reveal
/> />
</b-field> </b-field>
<div class="has-text-centered"> <div class="has-text-centered">
<b-button <b-button
@click="login()"
type="is-success" type="is-success"
:disabled="error || !(usuario && password)" :disabled="error || !(usuario && password)"
@click="login()"
> >
Iniciar Sesión Iniciar Sesión
</b-button> </b-button>
@@ -41,10 +41,10 @@ import axios from 'axios'
export default { export default {
data() { data() {
return { return {
usuario: '',
password: '',
error: '',
isLoading: false, isLoading: false,
error: '',
password: '',
usuario: '',
} }
}, },
methods: { methods: {
@@ -110,9 +110,7 @@ export default {
localStorage.getItem('tipoUsuario') localStorage.getItem('tipoUsuario')
) )
this.$router.push(`/${localStorage.getItem('tipoUsuario')}`) this.$router.push(`/${localStorage.getItem('tipoUsuario')}`)
else { else localStorage.clear()
localStorage.clear()
}
}, },
layout: 'login', layout: 'login',
} }
+6 -2
View File
@@ -1,10 +1,12 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container px-2 pb-6">
<BotonRegresar <BotonRegresar
path="/responsable" path="/responsable"
:deleteFromLocalStorage="['idServicio']" :deleteFromLocalStorage="['idServicio']"
/> />
<h3 class="title">{{ alumno.nombre }} {{ alumno.usuario }}</h3>
<UploadArchivo <UploadArchivo
path="carta_aceptacion" path="carta_aceptacion"
tipoCarta="aceptación" tipoCarta="aceptación"
@@ -18,7 +20,7 @@
/> />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" /> <b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</div> </section>
</template> </template>
<script> <script>
@@ -32,6 +34,7 @@ export default {
return { return {
isLoading: false, isLoading: false,
idServicio: null, idServicio: null,
alumno: {},
responsable: {}, responsable: {},
} }
}, },
@@ -47,6 +50,7 @@ export default {
this.responsable.token this.responsable.token
) )
.then((res) => { .then((res) => {
this.alumno = res.data.Usuario
this.updateIsLoading(false) this.updateIsLoading(false)
if (res.data.Status.idStatus != 7) this.$router.push('/responsable') if (res.data.Status.idStatus != 7) this.$router.push('/responsable')
}) })
+6 -2
View File
@@ -1,10 +1,12 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container px-2 pb-6">
<BotonRegresar <BotonRegresar
path="/responsable" path="/responsable"
:deleteFromLocalStorage="['idServicio']" :deleteFromLocalStorage="['idServicio']"
/> />
<h3 class="title">{{ alumno.nombre }} {{ alumno.usuario }}</h3>
<UploadArchivo <UploadArchivo
path="carta_termino" path="carta_termino"
tipoCarta="termino" tipoCarta="termino"
@@ -18,7 +20,7 @@
/> />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" /> <b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</div> </section>
</template> </template>
<script> <script>
@@ -32,6 +34,7 @@ export default {
return { return {
isLoading: false, isLoading: false,
idServicio: null, idServicio: null,
alumno: {},
responsable: {}, responsable: {},
} }
}, },
@@ -47,6 +50,7 @@ export default {
this.responsable.token this.responsable.token
) )
.then((res) => { .then((res) => {
this.alumno = res.data.Usuario
this.updateIsLoading(false) this.updateIsLoading(false)
if (res.data.Status.idStatus != 4 && res.data.Status.idStatus != 8) if (res.data.Status.idStatus != 4 && res.data.Status.idStatus != 8)
this.$router.push('/responsable') this.$router.push('/responsable')
@@ -0,0 +1,333 @@
<template>
<section class="container my-5 px-3">
<!-- <div v-if="idCuestionario === 'null'"> -->
<div class="my-5 mensaje">
<p class="is-size-2">2025 Evaluación de la institución receptora de servicio social</p>
<p>
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:
<a
href="https://www.acatlan.unam.mx/normatividad"
class="column "
target="_blank"> www.acatlan.unam.mx/normatividad </a>
</p>
</div>
<!-- <parteA />
<parteB />
<parteC />
<parteD />
<parteE />
<parteF /> -->
<!-- <FullCuestionario /> -->
<FullCuestionario
:idServicio="idServicio"
:responsable="responsable"
:imprimirMensaje="imprimirMensaje"
:imprimirWarning="imprimirWarning"
:imprimirError="imprimirError"
:updateIsLoading="updateIsLoading"
/>
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading">
</b-loading>
</section>
</template>
<script>
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
import axios from 'axios'
import parteA from '@/components/alumno/cuestionario/A'
import parteB from '@/components/alumno/cuestionario/B'
import parteC from '@/components/alumno/cuestionario/C'
import parteD from '@/components/alumno/cuestionario/D'
import parteE from '@/components/alumno/cuestionario/E'
import parteF from '@/components/alumno/cuestionario/F'
import navCues from '@/components/alumno/cuestionario/navCues'
import BotonRegresar from '@/components/botonRegresar'
import FullCuestionario from '@/components/responsable/CuestionarioResponsable2'
export default {
components: {
parteA,
parteB,
parteC,
parteD,
parteE,
parteF,
navCues,
BotonRegresar,
FullCuestionario
},
data() {
return {
token: {
headers: {
token: localStorage.getItem('token'),
},
},
isLoading: false,
current: 1,
idCuestionario: "null",
answers: {
sexo: '',
edad: '',
servicioMedico: '',
servicioMedicoOtro: '',
servicioMedicoAux: '',
p1: '',
p2: '',
p3: [], // selecciona 3 opciones
p3Otro: '',
p4: '',
p5: [],
p6: '',
p7: '',
p8: [],
p9: '',
p10: '',
p11: '',
p12: '',
p13: '',
p14: [],
p15: [],
p16: '',
p17: [],
p18: '',
p19: '',
p20: '',
p21: [],
p22: [],
p23: [],
p24: [],
p25: '',
p26: '',
p27: '',
p28: null,
p29: null,
p30: '',
},
}
},
methods: {
onChildA(value) {
this.answers.servicioMedico = value.servicioMedico
this.answers.sexo = value.sexo
this.answers.edad = value.edad
},
onChildB(value) {
this.answers.p1 = value.p1
this.answers.p2 = value.p2
this.answers.p3 = value.p3
this.answers.p3Otro = value.p3Otro
},
onChildC(value) {
this.answers.p4 = value.p4
this.answers.p5 = value.p5
this.answers.p6 = value.p6
this.answers.p7 = value.p7
this.answers.p8 = value.p8
this.answers.p9 = value.p9
this.answers.p10 = value.p10
this.answers.p11 = value.p11
this.answers.p12 = value.p12
this.answers.p13 = value.p13
},
onChildD(value) {
this.answers.p14 = value.p14
this.answers.p15 = value.p15
this.answers.p16 = value.p16
this.answers.p17 = value.p17
},
onChildE(value) {
this.answers.p18 = value.p18
this.answers.p19 = value.p19
this.answers.p20 = value.p20
this.answers.p21 = value.p21
},
onChildF(value) {
this.answers.p22 = value.p22
this.answers.p23 = value.p23
this.answers.p24 = value.p24
this.answers.p25 = value.p25
this.answers.p26 = value.p26
this.answers.p27 = value.p27
this.answers.p28 = value.p28
this.answers.p29 = value.p29
this.answers.p30 = value.p30
},
onChildNAV(value) {
this.current = value
},
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',
ariaRole: 'alertdialog',
ariaModal: true,
})
if (salir == true) {
localStorage.clear()
this.$router.push(`/`)
}
},
enviarCuestionario() {
this.isLoading = true
if (this.answers.p3Otro != '' && this.maxCheckbox < 3) {
this.answers.p3.push(this.answers.p3Otro)
}
const data = {
idServicio: localStorage.getItem('idServicio'),
sexo: this.answers.sexo,
edad: this.answers.edad,
servicioMedico: this.answers.servicioMedico,
p1: this.answers.p1,
p2: this.answers.p2,
p3: this.answers.p3,
p4: this.answers.p4,
p5: this.answers.p5,
p6: this.answers.p6,
p7: this.answers.p7,
p8: this.answers.p8,
p9: this.answers.p9,
p10: this.answers.p10,
p11: this.answers.p11,
p12: this.answers.p12,
p13: this.answers.p13,
p14: this.answers.p14,
p15: this.answers.p15,
p16: this.answers.p16,
p17: this.answers.p17,
p18: this.answers.p18,
p19: this.answers.p19,
p20: this.answers.p20,
p21: this.answers.p21,
p22: this.answers.p22,
p23: this.answers.p23,
p24: this.answers.p24,
p25: this.answers.p25,
p26: this.answers.p26,
p27: this.answers.p27,
p28: this.answers.p28,
p29: this.answers.p29,
p30: this.answers.p30,
}
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)
})
.finally(() => {
this.isLoading = false
})
},
},
}
</script>
<style>
.SINO * {
margin: 0.5rem 0 !important;
}
.apartado,
.pag {
margin: 5rem 0;
}
.manyInputs {
margin: 1.5rem 0;
}
.checkb {
width: 20px;
height: 20px;
}
.navPages {
padding: 1rem;
}
.td-w {
width: 2000px;
}
.active,
.active:hover {
background-color: #bb8800 !important;
}
.centro {
text-align: center;
}
.vh {
height: 75vh;
display: flex;
justify-content: center;
align-items: center;
}
.vh h1 {
font-size: 60px;
}
</style>
+115 -10
View File
@@ -1,35 +1,79 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container my-5 px-3">
<BotonRegresar <!-- <div v-if="idCuestionario === 'null'"> -->
path="/responsable"
:deleteFromLocalStorage="['idServicio']" <div class="my-5 mensaje">
/> <p class="is-size-2">2025 Evaluación de la institución receptora de servicio social</p>
<p>
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)
<CuestionarioResponasble Los datos están sujetos al aviso de privacidad integral que se puede consultar en el sitio
web:
<a
href="https://www.acatlan.unam.mx/normatividad"
class="column "
target="_blank"> www.acatlan.unam.mx/normatividad </a>
</p>
</div>
<!-- <parteA />
<parteB />
<parteC />
<parteD />
<parteE />
<parteF /> -->
<!-- <FullCuestionario /> -->
<FullCuestionario
:idServicio="idServicio"
:responsable="responsable" :responsable="responsable"
:imprimirMensaje="imprimirMensaje" :imprimirMensaje="imprimirMensaje"
:imprimirWarning="imprimirWarning" :imprimirWarning="imprimirWarning"
:imprimirError="imprimirError" :imprimirError="imprimirError"
:updateIsLoading="updateIsLoading" :updateIsLoading="updateIsLoading"
/> />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading">
</b-loading>
</section>
</template>
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</div>
</template>
<script> <script>
import axios from 'axios'
import BotonRegresar from '@/components/botonRegresar' import BotonRegresar from '@/components/botonRegresar'
import CuestionarioResponasble from '@/components/responsable/CuestionarioResponasble' import CuestionarioResponasble from '@/components/responsable/CuestionarioResponasble'
import FullCuestionario from '@/components/responsable/CuestionarioResponsable2'
export default { export default {
components: { components: {
BotonRegresar, BotonRegresar,
CuestionarioResponasble, CuestionarioResponasble,
FullCuestionario
}, },
data() { data() {
return { return {
isLoading: false, isLoading: false,
idServicio: null,
alumno: {},
responsable: {}, responsable: {},
} }
}, },
@@ -37,6 +81,22 @@ export default {
updateIsLoading(booleanValue) { updateIsLoading(booleanValue) {
this.isLoading = booleanValue this.isLoading = booleanValue
}, },
obtenerRegistro() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/servicio/admin?idServicio=${this.idServicio}`,
this.responsable.token
)
.then((res) => {
this.alumno = res.data.Usuario
this.updateIsLoading(false)
if (res.data.idCuestionarioPrograma) this.$router.push('/responsable')
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) { imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) {
this.$buefy.dialog.alert({ this.$buefy.dialog.alert({
ariaRole: 'alertdialog', ariaRole: 'alertdialog',
@@ -102,6 +162,7 @@ export default {
token: localStorage.getItem('token'), token: localStorage.getItem('token'),
}, },
} }
this.idServicio = Number(localStorage.getItem('idServicio'))
}, },
}, },
created() { created() {
@@ -109,6 +170,50 @@ export default {
if (this.responsable.idTipoUsuario === 1) this.$router.push('/admin') if (this.responsable.idTipoUsuario === 1) this.$router.push('/admin')
if (this.responsable.idTipoUsuario === 3) this.$router.push('/alumno') if (this.responsable.idTipoUsuario === 3) this.$router.push('/alumno')
if (this.responsable.idTipoUsuario === 4) this.$router.push('/casoEspecial') if (this.responsable.idTipoUsuario === 4) this.$router.push('/casoEspecial')
if (!this.idServicio) this.$router.push('/responsable')
else this.obtenerRegistro()
}, },
} }
</script> </script>
<style>
.SINO * {
margin: 0.5rem 0 !important;
}
.apartado,
.pag {
margin: 5rem 0;
}
.manyInputs {
margin: 1.5rem 0;
}
.checkb {
width: 20px;
height: 20px;
}
.navPages {
padding: 1rem;
}
.td-w {
width: 2000px;
}
.active,
.active:hover {
background-color: #bb8800 !important;
}
.centro {
text-align: center;
}
.vh {
height: 75vh;
display: flex;
justify-content: center;
align-items: center;
}
.vh h1 {
font-size: 60px;
}
</style>
+143
View File
@@ -0,0 +1,143 @@
<template>
<section class="container px-2 pb-6">
<BotonRegresar
path="/responsable"
:deleteFromLocalStorage="['idServicio']"
/>
<h3 class="title">{{ alumno.nombre }} {{ alumno.usuario }}</h3>
<CuestionarioResponasble
:idServicio="idServicio"
:responsable="responsable"
:imprimirMensaje="imprimirMensaje"
:imprimirWarning="imprimirWarning"
:imprimirError="imprimirError"
:updateIsLoading="updateIsLoading"
/>
<BotonRegresar
path="/responsable"
:deleteFromLocalStorage="['idServicio']"
/>
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</section>
</template>
<script>
import axios from 'axios'
import BotonRegresar from '@/components/botonRegresar'
import CuestionarioResponasble from '@/components/responsable/CuestionarioResponasble'
export default {
components: {
BotonRegresar,
CuestionarioResponasble,
},
data() {
return {
isLoading: false,
idServicio: null,
alumno: {},
responsable: {},
}
},
methods: {
updateIsLoading(booleanValue) {
this.isLoading = booleanValue
},
obtenerRegistro() {
this.updateIsLoading(true)
axios
.get(
`${process.env.api}/servicio/admin?idServicio=${this.idServicio}`,
this.responsable.token
)
.then((res) => {
this.alumno = res.data.Usuario
this.updateIsLoading(false)
if (res.data.idCuestionarioPrograma) this.$router.push('/responsable')
})
.catch((err) => {
this.imprimirError(err.response.data)
})
},
imprimirError(err = {}, title = '¡Hubo un error!', onConfirm = () => {}) {
this.$buefy.dialog.alert({
ariaRole: 'alertdialog',
ariaModal: true,
type: 'is-danger',
title,
message: err.message,
confirmText: 'Entendido',
hasIcon: true,
iconPack: 'mdi',
icon: 'alert-octagon',
onConfirm: () => onConfirm(),
})
if (err.err && err.err === 'token error') {
localStorage.clear()
this.$router.push('/')
}
},
imprimirMensaje(message, title = '¡Felicidades!', onConfirm = () => {}) {
this.$buefy.dialog.alert({
ariaRole: 'alertdialog',
ariaModal: true,
type: 'is-success',
title,
message,
confirmText: 'Ok',
hasIcon: true,
iconPack: 'mdi',
icon: 'check-circle',
onConfirm: () => onConfirm(),
})
},
imprimirWarning(
message,
onConfirm = () => {},
title = '¡Espera un minuto!',
onCancel = () => {}
) {
this.$buefy.dialog.alert({
ariaRole: 'alertdialog',
ariaModal: true,
type: 'is-warning',
title,
message,
confirmText: 'Confirmar',
canCancel: true,
cancelText: 'Cancelar',
hasIcon: true,
iconPack: 'mdi',
icon: 'help-circle',
onConfirm: () => onConfirm(),
onCancel: () => onCancel(),
})
},
getLocalhostInfo() {
this.responsable.idUsuario = Number(localStorage.getItem('idUsuario'))
this.responsable.idTipoUsuario = Number(
localStorage.getItem('idTipoUsuario')
)
this.responsable.tipoUsuario = localStorage.getItem('tipoUsuario')
this.responsable.token = {
headers: {
token: localStorage.getItem('token'),
},
}
this.idServicio = Number(localStorage.getItem('idServicio'))
},
},
created() {
this.getLocalhostInfo()
if (this.responsable.idTipoUsuario === 1) this.$router.push('/admin')
if (this.responsable.idTipoUsuario === 3) this.$router.push('/alumno')
if (this.responsable.idTipoUsuario === 4) this.$router.push('/casoEspecial')
if (!this.idServicio) this.$router.push('/responsable')
else this.obtenerRegistro()
},
}
</script>
+2 -2
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container px-2 pb-6">
<div class="pt-6 pb-5"> <div class="pt-6 pb-5">
<p class="is-size-4 block"> <p class="is-size-4 block">
Estimado(a) responsable del programa de servicio social: Estimado(a) responsable del programa de servicio social:
@@ -27,7 +27,7 @@
:responsable="responsable" :responsable="responsable"
:imprimirError="imprimirError" :imprimirError="imprimirError"
/> />
</div> </section>
</template> </template>
<script> <script>
+2 -2
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="container px-2 pb-6"> <section class="container px-2 pb-6">
<BotonRegresar path="/responsable" /> <BotonRegresar path="/responsable" />
<div class="has-text-justified is-size-6 mb-6"> <div class="has-text-justified is-size-6 mb-6">
@@ -42,7 +42,7 @@
<BotonRegresar path="/responsable" /> <BotonRegresar path="/responsable" />
<b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" /> <b-loading :is-full-page="true" :can-cancel="false" v-model="isLoading" />
</div> </section>
</template> </template>
<script> <script>